cpu_instructions_reader/
lib.rs

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