mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-115168: Add pystats counter for invalidated executors (GH-115169)
This commit is contained in:
parent
96c10c6485
commit
b05afdd5ec
11 changed files with 31 additions and 14 deletions
|
@ -100,8 +100,8 @@ void _Py_ExecutorClear(_PyExecutorObject *);
|
||||||
void _Py_BloomFilter_Init(_PyBloomFilter *);
|
void _Py_BloomFilter_Init(_PyBloomFilter *);
|
||||||
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);
|
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);
|
||||||
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
|
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
|
||||||
PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj);
|
PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation);
|
||||||
extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp);
|
extern void _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation);
|
||||||
|
|
||||||
/* For testing */
|
/* For testing */
|
||||||
PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void);
|
PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void);
|
||||||
|
|
|
@ -115,6 +115,7 @@ typedef struct _optimization_stats {
|
||||||
uint64_t inner_loop;
|
uint64_t inner_loop;
|
||||||
uint64_t recursive_call;
|
uint64_t recursive_call;
|
||||||
uint64_t low_confidence;
|
uint64_t low_confidence;
|
||||||
|
uint64_t executors_invalidated;
|
||||||
UOpStats opcode[512];
|
UOpStats opcode[512];
|
||||||
uint64_t unsupported_opcode[256];
|
uint64_t unsupported_opcode[256];
|
||||||
uint64_t trace_length_hist[_Py_UOP_HIST_SIZE];
|
uint64_t trace_length_hist[_Py_UOP_HIST_SIZE];
|
||||||
|
|
|
@ -1035,7 +1035,7 @@ static PyObject *
|
||||||
invalidate_executors(PyObject *self, PyObject *obj)
|
invalidate_executors(PyObject *self, PyObject *obj)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
_Py_Executors_InvalidateDependency(interp, obj);
|
_Py_Executors_InvalidateDependency(interp, obj, 1);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1599,7 +1599,7 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
|
||||||
if (code->co_executors != NULL) {
|
if (code->co_executors != NULL) {
|
||||||
_PyCode_Clear_Executors(code);
|
_PyCode_Clear_Executors(code);
|
||||||
}
|
}
|
||||||
_Py_Executors_InvalidateDependency(interp, code);
|
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||||
int code_len = (int)Py_SIZE(code);
|
int code_len = (int)Py_SIZE(code);
|
||||||
/* Exit early to avoid creating instrumentation
|
/* Exit early to avoid creating instrumentation
|
||||||
* data for potential statically allocated code
|
* data for potential statically allocated code
|
||||||
|
@ -1820,7 +1820,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_global_version(tstate, new_version);
|
set_global_version(tstate, new_version);
|
||||||
_Py_Executors_InvalidateAll(interp);
|
_Py_Executors_InvalidateAll(interp, 1);
|
||||||
return instrument_all_executing_code_objects(interp);
|
return instrument_all_executing_code_objects(interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1850,7 +1850,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent
|
||||||
/* Force instrumentation update */
|
/* Force instrumentation update */
|
||||||
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
|
code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT;
|
||||||
}
|
}
|
||||||
_Py_Executors_InvalidateDependency(interp, code);
|
_Py_Executors_InvalidateDependency(interp, code, 1);
|
||||||
if (_Py_Instrument(code, interp)) {
|
if (_Py_Instrument(code, interp)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1348,7 +1348,7 @@ _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj)
|
||||||
* May cause other executors to be invalidated as well
|
* May cause other executors to be invalidated as well
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
|
_Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation)
|
||||||
{
|
{
|
||||||
_PyBloomFilter obj_filter;
|
_PyBloomFilter obj_filter;
|
||||||
_Py_BloomFilter_Init(&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;
|
_PyExecutorObject *next = exec->vm_data.links.next;
|
||||||
if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) {
|
if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) {
|
||||||
_Py_ExecutorClear(exec);
|
_Py_ExecutorClear(exec);
|
||||||
|
if (is_invalidation) {
|
||||||
|
OPT_STAT_INC(executors_invalidated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exec = next;
|
exec = next;
|
||||||
}
|
}
|
||||||
|
@ -1367,7 +1370,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
|
||||||
|
|
||||||
/* Invalidate all executors */
|
/* Invalidate all executors */
|
||||||
void
|
void
|
||||||
_Py_Executors_InvalidateAll(PyInterpreterState *interp)
|
_Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
|
||||||
{
|
{
|
||||||
while (interp->executor_list_head) {
|
while (interp->executor_list_head) {
|
||||||
_PyExecutorObject *executor = interp->executor_list_head;
|
_PyExecutorObject *executor = interp->executor_list_head;
|
||||||
|
@ -1378,5 +1381,8 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp)
|
||||||
else {
|
else {
|
||||||
_Py_ExecutorClear(executor);
|
_Py_ExecutorClear(executor);
|
||||||
}
|
}
|
||||||
|
if (is_invalidation) {
|
||||||
|
OPT_STAT_INC(executors_invalidated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,7 +405,7 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict,
|
||||||
{
|
{
|
||||||
RARE_EVENT_STAT_INC(watched_globals_modification);
|
RARE_EVENT_STAT_INC(watched_globals_modification);
|
||||||
assert(get_mutations(dict) < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS);
|
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);
|
increment_mutations(dict);
|
||||||
PyDict_Unwatch(GLOBALS_WATCHER_ID, dict);
|
PyDict_Unwatch(GLOBALS_WATCHER_ID, dict);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -612,7 +612,7 @@ builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, Py
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
|
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);
|
RARE_EVENT_INTERP_INC(interp, builtin_dict);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1628,7 +1628,7 @@ finalize_modules(PyThreadState *tstate)
|
||||||
PyInterpreterState *interp = tstate->interp;
|
PyInterpreterState *interp = tstate->interp;
|
||||||
|
|
||||||
// Invalidate all executors and turn off tier 2 optimizer
|
// Invalidate all executors and turn off tier 2 optimizer
|
||||||
_Py_Executors_InvalidateAll(interp);
|
_Py_Executors_InvalidateAll(interp, 0);
|
||||||
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
_PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL);
|
||||||
Py_XDECREF(old);
|
Py_XDECREF(old);
|
||||||
|
|
||||||
|
|
|
@ -2666,7 +2666,7 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (eval_frame != NULL) {
|
if (eval_frame != NULL) {
|
||||||
_Py_Executors_InvalidateAll(interp);
|
_Py_Executors_InvalidateAll(interp, 1);
|
||||||
}
|
}
|
||||||
RARE_EVENT_INC(set_eval_frame_func);
|
RARE_EVENT_INC(set_eval_frame_func);
|
||||||
interp->eval_frame = eval_frame;
|
interp->eval_frame = eval_frame;
|
||||||
|
|
|
@ -236,6 +236,7 @@ print_optimization_stats(FILE *out, OptimizationStats *stats)
|
||||||
fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop);
|
fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop);
|
||||||
fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call);
|
fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call);
|
||||||
fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence);
|
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 length", stats->trace_length_hist);
|
||||||
print_histogram(out, "Trace run length", stats->trace_run_length_hist);
|
print_histogram(out, "Trace run length", stats->trace_run_length_hist);
|
||||||
|
|
|
@ -2138,7 +2138,7 @@ sys__clear_internal_caches_impl(PyObject *module)
|
||||||
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
_Py_Executors_InvalidateAll(interp);
|
_Py_Executors_InvalidateAll(interp, 0);
|
||||||
PyType_ClearCache();
|
PyType_ClearCache();
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -451,6 +451,7 @@ class Stats:
|
||||||
inner_loop = self._data["Optimization inner loop"]
|
inner_loop = self._data["Optimization inner loop"]
|
||||||
recursive_call = self._data["Optimization recursive call"]
|
recursive_call = self._data["Optimization recursive call"]
|
||||||
low_confidence = self._data["Optimization low confidence"]
|
low_confidence = self._data["Optimization low confidence"]
|
||||||
|
executors_invalidated = self._data["Executors invalidated"]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Doc(
|
Doc(
|
||||||
|
@ -493,11 +494,19 @@ class Stats:
|
||||||
"A trace is abandoned because the likelihood of the jump to top being taken "
|
"A trace is abandoned because the likelihood of the jump to top being taken "
|
||||||
"is too low.",
|
"is too low.",
|
||||||
): (low_confidence, attempts),
|
): (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"): (
|
Doc("Traces executed", "The number of traces that were executed"): (
|
||||||
executed,
|
executed,
|
||||||
None,
|
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,
|
uops,
|
||||||
executed,
|
executed,
|
||||||
),
|
),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue