Skip to content

Commit efd6236

Browse files
authored
bpo-46072: Add top level stats struct (GH-30169)
1 parent 396b583 commit efd6236

File tree

6 files changed

+154
-103
lines changed

6 files changed

+154
-103
lines changed

Include/internal/pycore_code.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,27 +281,40 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
281281

282282
#define SPECIALIZATION_FAILURE_KINDS 30
283283

284-
typedef struct _stats {
285-
uint64_t specialization_success;
286-
uint64_t specialization_failure;
284+
typedef struct _specialization_stats {
285+
uint64_t success;
286+
uint64_t failure;
287287
uint64_t hit;
288288
uint64_t deferred;
289289
uint64_t miss;
290290
uint64_t deopt;
291-
uint64_t unquickened;
292-
uint64_t specialization_failure_kinds[SPECIALIZATION_FAILURE_KINDS];
291+
uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS];
293292
} SpecializationStats;
294293

295-
extern SpecializationStats _specialization_stats[256];
296-
#define STAT_INC(opname, name) _specialization_stats[opname].name++
297-
#define STAT_DEC(opname, name) _specialization_stats[opname].name--
294+
typedef struct _opcode_stats {
295+
SpecializationStats specialization;
296+
uint64_t execution_count;
297+
uint64_t pair_count[256];
298+
} OpcodeStats;
299+
300+
typedef struct _stats {
301+
OpcodeStats opcode_stats[256];
302+
} PyStats;
303+
304+
extern PyStats _py_stats;
305+
306+
#define STAT_INC(opname, name) _py_stats.opcode_stats[opname].specialization.name++
307+
#define STAT_DEC(opname, name) _py_stats.opcode_stats[opname].specialization.name--
308+
#define OPCODE_EXE_INC(opname) _py_stats.opcode_stats[opname].execution_count++
309+
298310
void _Py_PrintSpecializationStats(int to_file);
299311

300312
PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
301313

302314
#else
303315
#define STAT_INC(opname, name) ((void)0)
304316
#define STAT_DEC(opname, name) ((void)0)
317+
#define OPCODE_EXE_INC(opname) ((void)0)
305318
#endif
306319

307320

Lib/opcode.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,10 @@ def jabs_op(name, op):
288288
"STORE_FAST__STORE_FAST",
289289
]
290290
_specialization_stats = [
291-
"specialization_success",
292-
"specialization_failure",
291+
"success",
292+
"failure",
293293
"hit",
294294
"deferred",
295295
"miss",
296296
"deopt",
297-
"unquickened",
298297
]

Lib/test/test__opcode.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ def test_specialization_stats(self):
8282
self.assertCountEqual(stats.keys(), specialized_opcodes)
8383
self.assertCountEqual(
8484
stats['load_attr'].keys(),
85-
stat_names + ['specialization_failure_kinds'])
85+
stat_names + ['failure_kinds'])
8686
for sn in stat_names:
8787
self.assertIsInstance(stats['load_attr'][sn], int)
8888
self.assertIsInstance(
89-
stats['load_attr']['specialization_failure_kinds'],
89+
stats['load_attr']['failure_kinds'],
9090
tuple)
91-
for v in stats['load_attr']['specialization_failure_kinds']:
91+
for v in stats['load_attr']['failure_kinds']:
9292
self.assertIsInstance(v, int)
9393

9494

Python/ceval.c

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,13 +1290,17 @@ eval_frame_handle_pending(PyThreadState *tstate)
12901290
#define USE_COMPUTED_GOTOS 0
12911291
#endif
12921292

1293-
#define INSTRUCTION_START() frame->f_lasti = INSTR_OFFSET(); next_instr++
1293+
#ifdef Py_STATS
1294+
#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++; OPCODE_EXE_INC(op);
1295+
#else
1296+
#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++
1297+
#endif
12941298

