1. AMU簡介
AMU是ActivityMonitor Unit的縮寫,在Arm v8.4架構中引入。從Arm文檔描述來看,AMU與PMU(PerformanceMonitor Unit)有類似的性能監(jiān)控功能,但其設計初衷是為了系統(tǒng)管理,而PMU的用途是用戶態(tài)程序或者調試功能。AMU可以為系統(tǒng)性能、功耗管理提供持續(xù)不斷的監(jiān)控并獲取非常有用的信息。
在介紹AMU之前,先介紹下PMU幾個基本概念,對了解AMU會有所幫助。PMU用于跟蹤、統(tǒng)計系統(tǒng)內部的一些底層硬件事件,這些事件反映了程序在CPU上執(zhí)行的行為,可以幫助我們對程序進行分析和調優(yōu):
Event,即事件,例如CPU相關的事件包括執(zhí)行指令數(shù),時鐘周期等,cache相關的事件包括各級cache訪問、refill計數(shù)等,以及與TLB有關的事件等。每個event都有一個特定的eventid。
Counter,事件計數(shù)器,數(shù)量固定,以Cortex-A53為例,一共有1+6個Counter,CycleCounter只用于記錄CPU Cycle數(shù),另外6個Counter是可配置的Counter,根據(jù)配置選擇的Event進行計數(shù)。當計數(shù)器發(fā)生溢出時,計數(shù)器會產生overflow中斷。

AMUv1架構定義(architecturally defined)4個固定的EventCounter,分別是:

既然是架構規(guī)定要實現(xiàn)的,那么一定是被經常用到的Event。未來可能會增加固定Counter的數(shù)量,AMU最多可支持16個固定Counter。
除了固定Counter,還支持最多16個輔助的Counter,這些Counter可以做成固定的也可以是可配置的,取決于具體實現(xiàn)。所有AMUEvent Counter都是64位的,在溢出時沒有提示或者中斷。
2. AMU寄存器
AMU寄存器如下圖所列,

AMU寄存器通過systemregister接口MRS和MSR指令進行訪問。
訪問控制
可通過配置控制是否允許更低EL級別訪問AMU寄存器。AMUSERENR_EL0.ENbit控制EL0訪問AMU寄存器,可在EL1,EL2,EL3中配置。CPTR_EL2.TAMbit控制來自EL0和EL1的訪問,CPTR_EL3.TAMbit控制來自EL0,EL1和EL2的訪問。其他的配置,只允許在最高的EL級別中進行。
Counter寄存器

Counter寄存器都有以下特點:
都是64位寄存器,并且overflow時不產生狀態(tài)提示或者中斷;
CPU復位后Counter寄存器值恢復為0;
Event Type寄存器

