8000 Refactor initial counter values. · python/cpython@df6f34c · GitHub
[go: up one dir, main page]

Skip to content

Commit df6f34c

Browse files
committed
Refactor initial counter values.
- The initial exit temperature is 64; this must be greater than the specialization cooldown value (52) otherwise we might create a trace before we have re-specialized the Tier 1 bytecode - There's now a handy helper function for every counter initialization
1 parent 3fee35f commit df6f34c

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

Include/internal/pycore_backoff.h

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,38 @@ backoff_counter_triggers(_Py_BackoffCounter counter)
8888
return counter.value == 0;
8989
}
9090

91+
/* Initial JUMP_BACKWARD counter.
92+
* This determines when we create a trace for a loop.
93+
* Backoff sequence 16, 32, 64, 128, 256, 512, 1024, 2048, 4096. */
94+
#define JUMP_BACKWARD_INITIAL_VALUE 16
95+
#define JUMP_BACKWARD_INITIAL_BACKOFF 4
9196
static inline _Py_BackoffCounter
92-
initial_backoff_counter(void)
97+
initial_jump_backoff_counter(void)
9398
{
94-
// Backoff sequence 16, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096
95-
return make_backoff_counter(16, 3);
99+
return make_backoff_counter(JUMP_BACKWARD_INITIAL_VALUE,
100+
JUMP_BACKWARD_INITIAL_BACKOFF);
101+
}
102+
103+
/* Initial exit temperature.
104+
* Must be larger than ADAPTIVE_COOLDOWN_VALUE,
105+
* otherwise when a side exit warms up we may construct
106+
* a new trace before the Tier 1 code has properly re-specialized.
107+
* Backoff sequence 64, 128, 256, 512, 1024, 2048, 4096. */
108+
#define COLD_EXIT_INITIAL_VALUE 64
109+
#define COLD_EXIT_INITIAL_BACKOFF 6
110+
111+
static inline _Py_BackoffCounter
112+
initial_temperature_backoff_counter(void)
113+
{
114+
return make_backoff_counter(COLD_EXIT_INITIAL_VALUE,
115+
COLD_EXIT_INITIAL_BACKOFF);
116+
}
117+
118+
/* Unreachable backoff counter. */
119+
static inline _Py_BackoffCounter
120+
initial_unreachable_backoff_counter(void)
121+
{
122+
return forge_backoff_counter(UNREACHABLE_BACKOFF);
96123
}
97124

98125
#ifdef __cplusplus

Include/internal/pycore_code.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ write_location_entry_start(uint8_t *ptr, int code, int length)
476476
#define ADAPTIVE_COOLDOWN_VALUE 52
477477
#define ADAPTIVE_COOLDOWN_BACKOFF 0
478478

479+
// Can't assert this in pycore_backoff.h because of header order dependencies
480+
static_assert(COLD_EXIT_INITIAL_VALUE > ADAPTIVE_COOLDOWN_VALUE,
481+
"Cold exit value should be larger than adaptive cooldown value");
482+
479483
static inline _Py_BackoffCounter
480484
adaptive_counter_bits(uint16_t value, uint16_t backoff) {
481485
return make_backoff_counter(value, backoff);

Python/ceval_macros.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ GETITEM(PyObject *v, Py_ssize_t i) {
290290
dtrace_function_entry(frame); \
291291
}
292292

293+
/* This takes a uint16_t instead of a _Py_BackoffCounter,
294+
* because it is used directly on the cache entry in generated code,
295+
* which is always an integral type. */
293296
#define ADAPTIVE_COUNTER_TRIGGERS(COUNTER) \
294297
backoff_counter_triggers(forge_backoff_counter((COUNTER)))
295298

Python/optimizer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
10881088
assert(exit_count < COLD_EXIT_COUNT);
10891089
for (int i = 0; i < exit_count; i++) {
10901090
executor->exits[i].executor = &COLD_EXITS[i];
1091-
executor->exits[i].temperature = initial_backoff_counter();
1091+
executor->exits[i].temperature = initial_temperature_backoff_counter();
10921092
}
10931093
int next_exit = exit_count-1;
10941094
_PyUOpInstruction *dest = (_PyUOpInstruction *)&executor->trace[length];
@@ -1525,7 +1525,7 @@ _Py_ExecutorClear(_PyExecutorObject *executor)
15251525
for (uint32_t i = 0; i < executor->exit_count; i++) {
15261526
Py_DECREF(executor->exits[i].executor);
15271527
executor->exits[i].executor = &COLD_EXITS[i];
1528-
executor->exits[i].temperature = forge_backoff_counter(UNREACHABLE_BACKOFF);
1528+
executor->exits[i].temperature = initial_unreachable_backoff_counter();
15291529
}
15301530
_Py_CODEUNIT *instruction = &_PyCode_CODE(code)[executor->vm_data.index];
15311531
assert(instruction->op.code == ENTER_EXECUTOR);

Python/specialize.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,22 +419,20 @@ _PyCode_Quicken(PyCodeObject *code)
419419
int caches = _PyOpcode_Caches[opcode];
420420
if (caches) {
421421
// The initial value depends on the opcode
422-
int initial_value;
423422
switch (opcode) {
424423
case JUMP_BACKWARD:
425-
initial_value = initial_backoff_counter().as_counter;
424+
instructions[i + 1].counter = initial_jump_backoff_counter();
426425
break;
427426
case POP_JUMP_IF_FALSE:
428427
case POP_JUMP_IF_TRUE:
429428
case POP_JUMP_IF_NONE:
430429
case POP_JUMP_IF_NOT_NONE:
431-
initial_value = 0x5555; // Alternating 0, 1 bits
430+
instructions[i + 1].cache = 0x5555; // Alternating 0, 1 bits
432431
break;
433432
default:
434-
initial_value = adaptive_counter_warmup().as_counter;
433+
instructions[i + 1].counter = adaptive_counter_warmup();
435434
break;
436435
}
437-
instructions[i + 1].cache = initial_value;
438436
i += caches;
439437
}
440438
}

0 commit comments

Comments
 (0)
0