forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-108753: Enhance pystats (python#108754)
Statistics gathering is now off by default. Use the "-X pystats" command line option or set the new PYTHONSTATS environment variable to 1 to turn statistics gathering on at Python startup. Statistics are no longer dumped at exit if statistics gathering was off or statistics have been cleared. Changes: * Add PYTHONSTATS environment variable. * sys._stats_dump() now returns False if statistics are not dumped because they are all equal to zero. * Add PyConfig._pystats member. * Add tests on sys functions and on setting PyConfig._pystats to 1. * Add Include/cpython/pystats.h and Include/internal/pycore_pystats.h header files. * Rename '_py_stats' variable to '_Py_stats'. * Exclude Include/cpython/pystats.h from the Py_LIMITED_API. * Move pystats.h include from object.h to Python.h. * Add _Py_StatsOn() and _Py_StatsOff() functions. Remove '_py_stats_struct' variable from the API: make it static in specialize.c. * Document API in Include/pystats.h and Include/cpython/pystats.h. * Complete pystats documentation in Doc/using/configure.rst. * Don't write "all zeros" stats: if _stats_off() and _stats_clear() or _stats_dump() were called. * _PyEval_Fini() now always call _Py_PrintSpecializationStats() which does nothing if stats are all zeros. Co-authored-by: Michael Droettboom <[email protected]>
- Loading branch information
Showing
19 changed files
with
402 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Statistics on Python performance. | ||
// | ||
// API: | ||
// | ||
// - _Py_INCREF_STAT_INC() and _Py_DECREF_STAT_INC() used by Py_INCREF() | ||
// and Py_DECREF(). | ||
// - _Py_stats variable | ||
// | ||
// Functions of the sys module: | ||
// | ||
// - sys._stats_on() | ||
// - sys._stats_off() | ||
// - sys._stats_clear() | ||
// - sys._stats_dump() | ||
// | ||
// Python must be built with ./configure --enable-pystats to define the | ||
// Py_STATS macro. | ||
// | ||
// Define _PY_INTERPRETER macro to increment interpreter_increfs and | ||
// interpreter_decrefs. Otherwise, increment increfs and decrefs. | ||
|
||
#ifndef Py_CPYTHON_PYSTATS_H | ||
# error "this header file must not be included directly" | ||
#endif | ||
|
||
#define SPECIALIZATION_FAILURE_KINDS 36 | ||
|
||
/* Stats for determining who is calling PyEval_EvalFrame */ | ||
#define EVAL_CALL_TOTAL 0 | ||
#define EVAL_CALL_VECTOR 1 | ||
#define EVAL_CALL_GENERATOR 2 | ||
#define EVAL_CALL_LEGACY 3 | ||
#define EVAL_CALL_FUNCTION_VECTORCALL 4 | ||
#define EVAL_CALL_BUILD_CLASS 5 | ||
#define EVAL_CALL_SLOT 6 | ||
#define EVAL_CALL_FUNCTION_EX 7 | ||
#define EVAL_CALL_API 8 | ||
#define EVAL_CALL_METHOD 9 | ||
|
||
#define EVAL_CALL_KINDS 10 | ||
|
||
typedef struct _specialization_stats { | ||
uint64_t success; | ||
uint64_t failure; | ||
uint64_t hit; | ||
uint64_t deferred; | ||
uint64_t miss; | ||
uint64_t deopt; | ||
uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS]; | ||
} SpecializationStats; | ||
|
||
typedef struct _opcode_stats { | ||
SpecializationStats specialization; | ||
uint64_t execution_count; | ||
uint64_t pair_count[256]; | ||
} OpcodeStats; | ||
|
||
typedef struct _call_stats { | ||
uint64_t inlined_py_calls; | ||
uint64_t pyeval_calls; | ||
uint64_t frames_pushed; | ||
uint64_t frame_objects_created; | ||
uint64_t eval_calls[EVAL_CALL_KINDS]; | ||
} CallStats; | ||
|
||
typedef struct _object_stats { | ||
uint64_t increfs; | ||
uint64_t decrefs; | ||
uint64_t interpreter_increfs; | ||
uint64_t interpreter_decrefs; | ||
uint64_t allocations; | ||
uint64_t allocations512; | ||
uint64_t allocations4k; | ||
uint64_t allocations_big; | ||
uint64_t frees; | ||
uint64_t to_freelist; | ||
uint64_t from_freelist; | ||
uint64_t new_values; | ||
uint64_t dict_materialized_on_request; | ||
uint64_t dict_materialized_new_key; | ||
uint64_t dict_materialized_too_big; | ||
uint64_t dict_materialized_str_subclass; | ||
uint64_t dict_dematerialized; | ||
uint64_t type_cache_hits; | ||
uint64_t type_cache_misses; | ||
uint64_t type_cache_dunder_hits; | ||
uint64_t type_cache_dunder_misses; | ||
uint64_t type_cache_collisions; | ||
uint64_t optimization_attempts; | ||
uint64_t optimization_traces_created; | ||
uint64_t optimization_traces_executed; | ||
uint64_t optimization_uops_executed; | ||
/* Temporary value used during GC */ | ||
uint64_t object_visits; | ||
} ObjectStats; | ||
|
||
typedef struct _gc_stats { | ||
uint64_t collections; | ||
uint64_t object_visits; | ||
uint64_t objects_collected; | ||
} GCStats; | ||
|
||
typedef struct _stats { | ||
OpcodeStats opcode_stats[256]; | ||
CallStats call_stats; | ||
ObjectStats object_stats; | ||
GCStats *gc_stats; | ||
} PyStats; | ||
|
||
|
||
// Export for shared extensions like 'math' | ||
PyAPI_DATA(PyStats*) _Py_stats; | ||
|
||
#ifdef _PY_INTERPRETER | ||
# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_increfs++; } while (0) | ||
# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_decrefs++; } while (0) | ||
#else | ||
# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.increfs++; } while (0) | ||
# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.decrefs++; } while (0) | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef Py_INTERNAL_PYSTATS_H | ||
#define Py_INTERNAL_PYSTATS_H | ||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#ifndef Py_BUILD_CORE | ||
# error "this header requires Py_BUILD_CORE define" | ||
#endif | ||
|
||
#ifdef Py_STATS | ||
extern void _Py_StatsOn(void); | ||
extern void _Py_StatsOff(void); | ||
extern void _Py_StatsClear(void); | ||
extern int _Py_PrintSpecializationStats(int to_file); | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif // !Py_INTERNAL_PYSTATS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,124 +1,26 @@ | ||
|
||
// Statistics on Python performance (public API). | ||
// | ||
// Define _Py_INCREF_STAT_INC() and _Py_DECREF_STAT_INC() used by Py_INCREF() | ||
// and Py_DECREF(). | ||
// | ||
// See Include/cpython/pystats.h for the full API. | ||
|
||
#ifndef Py_PYSTATS_H | ||
#define Py_PYSTATS_H | ||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#ifdef Py_STATS | ||
|
||
#define SPECIALIZATION_FAILURE_KINDS 36 | ||
|
||
/* Stats for determining who is calling PyEval_EvalFrame */ | ||
#define EVAL_CALL_TOTAL 0 | ||
#define EVAL_CALL_VECTOR 1 | ||
#define EVAL_CALL_GENERATOR 2 | ||
#define EVAL_CALL_LEGACY 3 | ||
#define EVAL_CALL_FUNCTION_VECTORCALL 4 | ||
#define EVAL_CALL_BUILD_CLASS 5 | ||
#define EVAL_CALL_SLOT 6 | ||
#define EVAL_CALL_FUNCTION_EX 7 | ||
#define EVAL_CALL_API 8 | ||
#define EVAL_CALL_METHOD 9 | ||
|
||
#define EVAL_CALL_KINDS 10 | ||
|
||
typedef struct _specialization_stats { | ||
uint64_t success; | ||
uint64_t failure; | ||
uint64_t hit; | ||
uint64_t deferred; | ||
uint64_t miss; | ||
uint64_t deopt; | ||
uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS]; | ||
} SpecializationStats; | ||
|
||
typedef struct _opcode_stats { | ||
SpecializationStats specialization; | ||
uint64_t execution_count; | ||
uint64_t pair_count[256]; | ||
} OpcodeStats; | ||
|
||
typedef struct _call_stats { | ||
uint64_t inlined_py_calls; | ||
uint64_t pyeval_calls; | ||
uint64_t frames_pushed; | ||
uint64_t frame_objects_created; | ||
uint64_t eval_calls[EVAL_CALL_KINDS]; | ||
} CallStats; | ||
|
||
typedef struct _object_stats { | ||
uint64_t increfs; | ||
uint64_t decrefs; | ||
uint64_t interpreter_increfs; | ||
uint64_t interpreter_decrefs; | ||
uint64_t allocations; | ||
uint64_t allocations512; | ||
uint64_t allocations4k; | ||
uint64_t allocations_big; | ||
uint64_t frees; | ||
uint64_t to_freelist; | ||
uint64_t from_freelist; | ||
uint64_t new_values; | ||
uint64_t dict_materialized_on_request; | ||
uint64_t dict_materialized_new_key; | ||
uint64_t dict_materialized_too_big; | ||
uint64_t dict_materialized_str_subclass; | ||
uint64_t dict_dematerialized; | ||
uint64_t type_cache_hits; | ||
uint64_t type_cache_misses; | ||
uint64_t type_cache_dunder_hits; | ||
uint64_t type_cache_dunder_misses; | ||
uint64_t type_cache_collisions; | ||
uint64_t optimization_attempts; | ||
uint64_t optimization_traces_created; | ||
uint64_t optimization_traces_executed; | ||
uint64_t optimization_uops_executed; | ||
/* Temporary value used during GC */ | ||
uint64_t object_visits; | ||
} ObjectStats; | ||
|
||
typedef struct _gc_stats { | ||
uint64_t collections; | ||
uint64_t object_visits; | ||
uint64_t objects_collected; | ||
} GCStats; | ||
|
||
typedef struct _stats { | ||
OpcodeStats opcode_stats[256]; | ||
CallStats call_stats; | ||
ObjectStats object_stats; | ||
GCStats *gc_stats; | ||
} PyStats; | ||
|
||
|
||
PyAPI_DATA(PyStats) _py_stats_struct; | ||
PyAPI_DATA(PyStats *) _py_stats; | ||
|
||
extern void _Py_StatsClear(void); | ||
extern void _Py_PrintSpecializationStats(int to_file); | ||
|
||
#ifdef _PY_INTERPRETER | ||
|
||
#define _Py_INCREF_STAT_INC() do { if (_py_stats) _py_stats->object_stats.interpreter_increfs++; } while (0) | ||
#define _Py_DECREF_STAT_INC() do { if (_py_stats) _py_stats->object_stats.interpreter_decrefs++; } while (0) | ||
|
||
#if defined(Py_STATS) && !defined(Py_LIMITED_API) | ||
# define Py_CPYTHON_PYSTATS_H | ||
# include "cpython/pystats.h" | ||
# undef Py_CPYTHON_PYSTATS_H | ||
#else | ||
|
||
#define _Py_INCREF_STAT_INC() do { if (_py_stats) _py_stats->object_stats.increfs++; } while (0) | ||
#define _Py_DECREF_STAT_INC() do { if (_py_stats) _py_stats->object_stats.decrefs++; } while (0) | ||
|
||
#endif | ||
|
||
#else | ||
|
||
#define _Py_INCREF_STAT_INC() ((void)0) | ||
#define _Py_DECREF_STAT_INC() ((void)0) | ||
|
||
# define _Py_INCREF_STAT_INC() ((void)0) | ||
# define _Py_DECREF_STAT_INC() ((void)0) | ||
#endif // !Py_STATS | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
#endif /* !Py_PYSTATs_H */ | ||
#endif // !Py_PYSTATS_H |
Oops, something went wrong.