8000 gh-116968: Reimplement Tier 2 counters by gvanrossum · Pull Request #117144 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-116968: Reimplement Tier 2 counters #117144

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 46 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e7e819b
Baby steps: reimplement thresholds using adaptive counter abstractions
gvanrossum Mar 22, 2024
8c74dfa
Make temperature an adaptive counter like the rest
gvanrossum Mar 22, 2024
79036ff
Fix tests
gvanrossum Mar 22, 2024
54c1f8e
Remove dead adaptive_counter_jump_init()
gvanrossum Mar 22, 2024
015bb00
Fix no-GIL build failure in _COLD_EXIT
gvanrossum Mar 22, 2024
1730295
Use the right named constant in initial temperature
gvanrossum Mar 23, 2024
95f93b7
Add pycore_backoff.h, and include it, but don't use it yet
gvanrossum Mar 26, 2024
7df0f10
Reimplement adaptive counters in terms of backoff_counter
gvanrossum Mar 26, 2024
925cae7
Redefine T2 temperature as a backoff counter
gvanrossum Mar 27, 2024
f0c7fb0
Don't increment branch cache (bitmask) in INSTRUMENTED_INSTRUCTION
gvanrossum Mar 27, 2024
8f79a60
Don't increment branch cache (bitmask) in INSTRUMENTED_LINE
gvanrossum Mar 27, 2024
149e9c4
Don't update unreachable counters
gvanrossum Mar 27, 2024
1d76112
Simplify dynamic counter initialization for JUMP_BACKWARD
gvanrossum Mar 27, 2024
a5ffe02
Revert "Don't increment branch cache (bitmask) in INSTRUMENTED_LINE"
gvanrossum Mar 27, 2024
ce7726c
Different approach to avoid incrementing bitmask in INSTRUMENTED_LINE
gvanrossum Mar 27, 2024
e2c39f2
Different approach to avoid incrementing bitmask in INSTRUMENTED_INST…
gvanrossum Mar 27, 2024
8d22790
Fix dynamic counter initialization for JUMP_BACKWARD
gvanrossum Mar 27, 2024
cd8264e
Get rid of (unused) resume_threshold
gvanrossum Mar 27, 2024
d72c2ef
Hopeful fix for non-clang builds
gvanrossum Mar 27, 2024
f6bf194
In no-GIL mode, make INCREMENT_ADAPTIVE_COUNTER() a no-op
gvanrossum Mar 27, 2024
b991843
Revert "In no-GIL mode, make INCREMENT_ADAPTIVE_COUNTER() a no-op"
gvanrossum Mar 27, 2024
9b9f26a
Fix comment and fix size of optimizer_backedge_threshold
gvanrossum Mar 27, 2024
354cd81
_COLD_EXIT is not conditional on ENABLE_SPECIALIZATION
gvanrossum Mar 27, 2024
c1de44f
Rewrite _COLD_EXIT using backoff_counter_t directly
gvanrossum Mar 27, 2024
1fe27c9
Rename increment,decrement to advance,pause
gvanrossum Mar 27, 2024
225ea17
Give up on restricting backoff to <= 12
gvanrossum Mar 27, 2024
63d8bc7
Rip out backoff thresholds
gvanrossum Mar 29, 2024
8aa2c75
Fix tests
gvanrossum Mar 29, 2024
7bd4daa
Fix initial temperature, clean up
gvanrossum Mar 29, 2024
3f1c58a
Merge branch 'main' into exp-backoff
gvanrossum Mar 29, 2024
8ce8068
Remove unused variable
gvanrossum Mar 29, 2024
7bb5618
Admit defeat: advance_backoff_counter() may be entered when value == 0
gvanrossum Mar 29, 2024
63e286c
Merge branch 'main' into exp-backoff
gvanrossum Apr 1, 2024
7f64392
Merge remote-tracking branch 'origin/main' into exp-backoff
gvanrossum Apr 2, 2024
8eee1b4
Put backoff field before value
gvanrossum Apr 2, 2024
42c1f26
Small cleanup in .h files
gvanrossum Apr 3, 2024
a80cd0a
Rename DECREMENT_ADAPTIVE_COUNTER to ADVANCE_...
gvanrossum Apr 3, 2024
545c60e
Rename ADAPTIVE_COUNTER_IS_ZERO to ..._TRIGGERS
gvanrossum Apr 3, 2024
6c0bb30
Rename backoff_counter_is_zero to ..._triggers
gvanrossum Apr 3, 2024
a7c9b6d
Rename reset_background_counter to restart_...
gvanrossum Apr 3, 2024
3fee35f
Make _Py_BackoffCounter a member of _Py_CODEUNIT
gvanrossum Apr 3, 2024
df6f34c
Refactor initial counter values.
gvanrossum Apr 3, 2024
72f6b0d
Export tier 2 threshold from _testinternalcapi
gvanrossum Apr 3, 2024
dcee362
Merge remote-tracking branch 'origin/main' into exp-backoff
gvanrossum Apr 3, 2024
f38d922
Add news
gvanrossum Apr 3, 2024
ef6366b
Fix blurb formatting (I hope)
gvanrossum Apr 4, 2024
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
Prev Previous commit
Next Next commit
Make _Py_BackoffCounter a member of _Py_CODEUNIT
This changes a lot of things but the end result is arguably better.
  • Loading branch information
gvanrossum committed Apr 3, 2024
commit 3fee35f0e749feb27e104e8f212bed20c390149e
11 changes: 11 additions & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ typedef struct _Py_GlobalMonitors {
uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS];
} _Py_GlobalMonitors;

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

/* Each instruction in a code object is a fixed-width value,
* currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG
* opcode allows for larger values but the current limit is 3 uses
Expand All @@ -39,6 +49,7 @@ typedef union {
uint8_t code;
uint8_t arg;
} op;
_Py_BackoffCounter counter; // First cache entry of specializable op
} _Py_CODEUNIT;


Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst)

typedef struct _exit_data {
uint32_t target;
uint16_t temperature;
_Py_BackoffCounter temperature;
Copy link
Member Author

Choose a reason for hiding this comment

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

temperature is now a bit of a misnomer, since it counts down. Maybe it should be renamed to counter (same as in CODEUNIT)?

Copy link
Member

Choose a reason for hiding this comment

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

I'm fine with either.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll keep temperature, despite the misnomer -- it stands out and makes it easy to grep for this particular concept.

const struct _PyExecutorObject *executor;
} _PyExitData;

Expand Down
43 changes: 15 additions & 28 deletions Include/internal/pycore_backoff.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,43 +31,30 @@ extern "C" {
There is an exceptional value which must not be updated, 0xFFFF.
*/

typedef struct {
union {
uint16_t counter;
struct {
uint16_t backoff : 4;
uint16_t value : 12;
};
};
} backoff_counter_t;

static_assert(sizeof(backoff_counter_t) == sizeof(_Py_CODEUNIT),
"backoff counter size should be the same size as a code unit");

#define UNREACHABLE_BACKOFF 0xFFFF

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

static inline backoff_counter_t
static inline _Py_BackoffCounter
make_backoff_counter(uint16_t value, uint16_t backoff)
{
assert(backoff <= 15);
assert(value <= 0xFFF);
return (backoff_counter_t){.value = value, .backoff = backoff};
return (_Py_BackoffCounter){.value = value, .backoff = backoff};
}

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

static inline backoff_counter_t
restart_backoff_counter(backoff_counter_t counter)
static inline _Py_BackoffCounter
restart_backoff_counter(_Py_BackoffCounter counter)
{
assert(!is_unreachable_backoff_counter(counter));
if (counter.backoff < 12) {
Expand All @@ -78,14 +65,14 @@ restart_backoff_counter(backoff_counter_t counter)
}
}

static inline backoff_counter_t
pause_backoff_counter(backoff_counter_t counter)
static inline _Py_BackoffCounter
pause_backoff_counter(_Py_BackoffCounter counter)
{
return make_backoff_counter(counter.value | 1, counter.backoff);
}

static inline backoff_counter_t
advance_backoff_counter(backoff_counter_t counter)
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);
Expand All @@ -96,16 +83,16 @@ advance_backoff_counter(backoff_counter_t counter)
}

static inline bool
backoff_counter_triggers(backoff_counter_t counter)
backoff_counter_triggers(_Py_BackoffCounter counter)
{
return counter.value == 0;
}

