Skip to content

Commit 2478aa2

Browse files
committed
scx_rusty: add boilerplate for setting up perf counters
1 parent 90eeecb commit 2478aa2

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

scheds/rust/scx_rusty/src/bpf/main.bpf.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,18 @@ static void refresh_tune_params(void)
572572
}
573573
}
574574

575+
/*
576+
* Performance counter callback.
577+
*/
578+
579+
SEC("perf_event")
580+
int drain_counters(void *ctx)
581+
{
582+
scx_bpf_error("HIT");
583+
bpf_printk("Callback detected");
584+
return 1;
585+
}
586+
575587
static u64 min(u64 a, u64 b)
576588
{
577589
return a <= b ? a : b;

scheds/rust/scx_rusty/src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ use tuner::Tuner;
1515
pub mod load_balance;
1616
use load_balance::LoadBalancer;
1717

18+
pub mod perf;
19+
use perf::init_perf_counters;
20+
1821
mod stats;
1922
use std::collections::BTreeMap;
2023
use std::mem::MaybeUninit;
@@ -444,6 +447,10 @@ impl<'a> Scheduler<'a> {
444447

445448
// Attach.
446449
let mut skel = scx_ops_load!(skel, rusty, uei)?;
450+
451+
let (pefd, _link) = init_perf_counters(&mut skel, &0)?;
452+
println!("Got perf file descriptor {}", pefd);
453+
447454
let struct_ops = Some(scx_ops_attach!(skel, rusty)?);
448455
let stats_server = StatsServer::new(stats::server_data()).launch()?;
449456

scheds/rust/scx_rusty/src/perf.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
extern crate libc;
2+
3+
use crate::bpf_skel::*;
4+
5+
use libbpf_rs;
6+
use libbpf_rs::AsRawLibbpf;
7+
use libbpf_rs::libbpf_sys;
8+
use std::io;
9+
use std::mem;
10+
11+
// Expanded from systing's code: www.github.com/josefbacik/systing
12+
13+
const PERF_TYPE_HARDWARE: u32 = 0x0;
14+
const PERF_TYPE_SOFTWARE: u32 = 0x1;
15+
const PERF_TYPE_RAW: u32 = 0x3;
16+
const PERF_TYPE_IBS: u32 = 0xb;
17+
18+
const PERF_COUNT_HW_CPU_CYCLES: u64 = 0;
19+
const PERF_COUNT_HW_CACHE_REFERENCES: u64 = 2;
20+
const PERF_COUNT_HW_CACHE_MISSES: u64 = 3;
21+
const PERF_COUNT_HW_STALLED_CYCLES_FRONTEND: u64 = 7;
22+
const PERF_COUNT_HW_STALLED_CYCLES_BACKEND: u64 = 8;
23+
24+
const PERF_COUNT_SW_CPU_CLOCK: u64 = 0;
25+
26+
#[repr(C)]
27+
union sample_un {
28+
pub sample_period: u64,
29+
pub sample_freq: u64,
30+
}
31+
32+
#[repr(C)]
33+
union wakeup_un {
34+
pub wakeup_events: u32,
35+
pub wakeup_atermark: u32,
36+
}
37+
38+
#[repr(C)]
39+
union bp_1_un {
40+
pub bp_addr: u64,
41+
pub kprobe_func: u64,
42+
pub uprobe_path: u64,
43+
pub config1: u64,
44+
}
45+
46+
#[repr(C)]
47+
union bp_2_un {
48+
pub bp_len: u64,
49+
pub kprobe_addr: u64,
50+
pub probe_offset: u64,
51+
pub config2: u64,
52+
}
53+
54+
#[repr(C)]
55+
#[allow(non_camel_case_types)]
56+
struct perf_event_attr {
57+
pub _type: u32,
58+
pub size: u32,
59+
pub config: u64,
60+
pub sample: sample_un,
61+
pub sample_type: u64,
62+
pub read_format: u64,
63+
pub flags: u64,
64+
pub wakeup: wakeup_un,
65+
pub bp_type: u32,
66+
pub bp_1: bp_1_un,
67+
pub bp_2: bp_2_un,
68+
pub branch_sample_type: u64,
69+
pub sample_regs_user: u64,
70+
pub sample_stack_user: u32,
71+
pub clockid: i32,
72+
pub sample_regs_intr: u64,
73+
pub aux_watermark: u32,
74+
pub sample_max_stack: u16,
75+
pub __reserved_2: u16,
76+
pub aux_sample_size: u32,
77+
pub __reserved_3: u32,
78+
}
79+
80+
extern "C" {
81+
fn syscall(number: libc::c_long, ...) -> libc::c_long;
82+
}
83+
84+
fn perf_event_open(
85+
hw_event: &perf_event_attr,
86+
pid: libc::pid_t,
87+
cpu: libc::c_int,
88+
group_fd: libc::c_int,
89+
flags: libc::c_ulong,
90+
) -> libc::c_long {
91+
unsafe {
92+
syscall(
93+
libc::SYS_perf_event_open,
94+
hw_event as *const perf_event_attr,
95+
pid,
96+
cpu,
97+
group_fd,
98+
flags,
99+
)
100+
}
101+
}
102+
103+
// XXXETSAL: Comment below is taken verbatim from the original systing code
104+
// We're just doing this until the libbpf-rs crate gets updated with my patch.
105+
trait LibbpfPerfOptions {
106+
fn attach_perf_event_with_opts(
107+
&self,
108+
pefd: i32,
109+
) -> Result<libbpf_rs::Link, libbpf_rs::Error>;
110+
}
111+
112+
impl LibbpfPerfOptions for libbpf_rs::ProgramMut<'_> {
113+
fn attach_perf_event_with_opts(
114+
&self,
115+
pefd: i32,
116+
) -> Result<libbpf_rs::Link, libbpf_rs::Error> {
117+
let mut opts = libbpf_sys::bpf_perf_event_opts::default();
118+
opts.bpf_cookie = 0;
119+
opts.sz = mem::size_of::<libbpf_sys::bpf_perf_event_opts>() as u64;
120+
let ptr = unsafe {
121+
libbpf_sys::bpf_program__attach_perf_event_opts(
122+
self.as_libbpf_object().as_ptr(),
123+
pefd,
124+
&opts as *const _ as *const _,
125+
)
126+
};
127+
let ret = unsafe { libbpf_sys::libbpf_get_error(ptr as *const _) };
128+
if ret != 0 {
129+
return Err(libbpf_rs::Error::from_raw_os_error(-ret as i32));
130+
}
131+
let ptr = unsafe { std::ptr::NonNull::new_unchecked(ptr) };
132+
let link = unsafe { libbpf_rs::Link::from_ptr(ptr) };
133+
Ok(link)
134+
}
135+
}
136+
pub fn init_perf_counters(skel: &mut BpfSkel, cpu: &i32) -> Result<(i32, libbpf_rs::Link), libbpf_rs::Error> {
137+
let buf: Vec<u8> = vec![0; mem::size_of::<perf_event_attr>()];
138+
let mut attr = unsafe {
139+
Box::<perf_event_attr>::from_raw(
140+
buf.leak().as_mut_ptr() as *mut perf_event_attr
141+
)
142+
};
143+
144+
attr._type = PERF_TYPE_HARDWARE;
145+
attr.size = mem::size_of::<perf_event_attr>() as u32;
146+
attr.config = PERF_COUNT_HW_CPU_CYCLES;
147+
attr.sample.sample_period = 1000;
148+
attr.flags = 0;
149+
150+
let pefd = perf_event_open(attr.as_ref(), -1, *cpu, -1, 0) as i32;
151+
if pefd == -1 {
152+
let os_error = io::Error::last_os_error();
153+
return Err(libbpf_rs::Error::from(os_error));
154+
}
155+
156+
let link = skel.progs.drain_counters.attach_perf_event_with_opts(pefd);
157+
158+
Ok((pefd, link?))
159+
}

0 commit comments

Comments
 (0)