Skip to content

Commit

Permalink
If a back branch target can't be reached from inside the current trac…
Browse files Browse the repository at this point in the history
…e and it is a trace prepare point, boost its hit count

This will cause it to get jitted sooner
  • Loading branch information
kg committed Mar 25, 2023
1 parent 975affb commit aa55a35
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 22 deletions.
25 changes: 25 additions & 0 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,31 @@ mono_jiterp_get_rejected_trace_count ()
return traces_rejected;
}

EMSCRIPTEN_KEEPALIVE void
mono_jiterp_boost_back_branch_target (guint16 *ip) {
if (*ip != MINT_TIER_PREPARE_JITERPRETER) {
// g_print ("Failed to boost back branch target %d because it was %s\n", ip, mono_interp_opname(*ip));
return;
}

guint32 trace_index = READ32 (ip + 1);
if (!trace_index)
return;

TraceInfo *trace_info = trace_info_get (trace_index);
// We need to make sure we don't boost the hit count too high, because if we do
// it will increment past the compile threshold and never compile
int limit = mono_opt_jiterpreter_minimum_trace_hit_count - 1,
old_hit_count = trace_info->hit_count;
trace_info->hit_count = MIN (limit, trace_info->hit_count + mono_opt_jiterpreter_back_branch_boost);
/*
if (trace_info->hit_count > old_hit_count)
g_print ("Boosted entry point #%d at %d to %d\n", trace_index, ip, trace_info->hit_count);
else
g_print ("Entry point #%d at %d was already maxed out\n", trace_index, ip, trace_info->hit_count);
*/
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/utils/options-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ DEFINE_INT(jiterpreter_trace_monitoring_long_distance, "jiterpreter-trace-monito
DEFINE_INT(jiterpreter_trace_monitoring_max_average_penalty, "jiterpreter-trace-monitoring-max-average-penalty", 75, "If the average penalty value for a trace is above this value it will be rejected")
// 0 = no monitoring, 1 = log when rejecting a trace, 2 = log when accepting or rejecting a trace, 3 = log every recorded bailout
DEFINE_INT(jiterpreter_trace_monitoring_log, "jiterpreter-trace-monitoring-log", 0, "Logging detail level for trace monitoring")
// if a trace fails to back branch outside of itself, and there is a prepare point at the branch target, boost
// the hit count of that prepare point so it will JIT much sooner
DEFINE_INT(jiterpreter_back_branch_boost, "jiterpreter-back-branch-boost", 4900, "Boost the hit count of prepare points targeted by a failed backward branch")
// After a do_jit_call call site is hit this many times, we will queue it to be jitted
DEFINE_INT(jiterpreter_jit_call_trampoline_hit_count, "jiterpreter-jit-call-hit-count", 1000, "Queue specialized do_jit_call trampoline for JIT after this many hits")
// After a do_jit_call call site is hit this many times without being jitted, we will flush the JIT queue
Expand Down
2 changes: 2 additions & 0 deletions src/mono/wasm/runtime/cwraps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_get_trace_hit_count", "number", ["number"]],
[true, "mono_jiterp_get_polling_required_address", "number", []],
[true, "mono_jiterp_get_rejected_trace_count", "number", []],
[true, "mono_jiterp_boost_back_branch_target", "void", ["number"]],
...legacy_interop_cwraps
];

Expand Down Expand Up @@ -240,6 +241,7 @@ export interface t_Cwraps {
mono_jiterp_get_polling_required_address(): Int32Ptr;
mono_jiterp_write_number_unaligned(destination: VoidPtr, value: number, mode: number): void;
mono_jiterp_get_rejected_trace_count(): number;
mono_jiterp_boost_back_branch_target(destination: number): void;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
2 changes: 2 additions & 0 deletions src/mono/wasm/runtime/jiterpreter-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,7 @@ export type JiterpreterOptions = {
monitoringShortDistance: number;
monitoringLongDistance: number;
monitoringMaxAveragePenalty: number;
backBranchBoost: number;
jitCallHitCount: number;
jitCallFlushThreshold: number;
interpEntryHitCount: number;
Expand Down Expand Up @@ -1641,6 +1642,7 @@ const optionNames : { [jsName: string] : string } = {
"monitoringShortDistance": "jiterpreter-trace-monitoring-short-distance",
"monitoringLongDistance": "jiterpreter-trace-monitoring-long-distance",
"monitoringMaxAveragePenalty": "jiterpreter-trace-monitoring-max-average-penalty",
"backBranchBoost": "jiterpreter-back-branch-boost",
"jitCallHitCount": "jiterpreter-jit-call-hit-count",
"jitCallFlushThreshold": "jiterpreter-jit-call-queue-flush-threshold",
"interpEntryHitCount": "jiterpreter-interp-entry-hit-count",
Expand Down
38 changes: 17 additions & 21 deletions src/mono/wasm/runtime/jiterpreter-trace-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export function generate_wasm_body (
// We record the offset of each backward branch we encounter, so that later branch
// opcodes know that it's available by branching to the top of the dispatch loop
if (isBackBranchTarget) {
if (traceBackBranches)
if (traceBackBranches > 1)
console.log(`${traceName} recording back branch target 0x${(<any>ip).toString(16)}`);
builder.backBranchOffsets.push(ip);
}
Expand Down Expand Up @@ -845,7 +845,7 @@ export function generate_wasm_body (
else
callTargetCounts[<any>targetMethod] = 1;
}
if (builder.branchTargets.size > 0) {
if (isConditionallyExecuted) {
// We generate a bailout instead of aborting, because we don't want calls
// to abort the entire trace if we have branch support enabled - the call
// might be infrequently hit and as a result it's worth it to keep going.
Expand All @@ -868,7 +868,7 @@ export function generate_wasm_body (
case MintOpcode.MINT_CALLI_NAT_FAST:
case MintOpcode.MINT_CALL_DELEGATE:
// See comments for MINT_CALL
if (builder.branchTargets.size > 0) {
if (isConditionallyExecuted) {
append_exit(builder, ip, exitOpcodeCounter,
opcode == MintOpcode.MINT_CALL_DELEGATE
? BailoutReason.CallDelegate
Expand All @@ -888,7 +888,7 @@ export function generate_wasm_body (
case MintOpcode.MINT_ICALL_PP_V:
case MintOpcode.MINT_ICALL_PP_P:
// See comments for MINT_CALL
if (builder.branchTargets.size > 0) {
if (isConditionallyExecuted) {
append_bailout(builder, ip, BailoutReason.Icall);
isLowValueOpcode = true;
} else {
Expand All @@ -900,16 +900,10 @@ export function generate_wasm_body (
// MONO_RETHROW appears to show up in other places, so it's worth conditional bailout
case MintOpcode.MINT_MONO_RETHROW:
case MintOpcode.MINT_THROW:
// As above, only abort if this throw happens unconditionally.
// Otherwise, it may be in a branch that is unlikely to execute
if (builder.branchTargets.size > 0) {
// Not an exit, because throws are by definition unlikely
// We shouldn't make optimization decisions based on them.
append_bailout(builder, ip, BailoutReason.Throw);
isLowValueOpcode = true;
} else {
ip = abort;
}
// Not an exit, because throws are by definition unlikely
// We shouldn't make optimization decisions based on them.
append_bailout(builder, ip, BailoutReason.Throw);
isLowValueOpcode = true;
break;

case MintOpcode.MINT_ENDFINALLY:
Expand Down Expand Up @@ -1102,7 +1096,7 @@ export function generate_wasm_body (
(opcode <= MintOpcode.MINT_RET_I8_IMM)
)
) {
if ((builder.branchTargets.size > 0) || trapTraceErrors || builder.options.countBailouts) {
if (isConditionallyExecuted || trapTraceErrors || builder.options.countBailouts) {
// Not an exit, because returns are normal and we don't want to make them more expensive.
// FIXME: Or do we want to record them? Early conditional returns might reduce the value of a trace,
// but the main problem is more likely to be calls early in traces. Worth testing later.
Expand Down Expand Up @@ -1227,7 +1221,7 @@ export function generate_wasm_body (
}

if (!isLowValueOpcode) {
if (inBranchBlock)
if (isConditionallyExecuted)
conditionalOpcodeCounter++;
else
prologueOpcodeCounter++;
Expand Down Expand Up @@ -2433,18 +2427,19 @@ function emit_branch (
// We found a backward branch target we can branch to, so we branch out
// to the top of the loop body
// append_safepoint(builder, ip);
if (traceBackBranches)
if (traceBackBranches > 1)
console.log(`performing backward branch to 0x${destination.toString(16)}`);
if (isCallHandler)
append_call_handler_store_ret_ip(builder, ip, frame, opcode);
builder.cfg.branch(destination, true, false);
counters.backBranchesEmitted++;
return true;
} else {
if (traceBackBranches)
if (traceBackBranches > 0)
console.log(`back branch target 0x${destination.toString(16)} not found`);
cwraps.mono_jiterp_boost_back_branch_target(destination);
// FIXME: Should there be a safepoint here?
append_bailout(builder, destination, displacement > 0 ? BailoutReason.Branch : BailoutReason.BackwardBranch);
append_bailout(builder, destination, BailoutReason.BackwardBranch);
counters.backBranchesNotEmitted++;
return true;
}
Expand Down Expand Up @@ -2523,14 +2518,15 @@ function emit_branch (
if (builder.backBranchOffsets.indexOf(destination) >= 0) {
// We found a backwards branch target we can reach via our outer trace loop, so
// we update eip and branch out to the top of the loop block
if (traceBackBranches)
if (traceBackBranches > 1)
console.log(`performing conditional backward branch to 0x${destination.toString(16)}`);
builder.cfg.branch(destination, true, true);
counters.backBranchesEmitted++;
} else {
if (traceBackBranches)
if (traceBackBranches > 0)
console.log(`back branch target 0x${destination.toString(16)} not found`);
// We didn't find a loop to branch to, so bail out
cwraps.mono_jiterp_boost_back_branch_target(destination);
append_bailout(builder, destination, BailoutReason.BackwardBranch);
counters.backBranchesNotEmitted++;
}
Expand Down
3 changes: 2 additions & 1 deletion src/mono/wasm/runtime/jiterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ export const
// Print diagnostic information to the console when performing null check optimizations
traceNullCheckOptimizations = false,
// Print diagnostic information when generating backward branches
traceBackBranches = false,
// 1 = failures only, 2 = full detail
traceBackBranches = 0,
// If we encounter an enter opcode that looks like a loop body and it was already
// jitted, we should abort the current trace since it's not worth continuing
// Unproductive if we have backward branches enabled because it can stop us from jitting
Expand Down

0 comments on commit aa55a35

Please sign in to comment.