Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Revert "[wasm] Add a monitoring phase to jiterpreter traces and discard unproductive ones (#83432)" by kg · Pull Request #83446 · dotnet/runtime · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/mono/mono/mini/interp/interp.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -7787,7 +7787,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* (note that right now threading doesn't work, but it's worth being correct
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_MONITOR_JITERPRETER;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
Expand All@@ -7802,15 +7806,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_MONITOR_JITERPRETER) {
// The trace is in monitoring mode, where we track how far it actually goes
// each time it is executed for a while. After N more hits, we either
// turn it into an ENTER or a NOP depending on how well it is working
ptrdiff_t offset = mono_jiterp_monitor_trace (ip, frame, locals);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
ptrdiff_t offset = thunk(frame, locals);
Expand Down
71 changes: 0 additions & 71 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -863,24 +863,13 @@ typedef struct {
// 64-bits because it can get very high if estimate heat is turned on
gint64 hit_count;
JiterpreterThunk thunk;
int size_of_trace;
gint32 total_distance;
} TraceInfo;

// If a trace exits with an exterior backward branch, treat its distance as this value
#define TRACE_NEGATIVE_DISTANCE 64
// Don't allow a trace to increase the total distance by more than this amount, since
// it would skew the average too much
#define TRACE_DISTANCE_LIMIT 512

// The maximum number of trace segments used to store TraceInfo. This limits
// the maximum total number of traces to MAX_TRACE_SEGMENTS * TRACE_SEGMENT_SIZE
#define MAX_TRACE_SEGMENTS 256
#define TRACE_SEGMENT_SIZE 1024

static volatile gint32 trace_count = 0;
static TraceInfo *trace_segments[MAX_TRACE_SEGMENTS] = { NULL };
static gint32 traces_rejected = 0;

static TraceInfo *
trace_info_allocate_segment (gint32 index) {
Expand DownExpand Up@@ -1041,9 +1030,6 @@ mono_interp_tier_prepare_jiterpreter_fast (
frame, method, ip, (gint32)trace_index,
start_of_body, size_of_body
);
// Record the maximum size of the trace (we don't know how long it actually is here)
// which might be smaller than the function body if this trace is in the middle
trace_info->size_of_trace = size_of_body - (ip - start_of_body);
trace_info->thunk = result;
return result;
} else {
Expand DownExpand Up@@ -1323,63 +1309,6 @@ mono_jiterp_write_number_unaligned (void *dest, double value, int mode) {
}
}

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals)
{
gint32 index = READ32(ip + 1);
TraceInfo *info = trace_info_get(index);
g_assert(info);

JiterpreterThunk thunk = info->thunk;
// FIXME: This shouldn't be possible
if (((guint32)(void *)thunk) <= JITERPRETER_NOT_JITTED)
return 6;
ptrdiff_t result = thunk(frame, locals);
// Maintain an approximate sum of how far trace execution has advanced over
// the monitoring period, so we can evaluate its average later and decide
// whether to keep the trace
// Note that a result of 0 means that a loop back-branched to itself.
info->total_distance += result <= 0
? TRACE_NEGATIVE_DISTANCE
: (result > TRACE_DISTANCE_LIMIT
? TRACE_DISTANCE_LIMIT
: result
);

gint64 hit_count = info->hit_count++ - mono_opt_jiterpreter_minimum_trace_hit_count;
if (hit_count == mono_opt_jiterpreter_trace_monitoring_period) {
// Prepare to enable the trace
volatile guint16 *mutable_ip = (volatile guint16*)ip;
*mutable_ip = MINT_TIER_NOP_JITERPRETER;

mono_memory_barrier ();
gint64 average_distance = info->total_distance / hit_count;
gint64 threshold = mono_opt_jiterpreter_trace_average_distance_threshold,
low_threshold = info->size_of_trace / 2;
// Don't reject short traces as long as they run mostly to the end, we already
// decided previously that they are worth keeping for some reason
if (low_threshold < threshold)
threshold = low_threshold;

if (average_distance >= threshold) {
*(volatile JiterpreterThunk*)(ip + 1) = thunk;
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
} else {
traces_rejected++;
// g_print("trace #%d @%d rejected; average_distance==%d\n", index, ip, average_distance);
}
}

return result;
}

EMSCRIPTEN_KEEPALIVE gint32
mono_jiterp_get_rejected_trace_count ()
{
return traces_rejected;
}

// HACK: fix C4206
EMSCRIPTEN_KEEPALIVE
#endif // HOST_BROWSER
Expand Down
3 changes: 0 additions & 3 deletions src/mono/mono/mini/interp/jiterpreter.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,9 +139,6 @@ mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod);
void
mono_jiterp_enum_hasflag (MonoClass *klass, gint32 *dest, stackval *sp1, stackval *sp2);

ptrdiff_t
mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals);

#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__

extern WasmDoJitCall jiterpreter_do_jit_call;
Expand Down
1 change: 0 additions & 1 deletion src/mono/mono/mini/interp/mintops.def
Original file line numberDiff line numberDiff line change
Expand Up@@ -841,7 +841,6 @@ OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoS
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_MONITOR_JITERPRETER, "tier_monitor_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
Expand Down
4 changes: 0 additions & 4 deletions src/mono/mono/utils/options-def.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,10 +119,6 @@ DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length",
DEFINE_INT(jiterpreter_minimum_distance_between_traces, "jiterpreter-minimum-distance-between-traces", 4, "Don't insert entry points closer together than this")
// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times
DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 5000, "JIT trace entry points once they are hit this many times")
// trace prepares turn into a monitor opcode and stay one this long before being converted to enter or nop
DEFINE_INT(jiterpreter_trace_monitoring_period, "jiterpreter-trace-monitoring-period", 3000, "Monitor jitted traces for this many calls to determine whether to keep them")
// traces that only offset ip by less than this on average will be rejected
DEFINE_INT(jiterpreter_trace_average_distance_threshold, "jiterpreter-trace-average-distance-threshold", 52, "Traces with an average distance less than this will be discarded")
// 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: 0 additions & 2 deletions src/mono/wasm/runtime/cwraps.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,7 +120,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_debug_count", "number", []],
[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", []],
...legacy_interop_cwraps
];

Expand DownExpand Up@@ -237,7 +236,6 @@ export interface t_Cwraps {
mono_jiterp_get_trace_hit_count(traceIndex: number): number;
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;
}

const wrapped_c_functions: t_Cwraps = <any>{};
Expand Down
3 changes: 1 addition & 2 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -955,8 +955,7 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {

console.log(`// jitted ${counters.bytesGenerated} bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
const backBranchHitRate = (counters.backBranchesEmitted / (counters.backBranchesEmitted + counters.backBranchesNotEmitted)) * 100;
const tracesRejected = cwraps.mono_jiterp_get_rejected_trace_count();
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} cknulls removed. ${counters.backBranchesEmitted} back-branches (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%), ${tracesRejected} traces rejected`);
console.log(`// time: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm. ${counters.nullChecksEliminated} null checks eliminated. ${counters.backBranchesEmitted} back-branches emitted (${counters.backBranchesNotEmitted} failed, ${backBranchHitRate.toFixed(1)}%)`);
if (concise)
return;

Expand Down