Skip to content

Commit 3c0cb00

Browse files
committed
pd-vm: codex: lower ldloc.copy directly in jit traces
1 parent c778884 commit 3c0cb00

9 files changed

Lines changed: 219 additions & 94 deletions

File tree

pd-vm/examples/mini_bench.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use std::time::{Duration, Instant};
88

99
use serde_json::json;
1010
use vm::{
11-
CallOutcome, CompiledProgram, HostFunction, HostFunctionRegistry, JitConfig, Program,
12-
SourceFlavor, Value, Vm, VmError, VmStatus, compile_source, compile_source_file,
13-
compile_source_with_flavor,
11+
CallOutcome, CompiledProgram, HostFunction, HostFunctionRegistry, JitConfig, JitSnapshot,
12+
JitTraceTerminal, Program, SourceFlavor, Value, Vm, VmError, VmStatus, compile_source,
13+
compile_source_file, compile_source_with_flavor,
1414
};
1515

1616
const DEFAULT_COMPILE_ITERS: usize = 20;
@@ -767,7 +767,6 @@ fn measure_pd_vm_lua_compare_mode(
767767
hot_loop_threshold: 1,
768768
max_trace_len: 16_384,
769769
});
770-
vm.set_jit_runtime_diagnostics_enabled(jit_enabled);
771770
vm.set_jit_native_bridge_stats_enabled(jit_enabled);
772771
vm.set_interpreter_opcode_profiling_enabled(!jit_enabled);
773772

