Skip to content

Commit 0e09267

Browse files
committed
Cleanup init of interp->pystats_struct.
Add the _PyStats_InterpInit() function which will set pystats_enabled flag and allocate pystats_struct as required. We shouldn't be putting logic in _PyObject_InitState(). This also fixes a bug where interp->pystats_struct was allocated repeated rather than once per interpreter.
1 parent 612ea96 commit 0e09267

File tree

4 files changed

+39
-19
lines changed

4 files changed

+39
-19
lines changed

Include/internal/pycore_stats.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
110110
RARE_EVENT_INTERP_INC(interp, name); \
111111
} while (0); \
112112

113+
PyStatus _PyStats_InterpInit(PyInterpreterState *);
113114
bool _PyStats_ThreadInit(PyInterpreterState *, _PyThreadStateImpl *);
114115
void _PyStats_ThreadFini(_PyThreadStateImpl *);
115116
void _PyStats_Attach(_PyThreadStateImpl *);

Objects/object.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,13 +2418,6 @@ _PyObject_InitState(PyInterpreterState *interp)
24182418
if (refchain_init(interp) < 0) {
24192419
return _PyStatus_NO_MEMORY();
24202420
}
2421-
#endif
2422-
#ifdef Py_STATS
2423-
if (interp->config._pystats) {
2424-
// start with pystats enabled, can be disabled via sys._stats_off()
2425-
// this needs to be set before the first tstate is created
2426-
interp->pystats_enabled = 1;
2427-
}
24282421
#endif
24292422
return _PyStatus_OK();
24302423
}

Python/pylifecycle.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "pycore_runtime.h" // _Py_ID()
2727
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
2828
#include "pycore_setobject.h" // _PySet_NextEntry()
29+
#include "pycore_stats.h" // _PyStats_InterpInit()
2930
#include "pycore_sysmodule.h" // _PySys_ClearAttrString()
3031
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
3132
#include "pycore_typeobject.h" // _PyTypes_InitTypes()
@@ -652,6 +653,14 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
652653
return status;
653654
}
654655

656+
#ifdef Py_STATS
657+
// initialize pystats. This must be done after the settings are loaded.
658+
status = _PyStats_InterpInit(interp);
659+
if (_PyStatus_EXCEPTION(status)) {
660+
return status;
661+
}
662+
#endif
663+
655664
// initialize the interp->obmalloc state. This must be done after
656665
// the settings are loaded (so that feature_flags are set) but before
657666
// any calls are made to obmalloc functions.
@@ -2349,6 +2358,14 @@ new_interpreter(PyThreadState **tstate_p,
23492358
return status;
23502359
}
23512360

2361+
#ifdef Py_STATS
2362+
// initialize pystats. This must be done after the settings are loaded.
2363+
status = _PyStats_InterpInit(interp);
2364+
if (_PyStatus_EXCEPTION(status)) {
2365+
return status;
2366+
}
2367+
#endif
2368+
23522369
// initialize the interp->obmalloc state. This must be done after
23532370
// the settings are loaded (so that feature_flags are set) but before
23542371
// any calls are made to obmalloc functions.

Python/pystats.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "pycore_pyatomic_ft_wrappers.h"
55
#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock()
66
#include "pycore_tstate.h"
7+
#include "pycore_initconfig.h" // _PyStatus_OK()
78
#include "pycore_uop_metadata.h" // _PyOpcode_uop_name
89
#include "pycore_uop_ids.h" // MAX_UOP_ID
910
#include "pycore_pystate.h" // _PyThreadState_GET()
@@ -725,23 +726,31 @@ _Py_PrintSpecializationStats(int to_file)
725726
return 1;
726727
}
727728

729+
PyStatus
730+
_PyStats_InterpInit(PyInterpreterState *interp)
731+
{
732+
if (interp->config._pystats) {
733+
// start with pystats enabled, can be disabled via sys._stats_off()
734+
// this needs to be set before the first tstate is created
735+
interp->pystats_enabled = 1;
736+
interp->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats));
737+
if (interp->pystats_struct == NULL) {
738+
return _PyStatus_ERR("out-of-memory while initializing interpreter");
739+
}
740+
}
741+
return _PyStatus_OK();
742+
}
743+
728744
bool
729745
_PyStats_ThreadInit(PyInterpreterState *interp, _PyThreadStateImpl *tstate)
730746
{
731-
STATS_LOCK(interp);
732-
if (interp->pystats_enabled) {
733-
PyStats *s = PyMem_RawCalloc(1, sizeof(PyStats));
734-
if (s == NULL) {
735-
STATS_UNLOCK(interp);
747+
#ifdef Py_GIL_DISABLED
748+
if (FT_ATOMIC_LOAD_INT_RELAXED(interp->pystats_enabled)) {
749+
assert(interp->pystats_struct != NULL);
750+
tstate->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats));
751+
if (tstate->pystats_struct == NULL) {
736752
return false;
737753
}
738-
FT_ATOMIC_STORE_PTR_RELAXED(interp->pystats_struct, s);
739-
}
740-
STATS_UNLOCK(interp);
741-
#ifdef Py_GIL_DISABLED
742-
tstate->pystats_struct = PyMem_RawCalloc(1, sizeof(PyStats));
743-
if (tstate->pystats_struct == NULL) {
744-
return false;
745754
}
746755
#endif
747756
return true;

0 commit comments

Comments
 (0)