Include inline functions when profiling
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
use std::{borrow::Cow, ffi::c_void, ptr, slice};
|
||||
use std::{borrow::Cow, ffi::c_void, ptr, slice, sync::Arc};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use bitflags::bitflags;
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::emulator::inline_stack_map::{InlineStack, InlineStackMap};
|
||||
|
||||
use super::address_set::AddressSet;
|
||||
|
||||
#[repr(C)]
|
||||
@@ -206,11 +208,9 @@ extern "C" fn on_execute(sim: *mut VB, address: u32, code: *const u16, length: c
|
||||
if data.monitor.enabled {
|
||||
// SAFETY: length is the length of code, in elements
|
||||
let code = unsafe { slice::from_raw_parts(code, length as usize) };
|
||||
if data.monitor.detect_event(sim, address, code) {
|
||||
// Something interesting will happen after this instruction is run.
|
||||
// The on_fetch callback will fire when it does.
|
||||
unsafe { vb_set_fetch_callback(sim, Some(on_fetch)) };
|
||||
}
|
||||
data.monitor.detect_event(sim, address, code);
|
||||
// Something interesting will happen after this instruction is run.
|
||||
// We'll react in the on_fetch callback it does.
|
||||
}
|
||||
|
||||
let mut stopped = data.stop_reason.is_some() || data.monitor.event.is_some();
|
||||
@@ -231,7 +231,7 @@ extern "C" fn on_execute(sim: *mut VB, address: u32, code: *const u16, length: c
|
||||
extern "C" fn on_fetch(
|
||||
sim: *mut VB,
|
||||
_fetch: c_int,
|
||||
_address: u32,
|
||||
address: u32,
|
||||
_value: *mut i32,
|
||||
_cycles: *mut u32,
|
||||
) -> c_int {
|
||||
@@ -239,9 +239,13 @@ extern "C" fn on_fetch(
|
||||
// There is no way for the userdata to be null or otherwise invalid.
|
||||
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||
data.monitor.event = data.monitor.queued_event.take();
|
||||
data.monitor.new_inline_stack = data.monitor.detect_new_inline_stack(address);
|
||||
unsafe { vb_set_exception_callback(sim, Some(on_exception)) };
|
||||
unsafe { vb_set_fetch_callback(sim, None) };
|
||||
1
|
||||
if data.monitor.event.is_some() || data.monitor.new_inline_stack.is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -249,17 +253,21 @@ extern "C" fn on_exception(sim: *mut VB, cause: *mut u16) -> c_int {
|
||||
// SAFETY: the *mut VB owns its userdata.
|
||||
// There is no way for the userdata to be null or otherwise invalid.
|
||||
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||
data.monitor.event = data.monitor.queued_event.take();
|
||||
let cause = unsafe { *cause };
|
||||
let pc = if cause == 0xff70 {
|
||||
0xffffff60
|
||||
} else {
|
||||
(cause & 0xfff0) as u32 | 0xffff0000
|
||||
};
|
||||
data.monitor.event = data.monitor.queued_event.take();
|
||||
data.monitor.new_inline_stack = data.monitor.detect_new_inline_stack(pc);
|
||||
data.monitor.queued_event = Some(SimEvent::Interrupt(cause, pc));
|
||||
unsafe { vb_set_exception_callback(sim, None) };
|
||||
unsafe { vb_set_fetch_callback(sim, Some(on_fetch)) };
|
||||
if data.monitor.event.is_some() { 1 } else { 0 }
|
||||
if data.monitor.event.is_some() || data.monitor.new_inline_stack.is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -339,18 +347,35 @@ struct EventMonitor {
|
||||
event: Option<SimEvent>,
|
||||
queued_event: Option<SimEvent>,
|
||||
just_halted: bool,
|
||||
inline_stack_map: InlineStackMap,
|
||||
new_inline_stack: Option<InlineStack>,
|
||||
last_inline_stack: InlineStack,
|
||||
}
|
||||
|
||||
impl EventMonitor {
|
||||
fn new() -> Self {
|
||||
let inline_stack_map = InlineStackMap::empty();
|
||||
let last_inline_stack = inline_stack_map.get(0).clone();
|
||||
Self {
|
||||
enabled: false,
|
||||
event: None,
|
||||
queued_event: None,
|
||||
just_halted: false,
|
||||
inline_stack_map,
|
||||
new_inline_stack: None,
|
||||
last_inline_stack,
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_new_inline_stack(&mut self, address: u32) -> Option<InlineStack> {
|
||||
let stack = self.inline_stack_map.get(address);
|
||||
if Arc::ptr_eq(stack, &self.last_inline_stack) {
|
||||
return None;
|
||||
}
|
||||
self.last_inline_stack = stack.clone();
|
||||
Some(stack.clone())
|
||||
}
|
||||
|
||||
fn detect_event(&mut self, sim: *mut VB, address: u32, code: &[u16]) -> bool {
|
||||
self.queued_event = self.do_detect_event(sim, address, code);
|
||||
self.queued_event.is_some()
|
||||
@@ -492,14 +517,18 @@ impl Sim {
|
||||
unsafe { vb_reset(self.sim) };
|
||||
}
|
||||
|
||||
pub fn monitor_events(&mut self, enabled: bool) {
|
||||
pub fn monitor_events(&mut self, enabled: bool, inline_stack_map: InlineStackMap) {
|
||||
let state = self.get_state();
|
||||
state.monitor.enabled = enabled;
|
||||
state.monitor.event = None;
|
||||
state.monitor.queued_event = None;
|
||||
state.monitor.new_inline_stack = None;
|
||||
state.monitor.last_inline_stack = inline_stack_map.get(0).clone();
|
||||
state.monitor.inline_stack_map = inline_stack_map;
|
||||
if enabled {
|
||||
unsafe { vb_set_execute_callback(self.sim, Some(on_execute)) };
|
||||
unsafe { vb_set_exception_callback(self.sim, Some(on_exception)) };
|
||||
unsafe { vb_set_fetch_callback(self.sim, Some(on_fetch)) };
|
||||
} else {
|
||||
if !state.needs_execute_callback() {
|
||||
unsafe { vb_set_execute_callback(self.sim, None) };
|
||||
@@ -816,9 +845,11 @@ impl Sim {
|
||||
reason
|
||||
}
|
||||
|
||||
pub fn take_sim_event(&mut self) -> Option<SimEvent> {
|
||||
pub fn take_profiler_updates(&mut self) -> (Option<SimEvent>, Option<InlineStack>) {
|
||||
let data = self.get_state();
|
||||
data.monitor.event.take()
|
||||
let event = data.monitor.event.take();
|
||||
let inline_stack = data.monitor.new_inline_stack.take();
|
||||
(event, inline_stack)
|
||||
}
|
||||
|
||||
fn get_state(&mut self) -> &mut VBState {
|
||||
|
||||
Reference in New Issue
Block a user