访问 RISC-V 中的硬件性能计数器



我想检测一个程序来访问硬件性能计数器。

我已经编译了一个基本的火箭芯片(freechips.rocketchip.system-DefaultConfig(,并使用riscv-pk来运行二进制文件。我正在Verilator中运行内核的模拟,在UCB Chipyard项目中以大部分默认值编译了所有内容。

二进制文件的 C 如下所示:

#include <stdio.h>
#define CACHE_MISS      0x100
int loop(int n, int a) {
int b = 0;
for(int i=0; i<n; i++) {
b = a + b;
}
return b;
}
int main() {
int a = 1;
int n = 200;
int count = 0;
printf("Configuring event monitor ...n");
/*
// initialize counters here
// should start tracking cache misses with 0x100
__asm__ volatile("csrw mhpmevent3, %0"
:
: "r"(CACHE_MISS)
);
*/
printf("Executing loop ...n");
loop(n, a);
printf("Reading event counter ...n");
// read counters here
__asm__ volatile("csrr %0, hpmcounter3"
: "=r"(count)
);
printf("Cache misses: %dn", count);
return 0;
}

这是一个基本代码,只是为了查看我是否可以计算缓存未命中数。此代码给了我一个"非法指令"错误。

z  0000000000000000 ra 00000000000101e0 sp 000000000fee9b00 gp 000000000001e560
tp 0000000000000000 t0 0000000000000000 t1 000000000000000f t2 0000000000000000
s0 000000000fee9b20 s1 0000000000000000 a0 00000000000000c8 a1 0000000000000001
a2 0000000000000000 a3 0000000000000010 a4 00000000000000c8 a5 00000000000000c8
a6 000000000000001f a7 0000000000000000 s2 0000000000000000 s3 0000000000000000
s4 0000000000000000 s5 0000000000000000 s6 0000000000000000 s7 0000000000000000
s8 0000000000000000 s9 0000000000000000 sA 0000000000000000 sB 0000000000000000
t3 0000000000000000 t4 0000000000000000 t5 0000000000000000 t6 0000000000000000
pc 00000000000101e0 va 00000000b03027f3 insn       b03027f3 sr 8000000200046020
An illegal instruction was executed!

最初,从hpmcounter3读取的行是从mhpmcounter3读取的,并导致相同的错误。

与另一位开发人员交谈时,一个可能的原因是riscv-pk在 U 模式下运行二进制文件,因此在调用m*汇编指令(在 Machine、M 模式下运行(之后会出现非法指令。所以我更改了二进制文件以注释掉对 mphmevent3 的第一次写入,并且只是从 hpmcounter3 进行了裸读,但仍然收到非法指令错误。这个结果的理论是mcounterenscounteren寄存器没有启用,所以我无法访问计数器。然而,在riscv-pkminit.c内部,我发现:

// Enable user/supervisor use of perf counters
if (supports_extension('S'))
write_csr(scounteren, -1);
if (supports_extension('U'))
write_csr(mcounteren, -1);

我不确定,但我觉得这启用了计数器。

关于我应该如何访问硬件性能计数器的任何想法?

是的,pk 在用户模式下运行二进制文件,因此从用户空间访问计算机级寄存器会产生非法指令异常:

尝试访问 没有适当权限级别的CSR或编写只读寄存器也会引发非法指令 异常。

(RISC-V 特权规范 1.12-草案 2020-01-13,第 2.1 节 CSR 地址映射约定(

hpmcounter*寄存器可以从用户模式访问(参见表2.2当前分配的RISC-V用户级CSR地址,RISC-V特权规范(,当且仅当它们在下一个更高模式下启用时:

如果实现了S模式,则scounteren寄存器中的相同位位置类似地控制 在 U 模式下执行时访问这些寄存器。如果允许 S 模式访问计数器 寄存器并在scounteren中设置相应的位,然后也允许U模式访问 那个寄存器。

启用它们的 pk 代码段看起来很合理。"S"和"U"misa位在RISC-V特权规范中定义:

如果分别支持用户和主管模式,则将设置"U"和"S"位。

但请注意,RISC-V特权规范还指定(强调我的(:

寄存器 mcounter en 和 scounteren 是 WARL 寄存器,如果 U 模式必须实现 和 S 模式实现。任何位都可能包含硬连线值为零,指示 读取到相应的计数器将导致权限较低的模式。

也许您的 CPU 没有实现hpmcounter3并且是否硬连线为零?

要进一步解决此问题,您可以在 pk 中添加断点,即在write_csr(scounteren, -1)和单步汇编器指令之前,以查看写入是否实际发生。如果它们发生了,您可以检查寄存器以检查hpmcounter3是否硬连线为零。

最新更新