mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-131253: free-threaded build support for pystats (gh-137189)
Allow the --enable-pystats build option to be used with free-threading. The stats are now stored on a per-interpreter basis, rather than process global. For free-threaded builds, the stats structure is allocated per-thread and then periodically merged into the per-interpreter stats structure (on thread exit or when the reporting function is called). Most of the pystats related code has be moved into the file Python/pystats.c.
This commit is contained in:
parent
cf1a2c1ee4
commit
c98c5b3449
24 changed files with 1269 additions and 485 deletions
|
|
@ -21,6 +21,7 @@
|
|||
#include "pycore_runtime.h" // _PyRuntime
|
||||
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
|
||||
#include "pycore_stackref.h" // Py_STACKREF_DEBUG
|
||||
#include "pycore_stats.h" // FT_STAT_WORLD_STOP_INC()
|
||||
#include "pycore_time.h" // _PyTime_Init()
|
||||
#include "pycore_uop.h" // UOP_BUFFER_SIZE
|
||||
#include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts()
|
||||
|
|
@ -465,6 +466,12 @@ alloc_interpreter(void)
|
|||
static void
|
||||
free_interpreter(PyInterpreterState *interp)
|
||||
{
|
||||
#ifdef Py_STATS
|
||||
if (interp->pystats_struct) {
|
||||
PyMem_RawFree(interp->pystats_struct);
|
||||
interp->pystats_struct = NULL;
|
||||
}
|
||||
#endif
|
||||
// The main interpreter is statically allocated so
|
||||
// should not be freed.
|
||||
if (interp != &_PyRuntime._main_interpreter) {
|
||||
|
|
@ -1407,6 +1414,9 @@ static void
|
|||
free_threadstate(_PyThreadStateImpl *tstate)
|
||||
{
|
||||
PyInterpreterState *interp = tstate->base.interp;
|
||||
#ifdef Py_STATS
|
||||
_PyStats_ThreadFini(tstate);
|
||||
#endif
|
||||
// The initial thread state of the interpreter is allocated
|
||||
// as part of the interpreter state so should not be freed.
|
||||
if (tstate == &interp->_initial_thread) {
|
||||
|
|
@ -1535,6 +1545,13 @@ new_threadstate(PyInterpreterState *interp, int whence)
|
|||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef Py_STATS
|
||||
// The PyStats structure is quite large and is allocated separated from tstate.
|
||||
if (!_PyStats_ThreadInit(interp, tstate)) {
|
||||
free_threadstate(tstate);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We serialize concurrent creation to protect global state. */
|
||||
HEAD_LOCK(interp->runtime);
|
||||
|
|
@ -1846,6 +1863,9 @@ _PyThreadState_DeleteCurrent(PyThreadState *tstate)
|
|||
_Py_EnsureTstateNotNULL(tstate);
|
||||
#ifdef Py_GIL_DISABLED
|
||||
_Py_qsbr_detach(((_PyThreadStateImpl *)tstate)->qsbr);
|
||||
#endif
|
||||
#ifdef Py_STATS
|
||||
_PyStats_Detach((_PyThreadStateImpl *)tstate);
|
||||
#endif
|
||||
current_fast_clear(tstate->interp->runtime);
|
||||
tstate_delete_common(tstate, 1); // release GIL as part of call
|
||||
|
|
@ -2020,6 +2040,10 @@ tstate_deactivate(PyThreadState *tstate)
|
|||
assert(tstate_is_bound(tstate));
|
||||
assert(tstate->_status.active);
|
||||
|
||||
#if Py_STATS
|
||||
_PyStats_Detach((_PyThreadStateImpl *)tstate);
|
||||
#endif
|
||||
|
||||
tstate->_status.active = 0;
|
||||
|
||||
// We do not unbind the gilstate tstate here.
|
||||
|
|
@ -2123,6 +2147,10 @@ _PyThreadState_Attach(PyThreadState *tstate)
|
|||
_PyCriticalSection_Resume(tstate);
|
||||
}
|
||||
|
||||
#ifdef Py_STATS
|
||||
_PyStats_Attach((_PyThreadStateImpl *)tstate);
|
||||
#endif
|
||||
|
||||
#if defined(Py_DEBUG)
|
||||
errno = err;
|
||||
#endif
|
||||
|
|
@ -2272,6 +2300,7 @@ stop_the_world(struct _stoptheworld_state *stw)
|
|||
stw->thread_countdown = 0;
|
||||
stw->stop_event = (PyEvent){0}; // zero-initialize (unset)
|
||||
stw->requester = _PyThreadState_GET(); // may be NULL
|
||||
FT_STAT_WORLD_STOP_INC();
|
||||
|
||||
_Py_FOR_EACH_STW_INTERP(stw, i) {
|
||||
_Py_FOR_EACH_TSTATE_UNLOCKED(i, t) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue