@@ -22,33 +22,48 @@ extern "C" {
2222 Another use is for the Tier 2 optimizer to decide when to create
2323 a new Tier 2 trace (executor). Again, exponential backoff is used.
2424
25- The 16-bit counter is structured as a 12 -bit unsigned 'value'
26- and a 4 -bit 'backoff' field. When resetting the counter, the
25+ The 16-bit counter is structured as a 13 -bit unsigned 'value'
26+ and a 3 -bit 'backoff' field. When resetting the counter, the
2727 backoff field is incremented (until it reaches a limit) and the
28- value is set to a bit mask representing the value 2**backoff - 1.
29- The maximum backoff is 12 (the number of bits in the value).
28+ value is set to a bit mask representing some prime value - 1.
29+ New values and backoffs for each backoff are calculated once
30+ at compile time and saved to value_and_backoff_next table.
31+ The maximum backoff is 6, since 7 is an UNREACHABLE_BACKOFF.
3032
3133 There is an exceptional value which must not be updated, 0xFFFF.
3234*/
3335
34- #define BACKOFF_BITS 4
35- #define MAX_BACKOFF 12
36- #define UNREACHABLE_BACKOFF 15
37-
38- static inline bool
39- is_unreachable_backoff_counter (_Py_BackoffCounter counter )
40- {
41- return counter .value_and_backoff == UNREACHABLE_BACKOFF ;
42- }
36+ #define BACKOFF_BITS 3
37+ #define BACKOFF_MASK 7
38+ #define MAX_BACKOFF 6
39+ #define UNREACHABLE_BACKOFF 7
40+ #define MAX_VALUE 0x1FFF
41+
42+ #define MAKE_VALUE_AND_BACKOFF (value , backoff ) \
43+ ((value << BACKOFF_BITS) | backoff)
44+
45+ // For previous backoff b we use value x such that
46+ // x + 1 is near to 2**(2*b+1) and x + 1 is prime.
47+ static const uint16_t value_and_backoff_next [] = {
48+ MAKE_VALUE_AND_BACKOFF (1 , 1 ),
49+ MAKE_VALUE_AND_BACKOFF (6 , 2 ),
50+ MAKE_VALUE_AND_BACKOFF (30 , 3 ),
51+ MAKE_VALUE_AND_BACKOFF (126 , 4 ),
52+ MAKE_VALUE_AND_BACKOFF (508 , 5 ),
53+ MAKE_VALUE_AND_BACKOFF (2052 , 6 ),
54+ // We use the same backoff counter for all backoffs >= MAX_BACKOFF.
55+ MAKE_VALUE_AND_BACKOFF (8190 , 6 ),
56+ MAKE_VALUE_AND_BACKOFF (8190 , 6 ),
57+ };
4358
4459static inline _Py_BackoffCounter
4560make_backoff_counter (uint16_t value , uint16_t backoff )
4661{
47- assert (backoff <= 15 );
48- assert (value <= 0xFFF );
49- _Py_BackoffCounter result ;
50- result .value_and_backoff = (value << BACKOFF_BITS ) | backoff ;
51- return result ;
62+ assert (backoff <= UNREACHABLE_BACKOFF );
63+ assert (value <= MAX_VALUE );
64+ return (( _Py_BackoffCounter ){
65+ .value_and_backoff = MAKE_VALUE_AND_BACKOFF (value , backoff )
66+ }) ;
5267}
5368
5469static inline _Py_BackoffCounter
@@ -62,14 +77,11 @@ forge_backoff_counter(uint16_t counter)
6277static inline _Py_BackoffCounter
6378restart_backoff_counter (_Py_BackoffCounter counter )
6479{
65- assert (!is_unreachable_backoff_counter (counter ));
66- int backoff = counter .value_and_backoff & 15 ;
67- if (backoff < MAX_BACKOFF ) {
68- return make_backoff_counter ((1 << (backoff + 1 )) - 1 , backoff + 1 );
69- }
70- else {
71- return make_backoff_counter ((1 << MAX_BACKOFF ) - 1 , MAX_BACKOFF );
72- }
80+ uint16_t backoff = counter .value_and_backoff & BACKOFF_MASK ;
81+ assert (backoff <= MAX_BACKOFF );
82+ return ((_Py_BackoffCounter ){
83+ .value_and_backoff = value_and_backoff_next [backoff ]
84+ });
7385}
7486
7587static inline _Py_BackoffCounter
@@ -113,7 +125,7 @@ trigger_backoff_counter(void)
113125// as we always end up tracing the loop iteration's
114126// exhaustion iteration. Which aborts our current tracer.
115127#define JUMP_BACKWARD_INITIAL_VALUE 4000
116- #define JUMP_BACKWARD_INITIAL_BACKOFF 12
128+ #define JUMP_BACKWARD_INITIAL_BACKOFF 6
117129static inline _Py_BackoffCounter
118130initial_jump_backoff_counter (void )
119131{
@@ -126,7 +138,7 @@ initial_jump_backoff_counter(void)
126138 * otherwise when a side exit warms up we may construct
127139 * a new trace before the Tier 1 code has properly re-specialized. */
128140#define SIDE_EXIT_INITIAL_VALUE 4000
129- #define SIDE_EXIT_INITIAL_BACKOFF 12
141+ #define SIDE_EXIT_INITIAL_BACKOFF 6
130142
131143static inline _Py_BackoffCounter
132144initial_temperature_backoff_counter (void )
0 commit comments