PMU简介
PMU即性能监视器,本文只对ARM架构的PMU进行阐述,它运行时可以收集关于处理器和内存的各种统计信息。对于处理器来说这些统计信息中的事件非常有用,你可以利用它们来调试或者剖析代码,很明显这东西是用来测量性能与调优的。之前有段时间在做性能的优化,它是一种硬件实现的机制,因此测量的结果也是比较可信的。需要注意的是,这一整套的PMU寄存器是每个core一套,而每一套PMU相关的寄存器,大体可以分成两类:一部分寄存器是用来做计数或者(计时),比如测量运行这段代码的运行时间,从寄存器里面读取出来的是cycles数,在已知cpu的主频下,也可以计算出来时间;另一部分寄存器是用来统计CPU和内存等的数据,即event事件,如每一级cache的miss率,帮助你调整代码,来优化性能,linux里面大名鼎鼎的perf也是基于PMU来实现的,这些event事件,ARM已经定义好了,具体的定义如下表所示:
PMU有两个主流版本PMUv2和PMUv3,其中大部分32位ARM的处理器使用的PMUv2,大部分64位ARM的处理器使用的PMUv3。两者的主要区别是读取相关寄存器的汇编命令不一样,PMUv2 寄存器是通过CP15 协处理器和外部APB接口来编程,PMUv3则是可以直接使用寄存器的名字来通过mrs和msr命令来读取。
设置和使用事件计数器
本节概述了在Cortex-A15(Armv7-A)上设置和使用事件计数器所需的步骤。Armv8-A处理器的步骤相似,尽管可能会有一些细微的变化。
您可以选择不激活周期计数器(标记为可选的步骤)。这不会影响事件计数器,因为它们独立于周期计数器。如果不需要读出周期数,则可以关闭计数器,这将减少PMU对系统的性能影响。
- (不是必需的)启用PMU用户态访问(即允许在EL0操作PMU相关寄存器),如果你要测的代码是在用户态,那么你必须要把性能监视器用户启用寄存器(PMUSERENR)中的EN,bit [0]设置为1。如果仅在内核态使用(即EL1)则不必设置PMUSERENR寄存器。
- 启用PMU–在性能监视器控制寄存器(PMCR)中,将E,bit [0]设置为1。 配置事件计数器
- 在性能监视器事件计数器选择寄存器(PMSELR)中,将计数器编号(0-5)写入您要配置的SEL位[4:0],即选用那个计数器。
- 在性能监视器事件类型选择寄存器(PMXEVTYPER)中,将事件编号(从event事件列表中,见上表)写入evtCount,bits [7:0],以便选择计数器正在监视的事件。
- 启用已配置的事件计数器 -在性能监视器计数启用设置寄存器 (PMCNTENSET)中,将Px,bit[x](其中x对应于要启用的计数器0-5)设置为1。
- (可选)启用周期计数器(CCNT) -在性能监视器计数启用设置寄存器(PMCNTENSET)中,将C,bit [31]设置为1。
- (可选)重置周期计数器(CCNT) -在性能监视器控制寄存器(PMCR)中,将C,bit [2]设置为1。
- 重置事件计数器 -在性能监视器控制寄存器(PMCR)中,将P,bit [1]设置为1。
现在配置了计数器,并将在执行继续时监视感兴趣的事件。
- (可选)禁用周期计数器(CCNT)-在性能监视器计数启用清除寄存器(PMCNTENCLR)中,将C,bit [31]设置为1。
- 禁用事件计数器 -在性能监视器计数启用清除寄存器(PMCNTENCLR)中,将Px,bit
[x](其中x对应于要禁用的计数器0-5)设置为1。 读取事件计数器的值 - 在性能监视器事件计数器选择寄存器(PMSELR)中,将计数器号(0-5)写入到您要读取的SEL位[4:0]。
所选计数器的值存储在性能监视器所选事件计数寄存器(PMXEVCNTR)中。 - (可选)读取周期计数器(CCNT)的值-周期计数器的值存储在性能监视器周期计数寄存器(PMCCNTR)中。