8000 bpo-45527: Don't count cache hits, just misses. (GH-29092) · python/cpython@bc85eb7 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit bc85eb7

Browse files
authored
bpo-45527: Don't count cache hits, just misses. (GH-29092)
1 parent d89fb9a commit bc85eb7

File tree

3 files changed

+33
-107
lines changed

3 files changed

+33
-107
lines changed

Include/internal/pycore_code.h

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -253,53 +253,6 @@ PyAPI_FUNC(PyObject *) _PyCode_GetVarnames(PyCodeObject *);
253253
PyAPI_FUNC(PyObject *) _PyCode_GetCellvars(PyCodeObject *);
254254
PyAPI_FUNC(PyObject *) _PyCode_GetFreevars(PyCodeObject *);
255255

256-
257-
/* Cache hits and misses */
258-
259-
static inline uint8_t
260-
saturating_increment(uint8_t c)
261-
{
262-
return c<<1;
263-
}
264-
265-
static inline uint8_t
266-
saturating_decrement(uint8_t c)
267-
{
268-
return (c>>1) + 128;
269-
}
270-
271-
static inline uint8_t
272-
saturating_zero(void)
273-
{
274-
return 255;
275-
}
276-
277-
/* Starting value for saturating counter.
278-
* Technically this should be 1, but that is likely to
279-
* cause a bit of thrashing when we optimize then get an immediate miss.
280-
* We want to give the counter a change to stabilize, so we start at 3.
281-
*/
282-
static inline uint8_t
283-
saturating_start(void)
284-
{
285-
return saturating_zero()<<3;
286-
}
287-
288-
static inline void
289-
record_cache_hit(_PyAdaptiveEntry *entry) {
290-
entry->counter = saturating_increment(entry->counter);
291-
}
292-
293-
static inline void
294-
record_cache_miss(_PyAdaptiveEntry *entry) {
295-
entry->counter = saturating_decrement(entry->counter);
296-
}
297-
298-
static inline int
299-
too_many_cache_misses(_PyAdaptiveEntry *entry) {
300-
return entry->counter == saturating_zero();
301-
}
302-
303256
#define ADAPTIVE_CACHE_BACKOFF 64
304257

305258
static inline void

Python/ceval.c

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "pycore_abstract.h" // _PyIndex_Check()
1414
#include "pycore_call.h" // _PyObject_FastCallDictTstate()
1515
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
16-
#include "pycore_code.h" // saturating_increment()
16+
#include "pycore_code.h"
1717
#include "pycore_initconfig.h" // _PyStatus_OK()
1818
#include "pycore_long.h" // _PyLong_GetZero()
1919
#include "pycore_object.h" // _PyObject_GC_TRACK()
@@ -1452,11 +1452,6 @@ eval_frame_handle_pending(PyThreadState *tstate)
14521452

14531453
#define UPDATE_PREV_INSTR_OPARG(instr, oparg) ((uint8_t*)(instr))[-1] = (oparg)
14541454

1455-
static inline void
1456-
record_hit_inline(_Py_CODEUNIT *next_instr, int oparg)
1457-
{
1458-
UPDATE_PREV_INSTR_OPARG(next_instr, saturating_increment(oparg));
1459-
}
14601455