@@ -777,12 +776,12 @@ fn measure_pd_vm_lua_compare_mode(
777776
.map_err(|err| format!("warmup {} run failed: {err}", mode.label()))?;
778777
ensure_expected_completion(&vm, warm_status, &expected_stack, mode.label())?;
779778
vm.reset_for_reuse();
780-
vm.clear_jit_runtime_diagnostics();
781779
vm.clear_jit_native_bridge_stats();
782780
vm.clear_interpreter_opcode_profile();
783781

784782
let native_trace_count_before = vm.jit_native_trace_count();
785783
let native_exec_before = vm.jit_native_exec_count();
784+
let jit_snapshot_before = vm.jit_snapshot();
786785
let started = Instant::now();
787786
let total_program_runs = timed_runs.saturating_mul(outer as usize);
788787
for run_index in 0..total_program_runs {
@@ -798,6 +797,7 @@ fn measure_pd_vm_lua_compare_mode(
798797
}
799798
}
800799
let total_elapsed = started.elapsed();
800+
let jit_snapshot_after = vm.jit_snapshot();
801801

802802
Ok(LuaCompareSample {
803803
mode,
@@ -817,7 +817,10 @@ fn measure_pd_vm_lua_compare_mode(
817817
native_trace_count_before: Some(native_trace_count_before),
818818
native_trace_count_after: Some(vm.jit_native_trace_count()),
819819
native_exec_delta: Some(vm.jit_native_exec_count().saturating_sub(native_exec_before)),
820-
jit_runtime_diagnostics: vm.jit_runtime_diagnostics_snapshot(),
820+
jit_runtime_diagnostics: trace_execution_diagnostics(
821+
&jit_snapshot_before,
822+
&jit_snapshot_after,
823+
),
821824
native_bridge_stats: vm
822825
.jit_native_bridge_stats_snapshot()
823826
.into_iter()
@@ -997,6 +1000,40 @@ fn normalized_ns_per_inner_iter(
9971000
elapsed.as_nanos() as f64 / (inner as f64 * outer as f64 * timed_runs as f64)
9981001
}
9991002

1003+
fn trace_execution_diagnostics(
1004+
before: &JitSnapshot,
1005+
after: &JitSnapshot,
1006+
) -> Vec<(String, u64)> {
1007+
let mut before_execs = before
1008+
.traces
1009+
.iter()
1010+
.map(|trace| (trace.id, trace.executions))
1011+
.collect::<std::collections::HashMap<_, _>>();
1012+
let mut loop_back = 0_u64;
1013+
let mut branch_exit = 0_u64;
1014+
let mut halt = 0_u64;
1015+
for trace in &after.traces {
1016+
let before_exec = before_execs.remove(&trace.id).unwrap_or(0);
1017+
let delta = trace.executions.saturating_sub(before_exec);
1018+
match trace.terminal {
1019+
JitTraceTerminal::LoopBack => loop_back = loop_back.saturating_add(delta),
1020+
JitTraceTerminal::BranchExit => branch_exit = branch_exit.saturating_add(delta),
1021+
JitTraceTerminal::Halt => halt = halt.saturating_add(delta),
1022+
}
1023+
}
1024+
let mut entries = Vec::new();
1025+
for (name, count) in [
1026+
("loop_back_trace_exec_delta", loop_back),
1027+
("branch_exit_trace_exec_delta", branch_exit),
1028+
("halt_trace_exec_delta", halt),
1029+
] {
1030+
if count > 0 {
1031+
entries.push((name.to_string(), count));
1032+
}
1033+
}
1034+
entries
1035+
}
1036+
10001037
fn write_lua_compare_artifacts(
10011038
config: &BenchConfig,
10021039
shared_source: &str,

pd-vm/src/vm/jit/aot.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,10 @@ fn encode_trace_step(step: &TraceStep, out: &mut Vec<u8>) -> VmResult<()> {
602602
out.push(17);
603603
out.push(*index);
604604
}
605+
TraceStep::LdlocCopy(index) => {
606+
out.push(43);
607+
out.push(*index);
608+
}
605609
TraceStep::Stloc(index) => {
606610
out.push(18);
607611
out.push(*index);
@@ -679,6 +683,7 @@ fn decode_trace_step(cursor: &mut AotCursor<'_>) -> VmResult<TraceStep> {
679683
15 => TraceStep::Pop,
680684
16 => TraceStep::Dup,
681685
17 => TraceStep::Ldloc(cursor.read_u8("ldloc index")?),
686+
43 => TraceStep::LdlocCopy(cursor.read_u8("ldloc.copy index")?),
682687
18 => TraceStep::Stloc(cursor.read_u8("stloc index")?),
683688
19 => TraceStep::BuiltinCall {
684689
index: cursor.read_u16("builtin index")?,
@@ -888,6 +893,7 @@ fn validate_aot_trace(trace: &JitTrace, code_len: usize) -> VmResult<()> {
888893
| TraceStep::Pop
889894
| TraceStep::Dup
890895
| TraceStep::Ldloc(_)
896+
| TraceStep::LdlocCopy(_)
891897
| TraceStep::Stloc(_)
892898
| TraceStep::JumpToRoot
893899
| TraceStep::Ret => {}

pd-vm/src/vm/jit/native/codegen.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,20 @@ pub(super) fn emit_inline_or_helper_step(
340340
)?;
341341
Ok(true)
342342
}
343+
TraceStep::LdlocCopy(index) => {
344+
emit_inline_ldloc_copy(
345+
b,
346+
vm_ptr,
347+
helper_ref,
348+
exit_block,
349+
pointer_type,
350+
layout,
351+
offsets,
352+
*index,
353+
root_ip,
354+
)?;
355+
Ok(true)
356+
}
343357
TraceStep::Stloc(index) => {
344358
emit_inline_stloc(
345359
b,
@@ -2482,6 +2496,7 @@ fn step_to_call(step: &TraceStep, root_ip: usize) -> VmResult<(i64, i64, i64, i6
24822496
TraceStep::Pop => (OP_POP, 0, 0, 0),
24832497
TraceStep::Dup => (OP_DUP, 0, 0, 0),
24842498
TraceStep::Ldloc(index) => (OP_LDLOC, i64::from(*index), 0, 0),
2499+
TraceStep::LdlocCopy(index) => (OP_LDLOC, i64::from(*index), 0, 0),
24852500
TraceStep::Stloc(index) => (OP_STLOC, i64::from(*index), 0, 0),
24862501
TraceStep::Call {
24872502
index,

pd-vm/src/vm/jit/native/cranelift.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const OP_JUMP: i64 = 23;
6666
const OP_BUILTIN_CALL: i64 = 24;
6767

6868
fn fused_ldloc_copy_slot(steps: &[TraceStep], index: usize) -> Option<u8> {
69+
if let Some(TraceStep::LdlocCopy(slot)) = steps.get(index) {
70+
return Some(*slot);
71+
}
6972
let Some(TraceStep::Ldloc(slot)) = steps.get(index) else {
7073
return None;
7174
};
@@ -274,7 +277,12 @@ pub(crate) fn compile_trace(
274277
slot,
275278
trace.root_ip,
276279
)?;
277-
step_index += 3;
280+
step_index += if matches!(trace.steps.get(step_index), Some(TraceStep::LdlocCopy(_)))
281+
{
282+
1
283+
} else {
284+
3
285+
};
278286
continue;
279287
}
280288

pd-vm/src/vm/jit/runtime.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,7 @@ impl Vm {
214214
self.native_trace_exec_count
215215
));
216216
if self.jit_runtime_diagnostics_enabled {
217-
let mut runtime_entries: Vec<(&'static str, u64)> = self
218-
.jit_runtime_counters
219-
.iter()
220-
.map(|(name, count)| (*name, *count))
221-
.collect();
222-
runtime_entries.sort_unstable_by_key(|(name, _)| *name);
217+
let runtime_entries = self.jit_runtime_diagnostics_snapshot();
223218
let total_runtime_events = runtime_entries
224219
.iter()
225220
.fold(0u64, |acc, (_, count)| acc.saturating_add(*count));
@@ -465,6 +460,14 @@ impl Vm {
465460
let value = std::mem::replace(slot, crate::bytecode::Value::Null);
466461
self.stack.push(value);
467462
}
463+
TraceStep::LdlocCopy(index) => {
464+
let value = self
465+
.locals
466+
.get(*index as usize)
467+
.cloned()
468+
.ok_or(VmError::InvalidLocal(*index))?;
469+
self.stack.push(value);
470+
}
468471
TraceStep::Stloc(index) => {
469472
let value = self.pop_value()?;
470473
self.store_local_with_drop_contract(*index, value)?;

pd-vm/src/vm/jit/trace.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub enum TraceStep {
112112
Pop,
113113
Dup,
114114
Ldloc(u8),
115+
LdlocCopy(u8),
115116
Stloc(u8),
116117
BuiltinCall {
117118
index: u16,
@@ -721,11 +722,7 @@ impl TraceJitEngine {
721722
let index = read_u8(code, &mut ip)
722723
.ok_or(JitNyiReason::InvalidImmediate("ldloc.copy"))?;
723724
step_ips.push(instr_ip);
724-
steps.push(TraceStep::Ldloc(index));
725-
step_ips.push(instr_ip);
726-
steps.push(TraceStep::Dup);
727-
step_ips.push(instr_ip);
728-
steps.push(TraceStep::Stloc(index));
725+
steps.push(TraceStep::LdlocCopy(index));
729726
continue;
730727
}
731728
if opcode == OpCode::Stloc as u8 {
@@ -987,11 +984,7 @@ impl TraceJitEngine {
987984
let index = read_u8(code, &mut ip)
988985
.ok_or(JitNyiReason::InvalidImmediate("ldloc.copy"))?;
989986
step_ips.push(instr_ip);
990-
steps.push(TraceStep::Ldloc(index));
991-
step_ips.push(instr_ip);
992-
steps.push(TraceStep::Dup);
993-
step_ips.push(instr_ip);
994-
steps.push(TraceStep::Stloc(index));
987+
steps.push(TraceStep::LdlocCopy(index));
995988
continue;
996989
}
997990
if opcode == OpCode::Stloc as u8 {
@@ -1224,6 +1217,7 @@ fn trace_step_name(step: &TraceStep) -> &'static str {
12241217
TraceStep::Pop => "pop",
12251218
TraceStep::Dup => "dup",
12261219
TraceStep::Ldloc(_) => "ldloc",
1220+
TraceStep::LdlocCopy(_) => "ldloc_copy",
12271221
TraceStep::Stloc(_) => "stloc",
12281222
TraceStep::BuiltinCall { .. } => "call",
12291223
TraceStep::Call { .. } => "call",

0 commit comments

Comments
 (0)