scirs2_core/profiling/
perf_integration.rs1#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
32use crate::CoreResult;
33#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
34use perf_event::{events::Hardware, Builder, Counter};
35#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
36use std::sync::Arc;
37
38#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum PerfEvent {
42 CpuCycles,
44 Instructions,
46 CacheReferences,
48 CacheMisses,
50 BranchInstructions,
52 BranchMisses,
54 BusCycles,
56 StalledCyclesFrontend,
58 StalledCyclesBackend,
60}
61
62#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
63impl PerfEvent {
64 fn to_hardware(self) -> Hardware {
66 match self {
67 PerfEvent::CpuCycles => Hardware::CPU_CYCLES,
68 PerfEvent::Instructions => Hardware::INSTRUCTIONS,
69 PerfEvent::CacheReferences => Hardware::CACHE_REFERENCES,
70 PerfEvent::CacheMisses => Hardware::CACHE_MISSES,
71 PerfEvent::BranchInstructions => Hardware::BRANCH_INSTRUCTIONS,
72 PerfEvent::BranchMisses => Hardware::BRANCH_MISSES,
73 PerfEvent::BusCycles => Hardware::BUS_CYCLES,
74 PerfEvent::StalledCyclesFrontend => Hardware::STALLED_CYCLES_FRONTEND,
75 PerfEvent::StalledCyclesBackend => Hardware::STALLED_CYCLES_BACKEND,
76 }
77 }
78}
79
80#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
82pub struct PerfCounter {
83 counter: Counter,
84 event: PerfEvent,
85}
86
87#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
88impl PerfCounter {
89 pub fn new(event: PerfEvent) -> CoreResult<Self> {
91 let counter = Builder::new()
92 .one_cpu(0)
93 .kind(event.to_hardware())
94 .build()
95 .map_err(|e| {
96 crate::CoreError::ConfigError(crate::error::ErrorContext::new(format!(
97 "Failed to create perf counter: {}",
98 e
99 )))
100 })?;
101
102 Ok(Self { counter, event })
103 }
104
105 pub fn enable(&mut self) -> CoreResult<()> {
107 self.counter.enable().map_err(|e| {
108 crate::CoreError::ConfigError(crate::error::ErrorContext::new(format!(
109 "Failed to enable perf counter: {}",
110 e
111 )))
112 })?;
113 Ok(())
114 }
115
116 pub fn disable(&mut self) -> CoreResult<()> {
118 self.counter.disable().map_err(|e| {
119 crate::CoreError::ConfigError(crate::error::ErrorContext::new(format!(
120 "Failed to disable perf counter: {}",
121 e
122 )))
123 })?;
124 Ok(())
125 }
126
127 pub fn read(&mut self) -> CoreResult<u64> {
129 let value = self.counter.read().map_err(|e| {
130 crate::CoreError::ConfigError(crate::error::ErrorContext::new(format!(
131 "Failed to read perf counter: {}",
132 e
133 )))
134 })?;
135 Ok(value)
136 }
137
138 pub fn reset(&mut self) -> CoreResult<()> {
140 self.counter.reset().map_err(|e| {
141 crate::CoreError::ConfigError(crate::error::ErrorContext::new(format!(
142 "Failed to reset perf counter: {}",
143 e
144 )))
145 })?;
146 Ok(())
147 }
148
149 pub fn event(&self) -> PerfEvent {
151 self.event
152 }
153}
154
155#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
157pub struct PerfCounterGroup {
158 counters: Vec<PerfCounter>,
159}
160
161#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
162impl PerfCounterGroup {
163 pub fn new(events: &[PerfEvent]) -> CoreResult<Self> {
165 let mut counters = Vec::new();
166
167 for &event in events {
168 counters.push(PerfCounter::new(event)?);
169 }
170
171 Ok(Self { counters })
172 }
173
174 pub fn enable(&mut self) -> CoreResult<()> {
176 for counter in &mut self.counters {
177 counter.enable()?;
178 }
179 Ok(())
180 }
181
182 pub fn disable(&mut self) -> CoreResult<()> {
184 for counter in &mut self.counters {
185 counter.disable()?;
186 }
187 Ok(())
188 }
189
190 pub fn read(&mut self) -> CoreResult<Vec<(PerfEvent, u64)>> {
192 let mut results = Vec::new();
193
194 for counter in &mut self.counters {
195 let value = counter.read()?;
196 results.push((counter.event(), value));
197 }
198
199 Ok(results)
200 }
201
202 pub fn reset(&mut self) -> CoreResult<()> {
204 for counter in &mut self.counters {
205 counter.reset()?;
206 }
207 Ok(())
208 }
209}
210
211#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
213pub struct PerfMarker {
214 name: String,
215}
216
217#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
218impl PerfMarker {
219 pub fn new(name: impl Into<String>) -> Self {
221 let marker = Self { name: name.into() };
222 marker
225 }
226
227 pub fn end(self) {
229 }
231}
232
233#[macro_export]
235#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
236macro_rules! perf_marker {
237 ($name:expr) => {
238 let _marker = $crate::profiling::perf_integration::PerfMarker::new($name);
239 };
240}
241
242#[cfg(not(all(target_os = "linux", feature = "profiling_perf")))]
244use crate::CoreResult;
245
246#[cfg(not(all(target_os = "linux", feature = "profiling_perf")))]
247#[derive(Debug, Clone, Copy)]
248pub enum PerfEvent {
249 CpuCycles,
250 Instructions,
251 CacheReferences,
252 CacheMisses,
253 BranchInstructions,
254 BranchMisses,
255 BusCycles,
256 StalledCyclesFrontend,
257 StalledCyclesBackend,
258}
259
260#[cfg(not(all(target_os = "linux", feature = "profiling_perf")))]
261pub struct PerfCounter;
262
263#[cfg(not(all(target_os = "linux", feature = "profiling_perf")))]
264impl PerfCounter {
265 pub fn new(_event: PerfEvent) -> CoreResult<Self> {
266 Ok(Self)
267 }
268 pub fn enable(&mut self) -> CoreResult<()> {
269 Ok(())
270 }
271 pub fn disable(&mut self) -> CoreResult<()> {
272 Ok(())
273 }
274 pub fn read(&mut self) -> CoreResult<u64> {
275 Ok(0)
276 }
277 pub fn reset(&mut self) -> CoreResult<()> {
278 Ok(())
279 }
280}
281
282#[cfg(test)]
283#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_perf_counter_creation() {
289 let result = PerfCounter::new(PerfEvent::CpuCycles);
290 if let Ok(mut counter) = result {
292 assert!(counter.enable().is_ok() || counter.enable().is_err());
293 }
294 }
295
296 #[test]
297 fn test_perf_counter_group() {
298 let events = [PerfEvent::CpuCycles, PerfEvent::Instructions];
299 let result = PerfCounterGroup::new(&events);
300
301 if let Ok(mut group) = result {
303 assert!(group.enable().is_ok() || group.enable().is_err());
304 }
305 }
306
307 #[test]
308 fn test_perf_marker() {
309 let marker = PerfMarker::new("test_marker");
310 marker.end();
311 }
313}