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