1#[allow(non_camel_case_types)]
5#[allow(non_snake_case)]
6#[allow(dead_code)]
7#[allow(non_upper_case_globals)]
8#[allow(deref_nullptr)]
9mod bindings;
10pub mod counter;
11pub mod events_set;
12
13use std::os::raw::{c_int, c_ulong};
14use std::sync::atomic::{AtomicU64, Ordering};
15
16use crate::bindings::*;
17
18const fn papi_version_number(maj: u32, min: u32, rev: u32, inc: u32) -> u32 {
19 (maj << 24) | (min << 16) | (rev << 8) | inc
20}
21
22const PAPI_VERSION: u32 = papi_version_number(6, 0, 0, 1);
23const PAPI_VER_CURRENT: c_int = (PAPI_VERSION & 0xffff0000) as c_int;
24
25#[link(name = "papi")]
26extern "C" {}
27
28#[derive(Debug)]
29#[allow(dead_code)]
30pub struct PapiError {
31 code: i32,
32}
33
34pub(crate) fn check_error(code: i32) -> Result<(), PapiError> {
35 if code == (PAPI_OK as i32) {
36 Ok(())
37 } else {
38 Err(PapiError { code })
39 }
40}
41
42static THREAD_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
43
44thread_local! {
45 static THREAD_INDEX: u64 = THREAD_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
46}
47
48extern "C" fn get_thread_id() -> c_ulong {
49 THREAD_INDEX.with(|id| *id as c_ulong)
50}
51
52pub fn initialize(multithread: bool) -> Result<(), PapiError> {
53 unsafe {
54 let version = PAPI_library_init(PAPI_VER_CURRENT);
55 if version != PAPI_VER_CURRENT {
56 return Err(PapiError { code: version });
57 }
58
59 if multithread {
60 check_error(PAPI_thread_init(Some(get_thread_id)))?;
61 }
62 }
63
64 Ok(())
65}
66
67pub fn is_initialized() -> bool {
68 unsafe { check_error(PAPI_is_initialized()).is_ok() }
69}
70
71#[derive(PartialEq, Eq)]
74pub enum Action {
75 Retry,
76}
77
78#[cfg(test)]
79mod tests {
80 use crate::counter::Counter;
81 use crate::events_set::EventsSet;
82
83 #[test]
84 fn test_fib() {
85 crate::initialize(true).unwrap();
86
87 let counters = vec![
88 Counter::from_name("ix86arch::INSTRUCTION_RETIRED").unwrap(),
89 Counter::from_name("ix86arch::MISPREDICTED_BRANCH_RETIRED").unwrap(),
90 ];
91
92 let mut event_set = EventsSet::new(&counters).unwrap();
93 let mut second_set = event_set.try_clone().unwrap();
94
95 for fv in 1..45 {
96 event_set.start().unwrap();
97 second_set.start().unwrap();
98 let x = fib(fv);
99 second_set.stop().unwrap();
100 let counters = event_set.stop().unwrap();
101 println!(
102 "Computed fib({}) = {} in {} instructions [mispredicted: {}].",
103 fv, x, counters[0], counters[1]
104 );
105 }
106 }
107
108 fn fib(n: isize) -> isize {
109 if n < 2 {
110 1
111 } else {
112 fib(n - 1) + fib(n - 2)
113 }
114 }
115}