以下的代码中,用来采集PERF_COUNT_HW_CPU_CYCLES 数据, 现在遇到了一个比较奇怪的问题,具体说明如下
环境1
- 操作系统版本: 5.15.0-161-generic #171-Ubuntu x86_64 GNU/Linux
- 执行后的输出(符合预期的输出)
read 40 bytes, value is [2, 7479, 238, 2431, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 127709, 238, 36506, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 343860, 238, 60451, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 644166, 238, 84421, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 847368, 238, 108401, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 1124773, 238, 132528, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 1329805, 238, 156512, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
环境2
- 操作系统版本: alios 5.10.134-010.x86_64
- 执行输出(结果没有任何变化):
read 40 bytes, value is [2, 0, 523119, 0, 523120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 0, 523119, 0, 523120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 0, 523119, 0, 523120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 0, 523119, 0, 523120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
read 40 bytes, value is [2, 0, 523119, 0, 523120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
示例代码:
use std::{thread::sleep, time::Duration};
use log::warn;
use perf_event_open_sys as sys;
use perf_event_open_sys::bindings as perf_bindings;
fn main() {
env_logger::init();
perf_event(0, -1, -1);
}
pub fn perf_event(pid: i32, cpu: i32, group_fd: i32) {
let type_ = sys::bindings::PERF_TYPE_HARDWARE;
let config = sys::bindings::PERF_COUNT_HW_CPU_CYCLES as u64;
let fd = perf_counter_event_open(
pid,
cpu,
group_fd,
type_,
config,
sys::bindings::PERF_FLAG_FD_CLOEXEC as u64,
sys::bindings::PERF_FORMAT_GROUP as u64 | sys::bindings::PERF_FORMAT_ID as u64,
);
if fd < 0 {
panic!(
"perf_event_open failed, the error code is {}",
std::io::Error::last_os_error()
);
}
let type_ = sys::bindings::PERF_TYPE_HARDWARE;
let config = sys::bindings::PERF_COUNT_HW_INSTRUCTIONS as u64;
let _follower_fd = perf_counter_event_open(
pid,
cpu,
fd,
type_,
config,
sys::bindings::PERF_FLAG_FD_CLOEXEC as u64,
sys::bindings::PERF_FORMAT_GROUP as u64,
);
if _follower_fd < 0 {
panic!(
"perf_event_open failed, the error is {}",
std::io::Error::last_os_error()
);
}
perf_event_ioctl_reset(fd, sys::bindings::PERF_IOC_FLAG_GROUP);
perf_event_ioctl_enable(fd, sys::bindings::PERF_IOC_FLAG_GROUP);
loop {
let mut buf = [0u64; 24];
let _size = unsafe {
libc::read(
fd,
buf.as_mut_ptr() as *mut libc::c_void,
buf.len() * std::mem::size_of::<u64>(),
)
};
if _size < 0 {
panic!(
"read failed, the error code is {}",
std::io::Error::last_os_error()
);
}
println!("read {} bytes, value is {:?}", _size, buf);
sleep(Duration::from_millis(1000));
}
}
// perf_event_open a counter event
// return fd , fd < 0 means open failed, just warn log
pub fn perf_counter_event_open(
pid: i32,
cpu: i32,
group_fd: i32,
type_: u32,
config: u64,
flags: u64,
read_format: u64,
) -> i32 {
let mut attrs = perf_bindings::perf_event_attr::default();
attrs.type_ = type_;
attrs.config = config;
attrs.size = std::mem::size_of::<perf_bindings::perf_event_attr>() as u32;
attrs.read_format = read_format;
let fd = unsafe { sys::perf_event_open(&mut attrs, pid, cpu, group_fd, flags) };
if fd < 0 {
warn!(
"perf_event_open failed, pid {} , type {} , config {} , fd {} , errno {}",
pid,
type_,
config,
fd,
std::io::Error::last_os_error()
);
}
return fd;
}
// perf_event_ ioctl reset
// return ret, ret < 0 means ioctl failed, just warn log
pub fn perf_event_ioctl_reset(fd: i32, flag: u32) -> i32 {
let ret = unsafe { sys::ioctls::RESET(fd, flag) };
if ret < 0 {
warn!(
"perf_event_ioctl_reset failed, fd {} , errno {}",
fd,
std::io::Error::last_os_error()
);
}
return ret;
}
pub fn perf_event_ioctl_enable(fd: i32, flag: u32) -> i32 {
let ret = unsafe { sys::ioctls::ENABLE(fd, flag) };
if ret < 0 {
warn!(
"perf_event_ioctl_enable failed, fd {} , errno {}",
fd,
std::io::Error::last_os_error()
);
}
return ret;
}
1
共 1 条评论, 1 页
评论区
写评论alios大概是运行在ECS上?那很可能是没有透传PMU硬件,试试改为PERF_TYPE_SOFTWARE