【问题标题】:Accessing Hardware Performance Counters in RISC-V在 RISC-V 中访问硬件性能计数器
【发布时间】:2020-05-19 17:55:27
【问题描述】:

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

我已经编译了一个基本的 Rocketchip (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: %d\n", 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* 汇编指令(在机器、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);

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

对我应该如何访问硬件性能计数器有什么想法吗?

【问题讨论】:

    标签: riscv


    【解决方案1】:

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

    尝试访问 没有适当特权级别的 CSR 或写入只读寄存器也​​会引发非法指令 例外。

    RISC-V Privileged spec 1.12-draft 2020-01-13,第 2.1 节 CSR 地址映射约定)

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

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

    启用它们的 pk sn-p 看起来不错。 'S' 和 'U' misa 位在 RISC-V 特权规范中定义:

    如果分别支持用户和管理员模式,则“U”和“S”位将被设置。

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

    寄存器 mcounteren 和 scounteren 是 WARL 寄存器,如果 U 模式必须实现 和S模式被实施。任何位可能包含硬连线值零,表示 读取对应的计数器会导致非法指令异常 低权限模式。

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-20
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      • 2021-01-31
      • 2021-08-02
      • 2019-08-19
      • 2023-04-09
      相关资源
      最近更新 更多