1use serde::{Deserialize, Serialize};
7
8pub type Timestamp = u64;
10
11pub type Pid = i32;
13
14pub type Tid = i32;
16
17pub type CpuId = u32;
19
20pub type StackTrace = Vec<u64>;
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct CpuSample {
26 pub timestamp: Timestamp,
28
29 pub pid: Pid,
31
32 pub tid: Tid,
34
35 pub cpu_id: CpuId,
37
38 pub user_stack: StackTrace,
40
41 pub kernel_stack: StackTrace,
43
44 pub comm: String,
46
47 #[serde(default)]
49 pub user_stack_symbols: Vec<Option<String>>,
50
51 #[serde(default)]
53 pub kernel_stack_symbols: Vec<Option<String>>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct LockEvent {
59 pub timestamp: Timestamp,
60 pub pid: Pid,
61 pub tid: Tid,
62 pub lock_addr: u64,
63 pub hold_time_ns: u64,
64 pub wait_time_ns: u64,
65 pub stack_trace: StackTrace,
66 pub comm: String,
67
68 #[serde(default)]
70 pub stack_symbols: Vec<Option<String>>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct SyscallEvent {
76 pub timestamp: Timestamp,
77 pub pid: Pid,
78 pub tid: Tid,
79 pub syscall_id: u32,
80 pub duration_ns: u64,
81 pub return_value: i64,
82 pub comm: String,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct GpuKernelEvent {
88 pub timestamp: Timestamp,
89 pub pid: Pid,
90 pub kernel_name: String,
91 pub duration_ns: u64,
92 pub grid_size: (u32, u32, u32),
93 pub block_size: (u32, u32, u32),
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub enum ProfileEvent {
99 CpuSample(CpuSample),
100 Lock(LockEvent),
101 Syscall(SyscallEvent),
102 GpuKernel(GpuKernelEvent),
103}
104
105impl ProfileEvent {
106 pub fn timestamp(&self) -> Timestamp {
108 match self {
109 ProfileEvent::CpuSample(e) => e.timestamp,
110 ProfileEvent::Lock(e) => e.timestamp,
111 ProfileEvent::Syscall(e) => e.timestamp,
112 ProfileEvent::GpuKernel(e) => e.timestamp,
113 }
114 }
115
116 pub fn pid(&self) -> Pid {
118 match self {
119 ProfileEvent::CpuSample(e) => e.pid,
120 ProfileEvent::Lock(e) => e.pid,
121 ProfileEvent::Syscall(e) => e.pid,
122 ProfileEvent::GpuKernel(e) => e.pid,
123 }
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_cpu_sample_serialization() {
133 let sample = CpuSample {
134 timestamp: 1234567890,
135 pid: 1000,
136 tid: 1001,
137 cpu_id: 0,
138 user_stack: vec![0x400000, 0x400100],
139 kernel_stack: vec![],
140 comm: "test".to_string(),
141 user_stack_symbols: vec![],
142 kernel_stack_symbols: vec![],
143 };
144
145 let json = serde_json::to_string(&sample).unwrap();
146 let deserialized: CpuSample = serde_json::from_str(&json).unwrap();
147
148 assert_eq!(sample.pid, deserialized.pid);
149 assert_eq!(sample.timestamp, deserialized.timestamp);
150 }
151
152 #[test]
153 fn test_profile_event_bincode_serialization() {
154 use bincode::Options;
155 let config = bincode::config::DefaultOptions::new()
156 .with_fixint_encoding()
157 .allow_trailing_bytes();
158
159 let event = ProfileEvent::Syscall(SyscallEvent {
160 timestamp: 0x1122334455667788,
161 pid: 0x11111111,
162 tid: 0x22222222,
163 syscall_id: 198, duration_ns: 1000,
165 return_value: 0,
166 comm: "test".to_string(),
167 });
168
169 let bytes = config.serialize(&event).unwrap();
170
171 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();
182 match deserialized {
183 ProfileEvent::Syscall(e) => {
184 assert_eq!(e.syscall_id, 198);
185 }
186 _ => panic!("Wrong variant"),
187 }
188 }
189}