一文深入分析arm64 cache機(jī)制
說(shuō)明:
Kernel版本:4.14
ARM64處理器,Contex-A53,雙核
使用工具:Source Insight 3.5, Visio
1. 概述
先來(lái)看一下經(jīng)典的存儲(chǔ)器層次結(jié)構(gòu)圖:

不同存儲(chǔ)器技術(shù)的訪問(wèn)時(shí)間差異很大,CPU和主存的速度差距在增大,如果直接從主存進(jìn)行數(shù)據(jù)的load/store,CPU的大部分時(shí)間將會(huì)處在等待的狀態(tài);
cache的作用就是來(lái)解決CPU與主存的速度不匹配問(wèn)題;
以ARMv8的CPU架構(gòu)為例:

ARMv架構(gòu)的CPU通常包含兩級(jí)或多級(jí)cache;
L1 cache為Core所獨(dú)享的,通常包含Instruction cache和Data cache;
L2 cache為同一個(gè)Cluster中的多個(gè)Core進(jìn)行共享;
L3 cache通常實(shí)現(xiàn)為外部的硬件模塊,可以在Cluster之間進(jìn)行共享,或者與其他IP進(jìn)行共享;
接下來(lái)讓我們對(duì)cache一探究竟。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書(shū)籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書(shū)、實(shí)戰(zhàn)項(xiàng)目及代碼)??


2. cache
2.1 cache結(jié)構(gòu)
先看一下cache的內(nèi)部結(jié)構(gòu)圖:

cache line
:cache按行來(lái)組織,它是訪問(wèn)cache的最小單位,通常為16、32、64或128字節(jié),cache line
的大小通常在架構(gòu)設(shè)計(jì)階段確定;64-bit address
:CPU訪問(wèn)cache的地址編碼,分成三部分:Tag
、Index
、Offset
;Index
:地址編碼中的index域,用于索引cache line
;Offset
:地址編碼中的offset域,cache line
中的偏移量,可按word
和byte
來(lái)尋址;Tag
:Tag
在cache中占用實(shí)際的物理空間,用于存儲(chǔ)緩存地址的高位部分,通過(guò)與地址編碼中的Tag
域進(jìn)行比較來(lái)確定是否cache hit
;Way
:cache分成大小相同的子塊,每個(gè)子塊以相同的方式進(jìn)行索引;Set
:所有Way
中相同的索引對(duì)應(yīng)的cache line
組成的集合;
2.2 cache映射
2.2.1 direct mapped
直接映射的方式如下:

圖中的示例cache只有四個(gè)緩存行,內(nèi)存中
index域
相同的地址,都會(huì)映射到cache中的同一行上;圖中所示,
0x00,0x40,0x80
三個(gè)地址會(huì)映射到cache的第一行,而同一時(shí)刻只能允許1行;如果有程序訪問(wèn)區(qū)域覆蓋了這三個(gè)地址,可能造成cache line的頻繁換入換出,從而導(dǎo)致
cache thrashing
(顛簸)問(wèn)題;優(yōu)點(diǎn)是硬件設(shè)計(jì)簡(jiǎn)單,成本低,缺點(diǎn)是cache顛簸造成性能問(wèn)題;
2.2.2 set associative
組相連的映射方式如下:

組相聯(lián)方式在現(xiàn)代處理器中得到廣泛的使用;
圖中示例有兩路cache,因此每組有兩個(gè)緩存行;
每個(gè)內(nèi)存地址在映射時(shí),有兩個(gè)緩存行可以選擇,替換出去的概率降低了,這也就有效的降低了cache顛簸;
優(yōu)點(diǎn)是減少了cache顛簸,缺點(diǎn)是成本和復(fù)雜度增大;
2.2.3 fully associative
全相連的映射方式如下:

內(nèi)存地址不需要
index域
,全相連緩存相當(dāng)是N路集中的所有緩存行,因此需要大量的比較器;優(yōu)點(diǎn)是最大程度降低cache顛簸,缺點(diǎn)依然是復(fù)雜度和成本問(wèn)題;
2.3 cache策略
Read allocation(RA) 當(dāng)讀操作
cache miss
時(shí)默認(rèn)進(jìn)行分配cache line
;Write allocation(WA) 當(dāng)寫操作
cache miss
時(shí),會(huì)觸發(fā)一個(gè)burst讀,通過(guò)讀的方式來(lái)分配cache line
,然后再將數(shù)據(jù)寫入cache;Write-back(WB) WB方式下,數(shù)據(jù)只寫入cache,并標(biāo)記為dirty,當(dāng)
cache line
被換出或者顯式的clean操作才會(huì)更新到外部?jī)?nèi)存中,如下圖:

Write-through(WT) WT方式下,數(shù)據(jù)同時(shí)寫入cache和外部?jī)?nèi)存,不會(huì)將
cache line
標(biāo)記為dirty,如下圖:

2.4 cache分類
先來(lái)看看cache中的重名(aliasing
)問(wèn)題和同名(homonyms
)問(wèn)題:

