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

pwuypxnk  于 2023-10-16  发布在  Linux
关注(0)|答案(1)|浏览(159)

此程序显示当前核心执行的实际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);

}

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

  • 我在情报方面没做什么特别的事。此PMC是否默认启用?
  • 如何让它在AMD上工作?
  • 我尝试使用wrmsr命令listed here启用计数器,但他们也立即给了我一个“分段错误”
  • 我尝试了以下命令echo 2 | sudo tee /sys/devices/cpu/rdpmc # enable RDPMC always, not just when a perf event is open
h7wcgrx3

h7wcgrx31#

数字是错误的,AMD使用不同的RDPMC值比英特尔。根据处理器的不同,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上测试

相关问题