@@ -43,7 +43,7 @@ struct stacktrace_event {
43
43
ustack : [ u64 ; MAX_STACK_DEPTH ] ,
44
44
}
45
45
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 > {
47
47
let nprocs = libbpf_rs:: num_possible_cpus ( ) . unwrap ( ) ;
48
48
let pid = -1 ;
49
49
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> {
52
52
buf. leak ( ) . as_mut_ptr ( ) as * mut syscall:: perf_event_attr
53
53
)
54
54
} ;
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
+ } ;
56
60
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
+ } ;
58
66
attr. sample . sample_freq = freq;
59
67
attr. flags = 1 << 10 ; // freq = 1
60
68
( 0 ..nprocs)
61
69
. map ( |cpu| {
62
70
let fd = syscall:: perf_event_open ( attr. as_ref ( ) , pid, cpu as i32 , -1 , 0 ) as i32 ;
63
71
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)
66
79
} else {
67
80
Ok ( fd)
68
81
}
@@ -224,6 +237,12 @@ struct Args {
224
237
/// Increase verbosity (can be supplied multiple times).
225
238
#[ arg( short = 'v' , long = "verbose" , global = true , action = ArgAction :: Count ) ]
226
239
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 ,
227
246
}
228
247
229
248
fn main ( ) -> Result < ( ) , libbpf_rs:: Error > {
@@ -251,7 +270,7 @@ fn main() -> Result<(), libbpf_rs::Error> {
251
270
let open_skel = skel_builder. open ( & mut open_object) . unwrap ( ) ;
252
271
let skel = open_skel. load ( ) . unwrap ( ) ;
253
272
254
- let pefds = init_perf_monitor ( freq) ?;
273
+ let pefds = init_perf_monitor ( freq, args . sw_event ) ?;
255
274
let _links = attach_perf_event ( & pefds, & skel. progs . profile ) ;
256
275
257
276
let mut builder = libbpf_rs:: RingBufferBuilder :: new ( ) ;
0 commit comments