14611456
#define GLOBALS() frame->f_globals
14621457
#define BUILTINS() frame->f_builtins
@@ -1480,7 +1475,6 @@ record_hit_inline(_Py_CODEUNIT *next_instr, int oparg)
14801475
res = ep->me_value; \
14811476
DEOPT_IF(res == NULL, LOAD_##attr_or_method); \
14821477
STAT_INC(LOAD_##attr_or_method, hit); \
1483-
record_cache_hit(cache0); \
14841478
Py_INCREF(res);
14851479

14861480
static int
@@ -1976,7 +1970,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
19761970
DEOPT_IF(!PyLong_CheckExact(left), BINARY_MULTIPLY);
19771971
DEOPT_IF(!PyLong_CheckExact(right), BINARY_MULTIPLY);
19781972
STAT_INC(BINARY_MULTIPLY, hit);
1979-
record_hit_inline(next_instr, oparg);
19801973
PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
19811974
SET_SECOND(prod);
19821975
Py_DECREF(right);
@@ -1994,7 +1987,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
19941987
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_MULTIPLY);
19951988
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_MULTIPLY);
19961989
STAT_INC(BINARY_MULTIPLY, hit);
1997-
record_hit_inline(next_instr, oparg);
19981990
double dprod = ((PyFloatObject *)left)->ob_fval *
19991991
((PyFloatObject *)right)->ob_fval;
20001992
PyObject *prod = PyFloat_FromDouble(dprod);
@@ -2103,7 +2095,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21032095
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_ADD);
21042096
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_ADD);
21052097
STAT_INC(BINARY_ADD, hit);
2106-
record_hit_inline(next_instr, oparg);
21072098
PyObject *res = PyUnicode_Concat(left, right);
21082099
STACK_SHRINK(1);
21092100
SET_TOP(res);
@@ -2132,7 +2123,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21322123
PyObject *var = GETLOCAL(next_oparg);
21332124
DEOPT_IF(var != left, BINARY_ADD);
21342125
STAT_INC(BINARY_ADD, hit);
2135-
record_hit_inline(next_instr, oparg);
21362126
GETLOCAL(next_oparg) = NULL;
21372127
Py_DECREF(left);
21382128
STACK_SHRINK(1);
@@ -2150,7 +2140,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21502140
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_ADD);
21512141
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_ADD);
21522142
STAT_INC(BINARY_ADD, hit);
2153-
record_hit_inline(next_instr, oparg);
21542143
double dsum = ((PyFloatObject *)left)->ob_fval +
21552144
((PyFloatObject *)right)->ob_fval;
21562145
PyObject *sum = PyFloat_FromDouble(dsum);
@@ -2170,7 +2159,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21702159
DEOPT_IF(!PyLong_CheckExact(left), BINARY_ADD);
21712160
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_ADD);
21722161
STAT_INC(BINARY_ADD, hit);
2173-
record_hit_inline(next_instr, oparg);
21742162
PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
21752163
SET_SECOND(sum);
21762164
Py_DECREF(right);
@@ -2241,8 +2229,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22412229
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
22422230
Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
22432231
DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
2244-
2245-
record_hit_inline(next_instr, oparg);
22462232
STAT_INC(BINARY_SUBSCR, hit);
22472233
PyObject *res = PyList_GET_ITEM(list, index);
22482234
assert(res != NULL);
@@ -2266,8 +2252,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22662252
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
22672253
Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
22682254
DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
2269-
2270-
record_hit_inline(next_instr, oparg);
22712255
STAT_INC(BINARY_SUBSCR, hit);
22722256
PyObject *res = PyTuple_GET_ITEM(tuple, index);
22732257
assert(res != NULL);
@@ -2282,7 +2266,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22822266
TARGET(BINARY_SUBSCR_DICT) {
22832267
PyObject *dict = SECOND();
22842268
DEOPT_IF(!PyDict_CheckExact(SECOND()), BINARY_SUBSCR);
2285-
record_hit_inline(next_instr, oparg);
22862269
STAT_INC(BINARY_SUBSCR, hit);
22872270
PyObject *sub = TOP();
22882271
PyObject *res = PyDict_GetItemWithError(dict, sub);
@@ -3258,7 +3241,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
32583241
PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + cache0->index;
32593242
PyObject *res = ep->me_value;
32603243
DEOPT_IF(res == NULL, LOAD_GLOBAL);
3261-
record_cache_hit(cache0);
32623244
STAT_INC(LOAD_GLOBAL, hit);
32633245
Py_INCREF(res);
32643246
PUSH(res);
@@ -3279,7 +3261,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
32793261
PyDictKeyEntry *ep = DK_ENTRIES(bdict->ma_keys) + cache0->index;
32803262
PyObject *res = ep->me_value;
32813263
DEOPT_IF(res == NULL, LOAD_GLOBAL);
3282-
record_cache_hit(cache0);
32833264
STAT_INC(LOAD_GLOBAL, hit);
32843265
Py_INCREF(res);
32853266
PUSH(res);
@@ -3702,7 +3683,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37023683
res = values->values[cache0->index];
37033684
DEOPT_IF(res == NULL, LOAD_ATTR);
37043685
STAT_INC(LOAD_ATTR, hit);
3705-
record_cache_hit(cache0);
37063686
Py_INCREF(res);
37073687
SET_TOP(res);
37083688
Py_DECREF(owner);
@@ -3742,7 +3722,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37423722
res = ep->me_value;
37433723
DEOPT_IF(res == NULL, LOAD_ATTR);
37443724
STAT_INC(LOAD_ATTR, hit);
3745-
record_cache_hit(cache0);
37463725
Py_INCREF(res);
37473726
SET_TOP(res);
37483727
Py_DECREF(owner);
@@ -3763,7 +3742,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37633742
res = *(PyObject **)addr;
37643743
DEOPT_IF(res == NULL, LOAD_ATTR);
37653744
STAT_INC(LOAD_ATTR, hit);
3766-
record_cache_hit(cache0);
37673745
Py_INCREF(res);
37683746
SET_TOP(res);
37693747
Py_DECREF(owner);
@@ -3805,7 +3783,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
38053783
PyDictValues *values = *(PyDictValues **)(((char *)owner) + tp->tp_inline_values_offset);
38063784
DEOPT_IF(values == NULL, STORE_ATTR);
38073785
STAT_INC(STORE_ATTR, hit);
3808-
record_cache_hit(cache0);
38093786
int index = cache0->index;
38103787
STACK_SHRINK(1);
38113788
PyObject *value = POP();
@@ -3843,7 +3820,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
38433820
PyObject *old_value = ep->me_value;
38443821
DEOPT_IF(old_value == NULL, STORE_ATTR);
38453822
STAT_INC(STORE_ATTR, hit);
3846-
record_cache_hit(cache0);
38473823
STACK_SHR 179B INK(1);
38483824
PyObject *value = POP();
38493825
ep->me_value = value;
@@ -3869,7 +3845,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
38693845
DEOPT_IF(tp->tp_version_tag != cache1->tp_version, STORE_ATTR);
38703846
char *addr = (char *)owner + cache0->index;
38713847
STAT_INC(STORE_ATTR, hit);
3872-
record_cache_hit(cache0);
38733848
STACK_SHRINK(1);
38743849
PyObject *value = POP();
38753850
PyObject *old_value = *(PyObject **)addr;
@@ -4527,7 +4502,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45274502
PyObject *self = TOP();
45284503
PyTypeObject *self_cls = Py_TYPE(self);
45294504
SpecializedCacheEntry *caches = GET_CACHE();
4530-
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
45314505
_PyAttrCache *cache1 = &caches[-1].attr;
45324506
_PyObjectCache *cache2 = &caches[-2].obj;
45334507

@@ -4538,7 +4512,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45384512
DEOPT_IF(dict != NULL, LOAD_METHOD);
45394513
DEOPT_IF(((PyHeapTypeObject *)self_cls)->ht_cached_keys->dk_version != cache1->dk_version_or_hint, LOAD_METHOD);
45404514
STAT_INC(LOAD_METHOD, hit);
4541-
record_cache_hit(cache0);
45424515
PyObject *res = cache2->obj;
45434516
assert(res != NULL);
45444517
assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
@@ -4552,13 +4525,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45524525
PyObject *self = TOP();
45534526
PyTypeObject *self_cls = Py_TYPE(self);
45544527
SpecializedCacheEntry *caches = GET_CACHE();
4555-
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
45564528
_PyAttrCache *cache1 = &caches[-1].attr;
45574529
_PyObjectCache *cache2 = &caches[-2].obj;
45584530
DEOPT_IF(self_cls->tp_version_tag != cache1->tp_version, LOAD_METHOD);
45594531
assert(self_cls->tp_dictoffset == 0);
45604532
STAT_INC(LOAD_METHOD, hit);
4561-
record_cache_hit(cache0);
45624533
PyObject *res = cache2->obj;
45634534
assert(res != NULL);
45644535
assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
@@ -4584,7 +4555,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45844555
/* LOAD_METHOD, for class methods */
45854556
assert(cframe.use_tracing == 0);
45864557
SpecializedCacheEntry *caches = GET_CACHE();
4587-
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
45884558
_PyAttrCache *cache1 = &caches[-1].attr;
45894559
_PyObjectCache *cache2 = &caches[-2].obj;
45904560

@@ -4595,7 +4565,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45954565
assert(cache1->tp_version != 0);
45964566

45974567
STAT_INC(LOAD_METHOD, hit);
4598-
record_cache_hit(cache0);
45994568
PyObject *res = cache2->obj;
46004569
assert(res != NULL);
46014570
Py_INCREF(res);
@@ -4751,7 +4720,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47514720
/* PEP 523 */
47524721
DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_FUNCTION);
47534722
STAT_INC(CALL_FUNCTION, hit);
4754-
record_cache_hit(cache0);
47554723
InterpreterFrame *new_frame = _PyThreadState_PushFrame(
47564724
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(func), NULL);
47574725
if (new_frame == NULL) {
@@ -4783,8 +4751,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47834751
PyObject *callable = SECOND();
47844752
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_FUNCTION);
47854753
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL_FUNCTION);
4786-
_PyAdaptiveEntry *cache0 = &GET_CACHE()[0].adaptive;
4787-
record_cache_hit(cache0);
47884754
STAT_INC(CALL_FUNCTION, hit);
47894755

