Loads both frameworks, opens the PMC database, and force-acquires counters. # Errors Returns [`SamplerError`] if either framework fails to load, the PMC database cannot be opened, the CPU is not recognized, or counter acquisition fails.
()
| 147 | /// database cannot be opened, the CPU is not recognized, or counter |
| 148 | /// acquisition fails. |
| 149 | pub(crate) fn ll_init() -> Result<Sampler, SamplerError> { |
| 150 | let kperf = KPerf::new()?; |
| 151 | let kperfdata = KPerfData::new()?; |
| 152 | |
| 153 | let kpc_vt = kperf.vtable(); |
| 154 | let kpep_vt = kperfdata.vtable(); |
| 155 | |
| 156 | let mut db = ptr::null_mut(); |
| 157 | // SAFETY: passing null name opens the database for the current CPU. |
| 158 | try_kpep(unsafe { (kpep_vt.kpep_db_create)(ptr::null(), &raw mut db) })?; |
| 159 | let Some(db) = NonNull::new(db) else { |
| 160 | return Err(SamplerError::UnexpectedNullPointer); |
| 161 | }; |
| 162 | |
| 163 | let db = DropGuard::new(db, |db| { |
| 164 | // SAFETY: db was allocated by kpep_db_create above. |
| 165 | unsafe { (kpep_vt.kpep_db_free)(db.as_ptr()) } |
| 166 | }); |
| 167 | |
| 168 | // SAFETY: db is valid, name receives a pointer into the db's internal storage. |
| 169 | let name = unsafe { db.as_ref().name }; |
| 170 | |
| 171 | // SAFETY: kpep_db_name returns a pointer into the db's internal storage, |
| 172 | // valid for the lifetime of the db. |
| 173 | let name = unsafe { CStr::from_ptr(name) }; |
| 174 | let name = name.to_str().map_err(|_err| SamplerError::InvalidCpuName)?; |
| 175 | |
| 176 | let cpu = Cpu::from_db_name(name).ok_or_else(|| SamplerError::UnknownCpu(name.to_owned()))?; |
| 177 | |
| 178 | // Save the previous force_all state so we can restore it on drop. |
| 179 | let mut saved_force_all = 0; |
| 180 | try_kpc( |
| 181 | // SAFETY: reads the current force_all_ctrs sysctl value. |
| 182 | unsafe { (kpc_vt.kpc_force_all_ctrs_get)(&raw mut saved_force_all) }, |
| 183 | |_| SamplerError::MissingPrivileges, |
| 184 | )?; |
| 185 | |
| 186 | try_kpc( |
| 187 | // SAFETY: acquires power counters from the OS Power Manager. |
| 188 | unsafe { (kpc_vt.kpc_force_all_ctrs_set)(1) }, |
| 189 | SamplerError::FailedToForceAllCounters, |
| 190 | )?; |
| 191 | |
| 192 | let clear_force = DropGuard::new((), |()| { |
| 193 | // SAFETY: Value acquired is simply re-set |
| 194 | let _result = unsafe { (kpc_vt.kpc_force_all_ctrs_set)(saved_force_all) }; |
| 195 | }); |
| 196 | |
| 197 | // Verify that the framework's kpep_event stride matches our struct |
| 198 | // definition. Apple has changed this struct size across macOS versions; |
| 199 | // a mismatch means our repr(C) definition is stale and direct field |
| 200 | // access would read corrupt data. |
| 201 | if cfg!(any(debug_assertions, feature = "runtime-assertions")) { |
| 202 | verify_event_stride(kpep_vt, db.as_ptr())?; |
| 203 | } |
| 204 | |
| 205 | DropGuard::dismiss(clear_force); |
| 206 | let db = DropGuard::dismiss(db); |
no test coverage detected