#![expect(non_camel_case_types)]
use core::{
ffi::{c_char, c_int},
fmt,
};
use crate::load::{LibraryHandle, LibrarySymbol, LoadError};
pub type kpc_config_t = u64;
pub const KPC_CLASS_FIXED: u32 = 0;
pub const KPC_CLASS_CONFIGURABLE: u32 = 1;
pub const KPC_CLASS_POWER: u32 = 2;
pub const KPC_CLASS_RAWPMU: u32 = 3;
pub const KPC_CLASS_FIXED_MASK: u32 = 1 << KPC_CLASS_FIXED;
pub const KPC_CLASS_CONFIGURABLE_MASK: u32 = 1 << KPC_CLASS_CONFIGURABLE;
pub const KPC_CLASS_POWER_MASK: u32 = 1 << KPC_CLASS_POWER;
pub const KPC_CLASS_RAWPMU_MASK: u32 = 1 << KPC_CLASS_RAWPMU;
pub const KPC_PMU_ERROR: u32 = 0;
pub const KPC_PMU_INTEL_V3: u32 = 1;
pub const KPC_PMU_ARM_APPLE: u32 = 2;
pub const KPC_PMU_INTEL_V2: u32 = 3;
pub const KPC_PMU_ARM_V2: u32 = 4;
pub const KPC_MAX_COUNTERS: usize = 32;
pub const KPERF_SAMPLER_TH_INFO: u32 = 1 << 0;
pub const KPERF_SAMPLER_TH_SNAPSHOT: u32 = 1 << 1;
pub const KPERF_SAMPLER_KSTACK: u32 = 1 << 2;
pub const KPERF_SAMPLER_USTACK: u32 = 1 << 3;
pub const KPERF_SAMPLER_PMC_THREAD: u32 = 1 << 4;
pub const KPERF_SAMPLER_PMC_CPU: u32 = 1 << 5;
pub const KPERF_SAMPLER_PMC_CONFIG: u32 = 1 << 6;
pub const KPERF_SAMPLER_MEMINFO: u32 = 1 << 7;
pub const KPERF_SAMPLER_TH_SCHEDULING: u32 = 1 << 8;
pub const KPERF_SAMPLER_TH_DISPATCH: u32 = 1 << 9;
pub const KPERF_SAMPLER_TK_SNAPSHOT: u32 = 1 << 10;
pub const KPERF_SAMPLER_SYS_MEM: u32 = 1 << 11;
pub const KPERF_SAMPLER_TH_INSCYC: u32 = 1 << 12;
pub const KPERF_SAMPLER_TK_INFO: u32 = 1 << 13;
pub const KPERF_ACTION_MAX: u32 = 32;
pub const KPERF_TIMER_MAX: u32 = 8;
pub type kpc_cpu_string = unsafe extern "C" fn(buf: *mut c_char, buf_size: usize) -> c_int;
pub type kpc_pmu_version = unsafe extern "C" fn() -> u32;
pub type kpc_get_counting = unsafe extern "C" fn() -> u32;
pub type kpc_set_counting = unsafe extern "C" fn(classes: u32) -> c_int;
pub type kpc_get_thread_counting = unsafe extern "C" fn() -> u32;
pub type kpc_set_thread_counting = unsafe extern "C" fn(classes: u32) -> c_int;
pub type kpc_get_config_count = unsafe extern "C" fn(classes: u32) -> u32;
pub type kpc_get_counter_count = unsafe extern "C" fn(classes: u32) -> u32;
pub type kpc_get_config = unsafe extern "C" fn(classes: u32, config: *mut kpc_config_t) -> c_int;
pub type kpc_set_config = unsafe extern "C" fn(classes: u32, config: *mut kpc_config_t) -> c_int;
pub type kpc_get_cpu_counters =
unsafe extern "C" fn(all_cpus: bool, classes: u32, curcpu: *mut c_int, buf: *mut u64) -> c_int;
pub type kpc_get_thread_counters =
unsafe extern "C" fn(tid: u32, buf_count: u32, buf: *mut u64) -> c_int;
pub type kpc_force_all_ctrs_set = unsafe extern "C" fn(val: c_int) -> c_int;
pub type kpc_force_all_ctrs_get = unsafe extern "C" fn(val_out: *mut c_int) -> c_int;
pub type kperf_action_count_set = unsafe extern "C" fn(count: u32) -> c_int;
pub type kperf_action_count_get = unsafe extern "C" fn(count: *mut u32) -> c_int;
pub type kperf_action_samplers_set = unsafe extern "C" fn(actionid: u32, sample: u32) -> c_int;
pub type kperf_action_samplers_get = unsafe extern "C" fn(actionid: u32, sample: *mut u32) -> c_int;
pub type kperf_action_filter_set_by_task = unsafe extern "C" fn(actionid: u32, port: i32) -> c_int;
pub type kperf_action_filter_set_by_pid = unsafe extern "C" fn(actionid: u32, pid: i32) -> c_int;
pub type kperf_timer_count_set = unsafe extern "C" fn(count: u32) -> c_int;
pub type kperf_timer_count_get = unsafe extern "C" fn(count: *mut u32) -> c_int;
pub type kperf_timer_period_set = unsafe extern "C" fn(actionid: u32, tick: u64) -> c_int;
pub type kperf_timer_period_get = unsafe extern "C" fn(actionid: u32, tick: *mut u64) -> c_int;
pub type kperf_timer_action_set = unsafe extern "C" fn(actionid: u32, timerid: u32) -> c_int;
pub type kperf_timer_action_get = unsafe extern "C" fn(actionid: u32, timerid: *mut u32) -> c_int;
pub type kperf_timer_pet_set = unsafe extern "C" fn(timerid: u32) -> c_int;
pub type kperf_timer_pet_get = unsafe extern "C" fn(timerid: *mut u32) -> c_int;
pub type kperf_sample_set = unsafe extern "C" fn(enabled: u32) -> c_int;
pub type kperf_sample_get = unsafe extern "C" fn(enabled: *mut u32) -> c_int;
pub type kperf_reset = unsafe extern "C" fn() -> c_int;
pub type kperf_ns_to_ticks = unsafe extern "C" fn(ns: u64) -> u64;
pub type kperf_ticks_to_ns = unsafe extern "C" fn(ticks: u64) -> u64;
pub type kperf_tick_frequency = unsafe extern "C" fn() -> u64;
macro_rules! load_sym {
($handle:expr, $name:ident, $cname:expr) => {{
unsafe { core::mem::transmute::<LibrarySymbol, $name>($handle.symbol($cname)?) }
}};
}
pub struct VTable {
pub kpc_cpu_string: kpc_cpu_string,
pub kpc_pmu_version: kpc_pmu_version,
pub kpc_get_counting: kpc_get_counting,
pub kpc_set_counting: kpc_set_counting,
pub kpc_get_thread_counting: kpc_get_thread_counting,
pub kpc_set_thread_counting: kpc_set_thread_counting,
pub kpc_get_config_count: kpc_get_config_count,
pub kpc_get_counter_count: kpc_get_counter_count,
pub kpc_get_config: kpc_get_config,
pub kpc_set_config: kpc_set_config,
pub kpc_get_cpu_counters: kpc_get_cpu_counters,
pub kpc_get_thread_counters: kpc_get_thread_counters,
pub kpc_force_all_ctrs_set: kpc_force_all_ctrs_set,
pub kpc_force_all_ctrs_get: kpc_force_all_ctrs_get,
pub kperf_action_count_set: kperf_action_count_set,
pub kperf_action_count_get: kperf_action_count_get,
pub kperf_action_samplers_set: kperf_action_samplers_set,
pub kperf_action_samplers_get: kperf_action_samplers_get,
pub kperf_action_filter_set_by_task: kperf_action_filter_set_by_task,
pub kperf_action_filter_set_by_pid: kperf_action_filter_set_by_pid,
pub kperf_timer_count_set: kperf_timer_count_set,
pub kperf_timer_count_get: kperf_timer_count_get,
pub kperf_timer_period_set: kperf_timer_period_set,
pub kperf_timer_period_get: kperf_timer_period_get,
pub kperf_timer_action_set: kperf_timer_action_set,
pub kperf_timer_action_get: kperf_timer_action_get,
pub kperf_timer_pet_set: kperf_timer_pet_set,
pub kperf_timer_pet_get: kperf_timer_pet_get,
pub kperf_sample_set: kperf_sample_set,
pub kperf_sample_get: kperf_sample_get,
pub kperf_reset: kperf_reset,
pub kperf_ns_to_ticks: kperf_ns_to_ticks,
pub kperf_ticks_to_ns: kperf_ticks_to_ns,
pub kperf_tick_frequency: kperf_tick_frequency,
}
impl fmt::Debug for VTable {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("VTable").finish_non_exhaustive()
}
}
impl VTable {
#[expect(clippy::too_many_lines)]
pub fn load(handle: &LibraryHandle) -> Result<Self, LoadError> {
Ok(Self {
kpc_cpu_string: load_sym!(handle, kpc_cpu_string, c"kpc_cpu_string"),
kpc_pmu_version: load_sym!(handle, kpc_pmu_version, c"kpc_pmu_version"),
kpc_get_counting: load_sym!(handle, kpc_get_counting, c"kpc_get_counting"),
kpc_set_counting: load_sym!(handle, kpc_set_counting, c"kpc_set_counting"),
kpc_get_thread_counting: load_sym!(
handle,
kpc_get_thread_counting,
c"kpc_get_thread_counting"
),
kpc_set_thread_counting: load_sym!(
handle,
kpc_set_thread_counting,
c"kpc_set_thread_counting"
),
kpc_get_config_count: load_sym!(handle, kpc_get_config_count, c"kpc_get_config_count"),
kpc_get_counter_count: load_sym!(
handle,
kpc_get_counter_count,
c"kpc_get_counter_count"
),
kpc_get_config: load_sym!(handle, kpc_get_config, c"kpc_get_config"),
kpc_set_config: load_sym!(handle, kpc_set_config, c"kpc_set_config"),
kpc_get_cpu_counters: load_sym!(handle, kpc_get_cpu_counters, c"kpc_get_cpu_counters"),
kpc_get_thread_counters: load_sym!(
handle,
kpc_get_thread_counters,
c"kpc_get_thread_counters"
),
kpc_force_all_ctrs_set: load_sym!(
handle,
kpc_force_all_ctrs_set,
c"kpc_force_all_ctrs_set"
),
kpc_force_all_ctrs_get: load_sym!(
handle,
kpc_force_all_ctrs_get,
c"kpc_force_all_ctrs_get"
),
kperf_action_count_set: load_sym!(
handle,
kperf_action_count_set,
c"kperf_action_count_set"
),
kperf_action_count_get: load_sym!(
handle,
kperf_action_count_get,
c"kperf_action_count_get"
),
kperf_action_samplers_set: load_sym!(
handle,
kperf_action_samplers_set,
c"kperf_action_samplers_set"
),
kperf_action_samplers_get: load_sym!(
handle,
kperf_action_samplers_get,
c"kperf_action_samplers_get"
),
kperf_action_filter_set_by_task: load_sym!(
handle,
kperf_action_filter_set_by_task,
c"kperf_action_filter_set_by_task"
),
kperf_action_filter_set_by_pid: load_sym!(
handle,
kperf_action_filter_set_by_pid,
c"kperf_action_filter_set_by_pid"
),
kperf_timer_count_set: load_sym!(
handle,
kperf_timer_count_set,
c"kperf_timer_count_set"
),
kperf_timer_count_get: load_sym!(
handle,
kperf_timer_count_get,
c"kperf_timer_count_get"
),
kperf_timer_period_set: load_sym!(
handle,
kperf_timer_period_set,
c"kperf_timer_period_set"
),
kperf_timer_period_get: load_sym!(
handle,
kperf_timer_period_get,
c"kperf_timer_period_get"
),
kperf_timer_action_set: load_sym!(
handle,
kperf_timer_action_set,
c"kperf_timer_action_set"
),
kperf_timer_action_get: load_sym!(
handle,
kperf_timer_action_get,
c"kperf_timer_action_get"
),
kperf_timer_pet_set: load_sym!(handle, kperf_timer_pet_set, c"kperf_timer_pet_set"),
kperf_timer_pet_get: load_sym!(handle, kperf_timer_pet_get, c"kperf_timer_pet_get"),
kperf_sample_set: load_sym!(handle, kperf_sample_set, c"kperf_sample_set"),
kperf_sample_get: load_sym!(handle, kperf_sample_get, c"kperf_sample_get"),
kperf_reset: load_sym!(handle, kperf_reset, c"kperf_reset"),
kperf_ns_to_ticks: load_sym!(handle, kperf_ns_to_ticks, c"kperf_ns_to_ticks"),
kperf_ticks_to_ns: load_sym!(handle, kperf_ticks_to_ns, c"kperf_ticks_to_ns"),
kperf_tick_frequency: load_sym!(handle, kperf_tick_frequency, c"kperf_tick_frequency"),
})
}
}