47904756
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
@@ -4813,7 +4779,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
48134779
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_FUNCTION);
48144780
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
48154781
CALL_FUNCTION);
4816-
record_cache_hit(cache0);
48174782
STAT_INC(CALL_FUNCTION, hit);
48184783

48194784
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
@@ -4845,13 +4810,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
48454810
assert(cframe.use_tracing == 0);
48464811
/* len(o) */
48474812
SpecializedCacheEntry *caches = GET_CACHE();
4848-
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
4813+
assert(caches[0].adaptive.original_oparg == 1);
48494814
_PyObjectCache *cache1 = &caches[-1].obj;
4850-
assert(cache0->original_oparg == 1);
48514815

48524816
PyObject *callable = SECOND();
48534817
DEOPT_IF(callable != cache1->obj, CALL_FUNCTION);
4854-
record_cache_hit(cache0);
48554818
STAT_INC(CALL_FUNCTION, hit);
48564819

48574820
Py_ssize_t len_i = PyObject_Length(TOP());
@@ -4875,13 +4838,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
48754838
assert(cframe.use_tracing == 0);
48764839
/* isinstance(o, o2) */
48774840
SpecializedCacheEntry *caches = GET_CACHE();
4878-
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
4841+
assert(caches[0].adaptive.original_oparg == 2);
48794842
_PyObjectCache *cache1 = &caches[-1].obj;
4880-
assert(cache0->original_oparg == 2);
48814843

