summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
Diffstat (limited to 'Include')
-rw-r--r--Include/cpython/initconfig.h5
-rw-r--r--Include/cpython/pystats.h120
-rw-r--r--Include/internal/pycore_code.h18
-rw-r--r--Include/internal/pycore_pystats.h21
-rw-r--r--Include/pystats.h124
5 files changed, 168 insertions, 120 deletions
diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h
index 7fb7a98..ee13046 100644
--- a/Include/cpython/initconfig.h
+++ b/Include/cpython/initconfig.h
@@ -215,6 +215,11 @@ typedef struct PyConfig {
// If non-zero, we believe we're running from a source tree.
int _is_python_build;
+
+#ifdef Py_STATS
+ // If non-zero, turns on statistics gathering.
+ int _pystats;
+#endif
} PyConfig;
PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config);
diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h
new file mode 100644
index 0000000..150e16f
--- /dev/null
+++ b/Include/cpython/pystats.h
@@ -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
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index f5127a8..7c66290 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -268,17 +268,17 @@ extern int _PyStaticCode_Init(PyCodeObject *co);
#ifdef Py_STATS
-#define STAT_INC(opname, name) do { if (_py_stats) _py_stats->opcode_stats[opname].specialization.name++; } while (0)
-#define STAT_DEC(opname, name) do { if (_py_stats) _py_stats->opcode_stats[opname].specialization.name--; } while (0)
-#define OPCODE_EXE_INC(opname) do { if (_py_stats) _py_stats->opcode_stats[opname].execution_count++; } while (0)
-#define CALL_STAT_INC(name) do { if (_py_stats) _py_stats->call_stats.name++; } while (0)
-#define OBJECT_STAT_INC(name) do { if (_py_stats) _py_stats->object_stats.name++; } while (0)
+#define STAT_INC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name++; } while (0)
+#define STAT_DEC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name--; } while (0)
+#define OPCODE_EXE_INC(opname) do { if (_Py_stats) _Py_stats->opcode_stats[opname].execution_count++; } while (0)
+#define CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.name++; } while (0)
+#define OBJECT_STAT_INC(name) do { if (_Py_stats) _Py_stats->object_stats.name++; } while (0)
#define OBJECT_STAT_INC_COND(name, cond) \
- do { if (_py_stats && cond) _py_stats->object_stats.name++; } while (0)
-#define EVAL_CALL_STAT_INC(name) do { if (_py_stats) _py_stats->call_stats.eval_calls[name]++; } while (0)
+ do { if (_Py_stats && cond) _Py_stats->object_stats.name++; } while (0)
+#define EVAL_CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.eval_calls[name]++; } while (0)
#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) \
- do { if (_py_stats && PyFunction_Check(callable)) _py_stats->call_stats.eval_calls[name]++; } while (0)
-#define GC_STAT_ADD(gen, name, n) do { if (_py_stats) _py_stats->gc_stats[(gen)].name += (n); } while (0)
+ do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0)
+#define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0)
// Export for '_opcode' shared extension
PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
diff --git a/Include/internal/pycore_pystats.h b/Include/internal/pycore_pystats.h
new file mode 100644
index 0000000..f8af398
--- /dev/null
+++ b/Include/internal/pycore_pystats.h
@@ -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
diff --git a/Include/pystats.h b/Include/pystats.h
index b195759..acfa322 100644
--- a/Include/pystats.h
+++ b/Include/pystats.h
@@ -1,4 +1,9 @@
-
+// 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
@@ -6,119 +11,16 @@
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