aliasing
:多個(gè)不同的虛擬地址可能映射到相同的物理地址;引入的問(wèn)題包括:1)浪費(fèi)cache的空間,造成性能下降;2)寫操作時(shí)可能造成cache數(shù)據(jù)更新不一致,造成物理地址在cache中維護(hù)多個(gè)不同的數(shù)據(jù);

homonyms
:相同的虛擬地址映射到不同的物理地址;引入的問(wèn)題:比如進(jìn)程切換時(shí),上一個(gè)進(jìn)程的相同虛擬地址在cache中的數(shù)據(jù),對(duì)于本進(jìn)程無(wú)用,需要額外的
invalidate
操作;
2.4.1?VIVT
(Virtually-Indexed Virtually-Tagged
)

VIVT:處理器使用虛擬地址來(lái)進(jìn)行cache的尋址操作,使用虛擬地址的
Tag域
和Index域
進(jìn)行判斷是否hit;導(dǎo)致cache重名問(wèn)題(Index域?qū)е拢┡c同名問(wèn)題(Tag域?qū)е拢?,?dāng)改變虛擬地址到物理地址映射時(shí),需要
flush
和invalidate
操作,導(dǎo)致性能下降;
2.4.2?PIPT
(Physically-Indexed Physically-Tagged
)

PIPT:處理器使用物理地址進(jìn)行cache的尋址操作,使用物理地址的
Tag域
和Index域
進(jìn)行判斷是否hit;處理器在查詢cache時(shí),需要先查詢MMU/TLB后才能訪問(wèn),增加了pipeline的時(shí)間;
能有效避免重名和同名問(wèn)題,但是硬件的設(shè)計(jì)復(fù)雜度和成本更高;
2.4.3?VIPT
(Virtually-Indexed Physically-Tagged
)

VIPT:使用虛擬地址的
Index域
和物理地址的Tag域
進(jìn)行判斷是否cache hit;使用物理地址的
Tag域
(物理Tag唯一),能有效的避免同名問(wèn)題;VIPT也可能存在重名問(wèn)題,以Linux為例,Linux內(nèi)核以4KB的頁(yè)面大小進(jìn)行管理,虛擬地址和物理地址的[11:0]是相同的,重名問(wèn)題下多個(gè)虛擬地址的[11:0]是一樣的。當(dāng)index索引域在[11:0]之內(nèi)時(shí),不會(huì)發(fā)生重名問(wèn)題,因?yàn)樵摲秶鷮儆谝粋€(gè)頁(yè)面內(nèi);
3. mesi
先來(lái)看問(wèn)題的引入:

圖中的cluster,不同CPU core的cache和DDR中可能維護(hù)了同一個(gè)數(shù)據(jù)的多個(gè)副本;
維護(hù)cache的一致性,需要跟蹤cache行的狀態(tài),ARM采用MESI協(xié)議(
snooping protocol
)來(lái)維護(hù)cache的一致性;
MESI協(xié)議的名字來(lái)源于cache line的四個(gè)狀態(tài):
Modified(M)
:cache line數(shù)據(jù)有效,cache line數(shù)據(jù)被修改,與內(nèi)存中的數(shù)據(jù)不一致,修改的數(shù)據(jù)只存在本cache中;Exclusive(E)
:cache line數(shù)據(jù)有效,cache line數(shù)據(jù)和內(nèi)存中一致,數(shù)據(jù)只存在本cache中;Shared(S)
:cache line數(shù)據(jù)有效,cache line數(shù)據(jù)和內(nèi)存中一致,數(shù)據(jù)存在于多個(gè)cache中;Invalid(I)
:cache line數(shù)據(jù)無(wú)效;
狀態(tài)說(shuō)明如下:
M和E狀態(tài),數(shù)據(jù)都是本地獨(dú)有的,不同點(diǎn)在于M狀態(tài)的數(shù)據(jù)是臟的,而E狀態(tài)的數(shù)據(jù)是干凈的,M狀態(tài)的cache line寫回內(nèi)存后,狀態(tài)變成了S;
S狀態(tài)的cache line,數(shù)據(jù)和其他cache共享,只有干凈的數(shù)據(jù)才能被多個(gè)cache共享;

MESI協(xié)議在總線上的操作分為兩大類:CPU請(qǐng)求和總線請(qǐng)求,如下圖:

MESI協(xié)議中涉及到各個(gè)狀態(tài)的轉(zhuǎn)換:
本地CPU操作,狀態(tài)轉(zhuǎn)換如下圖:

操作為本地CPU讀寫
總線監(jiān)聽(tīng)到其他CPU的操作請(qǐng)求,狀態(tài)轉(zhuǎn)換如下圖:

操作類型為總線讀寫,來(lái)自其他CPU的請(qǐng)求,或者DMA的操作等;
當(dāng)多個(gè)cpu訪問(wèn)同一個(gè)cache line中的不同數(shù)據(jù)時(shí),根據(jù)MESI協(xié)議,容易造成cache的偽共享問(wèn)題,解決方式是讓多線程操作的數(shù)據(jù)處在不同的cache line中。
原文作者:LoyenWang
