Skip to content

gh-155725: Remove PyGILState_Ensure usage from tracemalloc - #156409

Open
kumaraditya303 wants to merge 4 commits into
python:mainfrom
kumaraditya303:tracemalloc
Open

gh-155725: Remove PyGILState_Ensure usage from tracemalloc#156409
kumaraditya303 wants to merge 4 commits into
python:mainfrom
kumaraditya303:tracemalloc

Conversation

@kumaraditya303

@kumaraditya303 kumaraditya303 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

tracemalloc no longer acquires the GIL nor creates a temporary thread state when tracing memory allocations.

tracemalloc no longer acquires the GIL nor creates a temporary thread
state when tracing memory allocations. A thread with no attached thread
state now records the trace with the "<unknown>" traceback instead of
attaching a thread state to capture the Python traceback. Threads
without a thread state used to pay for a GIL acquisition plus a full
thread state creation and destruction on every traced raw allocation,
only to record an empty traceback anyway.
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #34238669 | 📁 Comparing 69d37ec against main (7f0ccd6)

  🔍 Preview build  

2 files changed
± c-api/memory.html
± whatsnew/changelog.html

…e attached

Store traceback frame filenames as interned NUL terminated UTF-8 strings
instead of Python str objects, so that capturing a traceback no longer
uses or modifies Python objects. Threads without an attached thread state
now capture their Python traceback by walking the frames of the thread
state most recently bound to the thread; only threads which never had a
thread state record the traceback as "<unknown>".

@ZeroIntensity ZeroIntensity left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a much better approach.

Comment thread Python/tracemalloc.c
Comment thread Python/tracemalloc.c
Comment on lines +952 to +954
filename_obj = PyUnicode_DecodeUTF8(filename,
(Py_ssize_t)strlen(filename),
"surrogatepass");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can call arbitrary Python code through the codec error handler, meaning this can encounter a re-entrancy deadlock with the tables lock. I'm okay with not fixing that since there's no reason an error handler should be invoking tracemalloc, but it's probably worth adding a comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tracemalloc checks for re-entrancy before acquring the tables lock, so this shoudn't be a issue unless I am missing something.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's not an issue for the allocator functions, but it would be an issue if the Python code called tracemalloc.clear_traces or something like that, which access the tables lock unconditionally.

Comment thread Python/tracemalloc.c Outdated
Comment thread Python/tracemalloc.c
Comment on lines +423 to +426
if (_PyInterpreterGuard_TryAcquire(_PyInterpreterState_Main(),
&guard) < 0) {
return tracemalloc_empty_traceback;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_PyInterpreterGuard_TryAcquire isn't thread safe in this manner, because the interpreter state can be deleted before the guard has been acquired. It's technically not an issue here because the main interpreter is statically allocated, but relying on that will make refactoring harder later.

It would be nicer to use the interpreter ID instead (the main interpreter ID is always zero), which has a thread-safe lookup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking up by interpreter id would require holding the runtime lock which I am trying to avoid here. FWIW main interpreter being statically allocated is relied upon in a lot of code anyways so avoiding that isn't very useful here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the runtime lock a bad thing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants