darwin_kperf/sampler/
error.rs1use alloc::string::String;
4use core::{error, ffi::c_int, fmt};
5
6use darwin_kperf_sys::load::LoadError;
7
8use crate::{FrameworkError, event::Event};
9
10#[derive(Debug)]
12pub enum SamplerError {
13 Load(LoadError),
15 Framework(FrameworkError),
17 InvalidCpuName,
19 UnknownCpu(String),
21 EventUnavailable(Event),
23 EventLayoutMismatch { expected: usize, actual: usize },
25 UnexpectedNullPointer,
27 MissingPrivileges,
32 FailedToForceAllCounters(c_int),
34 FailedToSetKpcConfig(c_int),
36 UnableToStartCounting(c_int),
38 UnableToStopCounting(c_int),
40 UnableToStartThreadCounting(c_int),
42 UnableToStopThreadCounting(c_int),
44 UnableToReadCounters(c_int),
46 UnableToResetControl(c_int),
48 SamplerNotRunning,
50}
51
52impl fmt::Display for SamplerError {
53 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::Load(error) => write!(fmt, "framework load failed: {error}"),
56 Self::Framework(error) => fmt::Display::fmt(error, fmt),
57 Self::InvalidCpuName => fmt.write_str("PMC database name is not valid UTF-8"),
58 Self::UnknownCpu(name) => write!(fmt, "unrecognized CPU: {name}"),
59 #[expect(clippy::use_debug)]
60 Self::EventUnavailable(event) => {
61 write!(fmt, "event {event:?} is unavailable on this CPU")
62 }
63 Self::EventLayoutMismatch { expected, actual } => {
64 write!(
65 fmt,
66 "kpep_event layout mismatch: expected stride {expected}, got {actual}"
67 )
68 }
69 Self::UnexpectedNullPointer => {
70 fmt.write_str("framework returned unexpected null pointer")
71 }
72 Self::MissingPrivileges => {
73 fmt.write_str("insufficient privileges to access performance counters")
74 }
75 Self::FailedToForceAllCounters(code) => {
76 write!(fmt, "failed to force-acquire counters (code {code})")
77 }
78 Self::FailedToSetKpcConfig(code) => {
79 write!(fmt, "failed to set KPC config (code {code})")
80 }
81 Self::UnableToStartCounting(code) => {
82 write!(fmt, "failed to start counting (code {code})")
83 }
84 Self::UnableToStopCounting(code) => {
85 write!(fmt, "failed to stop counting (code {code})")
86 }
87 Self::UnableToStartThreadCounting(code) => {
88 write!(fmt, "failed to start thread counting (code {code})")
89 }
90 Self::UnableToStopThreadCounting(code) => {
91 write!(fmt, "failed to stop thread counting (code {code})")
92 }
93 Self::UnableToReadCounters(code) => {
94 write!(fmt, "failed to read thread counters (code {code})")
95 }
96 Self::UnableToResetControl(code) => {
97 write!(fmt, "failed to release counters (code {code})")
98 }
99 Self::SamplerNotRunning => {
100 fmt.write_str("attempted to sample while counting is not enabled")
101 }
102 }
103 }
104}
105
106impl error::Error for SamplerError {
107 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
108 match self {
109 Self::Load(err) => Some(err),
110 Self::Framework(err) => Some(err),
111 Self::InvalidCpuName
112 | Self::UnknownCpu(_)
113 | Self::EventUnavailable(_)
114 | Self::EventLayoutMismatch { .. }
115 | Self::UnexpectedNullPointer
116 | Self::MissingPrivileges
117 | Self::FailedToForceAllCounters(_)
118 | Self::FailedToSetKpcConfig(_)
119 | Self::UnableToStartCounting(_)
120 | Self::UnableToStopCounting(_)
121 | Self::UnableToStartThreadCounting(_)
122 | Self::UnableToStopThreadCounting(_)
123 | Self::UnableToReadCounters(_)
124 | Self::UnableToResetControl(_)
125 | Self::SamplerNotRunning => None,
126 }
127 }
128}
129
130impl From<LoadError> for SamplerError {
131 fn from(value: LoadError) -> Self {
132 Self::Load(value)
133 }
134}
135
136impl From<FrameworkError> for SamplerError {
137 fn from(value: FrameworkError) -> Self {
138 Self::Framework(value)
139 }
140}
141
142pub(crate) const fn try_kpep(code: c_int) -> Result<(), FrameworkError> {
145 if code == 0 {
146 Ok(())
147 } else {
148 Err(FrameworkError::from_code(code))
149 }
150}
151
152pub(crate) fn try_kpc(code: c_int, error: fn(c_int) -> SamplerError) -> Result<(), SamplerError> {
155 if code == 0 { Ok(()) } else { Err(error(code)) }
156}