| pub mod ffi; |
| |
| use std::ffi::CString; |
| use std::os::raw::c_char; |
| use std::pin::Pin; |
| |
| pub struct State<'a> { |
| #[doc(hidden)] |
| pub inner: Pin<&'a mut ffi::ffi::State>, |
| } |
| |
| impl<'a> State<'a> { |
| /// Returns true if the benchmark should continue running. |
| /// |
| /// **Note:** `keep_running()` currently has a small per-iteration overhead due to the FFI boundary. |
| /// In the future, this could be optimized using `KeepRunningBatch` under the hood. |
| #[inline] |
| pub fn keep_running(&mut self) -> bool { |
| self.inner.as_mut().KeepRunning() |
| } |
| |
| pub fn skip_with_error(&mut self, msg: &str) { |
| unsafe { |
| ffi::ffi::SkipWithError(self.inner.as_mut(), msg); |
| } |
| } |
| } |
| |
| /// Initialize the benchmark library. |
| /// This should be called before `run_specified_benchmarks`. |
| pub fn initialize(args: &Vec<String>) { |
| let mut c_args: Vec<CString> = args.iter() |
| .map(|arg| CString::new(arg.as_str()).unwrap()) |
| .collect(); |
| |
| let mut c_ptrs: Vec<*mut c_char> = c_args.iter_mut() |
| .map(|c| c.as_ptr() as *mut c_char) |
| .collect(); |
| |
| let mut argc = c_ptrs.len() as i32; |
| let argv = c_ptrs.as_mut_ptr(); |
| |
| unsafe { |
| ffi::ffi::Initialize(&mut argc as *mut _, argv as usize); |
| } |
| } |
| |
| #[macro_export] |
| macro_rules! register_benchmark { |
| ($name:expr, $func:path) => { |
| { |
| fn trampoline(mut state: std::pin::Pin<&mut $crate::ffi::ffi::State>) { |
| let mut wrapped = $crate::State { inner: state.as_mut() }; |
| $func(&mut wrapped); |
| } |
| unsafe { |
| $crate::ffi::ffi::RegisterBenchmark($name, trampoline); |
| } |
| } |
| }; |
| } |
| |
| /// Run all registered benchmarks. |
| pub fn run_specified_benchmarks() -> usize { |
| ffi::ffi::RunSpecifiedBenchmarks() |
| } |