diff options
author | Brandt Bucher <brandtbucher@microsoft.com> | 2024-07-01 20:17:40 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-01 20:17:40 (GMT) |
commit | 33903c53dbdb768e1ef7c46d347869577f2173ce (patch) | |
tree | 9e1e8473028f803ece96c8ccbde3f6bfef08ade3 /Python | |
parent | 294e72496439da984cb8dba9100d3613c8cc8a6d (diff) | |
download | cpython-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.c | 93 | ||||
-rw-r--r-- | Python/ceval.c | 23 | ||||
-rw-r--r-- | Python/ceval_macros.h | 3 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 93 | ||||
-rw-r--r-- | Python/jit.c | 2 | ||||
-rw-r--r-- | Python/optimizer.c | 86 | ||||
-rw-r--r-- | Python/optimizer_cases.c.h | 4 |
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 = ¤t_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 *)¤t_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 = ¤t_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 = ¤t_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 *)¤t_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; } |