学习、沉淀、分享,才能有所获~
文章目录
- HPM简介
- 性能监控计数器重置行为
- 固定功能性能监控计数器
- 事件可编程性能监控计数器
- 事件选择器寄存器
- 事件选择器编码
- 计数使能寄存器
对于性能分析,通常我们会使用Perf工具。而perf中的硬件事件,则需要硬件的支持——性能监视单元PMU。RISC-V u64内核支持PMU,使得我们可以通过perf来统计程序运行所产生的cycle、cache hit、cache miss等事件的次数,从而进一步分析、优化性能。
在SiFive U64内核中,把PMU称作HPM,实际是一个东西。另外,u64内核的hpm增加了一个新的特性——hpm计数溢出中断。
下面详细介绍SiFive U64的HPM。
HPM简介
HPM:Hardware Performance Monitor。 U6 处理器内核支持基本的硬件性能监控 (HPM) 设施。 性能监视工具分为两类计数器:固定功能计数器和事件可编程计数器。 这些类包括一组固定计数器及其计数器使能寄存器,以及一组事件可编程计数器及其事件选择器寄存器。 寄存器可用于控制计数器的行为。 性能监控可用于多种用途,从优化到调试。
性能监控计数器重置行为
instret
和循环计数器在系统复位时被初始化为零。 硬件性能监视器事件计数器不会在系统重置时初始化,因此具有任意值。 用户可以将所需值写入计数器控制和状态寄存器 (CSR),以在给定的已知值开始计数。
固定功能性能监控计数器
一个固定功能的性能监视器计数器是硬件连接的,只计算一种特定的事件类型。 也就是说,它们不能根据它们计数的事件类型进行重新配置。 唯一的可以对固定功能性能监控计数器进行的修改是启用或禁用计数,并写入计数器值本身。
U6 处理器内核包含两个固定功能的性能监控计数器
Fixed-Function Cycle Counter (mcycle)
固定功能性能监控计数器 mcycle
保存自过去某个任意时间以来 hart 执行的时钟周期数的计数。 mcycle 计数器是可读写的,64 位宽。 读取 mcycle 返回 mcycle CSR 的所有 64 位。
Fixed-Function Instructions-Retired Counter (minstret)
固定功能性能监控计数器 minstret
保存 hart 自过去某个任意时间以来退役的指令数。 minstret 计数器是可读写的并且是 64 位宽的。 读取 minstret 返回 minstret CSR 的所有 64 位。
事件可编程性能监控计数器
一组可编程事件计数器与固定功能计数器相辅相成。 U6 HPM 包括两个额外的事件计数器,mhpmcounter3
和 mhpmcounter4
。 这些可编程事件计数器是可读写的,宽度为 64 位。 硬件计数器本身在 U6 内核系列上实现为 40 位计数器。 可以写入这些硬件计数器以初始化计数器值。
事件选择器寄存器
为了控制要计数的事件类型,事件选择器 CSR mhpmevent3 和 mhpmevent4 用于对相应的事件计数器进行编程。 这些事件选择器 CSR 是 64 位 WARL 寄存器。
事件选择器分为三个字段; 低 8 位选择一个事件类别,中间的一组位形成该类别中事件的掩码,高 8 位用于计数器溢出和事件过滤。
如果对应于任何设置掩码位的事件发生,则计数器递增。 例如,如果 mhpmevent3 设置为 0x4200,则 mhpmcounter3 将在任一加载指令时递增或者条件分支指令退出。 事件选择器 0 意味着“什么都不考虑”。
Counter Overflow and Event Filters
mhmpevent
寄存器的高 8 位用于控制计数器溢出中断,以及基于模式的事件过滤。 位布局如下图所示:
Performance Counter Overflow Operation
当内核处于特权模式 x 时,五个 xINH 位中的每一个都禁止事件计数。 这些字段中的所有零导致所有模式下的事件计数。
当相应的 hpmcounterX
溢出时,OF
位由硬件设置,并保持设置状态,直到被软件写入。 由于 hpmcounter
值是无符号的,溢出被定义为从全一递增到全零。 请注意,溢出后不会丢失信息,因为计数器环绕并继续计数,同时粘性 OF
位保持设置。
如果 hpmcounter
溢出而关联的 OF
位为零,则会生成计数溢出中断请求。 如果 hpmcounter
溢出而关联的 OF
位为 1,则不会生成中断。 因此,OF 位还用作相关 hpmcounter 的计数溢出中断禁用。
写入 mhpmcounterX 或 mhpmeventX 寄存器不会导致计数溢出。 仅当事件导致计数器递增时才会发生溢出。
计数器溢出中断是一个标准的本地中断,对应于 mip
和 mie
寄存器中的第 13
位。 mip LCOFIP 位是这个中断和 mie 的中断挂起位 LCOFIE
位是该中断的中断使能位。 LCOFI 表示本地计数溢出中断。 如果存在 S 模式,则 sip 和 sie 包括用于管理程序中断控制和状态的相应位。
hpmcounter
生成计数溢出中断请求会设置 mip
寄存器中的 LCOFIP
位并设置相关的 OF
位。 如果存在 S 模式,则 mideleg
寄存器控制将此中断委托给 S 模式,这会设置 sip
寄存器中的 LCOFIP
位。 在处理计数溢出中断后,LCOFIP
位由软件清零。
发往相同特权模式的多个同时中断按以下优先级递减顺序处理:MEI、MSI、MTI、SEI、SSI、STI、LCOFI。
请注意,没有单独的溢出状态和溢出中断使能位。 实际上,通过清除 OF 位来启用溢出中断生成是与将计数器初始化为起始值一起完成的。 一旦计数器溢出,它和 OF 位必须在产生另一个溢出中断之前重新初始化。
软件可以区分尚未被溢出中断处理程序服务的新溢出计数器和已经被服务的溢出计数器(或者通过维护反映哪些计数器处于活动状态和到期的位掩码配置为不在溢出时生成中断的计数器) 最终溢出。
Scountovf 寄存器
scountovf
CSR 是一个 32 位只读寄存器,包含 29
个 mhpmevent
CSR 中 OF
位的影子副本。 scountovf 中的位 X 对应于 mhpmeventX 中的 OF 位。 该寄存器使主管级溢出中断处理程序软件能够快速确定哪些计数器已经溢出,而无需对 M 模式进行环境调用。 CSR 地址为 0xDA0。
对 scountovf 位 X 的读取访问受制于调解 S 模式软件对 hpmcounterX 访问的相同 mcounteren CSR。 在 S 模式下,当设置 mcounteren 位 X 时,scountovf 位 X 是可读的,否则读为零。
Disabling Counters in Debug Mode
设置后,dcsr.stopcount 位会在调试模式下停止计数器。 这对于 mcycle 和 minstret 计数器尤其重要,因为在调试模式下,核心在紧密循环中执行 ROM 指令。 Freedom Studio Performance Monitor View 自动设置dcsr.stopcount 位。
事件选择器编码
表 20 描述了可用的事件选择器编码。 根据 mhpmeventX
[7:0] 中编码的事件类字段,将事件分类为类。 可以通过为给定事件类别设置相应的事件掩码位来对一个或多个事件进行编程。 事件选择器编码为 0 表示“无意义”。 任何选定事件发生时,多个事件都会导致计数器递增。
对任何事件类可写的事件掩码位对所有类都是可写的。 设置与表 20 中定义的事件不对应的事件掩码位对当前实现没有影响。 但是,未来的实现可能会在该编码空间中定义新事件,因此不建议将不受支持的值编程到 mhpmevent
寄存器中。
Combining Events
直接计算每个事件是常见的用法。 此外,可以使用这些事件的组合来计算新的、独特的事件。 例如,要确定来自数据存储器子系统的每次加载的平均周期数,可以对一个计数器进行编程以计算“数据高速缓存/DTIM 繁忙”,并对另一个计数器进行编程以计算“已退出的整数加载指令”。 然后,简单地将“数据高速缓存/DTIM 繁忙”周期计数除以“整数加载指令退休”指令计数,结果就是每条指令加载周期的平均周期时间。
了解组合的事件类型很重要; 具体来说,事件类型计算发生次数,事件类型计算周期。
计数使能寄存器
32 位计数器使能寄存器 mcounteren
和 scounteren
控制硬件性能监控计数器在下一个最低特权模式下的可用性。
这些寄存器中的设置仅控制可访问性。 读取或写入这些启用寄存器的行为不会影响底层计数器,这些计数器在不可访问时会继续递增。
当 mcounteren
寄存器中的任何位清零时,在 S 模式下执行时尝试读取周期、时间、指令退出或 hpmcounterX
寄存器将导致非法指令异常。 当这些位中的一个被设置时,在下一个实现的特权模式 S 模式下允许访问相应的寄存器。
在 U 模式下执行时,scounteren
寄存器中的相同位位置类似地控制对这些寄存器的访问。 如果允许 S-mode 访问计数器寄存器并且在 scounteren
中设置了相应的位,则也允许 U-mode 访问该寄存器。
mcounteren
和 scounteren
是 WARL 寄存器。 任何位都可能包含硬连线值零,表示在低特权模式下执行时,读取相应计数器将导致非法指令异常。