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

为何Perf在Zen 2平台无法打开L1缓存写访问事件?

问题描述

在AMD Zen2架构的Ryzen Threadripper 3960X 24核处理器上,尝试通过perf_event_open读取以下L1d缓存事件:

  • L1d所有读访问
  • L1d所有写访问
  • L1d读缺失
  • L1d写缺失

按照perf_event_open的规则,通过位运算构造perf_event_attr.config:

config = (perf_hw_cache_id) |
         (perf_hw_cache_op_id << 8) |
         (perf_hw_cache_op_result_id << 16);

测试L1D_read_access时代码正常运行,但测试L1D_write_access时,perf_event_open返回-1,报错Error: Perf couldn't open event.。该代码在Intel平台可正常执行。


机器信息

$ lscpu
Architecture:             x86_64
  CPU op-mode(s):         32-bit, 64-bit
  Address sizes:          43 bits physical, 48 bits virtual
  Byte Order:             Little Endian
CPU(s):                   24
  On-line CPU(s) list:    0-23
Vendor ID:                AuthenticAMD
  Model name:             AMD Ryzen Threadripper 3960X 24-Core Processor
    CPU family:           23
    Model:                49
...

$ uname -r
6.13.2-arch1-1

说明

代码中设置了PERF_FORMAT_ID和PERF_FORMAT_GROUP标志,用于后续创建包含四个目标事件的事件组。

测试代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/ioctl.h>

#define MAX_EVENTS 4

struct read_format{
    uint64_t nr;
    struct {
        uint64_t val;
        uint64_t id;
    }rec[MAX_EVENTS];
};

int main(){
    // define HW_CACHE event
    uint64_t L1D_write_access = ((PERF_COUNT_HW_CACHE_L1D) |            \
                                 (PERF_COUNT_HW_CACHE_OP_WRITE << 8) |  \
                                 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16));
    uint64_t L1D_read_access = ((PERF_COUNT_HW_CACHE_L1D) |             \
                                (PERF_COUNT_HW_CACHE_OP_READ << 8) |    \
                                (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16));
    uint64_t test_event = L1D_write_access;

    // set event attributes
    struct perf_event_attr pea;
    memset(&pea, 0, sizeof(pea));
    pea.size = sizeof(struct perf_event_attr);
    pea.type = PERF_TYPE_HW_CACHE;
    pea.config = test_event;
    pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP;
    pea.disabled = 1;
    pea.exclude_kernel = 1;
    pea.exclude_hv = 1;
    pea.exclude_idle = 1;

    // open event
    int64_t event_fd = -1;
    event_fd = syscall(SYS_perf_event_open, &pea, 0, -1, event_fd, 0);
    if (event_fd == -1) {
        fprintf(stderr, "Error: Perf couldn't open event.\n");
        exit(EXIT_FAILURE);
    }
    uint64_t event_id;
    ioctl(event_fd, PERF_EVENT_IOC_ID, &event_id);
    ioctl(event_fd, PERF_EVENT_IOC_RESET, 0);
    printf("Created event ID: %lX\n", event_id);


    // measure work
    size_t mem_l = 1024*1024;
    uint64_t var = 0;
    uint64_t *mem = (uint64_t*)malloc(mem_l*sizeof(uint64_t));
    ioctl(event_fd, PERF_EVENT_IOC_ENABLE, 0);
    for(size_t i=0; i<mem_l; i++){
        mem[i] ^= var;
    }
    ioctl(event_fd, PERF_EVENT_IOC_DISABLE, 0);

    // read results
    struct read_format rfmt;
    ssize_t read_bytes = read(event_fd, &rfmt, sizeof(rfmt));
    if(!read_bytes){
        fprintf(stderr, "Error: Zero bytes read from the file descriptor.\n");
        exit(1);
    }
    if(read_bytes == -1){
        perror("Error: Couldn't read the event's file descriptor");
        exit(1);
    }
    printf("%ld bytes read from events file.\n", read_bytes);
    for(size_t i=0; i<rfmt.nr; i++){
        printf("\nregister %lu:\n", i);
        printf("%12lu : val\n", rfmt.rec[i].val);
        printf("%12lX :  id\n", rfmt.rec[i].id);
    }
    printf("done\n");
}

问题原因与解决方法

原因

AMD Zen2架构的PMU(性能监控单元)不支持PERF_COUNT_HW_CACHE_OP_WRITE + PERF_COUNT_HW_CACHE_RESULT_ACCESS的组合事件。Intel与AMD的PMU事件模型存在差异,部分通用的PERF_TYPE_HW_CACHE抽象事件在AMD平台没有对应的硬件计数器支持。

对于Zen2架构,L1D写访问无法通过标准的PERF_TYPE_HW_CACHE事件直接获取,必须使用AMD特定的原始事件代码。

解决方法

方法1:替换为AMD原始PMU事件

Zen2架构中,L1D写访问对应的原始事件配置为:

  • 事件选择码:0x40
  • UMASK:0x02

修改代码中的事件定义和类型:

// Zen2 L1D写访问的原始事件
uint64_t L1D_write_access_raw = (0x02 << 8) | 0x40;
uint64_t test_event = L1D_write_access_raw;

// 修改事件类型为原始事件
pea.type = PERF_TYPE_RAW;

方法2:通过perf list确认支持的事件

先通过命令查看Zen2平台支持的L1D相关事件:

perf list | grep L1-dcache

找到对应的写访问事件(如l1d_writes),通过perf stat -e l1d_writes ./your_program验证后,再转换为perf_event_open的配置。

补充:L1D读/写缺失的处理

同样需要使用AMD原始事件:

  • L1D读缺失:(0x01 << 8) | 0x41
  • L1D写缺失:(0x02 << 8) | 0x41

验证

修改代码后重新编译运行,即可正常打开L1D写访问事件并获取计数。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:38:09