Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix quadratically increasing garbage collection delays in free-threaded
build.
14 changes: 13 additions & 1 deletion Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -2210,7 +2210,19 @@ record_deallocation(PyThreadState *tstate)
gc->alloc_count--;
if (gc->alloc_count <= -LOCAL_ALLOC_COUNT_THRESHOLD) {
GCState *gcstate = &tstate->interp->gc;
_Py_atomic_add_int(&gcstate->young.count, (int)gc->alloc_count);
int count = _Py_atomic_load_int_relaxed(&gcstate->young.count);
int new_count;
do {
if (count == 0) {
break;
}
new_count = count + (int)gc->alloc_count;
if (new_count < 0) {
new_count = 0;
}
} while (!_Py_atomic_compare_exchange_int(&gcstate->young.count,
&count,
new_count));
gc->alloc_count = 0;
}
}
Expand Down
8 changes: 8 additions & 0 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,14 @@ tstate_delete_common(PyThreadState *tstate, int release_gil)
assert(tstate_impl->refcounts.values == NULL);
#endif

#ifdef Py_GIL_DISABLED
// Flush the thread's local GC allocation count to the global count
// before the thread state is deleted, otherwise the count is lost.
_Py_atomic_add_int(&tstate->interp->gc.young.count,
(int)tstate_impl->gc.alloc_count);
tstate_impl->gc.alloc_count = 0;
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's remove this for now. It's not essential for the fix and we can add it back correctly in a subsequent PR.

This is causing a thread sanitizer failure. You can see it in the job if you expand the "Display logs" section:

WARNING: ThreadSanitizer: data race (pid=19505)
  Atomic write of size 4 at 0x55bb91207c44 by thread T52:
    #0 _Py_atomic_add_int /home/runner/work/cpython/cpython/./Include/cpython/pyatomic_gcc.h:15:10 (python+0x63520e) (BuildId: c37d32af53b8782ca7323d5cb2febaf42023f6ab)
    #1 tstate_delete_common /home/runner/work/cpython/cpython/Python/pystate.c:1816:5 (python+0x63520e)
    #2 _PyThreadState_DeleteCurrent /home/runner/work/cpython/cpython/Python/pystate.c:1893:5 (python+0x635582) (BuildId: c37d32af53b8782ca7323d5cb2febaf42023f6ab)
...

  Previous write of size 4 at 0x55bb91207c44 by main thread:
    #0 gc_collect_internal /home/runner/work/cpython/cpython/Python/gc_free_threading.c:2240:33 (python+0x5940bb) (BuildId: c37d32af53b8782ca7323d5cb2febaf42023f6ab)
    #1 gc_collect_main /home/runner/work/cpython/cpython/Python/gc_free_threading.c:2414:5 (python+0x59199c) (BuildId: c37d32af53b8782ca7323d5cb2febaf42023f6ab)
    #2 _PyGC_Collect /home/runner/work/cpython/cpython/Python/gc_free_threading.c:2723:12 (python+0x591cb7) (BuildId: c37d32af53b8782ca7323d5cb2febaf42023f6ab)
...

The problem is that gc_collect_internal reads this during a stop the world pause, but this thread is no longer considered active (i.e., we have a "detached" thread state that's getting deleted).

We could move this to PyThreadState_Clear(), but let's just not include it for now. I'd like to keep the critical fix small for backporting and "losing" a few local counts probably doesn't matter.

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.

Makes sense, done!

#if _Py_TIER2
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
if (_tstate->jit_tracer_state.code_buffer != NULL) {
Expand Down
Loading