darwin_kperf/framework/mod.rs
1//! RAII handles for Apple's private performance counter frameworks.
2//!
3//! [`KPerf`] wraps `kperf.framework` (counter configuration and sampling) and
4//! [`KPerfData`] wraps `kperfdata.framework` (PMC event database and
5//! configuration building). Both load their framework at construction via
6//! `dlopen` and resolve all required symbols eagerly into a
7//! [`VTable`](darwin_kperf_sys::kperf::VTable).
8//!
9//! You normally don't construct these directly. [`Sampler::new`](crate::Sampler::new)
10//! creates both handles internally. If you need the raw function pointers for
11//! something the safe API doesn't expose, you can access them through
12//! [`Sampler::kperf`](crate::Sampler::kperf) and
13//! [`Sampler::kperfdata`](crate::Sampler::kperfdata).
14
15mod error;
16
17use core::ffi::CStr;
18
19use darwin_kperf_sys::load::{LibraryHandle, LoadError};
20
21pub use self::error::{FrameworkError, FrameworkErrorKind};
22
23/// Handle to Apple's private `kperf.framework`.
24///
25/// Owns the dynamically loaded library and its resolved
26/// [`VTable`](darwin_kperf_sys::kperf::VTable), which has the KPC function
27/// pointers for counter configuration, sampling, and tick/nanosecond
28/// conversion.
29#[derive(Debug)]
30pub struct KPerf {
31 _handle: LibraryHandle,
32 vtable: darwin_kperf_sys::kperf::VTable,
33}
34
35impl KPerf {
36 /// Loads `kperf.framework` from its default system path.
37 ///
38 /// # Errors
39 ///
40 /// Returns [`LoadError`] if the framework cannot be loaded or any required symbol
41 /// cannot be resolved.
42 pub fn new() -> Result<Self, LoadError> {
43 Self::load(c"/System/Library/PrivateFrameworks/kperf.framework/kperf")
44 }
45
46 /// Loads `kperf.framework` from a custom `path`.
47 ///
48 /// # Errors
49 ///
50 /// Returns [`LoadError`] if the framework cannot be loaded or any required symbol
51 /// cannot be resolved.
52 pub fn load(path: &CStr) -> Result<Self, LoadError> {
53 let handle = LibraryHandle::open(path)?;
54 let vtable = darwin_kperf_sys::kperf::VTable::load(&handle)?;
55
56 Ok(Self {
57 _handle: handle,
58 vtable,
59 })
60 }
61
62 /// Resolved vtable for the loaded `kperf.framework`.
63 #[must_use]
64 pub const fn vtable(&self) -> &darwin_kperf_sys::kperf::VTable {
65 &self.vtable
66 }
67}
68
69/// Handle to Apple's private `kperfdata.framework`.
70///
71/// Owns the dynamically loaded library and its resolved
72/// [`VTable`](darwin_kperf_sys::kperfdata::VTable). The vtable contains the
73/// KPEP functions for opening the PMC event database for the current CPU,
74/// looking up events by name or alias, and building the register configuration
75/// that gets pushed to the kernel via [`KPerf`].
76#[derive(Debug)]
77pub struct KPerfData {
78 _handle: LibraryHandle,
79 vtable: darwin_kperf_sys::kperfdata::VTable,
80}
81
82impl KPerfData {
83 /// Loads `kperfdata.framework` from its default system path.
84 ///
85 /// # Errors
86 ///
87 /// Returns [`LoadError`] if the framework cannot be loaded or any required symbol
88 /// cannot be resolved.
89 pub fn new() -> Result<Self, LoadError> {
90 Self::load(c"/System/Library/PrivateFrameworks/kperfdata.framework/kperfdata")
91 }
92
93 /// Loads `kperfdata.framework` from a custom `path`.
94 ///
95 /// # Errors
96 ///
97 /// Returns [`LoadError`] if the framework cannot be loaded or any required symbol
98 /// cannot be resolved.
99 pub fn load(path: &CStr) -> Result<Self, LoadError> {
100 let handle = LibraryHandle::open(path)?;
101 let vtable = darwin_kperf_sys::kperfdata::VTable::load(&handle)?;
102
103 Ok(Self {
104 _handle: handle,
105 vtable,
106 })
107 }
108
109 /// Resolved vtable for the loaded `kperfdata.framework`.
110 #[must_use]
111 pub const fn vtable(&self) -> &darwin_kperf_sys::kperfdata::VTable {
112 &self.vtable
113 }
114}