use serde::{Deserialize, Serialize};
pub type Timestamp = u64;
pub type Pid = i32;
pub type Tid = i32;
pub type CpuId = u32;
pub type StackTrace = Vec<u64>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CpuSample {
pub timestamp: Timestamp,
pub pid: Pid,
pub tid: Tid,
pub cpu_id: CpuId,
pub user_stack: StackTrace,
pub kernel_stack: StackTrace,
pub comm: String,
#[serde(default)]
pub user_stack_symbols: Vec<Option<String>>,
#[serde(default)]
pub kernel_stack_symbols: Vec<Option<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LockEvent {
pub timestamp: Timestamp,
pub pid: Pid,
pub tid: Tid,
pub lock_addr: u64,
pub hold_time_ns: u64,
pub wait_time_ns: u64,
pub stack_trace: StackTrace,
pub comm: String,
#[serde(default)]
pub stack_symbols: Vec<Option<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyscallEvent {
pub timestamp: Timestamp,
pub pid: Pid,
pub tid: Tid,
pub syscall_id: u32,
pub duration_ns: u64,
pub return_value: i64,
pub comm: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GpuKernelEvent {
pub timestamp: Timestamp,
pub pid: Pid,
pub kernel_name: String,
pub duration_ns: u64,
pub grid_size: (u32, u32, u32),
pub block_size: (u32, u32, u32),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ProfileEvent {
CpuSample(CpuSample),
Lock(LockEvent),
Syscall(SyscallEvent),
GpuKernel(GpuKernelEvent),
}
impl ProfileEvent {
pub fn timestamp(&self) -> Timestamp {
match self {
ProfileEvent::CpuSample(e) => e.timestamp,
ProfileEvent::Lock(e) => e.timestamp,
ProfileEvent::Syscall(e) => e.timestamp,
ProfileEvent::GpuKernel(e) => e.timestamp,
}
}
pub fn pid(&self) -> Pid {
match self {
ProfileEvent::CpuSample(e) => e.pid,
ProfileEvent::Lock(e) => e.pid,
ProfileEvent::Syscall(e) => e.pid,
ProfileEvent::GpuKernel(e) => e.pid,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpu_sample_serialization() {
let sample = CpuSample {
timestamp: 1234567890,
pid: 1000,
tid: 1001,
cpu_id: 0,
user_stack: vec![0x400000, 0x400100],
kernel_stack: vec![],
comm: "test".to_string(),
user_stack_symbols: vec![],
kernel_stack_symbols: vec![],
};
let json = serde_json::to_string(&sample).unwrap();
let deserialized: CpuSample = serde_json::from_str(&json).unwrap();
assert_eq!(sample.pid, deserialized.pid);
assert_eq!(sample.timestamp, deserialized.timestamp);
}
#[test]
fn test_profile_event_bincode_serialization() {
use bincode::Options;
let config = bincode::config::DefaultOptions::new()
.with_fixint_encoding()
.allow_trailing_bytes();
let event = ProfileEvent::Syscall(SyscallEvent {
timestamp: 0x1122334455667788,
pid: 0x11111111,
tid: 0x22222222,
syscall_id: 198, duration_ns: 1000,
return_value: 0,
comm: "test".to_string(),
});
let bytes = config.serialize(&event).unwrap();
assert_eq!(bytes[0..4], [2, 0, 0, 0]); assert_eq!(bytes[20..24], [198, 0, 0, 0]);
let deserialized: ProfileEvent = config.deserialize(&bytes).unwrap();
match deserialized {
ProfileEvent::Syscall(e) => {
assert_eq!(e.syscall_id, 198);
}
_ => panic!("Wrong variant"),
}
}
}