Skip to content

Commit fa45ae8

Browse files
add stats, document
1 parent 8993e6c commit fa45ae8

File tree

4 files changed

+35
-27
lines changed

4 files changed

+35
-27
lines changed

Include/cpython/pystats.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ typedef struct _optimization_stats {
150150
uint64_t optimized_trace_length_hist[_Py_UOP_HIST_SIZE];
151151
uint64_t optimizer_attempts;
152152
uint64_t optimizer_successes;
153+
uint64_t optimizer_contradiction;
154+
uint64_t optimizer_frame_overflow;
153155
uint64_t optimizer_failure_reason_no_memory;
154156
uint64_t remove_globals_builtins_changed;
155157
uint64_t remove_globals_incorrect_keys;

Python/optimizer.c

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929

3030
#define MAX_EXECUTORS_SIZE 256
3131

32+
// Trace too short, no progress:
33+
// _START_EXECUTOR
34+
// _MAKE_WARM
35+
// _CHECK_VALIDITY
36+
// _SET_IP
37+
// is 4-5 instructions.
38+
#define CODE_SIZE_NO_PROGRESS 5
39+
// We start with _START_EXECUTOR, _MAKE_WARM
40+
#define CODE_SIZE_EMPTY 2
41+
3242
#define _PyExecutorObject_CAST(op) ((_PyExecutorObject *)(op))
3343

3444
static bool
@@ -489,6 +499,14 @@ BRANCH_TO_GUARD[4][2] = {
489499
[POP_JUMP_IF_NOT_NONE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_NOT_NONE_POP,
490500
};
491501

502+
static const uint16_t
503+
guard_ip_uop[MAX_UOP_ID + 1] = {
504+
[_PUSH_FRAME] = _GUARD_IP__PUSH_FRAME,
505+
[_RETURN_GENERATOR] = _GUARD_IP_RETURN_GENERATOR,
506+
[_RETURN_VALUE] = _GUARD_IP_RETURN_VALUE,
507+
[_YIELD_VALUE] = _GUARD_IP_YIELD_VALUE,
508+
};
509+
492510

493511
#define CONFIDENCE_RANGE 1000
494512
#define CONFIDENCE_CUTOFF 333
@@ -601,7 +619,7 @@ _PyJit_translate_single_bytecode_to_trace(
601619

602620
/* Special case the first instruction,
603621
* so that we can guarantee forward progress */
604-
if (progress_needed && _tstate->jit_tracer_state.prev_state.code_curr_size <= 3) {
622+
if (progress_needed && _tstate->jit_tracer_state.prev_state.code_curr_size <= CODE_SIZE_NO_PROGRESS) {
605623
if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) {
606624
opcode = _PyOpcode_Deopt[opcode];
607625
}
@@ -750,7 +768,7 @@ _PyJit_translate_single_bytecode_to_trace(
750768
{
751769
if ((next_instr != _tstate->jit_tracer_state.initial_state.close_loop_instr) &&
752770
(next_instr != _tstate->jit_tracer_state.initial_state.start_instr) &&
753-
_tstate->jit_tracer_state.prev_state.code_curr_size > 5 &&
771+
_tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS &&
754772
// For side exits, we don't want to terminate them early.
755773
_tstate->jit_tracer_state.initial_state.exit == NULL &&
756774
// These are coroutines, and we want to unroll those usually.
@@ -898,28 +916,17 @@ _PyJit_translate_single_bytecode_to_trace(
898916
} // End switch (opcode)
899917

900918
if (needs_guard_ip) {
901-
switch (trace[trace_length-1].opcode) {
902-
case _PUSH_FRAME:
903-
ADD_TO_TRACE(_GUARD_IP__PUSH_FRAME, 0, (uintptr_t)next_instr, 0);
904-
break;
905-
case _RETURN_GENERATOR:
906-
ADD_TO_TRACE(_GUARD_IP_RETURN_GENERATOR, 0, (uintptr_t)next_instr, 0);
907-
break;
908-
case _RETURN_VALUE:
909-
ADD_TO_TRACE(_GUARD_IP_RETURN_VALUE, 0, (uintptr_t)next_instr, 0);
910-
break;
911-
case _YIELD_VALUE:
912-
ADD_TO_TRACE(_GUARD_IP_YIELD_VALUE, 0, (uintptr_t)next_instr, 0);
913-
break;
914-
default:
915-
DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[trace[trace_length-1].opcode]);
916-
Py_UNREACHABLE();
919+
uint16_t guard_ip = guard_ip_uop[trace[trace_length-1].opcode];
920+
if (guard_ip == 0) {
921+
DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[trace[trace_length-1].opcode]);
922+
Py_UNREACHABLE();
917923
}
924+
ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0);
918925
}
919926
// Loop back to the start
920927
int is_first_instr = _tstate->jit_tracer_state.initial_state.close_loop_instr == next_instr ||
921928
_tstate->jit_tracer_state.initial_state.start_instr == next_instr;
922-
if (is_first_instr && _tstate->jit_tracer_state.prev_state.code_curr_size > 5) {
929+
if (is_first_instr && _tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS) {
923930
if (needs_guard_ip) {
924931
ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)next_instr, 0);
925932
}
@@ -961,7 +968,7 @@ _PyJit_TryInitializeTracing(
961968
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
962969
// A recursive trace.
963970
// Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces.
964-
if (_tstate->jit_tracer_state.prev_state.code_curr_size > 2) {
971+
if (_tstate->jit_tracer_state.prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS) {
965972
return 0;
966973
}
967974
if (oparg > 0xFFFF) {
@@ -996,7 +1003,7 @@ _PyJit_TryInitializeTracing(
9961003

9971004
add_to_trace(_tstate->jit_tracer_state.code_buffer, 0, _START_EXECUTOR, 0, (uintptr_t)start_instr, INSTR_IP(start_instr, code));
9981005
add_to_trace(_tstate->jit_tracer_state.code_buffer, 1, _MAKE_WARM, 0, 0, 0);
999-
_tstate->jit_tracer_state.prev_state.code_curr_size = 2;
1006+
_tstate->jit_tracer_state.prev_state.code_curr_size = CODE_SIZE_EMPTY;
10001007

10011008
_tstate->jit_tracer_state.prev_state.code_max_size = UOP_MAX_TRACE_LENGTH;
10021009
_tstate->jit_tracer_state.initial_state.start_instr = start_instr;
@@ -1031,7 +1038,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate)
10311038
Py_CLEAR(_tstate->jit_tracer_state.initial_state.code);
10321039
Py_CLEAR(_tstate->jit_tracer_state.initial_state.func);
10331040
Py_CLEAR(_tstate->jit_tracer_state.prev_state.instr_code);
1034-
_tstate->jit_tracer_state.prev_state.code_curr_size = 2;
1041+
_tstate->jit_tracer_state.prev_state.code_curr_size = CODE_SIZE_EMPTY;
10351042
_tstate->jit_tracer_state.prev_state.code_max_size = UOP_MAX_TRACE_LENGTH - 1;
10361043
}
10371044

@@ -1112,18 +1119,16 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length)
11121119
exit_op = _HANDLE_PENDING_AND_DEOPT;
11131120
}
11141121
int32_t jump_target = target;
1115-
bool unique_target = false;
11161122
if (
11171123
opcode == _GUARD_IP__PUSH_FRAME ||
11181124
opcode == _GUARD_IP_RETURN_VALUE ||
11191125
opcode == _GUARD_IP_YIELD_VALUE ||
11201126
opcode == _GUARD_IP_RETURN_GENERATOR
11211127
) {
11221128
exit_op = _DYNAMIC_EXIT;
1123-
unique_target = true;
11241129
}
11251130
bool is_control_flow = (opcode == _GUARD_IS_FALSE_POP || opcode == _GUARD_IS_TRUE_POP || is_for_iter_test[opcode]);
1126-
if (unique_target || jump_target != current_jump_target || current_exit_op != exit_op) {
1131+
if (jump_target != current_jump_target || current_exit_op != exit_op) {
11271132
make_exit(&buffer[next_spare], exit_op, jump_target, is_control_flow);
11281133
current_exit_op = exit_op;
11291134
current_jump_target = jump_target;
@@ -1363,8 +1368,7 @@ uop_optimize(
13631368
}
13641369
int curr_stackentries = _tstate->jit_tracer_state.initial_state.stack_depth;
13651370
int length = _tstate->jit_tracer_state.prev_state.code_curr_size;
1366-
// Trace too short, don't bother.
1367-
if (length <= 5) {
1371+
if (length <= CODE_SIZE_NO_PROGRESS) {
13681372
return 0;
13691373
}
13701374
assert(length > 0);

Python/optimizer_analysis.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ optimize_uops(
368368
DPRINTF(3, "\n");
369369
DPRINTF(1, "Hit bottom in abstract interpreter\n");
370370
_Py_uop_abstractcontext_fini(ctx);
371+
OPT_STAT_INC(optimizer_contradiction);
371372
return 0;
372373
}
373374

Python/optimizer_symbols.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ _Py_uop_frame_new(
820820
if (ctx->curr_frame_depth >= MAX_ABSTRACT_FRAME_DEPTH) {
821821
ctx->done = true;
822822
ctx->out_of_space = true;
823+
OPT_STAT_INC(optimizer_frame_overflow);
823824
return NULL;
824825
}
825826
_Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth];

0 commit comments

Comments
 (0)