Python Call Stack
Why function calls aren't free
4 January 2019
Tiago "Myhro" Ilieve
DevOps Engineer, Zalando SE
Tiago "Myhro" Ilieve
DevOps Engineer, Zalando SE
Also known as "activation records" or "activation frames", (basically) composed of:
Include/frameobject.h, lines 17 to 53:
PyFrameObject
pointer to the previous framePyCodeObject
pointerPyTryBlock
(3x int
)PyObject
pointers (and pointers to pointers)char
int
Total: 129 bytes (on x86_64)
4Loop:
def factorial(n): r = 1 while n > 0: r *= n n -= 1 return r
Recursion:
def rec_factorial(n): if n == 1: return 1 return n * rec_factorial(n - 1)
Measured using IPython's %timeit
built-in magic command:
In [1]: %timeit factorial(5) 485 ns ± 1.85 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [2]: %timeit rec_factorial(5) 704 ns ± 2.49 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [3]: %timeit factorial(10) 902 ns ± 27.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [4]: %timeit rec_factorial(10) 1.41 µs ± 6.95 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [5]: %timeit factorial(100) 10.4 µs ± 96 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) In [6]: %timeit rec_factorial(100) 15.9 µs ± 276 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Python/C API Reference Manual - Memory Management
Python memory management - The Run-time stack and the Heap