3. TLB的缓存策略:全相连、组相连、直接映射,以及SMMU中的实际选择
TLB说白了就是一张地址转换的“快查表”。但这张表怎么组织,直接决定了你查得快不快、命中率高不高、芯片面积烧不烧得起。我这些年调过不少TLB的坑,今天就把三种经典映射策略掰开揉碎了讲清楚。
3.1 三种映射策略的核心差异
先看一张对比表,心里有个底:
| 策略 | 查找方式 | 硬件开销 | 冲突率 | 典型场景 |
|---|---|---|---|---|
| 全相连 | 并行比较所有条目 | 极高(比较器多) | 最低 | 微TLB(L1 TLB) |
| 组相连 | 先索引组,再组内比较 | 中等 | 较低 | 主流SMMU主TLB |
| 直接映射 | 直接算位置,无比较 | 最低 | 最高 | 极少用,仅特殊场景 |
3.2 全相连(Fully Associative)
全相连的意思是:任何一个虚拟地址可以缓存在TLB的任意一个条目里。查找时,硬件把所有条目拿出来跟输入地址同时比——对,就是并行比较。
优点:几乎没有冲突miss。你想想看,只要TLB里有这条记录,不管它藏在哪个位置,一次比较就能找到。
缺点:每个条目都需要一个比较器。64条全相连TLB,就需要64个比较器。面积和功耗直线上升。
我在一个手机SoC项目里见过L1微TLB用全相连,条目数只有8~16条。为什么?因为微TLB追求极致命中延迟,全相连的并行比较可以在一个周期内出结果。但条目一多,比如32条以上,全相连的硬件代价就扛不住了。
实战建议:全相连适合条目少(≤16)、延迟敏感的场景。SMMU的微TLB(L1 TLB)常用这种策略。
3.3 直接映射(Direct-Mapped)
直接映射是另一个极端。每个虚拟地址只能缓存在TLB中唯一的一个位置。怎么算?拿地址的某些位做索引,直接定位到那个槽位。
举个例子:假设TLB有64个条目,地址的bit[5:0]做索引。那么虚拟地址0x1000和0x1040,因为索引相同,会竞争同一个条目。
我曾经踩过的坑:在一个DMA密集型场景里,驱动连续访问两个索引冲突的4K页面,导致TLB每两次访问就miss一次。性能直接腰斩。这就是直接映射的“颠簸效应”。
直接映射的硬件最简单——不需要比较器,只需要一个解码器。但冲突率太高,在现代SMMU里几乎绝迹。我只有在一些极低功耗的IoT芯片里见过它的影子。
3.4 组相连(Set-Associative)
组相连是前两者的折中方案。它把TLB分成若干组(set),每个虚拟地址先通过索引定位到某一组,然后在该组内做全相连查找。
比如一个4路组相连TLB,每组有4个条目。地址先算索引找到组,然后在这4个条目里并行比较。硬件上只需要4个比较器,而不是全相连的64个。
关键参数:相联度(associativity)。4路、8路、16路是常见选择。相联度越高,冲突越少,但硬件开销也越大。
我个人的经验是:SMMU的主TLB(L2 TLB)通常用4路或8路组相连。为什么?因为SMMU要服务多个设备,地址空间大,条目数动辄512甚至1024条。全相连根本做不了,直接映射又太容易冲突。组相连刚好平衡了命中率和硬件成本。
3.5 SMMU中的实际选择
好了,理论讲完,咱们看看SMMU里到底怎么选。我画了一张图,帮你理清层次:
从图上可以看得很清楚:SMMU内部是一个多级TLB层次。微TLB用全相连追求极致速度,主TLB用组相连平衡性能和面积。直接映射?我几乎没见过商用SMMU用它做主结构。
3.6 实战中的选择依据
如果你在选型或设计SMMU,我建议你按这个思路来:
- 先看条目数:少于16条,全相连是首选。多于64条,老老实实组相连。
- 再看延迟要求:微TLB必须1~2周期命中,全相连是唯一选择。主TLB可以容忍3~5周期,组相连足够。
- 最后看面积预算:组相连的相联度每翻一倍,比较器数量翻倍,面积涨约20%~30%。
我个人的经验法则:对于SMMU主TLB,4路组相连是“甜点区”。8路性能更好但面积涨得明显。除非你的设备有极端的时间局部性要求,否则4路够用。
3.7 一个真实案例
我记得有一次调试一个GPU的SMMU性能问题。GPU的TLB用了8路组相连,但某个特定工作负载下TLB miss率高达15%。我一看地址模式,发现GPU访问的页面地址在组索引位上规律跳动,导致大部分请求挤在同一个组里。
解决办法?不是改TLB设计,而是调整了页面着色(page coloring)策略,让地址分布更均匀。miss率直接降到3%以下。
教训:组相连不是万能的。地址模式的“伪冲突”依然会导致组内颠簸。这时候需要软件配合,或者考虑增加相联度。
好了,三种映射策略就讲到这里。记住一句话:全相连拼速度,组相连拼平衡,直接映射拼省钱——但在SMMU里,省钱往往意味着丢性能。