You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何绑定特定CPU的perf_event_open+BPF程序全CPU触发?

特定CPU绑定BPF程序到系统调用Tracepoint的问题

我需要编写一个C程序,实现仅当进程/线程在指定CPU上执行系统调用时触发BPF程序的功能。实现步骤如下:

  • 调用perf_event_open(pattr, -1, {MY_CPU_NUM}, -1, 0)创建绑定到目标CPU的perf事件
  • 通过ioctl(efd, PERF_EVENT_IOC_SET_BPF, prog_fd)挂载BPF程序,该程序会递增一个映射中的计数器,供用户态读取结果

测试时以sys_exit_unlinkat系统调用为例,执行命令taskset --cpu-list {ANY_CPU_OTHER_THAN_MY_CPU_NUMBER} rm -rf {DIRECTORY},预期跨CPU执行删除操作时计数器不会递增,但实际无论perf_event_open指定哪个CPU,计数器都会被触发递增,完全不符合预期。

参考perf record -C XX的实现,它同样使用PERF_TYPE_TRACEPOINT类型的perf事件,却能正确仅在指定CPU上触发输出。

我的代码片段

pattr.type = PERF_TYPE_TRACEPOINT;
    pattr.size = sizeof(pattr);
    pattr.config =721; //unlinkat // 723; // rmdir                                                                      
    pattr.sample_period = 1;
    pattr.wakeup_events = 1;
    pattr.disabled = 1;
    pattr.exclude_guest = 1;
    pattr.sample_type = PERF_SAMPLE_RAW;
    efd = perf_event_open(&pattr, -1, 0, -1, 0); // cpu number is zero                                                                     
    if(efd < 0) {
        printf("error in efd opening, %s\n", strerror(errno));
        exit(1);
    } 
    ret = ioctl(efd, PERF_EVENT_IOC_SET_BPF, prog_fd);
    if (ret < 0) {
        printf("PERF_EVENT_IOC_SET_BPF error: %s\n", strerror(errno));
        exit(-1);
    }                                                                                                             
    ret = ioctl(efd, PERF_EVENT_IOC_ENABLE, 0);
    if (ret < 0) {
        printf("PERF_EVENT_IOC_ENABLE error: %s\n", strerror(errno));
        exit(-1);
    }

机器内核版本:Linux zephyr 5.4.0-110-generic


调试定位的问题

通过GDB调试内核,追踪到系统调用退出路径中的perf_syscall_exit(位于kernel/events/trace_syscalls.c)逻辑存在异常:

static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
{
...
        syscall_nr = trace_get_syscall_nr(current, regs);
        if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
                return;
        if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
                return;

        sys_data = syscall_nr_to_meta(syscall_nr);
        if (!sys_data)
                return;

        head = this_cpu_ptr(sys_data->exit_event->perf_events);
        valid_prog_array = bpf_prog_array_valid(sys_data->exit_event);
        if (!valid_prog_array && hlist_empty(head)) // <--- WATCH
                return;

...
}

标注WATCH的判断逻辑为:如果BPF程序无效且事件列表为空则返回;但只要BPF程序有效,无论当前CPU是否绑定了对应的perf事件,都会执行BPF程序。测试验证了这一结论:未挂载BPF程序时,跨CPU操作不会触发事件;挂载后,所有CPU上的系统调用都会触发BPF程序执行。

疑问

这是否意味着内核不支持将BPF程序绑定到特定CPU的tracepoint事件?这是内核bug还是设计限制?


内容的提问来源于stack exchange,提问作者zephyr0110

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:40:23