-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance tracemalloc to trace properly free lists #79234
Comments
CPython uses many "free lists": list of "deallocated" objects which are kept alive to optimize allocation of new objects. For example, the builtin list type has a free list. Problem: tracemalloc only traces the memory allocation when the object is created, but it doesn't update the traceback when the "free object" is reused to create "a new object". Attached PR modifies _Py_NewReference() to update the Python traceback in the tracemalloc trace. |
Is performance overhead negligible? |
Thank you for asking the most important question :-) I ran this microbenchmark: make distclean My first attempt: $ env/bin/python -m perf compare_to ref.json patch.json
Mean +- std dev: [ref] 20.6 ns +- 0.1 ns -> [patch] 22.4 ns +- 0.1 ns: 1.09x slower (+9%) The addition of the _PyTraceMalloc_NewReference() call which does nothing (check tracing flag, return) adds 1.7 ns: it's not negligible on such micro-benchmark, and I would prefer to avoid it whenever possible since _Py_NewReference() is the root of the free list optimization. New attempt: expose tracemalloc_config and add _Py_unlikely() macro (instruct the compiler that tracing is false most of the time): Mean +- std dev: [ref] 20.6 ns +- 0.1 ns -> [unlikely] 20.4 ns +- 0.3 ns: 1.01x faster (-1%) Good! The overhead is now negligible! But... is the hardcore low-level _Py_unlikely() optimization really needed?... $ env/bin/python -m perf compare_to ref.json if_tracing.json
Benchmark hidden because not significant (1): timeit => no, the macro is useless, so I removed it! New benchmark to double-check on my laptop. git checkout master git checkout tracemalloc_newref $ env/bin/python -m perf compare_to ref.json patch.json
Mean +- std dev: [ref] 20.8 ns +- 0.7 ns -> [patch] 20.5 ns +- 0.3 ns: 1.01x faster (-1%) The std dev is a little bit high. I didn't use CPU isolation and Hexchat + Firefox was running in the background, *but* it seems like the mean is very close, and so that my PR has no significant overhead. |
Python 3.8 uses many free lists: Attached dict_wrong_traceback.py shows the bug on the dictionary of an object: $ ./python ~/dict_wrong_traceback.py
File "/home/vstinner/dict_wrong_traceback.py", line 13
p = Point() # first object (dead!)
File "/home/vstinner/dict_wrong_traceback.py", line 8
self.x = 1 tracemalloc shows the traceback of the first object... which has been destroyed! With the fix: $ ./python ~/dict_wrong_traceback.py
File "/home/vstinner/dict_wrong_traceback.py", line 16
p = Point() # second object (alive)
File "/home/vstinner/dict_wrong_traceback.py", line 8
self.x = 1 It's much better: it doesn't show dead objects anymore :-) |
A little bit of history. I opened a bug 2 years ago but I closed it (lack of interest): I rewrote tracemalloc between version 0.9 and 1.0. In tracemalloc 0.9, there was an API to track free lists. Here is the code to handle "alloc" and "free" of an object inside a freelist: My PR 10063 has a more correct and efficient implementation:
|
Even if Python 3.6 and 3.7 are impacted by the bug, I propose to only fix Python 3.8 since the change modifies a _Py_NewReference() function which is critical for performance. |
New changeset 6279c1c by Victor Stinner in branch 'master': |
This change modifies _Py_NewReference() which is a very important function and it impacts Python performance. I prefer to keep the bug in Python 3.6 and 3.7 to not risk to introduce a regression. The bug exists since Python 3.4 and I'm the first one to spot it. It's not like there is huge pressure to backport the fix. Thanks again INADA-san for the review! |
Oh :-( I didn't expect that I would have to declare PyTraceMalloc_NewReference() in object.h even if Py_LIMITED_API is defined... Python currently leaks too much things even if Py_LIMITED_API is defined. It's time to break the C API! :-) https://pythoncapi.readthedocs.io/ (just kidding, or not) |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: