|
for (Py_ssize_t i=0; i<PyList_GET_SIZE(gcstate->callbacks); i++) { |
|
PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i); |
|
Py_INCREF(cb); /* make sure cb doesn't go away */ |
|
r = PyObject_CallFunction(cb, "sO", phase, info); |
|
if (r == NULL) { |
|
PyErr_WriteUnraisable(cb); |
|
} |
|
else { |
|
Py_DECREF(r); |
|
} |
|
Py_DECREF(cb); |
|
} |
The phase object can be created earlier with one-time creation and it can be replaced with vectorcall either.
From my microbenchmark, there is 4-5% performance improvement by doing this.
microbenchmark
import pyperf
import gc
def benchamark_collection(loops):
def callback_foo(phase, info):
pass
for _ in range(100):
gc.callbacks.append(callback_foo)
total_time = 0
for _ in range(loops):
t0 = pyperf.perf_counter()
collected = gc.collect()
total_time += pyperf.perf_counter() - t0
return total_time
if __name__ == "__main__":
runner = pyperf.Runner()
runner.metadata["description"] = "GC callback benchmark"
runner.bench_time_func("create_gc_cycles", benchamark_collection)
Linked PRs