Skip to main content

probex_common/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3/// Event types for kernel-userspace communication
4#[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}
29
30impl TryFrom<u8> for EventType {
31    type Error = u8;
32
33    fn try_from(value: u8) -> Result<Self, Self::Error> {
34        match value {
35            0 => Ok(EventType::SchedSwitch),
36            1 => Ok(EventType::ProcessFork),
37            2 => Ok(EventType::ProcessExit),
38            3 => Ok(EventType::PageFault),
39            4 => Ok(EventType::SyscallReadEnter),
40            5 => Ok(EventType::SyscallReadExit),
41            6 => Ok(EventType::SyscallWriteEnter),
42            7 => Ok(EventType::SyscallWriteExit),
43            8 => Ok(EventType::SyscallMmapEnter),
44            9 => Ok(EventType::SyscallMmapExit),
45            10 => Ok(EventType::SyscallMunmapEnter),
46            11 => Ok(EventType::SyscallMunmapExit),
47            12 => Ok(EventType::SyscallBrkEnter),
48            13 => Ok(EventType::SyscallBrkExit),
49            14 => Ok(EventType::SyscallIoUringSetupEnter),
50            15 => Ok(EventType::SyscallIoUringSetupExit),
51            16 => Ok(EventType::SyscallIoUringEnterEnter),
52            17 => Ok(EventType::SyscallIoUringEnterExit),
53            18 => Ok(EventType::SyscallIoUringRegisterEnter),
54            19 => Ok(EventType::SyscallIoUringRegisterExit),
55            20 => Ok(EventType::CpuSample),
56            v => Err(v),
57        }
58    }
59}
60
61/// Common header for all events
62#[repr(C)]
63#[derive(Clone, Copy, Debug)]
64pub struct EventHeader {
65    pub timestamp_ns: u64,
66    pub pid: u32,
67    pub tgid: u32,
68    /// User-space stack id from bpf_get_stackid(BPF_F_USER_STACK), or -1.
69    pub stack_id: i32,
70    /// Kernel-space stack id from bpf_get_stackid(0), or -1.
71    pub kernel_stack_id: i32,
72    pub stack_kind: u8,
73    pub event_type: u8,
74    pub cpu: u8,
75    pub _padding: [u8; 5],
76}
77
78pub const STACK_KIND_NONE: u8 = 0;
79pub const STACK_KIND_USER: u8 = 1;
80pub const STACK_KIND_KERNEL: u8 = 2;
81pub const STACK_KIND_BOTH: u8 = STACK_KIND_USER | STACK_KIND_KERNEL;
82
83/// Maximum number of frame-pointer-derived user frames emitted in each cpu sample event.
84pub const MAX_CPU_SAMPLE_FRAMES: usize = 127;
85
86// CPU sampler stats indices (per-CPU array slot 0).
87pub const CPU_SAMPLE_STATS_LEN: usize = 7;
88pub const CPU_SAMPLE_STAT_CALLBACK_TOTAL: usize = 0;
89pub const CPU_SAMPLE_STAT_FILTERED_NOT_TRACED: usize = 1;
90pub const CPU_SAMPLE_STAT_EMITTED: usize = 2;
91pub const CPU_SAMPLE_STAT_RINGBUF_DROPPED: usize = 3;
92pub const CPU_SAMPLE_STAT_USER_STACK: usize = 4;
93pub const CPU_SAMPLE_STAT_KERNEL_STACK: usize = 5;
94pub const CPU_SAMPLE_STAT_NO_STACK: usize = 6;
95
96/// CPU sample event carrying explicit user-space return addresses from frame-pointer walking.
97#[repr(C)]
98#[derive(Clone, Copy, Debug)]
99pub struct CpuSampleEvent {
100    pub header: EventHeader,
101    pub frame_count: u16,
102    pub _padding: [u8; 6],
103    pub frames: [u64; MAX_CPU_SAMPLE_FRAMES],
104}
105
106/// Context switch event
107#[repr(C)]
108#[derive(Clone, Copy, Debug)]
109pub struct SchedSwitchEvent {
110    pub header: EventHeader,
111    pub prev_pid: u32,
112    pub prev_tgid: u32,
113    pub next_pid: u32,
114    pub next_tgid: u32,
115    pub prev_state: i64,
116}
117
118/// Process fork event
119#[repr(C)]
120#[derive(Clone, Copy, Debug)]
121pub struct ProcessForkEvent {
122    pub header: EventHeader,
123    pub parent_pid: u32,
124    pub child_pid: u32,
125}
126
127/// Process exit event
128#[repr(C)]
129#[derive(Clone, Copy, Debug)]
130pub struct ProcessExitEvent {
131    pub header: EventHeader,
132    pub exit_code: i32,
133    pub _padding: u32,
134}
135
136/// Page fault event
137#[repr(C)]
138#[derive(Clone, Copy, Debug)]
139pub struct PageFaultEvent {
140    pub header: EventHeader,
141    pub address: u64,
142    pub error_code: u64,
143}
144
145/// Syscall enter event (for read/write)
146#[repr(C)]
147#[derive(Clone, Copy, Debug)]
148pub struct SyscallEnterEvent {
149    pub header: EventHeader,
150    pub fd: i64,
151    pub count: u64,
152}
153
154/// Syscall exit event (for read/write)
155#[repr(C)]
156#[derive(Clone, Copy, Debug)]
157pub struct SyscallExitEvent {
158    pub header: EventHeader,
159    pub ret: i64,
160}
161
162// Constants for event sizes
163pub const SCHED_SWITCH_EVENT_SIZE: usize = core::mem::size_of::<SchedSwitchEvent>();
164pub const PROCESS_FORK_EVENT_SIZE: usize = core::mem::size_of::<ProcessForkEvent>();
165pub const PROCESS_EXIT_EVENT_SIZE: usize = core::mem::size_of::<ProcessExitEvent>();
166pub const PAGE_FAULT_EVENT_SIZE: usize = core::mem::size_of::<PageFaultEvent>();
167pub const SYSCALL_ENTER_EVENT_SIZE: usize = core::mem::size_of::<SyscallEnterEvent>();
168pub const SYSCALL_EXIT_EVENT_SIZE: usize = core::mem::size_of::<SyscallExitEvent>();
169pub const CPU_SAMPLE_EVENT_SIZE: usize = core::mem::size_of::<CpuSampleEvent>();
170
171// Ring buffer size
172pub const RING_BUF_SIZE: u32 = 64 * 1024 * 1024;
173
174// Maximum number of tracked PIDs
175pub const MAX_TRACKED_PIDS: u32 = 8192;
176
177#[cfg(feature = "viewer-api")]
178pub mod viewer_api {
179    use serde::{Deserialize, Serialize};
180    use std::collections::HashMap;
181
182    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
183    pub struct HistogramBucket {
184        pub bucket_start_ns: u64,
185        pub bucket_end_ns: u64,
186        pub count: usize,
187        pub counts_by_type: HashMap<String, usize>,
188    }
189
190    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
191    pub struct HistogramResponse {
192        pub buckets: Vec<HistogramBucket>,
193        pub total_in_range: usize,
194    }
195
196    #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
197    pub struct EventTypeCounts {
198        pub counts: HashMap<String, usize>,
199    }
200
201    #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
202    pub struct LatencySummary {
203        pub count: usize,
204        pub avg_ns: u64,
205        pub p50_ns: u64,
206        pub p95_ns: u64,
207        pub max_ns: u64,
208    }
209
210    #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
211    pub struct SyscallLatencyStats {
212        pub read: LatencySummary,
213        pub write: LatencySummary,
214        pub mmap_alloc_bytes: u64,
215        pub munmap_free_bytes: u64,
216    }
217
218    #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
219    pub struct TraceSummary {
220        pub total_events: usize,
221        pub event_types: Vec<String>,
222        pub unique_pids: Vec<u32>,
223        pub min_ts_ns: u64,
224        pub max_ts_ns: u64,
225        pub cpu_sample_frequency_hz: u64,
226    }
227
228    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
229    pub struct ProcessLifetime {
230        pub pid: u32,
231        pub process_name: Option<String>,
232        pub parent_pid: Option<u32>,
233        pub start_ns: u64,
234        pub end_ns: Option<u64>,
235        pub exit_code: Option<i32>,
236        pub was_forked: bool,
237        pub did_exit: bool,
238    }
239
240    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
241    pub struct ProcessLifetimesResponse {
242        pub processes: Vec<ProcessLifetime>,
243    }
244
245    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
246    pub struct EventMarker {
247        pub ts_ns: u64,
248        pub event_type: String,
249    }
250
251    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
252    pub struct ProcessEventsResponse {
253        pub events_by_pid: HashMap<u32, Vec<EventMarker>>,
254        pub cpu_sample_counts_by_pid: HashMap<u32, Vec<u16>>,
255        pub cpu_sample_bucket_count: usize,
256    }
257
258    #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
259    pub struct EventFlamegraphResponse {
260        pub event_type: String,
261        pub total_samples: usize,
262        pub svg: Option<String>,
263    }
264}