93 lines
2.8 KiB
Rust

use libipt::enc_dec_builder::EncoderDecoderBuilder;
use libipt::packet::{Packet, PacketDecoder};
use memmap2::Mmap;
use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::time::Duration;
#[derive(Debug)]
pub struct AnalyzeData {
pub packets: u64,
pub cycles: u64,
pub time: Duration,
pub time_main: Duration,
pub time_disabled: Duration,
}
#[derive(Debug, Eq, PartialEq)]
enum Scope {
Disabled,
Main,
PreRun,
PostRun,
}
pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
let trace_file = File::open(path)?;
let mmap = unsafe { Mmap::map(&trace_file)? };
let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
// I hope this is safe if the buffer is never written to
let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
let mut decoder = builder.build()?;
// Required before it can be used
decoder.sync_forward()?;
let mut segments = vec![(Scope::PreRun, 0u64)];
let mut total = 0u64;
for packet in decoder {
total += 1;
match packet {
Ok(Packet::Cyc(cyc)) => {
segments.last_mut().unwrap().1 += cyc.value();
}
Ok(Packet::TipPge(_)) => {
segments.push((Scope::Main, 0));
}
Ok(Packet::TipPgd(_)) => {
segments.push((Scope::Disabled, 0));
}
Ok(Packet::Ptw(ptwrite)) => {
if ptwrite.payload() == 42 {
// Main enter
segments.push((Scope::Main, 0));
} else if ptwrite.payload() == 43 {
// Main exit
segments.push((Scope::PostRun, 0));
} else {
println!("GOT PTWRITE!!!!!: {ptwrite:?}");
}
}
Ok(_) => {}
Err(error) => println!("Got error: {error:?}"),
}
}
// dbg!(&segments);
let cycles_total = segments.iter().map(|(_, cycles)| cycles).sum();
let total_seconds = cycles_total as f64 / 2_700_000_000.0;
let main_duration = duration_in_mode(&segments, Scope::Main);
let disabled_duration = duration_in_mode(&segments, Scope::Disabled);
Ok(AnalyzeData {
packets: total,
cycles: cycles_total,
time: Duration::from_secs_f64(total_seconds),
time_main: main_duration,
time_disabled: disabled_duration
})
}
fn duration_in_mode(segments: &[(Scope, u64)], scope: Scope) -> Duration {
let total_cycles = segments
.into_iter()
.filter(|(it, _)| *it == scope)
.map(|(_, cycles)| *cycles)
.sum::<u64>();
let total_seconds = total_cycles as f64 / 2_700_000_000.0;
Duration::from_secs_f64(total_seconds)
}