EventType寄存器配置了各Counter對哪個event進行計數(shù),這點與PMU的PMEVTYPER
AMCNTENSET0_EL0/AMCNTENCLR0_EL0可對各Counterenable/disable進行控制,其他寄存器含義可參考ARM文檔,這里不一一介紹。
3. 代碼實現(xiàn)
在Kernel中通過CONFIG_ARM64_AMU_EXTN宏進行AMU代碼控制,Kernel最早支持AMU的功能,在這個patch中:
arm64: add support for the AMU extension v1
在arch/arm64/include/asm/sysreg.h中定義了AMU各寄存器的地址
/* Definitions for system register interface to AMU for ARMv8.4 onwards */ #define SYS_AM_EL0(crm, op2) sys_reg(3, 3, 13, (crm), (op2)) #define SYS_AMCR_EL0 SYS_AM_EL0(2, 0) #define SYS_AMCFGR_EL0 SYS_AM_EL0(2, 1) #define SYS_AMCGCR_EL0 SYS_AM_EL0(2, 2) #define SYS_AMUSERENR_EL0 SYS_AM_EL0(2, 3) #define SYS_AMCNTENCLR0_EL0 SYS_AM_EL0(2, 4) #define SYS_AMCNTENSET0_EL0 SYS_AM_EL0(2, 5) #define SYS_AMCNTENCLR1_EL0 SYS_AM_EL0(3, 0) #define SYS_AMCNTENSET1_EL0 SYS_AM_EL0(3, 1) #define SYS_AMEVCNTR0_EL0(n) SYS_AM_EL0(4 + ((n) >> 3), (n) & 7) #define SYS_AMEVTYPER0_EL0(n) SYS_AM_EL0(6 + ((n) >> 3), (n) & 7) #define SYS_AMEVCNTR1_EL0(n) SYS_AM_EL0(12 + ((n) >> 3), (n) & 7) #define SYS_AMEVTYPER1_EL0(n) SYS_AM_EL0(14 + ((n) >> 3), (n) & 7) /* AMU v1: Fixed (architecturally defined) activity monitors */ #define SYS_AMEVCNTR0_CORE_EL0 SYS_AMEVCNTR0_EL0(0) #define SYS_AMEVCNTR0_CONST_EL0 SYS_AMEVCNTR0_EL0(1) #define SYS_AMEVCNTR0_INST_RET_EL0 SYS_AMEVCNTR0_EL0(2) #define SYS_AMEVCNTR0_MEM_STALL SYS_AMEVCNTR0_EL0(3)
在arm-trusted-firmware中,也有AMU寄存器讀寫相關代碼,還包括上下電時AMU備份恢復的操作,代碼主要在lib/extensions/amu/aarch64/和lib/cpus/aarch64/cpuamu_helpers.S。
4. AMU的應用
在內核中有這么一個patch,目的是為了讓調度LoadTracking的FIE計算更準確,
arm64: use activity monitors for frequency invariance
在此之前,Kernel中的freq scale計算都是通過cpufreq模塊記錄的當前頻率和最大頻率來計算的,但是實際頻率可能在Kernel之外的地方發(fā)生變化,與Kernel cpufreq模塊記錄的當前頻率不同,或者支持ACPI的cpufreq driver是不知道當前頻率的。因此AMU就為獲取CPU平均頻率提供了一個方法。通過CPU_CYCLES和CNT_CYCLES的Counter計數(shù)來計算CPU頻率,具體代碼如下。
arch/arm64/kernel/topology.c
/* Initialize counter reference per-cpu variables for the current
CPU */
void init_cpu_freq_invariance_counters(void)
{
this_cpu_write(arch_core_cycles_prev,
read_sysreg_s(SYS_AMEVCNTR0_CORE_EL0));
this_cpu_write(arch_const_cycles_prev,
read_sysreg_s(SYS_AMEVCNTR0_CONST_EL0));
}
void topology_scale_freq_tick(void)
{
u64 prev_core_cnt, prev_const_cnt;
u64 core_cnt, const_cnt, scale;
int cpu =
smp_processor_id();
if
(!amu_freq_invariant())
return;
if
(!cpumask_test_cpu(cpu, amu_fie_cpus))
return;
const_cnt =
read_sysreg_s(SYS_AMEVCNTR0_CONST_EL0);
core_cnt = read_sysreg_s(SYS_AMEVCNTR0_CORE_EL0);
prev_const_cnt =
this_cpu_read(arch_const_cycles_prev);
prev_core_cnt =
this_cpu_read(arch_core_cycles_prev);
if (unlikely(core_cnt
<= prev_core_cnt ||
const_cnt <= prev_const_cnt))
goto
store_and_exit;
/*
* /core arch_max_freq_scale
* scale = ------- * --------------------
* /const SCHED_CAPACITY_SCALE
*
* See validate_cpu_freq_invariance_counters()
for details on
* arch_max_freq_scale and the use of
SCHED_CAPACITY_SHIFT。
*/
scale = core_cnt -
prev_core_cnt;
scale *=
this_cpu_read(arch_max_freq_scale);
scale = div64_u64(scale
>> SCHED_CAPACITY_SHIFT,
const_cnt - prev_const_cnt);
scale = min_t(unsigned
long, scale, SCHED_CAPACITY_SCALE);
this_cpu_write(freq_scale, (unsigned long)scale);
store_and_exit:
this_cpu_write(arch_core_cycles_prev, core_cnt);
this_cpu_write(arch_const_cycles_prev, const_cnt);
}
5. AMU與PMU的區(qū)別
前文提到AMU與PMU的設計目的不同。除此之外,還有哪些差異點呢?
AMU與PMU具有類似的特性,設計的目的有所不同,AMU是為了系統(tǒng)功耗性能管理,PMU是為了用戶態(tài)程序或者調試目的。從硬件角度都是對事件進行計數(shù),我們同樣也可以使用PMU的統(tǒng)計結果進行功耗和性能管理,為什么還要再引入AMU呢?
可能的原因是,PMU有多個使用場景,如果在性能功耗管理方案上使用了PMU,那么在性能調試時也要獲取PMU信息就可能產生沖突,例如使用強大的perf工具抓取PMU信息,尤其在Counter數(shù)量有限的情況下,沖突概率更大。引入AMU是為了給固定的資源專門用來做系統(tǒng)控制方案,從而釋放PMU資源用作其他目的。
PMU和AMU的軟件使用方式上,也有很大的不同。AMU通過system register interface就可以訪問,而PMU需要通過內核的perf接口,軟件開銷遠超過AMU。
下圖列出了兩者功能上的一些差異,

審核編輯:劉清
-
寄存器
+關注
關注
31文章
5590瀏覽量
129145 -
cpu
+關注
關注
68文章
11223瀏覽量
223077 -
計數(shù)器
+關注
關注
32文章
2306瀏覽量
97642 -
Cortex-A53
+關注
關注
0文章
34瀏覽量
21861
原文標題:Perf monitor:從PMU到AMU
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
Revere AMU系統(tǒng)架構參考指南
PMU測試儀的設計與研究
PMU量測點優(yōu)化配置新方法

AMU與PMU有哪些差異點呢?
評論