(mut vm: Vm, mut target: CortexmMultiStream, trials: u64)
| 142 | } |
| 143 | |
| 144 | fn replay_bench(mut vm: Vm, mut target: CortexmMultiStream, trials: u64) -> anyhow::Result<()> { |
| 145 | let core_ids = core_affinity::get_core_ids().unwrap_or(vec![]); |
| 146 | if let Some(core_id) = core_ids.first() { |
| 147 | eprintln!("pinning active thread to core: {core_id:?}"); |
| 148 | core_affinity::set_for_current(*core_id); |
| 149 | } |
| 150 | |
| 151 | let mut snapshot = vm.snapshot(); |
| 152 | let mut cursor_snapshot = target.get_mmio_handler(&mut vm).unwrap().source.snapshot_cursors(); |
| 153 | |
| 154 | // Perform a dry run of the input to warm up the VM. |
| 155 | let exit = target.run(&mut vm); |
| 156 | vm.recompile(); |
| 157 | |
| 158 | // Dump JIT function ID -> guest address mapping for analysis. |
| 159 | if let Err(e) = vm.jit.dump_jit_mapping("jit_table.txt".as_ref(), vm.env.debug_info().unwrap()) |
| 160 | { |
| 161 | tracing::warn!("Failed to dump JIT table: {e}") |
| 162 | } |
| 163 | |
| 164 | let mut expected_icount = vm.cpu.icount(); |
| 165 | eprintln!("[icicle] exited with: {exit:?} (icount = {expected_icount})"); |
| 166 | |
| 167 | // We allow replaying from part way through the input if provided from an environment variable. |
| 168 | if let Some(bp) = |
| 169 | std::env::var("REPLAY_FROM").ok().and_then(|addr| parse_addr_or_symbol(&addr, &mut vm)) |
| 170 | { |
| 171 | vm.restore(&snapshot); |
| 172 | target.get_mmio_handler(&mut vm).unwrap().source.restore_cursors(&cursor_snapshot); |
| 173 | |
| 174 | vm.add_breakpoint(bp); |
| 175 | let exit = target.run(&mut vm); |
| 176 | let pc = vm.cpu.read_pc(); |
| 177 | anyhow::ensure!( |
| 178 | matches!(exit, Ok(VmExit::Breakpoint)) && pc == bp, |
| 179 | "Failed to hit breakpoint at: {bp:#x} when `REPLAY_FROM` is set (exited with: {exit:?} at: {pc:#x})", |
| 180 | ); |
| 181 | vm.remove_breakpoint(bp); |
| 182 | |
| 183 | eprintln!("[icicle] hit break: pc={pc:#x} {exit:?} (icount = {})", vm.cpu.icount()); |
| 184 | expected_icount += 1; |
| 185 | |
| 186 | snapshot = vm.snapshot(); |
| 187 | cursor_snapshot = target.get_mmio_handler(&mut vm).unwrap().source.snapshot_cursors(); |
| 188 | } |
| 189 | |
| 190 | let start = std::time::Instant::now(); |
| 191 | |
| 192 | for _ in 0..trials { |
| 193 | vm.restore(&snapshot); |
| 194 | // Restoring currently triggers a lookup flush, but we know the code will not change between |
| 195 | // execs so we can skip it here. |
| 196 | vm.cpu.mem.mapping_changed = false; |
| 197 | target.get_mmio_handler(&mut vm).unwrap().source.restore_cursors(&cursor_snapshot); |
| 198 | let _ = target.run(&mut vm); |
| 199 | |
| 200 | // Ensure execution doesn't diverge. |
| 201 | let icount = vm.cpu.icount(); |
no test coverage detected