#![expect(non_camel_case_types)]
use core::{
ffi::{c_char, c_int, c_void},
fmt,
};
use crate::{
kperf::kpc_config_t,
load::{LibraryHandle, LibrarySymbol, LoadError},
};
pub const KPEP_ARCH_I386: u32 = 0;
pub const KPEP_ARCH_X86_64: u32 = 1;
pub const KPEP_ARCH_ARM: u32 = 2;
pub const KPEP_ARCH_ARM64: u32 = 3;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct kpep_event {
pub name: *const c_char,
pub description: *const c_char,
pub errata: *const c_char,
pub alias: *const c_char,
pub fallback: *const c_char,
pub mask: u32,
pub number: u16,
pub umask: u8,
_pad0: u8,
pub flags: u8,
_pad1: [u8; 7],
}
const _: () = {
assert!(core::mem::size_of::<kpep_event>() == 56);
assert!(core::mem::align_of::<kpep_event>() == 8);
assert!(core::mem::offset_of!(kpep_event, name) == 0);
assert!(core::mem::offset_of!(kpep_event, description) == 8);
assert!(core::mem::offset_of!(kpep_event, errata) == 16);
assert!(core::mem::offset_of!(kpep_event, alias) == 24);
assert!(core::mem::offset_of!(kpep_event, fallback) == 32);
assert!(core::mem::offset_of!(kpep_event, mask) == 40);
assert!(core::mem::offset_of!(kpep_event, number) == 44);
assert!(core::mem::offset_of!(kpep_event, umask) == 46);
assert!(core::mem::offset_of!(kpep_event, flags) == 48);
};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct kpep_db {
pub name: *const c_char,
pub cpu_id: *const c_char,
pub marketing_name: *const c_char,
pub plist_data: *mut c_void,
pub event_map: *mut c_void,
pub event_arr: *mut kpep_event,
pub fixed_event_arr: *mut *mut kpep_event,
pub alias_map: *mut c_void,
_reserved0: usize,
_reserved1: usize,
_reserved2: usize,
pub event_count: usize,
pub alias_count: usize,
pub fixed_counter_count: usize,
pub config_counter_count: usize,
pub power_counter_count: usize,
pub archtecture: u32,
pub fixed_counter_bits: u32,
pub config_counter_bits: u32,
pub power_counter_bits: u32,
pub create_flags: u32,
pub is_internal: u8,
pub internal_known: u8,
_pad: [u8; 2],
}
const _: () = {
assert!(core::mem::size_of::<kpep_db>() == 152);
assert!(core::mem::align_of::<kpep_db>() == 8);
assert!(core::mem::offset_of!(kpep_db, name) == 0);
assert!(core::mem::offset_of!(kpep_db, cpu_id) == 8);
assert!(core::mem::offset_of!(kpep_db, marketing_name) == 16);
assert!(core::mem::offset_of!(kpep_db, plist_data) == 24);
assert!(core::mem::offset_of!(kpep_db, event_map) == 32);
assert!(core::mem::offset_of!(kpep_db, event_arr) == 40);
assert!(core::mem::offset_of!(kpep_db, fixed_event_arr) == 48);
assert!(core::mem::offset_of!(kpep_db, alias_map) == 56);
assert!(core::mem::offset_of!(kpep_db, event_count) == 88);
assert!(core::mem::offset_of!(kpep_db, alias_count) == 96);
assert!(core::mem::offset_of!(kpep_db, fixed_counter_count) == 104);
assert!(core::mem::offset_of!(kpep_db, config_counter_count) == 112);
assert!(core::mem::offset_of!(kpep_db, power_counter_count) == 120);
assert!(core::mem::offset_of!(kpep_db, archtecture) == 128);
assert!(core::mem::offset_of!(kpep_db, fixed_counter_bits) == 132);
assert!(core::mem::offset_of!(kpep_db, config_counter_bits) == 136);
assert!(core::mem::offset_of!(kpep_db, power_counter_bits) == 140);
assert!(core::mem::offset_of!(kpep_db, create_flags) == 144);
assert!(core::mem::offset_of!(kpep_db, is_internal) == 148);
assert!(core::mem::offset_of!(kpep_db, internal_known) == 149);
};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct kpep_config {
pub db: *mut kpep_db,
pub events: *mut *mut kpep_event,
pub event_map: *mut usize,
pub event_indices: *mut usize,
pub flags: *mut u32,
pub kpc_periods: *mut u64,
pub event_count: usize,
pub counter_count: usize,
pub classes: u32,
pub occupied_counters: u32,
pub force_flags: u8,
_pad: [u8; 7],
}
const _: () = {
assert!(core::mem::size_of::<kpep_config>() == 80);
assert!(core::mem::align_of::<kpep_config>() == 8);
assert!(core::mem::offset_of!(kpep_config, db) == 0);
assert!(core::mem::offset_of!(kpep_config, events) == 8);
assert!(core::mem::offset_of!(kpep_config, event_map) == 16);
assert!(core::mem::offset_of!(kpep_config, event_indices) == 24);
assert!(core::mem::offset_of!(kpep_config, flags) == 32);
assert!(core::mem::offset_of!(kpep_config, kpc_periods) == 40);
assert!(core::mem::offset_of!(kpep_config, event_count) == 48);
assert!(core::mem::offset_of!(kpep_config, counter_count) == 56);
assert!(core::mem::offset_of!(kpep_config, classes) == 64);
assert!(core::mem::offset_of!(kpep_config, occupied_counters) == 68);
assert!(core::mem::offset_of!(kpep_config, force_flags) == 72);
};
pub const KPEP_CONFIG_ERROR_NONE: c_int = 0;
pub const KPEP_CONFIG_ERROR_INVALID_ARGUMENT: c_int = 1;
pub const KPEP_CONFIG_ERROR_OUT_OF_MEMORY: c_int = 2;
pub const KPEP_CONFIG_ERROR_IO: c_int = 3;
pub const KPEP_CONFIG_ERROR_BUFFER_TOO_SMALL: c_int = 4;
pub const KPEP_CONFIG_ERROR_CUR_SYSTEM_UNKNOWN: c_int = 5;
pub const KPEP_CONFIG_ERROR_DB_PATH_INVALID: c_int = 6;
pub const KPEP_CONFIG_ERROR_DB_NOT_FOUND: c_int = 7;
pub const KPEP_CONFIG_ERROR_DB_ARCH_UNSUPPORTED: c_int = 8;
pub const KPEP_CONFIG_ERROR_DB_VERSION_UNSUPPORTED: c_int = 9;
pub const KPEP_CONFIG_ERROR_DB_CORRUPT: c_int = 10;
pub const KPEP_CONFIG_ERROR_EVENT_NOT_FOUND: c_int = 11;
pub const KPEP_CONFIG_ERROR_CONFLICTING_EVENTS: c_int = 12;
pub const KPEP_CONFIG_ERROR_COUNTERS_NOT_FORCED: c_int = 13;
pub const KPEP_CONFIG_ERROR_EVENT_UNAVAILABLE: c_int = 14;
pub const KPEP_CONFIG_ERROR_ERRNO: c_int = 15;
pub type kpep_config_create =
unsafe extern "C" fn(db: *mut kpep_db, cfg_ptr: *mut *mut kpep_config) -> c_int;
pub type kpep_config_free = unsafe extern "C" fn(cfg: *mut kpep_config);
pub type kpep_config_add_event = unsafe extern "C" fn(
cfg: *mut kpep_config,
ev_ptr: *mut *mut kpep_event,
flag: u32,
err: *mut u32,
) -> c_int;
pub type kpep_config_remove_event =
unsafe extern "C" fn(cfg: *mut kpep_config, idx: usize) -> c_int;
pub type kpep_config_force_counters = unsafe extern "C" fn(cfg: *mut kpep_config) -> c_int;
pub type kpep_config_events_count =
unsafe extern "C" fn(cfg: *mut kpep_config, count_ptr: *mut usize) -> c_int;
pub type kpep_config_events = unsafe extern "C" fn(
cfg: *mut kpep_config,
buf: *mut *mut kpep_event,
buf_size: usize,
) -> c_int;
pub type kpep_config_kpc =
unsafe extern "C" fn(cfg: *mut kpep_config, buf: *mut kpc_config_t, buf_size: usize) -> c_int;
pub type kpep_config_kpc_count =
unsafe extern "C" fn(cfg: *mut kpep_config, count_ptr: *mut usize) -> c_int;
pub type kpep_config_kpc_classes =
unsafe extern "C" fn(cfg: *mut kpep_config, classes_ptr: *mut u32) -> c_int;
pub type kpep_config_kpc_map =
unsafe extern "C" fn(cfg: *mut kpep_config, buf: *mut usize, buf_size: usize) -> c_int;
pub type kpep_db_create =
unsafe extern "C" fn(name: *const c_char, db_ptr: *mut *mut kpep_db) -> c_int;
pub type kpep_db_free = unsafe extern "C" fn(db: *mut kpep_db);
pub type kpep_db_name = unsafe extern "C" fn(db: *mut kpep_db, name: *mut *const c_char) -> c_int;
pub type kpep_db_aliases_count = unsafe extern "C" fn(db: *mut kpep_db, count: *mut usize) -> c_int;
pub type kpep_db_aliases =
unsafe extern "C" fn(db: *mut kpep_db, buf: *mut *const c_char, buf_size: usize) -> c_int;
pub type kpep_db_counters_count =
unsafe extern "C" fn(db: *mut kpep_db, classes: u8, count: *mut usize) -> c_int;
pub type kpep_db_events_count = unsafe extern "C" fn(db: *mut kpep_db, count: *mut usize) -> c_int;
pub type kpep_db_events =
unsafe extern "C" fn(db: *mut kpep_db, buf: *mut *mut kpep_event, buf_size: usize) -> c_int;
pub type kpep_db_event = unsafe extern "C" fn(
db: *mut kpep_db,
name: *const c_char,
ev_ptr: *mut *mut kpep_event,
) -> c_int;
pub type kpep_event_name =
unsafe extern "C" fn(ev: *mut kpep_event, name_ptr: *mut *const c_char) -> c_int;
pub type kpep_event_alias =
unsafe extern "C" fn(ev: *mut kpep_event, alias_ptr: *mut *const c_char) -> c_int;
pub type kpep_event_description =
unsafe extern "C" fn(ev: *mut kpep_event, str_ptr: *mut *const c_char) -> c_int;
macro_rules! load_sym {
($handle:expr, $name:ident, $cname:expr) => {{
unsafe { core::mem::transmute::<LibrarySymbol, $name>($handle.symbol($cname)?) }
}};
}
#[expect(clippy::struct_field_names)]
pub struct VTable {
pub kpep_config_create: kpep_config_create,
pub kpep_config_free: kpep_config_free,
pub kpep_config_add_event: kpep_config_add_event,
pub kpep_config_remove_event: kpep_config_remove_event,
pub kpep_config_force_counters: kpep_config_force_counters,
pub kpep_config_events_count: kpep_config_events_count,
pub kpep_config_events: kpep_config_events,
pub kpep_config_kpc: kpep_config_kpc,
pub kpep_config_kpc_count: kpep_config_kpc_count,
pub kpep_config_kpc_classes: kpep_config_kpc_classes,
pub kpep_config_kpc_map: kpep_config_kpc_map,
pub kpep_db_create: kpep_db_create,
pub kpep_db_free: kpep_db_free,
pub kpep_db_name: kpep_db_name,
pub kpep_db_aliases_count: kpep_db_aliases_count,
pub kpep_db_aliases: kpep_db_aliases,
pub kpep_db_counters_count: kpep_db_counters_count,
pub kpep_db_events_count: kpep_db_events_count,
pub kpep_db_events: kpep_db_events,
pub kpep_db_event: kpep_db_event,
pub kpep_event_name: kpep_event_name,
pub kpep_event_alias: kpep_event_alias,
pub kpep_event_description: kpep_event_description,
}
impl fmt::Debug for VTable {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("VTable").finish_non_exhaustive()
}
}
impl VTable {
pub fn load(handle: &LibraryHandle) -> Result<Self, LoadError> {
Ok(Self {
kpep_config_create: load_sym!(handle, kpep_config_create, c"kpep_config_create"),
kpep_config_free: load_sym!(handle, kpep_config_free, c"kpep_config_free"),
kpep_config_add_event: load_sym!(
handle,
kpep_config_add_event,
c"kpep_config_add_event"
),
kpep_config_remove_event: load_sym!(
handle,
kpep_config_remove_event,
c"kpep_config_remove_event"
),
kpep_config_force_counters: load_sym!(
handle,
kpep_config_force_counters,
c"kpep_config_force_counters"
),
kpep_config_events_count: load_sym!(
handle,
kpep_config_events_count,
c"kpep_config_events_count"
),
kpep_config_events: load_sym!(handle, kpep_config_events, c"kpep_config_events"),
kpep_config_kpc: load_sym!(handle, kpep_config_kpc, c"kpep_config_kpc"),
kpep_config_kpc_count: load_sym!(
handle,
kpep_config_kpc_count,
c"kpep_config_kpc_count"
),
kpep_config_kpc_classes: load_sym!(
handle,
kpep_config_kpc_classes,
c"kpep_config_kpc_classes"
),
kpep_config_kpc_map: load_sym!(handle, kpep_config_kpc_map, c"kpep_config_kpc_map"),
kpep_db_create: load_sym!(handle, kpep_db_create, c"kpep_db_create"),
kpep_db_free: load_sym!(handle, kpep_db_free, c"kpep_db_free"),
kpep_db_name: load_sym!(handle, kpep_db_name, c"kpep_db_name"),
kpep_db_aliases_count: load_sym!(
handle,
kpep_db_aliases_count,
c"kpep_db_aliases_count"
),
kpep_db_aliases: load_sym!(handle, kpep_db_aliases, c"kpep_db_aliases"),
kpep_db_counters_count: load_sym!(
handle,
kpep_db_counters_count,
c"kpep_db_counters_count"
),
kpep_db_events_count: load_sym!(handle, kpep_db_events_count, c"kpep_db_events_count"),
kpep_db_events: load_sym!(handle, kpep_db_events, c"kpep_db_events"),
kpep_db_event: load_sym!(handle, kpep_db_event, c"kpep_db_event"),
kpep_event_name: load_sym!(handle, kpep_event_name, c"kpep_event_name"),
kpep_event_alias: load_sym!(handle, kpep_event_alias, c"kpep_event_alias"),
kpep_event_description: load_sym!(
handle,
kpep_event_description,
c"kpep_event_description"
),
})
}
}