Add markers to event stream
This commit is contained in:
parent
adc333e6a6
commit
eca34e9a26
|
@ -1,4 +1,4 @@
|
||||||
use std::{ffi::c_void, ptr, slice};
|
use std::{borrow::Cow, ffi::c_void, ptr, slice};
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
@ -191,6 +191,9 @@ extern "C" fn on_frame(sim: *mut VB) -> c_int {
|
||||||
// There is no way for the userdata to be null or otherwise invalid.
|
// 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() };
|
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||||
data.frame_seen = true;
|
data.frame_seen = true;
|
||||||
|
if data.monitor.enabled {
|
||||||
|
data.monitor.event = Some(SimEvent::Marker(Cow::Borrowed("Frame Drawn")));
|
||||||
|
}
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +331,7 @@ pub enum SimEvent {
|
||||||
Halt,
|
Halt,
|
||||||
Interrupt(u16, u32),
|
Interrupt(u16, u32),
|
||||||
Reti,
|
Reti,
|
||||||
|
Marker(Cow<'static, str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventMonitor {
|
struct EventMonitor {
|
||||||
|
|
|
@ -213,11 +213,23 @@ impl ProfilerSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn track_event(&mut self, event: SimEvent) -> Result<()> {
|
fn track_event(&mut self, event: SimEvent) -> Result<()> {
|
||||||
if let Some(program) = &mut self.program {
|
let Some(program) = &mut self.program else {
|
||||||
program.track_event(event)?;
|
return Ok(());
|
||||||
}
|
};
|
||||||
|
match event {
|
||||||
|
SimEvent::Call(address) => program.track_call(address),
|
||||||
|
SimEvent::Return => program.track_return(),
|
||||||
|
SimEvent::Halt => program.track_halt(),
|
||||||
|
SimEvent::Interrupt(code, address) => program.track_interrupt(code, address),
|
||||||
|
SimEvent::Reti => program.track_reti(),
|
||||||
|
SimEvent::Marker(name) => {
|
||||||
|
if let Some(recording) = &mut self.recording {
|
||||||
|
recording.track_marker(name);
|
||||||
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_recording(&mut self) {
|
fn start_recording(&mut self) {
|
||||||
if let Some(program) = &self.program {
|
if let Some(program) = &self.program {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use std::collections::HashMap;
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
use fxprof_processed_profile::{
|
use fxprof_processed_profile::{
|
||||||
CategoryHandle, CpuDelta, Frame, FrameFlags, FrameInfo, ProcessHandle, Profile,
|
CategoryHandle, CpuDelta, Frame, FrameFlags, FrameInfo, MarkerTiming, ProcessHandle, Profile,
|
||||||
ReferenceTimestamp, SamplingInterval, StackHandle, ThreadHandle, Timestamp,
|
ReferenceTimestamp, SamplingInterval, StackHandle, StaticSchemaMarker, StringHandle,
|
||||||
|
ThreadHandle, Timestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::profiler::state::{ProgramState, RESET_CODE, StackFrame};
|
use crate::profiler::state::{ProgramState, RESET_CODE, StackFrame};
|
||||||
|
@ -72,6 +73,15 @@ impl Recording {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn track_marker(&mut self, name: Cow<'static, str>) {
|
||||||
|
let Some(thread) = self.threads.get(&RESET_CODE) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let timing = MarkerTiming::Instant(Timestamp::from_nanos_since_reference(self.now * 50));
|
||||||
|
let marker = SimpleMarker(name);
|
||||||
|
self.profile.add_marker(*thread, timing, marker);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn finish(self) -> Vec<u8> {
|
pub fn finish(self) -> Vec<u8> {
|
||||||
serde_json::to_vec(&self.profile).expect("could not serialize profile")
|
serde_json::to_vec(&self.profile).expect("could not serialize profile")
|
||||||
}
|
}
|
||||||
|
@ -92,6 +102,29 @@ impl Recording {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SimpleMarker(Cow<'static, str>);
|
||||||
|
|
||||||
|
impl StaticSchemaMarker for SimpleMarker {
|
||||||
|
const UNIQUE_MARKER_TYPE_NAME: &'static str = "Simple";
|
||||||
|
const FIELDS: &'static [fxprof_processed_profile::StaticSchemaMarkerField] = &[];
|
||||||
|
|
||||||
|
fn name(&self, profile: &mut Profile) -> StringHandle {
|
||||||
|
profile.intern_string(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn category(&self, _profile: &mut Profile) -> CategoryHandle {
|
||||||
|
CategoryHandle::OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_field_value(&self, _field_index: u32) -> StringHandle {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn number_field_value(&self, _field_index: u32) -> f64 {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn thread_name_for_code(code: u16) -> std::borrow::Cow<'static, str> {
|
fn thread_name_for_code(code: u16) -> std::borrow::Cow<'static, str> {
|
||||||
match code {
|
match code {
|
||||||
RESET_CODE => "Main".into(),
|
RESET_CODE => "Main".into(),
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
|
|
||||||
use crate::{emulator::SimEvent, profiler::symbols::SymbolFile};
|
use crate::profiler::symbols::SymbolFile;
|
||||||
|
|
||||||
pub struct ProgramState {
|
pub struct ProgramState {
|
||||||
symbol_file: SymbolFile,
|
symbol_file: SymbolFile,
|
||||||
|
@ -42,9 +42,7 @@ impl ProgramState {
|
||||||
Some((*code, call_stack))
|
Some((*code, call_stack))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn track_event(&mut self, event: SimEvent) -> Result<()> {
|
pub fn track_call(&mut self, address: u32) -> Result<()> {
|
||||||
match event {
|
|
||||||
SimEvent::Call(address) => {
|
|
||||||
let Some(code) = self.context_stack.last() else {
|
let Some(code) = self.context_stack.last() else {
|
||||||
bail!("How did we call anything when we're halted?");
|
bail!("How did we call anything when we're halted?");
|
||||||
};
|
};
|
||||||
|
@ -52,8 +50,10 @@ impl ProgramState {
|
||||||
bail!("missing stack {code:04x}");
|
bail!("missing stack {code:04x}");
|
||||||
};
|
};
|
||||||
stack.push(StackFrame { address });
|
stack.push(StackFrame { address });
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
SimEvent::Return => {
|
|
||||||
|
pub fn track_return(&mut self) -> Result<()> {
|
||||||
let Some(code) = self.context_stack.last() else {
|
let Some(code) = self.context_stack.last() else {
|
||||||
bail!("how did we return when we're halted?");
|
bail!("how did we return when we're halted?");
|
||||||
};
|
};
|
||||||
|
@ -66,13 +66,17 @@ impl ProgramState {
|
||||||
if stack.is_empty() {
|
if stack.is_empty() {
|
||||||
bail!("returned to oblivion");
|
bail!("returned to oblivion");
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
SimEvent::Halt => {
|
|
||||||
|
pub fn track_halt(&mut self) -> Result<()> {
|
||||||
let Some(RESET_CODE) = self.context_stack.pop() else {
|
let Some(RESET_CODE) = self.context_stack.pop() else {
|
||||||
bail!("halted when not in an interrupt");
|
bail!("halted when not in an interrupt");
|
||||||
};
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
SimEvent::Interrupt(code, address) => {
|
|
||||||
|
pub fn track_interrupt(&mut self, code: u16, address: u32) -> Result<()> {
|
||||||
// if the CPU was halted before, wake it up now
|
// if the CPU was halted before, wake it up now
|
||||||
if self.context_stack.is_empty() {
|
if self.context_stack.is_empty() {
|
||||||
self.context_stack.push(RESET_CODE);
|
self.context_stack.push(RESET_CODE);
|
||||||
|
@ -86,8 +90,10 @@ impl ProgramState {
|
||||||
{
|
{
|
||||||
bail!("{code:04x} fired twice");
|
bail!("{code:04x} fired twice");
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
SimEvent::Reti => {
|
|
||||||
|
pub fn track_reti(&mut self) -> Result<()> {
|
||||||
let Some(code) = self.context_stack.pop() else {
|
let Some(code) = self.context_stack.pop() else {
|
||||||
bail!("RETI when halted");
|
bail!("RETI when halted");
|
||||||
};
|
};
|
||||||
|
@ -97,8 +103,6 @@ impl ProgramState {
|
||||||
if self.call_stacks.remove(&code).is_none() {
|
if self.call_stacks.remove(&code).is_none() {
|
||||||
bail!("{code:04x} popped but never called");
|
bail!("{code:04x} popped but never called");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue