Performance Event FD 用于为程序提供 counter 功能。它的功能非常强大且多样化,具体的需求可以参考 此链接

总的来说,程序将自己性能测试的需求写入到 perf_event_attr 这个结构体中,然后根据 attr 利用 perf_event_open() 创建一个 fd ,然后通过 ioctl() 来控制计时器的行为(比如 enable, disable, reset )。最后用 read() 读取 counter 的值。

示例代码如下:

#include <linux/perf_event.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>
 
// 目前 perf_event_open 在 glibc 中没有封装,需要手工封装一下
int perf_event_open(
    struct perf_event_attr* attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
    return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
}
 
int main()
{
    int i = 5;
 
    // 设置 perf event
    struct perf_event_attr attr;
    memset(&attr, 0, sizeof(struct perf_event_attr));
    attr.size = sizeof(struct perf_event_attr);
    attr.type = PERF_TYPE_HARDWARE;           // 监测硬件
    attr.config = PERF_COUNT_HW_CPU_CYCLES;   // 监测 cycle 数
    attr.disabled = 1;                        // counter 初始状态为禁用
    // pe.exclude_kernel = 1;                    // 排除 kernel 时间
    // pe.exclude_hv = 1;                        // 排除 hypervisor 时间
 
    // 创建 perf 文件描述符,其中 pid = 0,cpu = -1 表示监测当前进程,不论运行在那个 cpu 上
    int fd = perf_event_open(&attr, 0, -1, -1, 0);
    if (fd < 0) {
        perror("Cannot open perf fd!, Use sudo or Check Kernel Config");
        return 1;
    }
 
    ioctl(fd, PERF_EVENT_IOC_RESET, 0);    // 重置
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);   // 开启
 
 
    while (i--) {
        uint64_t cycles;
        // 读取最新的计数值
        read(fd, &cycles, sizeof(cycles));
        printf("cycles = %ld\n", cycles);
        sleep(1);
    }
 
    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);   // 关闭
}

Linux Perf 机制依赖于 CONFIG_PERF_EVENTS, CONFIG_HW_PERF_EVENTS 的开启。