Repository navigation
[mypyc] Cache code objects used for traceback entries - #22476
Open
Jahongir-Qurbonov wants to merge 1 commit into
Open
Jahongir-Qurbonov wants to merge 1 commit into
Jahongir-Qurbonov wants to merge 1 commit into
Conversation
`CPy_AddTraceback` created a new code object for every traceback entry
added in native code. On free-threaded builds code objects use deferred
reference counting, so they are only freed by the cyclic GC, and the GC
only runs when the eval breaker is handled. A native loop that raises
and catches exceptions without calling interpreted code never gets
there, so each iteration leaked a dead code object until the native
function returned. For example, a loop doing
`try: raise TypeError("x") except TypeError: ...` grew RSS by ~500
bytes per iteration (~1.4 GB for 3M iterations in a single call).
Cache the code objects in a small direct-mapped table keyed by
filename, function name and line, protected by a mutex on free-threaded
builds. This fixes the memory growth, and it also makes raising
exceptions in native code faster on all builds, since creating a code
object is relatively expensive (the loop above got ~3.6x faster on
3.14t and ~2.2x faster on 3.14).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CPy_AddTracebackcreates a new code object for every traceback entry added by native code. On free-threaded builds, code objects use deferred reference counting, so only the cyclic GC can free them. The GC only runs when the eval breaker is handled, which never happens in a native loop that raises and catches exceptions without calling interpreted code. As a result, each iteration leaks a dead code object until the native function returns.For example, on 3.14t this grows RSS by about 500 bytes per iteration, which is about 1.4 GB for 3M iterations in a single call:
This PR caches the code objects in a small direct-mapped table keyed by filename, function name and line, guarded by a mutex on free-threaded builds. That fixes the memory growth. It also makes raising exceptions in native code faster on every build, because creating a code object is relatively expensive: the loop above runs about 3.6x faster on 3.14t and 2.2x faster on 3.14.
Added a run test that checks the traceback entries are still correct, that code objects are reused, and that a raise/catch loop doesn't create code-object garbage.