Cache的基本概念和使用场景
不同的Master硬件共享数据时---invalid cache
外设和DDR之间没有cache,所以外设直接把数据写入DDR中,但是cpu和DDR之间有cache,cpu会首先访问cache,如果命中直接从cache中拿数据,但是此时的cache并不是最新的数据,cache没有刷新,就拿不到DDR中的数据。此时的解决办法就是在cpu读取数据之前,让cache中的缓存无效,这样就会直接从DDR中读取数据。
不同的Master硬件共享数据时---flush cache
同样还有下面情况,需要刷新cache
不同的缓存策略的系统共享数据时---flush cache
不同的缓存策略的系统共享数据时---invalid cache
操作系统中软件维护cache一致性的API
void __flush_icache_range(unsigned long start, unsigned long end);
int invalidate_icache_range(unsigned long start, unsigned long end);
void __flush_dcache_area(void *addr, size_t len);
void __inval_dcache_area(void *addr, size_t len);
void __clean_dcache_area_poc(void *addr, size_t len);
void __clean_dcache_area_pop(void *addr, size_t len);
void __clean_dcache_area_pou(void *addr, size_t len);
long __flush_cache_user_range(unsigned long start, unsigned long end);
void sync_icache_aliases(void *kaddr, unsigned long len);
void flush_icache_range(unsigned long start, unsigned long end)
void __flush_icache_all(void)
modified的数据地址,在执行invalidate的时候,会先自动执行clean。即
DC IVAC等效于DC CIVAC
cache指令
为什么要用cache?
ARM 架构刚开始开发时,处理器的时钟速度和内存的访问速度大致相似。今天的处理器内核要复杂得多,并且时钟频率可以快几个数量级。然而,外部总线和存储设备的频率并没有达到同样的程度。可以实现可以与内核以相同速度运行的小片上 SRAM 块,但与标准 DRAM 块相比,这种 RAM 非常昂贵,标准DRAM 块的容量可能高出数千倍。在许多基于 ARM 处理器的系统中,访问外部存储器需要数十甚至数百个内核周期。缓存是位于核心和主内存之间的小而快速的内存块。它在主内存中保存项目的副本。对高速缓冲存储器的访问比对主存储器的访问快得多。每当内核读取或写入特定地址时,它首先会在缓存中查找。如果它在高速缓存中找到地址,它就使用高速缓存中的数据,而不是执行对主存储器的访问。通过减少缓慢的外部存储器访问时间的影响,这显着提高了系统的潜在性能。通过避免驱动外部信号的需要,它还降低了系统的功耗。
怎么去刷cache呢? (软件维护cache的一致性)
ARM提供了操作cache的指令, 软件维护操作cache的指令有三类:
• Invalidation:其实就是修改valid bit,让cache无效。
• Cleaning: 这其实就是我们所说的flush cache,这里就是清除dirty标志,这里会将cache数据回写到内存
• Zero:将cache中的数据清0.
那么一般什么时候需要软件维护cache一致性呢?
(1)、当有其它的Master改变的external memory,如DMA操作
(2)、MMU的enable或disable的整个区间的内存访问,
(3)、当不同缓存策略的系统使用同一块内存通信时,如REE enable了mmu,TEE disable了mmu.
cache一致性指令介绍
总结
按照指令,分为:
• IC : 操作instruction cache,指令cache
• DC : 操作data cache,数据cache
point:刷cache刷到哪个位置
U:一般L1刷到L2
C:从L2往后刷完
IS:刷哪些范围中的cache
按照操作,分为以下三类:
• Invalidation:其实就是修改valid bit,让cache无效。
• Cleaning: 清除cache中的data和TAG,这其实就是我们所说的flush cache,这里会将cache数据回写到内存,并清除dirty标志
• Zero:将cache中的数据清0.
可以以指定只刷L1或L2或L3 cache
Cache的架构
big.LITTLE 和 dynamIQ架构的cache
• 在big.LITTLE 架构中,大核小核在不同的cluster中,做为两个不同的ACE或CHI Master,连接到缓存一致性总线上(CCI或CMN)。大核cluster和小核cluster的缓存一致性,也需要通过一致性总线来解决。
• 到了DynamIQ 架构中,大核和小核都是一个DSU cluster中,一个DSU cluster最多可以支持8个core。如果你的系统是8个core,那么一个DSU就够了,那么系统中也就只有一个ACE或CHI Master,大核和小核之间的一致性,都在DSU cluster内
完成了
dynamIQ架构的cache
Cache是多级相连的
cache是多级的,在一个系统中你可能会看到L1、L2、L3, 当然越靠近core就越小,也是越昂贵。一般来说,对于big.LITTLE架构中,在L1是core中,L1又分为L1 data cache和 L1 Instruction cache, L2 cache在cluster中,L3则在BUS总线上。
cache的种类(VIVT,PIPT,VIPT)
在一个core中一个架构中一个SOC中,你所使用的cache是哪种类型的,都是固定的,是软件改不了的。
在ARM架构中,一般L1 cache都是VIPT的,其余的都是PIPT的。
L1、L2 和 L3 缓存:有什么区别?
三级高速缓存之间的主要区别在于大小、速度以及它们所在的位置。
• L1 缓存的存储容量较低,但通常是计算机中最快的内存,比 RAM 快 100 倍。每个处理器核心都有自
己的 L1 缓存,通常约为 64KB。
• L2 缓存可能比 L1 大几倍,但速度仅为 RAM 的 25 倍左右。与 L1 一样,每个处理器核心都有自己的
L2 缓存。每个通常为 256-512KB,有时高达 1MB。
• L3 缓存具有最大的存储容量,通常为 32MB 或更多,但速度可能仅为系统内存的两倍。L3 缓存通常嵌
入在 CPU 中,但与内核分开。
cache的组织形式(index, way, set)
cache的术语概念
• index : 用白话理解,其实就是在一块cache中,一行一行的编号(事实是没有编号/地址的)
• Set :用index查询到的cache line可能是多个,这些index值一样的cacheline称之为一个set
• way:用白话来说,将cache分成了多个块(多路),每一块是一个way
• cache TAG :查询到了一行cache后,cachelne由 TAG + DATA组成
• cache Data :查询到了一行cache后,cachelne由 TAG + DATA组成
• cache Line 和 entry 是一个概念
cache的分配策略(alocation,write-through, write-back)
读分配(read allocation)
当CPU读数据时,发生cache缺失,这种情况下都会分配一个cache line缓存从主存读取的数据。默认情况下,cache都支持读分配。
写分配(write allocation)
当CPU写数据发生cache缺失时,才会考虑写分配策略。当我们不支持写分配的情况下,写指令只会更新主存数据,然后就结束了。当支持写
分配的时候,我们首先从主存中加载数据到cache line中(相当于先做个读分配动作),然后会更新cache line中的数据。
写直通(write through)
当CPU执行store指令并在cache命中时,我们更新cache中的数据并且更新主存中的数据。cache和主存的数据始终保持一致。
写回(write back)
当CPU执行store指令并在cache命中时,我们只更新cache中的数据。并且每个cache line中会有一个bit位记录数据是否被修改过,称之为dirty
bit(翻翻前面的图片,cache line旁边有一个D就是dirty bit)。我们会将dirty bit置位。主存中的数据只会在cache line被替换或者显示的clean
操作时更新。因此,主存中的数据可能是未修改的数据,而修改的数据躺在cache中。cache和主存的数据可能不一致。
cache hit/miss hint的概念
命中(Hit):
当处理器需要访问内存中的数据或指令时,首先会在缓存中查找该数据或指令。
如果缓存中已经包含了所需的数据或指令,则称为"命中"(hit),处理器可以直接从缓存中获取数据,无
需访问主存。
命中通常导致较快的访问速度,因为缓存具有更快的访问时间和更短的延迟。
未命中(Miss):
如果处理器在缓存中未找到所需的数据或指令,则称为"未命中"(miss)。
在发生未命中时,处理器需要从主存中获取所需的数据或指令,然后将其加载到缓存中,以便日后的访问。
未命中通常导致较长的访问延迟,因为需要从相对较慢的主存中加载数据。
命中和未命中的概念可以用来评估缓存系统的性能和效率。高命中率通常表示缓存系统能够有效地提高访
问速度,因为大部分数据都能在缓存中找到。而较高的未命中率可能表明缓存容量不足、替换策略不佳或
者访问模式不合理,需要进行性能优化。
cache的查询原理
cache的层级
cache缓存形式
cache的查询过程
先使用index去查询cache,然后再比较TAG,比较tag的时候还会检查valid标志位
歧义
歧义(ambiguity)也称Homonyms(同名异物)是指一个VA对应不同的PA。例如两个不同的进程,虚拟内
存的地址互相独立,两个不同进程中的相同虚拟内存地址会指向不同的物理内存地址。
歧义主要是因为virtual tag引起的。因为两个不同进程的相同virtual tag可能对应两个不同的physical tag。那么当进程发生切换时,新来的进程B在使用VIVT访问Cache时,很有可能把上一个进程的virtual tag给hit了!!但实际上对应的是不同的physical tag!!这种情况可以使用flush解决:即当发生进程切换时,将Cache flush(clean+invalid)掉,然后再切换到新进程。
同一地址数据(虚拟地址)缓存到了不同的cache中
重名/别名
重名(aliasing),也称Synonyms(同物异名):重名即指多个不同的VA共享同一个PA。
不同地址数据(虚拟地址)缓存到了相同的cache中
解决重名问题:
1、如引入一个新功能:page color
2、物理TAG从BIT12开始
怎样去维护多核多系统缓存的一致性
有三种机制可以保持一致性:
- 禁用缓存是最简单的机制,但可能会显着降低 CPU 性能。为了获得最高性能,处理器通过管道以高频率运行,并从提供极
低延迟的缓存中运行。缓存多次访问的数据可显着提高性能并降低 DRAM 访问和功耗。将数据标记为"非缓存"可能会影响
性能和功耗。 - 软件管理的一致性是数据共享问题的传统解决方案。在这里,软件(通常是设备驱动程序)必须清除或刷新缓存中的脏数
据,并使旧数据无效,以便与系统中的其他处理器或主设备共享。这需要处理器周期、总线带宽和功率。 - 硬件管理的一致性提供了一种简化软件的替代方案。使用此解决方案,任何标记为"共享"的缓存数据将始终自动更新。该
共享域中的所有处理器和总线主控器看到的值完全相同。
Cluster中的缓存一致性
同一个cluster中多core之间的缓存一致性由DSU(big.LITTLE叫SCU)来维护,遵循MESI协议。
多Master之间的缓存一致性
Master分为以下几类:
• ACE Master : 如 big.LITTLE cluster 或 DSU
cluster
• CHI Master : 如 big.LITTLE cluster 或 DSU
cluster
• ACE-lite Master: 如 GPU cluster
• I/O Device Master : 如 DMA
以下是多Master之间的缓存一致性的结论:
• 首先,CHI/ACE总线都是支持MESI协议数据传输的
• Master与I/O Device Master之间没有一致性,因为I/O Device没有链接到CCI/CMN缓存互联总线上。
• 多个ACE/CHI Master之间的缓存一致性,是否遵循MESI,要具体情况具体分析,简而言之就是:
(1) 如果两个Master都支持带MESI状态位,支持带有MESI信号的读写,那么这两个Master缓存一致性是遵从MESI协议的
(2) 如果有一个Master不支持带MESI状态位,那么这个Master就无法支持带有MESI信号的读写,那么这两个Master缓存一致性是不遵从MESI协议的
(3) Master的MESI状态位,是在该Master的cache的TAG中。
• ACE/CHI Master和ACE-lite Master之间的缓存一致性,是不遵从MESI协议的。这主要是因为ACE/CHI Master无法snoop ACE-lite Master的内存,而ACE-lite Master却可以snoop ACE/CHI Master的内存,总得来说,这不是一个完整的MESI协议。
两个DSU cluster的L3 cache中的TAG中,是有MESI比特位的,这两个DSU通过ACE/CHI 接口发起的读写是带有MESI信号的,所以他们是支持MESI协议的。
dynamIQ架构同一个core中的L1和L2 cache
dynamIQ架构core中的L1和L2 cache不存在缓存一致性的问题,但有分配和替换策略。
下DynamIQ架构中的cache中新增的几个概念:
• (1) Strictly inclusive: 所有存在L1 cache中的数据,必然也存在L2 cache中
• (2) Weakly inclusive: 当miss的时候,数据会被同时缓存到L1和L2,但在之后,L2中的数据可能会被替换
• (3) Fully exclusive: 当miss的时候,数据只会缓存到L1
其实inclusive/exclusive属性描述的正是是 L1和L2之间的替换策略,这部分是硬件定死的,软件不可更改的。
• L1 I-cache和L2之间是 weakly inclusive的
• L1 D-cache和L2之间是 strictly inclusive的
也就是说:
• 当发生D-cache发生miss时,数据缓存到L1 D-cache的时候,也会被缓存到L2 Cache中,当L2 Cache被替换时,L1 D-cache也会跟着被替换
• 当发生I-cache发生miss时,数据缓存到L1 I-cache的时候,也会被缓存到L2 Cache中,当L2 Cache被替换时,L1 I- cache不会被替换。
所以总结一下就是 : L1 和 L2之间的cache的替换策略,针对I-cache和D-cache可以是不同的策略,每一个core都有每一个core的做法,这部
分是硬件决定的,请查阅你使用core的TRM手册。
Mesi协议的范围
Mesi协议状态切换
Events:
• RH = Read Hit
• RMS = Read miss, shared
• RME = Read miss, exclusive
• WH = Write hit
• WM = Write miss
• SHR = Snoop hit on read
• SHI = Snoop hit on invalidate
• LRU = LRU replacement
• Bus Transactions:
• Push = Write cache line back to memory
• Invalidate = Broadcast invalidate
• Read = Read cache line from memory
cache的安全访问
cache中的安全比特;
首先看到core,core中有一个SCR寄存器,寄存器中有一个NS比特位可以表示当前core所处的是安全还是非安全,NS=1非安全,NS=0安全。寄存器的值只能EL3修改,因此只有双系统切换时(安全状态和非安全状态切换时,会经过ATF)才能修改。
core最后要访问memory,中间隔了一个TZC,TZC可以配置memory的权限,是Secure memory还是Non-Secure memory,还有一个的作用就是过滤,如果是非安全的cpu要访问Secure memory会被挡住,无法访问;如果是安全的cpu,TZC都会放行。
看第二步,如果是secure的cpu那么MMU必然就是Secure Transaction Regime,然后就要看entry中的NS比特位,如果NS为1就代表发起Non-Secure Access;如果NS为0,就代表发起Secure Access。;如果是Non-secure的cpu那么使用的MMU就是Non Secure Transaction Regime,下面也永远是Non-Secure Access,不用看NS比特位。
再回看第一步,如果cpu在访问内存时,已经在TLB中命中,就不会经过MMU的翻译,直接进行标号位1的路径,此时TLB的entry中有两个NSbit位,后面的NS就对应了第二步中entry的NS位,二者一致,就决定了接下来访问的安全状态。前面的NS代表了是Secure Transaction Regime还是Non Secure Transaction Regime。
页表entry中的NS比特位在软件中是可以修改的。
一个非安全侧的entry中NS=1,如果给它修改位0,那么可以访问安全的memory可以吗?答案是不可以的,因为是Non Secure Transaction Regime,它就不会看NS比特位,自然还是进行Non Secure Access。
如果在安全侧是secure Transaction Regime,那么访问的内存可以修改NS比特位吗?答案是可以的。