0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

cache的排布與CPU的典型分布

Linux閱碼場(chǎng) ? 來源:Linux閱碼場(chǎng) ? 作者:Linux閱碼場(chǎng) ? 2022-10-18 09:01 ? 次閱讀

CACHE 基礎(chǔ)

對(duì)cache的掌握,對(duì)于Linux工程師(其他的非Linux工程師也一樣)寫出高效能代碼,以及優(yōu)化Linux系統(tǒng)的性能是至關(guān)重要的。簡(jiǎn)單來說,cache快,內(nèi)存慢,硬盤更慢。在一個(gè)典型的現(xiàn)代CPU中比較接近改進(jìn)的哈佛結(jié)構(gòu),cache的排布大概是這樣的:

077cacec-4e7d-11ed-a3b6-dac502259ad0.png

L1速度>L2速度>L3速度>RAM
L1容量

現(xiàn)代CPU,通常L1 cache的指令和數(shù)據(jù)是分離的。
這樣可以實(shí)現(xiàn)2條高速公路并行訪問,CPU可以同時(shí)load指令和數(shù)據(jù)。當(dāng)然,cache也不一定是一個(gè)core獨(dú)享,現(xiàn)代很多CPU的典型分布是這樣的,比如多個(gè)core共享一個(gè)L3。

比如這臺(tái)的Linux里面運(yùn)行 lstopo 命令:

07996044-4e7d-11ed-a3b6-dac502259ad0.png

人們也常常稱呼L2cache為 MLC (MiddleLevel Cache), L3cache為 LLC(LastLevelCache)。

這些Cache究竟有多塊呢?

我們來看看Intel的數(shù)據(jù),具體配置:Intel i7-4770 (Haswell), 3.4 GHz (Turbo Boostoff), 22nm. RAM: 32 GB (PC3-12800 cl11 cr2)

訪問延遲:

L1DataCacheLatency=4cyclesforsimpleaccessviapointer
L1DataCacheLatency=5cyclesforaccesswithcomplexaddresscalculation(size_tn,*p;n=p[n]).
L2CacheLatency=12cycles
L3CacheLatency=36cycles(3.4GHzi7-4770)
L3CacheLatency=43cycles(1.6GHzE5-2603v3)
L3CacheLatency=58cycles(core9)-66cycles(core5)(3.6GHzE5-2699v3-18cores)
RAMLatency=36cycles+57ns(3.4GHzi7-4770)
RAMLatency=62cycles+100ns(3.6GHzE5-2699v3dual)

數(shù)據(jù)來源:https://www.7-cpu.com/cpu/Haswell.html

由此我們可以知道,我們應(yīng)該盡可能追求cache的命中率高,以避免延遲, 最好是低級(jí)cache的命中率越高越好。

CACHE 的組織

SET、WAY、TAG、INDEX

現(xiàn)代的cache基本按照這個(gè)模式來組織:SET、WAY、TAG、INDEX
,這幾個(gè)概念是理解Cache的關(guān)鍵。隨便打開一個(gè)數(shù)據(jù)手冊(cè),就可以看到這樣的字眼:

07bfa56a-4e7d-11ed-a3b6-dac502259ad0.png

但是它的執(zhí)行時(shí)間,則遠(yuǎn)遠(yuǎn)不到后者的8倍:

07f7f7d0-4e7d-11ed-a3b6-dac502259ad0.png

16KB 的cache是 4way 的話,每個(gè)set包括 4*64B ,則整個(gè)cache分為 16KB/64B/4 =64set
,也即2的6次方。當(dāng)CPU從cache里面讀數(shù)據(jù)的時(shí)候,它會(huì)用地址位的BIT6-BIT11來尋址set,BIT0-BIT5是cacheline內(nèi)的offset。

080c7a5c-4e7d-11ed-a3b6-dac502259ad0.png

比如CPU訪問地址

0 000000 XXXXXX

或者

1 000000 XXXXXX

或者

YYYY 000000 XXXXXX

由于它們紅色的6位都相同,所以他們?nèi)慷紩?huì)找到第0個(gè)set的cacheline。第0個(gè)set里面有4個(gè)way,之后硬件會(huì)用地址的高位如0,1,YYYY作為tag,去檢索這4個(gè)way的tag是否與地址的高位相同,而且cacheline是否有效,如果tag匹配且cacheline有效,則cache命中。

所以地址YYYYYY000000XXXXXX全部都是找第0個(gè)set,YYYYYY000001XXXXXX全部都是找第1個(gè)set,YYYYYY111111XXXXXX全部都是找第63個(gè)set。每個(gè)set中的4個(gè)way,都有可能命中。

中間紅色的位就是INDEX,前面YYYY這些位就是TAG。

具體的實(shí)現(xiàn)可以是用虛擬地址或者物理地址的相應(yīng)位做TAG或者INDEX。

如果用虛擬地址做TAG,我們叫VT;

如果用物理地址做TAG,我們叫PT;

如果用虛擬地址做INDEX,我們叫VI;

如果用物理地址做INDEX,我們叫PI。

工程中碰到的cache可能有這么些組合:VIVT、VIPT、PIPT。

VIVT、VIPT、PIPT

具體的實(shí)現(xiàn)可以是用虛擬地址或者物理地址的相應(yīng)位做TAG或者INDEX。

如果用虛擬地址做TAG,我們叫VT;

如果用物理地址做TAG,我們叫PT;

如果用虛擬地址做INDEX,我們叫VI;

如果用物理地址做INDEX,我們叫PI。

VIVT的硬件實(shí)現(xiàn)開銷最低,但是軟件維護(hù)成本高;PIPT的硬件實(shí)現(xiàn)開銷最高,但是軟件維護(hù)成本最低;VIPT介于二者之間,但是有些硬件是VIPT,但是behave
as PIPT,這樣對(duì)軟件而言,維護(hù)成本與PIPT一樣。

在VIVT的情況下,CPU發(fā)出的虛擬地址,不需要經(jīng)過MMU的轉(zhuǎn)化,直接就可以去查cache。

0819e0e8-4e7d-11ed-a3b6-dac502259ad0.png

而在VIPT和PIPT的場(chǎng)景下,都涉及到虛擬地址轉(zhuǎn)換為物理地址后,再去比對(duì)cache的過程。VIPT如下:

08428afc-4e7d-11ed-a3b6-dac502259ad0.png

PIPT如下:

085cdc0e-4e7d-11ed-a3b6-dac502259ad0.png

從圖上看起來,VIVT的硬件實(shí)現(xiàn)效率很高,不需要經(jīng)過MMU就可以去查cache了。不過,對(duì)軟件來說,這是個(gè)災(zāi)難。因?yàn)閂IVT有嚴(yán)重的歧義和別名問題。

歧義:一個(gè)虛擬地址先后指向兩個(gè)(或者多個(gè))物理地址

別名:兩個(gè)(或者多個(gè))虛擬地址同時(shí)指向一個(gè)物理地址

Cache別名問題

這里我們重點(diǎn)看別名問題。比如2個(gè)虛擬地址對(duì)應(yīng)同一個(gè)物理地址,基于VIVT的邏輯,無論是INDEX還是TAG,2個(gè)虛擬地址都是可能不一樣的(盡管他們的物理地址一樣,但是物理地址在cache比對(duì)中完全不摻和),這樣它們完全可能在2個(gè)cacheline同時(shí)命中。

086b0f2c-4e7d-11ed-a3b6-dac502259ad0.png

由于2個(gè)虛擬地址指向1個(gè)物理地址,這樣CPU寫過第一個(gè)虛擬地址后,寫入cacheline1。CPU讀第2個(gè)虛擬地址,讀到的是過時(shí)的cacheline2,這樣就出現(xiàn)了不一致。所以,為了避免這種情況,軟件必須寫完虛擬地址1后,對(duì)虛擬地址1對(duì)應(yīng)的cache執(zhí)行clean,對(duì)虛擬地址2對(duì)應(yīng)的cache執(zhí)行invalidate。

而PIPT完全沒有這樣的問題,因?yàn)闊o論多少虛擬地址對(duì)應(yīng)一個(gè)物理地址,由于物理地址一樣,我們是基于物理地址去尋找和比對(duì)cache的,所以不可能出現(xiàn)這種別名問題。

08a1dff2-4e7d-11ed-a3b6-dac502259ad0.png

那么VIPT有沒有可能出現(xiàn)別名呢?答案是有可能,也有可能不能。 如果VI恰好對(duì)于PI,就不可能,這個(gè)時(shí)候,VIPT對(duì)軟件而言就是PIPT了:

VI=PI
PT=PT

那么什么時(shí)候VI會(huì)等于PI呢?這個(gè)時(shí)候我們來回憶下虛擬地址往物理地址的轉(zhuǎn)換過程,它是以頁為單位的。假設(shè)一頁是4K,那么地址的低12位虛擬地址和物理地址是完全一樣的。回憶我們前面的地址:

YYYYY000000XXXXXX

其中紅色的000000是INDEX。在我們的例子中,紅色的6位和后面的XXXXXX(cache內(nèi)部偏移)加起來正好12位,所以這個(gè)000000經(jīng)過虛實(shí)轉(zhuǎn)換后,其實(shí)還是000000的,這個(gè)時(shí)候
VI=PI ,VIPT沒有別名問題。

我們?cè)燃僭O(shè)的cache是:16KB大小的cache,假設(shè)是4路組相聯(lián),cacheline的長度是 64字節(jié)
,這樣我們正好需要紅色的6位來作為INDEX。但是如果我們把cache的大小增加為32KB,這樣我們需要
32KB/4/64B=128=2^7,也即7位來做INDEX。

YYYY0000000XXXXXX

這樣VI就可能不等于PI了,因?yàn)榧t色的最高位超過了2^12的范圍,完全可能出現(xiàn)如下2個(gè)虛擬地址,指向同一個(gè)物理地址:

08b534a8-4e7d-11ed-a3b6-dac502259ad0.png

這樣就出現(xiàn)了別名問題,
我們?cè)诠こ汤?,可能可以通過一些辦法避免這種別名問題,比如軟件在建立虛實(shí)轉(zhuǎn)換的時(shí)候,把虛實(shí)轉(zhuǎn)換往2^13而不是2^12對(duì)齊,讓物理地址的低13位而不是低12位與物理地址相同,這樣強(qiáng)行繞開別名問題,下圖中,2個(gè)虛擬地址指向了同一個(gè)物理地址,但是它們的INDEX是相同的,這樣VI=PI,就繞開了別名問題。這通常是PAGE
COLOURING技術(shù)中的一種技巧。

08c8de0e-4e7d-11ed-a3b6-dac502259ad0.png

如果這種PAGE
COLOURING的限制對(duì)軟件仍然不可接受,而我們又想享受VIPT的INDEX不需要經(jīng)過MMU虛實(shí)轉(zhuǎn)換的快捷?有沒有什么硬件技術(shù)來解決VIPT別名問題呢?確實(shí)是存在的,現(xiàn)代CPU很多都是把L1
CACHE做成VIPT,但是表現(xiàn)地(behave as)像PIPT。這是怎么做到的呢?

這要求VIPT的cache,硬件上具備alias detection的能力。比如,硬件知道YYYY 0000000 XXXXXX既有可能出現(xiàn)在第
0000000 ,又可能出現(xiàn)在 1000000
這2個(gè)set,然后硬件自動(dòng)去比對(duì)這2個(gè)set里面是否出現(xiàn)映射到相同物理地址的cacheline,并從硬件上解決好別名同步,那么軟件就完全不用操心了。

下面我們記住一個(gè)簡(jiǎn)單的規(guī)則:

對(duì)于VIPT,如果cache的size除以WAY數(shù),小于等于1個(gè)page的大小,則天然VI=PI,無別名問題;

對(duì)于VIPT,如果cache的size除以WAY數(shù),大于1個(gè)page的大小,則天然VI≠PI,有別名問題;這個(gè)時(shí)候又分成2種情況:

硬件不具備alias detection能力,軟件需要pagecolouring;

硬件具備alias detection能力,軟件把cache當(dāng)成PIPT用。

比如cache大小64KB,4WAY,PAGE SIZE是4K,顯然有別名問題;這個(gè)時(shí)候,如果cache改為16WAY,或者PAGE
SIZE改為16K,不再有別名問題。為什么?感覺小學(xué)數(shù)學(xué)知識(shí)也能算得清

CACHE 的一致性

Cache的一致性有這么幾個(gè)層面

1.一個(gè)CPU的icache和dcache的同步問題

2.多個(gè)CPU各自的cache同步問題

3.CPU與設(shè)備(其實(shí)也可能是個(gè)異構(gòu)處理器,不過在Linux運(yùn)行的CPU眼里,都是設(shè)備,都是 DMA )的cache同步問題

09551d06-4e7d-11ed-a3b6-dac502259ad0.png

cache中的映射

1. 直接映射

一個(gè)內(nèi)存地址能被映射到的Cache line是固定的。就如每個(gè)人的停車位是固定分配好的,可以直接找到。缺點(diǎn)是:因?yàn)槿硕嘬囄簧?,很可能幾個(gè)人爭(zhēng)用同一個(gè)車位,導(dǎo)致Cache淘汰換出頻繁,需要頻繁的從主存讀取數(shù)據(jù)到Cache,這個(gè)代價(jià)也較高。

2. 全相聯(lián)映射

主存中的一個(gè)地址可被映射進(jìn)任意cache line,問題是:當(dāng)尋找一個(gè)地址是否已經(jīng)被cache時(shí),需要遍歷每一個(gè)cache line來尋找,這個(gè)代價(jià)很高。就像停車位可以大家隨便停一樣,停的時(shí)候簡(jiǎn)單,找車的時(shí)候需要一個(gè)一個(gè)停車位的找了。
主存中任何一塊都可以映射到Cache中的任何一塊位置上。
全相聯(lián)映射方式比較靈活,主存的各塊可以映射到Cache的任一塊中,Cache的利用率高,塊沖突概率低,只要淘汰Cache中的某一塊,即可調(diào)入主存的任一塊。但是,由于Cache比較電路的設(shè)計(jì)和實(shí)現(xiàn)比較困難,這種方式只適合于小容量Cache采用。

3. 組相聯(lián)映射

組相聯(lián)映射實(shí)際上是直接映射和全相聯(lián)映射的折中方案,其組織結(jié)構(gòu)如圖(3)所示。
主存和Cache都分組,主存中一個(gè)組內(nèi)的塊數(shù)與Cache中的分組數(shù)相同,組間采用直接映射,組內(nèi)采用全相聯(lián)映射。也就是說,將Cache分成2^u組,每組包含2^v塊,主存塊存放到哪個(gè)組是固定的,至于存到該組哪一塊則是靈活的。即主存的某塊只能映射到Cache的特定組中的任意一塊。主存的某塊b與Cache的組k之間滿足以下關(guān)系:k=b%(2^u).

icache、dcache同步 - 指令流( icache )和數(shù)據(jù)流( dcache

先看一下 ICACHEDCACHE 同步問題。由于程序的運(yùn)行而言, 指令流的都流過icache ,而指令中涉及到的數(shù)據(jù)流經(jīng)過dcache 。所以對(duì)于自修改的代碼(Self-Modifying Code)而言,比如我們修改了內(nèi)存p這個(gè)位置的代碼(典型多見于JIT
compiler),這個(gè)時(shí)候我們是通過store的方式去寫的p,所以新的指令會(huì)進(jìn)入dcache。但是我們接下來去執(zhí)行p位置的指令的時(shí)候,icache里面可能命中的是修改之前的指令。

09831896-4e7d-11ed-a3b6-dac502259ad0.png

所以這個(gè)時(shí)候軟件需要把dcache的東西clean出去,然后讓icache invalidate,這個(gè)開銷顯然還是比較大的。

但是,比如ARM64的N1處理器,它支持硬件的icache同步,詳見文檔:The Arm Neoverse N1 Platform: BuildingBlocks for the Next-Gen Cloud-to-Edge InfrastructureSoC

0991e290-4e7d-11ed-a3b6-dac502259ad0.png

特別注意畫紅色的幾行。軟件維護(hù)的成本實(shí)際很高,還涉及到icache的invalidation向所有核廣播的動(dòng)作。

接下來的一個(gè)問題就是多個(gè)核之間的cache同步。下面是一個(gè)簡(jiǎn)化版的處理器,CPU_A和B共享了一個(gè)L3,CPU_C和CPU_D共享了一個(gè)L3。實(shí)際的硬件架構(gòu)由于涉及到NUMA,會(huì)比這個(gè)更加復(fù)雜,但是這個(gè)圖反映層級(jí)關(guān)系是足夠了。

09f4cacc-4e7d-11ed-a3b6-dac502259ad0.png

比如CPU_A讀了一個(gè)地址p的變量?CPU_B、C、D又讀,難道B,C,D又必須從RAM里面經(jīng)過L3,L2,L1再讀一遍嗎?這個(gè)顯然是沒有必要的,在硬件上,cache的snooping控制單元,可以協(xié)助直接把CPU_A的p地址cache拷貝到CPU_B、C和D的cache

0a03f92a-4e7d-11ed-a3b6-dac502259ad0.png

這樣A-B-C-D都得到了相同的p地址的棕色小球。

假設(shè)CPU B這個(gè)時(shí)候,把棕色小球?qū)懗杉t色,而其他CPU里面還是棕色,這樣就會(huì)不一致了:

0a108672-4e7d-11ed-a3b6-dac502259ad0.png

這個(gè)時(shí)候怎么辦?這里面顯然需要一個(gè)協(xié)議,典型的多核cache同步協(xié)議有MESI和MOESI。MOESI相對(duì)MESI有些細(xì)微的差異,不影響對(duì)全局的理解。下面我們重點(diǎn)看MESI協(xié)議。

MESI 協(xié)議

MESI協(xié)議定義了4種狀態(tài):

M(Modified) :
當(dāng)前cache的內(nèi)容有效,數(shù)據(jù)已被修改而且與內(nèi)存中的數(shù)據(jù)不一致,數(shù)據(jù)只在當(dāng)前cache里存在;類似RAM里面是棕色球,B里面是紅色球(CACHE與RAM不一致),A、C、D都沒有球。

0a35c73e-4e7d-11ed-a3b6-dac502259ad0.png

E(Exclusive 獨(dú)有的
:當(dāng)前cache的內(nèi)容有效,數(shù)據(jù)與內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)只在當(dāng)前cache里存在;類似RAM里面是棕色球,B里面是棕色球(RAM和CACHE一致),A、C、D都沒有球。

0a487726-4e7d-11ed-a3b6-dac502259ad0.png

S(Shared) :當(dāng)前cache的內(nèi)容有效,數(shù)據(jù)與內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)在多個(gè)cache里存在。類似如下圖,在CPU A-B-C里面cache的棕色球都與RAM一致。

0a84bccc-4e7d-11ed-a3b6-dac502259ad0.png

I(Invalid) :當(dāng)前cache無效。前面三幅圖里面cache沒有球的那些都是屬于這個(gè)情況。

然后它有個(gè)狀態(tài)機(jī)

0ab59248-4e7d-11ed-a3b6-dac502259ad0.png

這個(gè)狀態(tài)機(jī)比較難記,死記硬背是記不住的,也沒必要記,它講的cache原先的狀態(tài),經(jīng)過一個(gè)硬件在本cache或者其他cache的讀寫操作后,各個(gè)cache的狀態(tài)會(huì)如何變遷。所以,硬件上不僅僅是監(jiān)控本CPU的cache讀寫行為,還會(huì)監(jiān)控其他CPU的。只需要記住一點(diǎn):這個(gè)狀態(tài)機(jī)是為了保證多核之間cache的一致性,比如一個(gè)干凈的數(shù)據(jù),可以在
多個(gè)CPU的cache share ,這個(gè)沒有一致性問題;但是,假設(shè)其中一個(gè)CPU寫過了,比如A-B-C本來是這樣:

0a84bccc-4e7d-11ed-a3b6-dac502259ad0.png

然后B被寫過了:

0aead714-4e7d-11ed-a3b6-dac502259ad0.png

這樣A、C的cache實(shí)際是過時(shí)的數(shù)據(jù),這是不允許的。這個(gè)時(shí)候,硬件會(huì)自動(dòng)把A、C的cache
invalidate掉,不需要軟件的干預(yù),A、C其實(shí)變地相當(dāng)于不命中這個(gè)球了:

0b14661a-4e7d-11ed-a3b6-dac502259ad0.jpg

這個(gè)時(shí)候,你可能會(huì)繼續(xù)問,如果C要讀這個(gè)球呢?它目前的狀態(tài)在B里面是modified的,而且與RAM不一致,這個(gè)時(shí)候,硬件會(huì)把紅球clean,然后B、C、RAM變地一致,B、C的狀態(tài)都變化為S(Shared):

0b2aadee-4e7d-11ed-a3b6-dac502259ad0.png

這一系列的動(dòng)作雖然由硬件完成,但是對(duì)軟件而言不是免費(fèi)的,因?yàn)樗馁M(fèi)了時(shí)間。如果編程的時(shí)候不注意,引起了硬件的大量cache同步行為,則程序的效率可能會(huì)急劇下降。

為了讓大家直觀感受到這個(gè)cache同步的開銷,下面我們寫一個(gè)程序,這個(gè)程序有2個(gè)線程,一個(gè)寫變量,一個(gè)讀變量:

0b3a3d72-4e7d-11ed-a3b6-dac502259ad0.png

這個(gè)程序里,x和y都是cacheline對(duì)齊的,這個(gè)程序的thread1的寫,會(huì)不停地與thread2的讀,進(jìn)行cache同步。

它的執(zhí)行時(shí)間為:

$time./a.out
real0m3.614s
user0m7.021s
sys0m0.004s

它在2個(gè)CPU上的userspace共運(yùn)行了7.021秒,累計(jì)這個(gè)程序從開始到結(jié)束的對(duì)應(yīng)真實(shí)世界的時(shí)間是3.614秒(就是從命令開始到命令結(jié)束的時(shí)間)。

如果我們把程序改一句話,把thread2里面的c = x改為c =
y,這樣2個(gè)線程在2個(gè)CPU運(yùn)行的時(shí)候,讀寫的是不同的cacheline,就沒有這個(gè)硬件的cache同步開銷了:

0b919414-4e7d-11ed-a3b6-dac502259ad0.png

它的運(yùn)行時(shí)間:

$time./b.out
real0m1.820s
user0m3.606s
sys0m0.008s

現(xiàn)在只需要1.8秒,幾乎減小了一半。

感覺前面那個(gè)a.out,雙核的幫助甚至都不大。如果我們改為單核跑呢?

$timetaskset-c0./a.out
real0m3.299s
user0m3.297s
sys0m0.000s

它單核跑,居然只需要3.299秒跑完,而雙核跑,需要3.614s跑完。單核跑完這個(gè)程序,甚至比雙核還快,有沒有驚掉下巴??。?!因?yàn)閱魏死锩鏇]有cache同步的開銷。

下一個(gè)cache同步的重大問題,就是設(shè)備與CPU之間。如果設(shè)備感知不到CPU的cache的話(下圖中的紅色數(shù)據(jù)流向不經(jīng)過cache),這樣,做DMA前后,CPU就需要進(jìn)行相關(guān)的cacheclean和invalidate的動(dòng)作,軟件的開銷會(huì)比較大。

0baf8ad2-4e7d-11ed-a3b6-dac502259ad0.png

這些軟件的動(dòng)作,若我們?cè)贚inux編程的時(shí)候,使用的是 streaming DMA APIs 的話,都會(huì)被類似這樣的API自動(dòng)搞定:

dma_map_single()
dma_unmap_single()
dma_sync_single_for_cpu()
dma_sync_single_for_device()
dma_sync_sg_for_cpu()
dma_sync_sg_for_device()

如果是使用的 dma_alloc_coherent ()API呢,則設(shè)備和CPU之間的buffer是cache一致的,不需要每次DMA進(jìn)行同步。對(duì)于不支持硬件cache一致性的設(shè)備而言,很可能dma_alloc_coherent()會(huì)把CPU對(duì)那段DMA
buffer的訪問設(shè)置為uncachable的。

這些API把底層的硬件差異封裝掉了,如果硬件不支持CPU和設(shè)備的cache同步的話,延時(shí)還是比較大的。那么,對(duì)于底層硬件而言,更好的實(shí)現(xiàn)方式,應(yīng)該仍然是硬件幫我們來搞定。比如我們需要修改總線協(xié)議,延伸紅線的觸角:

0bcea5fc-4e7d-11ed-a3b6-dac502259ad0.png

當(dāng)設(shè)備訪問RAM的時(shí)候,可以去snoop CPU的cache:

如果做內(nèi)存到外設(shè)的DMA,則直接從CPU的cache取modified的數(shù)據(jù);

如果做外設(shè)到內(nèi)存的DMA,則直接把CPU的cache invalidate掉。

這樣,就實(shí)現(xiàn)硬件意義上的cache同步。當(dāng)然,硬件的cache同步,還有一些其他方法,原理上是類似的。注意,這種同步仍然不是免費(fèi)的,它仍然會(huì)消耗bus
cycles的。實(shí)際上,cache的同步開銷還與距離相關(guān),可以說距離越遠(yuǎn),同步開銷越大,比如下圖中A、B的同步開銷比A、C小。

09f4cacc-4e7d-11ed-a3b6-dac502259ad0.png

對(duì)于一個(gè)NUMA服務(wù)器而言,跨NUMA的cache同步開銷顯然是要比NUMA內(nèi)的同步開銷大。

意識(shí)到 CACHE 的編程

通過上一節(jié)的代碼,讀者應(yīng)該意識(shí)到了cache的問題不處理好,程序的運(yùn)行性能會(huì)急劇下降。所以意識(shí)到cache的編程,對(duì)程序員是至關(guān)重要的。

7-zip LZMA 基準(zhǔn)

https://www.7-cpu.com/

LZMA基準(zhǔn)說明

LZMA基準(zhǔn)測(cè)試顯示了MIPS等級(jí)(每秒百萬條指令)。額定值是根據(jù)測(cè)得的速度計(jì)算得出的,并通過關(guān)閉多線程選項(xiàng)的Intel Core 2CPU的結(jié)果進(jìn)行了標(biāo)準(zhǔn)化。因此,如果您擁有Intel或AMD的現(xiàn)代CPU,則單線程模式下的額定值必須接近實(shí)際CPU頻率。

該測(cè)試中用于壓縮的測(cè)試數(shù)據(jù)是使用特殊算法生成的,該算法創(chuàng)建的數(shù)據(jù)流具有真實(shí)數(shù)據(jù)的某些屬性,例如文本或執(zhí)行代碼。請(qǐng)注意,用于實(shí)際數(shù)據(jù)的LZMA的速度可能會(huì)略有不同。

壓縮速度 很大程度上取決于內(nèi)存(RAM)延遲,數(shù)據(jù)高速緩存大小/速度和TLB。CPU的無序執(zhí)行功能對(duì)該測(cè)試也很重要。

解壓縮速度在
很大程度上取決于CPU整數(shù)運(yùn)算。該測(cè)試最重要的事情是:分支錯(cuò)誤預(yù)測(cè)損失(流水線的長度)和32位指令的延遲(“乘”,“移位”,“加”和其他)。減壓測(cè)試具有大量不可預(yù)測(cè)的分支。請(qǐng)注意,某些CPU體系結(jié)構(gòu)(例如32位ARM)支持可以有條件執(zhí)行的指令。因此,在LZMA解壓縮代碼中的許多情況下,此類CPU可以在沒有分支的情況下工作(也無需管道沖洗)。與不支持復(fù)雜的有條件執(zhí)行的其他體系結(jié)構(gòu)相比,此類CPU具有一些速度優(yōu)勢(shì)。亂序執(zhí)行功能對(duì)于LZMA減壓并不那么重要。

測(cè)試代碼不使用FPU和SSE。大多數(shù)代碼是32位整數(shù)代碼。壓縮代碼中只有一小部分也使用64位整數(shù)。RAM和緩存帶寬對(duì)于這些測(cè)試而言并不那么重要。延遲要重要得多。

對(duì)于這些測(cè)試,CPU的IPC(每個(gè)周期的指令)速率不是很高。對(duì)于現(xiàn)代CPU,測(cè)試IPC的估計(jì)值為1(每個(gè)周期一條指令)。壓縮測(cè)試具有對(duì)RAM和數(shù)據(jù)緩存的大量隨機(jī)訪問。執(zhí)行時(shí)間中很大一部分,CPU等待數(shù)據(jù)緩存或RAM中的數(shù)據(jù)。在分支預(yù)測(cè)錯(cuò)誤之后,減壓測(cè)試會(huì)進(jìn)行大量的管道沖洗。如此低的IPC意味著有一些未使用的CPU資源。但是具有超線程功能的CPU可以使用兩個(gè)線程來加載這些CPU資源。因此,超線程在這些測(cè)試中提供了很大的改進(jìn)。

多線程模式下的LZMA

當(dāng)您指定(N *2)個(gè)線程進(jìn)行測(cè)試時(shí),程序?qū)?chuàng)建N份LZMA編碼器副本,并且每個(gè)LZMA編碼器實(shí)例都會(huì)壓縮單獨(dú)的測(cè)試數(shù)據(jù)塊。每個(gè)LZMA編碼器實(shí)例都會(huì)創(chuàng)建3個(gè)非對(duì)稱執(zhí)行線程:兩個(gè)大線程和一個(gè)小線程。這3個(gè)線程的總CPU負(fù)載可以在140%到200%之間變化。為了在壓縮過程中提供更好的CPU負(fù)載,我們還測(cè)試了基準(zhǔn)線程數(shù)大于硬件線程數(shù)的模式。

每個(gè)處于多線程模式的LZMA編碼器實(shí)例將壓縮任務(wù)分為3個(gè)不同的任務(wù),其中每個(gè)任務(wù)在單獨(dú)的線程中執(zhí)行。這些任務(wù)中的每一個(gè)都比原始任務(wù)簡(jiǎn)單,并且使用更少的內(nèi)存。因此,每個(gè)線程在多線程模式下都會(huì)更有效地使用數(shù)據(jù)緩存和TLB。LZMA編碼器在“多線程”模式下將“速度”的值除以“
CPU使用率”會(huì)更有效。

請(qǐng)注意,LZMA編碼器的3個(gè)線程之間存在一些數(shù)據(jù)通信。因此,通過CPU線程之間的內(nèi)存進(jìn)行數(shù)據(jù)交換的帶寬也很重要,尤其是在具有大量內(nèi)核或CPU的多核系統(tǒng)中。

所有LZMA解碼器線程都是對(duì)稱且獨(dú)立的。因此,如果使用了硬件線程數(shù),則解壓縮測(cè)試將使用所有硬件線程。

LZMA成績

我們將基準(zhǔn)測(cè)試結(jié)果用于32 MB詞典(控制臺(tái)版本的結(jié)果中的“ 25:”行)。如果沒有32
MB的字典結(jié)果,則將結(jié)果用于較小的字典。大多數(shù)x86測(cè)試都是在Windows
7官方二進(jìn)制文件上進(jìn)行的。一些測(cè)試是在64位模式下執(zhí)行的。其他平臺(tái)上的大多數(shù)測(cè)試都是使用GCC編譯的p7zip進(jìn)行速度優(yōu)化的。

新版本的7-Zip提供了改進(jìn)的性能。例如,最新版本的x64平臺(tái)的7-Zip使用以匯編器編寫的用于解壓縮的優(yōu)化代碼,因此評(píng)級(jí)結(jié)果可以是以前版本的7-Zip的1.7倍。但是表中的大多數(shù)結(jié)果表示在進(jìn)行這些優(yōu)化之前,使用舊版本的7-Zip執(zhí)行的度量。如果某些CPU已通過7-Zip的新版本進(jìn)行了測(cè)試,則會(huì)在7-Zip的版本號(hào)上打上標(biāo)記。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10804

    瀏覽量

    210829
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6808

    瀏覽量

    88743
  • Cache
    +關(guān)注

    關(guān)注

    0

    文章

    129

    瀏覽量

    28272
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68231

原文標(biāo)題:深入理解CPU cache:組織、一致性(同步)、編程

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    cpucache內(nèi)存交互的過程

    CPU接收到指令后,它會(huì)最先向CPU中的一級(jí)緩存(L1 Cache)去尋找相關(guān)的數(shù)據(jù),然一級(jí)緩存是與CPU同頻運(yùn)行的,但是由于容量較小,所以不可能每次都命中。
    的頭像 發(fā)表于 10-21 09:10 ?2341次閱讀

    CPU Cache是如何保證緩存一致性的?

    我們介紹`CPU Cache`的組織架構(gòu)及其進(jìn)行**讀操作**時(shí)的尋址方式,但是緩存不僅僅只有讀操作,還有 **寫操作** ,這會(huì)帶來一個(gè)新的問題
    的頭像 發(fā)表于 12-04 15:05 ?1259次閱讀
    <b class='flag-5'>CPU</b> <b class='flag-5'>Cache</b>是如何保證緩存一致性的?

    嵌入式CPU指令Cache的設(shè)計(jì)與實(shí)現(xiàn)

    針對(duì)嵌入式CPU 指令處理速度與存儲(chǔ)器指令存取速度不匹配問題,本文基于FPGA 設(shè)計(jì)并實(shí)現(xiàn)了可以有效解決這一問題的指令Cache。根據(jù)嵌入式五級(jí)流水線CPU 特性,所設(shè)計(jì)指令Cache
    發(fā)表于 08-05 14:27 ?36次下載

    什么是緩存Cache

    什么是緩存Cache 即高速緩沖存儲(chǔ)器,是位于CPU與主內(nèi)存間的一種容量較小但速度很高的存儲(chǔ)器。由于CPU的速度遠(yuǎn)高于主內(nèi)存,CPU直接
    發(fā)表于 01-23 10:57 ?884次閱讀

    什么是Cache/SIMD?

    什么是Cache/SIMD?   Cache :即高速緩沖存儲(chǔ)器,是位于CPU與主內(nèi)存間的一種容量較小但速度很高的存儲(chǔ)器。由于CPU的速度遠(yuǎn)高于主內(nèi)存
    發(fā)表于 02-04 11:29 ?533次閱讀

    什么是Instructions Cache/IMM/ID

    什么是Instructions Cache/IMM/ID  Instructions Cache: (指令緩存)由于系統(tǒng)主內(nèi)存的速度較慢,當(dāng)CPU讀取指令的時(shí)候,會(huì)導(dǎo)致CPU
    發(fā)表于 02-04 11:51 ?624次閱讀

    高速緩存(Cache),高速緩存(Cache)原理是什么?

    高速緩存(Cache),高速緩存(Cache)原理是什么? 高速緩存Cache是位于CPU和主存儲(chǔ)器之間規(guī)模較小、存取速度快捷的靜態(tài)存儲(chǔ)器。Cac
    發(fā)表于 03-26 10:49 ?6815次閱讀

    Buffer和Cache之間區(qū)別是什么?

    cpu在執(zhí)行程序所用的指令和讀數(shù)據(jù)都是針對(duì)內(nèi)存的,也就是從內(nèi)存中取得的。由于內(nèi)存讀寫速度慢,為了提高cpu和內(nèi)存之間數(shù)據(jù)交換的速度,在cpu和內(nèi)存之間增加了cache,它的速度比內(nèi)存快
    的頭像 發(fā)表于 04-02 10:35 ?6721次閱讀

    cache對(duì)寫好代碼真的有那么重要嗎

    典型的現(xiàn)代CPU中比較接近改進(jìn)的哈佛結(jié)構(gòu),cache排布大概是這樣的: L1速度》 L2速度》 L3速度》 RAM L1容量《 L2容量《 L3容量《 RAM 現(xiàn)代
    的頭像 發(fā)表于 07-26 15:18 ?1736次閱讀
    <b class='flag-5'>cache</b>對(duì)寫好代碼真的有那么重要嗎

    宋寶華:深入理解cache對(duì)寫好代碼至關(guān)重要

    現(xiàn)代CPU,通常L1 cache的指令和數(shù)據(jù)是分離的。這樣可以實(shí)現(xiàn)2條高速公路并行訪問,CPU可以同時(shí)load指令和數(shù)據(jù)。當(dāng)然,cache也不一定是一個(gè)core獨(dú)享,現(xiàn)代很多
    的頭像 發(fā)表于 12-06 10:38 ?837次閱讀

    CPU Cache偽共享問題

    當(dāng)CPU想要訪問主存中的元素時(shí),會(huì)先查看Cache中是否存在,如果存在(稱為Cache Hit),直接從Cache中獲取,如果不存在(稱為Cache
    的頭像 發(fā)表于 12-12 09:17 ?642次閱讀

    CPU設(shè)計(jì)之Cache存儲(chǔ)器

    Cache存儲(chǔ)器也被稱為高速緩沖存儲(chǔ)器,位于CPU和主存儲(chǔ)器之間。之所以在CPU和主存之間要加cache是因?yàn)楝F(xiàn)代的CPU頻率大大提高,內(nèi)存
    的頭像 發(fā)表于 03-21 14:34 ?1152次閱讀
    <b class='flag-5'>CPU</b>設(shè)計(jì)之<b class='flag-5'>Cache</b>存儲(chǔ)器

    CPU CACHE策略的初始化

    build_mem_type_table()函數(shù)的功能是獲取當(dāng)前CPUCACHE類型,據(jù)此初始化mem_type。
    的頭像 發(fā)表于 06-05 15:03 ?1337次閱讀
    <b class='flag-5'>CPU</b> <b class='flag-5'>CACHE</b>策略的初始化

    多個(gè)CPU各自的cache同步問題

    ? CACHE 的一致性 Cache的一致性有這么幾個(gè)層面 1.?????一個(gè)CPU的icache和dcache的同步問題 2.?????多個(gè)CPU各自的
    的頭像 發(fā)表于 06-17 10:38 ?1910次閱讀
    多個(gè)<b class='flag-5'>CPU</b>各自的<b class='flag-5'>cache</b>同步問題

    Cache的原理和地址映射

    cache存儲(chǔ)系統(tǒng)中,把cache和主存儲(chǔ)器都劃分成相同大小的塊。 主存地址由塊號(hào)B和塊內(nèi)地址W兩部分組成,cache地址由塊號(hào)b和塊內(nèi)地址w組成。 當(dāng)CPU訪問
    的頭像 發(fā)表于 10-31 11:21 ?1516次閱讀