summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@microsoft.com>2024-07-01 20:17:40 (GMT)
committerGitHub <noreply@github.com>2024-07-01 20:17:40 (GMT)
commit33903c53dbdb768e1ef7c46d347869577f2173ce (patch)
tree9e1e8473028f803ece96c8ccbde3f6bfef08ade3 /Python
parent294e72496439da984cb8dba9100d3613c8cc8a6d (diff)
downloadcpython-33903c53dbdb768e1ef7c46d347869577f2173ce.zip
cpython-33903c53dbdb768e1ef7c46d347869577f2173ce.tar.gz
cpython-33903c53dbdb768e1ef7c46d347869577f2173ce.tar.bz2
GH-116017: Get rid of _COLD_EXITs (GH-120960)
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c93
-rw-r--r--Python/ceval.c23
-rw-r--r--Python/ceval_macros.h3
-rw-r--r--Python/executor_cases.c.h93
-rw-r--r--Python/jit.c2
-rw-r--r--Python/optimizer.c86
-rw-r--r--Python/optimizer_cases.c.h4
7 files changed, 121 insertions, 183 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 50978a0..343481e 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -4618,7 +4618,50 @@ dummy_func(
}
tier2 op(_EXIT_TRACE, (--)) {
- EXIT_TO_TRACE();
+ _PyExitData *exit = &current_executor->exits[oparg];
+ PyCodeObject *code = _PyFrame_GetCode(frame);
+ _Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
+ #if defined(Py_DEBUG) && !defined(_Py_JIT)
+ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
+ if (lltrace >= 2) {
+ printf("SIDE EXIT: [UOp ");
+ _PyUOpPrint(&next_uop[-1]);
+ printf(", exit %u, temp %d, target %d -> %s]\n",
+ oparg, exit->temperature.as_counter,
+ (int)(target - _PyCode_CODE(code)),
+ _PyOpcode_OpName[target->op.code]);
+ }
+ #endif
+ if (exit->executor == NULL) {
+ _Py_BackoffCounter temperature = exit->temperature;
+ if (!backoff_counter_triggers(temperature)) {
+ exit->temperature = advance_backoff_counter(temperature);
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_ONE(target);
+ }
+ _PyExecutorObject *executor;
+ if (target->op.code == ENTER_EXECUTOR) {
+ executor = code->co_executors->executors[target->op.arg];
+ Py_INCREF(executor);
+ }
+ else {
+ int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
+ if (optimized <= 0) {
+ exit->temperature = restart_backoff_counter(temperature);
+ if (optimized < 0) {
+ Py_DECREF(current_executor);
+ tstate->previous_executor = Py_None;
+ GOTO_UNWIND();
+ }
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_ONE(target);
+ }
+ }
+ exit->executor = executor;
+ }
+ Py_INCREF(exit->executor);
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_TWO(exit->executor);
}
tier2 op(_CHECK_VALIDITY, (--)) {
@@ -4659,47 +4702,21 @@ dummy_func(
exe->count++;
}
- /* Only used for handling cold side exits, should never appear in
- * a normal trace or as part of an instruction.
- */
- tier2 op(_COLD_EXIT, (--)) {
- _PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
- _PyExitData *exit = &previous->exits[oparg];
- PyCodeObject *code = _PyFrame_GetCode(frame);
- _Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
- _Py_BackoffCounter temperature = exit->temperature;
- if (!backoff_counter_triggers(temperature)) {
- exit->temperature = advance_backoff_counter(temperature);
- GOTO_TIER_ONE(target);
- }
- _PyExecutorObject *executor;
- if (target->op.code == ENTER_EXECUTOR) {
- executor = code->co_executors->executors[target->op.arg];
- Py_INCREF(executor);
- }
- else {
- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
- if (optimized <= 0) {
- exit->temperature = restart_backoff_counter(temperature);
- if (optimized < 0) {
- Py_DECREF(previous);
- tstate->previous_executor = Py_None;
- GOTO_UNWIND();
- }
- GOTO_TIER_ONE(target);
- }
- }
- /* We need two references. One to store in exit->executor and
- * one to keep the executor alive when executing. */
- Py_INCREF(executor);
- exit->executor = executor;
- GOTO_TIER_TWO(executor);
- }
-
tier2 op(_DYNAMIC_EXIT, (--)) {
tstate->previous_executor = (PyObject *)current_executor;
_PyExitData *exit = (_PyExitData *)&current_executor->exits[oparg];
_Py_CODEUNIT *target = frame->instr_ptr;
+ #if defined(Py_DEBUG) && !defined(_Py_JIT)
+ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
+ if (lltrace >= 2) {
+ printf("DYNAMIC EXIT: [UOp ");
+ _PyUOpPrint(&next_uop[-1]);
+ printf(", exit %u, temp %d, target %d -> %s]\n",
+ oparg, exit->temperature.as_counter,
+ (int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))),
+ _PyOpcode_OpName[target->op.code]);
+ }
+ #endif
_PyExecutorObject *executor;
if (target->op.code == ENTER_EXECUTOR) {
PyCodeObject *code = (PyCodeObject *)frame->f_executable;
diff --git a/Python/ceval.c b/Python/ceval.c
index f4b3a41..a712446 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1054,13 +1054,13 @@ enter_tier_two:
uint64_t trace_uop_execution_counter = 0;
#endif
- assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT);
+ assert(next_uop->opcode == _START_EXECUTOR);
tier2_dispatch:
for (;;) {
uopcode = next_uop->opcode;
#ifdef Py_DEBUG
if (lltrace >= 3) {
- if (next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT) {
+ if (next_uop->opcode == _START_EXECUTOR) {
printf("%4d uop: ", 0);
}
else {
@@ -1148,25 +1148,6 @@ goto_to_tier1:
tstate->previous_executor = NULL;
DISPATCH();
-exit_to_trace:
- assert(next_uop[-1].format == UOP_FORMAT_EXIT);
- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
- uint32_t exit_index = next_uop[-1].exit_index;
- assert(exit_index < current_executor->exit_count);
- _PyExitData *exit = &current_executor->exits[exit_index];
-#ifdef Py_DEBUG
- if (lltrace >= 2) {
- printf("SIDE EXIT: [UOp ");
- _PyUOpPrint(&next_uop[-1]);
- printf(", exit %u, temp %d, target %d -> %s]\n",
- exit_index, exit->temperature.as_counter, exit->target,
- _PyOpcode_OpName[_PyCode_CODE(_PyFrame_GetCode(frame))[exit->target].op.code]);
- }
-#endif
- Py_INCREF(exit->executor);
- tstate->previous_executor = (PyObject *)current_executor;
- GOTO_TIER_TWO(exit->executor);
-
#endif // _Py_JIT
#endif // _Py_TIER2
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index f6d055a..595b72b 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -426,7 +426,7 @@ do { \
do { \
OPT_STAT_INC(traces_executed); \
next_uop = (EXECUTOR)->trace; \
- assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT); \
+ assert(next_uop->opcode == _START_EXECUTOR); \
goto enter_tier_two; \
} while (0)
#endif
@@ -446,7 +446,6 @@ do { \
#define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target
#define JUMP_TO_ERROR() goto jump_to_error_target
#define GOTO_UNWIND() goto error_tier_two
-#define EXIT_TO_TRACE() goto exit_to_trace
#define EXIT_TO_TIER1() goto exit_to_tier1
#define EXIT_TO_TIER1_DYNAMIC() goto exit_to_tier1_dynamic;
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 76b7a9b..d70a57a 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -4824,7 +4824,51 @@
}
case _EXIT_TRACE: {
- EXIT_TO_TRACE();
+ oparg = CURRENT_OPARG();
+ _PyExitData *exit = &current_executor->exits[oparg];
+ PyCodeObject *code = _PyFrame_GetCode(frame);
+ _Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
+ #if defined(Py_DEBUG) && !defined(_Py_JIT)
+ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
+ if (lltrace >= 2) {
+ printf("SIDE EXIT: [UOp ");
+ _PyUOpPrint(&next_uop[-1]);
+ printf(", exit %u, temp %d, target %d -> %s]\n",
+ oparg, exit->temperature.as_counter,
+ (int)(target - _PyCode_CODE(code)),
+ _PyOpcode_OpName[target->op.code]);
+ }
+ #endif
+ if (exit->executor == NULL) {
+ _Py_BackoffCounter temperature = exit->temperature;
+ if (!backoff_counter_triggers(temperature)) {
+ exit->temperature = advance_backoff_counter(temperature);
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_ONE(target);
+ }
+ _PyExecutorObject *executor;
+ if (target->op.code == ENTER_EXECUTOR) {
+ executor = code->co_executors->executors[target->op.arg];
+ Py_INCREF(executor);
+ }
+ else {
+ int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
+ if (optimized <= 0) {
+ exit->temperature = restart_backoff_counter(temperature);
+ if (optimized < 0) {
+ Py_DECREF(current_executor);
+ tstate->previous_executor = Py_None;
+ GOTO_UNWIND();
+ }
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_ONE(target);
+ }
+ }
+ exit->executor = executor;
+ }
+ Py_INCREF(exit->executor);
+ tstate->previous_executor = (PyObject *)current_executor;
+ GOTO_TIER_TWO(exit->executor);
break;
}
@@ -4913,47 +4957,22 @@
break;
}
- case _COLD_EXIT: {
- oparg = CURRENT_OPARG();
- _PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
- _PyExitData *exit = &previous->exits[oparg];
- PyCodeObject *code = _PyFrame_GetCode(frame);
- _Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
- _Py_BackoffCounter temperature = exit->temperature;
- if (!backoff_counter_triggers(temperature)) {
- exit->temperature = advance_backoff_counter(temperature);
- GOTO_TIER_ONE(target);
- }
- _PyExecutorObject *executor;
- if (target->op.code == ENTER_EXECUTOR) {
- executor = code->co_executors->executors[target->op.arg];
- Py_INCREF(executor);
- }
- else {
- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
- if (optimized <= 0) {
- exit->temperature = restart_backoff_counter(temperature);
- if (optimized < 0) {
- Py_DECREF(previous);
- tstate->previous_executor = Py_None;
- GOTO_UNWIND();
- }
- GOTO_TIER_ONE(target);
- }
- }
- /* We need two references. One to store in exit->executor and
- * one to keep the executor alive when executing. */
- Py_INCREF(executor);
- exit->executor = executor;
- GOTO_TIER_TWO(executor);
- break;
- }
-
case _DYNAMIC_EXIT: {
oparg = CURRENT_OPARG();
tstate->previous_executor = (PyObject *)current_executor;
_PyExitData *exit = (_PyExitData *)&current_executor->exits[oparg];
_Py_CODEUNIT *target = frame->instr_ptr;
+ #if defined(Py_DEBUG) && !defined(_Py_JIT)
+ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
+ if (lltrace >= 2) {
+ printf("DYNAMIC EXIT: [UOp ");
+ _PyUOpPrint(&next_uop[-1]);
+ printf(", exit %u, temp %d, target %d -> %s]\n",
+ oparg, exit->temperature.as_counter,
+ (int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))),
+ _PyOpcode_OpName[target->op.code]);
+ }
+ #endif
_PyExecutorObject *executor;
if (target->op.code == ENTER_EXECUTOR) {
PyCodeObject *code = (PyCodeObject *)frame->f_executable;
diff --git a/Python/jit.c b/Python/jit.c
index d0c0d24..3332076 100644
--- a/Python/jit.c
+++ b/Python/jit.c
@@ -439,7 +439,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
group->emit(code, data, executor, NULL, instruction_starts);
code += group->code_size;
data += group->data_size;
- assert(trace[0].opcode == _START_EXECUTOR || trace[0].opcode == _COLD_EXIT);
+ assert(trace[0].opcode == _START_EXECUTOR);
for (size_t i = 0; i < length; i++) {
const _PyUOpInstruction *instruction = &trace[i];
group = &stencil_groups[instruction->opcode];
diff --git a/Python/optimizer.c b/Python/optimizer.c
index f7387dc..561ec4e 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -144,18 +144,6 @@ _Py_GetOptimizer(void)
static _PyExecutorObject *
make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies);
-static int
-init_cold_exit_executor(_PyExecutorObject *executor, int oparg);
-
-/* It is impossible for the number of exits to reach 1/4 of the total length,
- * as the number of exits cannot reach 1/3 of the number of non-exits, due to
- * the presence of CHECK_VALIDITY checks and instructions to produce the values
- * being checked in exits. */
-#define COLD_EXIT_COUNT (UOP_MAX_TRACE_LENGTH/4)
-
-static int cold_exits_initialized = 0;
-static _PyExecutorObject COLD_EXITS[COLD_EXIT_COUNT] = { 0 };
-
static const _PyBloomFilter EMPTY_FILTER = { 0 };
_PyOptimizerObject *
@@ -164,14 +152,6 @@ _Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject *optimizer)
if (optimizer == NULL) {
optimizer = &_PyOptimizer_Default;
}
- else if (cold_exits_initialized == 0) {
- cold_exits_initialized = 1;
- for (int i = 0; i < COLD_EXIT_COUNT; i++) {
- if (init_cold_exit_executor(&COLD_EXITS[i], i)) {
- return NULL;
- }
- }
- }
_PyOptimizerObject *old = interp->optimizer;
if (old == NULL) {
old = &_PyOptimizer_Default;
@@ -317,12 +297,6 @@ _PyUOpPrint(const _PyUOpInstruction *uop)
uop->jump_target,
(uint64_t)uop->operand);
break;
- case UOP_FORMAT_EXIT:
- printf(" (%d, exit_index=%d, operand=%#" PRIx64,
- uop->oparg,
- uop->exit_index,
- (uint64_t)uop->operand);
- break;
default:
printf(" (%d, Unknown format)", uop->oparg);
}
@@ -1094,7 +1068,7 @@ sanity_check(_PyExecutorObject *executor)
}
bool ended = false;
uint32_t i = 0;
- CHECK(executor->trace[0].opcode == _START_EXECUTOR || executor->trace[0].opcode == _COLD_EXIT);
+ CHECK(executor->trace[0].opcode == _START_EXECUTOR);
for (; i < executor->code_size; i++) {
const _PyUOpInstruction *inst = &executor->trace[i];
uint16_t opcode = inst->opcode;
@@ -1104,22 +1078,15 @@ sanity_check(_PyExecutorObject *executor)
case UOP_FORMAT_TARGET:
CHECK(target_unused(opcode));
break;
- case UOP_FORMAT_EXIT:
- CHECK(opcode == _EXIT_TRACE);
- CHECK(inst->exit_index < executor->exit_count);
- break;
case UOP_FORMAT_JUMP:
CHECK(inst->jump_target < executor->code_size);
break;
- case UOP_FORMAT_UNUSED:
- CHECK(0);
- break;
}
if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG) {
CHECK(inst->format == UOP_FORMAT_JUMP);
CHECK(inst->error_target < executor->code_size);
}
- if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE || opcode == _COLD_EXIT) {
+ if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) {
ended = true;
i++;
break;
@@ -1133,9 +1100,6 @@ sanity_check(_PyExecutorObject *executor)
opcode == _DEOPT ||
opcode == _EXIT_TRACE ||
opcode == _ERROR_POP_N);
- if (opcode == _EXIT_TRACE) {
- CHECK(inst->format == UOP_FORMAT_EXIT);
- }
}
}
@@ -1157,9 +1121,8 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
}
/* Initialize exits */
- assert(exit_count < COLD_EXIT_COUNT);
for (int i = 0; i < exit_count; i++) {
- executor->exits[i].executor = &COLD_EXITS[i];
+ executor->exits[i].executor = NULL;
executor->exits[i].temperature = initial_temperature_backoff_counter();
}
int next_exit = exit_count-1;
@@ -1173,8 +1136,7 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
assert(opcode != _POP_JUMP_IF_FALSE && opcode != _POP_JUMP_IF_TRUE);
if (opcode == _EXIT_TRACE) {
executor->exits[next_exit].target = buffer[i].target;
- dest->exit_index = next_exit;
- dest->format = UOP_FORMAT_EXIT;
+ dest->oparg = next_exit;
next_exit--;
}
if (opcode == _DYNAMIC_EXIT) {
@@ -1216,36 +1178,6 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
return executor;
}
-static int
-init_cold_exit_executor(_PyExecutorObject *executor, int oparg)
-{
- _Py_SetImmortalUntracked((PyObject *)executor);
- Py_SET_TYPE(executor, &_PyUOpExecutor_Type);
- executor->trace = (_PyUOpInstruction *)executor->exits;
- executor->code_size = 1;
- executor->exit_count = 0;
- _PyUOpInstruction *inst = (_PyUOpInstruction *)&executor->trace[0];
- inst->opcode = _COLD_EXIT;
- inst->oparg = oparg;
- executor->vm_data.valid = true;
- executor->vm_data.linked = false;
- for (int i = 0; i < _Py_BLOOM_FILTER_WORDS; i++) {
- assert(executor->vm_data.bloom.bits[i] == 0);
- }
-#ifdef Py_DEBUG
- sanity_check(executor);
-#endif
-#ifdef _Py_JIT
- executor->jit_code = NULL;
- executor->jit_side_entry = NULL;
- executor->jit_size = 0;
- if (_PyJIT_Compile(executor, executor->trace, 1)) {
- return -1;
- }
-#endif
- return 0;
-}
-
#ifdef Py_STATS
/* Returns the effective trace length.
* Ignores NOPs and trailing exit and error handling.*/
@@ -1258,8 +1190,7 @@ int effective_trace_length(_PyUOpInstruction *buffer, int length)
nop_count++;
}
if (opcode == _EXIT_TRACE ||
- opcode == _JUMP_TO_TOP ||
- opcode == _COLD_EXIT) {
+ opcode == _JUMP_TO_TOP) {
return i+1-nop_count;
}
}
@@ -1624,13 +1555,8 @@ executor_clear(_PyExecutorObject *executor)
*/
Py_INCREF(executor);
for (uint32_t i = 0; i < executor->exit_count; i++) {
- const _PyExecutorObject *cold = &COLD_EXITS[i];
- const _PyExecutorObject *side = executor->exits[i].executor;
executor->exits[i].temperature = initial_unreachable_backoff_counter();
- if (side != cold) {
- executor->exits[i].executor = cold;
- Py_DECREF(side);
- }
+ Py_CLEAR(executor->exits[i].executor);
}
_Py_ExecutorDetach(executor);
Py_DECREF(executor);
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index a414b04..978aa91 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -2180,10 +2180,6 @@
break;
}
- case _COLD_EXIT: {
- break;
- }
-
case _DYNAMIC_EXIT: {
break;
}