linux - 如何在AMD(EPYC)处理器上使用rdpmc指令?

标签 linux performance x86 amd-processor intel-pmu

该程序显示当前核心执行的实际CPU核心周期数(使用相关的PMC,我认为是UNHALTED_CORE_CYCLES)

#include <unistd.h>
#include <cstdio>

int main(int argc, char* argv[]){

    unsigned long a, d, c, result;

    c = (1UL<<30)+1;
    __asm__ volatile("rdpmc" : "=a" (a), "=d" (d) : "c" (c));

    result = (a | (d << 32)); 
    printf("Current cycles  : %lu\n", result);

}

它在 Intel 处理器上运行良好,但在 AMD 处理器(7001 和 7002)上显示“段错误”。我的第一个猜测是找到与 CPU_CLOCKS_UNHALTED AMD 事件 (0x76) 相关的新 c 值,暂时没有成功

  • 我没有在英特尔方面做任何特别的事情。此 PMC 是否默认启用?
  • 如何才能使其在 AMD 上运行?
    • 我尝试使用 wrmsr 命令 listed here 启用计数器但他们也立即给了我一个“段错误”
    • 我尝试了以下命令echo 2 | sudo tee/sys/devices/cpu/rdpmc# 始终启用 RDPMC,而不仅仅是在性能事件打开时启用

最佳答案

数字错误,AMD 使用的 RDPMC 值与 Intel 不同。根据处理器的不同,通过rdpmc直接支持多个事件,请引用这个AMD manual了解更多信息(rdpmc 部分)。

在您的情况下,核心周期数应为 0

这段代码可以让我计算PERF_COUNT_HW_INSTRUCTIONS

#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                int cpu, int group_fd, unsigned long flags) {
    int ret;

    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
    return ret;
}

#define rdpmc(counter, low, high)                \
    __asm__ __volatile__("rdpmc"                 \
                         : "=a"(low), "=d"(high) \
                         : "c"(counter))


int main() {
    unsigned long values1, values2;
    unsigned int fixed0, low, high;
    struct perf_event_attr pe;
    int fd, i;

    //PERF_COUNT_HW_INSTRUCTIONS
    // Performance counter 1 on AMD
    // 1 << 30 on Intel
    fixed0 = 1;

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_INSTRUCTIONS;
    pe.disabled = 1;
    pe.exclude_kernel = 0;
    pe.exclude_hv = 0;
    pe.exclude_idle = 0;

    fd = perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1) {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }
    for (i = 1; i <= 50; i++) {
        ioctl(fd, PERF_EVENT_IOC_RESET, 0);
        ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

        rdpmc(fixed0, low, high);
        values1 = ((unsigned long)high << 32) + (unsigned long)low;
        asm volatile("lfence": : :"memory");        // test ()
        rdpmc(fixed0, low, high);
        values2 = ((unsigned long)high << 32) + (unsigned long)low;
        
        ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
        printf(" %lu\n", values2-values1);
    }
    close(fd);
}

在 Ryzen 7950X 上测试

关于linux - 如何在AMD(EPYC)处理器上使用rdpmc指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72045801/

相关文章:

c - 这个反汇编输出如何与函数源相关联?

assembly - 带有字节目标的 mov 指令立即到内存

linux - 监听 fifo 和 socket 文件

c - Bash中的增减运算符是Undefined Behavior吗?

linux - 为什么同一文件的 2 个 linux 进程不能共享文本段?

swift - 为什么 `String(describing: Class.self)` 比 `NSStringFromClass(Class.self)` 慢?

xml - 如何提高 VBA 中 XML 解析的速度

linux - 检索进程曾经在 linux 中打开的所有文件描述符(文件)的列表

php - jQuery 与 PHP - 性能比较

linux - NASM:MOV ECX 上的段错误