static inline uint16_t
static inline _Py_BackoffCounter
initial_backoff_counter(void)
{
// Backoff sequence 16, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096
return make_backoff_counter(16, 3).counter;
return make_backoff_counter(16, 3);
}

#ifdef __cplusplus
Expand Down
42 changes: 21 additions & 21 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extern "C" {
#define CACHE_ENTRIES(cache) (sizeof(cache)/sizeof(_Py_CODEUNIT))

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
uint16_t module_keys_version;
uint16_t builtin_keys_version;
uint16_t index;
Expand All @@ -40,44 +40,44 @@ typedef struct {
#define INLINE_CACHE_ENTRIES_LOAD_GLOBAL CACHE_ENTRIES(_PyLoadGlobalCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyBinaryOpCache;

#define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyUnpackSequenceCache;

#define INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE \
CACHE_ENTRIES(_PyUnpackSequenceCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyCompareOpCache;

#define INLINE_CACHE_ENTRIES_COMPARE_OP CACHE_ENTRIES(_PyCompareOpCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyBinarySubscrCache;

#define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PySuperAttrCache;

#define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
uint16_t version[2];
uint16_t index;
} _PyAttrCache;

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
uint16_t type_version[2];
union {
uint16_t keys_version[2];
Expand All @@ -93,39 +93,39 @@ typedef struct {
#define INLINE_CACHE_ENTRIES_STORE_ATTR CACHE_ENTRIES(_PyAttrCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
uint16_t func_version[2];
} _PyCallCache;

#define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyStoreSubscrCache;

#define INLINE_CACHE_ENTRIES_STORE_SUBSCR CACHE_ENTRIES(_PyStoreSubscrCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyForIterCache;

#define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PySendCache;

#define INLINE_CACHE_ENTRIES_SEND CACHE_ENTRIES(_PySendCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
uint16_t version[2];
} _PyToBoolCache;

#define INLINE_CACHE_ENTRIES_TO_BOOL CACHE_ENTRIES(_PyToBoolCache)

typedef struct {
uint16_t counter;
_Py_BackoffCounter counter;
} _PyContainsOpCache;

#define INLINE_CACHE_ENTRIES_CONTAINS_OP CACHE_ENTRIES(_PyContainsOpCache)
Expand Down Expand Up @@ -476,26 +476,26 @@ write_location_entry_start(uint8_t *ptr, int code, int length)
#define ADAPTIVE_COOLDOWN_VALUE 52
#define ADAPTIVE_COOLDOWN_BACKOFF 0

static inline uint16_t
static inline _Py_BackoffCounter
adaptive_counter_bits(uint16_t value, uint16_t backoff) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe drop the adaptive_counter functions and replace them with the backoff_counter equivalents?

To do that cleanly we will probably need to change _Py_CODEUNIT to:

typedef union {
    uint16_t cache;
    struct {
        uint8_t code;
        uint8_t arg;
    } op;
    backoff_counter_t counter;
} _Py_CODEUNIT;

Copy link
Member Author

Choose a reason for hiding this comment

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

I decided to keep them and not expose the backoff counter structure to other places.

Copy link
Member Author

Choose a reason for hiding this comment

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

I could dispense with adaptive_counter_bits(), using make_backoff_counter() directly below, but I would oppose getting rid of the cooldown() and warmup() helpers, because they are used in several/many places.

return make_backoff_counter(value, backoff).counter;
return make_backoff_counter(value, backoff);
}

static inline uint16_t
static inline _Py_BackoffCounter
adaptive_counter_warmup(void) {
return adaptive_counter_bits(ADAPTIVE_WARMUP_VALUE,
ADAPTIVE_WARMUP_BACKOFF);
}

static inline uint16_t
static inline _Py_BackoffCounter
adaptive_counter_cooldown(void) {
return adaptive_counter_bits(ADAPTIVE_COOLDOWN_VALUE,
ADAPTIVE_COOLDOWN_BACKOFF);
}

static inline uint16_t
adaptive_counter_backoff(uint16_t counter) {
return restart_backoff_counter(forge_backoff_counter(counter)).counter;
static inline _Py_BackoffCounter
adaptive_counter_backoff(_Py_BackoffCounter counter) {
return restart_backoff_counter(counter);
}


Expand Down
Loading
0