summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Droettboom <mdboom@gmail.com>2024-02-26 17:51:47 (GMT)
committerGitHub <noreply@github.com>2024-02-26 17:51:47 (GMT)
commitb05afdd5ec325bdb4cc89bb3be177ed577bea41f (patch)
treeecdb6276a76f5af92e3c3a9d249a5eb8361c9499
parent96c10c648565c7406d5606099dbbb937310c26dc (diff)
downloadcpython-b05afdd5ec325bdb4cc89bb3be177ed577bea41f.zip
cpython-b05afdd5ec325bdb4cc89bb3be177ed577bea41f.tar.gz
cpython-b05afdd5ec325bdb4cc89bb3be177ed577bea41f.tar.bz2
gh-115168: Add pystats counter for invalidated executors (GH-115169)
-rw-r--r--Include/cpython/optimizer.h4
-rw-r--r--Include/cpython/pystats.h1
-rw-r--r--Modules/_testinternalcapi.c2
-rw-r--r--Python/instrumentation.c6
-rw-r--r--Python/optimizer.c10
-rw-r--r--Python/optimizer_analysis.c2
-rw-r--r--Python/pylifecycle.c4
-rw-r--r--Python/pystate.c2
-rw-r--r--Python/specialize.c1
-rw-r--r--Python/sysmodule.c2
-rw-r--r--Tools/scripts/summarize_stats.py11
11 files changed, 31 insertions, 14 deletions
diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h
index fe54d1d..8fc9fb6 100644
--- a/Include/cpython/optimizer.h
+++ b/Include/cpython/optimizer.h
@@ -100,8 +100,8 @@ void _Py_ExecutorClear(_PyExecutorObject *);
void _Py_BloomFilter_Init(_PyBloomFilter *);
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
-PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj);
-extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp);
+PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation);
+extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation);
/* For testing */
PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void);
diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h
index db9aaed..887fbbe 100644
--- a/Include/cpython/pystats.h
+++ b/Include/cpython/pystats.h
@@ -115,6 +115,7 @@ typedef struct _optimization_stats {
uint64_t inner_loop;
uint64_t recursive_call;
uint64_t low_confidence;
+ uint64_t executors_invalidated;
UOpStats opcode[512];
uint64_t unsupported_opcode[256];
uint64_t trace_length_hist[_Py_UOP_HIST_SIZE];
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 0d23b18..5b714ca 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -1035,7 +1035,7 @@ static PyObject *
invalidate_executors(PyObject *self, PyObject *obj)
{
PyInterpreterState *interp = PyInterpreterState_Get();
- _Py_Executors_InvalidateDependency(interp, obj);
+ _Py_Executors_InvalidateDependency(interp, obj, 1);
Py_RETURN_NONE;
}
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
index 878d19f..6f1bc2e 100644
--- a/Python/instrumentation.c
+++ b/Python/instrumentation.c
@@ -1599,7 +1599,7 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
if (code->co_executors != NULL) {
_PyCode_Clear_Executors(code);
}
- _Py_Executors_InvalidateDependency(interp, code);
+ _Py_Executors_InvalidateDependency(interp, code, 1);
int code_len = (int)Py_SIZE(code);
/* Exit early to avoid creating instrumentation
* data for potential statically allocated code
@@ -1820,7 +1820,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
return -1;
}
set_global_version(tstate, new_version);
- _Py_Executors_InvalidateAll(interp);
+ _Py_Executors_InvalidateAll(interp, 1);
return instrument_all_executing_code_objects(interp);
}
@@ -1850,7 +1850,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent
/* Force instrumentation update */
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
}
- _Py_Executors_InvalidateDependency(interp, code);
+ _Py_Executors_InvalidateDependency(interp, code, 1);
if (_Py_Instrument(code, interp)) {
return -1;
}
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 6b2ba3a..c04ee17 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -1348,7 +1348,7 @@ _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj)
* May cause other executors to be invalidated as well
*/
void
-_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
+_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation)
{
_PyBloomFilter obj_filter;
_Py_BloomFilter_Init(&obj_filter);
@@ -1360,6 +1360,9 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
_PyExecutorObject *next = exec->vm_data.links.next;
if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) {
_Py_ExecutorClear(exec);
+ if (is_invalidation) {
+ OPT_STAT_INC(executors_invalidated);
+ }
}
exec = next;
}
@@ -1367,7 +1370,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
/* Invalidate all executors */
void
-_Py_Executors_InvalidateAll(PyInterpreterState *interp)
+_Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
{
while (interp->executor_list_head) {
_PyExecutorObject *executor = interp->executor_list_head;
@@ -1378,5 +1381,8 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp)
else {
_Py_ExecutorClear(executor);
}
+ if (is_invalidation) {
+ OPT_STAT_INC(executors_invalidated);
+ }
}
}
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
index 1a9e829..e975129 100644
--- a/Python/optimizer_analysis.c
+++ b/Python/optimizer_analysis.c
@@ -405,7 +405,7 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict,
{
RARE_EVENT_STAT_INC(watched_globals_modification);
assert(get_mutations(dict) < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS);
- _Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), dict);
+ _Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), dict, 1);
increment_mutations(dict);
PyDict_Unwatch(GLOBALS_WATCHER_ID, dict);
return 0;
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 0448734..3a2c0a4 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -612,7 +612,7 @@ builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, Py
{
PyInterpreterState *interp = _PyInterpreterState_GET();
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
- _Py_Executors_InvalidateAll(interp);
+ _Py_Executors_InvalidateAll(interp, 1);
}
RARE_EVENT_INTERP_INC(interp, builtin_dict);
return 0;
@@ -1628,7 +1628,7 @@ finalize_modules(PyThreadState *tstate)
PyInterpreterState *interp = tstate->interp;
// Invalidate all executors and turn off tier 2 optimizer
- _Py_Executors_InvalidateAll(interp);
+ _Py_Executors_InvalidateAll(interp, 0);
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
Py_XDECREF(old);
diff --git a/Python/pystate.c b/Python/pystate.c
index bb8e24c..a80c1b7 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -2666,7 +2666,7 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp,
return;
}
if (eval_frame != NULL) {
- _Py_Executors_InvalidateAll(interp);
+ _Py_Executors_InvalidateAll(interp, 1);
}
RARE_EVENT_INC(set_eval_frame_func);
interp->eval_frame = eval_frame;
diff --git a/Python/specialize.c b/Python/specialize.c
index 871979d..f83d8a9 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -236,6 +236,7 @@ print_optimization_stats(FILE *out, OptimizationStats *stats)
fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop);
fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call);
fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence);
+ fprintf(out, "Executors invalidated: %" PRIu64 "\n", stats->executors_invalidated);
print_histogram(out, "Trace length", stats->trace_length_hist);
print_histogram(out, "Trace run length", stats->trace_run_length_hist);
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 69b6d88..1bfd031 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -2138,7 +2138,7 @@ sys__clear_internal_caches_impl(PyObject *module)
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
{
PyInterpreterState *interp = _PyInterpreterState_GET();
- _Py_Executors_InvalidateAll(interp);
+ _Py_Executors_InvalidateAll(interp, 0);
PyType_ClearCache();
Py_RETURN_NONE;
}
diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py
index 6b60b59..2925e09 100644
--- a/Tools/scripts/summarize_stats.py
+++ b/Tools/scripts/summarize_stats.py
@@ -451,6 +451,7 @@ class Stats:
inner_loop = self._data["Optimization inner loop"]
recursive_call = self._data["Optimization recursive call"]
low_confidence = self._data["Optimization low confidence"]
+ executors_invalidated = self._data["Executors invalidated"]
return {
Doc(
@@ -493,11 +494,19 @@ class Stats:
"A trace is abandoned because the likelihood of the jump to top being taken "
"is too low.",
): (low_confidence, attempts),
+ Doc(
+ "Executors invalidated",
+ "The number of executors that were invalidated due to watched "
+ "dictionary changes.",
+ ): (executors_invalidated, created),
Doc("Traces executed", "The number of traces that were executed"): (
executed,
None,
),
- Doc("Uops executed", "The total number of uops (micro-operations) that were executed"): (
+ Doc(
+ "Uops executed",
+ "The total number of uops (micro-operations) that were executed",
+ ): (
uops,
executed,
),