-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjit_microbenchmark.rs
More file actions
104 lines (86 loc) · 3.34 KB
/
Copy pathjit_microbenchmark.rs
File metadata and controls
104 lines (86 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Micro-benchmark: Direct comparison of bytecode vs JIT
// This measures the raw execution speed difference
use ruff::bytecode::{BytecodeChunk, Constant, OpCode};
use ruff::jit::JitCompiler;
use ruff::vm::VM;
use std::time::Instant;
fn main() {
println!("=== JIT Micro-Benchmark ===\n");
// Create a simple hot loop bytecode
// Pseudo-code: for i in 0..1000 { i = i + 1 }
let mut chunk = BytecodeChunk::new();
let const_0 = chunk.add_constant(Constant::Int(0));
let const_1 = chunk.add_constant(Constant::Int(1));
let const_1000 = chunk.add_constant(Constant::Int(1000));
// Initialize counter
chunk.emit(OpCode::LoadConst(const_0)); // 0
// Loop start (PC 1)
let loop_start = chunk.instructions.len();
// counter + 1
chunk.emit(OpCode::Dup); // 1
chunk.emit(OpCode::LoadConst(const_1)); // 2
chunk.emit(OpCode::Add); // 3
// Check if counter < 1000
chunk.emit(OpCode::Dup); // 4
chunk.emit(OpCode::LoadConst(const_1000)); // 5
chunk.emit(OpCode::LessThan); // 6
// Loop back if true
let jump = chunk.emit(OpCode::JumpIfTrue(0)); // 7
chunk.set_jump_target(jump, loop_start);
// Return final value
chunk.emit(OpCode::Return); // 8
println!("Bytecode chunk: {} instructions", chunk.instructions.len());
println!("Expected iterations: 1000\n");
// Benchmark 1: Pure bytecode execution
println!("Benchmark 1: Bytecode VM (100 runs)");
let mut total_bytecode = std::time::Duration::ZERO;
for _ in 0..100 {
let mut vm = VM::new();
vm.set_jit_enabled(false);
let start = Instant::now();
let _ = vm.execute(chunk.clone());
total_bytecode += start.elapsed();
}
let avg_bytecode = total_bytecode / 100;
println!(" Average time: {:?}", avg_bytecode);
// Benchmark 2: Compile to native code
println!("\nBenchmark 2: JIT Compilation");
let mut compiler = JitCompiler::new().expect("Failed to create JIT compiler");
let compile_start = Instant::now();
let compiled_fn = match compiler.compile(&chunk, 0) {
Ok(f) => {
println!(" ✓ Compilation successful");
f
}
Err(e) => {
println!(" ✗ Compilation failed: {}", e);
return;
}
};
let compile_time = compile_start.elapsed();
println!(" Compilation time: {:?}", compile_time);
// Benchmark 3: Execute compiled code
println!("\nBenchmark 3: Execute Compiled Native Code (100 runs)");
let mut total_jit = std::time::Duration::ZERO;
for _ in 0..100 {
let start = Instant::now();
unsafe {
let _ = compiled_fn(std::ptr::null_mut());
}
total_jit += start.elapsed();
}
let avg_jit = total_jit / 100;
println!(" Average time: {:?}", avg_jit);
// Results
println!("\n=== Results ===");
println!(" Bytecode VM: {:?}", avg_bytecode);
println!(" Compiled code: {:?}", avg_jit);
let speedup = avg_bytecode.as_nanos() as f64 / avg_jit.as_nanos() as f64;
println!(" Speedup: {:.2}x", speedup);
if speedup > 1.0 {
println!("\n ✓ JIT is {:.2}x faster than bytecode!", speedup);
} else {
println!("\n Note: Compilation overhead: {:?}", compile_time);
println!(" JIT worth it after {} runs", compile_time.as_nanos() / avg_jit.as_nanos());
}
}