Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8144661

Browse filesBrowse files
authored
GH-113710: Fix updating of dict version tag and add watched dict stats (GH-115221)
1 parent 93ac78a commit 8144661
Copy full SHA for 8144661

File tree

Expand file treeCollapse file tree

6 files changed

+22
-23
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+22
-23
lines changed

‎Include/cpython/pystats.h

Copy file name to clipboardExpand all lines: Include/cpython/pystats.h
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ typedef struct _rare_event_stats {
133133
uint64_t builtin_dict;
134134
/* Modifying a function, e.g. func.__defaults__ = ..., etc. */
135135
uint64_t func_modification;
136+
/* Modifying a dict that is being watched */
137+
uint64_t watched_dict_modification;
138+
uint64_t watched_globals_modification;
136139
} RareEventStats;
137140

138141
typedef struct _stats {

‎Include/internal/pycore_dict.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_dict.h
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) {
209209

210210
#define DICT_VERSION_INCREMENT (1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS))
211211
#define DICT_WATCHER_MASK ((1 << DICT_MAX_WATCHERS) - 1)
212+
#define DICT_WATCHER_AND_MODIFICATION_MASK ((1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS)) - 1)
212213

213214
#ifdef Py_GIL_DISABLED
214215
#define DICT_NEXT_VERSION(INTERP) \
@@ -236,10 +237,10 @@ _PyDict_NotifyEvent(PyInterpreterState *interp,
236237
assert(Py_REFCNT((PyObject*)mp) > 0);
237238
int watcher_bits = mp->ma_version_tag & DICT_WATCHER_MASK;
238239
if (watcher_bits) {
240+
RARE_EVENT_STAT_INC(watched_dict_modification);
239241
_PyDict_SendEvent(watcher_bits, event, mp, key, value);
240-
return DICT_NEXT_VERSION(interp) | watcher_bits;
241242
}
242-
return DICT_NEXT_VERSION(interp);
243+
return DICT_NEXT_VERSION(interp) | (mp->ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK);
243244
}
244245

245246
extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values);

‎Python/optimizer_analysis.c

Copy file name to clipboardExpand all lines: Python/optimizer_analysis.c
+12-19Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,23 @@ increment_mutations(PyObject* dict) {
2828
d->ma_version_tag += (1 << DICT_MAX_WATCHERS);
2929
}
3030

31+
/* The first two dict watcher IDs are reserved for CPython,
32+
* so we don't need to check that they haven't been used */
33+
#define BUILTINS_WATCHER_ID 0
34+
#define GLOBALS_WATCHER_ID 1
35+
3136
static int
3237
globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict,
3338
PyObject* key, PyObject* new_value)
3439
{
35-
if (event == PyDict_EVENT_CLONED) {
36-
return 0;
37-
}
38-
uint64_t watched_mutations = get_mutations(dict);
39-
if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) {
40-
_Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), dict);
41-
increment_mutations(dict);
42-
}
43-
else {
44-
PyDict_Unwatch(1, dict);
45-
}
40+
RARE_EVENT_STAT_INC(watched_globals_modification);
41+
assert(get_mutations(dict) < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS);
42+
_Py_Executors_InvalidateDependency(_PyInterpreterState_GET(), dict);
43+
increment_mutations(dict);
44+
PyDict_Unwatch(GLOBALS_WATCHER_ID, dict);
4645
return 0;
4746
}
4847

49-
5048
static void
5149
global_to_const(_PyUOpInstruction *inst, PyObject *obj)
5250
{
@@ -82,11 +80,6 @@ incorrect_keys(_PyUOpInstruction *inst, PyObject *obj)
8280
return 0;
8381
}
8482

85-
/* The first two dict watcher IDs are reserved for CPython,
86-
* so we don't need to check that they haven't been used */
87-
#define BUILTINS_WATCHER_ID 0
88-
#define GLOBALS_WATCHER_ID 1
89-
9083
/* Returns 1 if successfully optimized
9184
* 0 if the trace is not suitable for optimization (yet)
9285
* -1 if there was an error. */
@@ -117,8 +110,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
117110
uint32_t builtins_watched = 0;
118111
uint32_t globals_checked = 0;
119112
uint32_t globals_watched = 0;
120-
if (interp->dict_state.watchers[1] == NULL) {
121-
interp->dict_state.watchers[1] = globals_watcher_callback;
113+
if (interp->dict_state.watchers[GLOBALS_WATCHER_ID] == NULL) {
114+
interp->dict_state.watchers[GLOBALS_WATCHER_ID] = globals_watcher_callback;
122115
}
123116
for (int pc = 0; pc < buffer_size; pc++) {
124117
_PyUOpInstruction *inst = &buffer[pc];

‎Python/pylifecycle.c

Copy file name to clipboardExpand all lines: Python/pylifecycle.c
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ static int
611611
builtins_dict_watcher(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)
612612
{
613613
PyInterpreterState *interp = _PyInterpreterState_GET();
614-
if (event != PyDict_EVENT_CLONED && interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
614+
if (interp->rare_events.builtin_dict < _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
615615
_Py_Executors_InvalidateAll(interp);
616616
}
617617
RARE_EVENT_INTERP_INC(interp, builtin_dict);

‎Python/specialize.c

Copy file name to clipboardExpand all lines: Python/specialize.c
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ print_rare_event_stats(FILE *out, RareEventStats *stats)
275275
fprintf(out, "Rare event (set_eval_frame_func): %" PRIu64 "\n", stats->set_eval_frame_func);
276276
fprintf(out, "Rare event (builtin_dict): %" PRIu64 "\n", stats->builtin_dict);
277277
fprintf(out, "Rare event (func_modification): %" PRIu64 "\n", stats->func_modification);
278+
fprintf(out, "Rare event (watched_dict_modification): %" PRIu64 "\n", stats->watched_dict_modification);
279+
fprintf(out, "Rare event (watched_globals_modification): %" PRIu64 "\n", stats->watched_globals_modification);
278280
}
279281

280282
static void

‎Tools/scripts/summarize_stats.py

Copy file name to clipboardExpand all lines: Tools/scripts/summarize_stats.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ def get_histogram(self, prefix: str) -> list[tuple[int, int]]:
415415
def get_rare_events(self) -> list[tuple[str, int]]:
416416
prefix = "Rare event "
417417
return [
418-
(key[len(prefix) + 1:-1], val)
418+
(key[len(prefix) + 1:-1].replace("_", " "), val)
419419
for key, val in self._data.items()
420420
if key.startswith(prefix)
421421
]

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.