Skip to content

Commit a3c9be7

Browse files
authored
Merge pull request #1737 from frelon/bindgen-perf-event
scx_utils, scxtop: Bindgen perf event
2 parents e96677c + 9203e0f commit a3c9be7

File tree

7 files changed

+105
-17
lines changed

7 files changed

+105
-17
lines changed

Cargo.lock

Lines changed: 0 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/scx_utils/build.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,17 @@ fn main() {
1414
.cargo_target_triple()
1515
.emit()
1616
.unwrap();
17+
18+
let bindings = bindgen::Builder::default()
19+
.header("perf_wrapper.h")
20+
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
21+
.prepend_enum_name(false)
22+
.derive_default(true)
23+
.generate()
24+
.expect("Unable to generate bindings");
25+
26+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
27+
bindings
28+
.write_to_file(out_path.join("perf_bindings.rs"))
29+
.expect("Couldn't write bindings!");
1730
}

rust/scx_utils/perf_wrapper.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// This file is consumed by bindgen, called from our build.rs file.
2+
3+
#include <linux/perf_event.h>
4+
5+
// for __NR_perf_event_open
6+
#include <asm/unistd.h>
7+
#include <asm/perf_regs.h>
8+
9+
// bindgen won't capture preprocessor macro definitions, so we have to do this.
10+
enum perf_event_ioctls {
11+
ENABLE = PERF_EVENT_IOC_ENABLE,
12+
DISABLE = PERF_EVENT_IOC_DISABLE,
13+
REFRESH = PERF_EVENT_IOC_REFRESH,
14+
RESET = PERF_EVENT_IOC_RESET,
15+
PERIOD = PERF_EVENT_IOC_PERIOD,
16+
SET_OUTPUT = PERF_EVENT_IOC_SET_OUTPUT,
17+
SET_FILTER = PERF_EVENT_IOC_SET_FILTER,
18+
ID = PERF_EVENT_IOC_ID,
19+
SET_BPF = PERF_EVENT_IOC_SET_BPF,
20+
PAUSE_OUTPUT = PERF_EVENT_IOC_PAUSE_OUTPUT,
21+
QUERY_BPF = PERF_EVENT_IOC_QUERY_BPF,
22+
MODIFY_ATTRIBUTES = PERF_EVENT_IOC_MODIFY_ATTRIBUTES,
23+
};

rust/scx_utils/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,5 @@ pub use enums::scx_enums;
104104

105105
#[cfg(feature = "autopower")]
106106
pub mod autopower;
107+
108+
pub mod perf;

rust/scx_utils/src/perf.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#![allow(non_upper_case_globals)]
2+
#![allow(non_camel_case_types)]
3+
#![allow(non_snake_case)]
4+
5+
use libc::pid_t;
6+
use std::os::raw::{c_int, c_ulong};
7+
8+
/// The `perf_event_open` system call.
9+
///
10+
/// See the [`perf_event_open(2) man page`][man] for details.
11+
///
12+
/// On error, this returns -1, and the C `errno` value (accessible via
13+
/// `std::io::Error::last_os_error`) is set to indicate the error.
14+
///
15+
/// Note: The `attrs` argument needs to be a `*mut` because if the `size` field
16+
/// is too small or too large, the kernel writes the size it was expecing back
17+
/// into that field. It might do other things as well.
18+
///
19+
/// # Safety
20+
///
21+
/// The `attrs` argument must point to a properly initialized
22+
/// `perf_event_attr` struct. The measurements and other behaviors its
23+
/// contents request must be safe.
24+
///
25+
/// [man]: https://www.mankier.com/2/perf_event_open
26+
pub unsafe fn perf_event_open(
27+
attrs: *mut bindings::perf_event_attr,
28+
pid: pid_t,
29+
cpu: c_int,
30+
group_fd: c_int,
31+
flags: c_ulong,
32+
) -> c_int {
33+
libc::syscall(
34+
bindings::__NR_perf_event_open as libc::c_long,
35+
attrs as *const bindings::perf_event_attr,
36+
pid,
37+
cpu,
38+
group_fd,
39+
flags,
40+
) as c_int
41+
}
42+
43+
pub mod bindings {
44+
include!(concat!(env!("OUT_DIR"), "/perf_bindings.rs"));
45+
}
46+
47+
pub mod ioctls {
48+
use crate::perf;
49+
use std::os::raw::{c_int, c_uint};
50+
51+
#[allow(clippy::missing_safety_doc)]
52+
pub unsafe fn enable(fd: c_int, arg: c_uint) -> c_int {
53+
libc::ioctl(fd, perf::bindings::ENABLE.into(), arg)
54+
}
55+
56+
#[allow(clippy::missing_safety_doc)]
57+
pub unsafe fn reset(fd: c_int, arg: c_uint) -> c_int {
58+
libc::ioctl(fd, perf::bindings::ENABLE.into(), arg)
59+
}
60+
}

tools/scxtop/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ libbpf-rs = "=0.25.0-beta.1"
3333
libc = "0.2.137"
3434
log = "0.4.17"
3535
num-format = { version = "0.4.3", features = ["with-serde", "with-system-locale"] }
36-
perf-event-open-sys2 = "5.0.6"
3736
plain = "0.2.3"
3837
prost = "0.13.5"
3938
rand = "0.8.5"

tools/scxtop/src/perf_event.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use anyhow::anyhow;
99
use anyhow::Context;
1010
use anyhow::Result;
1111
use libc::{close, read};
12-
use perf_event_open_sys as perf;
1312
use scx_utils::compat::tracefs_mount;
13+
use scx_utils::perf;
1414

1515
use std::collections::{BTreeMap, HashSet};
1616
use std::fs;
@@ -160,8 +160,10 @@ impl PerfEvent {
160160

161161
/// Attaches a PerfEvent struct.
162162
pub fn attach(&mut self, process_id: i32) -> Result<()> {
163-
let mut attrs = perf::bindings::perf_event_attr::default();
164-
attrs.size = std::mem::size_of::<perf::bindings::perf_event_attr>() as u32;
163+
let mut attrs = scx_utils::perf::bindings::perf_event_attr {
164+
size: std::mem::size_of::<perf::bindings::perf_event_attr>() as u32,
165+
..Default::default()
166+
};
165167

166168
match self.subsystem.to_lowercase().as_str() {
167169
"hw" | "hardware" => {
@@ -260,7 +262,7 @@ impl PerfEvent {
260262
}
261263

262264
unsafe {
263-
if perf::ioctls::ENABLE(result, 0) < 0 {
265+
if perf::ioctls::enable(result, 0) < 0 {
264266
return Err(anyhow!("failed to enable perf event: {}", self.event));
265267
}
266268
}
@@ -282,7 +284,7 @@ impl PerfEvent {
282284
{
283285
return Err(anyhow!("failed to read perf event {:?}", self));
284286
}
285-
if reset && perf::ioctls::RESET(self.fd as i32, 0) < 0 {
287+
if reset && perf::ioctls::reset(self.fd as i32, 0) < 0 {
286288
return Err(anyhow!("failed to reset perf event: {}", self.event));
287289
}
288290
}

0 commit comments

Comments
 (0)