Skip to content

Commit f56138a

Browse files
flearcdanielocfb
authored andcommitted
examples/profile: add --sw-event option for software events
A new command line option (`--sw-event`) to address the ENOENT error that occurs when hardware events are unavailable. This can be useful when running the profile example in a virtual machine. Signed-off-by: fl <[email protected]>
1 parent 0976e45 commit f56138a

File tree

3 files changed

+52
-12
lines changed

3 files changed

+52
-12
lines changed

examples/c/profile.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <assert.h>
44
#include <stdint.h>
55
#include <stdio.h>
6+
#include <getopt.h>
67
#include <unistd.h>
78
#include <string.h>
89
#include <fcntl.h>
@@ -133,13 +134,17 @@ static int event_handler(void *_ctx, void *data, size_t size)
133134

134135
static void show_help(const char *progname)
135136
{
136-
printf("Usage: %s [-f <frequency>] [-h]\n", progname);
137+
printf("Usage: %s [-f <frequency>] [--sw-event] [-h]\n", progname);
138+
printf("Options:\n");
139+
printf(" -f <frequency> Sampling frequency [default: 1]\n");
140+
printf(" --sw-event Use software event for triggering stack trace capture\n");
141+
printf(" -h Print help\n");
137142
}
138143

139144
int main(int argc, char *const argv[])
140145
{
141146
const char *online_cpus_file = "/sys/devices/system/cpu/online";
142-
int freq = 1, pid = -1, cpu;
147+
int freq = 1, sw_event = 0, pid = -1, cpu;
143148
struct profile_bpf *skel = NULL;
144149
struct perf_event_attr attr;
145150
struct bpf_link **links = NULL;
@@ -149,13 +154,21 @@ int main(int argc, char *const argv[])
149154
int argp, i, err = 0;
150155
bool *online_mask = NULL;
151156

152-
while ((argp = getopt(argc, argv, "hf:")) != -1) {
157+
static struct option long_options[] = {
158+
{"sw-event", no_argument, 0, 's'},
159+
{0, 0, 0, 0}
160+
};
161+
162+
while ((argp = getopt_long(argc, argv, "hf:", long_options, NULL)) != -1) {
153163
switch (argp) {
154164
case 'f':
155165
freq = atoi(optarg);
156166
if (freq < 1)
157167
freq = 1;
158168
break;
169+
case 's':
170+
sw_event = 1;
171+
break;
159172

160173
case 'h':
161174
default:
@@ -206,9 +219,9 @@ int main(int argc, char *const argv[])
206219
links = calloc(num_cpus, sizeof(struct bpf_link *));
207220

208221
memset(&attr, 0, sizeof(attr));
209-
attr.type = PERF_TYPE_HARDWARE;
222+
attr.type = sw_event ? PERF_TYPE_SOFTWARE : PERF_TYPE_HARDWARE;
210223
attr.size = sizeof(attr);
211-
attr.config = PERF_COUNT_HW_CPU_CYCLES;
224+
attr.config = sw_event ? PERF_COUNT_SW_CPU_CLOCK : PERF_COUNT_HW_CPU_CYCLES;
212225
attr.sample_freq = freq;
213226
attr.freq = 1;
214227

@@ -220,7 +233,13 @@ int main(int argc, char *const argv[])
220233
/* Set up performance monitoring on a CPU/Core */
221234
pefd = perf_event_open(&attr, pid, cpu, -1, PERF_FLAG_FD_CLOEXEC);
222235
if (pefd < 0) {
223-
fprintf(stderr, "Fail to set up performance monitor on a CPU/Core\n");
236+
if (!sw_event && errno == ENOENT) {
237+
fprintf(stderr,
238+
"Fail to set up performance monitor on a CPU/Core.\n"
239+
"Try running the profile example with the `--sw-event` option.\n");
240+
} else {
241+
fprintf(stderr, "Fail to set up performance monitor on a CPU/Core.\n");
242+
}
224243
err = -1;
225244
goto cleanup;
226245
}

examples/rust/profile/src/main.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ struct stacktrace_event {
4343
ustack: [u64; MAX_STACK_DEPTH],
4444
}
4545

46-
fn init_perf_monitor(freq: u64) -> Result<Vec<i32>, libbpf_rs::Error> {
46+
fn init_perf_monitor(freq: u64, sw_event: bool) -> Result<Vec<i32>, libbpf_rs::Error> {
4747
let nprocs = libbpf_rs::num_possible_cpus().unwrap();
4848
let pid = -1;
4949
let buf: Vec<u8> = vec![0; mem::size_of::<syscall::perf_event_attr>()];
@@ -52,17 +52,30 @@ fn init_perf_monitor(freq: u64) -> Result<Vec<i32>, libbpf_rs::Error> {
5252
buf.leak().as_mut_ptr() as *mut syscall::perf_event_attr
5353
)
5454
};
55-
attr._type = syscall::PERF_TYPE_HARDWARE;
55+
attr._type = if sw_event {
56+
syscall::PERF_TYPE_SOFTWARE
57+
} else {
58+
syscall::PERF_TYPE_HARDWARE
59+
};
5660
attr.size = mem::size_of::<syscall::perf_event_attr>() as u32;
57-
attr.config = syscall::PERF_COUNT_HW_CPU_CYCLES;
61+
attr.config = if sw_event {
62+
syscall::PERF_COUNT_SW_CPU_CLOCK
63+
} else {
64+
syscall::PERF_COUNT_HW_CPU_CYCLES
65+
};
5866
attr.sample.sample_freq = freq;
5967
attr.flags = 1 << 10; // freq = 1
6068
(0..nprocs)
6169
.map(|cpu| {
6270
let fd = syscall::perf_event_open(attr.as_ref(), pid, cpu as i32, -1, 0) as i32;
6371
if fd == -1 {
64-
Err(libbpf_rs::Error::from(io::Error::last_os_error()))
65-
.context("failed to open perf event")
72+
let mut error_context = "Failed to open perf event.";
73+
let os_error = io::Error::last_os_error();
74+
if !sw_event && os_error.kind() == io::ErrorKind::NotFound {
75+
error_context = "Failed to open perf event.\n\
76+
Try running the profile example with the `--sw-event` option.";
77+
}
78+
Err(libbpf_rs::Error::from(os_error)).context(error_context)
6679
} else {
6780
Ok(fd)
6881
}
@@ -224,6 +237,12 @@ struct Args {
224237
/// Increase verbosity (can be supplied multiple times).
225238
#[arg(short = 'v', long = "verbose", global = true, action = ArgAction::Count)]
226239
verbosity: u8,
240+
/// Use software event for triggering stack trace capture.
241+
///
242+
/// This can be useful for compatibility reasons if hardware event is not available
243+
/// (which could happen in a virtual machine, for example).
244+
#[arg(long = "sw-event")]
245+
sw_event: bool,
227246
}
228247

229248
fn main() -> Result<(), libbpf_rs::Error> {
@@ -251,7 +270,7 @@ fn main() -> Result<(), libbpf_rs::Error> {
251270
let open_skel = skel_builder.open(&mut open_object).unwrap();
252271
let skel = open_skel.load().unwrap();
253272

254-
let pefds = init_perf_monitor(freq)?;
273+
let pefds = init_perf_monitor(freq, args.sw_event)?;
255274
let _links = attach_perf_event(&pefds, &skel.progs.profile);
256275

257276
let mut builder = libbpf_rs::RingBufferBuilder::new();

examples/rust/profile/src/syscall.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ pub struct perf_event_attr {
5454
}
5555

5656
pub const PERF_TYPE_HARDWARE: u32 = 0;
57+
pub const PERF_TYPE_SOFTWARE: u32 = 1;
5758
pub const PERF_COUNT_HW_CPU_CYCLES: u64 = 0;
59+
pub const PERF_COUNT_SW_CPU_CLOCK: u64 = 0;
5860

5961
extern "C" {
6062
fn syscall(number: libc::c_long, ...) -> libc::c_long;

0 commit comments

Comments
 (0)