12951299
#if USE_COMPUTED_GOTOS
1296-
#define TARGET(op) TARGET_##op: INSTRUCTION_START();
1300+
#define TARGET(op) TARGET_##op: INSTRUCTION_START(op);
12971301
#define DISPATCH_GOTO() goto *opcode_targets[opcode]
12981302
#else
1299-
#define TARGET(op) case op: INSTRUCTION_START();
1303+
#define TARGET(op) case op: INSTRUCTION_START(op);
13001304
#define DISPATCH_GOTO() goto dispatch_opcode
13011305
#endif
13021306

@@ -1416,7 +1420,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
14161420
opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \
14171421
if (opcode == op) { \
14181422
oparg = _Py_OPARG(word); \
1419-
INSTRUCTION_START(); \
1423+
INSTRUCTION_START(op); \
14201424
goto PREDICT_ID(op); \
14211425
} \
14221426
} while(0)
@@ -2186,7 +2190,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21862190

21872191
TARGET(BINARY_SUBSCR) {
21882192
PREDICTED(BINARY_SUBSCR);
2189-
STAT_INC(BINARY_SUBSCR, unquickened);
21902193
PyObject *sub = POP();
21912194
PyObject *container = TOP();
21922195
PyObject *res = PyObject_GetItem(container, sub);
@@ -2214,7 +2217,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22142217
cache->adaptive.counter--;
22152218
assert(cache->adaptive.original_oparg == 0);
22162219
/* No need to set oparg here; it isn't used by BINARY_SUBSCR */
2217-
STAT_DEC(BINARY_SUBSCR, unquickened);
22182220
JUMP_TO_INSTRUCTION(BINARY_SUBSCR);
22192221
}
22202222
}
@@ -2339,7 +2341,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
23392341

23402342
TARGET(STORE_SUBSCR) {
23412343
PREDICTED(STORE_SUBSCR);
2342-
STAT_INC(STORE_SUBSCR, unquickened);
23432344
PyObject *sub = TOP();
23442345
PyObject *container = SECOND();
23452346
PyObject *v = THIRD();
@@ -2369,7 +2370,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
23692370
STAT_INC(STORE_SUBSCR, deferred);
23702371
// oparg is the adaptive cache counter
23712372
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
2372-
STAT_DEC(STORE_SUBSCR, unquickened);
23732373
JUMP_TO_INSTRUCTION(STORE_SUBSCR);
23742374
}
23752375
}
@@ -2933,7 +2933,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
29332933

29342934
TARGET(STORE_ATTR) {
29352935
PREDICTED(STORE_ATTR);
2936-
STAT_INC(STORE_ATTR, unquickened);
29372936
PyObject *name = GETITEM(names, oparg);
29382937
PyObject *owner = TOP();
29392938
PyObject *v = SECOND();
@@ -3049,7 +3048,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
30493048

30503049
TARGET(LOAD_GLOBAL) {
30513050
PREDICTED(LOAD_GLOBAL);
3052-
STAT_INC(LOAD_GLOBAL, unquickened);
30533051
PyObject *name = GETITEM(names, oparg);
30543052
PyObject *v;
30553053
if (PyDict_CheckExact(GLOBALS())
@@ -3112,7 +3110,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
31123110
STAT_INC(LOAD_GLOBAL, deferred);
31133111
cache->adaptive.counter--;
31143112
oparg = cache->adaptive.original_oparg;
3115-
STAT_DEC(LOAD_GLOBAL, unquickened);
31163113
JUMP_TO_INSTRUCTION(LOAD_GLOBAL);
31173114
}
31183115
}
@@ -3532,7 +3529,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
35323529

35333530
TARGET(LOAD_ATTR) {
35343531
PREDICTED(LOAD_ATTR);
3535-
STAT_INC(LOAD_ATTR, unquickened);
35363532
PyObject *name = GETITEM(names, oparg);
35373533
PyObject *owner = TOP();
35383534
PyObject *res = PyObject_GetAttr(owner, name);
@@ -3560,7 +3556,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
35603556
STAT_INC(LOAD_ATTR, deferred);
35613557
cache->adaptive.counter--;
35623558
oparg = cache->adaptive.original_oparg;
3563-
STAT_DEC(LOAD_ATTR, unquickened);
35643559
JUMP_TO_INSTRUCTION(LOAD_ATTR);
35653560
}
35663561
}
@@ -3663,7 +3658,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
36633658
STAT_INC(STORE_ATTR, deferred);
36643659
cache->adaptive.counter--;
36653660
oparg = cache->adaptive.original_oparg;
3666-
STAT_DEC(STORE_ATTR, unquickened);
36673661
JUMP_TO_INSTRUCTION(STORE_ATTR);
36683662
}
36693663
}
@@ -3754,7 +3748,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37543748

