Actually produce profiler files
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use fxprof_processed_profile::{
|
||||
CategoryHandle, CpuDelta, Frame, FrameFlags, FrameInfo, ProcessHandle, Profile,
|
||||
ReferenceTimestamp, SamplingInterval, StackHandle, ThreadHandle, Timestamp,
|
||||
};
|
||||
|
||||
use crate::profiler::state::{ProgramState, RESET_CODE, StackFrame};
|
||||
|
||||
pub struct Recording {
|
||||
profile: Profile,
|
||||
process: ProcessHandle,
|
||||
threads: HashMap<u16, ThreadHandle>,
|
||||
now: u64,
|
||||
}
|
||||
|
||||
impl Recording {
|
||||
pub fn new(state: &ProgramState) -> Self {
|
||||
let symbol_file = state.symbol_file();
|
||||
|
||||
let name = &symbol_file.name();
|
||||
let reference_timestamp = ReferenceTimestamp::from_millis_since_unix_epoch(0.0);
|
||||
let interval = SamplingInterval::from_hz(20_000_000.0);
|
||||
let mut profile = Profile::new(name, reference_timestamp, interval);
|
||||
|
||||
let process = profile.add_process(name, 1, Timestamp::from_nanos_since_reference(0));
|
||||
|
||||
let lib = profile.add_lib(symbol_file.library_info().clone());
|
||||
profile.add_lib_mapping(process, lib, 0x00000000, 0xffffffff, 0);
|
||||
|
||||
let mut me = Self {
|
||||
profile,
|
||||
process,
|
||||
threads: HashMap::new(),
|
||||
now: 0,
|
||||
};
|
||||
me.track_elapsed_cycles(state, 0);
|
||||
me
|
||||
}
|
||||
|
||||
pub fn track_elapsed_cycles(&mut self, state: &ProgramState, cycles: u32) {
|
||||
self.now += cycles as u64;
|
||||
let timestamp = Timestamp::from_nanos_since_reference(self.now * 50);
|
||||
let weight = 1;
|
||||
|
||||
let active_code = if let Some((code, frames)) = state.current_stack() {
|
||||
let thread = *self.threads.entry(code).or_insert_with(|| {
|
||||
let process = self.process;
|
||||
let tid = code as u32;
|
||||
let start_time = Timestamp::from_nanos_since_reference(self.now * 50);
|
||||
let is_main = code == RESET_CODE;
|
||||
let thread = self.profile.add_thread(process, tid, start_time, is_main);
|
||||
self.profile
|
||||
.set_thread_name(thread, &thread_name_for_code(code));
|
||||
thread
|
||||
});
|
||||
|
||||
let stack = self.handle_for_stack(thread, frames);
|
||||
let cpu_delta = CpuDelta::from_nanos((self.now - cycles as u64) * 50);
|
||||
self.profile
|
||||
.add_sample(thread, timestamp, stack, cpu_delta, weight);
|
||||
Some(code)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for (code, thread) in &self.threads {
|
||||
if active_code == Some(*code) {
|
||||
continue;
|
||||
}
|
||||
self.profile
|
||||
.add_sample_same_stack_zero_cpu(*thread, timestamp, weight);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Vec<u8> {
|
||||
serde_json::to_vec(&self.profile).expect("could not serialize profile")
|
||||
}
|
||||
|
||||
fn handle_for_stack(
|
||||
&mut self,
|
||||
thread: ThreadHandle,
|
||||
frames: &[StackFrame],
|
||||
) -> Option<StackHandle> {
|
||||
self.profile.intern_stack_frames(
|
||||
thread,
|
||||
frames.iter().map(|f| FrameInfo {
|
||||
frame: Frame::InstructionPointer(f.address as u64),
|
||||
category_pair: CategoryHandle::OTHER.into(),
|
||||
flags: FrameFlags::empty(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn thread_name_for_code(code: u16) -> std::borrow::Cow<'static, str> {
|
||||
match code {
|
||||
RESET_CODE => "Main".into(),
|
||||
0xffd0 => "Duplexed exception".into(),
|
||||
0xfe40 => "VIP interrupt".into(),
|
||||
0xfe30 => "Communication interrupt".into(),
|
||||
0xfe20 => "Game pak interrupt".into(),
|
||||
0xfe10 => "Timer interrupt".into(),
|
||||
0xfe00 => "Game pad interrupt".into(),
|
||||
0xffc0 => "Address trap".into(),
|
||||
0xffa0..0xffc0 => format!("Trap (vector {})", code - 0xffa0).into(),
|
||||
0xff90 => "Illegal opcode exception".into(),
|
||||
0xff80 => "Zero division exception".into(),
|
||||
0xff60 => "Floating-point reserved operand exception".into(),
|
||||
0xff70 => "Floating-point invalid operation exception".into(),
|
||||
0xff68 => "Floating-point zero division exception".into(),
|
||||
0xff64 => "Floating-point overflow exception".into(),
|
||||
other => format!("Unrecognized handler (0x{other:04x})").into(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user