Skip to content

GH-116968: Remove branch from advance_backoff_counter #124469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 21 additions & 25 deletions Include/internal/pycore_backoff.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@ extern "C" {


typedef struct {
union {
struct {
uint16_t backoff : 4;
uint16_t value : 12;
};
uint16_t as_counter; // For printf("%#x", ...)
};
uint16_t value_and_backoff;
} _Py_BackoffCounter;


Expand All @@ -38,17 +32,19 @@ typedef struct {
and a 4-bit 'backoff' field. When resetting the counter, the
backoff field is incremented (until it reaches a limit) and the
value is set to a bit mask representing the value 2**backoff - 1.
The maximum backoff is 12 (the number of value bits).
The maximum backoff is 12 (the number of bits in the value).

There is an exceptional value which must not be updated, 0xFFFF.
*/

#define UNREACHABLE_BACKOFF 0xFFFF
#define BACKOFF_BITS 4
#define MAX_BACKOFF 12
#define UNREACHABLE_BACKOFF 15

static inline bool
is_unreachable_backoff_counter(_Py_BackoffCounter counter)
{
return counter.as_counter == UNREACHABLE_BACKOFF;
return counter.value_and_backoff == UNREACHABLE_BACKOFF;
}

static inline _Py_BackoffCounter
Expand All @@ -57,52 +53,52 @@ make_backoff_counter(uint16_t value, uint16_t backoff)
assert(backoff <= 15);
assert(value <= 0xFFF);
_Py_BackoffCounter result;
result.value = value;
result.backoff = backoff;
result.value_and_backoff = (value << BACKOFF_BITS) | backoff;
return result;
}

static inline _Py_BackoffCounter
forge_backoff_counter(uint16_t counter)
{
_Py_BackoffCounter result;
result.as_counter = counter;
result.value_and_backoff = counter;
return result;
}

static inline _Py_BackoffCounter
restart_backoff_counter(_Py_BackoffCounter counter)
{
assert(!is_unreachable_backoff_counter(counter));
if (counter.backoff < 12) {
return make_backoff_counter((1 << (counter.backoff + 1)) - 1, counter.backoff + 1);
int backoff = counter.value_and_backoff & 15;
if (backoff < MAX_BACKOFF) {
return make_backoff_counter((1 << (backoff + 1)) - 1, backoff + 1);
}
else {
return make_backoff_counter((1 << 12) - 1, 12);
return make_backoff_counter((1 << MAX_BACKOFF) - 1, MAX_BACKOFF);
}
}

static inline _Py_BackoffCounter
pause_backoff_counter(_Py_BackoffCounter counter)
{
return make_backoff_counter(counter.value | 1, counter.backoff);
_Py_BackoffCounter result;
result.value_and_backoff = counter.value_and_backoff | (1 << BACKOFF_BITS);
return result;
}

static inline _Py_BackoffCounter
advance_backoff_counter(_Py_BackoffCounter counter)
{
if (!is_unreachable_backoff_counter(counter)) {
return make_backoff_counter((counter.value - 1) & 0xFFF, counter.backoff);
}
else {
return counter;
}
_Py_BackoffCounter result;
result.value_and_backoff = counter.value_and_backoff - (1 << BACKOFF_BITS);
return result;
}

static inline bool
backoff_counter_triggers(_Py_BackoffCounter counter)
{
return counter.value == 0;
/* Test whether the value is zero and the backoff is not UNREACHABLE_BACKOFF */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not testing that the value is zero. Is this comment accurate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is testing whether the value is zero. The value is the high bits, so value == 0 for any value_and_backoff < (1 << BACKOFF_BITS)

return counter.value_and_backoff < UNREACHABLE_BACKOFF;
}

/* Initial JUMP_BACKWARD counter.
Expand Down Expand Up @@ -136,7 +132,7 @@ initial_temperature_backoff_counter(void)
static inline _Py_BackoffCounter
initial_unreachable_backoff_counter(void)
{
return forge_backoff_counter(UNREACHABLE_BACKOFF);
return make_backoff_counter(0, UNREACHABLE_BACKOFF);
}

#ifdef __cplusplus
Expand Down
4 changes: 2 additions & 2 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4703,7 +4703,7 @@ dummy_func(
printf("SIDE EXIT: [UOp ");
_PyUOpPrint(&next_uop[-1]);
printf(", exit %u, temp %d, target %d -> %s]\n",
exit - current_executor->exits, exit->temperature.as_counter,
exit - current_executor->exits, exit->temperature.value_and_backoff,
(int)(target - _PyCode_CODE(code)),
_PyOpcode_OpName[target->op.code]);
}
Expand Down Expand Up @@ -4791,7 +4791,7 @@ dummy_func(
printf("DYNAMIC EXIT: [UOp ");
_PyUOpPrint(&next_uop[-1]);
printf(", exit %u, temp %d, target %d -> %s]\n",
exit - current_executor->exits, exit->temperature.as_counter,
exit - current_executor->exits, exit->temperature.value_and_backoff,
(int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))),
_PyOpcode_OpName[target->op.code]);
}
Expand Down
4 changes: 2 additions & 2 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Python/instrumentation.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,8 @@ de_instrument(PyCodeObject *code, int i, int event)
CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented);
FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, deinstrumented);
if (_PyOpcode_Caches[deinstrumented]) {
FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter,
adaptive_counter_warmup().as_counter);
FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.value_and_backoff,
adaptive_counter_warmup().value_and_backoff);
}
}

Expand Down Expand Up @@ -719,8 +719,8 @@ instrument(PyCodeObject *code, int i)
assert(instrumented);
FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, instrumented);
if (_PyOpcode_Caches[deopt]) {
FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter,
adaptive_counter_warmup().as_counter);
FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.value_and_backoff,
adaptive_counter_warmup().value_and_backoff);
instr[1].counter = adaptive_counter_warmup();
}
}
Expand Down
Loading