1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[repr(u8)]
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum EventType {
7 SchedSwitch = 0,
8 ProcessFork = 1,
9 ProcessExit = 2,
10 PageFault = 3,
11 SyscallReadEnter = 4,
12 SyscallReadExit = 5,
13 SyscallWriteEnter = 6,
14 SyscallWriteExit = 7,
15 SyscallMmapEnter = 8,
16 SyscallMmapExit = 9,
17 SyscallMunmapEnter = 10,
18 SyscallMunmapExit = 11,
19 SyscallBrkEnter = 12,
20 SyscallBrkExit = 13,
21 SyscallIoUringSetupEnter = 14,
22 SyscallIoUringSetupExit = 15,
23 SyscallIoUringEnterEnter = 16,
24 SyscallIoUringEnterExit = 17,
25 SyscallIoUringRegisterEnter = 18,
26 SyscallIoUringRegisterExit = 19,
27 CpuSample = 20,
28 SyscallFsyncEnter = 21,
29 SyscallFsyncExit = 22,
30 SyscallFdatasyncEnter = 23,
31 SyscallFdatasyncExit = 24,
32 IoUringComplete = 25,
33}
34
35impl TryFrom<u8> for EventType {
36 type Error = u8;
37
38 fn try_from(value: u8) -> Result<Self, Self::Error> {
39 match value {
40 0 => Ok(EventType::SchedSwitch),
41 1 => Ok(EventType::ProcessFork),
42 2 => Ok(EventType::ProcessExit),
43 3 => Ok(EventType::PageFault),
44 4 => Ok(EventType::SyscallReadEnter),
45 5 => Ok(EventType::SyscallReadExit),
46 6 => Ok(EventType::SyscallWriteEnter),
47 7 => Ok(EventType::SyscallWriteExit),
48 8 => Ok(EventType::SyscallMmapEnter),
49 9 => Ok(EventType::SyscallMmapExit),
50 10 => Ok(EventType::SyscallMunmapEnter),
51 11 => Ok(EventType::SyscallMunmapExit),
52 12 => Ok(EventType::SyscallBrkEnter),
53 13 => Ok(EventType::SyscallBrkExit),
54 14 => Ok(EventType::SyscallIoUringSetupEnter),
55 15 => Ok(EventType::SyscallIoUringSetupExit),
56 16 => Ok(EventType::SyscallIoUringEnterEnter),
57 17 => Ok(EventType::SyscallIoUringEnterExit),
58 18 => Ok(EventType::SyscallIoUringRegisterEnter),
59 19 => Ok(EventType::SyscallIoUringRegisterExit),
60 20 => Ok(EventType::CpuSample),
61 21 => Ok(EventType::SyscallFsyncEnter),
62 22 => Ok(EventType::SyscallFsyncExit),
63 23 => Ok(EventType::SyscallFdatasyncEnter),
64 24 => Ok(EventType::SyscallFdatasyncExit),
65 25 => Ok(EventType::IoUringComplete),
66 v => Err(v),
67 }
68 }
69}
70
71#[repr(C)]
73#[derive(Clone, Copy, Debug)]
74pub struct EventHeader {
75 pub timestamp_ns: u64,
76 pub pid: u32,
77 pub tgid: u32,
78 pub stack_id: i32,
80 pub kernel_stack_id: i32,
82 pub stack_kind: u8,
83 pub event_type: u8,
84 pub cpu: u8,
85 pub _padding: [u8; 5],
86}
87
88pub const STACK_KIND_NONE: u8 = 0;
89pub const STACK_KIND_USER: u8 = 1;
90pub const STACK_KIND_KERNEL: u8 = 2;
91pub const STACK_KIND_BOTH: u8 = STACK_KIND_USER | STACK_KIND_KERNEL;
92
93pub const MAX_CPU_SAMPLE_FRAMES: usize = 127;
95
96pub const CPU_SAMPLE_STATS_LEN: usize = 7;
98pub const CPU_SAMPLE_STAT_CALLBACK_TOTAL: usize = 0;
99pub const CPU_SAMPLE_STAT_FILTERED_NOT_TRACED: usize = 1;
100pub const CPU_SAMPLE_STAT_EMITTED: usize = 2;
101pub const CPU_SAMPLE_STAT_RINGBUF_DROPPED: usize = 3;
102pub const CPU_SAMPLE_STAT_USER_STACK: usize = 4;
103pub const CPU_SAMPLE_STAT_KERNEL_STACK: usize = 5;
104pub const CPU_SAMPLE_STAT_NO_STACK: usize = 6;
105
106#[repr(C)]
108#[derive(Clone, Copy, Debug)]
109pub struct CpuSampleEvent {
110 pub header: EventHeader,
111 pub frame_count: u16,
112 pub _padding: [u8; 6],
113 pub frames: [u64; MAX_CPU_SAMPLE_FRAMES],
114}
115
116#[repr(C)]
118#[derive(Clone, Copy, Debug)]
119pub struct SchedSwitchEvent {
120 pub header: EventHeader,
121 pub prev_pid: u32,
122 pub prev_tgid: u32,
123 pub next_pid: u32,
124 pub next_tgid: u32,
125 pub prev_state: i64,
126}
127
128#[repr(C)]
130#[derive(Clone, Copy, Debug)]
131pub struct ProcessForkEvent {
132 pub header: EventHeader,
133 pub parent_pid: u32,
134 pub child_pid: u32,
135}
136
137#[repr(C)]
139#[derive(Clone, Copy, Debug)]
140pub struct ProcessExitEvent {
141 pub header: EventHeader,
142 pub exit_code: i32,
143 pub _padding: u32,
144}
145
146#[repr(C)]
148#[derive(Clone, Copy, Debug)]
149pub struct PageFaultEvent {
150 pub header: EventHeader,
151 pub address: u64,
152 pub error_code: u64,
153}
154
155#[repr(C)]
157#[derive(Clone, Copy, Debug)]
158pub struct SyscallEnterEvent {
159 pub header: EventHeader,
160 pub fd: i64,
161 pub count: u64,
162}
163
164#[repr(C)]
166#[derive(Clone, Copy, Debug)]
167pub struct SyscallExitEvent {
168 pub header: EventHeader,
169 pub ret: i64,
170}
171
172#[repr(C)]
175#[derive(Clone, Copy, Debug)]
176pub struct IoUringCompleteEvent {
177 pub header: EventHeader,
178 pub submit_ts_ns: u64,
180 pub opcode: u8,
182 pub _padding: [u8; 3],
183 pub res: i32,
185}
186
187pub const SCHED_SWITCH_EVENT_SIZE: usize = core::mem::size_of::<SchedSwitchEvent>();
189pub const PROCESS_FORK_EVENT_SIZE: usize = core::mem::size_of::<ProcessForkEvent>();
190pub const PROCESS_EXIT_EVENT_SIZE: usize = core::mem::size_of::<ProcessExitEvent>();
191pub const PAGE_FAULT_EVENT_SIZE: usize = core::mem::size_of::<PageFaultEvent>();
192pub const SYSCALL_ENTER_EVENT_SIZE: usize = core::mem::size_of::<SyscallEnterEvent>();
193pub const SYSCALL_EXIT_EVENT_SIZE: usize = core::mem::size_of::<SyscallExitEvent>();
194pub const IO_URING_COMPLETE_EVENT_SIZE: usize = core::mem::size_of::<IoUringCompleteEvent>();
195pub const CPU_SAMPLE_EVENT_SIZE: usize = core::mem::size_of::<CpuSampleEvent>();
196
197pub const RING_BUF_SIZE: u32 = 64 * 1024 * 1024;
199
200pub const MAX_TRACKED_PIDS: u32 = 8192;
202
203pub const MAX_IO_URING_INFLIGHT: u32 = 16384;
205
206#[cfg(feature = "viewer-api")]
207pub mod viewer_api {
208 use serde::{Deserialize, Serialize};
209 use std::collections::HashMap;
210
211 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
212 pub struct HistogramBucket {
213 pub bucket_start_ns: u64,
214 pub bucket_end_ns: u64,
215 pub count: usize,
216 pub counts_by_type: HashMap<String, usize>,
217 }
218
219 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
220 pub struct HistogramResponse {
221 pub buckets: Vec<HistogramBucket>,
222 pub total_in_range: usize,
223 }
224
225 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
226 pub struct EventTypeCounts {
227 pub counts: HashMap<String, usize>,
228 }
229
230 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
231 pub struct LatencySummary {
232 pub count: usize,
233 pub avg_ns: u64,
234 pub p50_ns: u64,
235 pub p95_ns: u64,
236 pub max_ns: u64,
237 }
238
239 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
240 pub struct SyscallLatencyStats {
241 pub read: LatencySummary,
242 pub write: LatencySummary,
243 pub io_uring: LatencySummary,
244 pub mmap_alloc_bytes: u64,
245 pub munmap_free_bytes: u64,
246 }
247
248 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
249 pub struct TraceSummary {
250 pub total_events: usize,
251 pub event_types: Vec<String>,
252 pub unique_pids: Vec<u32>,
253 pub min_ts_ns: u64,
254 pub max_ts_ns: u64,
255 pub cpu_sample_frequency_hz: u64,
256 }
257
258 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
259 pub struct ProcessLifetime {
260 pub pid: u32,
261 pub process_name: Option<String>,
262 pub parent_pid: Option<u32>,
263 pub start_ns: u64,
264 pub end_ns: u64,
265 pub exit: Option<i32>,
266 pub was_forked: bool,
267 }
268
269 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
270 pub struct ProcessLifetimesResponse {
271 pub processes: Vec<ProcessLifetime>,
272 }
273
274 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
275 pub struct EventMarker {
276 pub ts_ns: u64,
277 pub event_type: String,
278 }
279
280 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
281 pub struct ProcessEventsResponse {
282 pub events_by_pid: HashMap<u32, Vec<EventMarker>>,
283 pub cpu_sample_counts_by_pid: HashMap<u32, Vec<u16>>,
284 pub cpu_sample_bucket_count: usize,
285 }
286
287 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
288 pub struct EventFlamegraphResponse {
289 pub event_type: String,
290 pub total_samples: usize,
291 pub svg: Option<String>,
292 }
293
294 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
295 pub struct IoTypeStats {
296 pub operation: String,
297 pub total_ops: u64,
298 pub total_bytes: u64,
299 pub avg_latency_ns: u64,
300 pub p50_event: Option<EventDetail>,
302 pub p95_event: Option<EventDetail>,
303 pub p99_event: Option<EventDetail>,
304 pub max_event: Option<EventDetail>,
305 pub latencies_ns: Vec<u64>,
307 pub sizes_bytes: Vec<u64>,
309 }
310
311 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
312 pub struct IoStatistics {
313 pub by_operation: Vec<IoTypeStats>,
314 pub total_ops: u64,
315 pub total_bytes: u64,
316 pub time_range_ns: (u64, u64),
317 }
318
319 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
320 pub struct CumulativeMemoryPoint {
321 pub ts_ns: u64,
322 pub cumulative_bytes: i64,
323 }
324
325 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
326 pub struct MemoryStatistics {
327 pub by_operation: Vec<IoTypeStats>,
328 pub total_alloc_ops: u64,
329 pub total_alloc_bytes: u64,
330 pub total_free_ops: u64,
331 pub total_free_bytes: u64,
332 pub cumulative_usage: Vec<CumulativeMemoryPoint>,
333 pub time_range_ns: (u64, u64),
334 }
335
336 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
337 pub struct EventDetail {
338 pub ts_ns: u64,
339 pub latency_ns: Option<u64>,
340 pub event_type: String,
341 pub pid: u32,
342 pub stack_trace: Option<Vec<String>>,
343 }
344
345 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
346 pub struct EventListResponse {
347 pub events: Vec<EventDetail>,
348 pub total_in_range: usize,
349 }
350}