11#include "Python.h"
22
33#include "pycore_opcode_metadata.h" // _PyOpcode_Caches
4+ #include "pycore_pyatomic_ft_wrappers.h"
5+ #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock()
46#include "pycore_uop_metadata.h" // _PyOpcode_uop_name
57#include "pycore_uop_ids.h" // MAX_UOP_ID
6- #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock()
78#include "pycore_pystate.h" // _PyThreadState_GET()
89#include "pycore_runtime.h" // NUM_GENERATIONS
910
@@ -105,7 +106,7 @@ add_stat_dict(
105106PyObject *
106107_Py_GetSpecializationStats (void ) {
107108 PyThreadState * tstate = _PyThreadState_GET ();
108- PyStats * src = tstate -> interp -> pystats_struct ;
109+ PyStats * src = FT_ATOMIC_LOAD_PTR_RELAXED ( tstate -> interp -> pystats_struct ) ;
109110 if (src == NULL ) {
110111 Py_RETURN_NONE ;
111112 }
@@ -554,11 +555,30 @@ stats_merge_thread(_PyThreadStateImpl *tstate, bool zero)
554555#endif // Py_GIL_DISABLED
555556
556557// toggle stats collection on or off for all threads
557- static void
558- stats_toggle_on_off (PyThreadState * tstate )
558+ static int
559+ stats_toggle_on_off (PyThreadState * tstate , int on )
559560{
561+ bool changed = false;
560562 PyInterpreterState * interp = tstate -> interp ;
561- _Py_FOR_EACH_TSTATE_BEGIN (interp , ts ) {
563+ STATS_LOCK (interp );
564+ if (on && interp -> pystats_struct == NULL ) {
565+ PyStats * s = PyMem_RawCalloc (1 , sizeof (PyStats ));
566+ if (s == NULL ) {
567+ STATS_UNLOCK (interp );
568+ return -1 ;
569+ }
570+ FT_ATOMIC_STORE_PTR_RELAXED (interp -> pystats_struct , s );
571+ }
572+ if (tstate -> interp -> pystats_enabled != on ) {
573+ FT_ATOMIC_STORE_INT_RELAXED (tstate -> interp -> pystats_enabled , on );
574+ changed = true;
575+ }
576+ STATS_UNLOCK (interp );
577+ if (!changed ) {
578+ return 0 ;
579+ }
580+ _PyEval_StopTheWorld (interp );
581+ _Py_FOR_EACH_TSTATE_UNLOCKED (interp , ts ) {
562582 if (!ts -> _status .active ) {
563583 continue ;
564584 }
@@ -577,65 +597,53 @@ stats_toggle_on_off(PyThreadState *tstate)
577597 // write to the tss variable for the 'ts' thread
578598 * ts_impl -> pystats_tss = s ;
579599 }
580- _Py_FOR_EACH_TSTATE_END (interp );
600+ _PyEval_StartTheWorld (interp );
601+ return 0 ;
581602}
582603
583- // merge stats for all threads into the global structure
604+ // merge stats for all threads into the per-interpreter structure
605+ // if 'zero' is true then the per-interpreter stats are zeroed after merging
584606static void
585- stats_merge_all (void )
607+ stats_merge_all (bool zero )
586608{
587- #ifdef Py_GIL_DISABLED
588609 PyThreadState * tstate = _PyThreadState_GET ();
589610 if (tstate == NULL ) {
590611 return ;
591612 }
613+ if (FT_ATOMIC_LOAD_PTR_RELAXED (tstate -> interp -> pystats_struct ) == NULL ) {
614+ return ;
615+ }
592616 PyInterpreterState * interp = tstate -> interp ;
593- _Py_FOR_EACH_TSTATE_BEGIN (interp , ts ) {
594- stats_merge_thread ((_PyThreadStateImpl * )ts , true);
617+ _PyEval_StopTheWorld (interp );
618+ #ifdef Py_GIL_DISABLED
619+ _Py_FOR_EACH_TSTATE_UNLOCKED (interp , ts ) {
620+ stats_merge_thread ((_PyThreadStateImpl * )ts , true);
595621 }
596- _Py_FOR_EACH_TSTATE_END (interp );
597622#endif
623+ if (zero ) {
624+ memset (interp -> pystats_struct , 0 , sizeof (PyStats ));
625+ }
626+ _PyEval_StartTheWorld (interp );
598627}
599628
600629int
601630_Py_StatsOn (void )
602631{
603632 PyThreadState * tstate = _PyThreadState_GET ();
604- PyInterpreterState * interp = tstate -> interp ;
605- STATS_LOCK (interp );
606- tstate -> interp -> pystats_enabled = true;
607- if (interp -> pystats_struct == NULL ) {
608- interp -> pystats_struct = PyMem_RawCalloc (1 , sizeof (PyStats ));
609- if (interp -> pystats_struct == NULL ) {
610- STATS_UNLOCK (interp );
611- return -1 ;
612- }
613- }
614- stats_toggle_on_off (tstate );
615- STATS_UNLOCK (interp );
616- return 0 ;
633+ return stats_toggle_on_off (tstate , 1 );
617634}
618635
619636void
620637_Py_StatsOff (void )
621638{
622639 PyThreadState * tstate = _PyThreadState_GET ();
623- STATS_LOCK (tstate -> interp );
624- tstate -> interp -> pystats_enabled = false;
625- stats_toggle_on_off (tstate );
626- STATS_UNLOCK (tstate -> interp );
640+ stats_toggle_on_off (tstate , 0 );
627641}
628642
629643void
630644_Py_StatsClear (void )
631645{
632- PyThreadState * tstate = _PyThreadState_GET ();
633- STATS_LOCK (tstate -> interp );
634- if (tstate -> interp -> pystats_struct != NULL ) {
635- stats_merge_all ();
636- memset (tstate -> interp -> pystats_struct , 0 , sizeof (PyStats ));
637- }
638- STATS_UNLOCK (tstate -> interp );
646+ stats_merge_all (true);
639647}
640648
641649static int
654662_Py_PrintSpecializationStats (int to_file )
655663{
656664 assert (to_file );
665+ stats_merge_all (false);
657666 PyThreadState * tstate = _PyThreadState_GET ();
658667 STATS_LOCK (tstate -> interp );
659668 PyStats * stats = tstate -> interp -> pystats_struct ;
@@ -721,11 +730,12 @@ _PyStats_ThreadInit(PyInterpreterState *interp, _PyThreadStateImpl *tstate)
721730{
722731 STATS_LOCK (interp );
723732 if (interp -> pystats_enabled ) {
724- interp -> pystats_struct = PyMem_RawCalloc (1 , sizeof (PyStats ));
725- if (interp -> pystats_struct == NULL ) {
733+ PyStats * s = PyMem_RawCalloc (1 , sizeof (PyStats ));
734+ if (s == NULL ) {
726735 STATS_UNLOCK (interp );
727736 return false;
728737 }
738+ FT_ATOMIC_STORE_PTR_RELAXED (interp -> pystats_struct , s );
729739 }
730740 STATS_UNLOCK (interp );
731741#ifdef Py_GIL_DISABLED
741751_PyStats_ThreadFini (_PyThreadStateImpl * tstate )
742752{
743753#ifdef Py_GIL_DISABLED
754+ STATS_LOCK (((PyThreadState * )tstate )-> interp );
744755 stats_merge_thread (tstate , false);
756+ STATS_UNLOCK (((PyThreadState * )tstate )-> interp );
745757 PyMem_RawFree (tstate -> pystats_struct );
746758#endif
747759}
@@ -751,8 +763,7 @@ _PyStats_Attach(_PyThreadStateImpl *tstate)
751763{
752764 PyStats * s ;
753765 PyInterpreterState * interp = ((PyThreadState * )tstate )-> interp ;
754- STATS_LOCK (interp );
755- if (interp -> pystats_enabled ) {
766+ if (FT_ATOMIC_LOAD_INT_RELAXED (interp -> pystats_enabled )) {
756767#ifdef Py_GIL_DISABLED
757768 s = tstate -> pystats_struct ;
758769#else
@@ -762,7 +773,6 @@ _PyStats_Attach(_PyThreadStateImpl *tstate)
762773 else {
763774 s = NULL ;
764775 }
765- STATS_UNLOCK (interp );
766776 // use correct TSS variable for thread
767777 tstate -> pystats_tss = & _Py_tss_stats ;
768778 // write to the tss variable for the 'ts' thread
0 commit comments