ARM Cache Miss 统计
在ARMv8/v9架构中,缓存未命中(Cache Miss)的统计对于性能调优和系统分析至关重要。缓存未命中意味着处理器尝试从缓存中读取数据时没有找到,因此不得不从更低速的存储(如L2缓存或主内存)中加载数据,这会导致延迟增加和性能下降。理解和分析缓存未命中有助于发现程序的瓶颈,从而做出相应的优化。
Cache 多层架构简介
ARMv8/v9 架构通常包含多级缓存,最常见的是三级缓存:
- L1缓存 :分为指令缓存(I-cache)和数据缓存(D-cache),通常每个核心都有自己的L1缓存。
- L2缓存 :作为一个桥梁,连接快速但容量较小的L1缓存和慢速但容量较大的L3或主内存。L2缓存可能对每个处理器核心是独立的,也可能是几个核心共享的。
- L3缓存 :在多核处理器上,L3缓存通常是所有核心共享的,容量更大,但速度慢于L1和L2缓存。
Cache 未命中的类型
- 指令缓存未命中 :当处理器试图从指令缓存中读取执行指令而未命中时发生。这会导致处理器从L2缓存或更低级别的存储中加载指令。
- 数据缓存未命中 :当处理器试图从数据缓存中读取或写入数据而未命中时发生。这迫使处理器从更低一级的缓存或主内存中加载数据。
Cache 未命中统计
在ARMv8/v9架构中,可以通过多种方式统计缓存未命中,这通常涉及到性能监视单元(Performance Monitoring Unit, PMU)的使用。PMU是ARM处理器的一个组件,可以统计包括缓存未命中在内的多种性能事件。
- 使用PMU寄存器 :ARMv8/v9提供了专门的寄存器来配置和读取PMU事件计数器。通过编程这些寄存器,可以选择需要监控的特定事件(例如L1数据缓存未命中、L2缓存未命中等)并读取事件计数。
- 软件工具 :一些软件工具,如
perf
(Linux性能分析工具)也可以用来统计缓存未命中。这些工具内部使用PMU或其他机制来收集数据,为用户提供了一个更为简洁和易用的接口。
本文将会以直接配置PMU 寄存器的方式来统计cache miss 数据。
Cache miss 统计代码实现
本文以统计L1 Data Cache 的miss 为例进行介绍。由于测试环境是在EL3先进行,所以这里需要先配置 mdcr_el3
, 使能 EL3异常等级下 PMU 统计的功能。
.section .text, "ax", %progbits.equ NUM_ITERATIONS, 20
.equ PMU_COUNTER0, 0x0
.equ PMU_EVENT_L1D_CACHE_REFILL, 0x3
.equ TEST_PASS, 0x1
.equ TEST_FAIL, 0x0.global l1_cache_miss
.type l1_cache_miss, %functionl1_cache_miss:stp x29, x30, [sp, #-16]!ldr x9, =NUM_ITERATIONS/* Allow PMU counting at EL3 */mrs x0, mdcr_el3orr x0, x0, #(1 << 17)msr mdcr_el3, x0/* Clear all counters */mrs x0, pmcr_el0bic x0, x0, #0xFmsr pmcr_el0, x0isb/* Set up counter for D cache miss */mov x1, #PMU_COUNTER0msr pmselr_el0, x1mov x1, #PMU_EVENT_L1D_CACHE_REFILLmsr pmxevtyper_el0, x1/* Clear overflow status and enable */ldr x1, =0x80000001msr pmovsclr_el0, x1msr pmcntenset_el0, x1/* Reset and enable counters */orr x0, x0, #0x7 msr pmcr_el0, x0isbloop: adr x0, data_array1adr x1, data_array2adr x2, data_array3/* Clean and invalidate */dsb sydc CIVAC, x0dc CIVAC, x1dc CIVAC, x2dsb syldr x1, [x0]ldr x2, [x1]ldr x3, [x2]isbsubs x9, x9, #0x1bne loopdsb syisb/* Disable counters */mrs x0, pmcr_el0bic x0, x0, #0x1msr pmcr_el0, x0/* Read event counter into x0*/mov x0, #PMU_COUNTER0msr pmselr_el0, x0mrs x0, pmxevcntr_el0ldr x1, =NUM_ITERATIONSmov x2, #0x3madd x2, x2, x1, xzrcmp x0, x2mov x0, #TEST_PASSb.pl test_finishmov x0, #TEST_FAIL
test_finish:bl test_result_outputldp x29,x30, [sp], #16ret.section .data, "aw", %progbits
data_array1: .quad data_array2.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5A.word 0x5A5A5A5Adata_array2: .quad data_array3.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000.word 0xFFFFFFFF.word 0x00000000data_array3: .word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF.word 0xDEADBEEF
上面测试代码可以分为三个部分:
- 配置系统寄存器,允许 EL3 异常登记下PMU 对 cache miss的统计;
- 配置PMU寄存器来进行 L1 Data Cache Miss 事件的统计测试;
- 数据访问及cache操作。
了解缓存未命中的情况后,可以通过各种优化策略减少缓存未命中的发生:
- 提高数据局部性 :通过优化数据结构和访问模式,尽量保证数据访问集中在相邻的内存位置。
- 循环展开 :减少循环中的迭代次数,以减少指令缓存未命中的机会。
- 预取指令和数据 :在数据或指令被需要之前就加载它们到缓存中。
Cache Miss 统计意义
缓存未命中统计是理解和优化ARMv8架构性能的关键环节。通过监控和分析缓存未命中,开发者可以识别性能瓶颈并采取措施进行优化,从而提高应用程序的整体性能。