Skip to content

Reduce redundant object creation while calling callback function from gc #104028

Closed
@corona10

Description

@corona10

cpython/Modules/gcmodule.c

Lines 1391 to 1402 in 4b27972

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance or resource usage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions