1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
//! This is only for reading `CpuInstructionNumber` specialization, not a complete package of [perf_event_read](https://www.man7.org/linux/man-pages/man2/perf_event_open.2.html)
//!
//! Example:
//! ```ignore
//! use std::{fs, time::{Duration, Instant}, thread};
//! use cpu_instructions_reader::{InstructionNumber, InstructionNumberReader, InstructionNumberInstant};
//!
//! let reader = InstructionNumberReader::new().unwrap();
//! let record_1 = reader.instant(0).unwrap();
//!
//! thread::sleep(Duration::from_secs(1));
//!
//! let record_2 = reader.instant(0).unwrap();
//! let instructions = record_2 - record_1;
//!
//! println!("{instructions}");
//! ```
#![deny(clippy::all, clippy::pedantic)]
#![warn(clippy::nursery, clippy::cargo)]
#![allow(clippy::missing_panics_doc, clippy::module_name_repetitions)]
#![cfg(any(target_os = "linux", target_os = "android"))]
mod instruction_number;
mod error;
pub mod ffi;
mod instant;
use std::ptr;
use ffi::InstructionNumberReaderRaw;
use libc::{c_int, pid_t};
pub use instruction_number::InstructionNumber;
pub use error::{Error, Result};
pub use instant::InstructionNumberInstant;
#[derive(Debug)]
pub struct InstructionNumberReader {
raw_ptr: *mut InstructionNumberReaderRaw,
}
impl Drop for InstructionNumberReader {
fn drop(&mut self) {
unsafe {
ffi::disableInstructionNumberReader(self.raw_ptr);
ffi::destroyInstructionNumberReader(self.raw_ptr);
}
self.raw_ptr = ptr::null_mut();
}
}
impl InstructionNumberReader {
/// pid: This measures the specified process/thread on any CPU. Set to `None` if measures all processes/threads on any cpu is wanted.
///
/// # Errors
///
/// If there is an error when calling the syscall, it will return an error
pub fn new(pid: Option<pid_t>) -> Result<Self> {
let cpus = c_int::try_from(num_cpus::get_physical())?;
let cpus: Vec<_> = (0..cpus).collect();
let cpus_ptr = cpus.as_ptr();
let raw_ptr = unsafe {
let ptr = ffi::createInstructionNumberReader(cpus_ptr, cpus.len(), pid.unwrap_or(-1));
ffi::enableInstructionNumberReader(ptr);
ptr
};
if raw_ptr.is_null() {
return Err(Error::FailedToCreate);
}
Ok(Self { raw_ptr })
}
/// # Errors
///
/// If there is an error when calling the syscall, it will return an error
pub fn instant(&self, cpu: c_int) -> Result<InstructionNumberInstant> {
let raw = unsafe { ffi::readInstructionNumberReader(self.raw_ptr, cpu) };
if raw == -1 {
Err(Error::FailedToRead)
} else {
let instructions = InstructionNumber::new(raw);
let instant = InstructionNumberInstant::new(cpu, instructions);
Ok(instant)
}
}
}