48824844
PyObject *callable = THIRD();
48834845
DEOPT_IF(callable != cache1->obj, CALL_FUNCTION);
4884-
record_cache_hit(cache0);
48854846
STAT_INC(CALL_FUNCTION, hit);
48864847

48874848
int retval = PyObject_IsInstance(SECOND(), TOP());
@@ -5139,8 +5100,8 @@ opname ## _miss: \
51395100
{ \
51405101
STAT_INC(opname, miss); \
51415102
_PyAdaptiveEntry *cache = &GET_CACHE()->adaptive; \
5142-
record_cache_miss(cache); \
5143-
if (too_many_cache_misses(cache)) { \
5103+
cache->counter--; \
5104+
if (cache->counter == 0) { \
51445105
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, _Py_OPARG(next_instr[-1])); \
51455106
STAT_INC(opname, deopt); \
51465107
cache_backoff(cache); \
@@ -5154,10 +5115,10 @@ opname ## _miss: \
51545115
opname ## _miss: \
51555116
{ \
51565117
STAT_INC(opname, miss); \
5157-
uint8_t oparg = saturating_decrement(_Py_OPARG(next_instr[-1])); \
5118+
uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \
51585119
UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
51595120
assert(_Py_OPARG(next_instr[-1]) == oparg); \
5160-
if (oparg == saturating_zero()) /* too many cache misses */ { \
5121+
if (oparg == 0) /* too many cache misses */ { \
51615122
oparg = ADAPTIVE_CACHE_BACKOFF; \
51625123
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
51635124
STAT_INC(opname, deopt); \

0 commit comments

Comments
 (0)
0