37553749
TARGET(COMPARE_OP) {
37563750
PREDICTED(COMPARE_OP);
3757-
STAT_INC(COMPARE_OP, unquickened);
37583751
assert(oparg <= Py_GE);
37593752
PyObject *right = POP();
37603753
PyObject *left = TOP();
@@ -3783,7 +3776,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37833776
STAT_INC(COMPARE_OP, deferred);
37843777
cache->adaptive.counter--;
37853778
oparg = cache->adaptive.original_oparg;
3786-
STAT_DEC(COMPARE_OP, unquickened);
37873779
JUMP_TO_INSTRUCTION(COMPARE_OP);
37883780
}
37893781
}
@@ -4438,7 +4430,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
44384430

44394431
TARGET(LOAD_METHOD) {
44404432
PREDICTED(LOAD_METHOD);
4441-
STAT_INC(LOAD_METHOD, unquickened);
44424433
/* Designed to work in tandem with CALL_METHOD. */
44434434
PyObject *name = GETITEM(names, oparg);
44444435
PyObject *obj = TOP();
@@ -4491,7 +4482,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
44914482
STAT_INC(LOAD_METHOD, deferred);
44924483
cache->adaptive.counter--;
44934484
oparg = cache->adaptive.original_oparg;
4494-
STAT_DEC(LOAD_METHOD, unquickened);
44954485
JUMP_TO_INSTRUCTION(LOAD_METHOD);
44964486
}
44974487
}
@@ -4617,7 +4607,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46174607
TARGET(CALL_NO_KW) {
46184608
PyObject *function;
46194609
PREDICTED(CALL_NO_KW);
4620-
STAT_INC(CALL_NO_KW, unquickened);
46214610
kwnames = NULL;
46224611
oparg += extra_args;
46234612
nargs = oparg;
@@ -5186,7 +5175,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
51865175

51875176
TARGET(BINARY_OP) {
51885177
PREDICTED(BINARY_OP);
5189-
STAT_INC(BINARY_OP, unquickened);
51905178
PyObject *rhs = POP();
51915179
PyObject *lhs = TOP();
51925180
assert(0 <= oparg);
@@ -5216,7 +5204,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
52165204
STAT_INC(BINARY_OP, deferred);
52175205
cache->adaptive.counter--;
52185206
oparg = cache->adaptive.original_oparg;
5219-
STAT_DEC(BINARY_OP, unquickened);
52205207
JUMP_TO_INSTRUCTION(BINARY_OP);
52215208
}
52225209
}
@@ -5301,7 +5288,6 @@ opname ## _miss: \
53015288
cache_backoff(cache); \
53025289
} \
53035290
oparg = cache->original_oparg; \
5304-
STAT_DEC(opname, unquickened); \
53055291
JUMP_TO_INSTRUCTION(opname); \
53065292
}
53075293

@@ -5317,7 +5303,6 @@ opname ## _miss: \
53175303
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
53185304
STAT_INC(opname, deopt); \
53195305
} \
5320-
STAT_DEC(opname, unquickened); \
53215306
JUMP_TO_INSTRUCTION(opname); \
53225307
}
53235308

0 commit comments

Comments
 (0)