緩存miss了咋整?傳統(tǒng)做法是CPU干等著,直到數(shù)據(jù)從內(nèi)存回來。無阻塞緩存(Non-blocking Cache)打破了這個規(guī)矩——即使前面有個miss正在處理,后面的請求該干嘛干嘛。這篇聊聊這個技術(shù)的原理、實現(xiàn)和效果。
1. 阻塞緩存的痛點
想象你在餐廳排隊點餐:
- 前面的人點了個復(fù)雜的套餐(緩存miss,需要等很久)
- 你只想點杯咖啡(緩存hit,很快)
- 但阻塞式服務(wù)要求你必須等前面的人拿完餐,才能點你的咖啡
這顯然不合理。CPU里的緩存也是這個道理。
1.1 實際性能損失
1994年,F(xiàn)arkas和Jouppi在DEC Western Research Lab做了個實驗[1]。他們模擬了一個8KB單級緩存,miss penalty 14個周期(90年代初的典型配置)。
結(jié)果發(fā)現(xiàn):SPECINT92基準(zhǔn)測試中,處理器因為緩存miss停頓的時間占總執(zhí)行時間的比例高達(dá)20-30%。這意味著每5條指令就有1條在等內(nèi)存。
2. 無阻塞緩存的兩級優(yōu)化
無阻塞緩存不是單一技術(shù),而是兩個層次的優(yōu)化:
2.1 Hit Under Miss(缺失時命中)
核心思想:前面有個load miss了,后面的load如果hit,照樣可以服務(wù)。
效果:Farkas & Jouppi的測試顯示[2],允許1個hit under miss時:
- SPECINT92:有效miss penalty降低20%
- SPECFP92:有效miss penalty降低30%
FP程序提升更明顯,因為科學(xué)計算常有規(guī)律的內(nèi)存訪問模式,miss后緊接著的訪問往往還在緩存里。
2.2 Miss Under Miss(缺失時缺失)
核心思想:允許同時發(fā)出多個內(nèi)存請求,重疊它們的延遲。
這需要內(nèi)存系統(tǒng)支持多未完成請求(Multiple Outstanding Requests)?,F(xiàn)代DDR內(nèi)存控制器可以管理幾十個待處理的請求,通過bank-level parallelism提升帶寬。
效果:Li等人在2011年更新了這項研究[3],基于Intel Core i7-like模型測試SPEC2006:
| 允許重疊的miss數(shù) | SPECINT2006延遲降低 | SPECFP2006延遲降低 |
|---|---|---|
| 1個hit under miss | ~9% | ~12.5% |
| 2個miss under miss | ~9% | ~12.5% |
| 64個miss under miss | ~9% | ~12.5% |
有趣的是,現(xiàn)代處理器中,單純增加miss under miss的數(shù)量收益有限。因為:
- L3緩存已經(jīng)很大(8-32MB),L2 miss rate本身就很低
- 亂序執(zhí)行處理器本身就能掩蓋部分延遲
- 內(nèi)存帶寬成為瓶頸,同時發(fā)太多請求反而沖突
3. 硬件實現(xiàn):MSHR
無阻塞緩存的核心部件是MSHR(Miss Status Handling Register,缺失狀態(tài)處理寄存器)[4]。
3.1 MSHR是干嘛的
當(dāng)緩存miss時,MSHR記錄:
- 缺失的內(nèi)存地址
- 請求類型(load/store)
- 目標(biāo)寄存器(load的話)
- 等待該數(shù)據(jù)的后續(xù)指令列表
一個MSHR條目對應(yīng)一個正在處理的miss。條目數(shù)決定了能同時處理的miss數(shù)量。
3.2 實際芯片的MSHR配置
| 處理器 | L1D MSHR | L2 MSHR | 備注 |
|---|---|---|---|
| DEC Alpha 21164[5] | 6 entries (MAF) | 2 entries (BAF) | 1995年經(jīng)典設(shè)計 |
| Intel Core i7[3] | 10+ entries | 16+ entries | 支持復(fù)雜亂序執(zhí)行 |
| NVIDIA GPU[6] | 16 entries | 128 entries | 高并行需求 |
| ARM Cortex-A77 | 有限支持 | 有限支持 | 移動端簡化設(shè)計 |
Alpha 21164的MSHR叫MAF(Miss Address File),6個條目。這6個條目不僅記錄miss,還合并對同一塊緩存行的多次訪問。比如:
// 假設(shè)addr1和addr2在同一緩存行(64字節(jié)對齊)
load r1, [addr1] // miss,分配MAF entry 0
load r2, [addr2] // 同一塊,合并到entry 0,不新增請求
這樣內(nèi)存控制器只發(fā)一次請求,但兩個load都能得到滿足。
3.3 MSHR的硬件結(jié)構(gòu)
簡化版MSHR條目結(jié)構(gòu):
// MSHR Entry 簡化結(jié)構(gòu)
module mshr_entry (
input valid, // 該條目是否有效
input [31:0] miss_addr, // 缺失的物理地址
input [3:0] block_offset, // 塊內(nèi)偏移(用于merge檢查)
input is_load, // 是load還是store
input [4:0] dest_reg, // load的目標(biāo)寄存器
input [7:0] waiting_mask, // 等待該數(shù)據(jù)的指令位圖
output filled // 數(shù)據(jù)是否已從內(nèi)存返回
);
// 同一塊檢查邏輯
wire same_block = (addr[31:6] == miss_addr[31:6]);
wire can_merge = valid & same_block & ~filled;
endmodule
MSHR需要支持:
- 分配:新miss時找空閑條目
- 合并:檢查新請求是否匹配已有條目
- 喚醒:數(shù)據(jù)返回時通知所有等待者
- 釋放:數(shù)據(jù)填入緩存后回收條目
4. 經(jīng)典案例:DEC Alpha 21164
DEC Alpha 21164是1995年發(fā)布的處理器,最早實現(xiàn)完整無阻塞緩存的商用芯片之一[5][7]。
4.1 緩存層次
| 層級 | 大小 | 相聯(lián)度 | 延遲 | 特性 |
|---|---|---|---|---|
| L1I | 8KB | 直接映射 | 1 cycle | 指令緩存 |
| L1D | 8KB | 直接映射 | 2 cycles | 雙端口,無阻塞 |
| L2 | 96KB | 3-way | 8 cycles | 片上,write-back |
| L3 | 可選 | 直接映射 | 12+ cycles | 片外 |
4.2 無阻塞機(jī)制
21164的L1D支持:
- 6-entry MAF:位于L1和L2之間,緩存L1 miss的地址
- 2-entry BAF:位于L2和外部內(nèi)存之間,管理L2 miss
- Load合并:最多21個load可以合并到同一個MAF entry
- 雙端口:每周期可以服務(wù)2個load hit,即使正在處理miss
關(guān)鍵設(shè)計:21164的L1D是write-through的,所有store直接下推到L2。這樣L1只需要處理load的miss,簡化了MSHR設(shè)計。
4.3 性能數(shù)據(jù)
21164在300MHz時達(dá)到:
- SPECint92:約345分
- SPECfp92:約505分
作為對比,同期Intel Pentium(66MHz)大約只有200分。無阻塞緩存是21164高性能的關(guān)鍵因素之一。
5. 現(xiàn)代處理器的演進(jìn)
5.1 Intel Core系列
現(xiàn)代Intel Core處理器(i3/i5/i7/i9)繼承了無阻塞緩存設(shè)計,但更加復(fù)雜:
- L1D:32KB,8-way,4-cycle延遲,支持hit under miss
- L2:256-512KB,支持miss under miss
- L3:8-32MB,共享,支持大量并發(fā)miss
Intel的MSHR設(shè)計不公開具體條目數(shù),但從性能反推,L1D大約支持10-16個未完成請求,L2支持更多。
5.2 移動端 vs 桌面端差異
| 特性 | 桌面/服務(wù)器(Core i7) | 移動端(ARM A77) |
|---|---|---|
| L1D MSHR | 多條目(10+) | 有限或沒有 |
| L2 MSHR | 支持 | 有限支持 |
| 設(shè)計重點 | 吞吐量最大化 | 功耗/面積優(yōu)化 |
| 亂序執(zhí)行 | 深度(192+ entries ROB) | 中等(128 entries) |
ARM Cortex-A77的L1D實際上是有阻塞的,或者說只支持非常有限的非阻塞能力。因為移動端:
- 功耗敏感,MSHR消耗靜態(tài)功耗
- 內(nèi)存帶寬有限,同時發(fā)多個請求收益小
- 工作負(fù)載不同,移動應(yīng)用緩存miss模式更簡單
6. 什么時候無阻塞緩存沒用
不是所有場景都能從無阻塞緩存受益。
6.1 順序執(zhí)行處理器
如果處理器是順序執(zhí)行的(如簡單的嵌入式MCU),一條指令不完成,后面的指令不能發(fā)射。這時候無阻塞緩存幫不上忙,因為后面的load根本進(jìn)不來。
6.2 內(nèi)存帶寬瓶頸
如果內(nèi)存控制器已經(jīng)飽和,同時發(fā)更多請求只會增加排隊延遲,不會提升吞吐量。這時候需要更大緩存或更快內(nèi)存,而不是更深的MSHR。
6.3 單線程順序訪問
// 指針追逐,每次訪問依賴前一次結(jié)果
while (node) {
node = node->next; // 必須等這次load完成才能知道下一次地址
}
這種代碼無法利用hit under miss,因為下一次訪問地址依賴于當(dāng)前l(fā)oad的結(jié)果。亂序執(zhí)行也幫不上忙。
7. 總結(jié)
無阻塞緩存通過MSHR結(jié)構(gòu),讓CPU在等待慢速內(nèi)存時也能處理其他請求。關(guān)鍵要點:
| 技術(shù) | 效果 | 硬件代價 |
|---|---|---|
| Hit Under Miss | 降低20-30%有效miss penalty | MSHR條目,合并邏輯 |
| Miss Under Miss | 重疊多個內(nèi)存延遲 | 更多MSHR條目,內(nèi)存控制器支持 |
設(shè)計權(quán)衡:
- 高性能處理器(服務(wù)器/桌面):深MSHR,支持大量并發(fā)miss
- 低功耗處理器(移動/嵌入式):簡化或省略MSHR,節(jié)省面積功耗
歷史意義:從1994年Farkas & Jouppi的理論研究,到1995年Alpha 21164的首次商用實現(xiàn),再到現(xiàn)代Intel/AMD/ARM處理器的標(biāo)配,無阻塞緩存已成為高性能CPU的基石技術(shù)。
參考
-
Farkas, K. I., & Jouppi, N. P. (1994). Complexity/performance tradeoffs with non-blocking loads. ACM SIGARCH Computer Architecture News, 22(2), 211-222. ?
-
計算機(jī)體系結(jié)構(gòu):量化研究方法(第5版),第2章:內(nèi)存層次設(shè)計優(yōu)化。 ?
-
Li, S., Chen, K., Brockman, J. B., & Jouppi, N. P. (2011). Performance impacts of non-blocking caches in out-of-order processors. HP Labs Technical Report HPL-2011-65. ? ?
-
Kroft, D. (1981). Lockup-free instruction fetch/prefetch cache organization. ISCA 1981. ?
-
DEC Alpha 21164 Microprocessor Hardware Reference Manual, EC-QAEQBTE, Digital Equipment Corporation, 1994. ? ?
-
LATPC: Accelerating GPU Address Translation Using Locality-Aware TLB Prefetching and MSHR Compression. MICRO 2024. ?
-
Edmondson, J. H., et al. (1995). Superscalar instruction execution in the 21164 Alpha microprocessor. IEEE Micro. ?