Skip to content

Commit 2f9438a

Browse files
committed
Rewrite the code structure
1 parent 1bfa176 commit 2f9438a

File tree

4 files changed

+57
-42
lines changed

4 files changed

+57
-42
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,11 @@ typedef struct _PyOptimizationConfig {
458458
uint16_t fitness_backward_edge;
459459
uint16_t fitness_frame_entry;
460460

461+
// Exit quality thresholds for fitness-based trace termination
462+
uint16_t exit_quality_enter_executor;
463+
uint16_t exit_quality_default;
464+
uint16_t exit_quality_specializable;
465+
461466
// Optimization flags
462467
bool specialization_enabled;
463468
bool uops_optimize_enabled;

Include/internal/pycore_optimizer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ extern "C" {
2525
#define FITNESS_BACKWARD_EDGE 80
2626
#define FITNESS_FRAME_ENTRY 10
2727

28+
/* Default exit quality constants for fitness-based trace termination.
29+
* Higher values mean better places to stop the trace.
30+
* These can be overridden via PYTHON_JIT_EXIT_QUALITY_* environment variables. */
31+
#define EXIT_QUALITY_ENTER_EXECUTOR 500
32+
#define EXIT_QUALITY_DEFAULT 200
33+
#define EXIT_QUALITY_SPECIALIZABLE 50
34+
2835

2936
typedef struct _PyJitUopBuffer {
3037
_PyUOpInstruction *start;

Python/optimizer.c

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -549,11 +549,6 @@ dynamic_exit_uop[MAX_UOP_ID + 1] = {
549549
};
550550

551551

552-
/* Exit quality constants for fitness-based trace termination.
553-
* Higher values mean better places to stop the trace. */
554-
#define EXIT_QUALITY_ENTER_EXECUTOR 500 // An executor already exists here
555-
#define EXIT_QUALITY_DEFAULT 200 // Ordinary bytecode position
556-
#define EXIT_QUALITY_SPECIALIZABLE 50 // Specializable instruction — avoid stopping here
557552

558553
#ifdef Py_DEBUG
559554
#define DPRINTF(level, ...) \
@@ -613,15 +608,16 @@ compute_branch_bias(uint16_t history)
613608
/* Compute exit quality for the current trace position.
614609
* Higher values mean it's a better place to stop the trace. */
615610
static inline int32_t
616-
compute_exit_quality(_Py_CODEUNIT *target_instr, int opcode)
611+
compute_exit_quality(_Py_CODEUNIT *target_instr, int opcode,
612+
const _PyOptimizationConfig *cfg)
617613
{
618614
if (target_instr->op.code == ENTER_EXECUTOR) {
619-
return EXIT_QUALITY_ENTER_EXECUTOR;
615+
return (int32_t)cfg->exit_quality_enter_executor;
620616
}
621617
if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) {
622-
return EXIT_QUALITY_SPECIALIZABLE;
618+
return (int32_t)cfg->exit_quality_specializable;
623619
}
624-
return EXIT_QUALITY_DEFAULT;
620+
return (int32_t)cfg->exit_quality_default;
625621
}
626622

627623
/* Try to truncate the trace to the best recorded exit point.
@@ -674,7 +670,6 @@ update_trace_fitness(
674670
case JUMP_BACKWARD_NO_JIT:
675671
ts->fitness -= cfg->fitness_backward_edge;
676672
break;
677-
/* JUMP_BACKWARD_NO_INTERRUPT: exempt from backward edge penalty (coroutines) */
678673
default:
679674
break;
680675
}
@@ -817,15 +812,13 @@ _PyJit_translate_single_bytecode_to_trace(
817812
if (frame != tracer->prev_state.instr_frame) {
818813
_PyJitTracerTranslatorState *ts_depth = &tracer->translator_state;
819814
if (frame->previous == tracer->prev_state.instr_frame) {
820-
// Entered a deeper frame (function call inlined)
821815
ts_depth->frame_depth++;
822816
// Penalty scales with depth: shallow inlining is cheap,
823817
// deep inlining gets progressively more expensive.
824818
int32_t penalty = (int32_t)tstate->interp->opt_config.fitness_frame_entry
825819
* ts_depth->frame_depth;
826820
ts_depth->fitness -= penalty;
827821
} else if (ts_depth->frame_depth > 0) {
828-
// Returned to a shallower frame
829822
ts_depth->frame_depth--;
830823
}
831824
}
@@ -838,7 +831,7 @@ _PyJit_translate_single_bytecode_to_trace(
838831
// prefer it over rewinding to last _SET_IP — this covers the
839832
// main unsupported path, not just the edge case.
840833
_PyJitTracerTranslatorState *ts_unsup = &tracer->translator_state;
841-
if (ts_unsup->best_exit_quality > EXIT_QUALITY_DEFAULT &&
834+
if (ts_unsup->best_exit_quality > (int32_t)tstate->interp->opt_config.exit_quality_default &&
842835
try_best_exit_fallback(trace, ts_unsup, progress_needed)) {
843836
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, ts_unsup->best_exit_target);
844837
uop_buffer_last(trace)->operand1 = true; // is_control_flow
@@ -876,37 +869,36 @@ _PyJit_translate_single_bytecode_to_trace(
876869
}
877870

878871
// Fitness-based trace quality check (before reserving space for this instruction)
879-
{
880-
_PyJitTracerTranslatorState *ts = &tracer->translator_state;
881-
int32_t eq = compute_exit_quality(target_instr, opcode);
882-
883-
// Record best exit candidate.
884-
// Only record after minimum progress to avoid truncating to near-empty traces.
885-
if (eq > ts->best_exit_quality &&
886-
uop_buffer_length(trace) > CODE_SIZE_NO_PROGRESS) {
887-
ts->best_exit_quality = eq;
888-
ts->best_exit_buffer_pos = uop_buffer_length(trace);
889-
ts->best_exit_target = target;
872+
_PyJitTracerTranslatorState *ts = &tracer->translator_state;
873+
int32_t eq = compute_exit_quality(target_instr, opcode,
874+
&tstate->interp->opt_config);
875+
876+
// Record best exit candidate.
877+
// Only record after minimum progress to avoid truncating to near-empty traces.
878+
if (eq > ts->best_exit_quality &&
879+
uop_buffer_length(trace) > CODE_SIZE_NO_PROGRESS) {
880+
ts->best_exit_quality = eq;
881+
ts->best_exit_buffer_pos = uop_buffer_length(trace);
882+
ts->best_exit_target = target;
883+
}
884+
885+
// Check if fitness is depleted — should we stop the trace?
886+
if (ts->fitness < eq &&
887+
!(progress_needed && uop_buffer_length(trace) < CODE_SIZE_NO_PROGRESS)) {
888+
// Prefer stopping at the best recorded exit point
889+
if (try_best_exit_fallback(trace, ts, progress_needed)) {
890+
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, ts->best_exit_target);
891+
uop_buffer_last(trace)->operand1 = true; // is_control_flow
890892
}
891-
892-
// Check if fitness is depleted — should we stop the trace?
893-
if (ts->fitness < eq &&
894-
!(progress_needed && uop_buffer_length(trace) < CODE_SIZE_NO_PROGRESS)) {
895-
// Prefer stopping at the best recorded exit point
896-
if (try_best_exit_fallback(trace, ts, progress_needed)) {
897-
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, ts->best_exit_target);
898-
uop_buffer_last(trace)->operand1 = true; // is_control_flow
899-
}
900-
else {
901-
// No valid best exit — stop at current position
902-
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target);
903-
uop_buffer_last(trace)->operand1 = true; // is_control_flow
904-
}
905-
OPT_STAT_INC(fitness_terminated_traces);
906-
DPRINTF(2, "Fitness terminated: fitness=%d < exit_quality=%d\n",
907-
ts->fitness, eq);
908-
goto done;
893+
else {
894+
// No valid best exit — stop at current position
895+
ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target);
896+
uop_buffer_last(trace)->operand1 = true; // is_control_flow
909897
}
898+
OPT_STAT_INC(fitness_terminated_traces);
899+
DPRINTF(2, "Fitness terminated: fitness=%d < exit_quality=%d\n",
900+
ts->fitness, eq);
901+
goto done;
910902
}
911903

912904
// One for possible _DEOPT, one because _CHECK_VALIDITY itself might _DEOPT

Python/pystate.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,17 @@ init_interpreter(PyInterpreterState *interp,
658658
"PYTHON_JIT_FITNESS_FRAME_ENTRY",
659659
FITNESS_FRAME_ENTRY, 0, 1000);
660660

661+
// Exit quality thresholds
662+
init_policy(&interp->opt_config.exit_quality_enter_executor,
663+
"PYTHON_JIT_EXIT_QUALITY_ENTER_EXECUTOR",
664+
EXIT_QUALITY_ENTER_EXECUTOR, 0, 10000);
665+
init_policy(&interp->opt_config.exit_quality_default,
666+
"PYTHON_JIT_EXIT_QUALITY_DEFAULT",
667+
EXIT_QUALITY_DEFAULT, 0, 10000);
668+
init_policy(&interp->opt_config.exit_quality_specializable,
669+
"PYTHON_JIT_EXIT_QUALITY_SPECIALIZABLE",
670+
EXIT_QUALITY_SPECIALIZABLE, 0, 10000);
671+
661672
interp->opt_config.specialization_enabled = !is_env_enabled("PYTHON_SPECIALIZATION_OFF");
662673
interp->opt_config.uops_optimize_enabled = !is_env_disabled("PYTHON_UOPS_OPTIMIZE");
663674
if (interp != &runtime->_main_interpreter) {

0 commit comments

Comments
 (0)