12 min read
Tags: Exploration, Python
Ignoring cheap operations (arithmetic, logical, bits) and some not-so-cheap operations (branching), this is the operational cost of adding two integers in CPython.
1 (hot) indirect read: read bytecode buffer. (NEXTOP macro)
1 jump-table jump: instruction selection (BINARY_ADD in this case).
2 (hot) indirect reads: pop the evaluation stack. (POP macro, TOP macro)
2 indirect reads: RTTI check for int type. (PyInt_CheckExact macro)
2 indirect reads: extract int value. (PyInt_AS_LONG macro)
1 unsigned long add: the actual addition (maybe).
1 overflow check. Four paths:
“Fast” path: (cached int object)
1 range check: determine if value is cached.
1 (warm) global read: read the cached object.
1 indirect increment: reference count.
“Slow” path: (not cached; int object 'free list' not full)
1 global read: use free list.
1 global write: advance free list.
1 indirect write: set object type. (PyObject_INIT macro)
1 indirect write: initialize reference count. (_Py_NewReference macro)
1 indirect write: set integer value.
“Slower” path: (not cached; free list full / not allocated)
1 memory allocation: allocate new PyIntObject free list.
1 indirect write: chain new free list to current (full) free list.
1 global write: set new free list as current free list.
1000 (hot) indirect writes: link PyIntObjects to each other.
Go to “Slow” path.
“Slowest” path: (addition overflow)
2 indirect reads: RTTI check.
1 double-indirect reads: read number method table.
1 triple-indirect reads: read addition method from table. (NB_BINOP)
1 quadruple-indirect call: go to int addition. (int_add)
2 indirect reads: RTTI check for int type. (CONVERT_TO_LONG)
2 indirect reads: extract int value.
1 unsigned long add: the actual addition (again).
1 overflow check (again).
1 global read: read PyLong_Type number method table.
1 indirect read: read long addition method.
1 doubly-indirect call: go to long addition. (long_add)
Convert ints to longs: (CONVERT_BINOP macro)
2 indirect reads: RTTI check for int type.
2 indirect reads: extract int value (third time). (PyInt_AS_LONG)
Allocate temporary long objects: (in PyLong_FromLong)
1 object allocation: for addition result.
4* indirect reads & writes: arbitrary-precision addition.
2 indirect decrements: refcount for temporary longs. (Py_DECREF)
2 indirect function calls: object deallocation. (_Py_Dealloc)
2 indirect decrements: refcount for popped stack values. (Py_DECREF)
(Possible) 2 indirect function calls: object deallocation. (_Py_Dealloc)
1 (hot) indirect write: set top of evaluation stack. (SET_TOP macro)