简介:
mcycle 是 RISC-V 架构中定义的一个 控制与状态寄存器 (CSR),用于记录自处理器启动以来所经历的 CPU 时钟周期数。它是性能分析中非常重要的一个寄存器,通常用于测量代码执行的时间或性能。我们可以利用该寄存器来评估某一段代码的执行时间。
本次试验使用GDVF103 基于芯来科技(Bumblebee RISC-V处理器)硬件平台进行验证,以下是芯片手册中对mcycle 寄存器的说明。
除了上述的计数器寄存器外,芯片上还涉及了对应功能的开关使能寄存器。
该寄存器为芯片自定义CSR寄存器,非RISC-V 标准定义的CSR寄存器
根据寄存器描述及CSR 寄存器访问index 编写如下测试代码打印输出cpu cecyle 和 运行指令计数器状态。
unsigned int mcountinhibit(char argc,char ** argv) { uint32_t countinhibit = 0; countinhibit = read_csr(0X320); //读取 mcycle 寄存器 printf("IR %s\n",((countinhibit & 0x01U << 2U) ? "OFF" : "ON")); printf("CY %s\n",((countinhibit & 0x01U << 0U) ? "OFF" : "ON")); return 0; } LTSH_FUNCTION_EXPORT(mcountinhibit,"show mcountinhibit register");
运行结果如下打印输出发现是关闭状态。
查看本地环境的启动代码,发现在进入main 函数前为了降低功耗关闭了该功能。
提到了功耗,我很好奇GD32VF103 的关闭和开启cpu 运行计数和指令计数功能内核的功耗差距会有多大,本地添加代码手动控开启关闭该功能比较功耗的差异能有多少。
unsigned int mcount(char argc,char ** argv) { uint32_t countinhibit = 0; if(argc == 1) { countinhibit = read_csr(mucounteren); //读取 mcycle 寄存器 printf("MCOUNT = 0x%08x \n",countinhibit); printf("IR %s\n",((countinhibit & 0x01U << 2U) ? "OFF" : "ON")); printf("CY %s\n",((countinhibit & 0x01U << 0U) ? "OFF" : "ON")); } if(argc == 2) { if(strcmp(argv[1],"off") == 0) asm volatile ("csrsi 0x320, 0x5"); if(strcmp(argv[1],"on") == 0) asm volatile ("csrci 0x320, 0x5"); } return 0; } LTSH_FUNCTION_EXPORT(mcount,"show mcountinhibit register");
通过串口关闭和开启的场景下在3.3v 供电的时整板电流差距0.1ma 对一般的应用来说这点功耗不会有很大影响。
cycle 计数器采用64位的计数器,本地系统配置运行的频率为108MHZ,溢出的周期为5.41 年所以我们就不考虑计数器溢出的场景了,毕竟一个程序连续运行这么就的场景也很少见。
对应的cycle CSR 寄存器的index 分别是0xc00 和 0xc80 分别代表低32bit 和 高32bit
添加如下测试代码,计算FreeRtos 5 s的delay 这段代码前后的CPU Cycle 计数
运行打印输出如下:
[2024-12-22 21:47:28.021] cycle 3659014800 [2024-12-22 21:47:28.021] cycleh 12 [2024-12-22 21:47:33.025] cycle --4199388774 [2024-12-22 21:47:33.025] cycleh --12
CPU 的主频运行在108M 每个周期 9.259ns 执行前后的cycle 差为,
4199388774 - 3659014800 = 540,373,974 * 9.259 = 5,003,322,625.266 ns = 5.003322625266 S
修改代码周期打印输出结果正常。
上述测试结果说明RISC-V 的cycle 计数功能可以用来评估代码性能,也可以和perf counter 对接完成底层依赖的计时器功能。