< 返回版块

ledkk 发表于 2025-11-12 19:43

以下的代码中,用来采集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;
}



评论区

写评论
shadow3aaa 2025-11-24 09:15

alios大概是运行在ECS上?那很可能是没有透传PMU硬件,试试改为PERF_TYPE_SOFTWARE

1 共 1 条评论, 1 页