一文吃透三種經(jīng)典映射策略,從理論到項(xiàng)目實(shí)踐
在計(jì)算機(jī)的世界里,有一個(gè)神秘的存在,它默默地工作,卻對計(jì)算機(jī)的性能起著至關(guān)重要的作用,它就是緩存(Cache)。Cache 就像是計(jì)算機(jī)的 “高速通道”,專門負(fù)責(zé)加速數(shù)據(jù)的讀取,讓計(jì)算機(jī)能夠快速響應(yīng)各種指令,極大地提升了運(yùn)行效率。想象一下,CPU 就像是一位忙碌的大廚,它需要各種食材(數(shù)據(jù))來烹飪出美味的 “程序大餐”。而主存則像是一個(gè)巨大的食材倉庫,里面存放著各種各樣的食材。但是,這個(gè)倉庫太大了,大廚每次去取食材都要花費(fèi)很長時(shí)間,這就大大降低了烹飪的效率。
這時(shí),Cache 就登場了,它就像是大廚身邊的一個(gè)小助手,會(huì)提前把一些常用的食材放在一個(gè)小籃子里(緩存),這樣大廚需要的時(shí)候,就可以直接從小籃子里拿,而不用每次都跑去大倉庫,大大節(jié)省了時(shí)間。Cache 之所以能夠如此高效地工作,離不開它獨(dú)特的映射方式。今天,我們就來深入探討一下 Cache 的三種映射方式,揭開它們神秘的面紗,看看它們是如何在幕后為計(jì)算機(jī)的性能保駕護(hù)航的。
一、直接映射:簡單直接的 “定位器”
直接映射是三種映射方式中最為簡單直接的一種。它的映射規(guī)則就像是給每個(gè)主存塊都分配了一個(gè)固定的 “座位”(緩存塊),這個(gè) “座位” 的確定方式是通過主存塊號對緩存塊數(shù)取模運(yùn)算。
假設(shè)主存中有很多個(gè)數(shù)據(jù)塊,編號從 0 開始依次遞增,而緩存也被劃分成了若干個(gè)緩存塊。對于主存中的第 n 個(gè)數(shù)據(jù)塊,它會(huì)被映射到緩存中的第(n % 緩存塊數(shù))個(gè)緩存塊中。例如,如果緩存有 8 個(gè)緩存塊,主存中的第 0 塊、第 8 塊、第 16 塊…… 都會(huì)被映射到緩存的第 0 塊;主存中的第 1 塊、第 9 塊、第 17 塊…… 都會(huì)被映射到緩存的第 1 塊,以此類推 。這種映射關(guān)系是固定且唯一的,每個(gè)主存塊在緩存中都有且僅有一個(gè)對應(yīng)的緩存塊。
直接映射是最簡單的地址映射方式,它的硬件簡單,成本低,地址變換速度快,而且不涉及替換算法問題。但是這種方式不夠靈活,Cache 的存儲(chǔ)空間得不到充分利用,每個(gè)主存塊只有一個(gè)固定位置可存放,容易產(chǎn)生沖突,使 Cache 效率下降,因此只適合大容量 Cache 采用。例如,如果一個(gè)程序需要重復(fù)引用主存中第 0 塊與第 16 塊,最好將主存第 0 塊與第 16 塊同時(shí)復(fù)制到 Cache 中,但由于它們都只能復(fù)制到 Cache 的第 0 塊中去,即使 Cache 中別的存儲(chǔ)空間空著也不能占用,因此這兩個(gè)塊會(huì)不斷地交替裝入 Cache 中,導(dǎo)致命中率降低。
1.1工作流程詳解
當(dāng) CPU 需要訪問某個(gè)數(shù)據(jù)時(shí),它會(huì)首先根據(jù)數(shù)據(jù)的主存地址來判斷該數(shù)據(jù)是否在緩存中。它會(huì)將主存地址分成幾個(gè)部分,其中一部分用于確定緩存塊的索引(也就是前面提到的取模運(yùn)算得到的結(jié)果),另一部分用于作為標(biāo)記(tag),還有一部分用于表示塊內(nèi)偏移(因?yàn)槊總€(gè)緩存塊中可以存儲(chǔ)多個(gè)數(shù)據(jù))。
CPU 會(huì)根據(jù)索引找到對應(yīng)的緩存塊,然后將主存地址中的標(biāo)記與緩存塊中的標(biāo)記進(jìn)行比較。如果兩者相同,并且緩存塊中的有效位為 1(表示該緩存塊中的數(shù)據(jù)是有效的),那么就表示命中,CPU 可以直接從緩存塊中讀取數(shù)據(jù);如果標(biāo)記不同或者有效位為 0,那就表示未命中,CPU 需要從主存中讀取數(shù)據(jù),并且將該數(shù)據(jù)所在的主存塊調(diào)入緩存中,同時(shí)更新緩存塊的標(biāo)記和有效位。
1.2主存與cache地址格式
主存地址格式: | Cache地址格式 |
主存塊號(S位) | Cache行號(m位) |
塊內(nèi)地址(W位) | 行內(nèi)地址(w位) |
- 當(dāng)主存的數(shù)據(jù)塊調(diào)入Cache中時(shí),該塊的塊號(主存標(biāo)記)保存于調(diào)入Cache行的對應(yīng)標(biāo)記位(即塊表中)
- 塊表的東西應(yīng)為2^m * S位
1.3優(yōu)劣勢深度分析
直接映射的優(yōu)點(diǎn)非常明顯,首先它的硬件實(shí)現(xiàn)非常簡單,因?yàn)橛成湟?guī)則固定,不需要復(fù)雜的硬件電路來進(jìn)行地址映射和查找。這就使得它的成本相對較低,而且地址變換的速度非常快,能夠快速地響應(yīng) CPU 的訪問請求。
然而,它的缺點(diǎn)也同樣突出。由于每個(gè)主存塊只能映射到固定的緩存塊,這就導(dǎo)致了緩存的沖突率非常高。當(dāng)多個(gè)主存塊都需要映射到同一個(gè)緩存塊時(shí),就會(huì)發(fā)生沖突,后面的主存塊會(huì)覆蓋前面主存塊的數(shù)據(jù),使得緩存的命中率降低。例如,如果程序頻繁地訪問主存中第 0 塊和第 8 塊的數(shù)據(jù),而它們都映射到緩存的第 0 塊,那么這兩個(gè)塊的數(shù)據(jù)就會(huì)不斷地在緩存中替換,導(dǎo)致每次訪問都可能需要從主存中讀取數(shù)據(jù),大大降低了緩存的效率 。這種沖突問題也使得緩存的利用率很低,很多緩存空間無法得到充分利用,因?yàn)榧词蛊渌彺鎵K空閑,主存塊也不能隨意映射到這些空閑塊中。
1.4案例分析
【例】設(shè)主存容量1MB , cache容量16KB,塊的大小為512B,采用全相聯(lián)映射方式。
(1)寫出cache的地址格式?
- cache的容量是16KB,所以按字編碼的話,cache的總線長度是14位。
- 塊(行)的大小是512B,也就是說塊(行)內(nèi)地址是9位。
- 因此行標(biāo)記 14-9=5位 ,也就是說cache一共有32行。
(2)寫出主存的地址格式?
- 主存容量1MB,一共是20位。
- 塊的大小是9位,所以塊標(biāo)記公用11位。 一共2048塊
(3)塊表的容量多大?
- 根據(jù)行的數(shù)量和塊標(biāo)記的位數(shù),可以得到塊表的容量是 32*11位
- 這個(gè)塊表不包含地址部分,只有標(biāo)記部分,塊表中塊的數(shù)量由cache行的數(shù)量決定。
(4)主存地址為CDE8FH的單元,在cache中的什么位置?
- 主存地址為CDE8FH的單元可映射到cache中的任何一個(gè)字塊位置;
- CDE8FH1100 1101 1110 1000 1111 B其塊7行內(nèi)地址為:010001111。
二、全相聯(lián)映射:自由靈活的 “數(shù)據(jù)收納盒”
全相聯(lián)映射與直接映射截然不同,它賦予了數(shù)據(jù)塊極高的自由度。在全相聯(lián)映射的規(guī)則下,主存中的任何一個(gè)數(shù)據(jù)塊都能夠隨心所欲地映射到緩存中的任意一個(gè)緩存塊位置 。這就好比一個(gè)大型圖書館,每本書(主存數(shù)據(jù)塊)可以被放置在圖書館的任意一個(gè)書架格子(緩存塊)里,沒有固定的限制區(qū)域。這種映射方式徹底打破了直接映射的那種固定對應(yīng)關(guān)系的束縛,極大地提高了緩存使用的靈活性。
全相聯(lián)映射方式比較靈活,主存的各塊可以映射到 Cache 的任一塊中,Cache 的利用率高,塊沖突概率低,只要淘汰 Cache 中的某一塊,即可調(diào)入主存的任一塊。但是,由于 Cache 比較電路的設(shè)計(jì)和實(shí)現(xiàn)比較困難,這種方式只適合于小容量 Cache 采用。
2.1查找匹配過程
當(dāng) CPU 需要從緩存中讀取數(shù)據(jù)時(shí),它會(huì)將主存地址拆分成標(biāo)記(tag)和塊內(nèi)偏移兩部分。接下來,CPU 會(huì)逐一比較緩存中每一個(gè)緩存塊的標(biāo)記與主存地址中的標(biāo)記。這個(gè)過程就像是在圖書館里,工作人員需要拿著書籍編號(主存地址標(biāo)記),在所有的書架格子(緩存塊)中尋找與之匹配的編號。如果找到了匹配的標(biāo)記,并且該緩存塊的有效位為 1,那就意味著命中了,CPU 可以直接從這個(gè)緩存塊中讀取數(shù)據(jù);要是遍歷完所有緩存塊都沒有找到匹配的標(biāo)記,那就表示未命中,CPU 不得不從主存中讀取數(shù)據(jù),并且將該數(shù)據(jù)所在的主存塊調(diào)入緩存中,同時(shí)更新緩存塊的標(biāo)記和有效位 。
2.2主存地址格式
- 假設(shè)主存共2^n個(gè)單元,分成2^s個(gè)塊,每塊單元數(shù)為2^w個(gè),則主存地址為s+w位。(2^s個(gè)塊代表塊標(biāo)記數(shù)目,每塊單元數(shù)2^w代表塊內(nèi)地址位數(shù))
- Cache空間被分成2^m行,每行大小也應(yīng)該為2^w單元,則Cache地址為m+w位。
圖片
2.3全面評價(jià)優(yōu)缺點(diǎn)
全相聯(lián)映射的優(yōu)點(diǎn)非常突出,由于它允許主存塊自由映射到緩存的任意位置,這使得緩存的命中率得到了顯著提高,緩存空間的利用率也達(dá)到了很高的水平。在實(shí)際應(yīng)用中,當(dāng)程序訪問的數(shù)據(jù)具有較強(qiáng)的隨機(jī)性和分散性時(shí),全相聯(lián)映射能夠充分發(fā)揮其優(yōu)勢,大大減少了緩存未命中的情況,從而提高了系統(tǒng)的性能 。
然而,全相聯(lián)映射也存在著明顯的缺點(diǎn)。由于查找數(shù)據(jù)時(shí)需要遍歷緩存中的所有塊來對比標(biāo)記,這就使得查找過程變得非常復(fù)雜,需要耗費(fèi)大量的時(shí)間,導(dǎo)致訪問速度較慢。而且,為了實(shí)現(xiàn)這種自由映射和快速查找,需要配備復(fù)雜的硬件電路和大量的比較器,這無疑大大增加了硬件成本和實(shí)現(xiàn)難度 。
也正是因?yàn)檫@些缺點(diǎn),全相聯(lián)映射在實(shí)際應(yīng)用中受到了一定的限制,通常只適用于對緩存容量要求較小的場景,比如一些對成本不太敏感但對緩存命中率要求極高的高端處理器緩存設(shè)計(jì)中 。
三、組相聯(lián)映射:取兩者之長的 “調(diào)和者”
組相聯(lián)映射就像是一個(gè)精心規(guī)劃的 “分組社區(qū)”,它巧妙地融合了直接映射和全相聯(lián)映射的優(yōu)點(diǎn) 。在組相聯(lián)映射的規(guī)則下,緩存被細(xì)致地劃分為多個(gè)組(Set),每個(gè)組里面又包含了若干個(gè)緩存塊(Block)。主存中的數(shù)據(jù)塊首先會(huì)依據(jù)特定的規(guī)則被映射到緩存中的某一個(gè)組,這個(gè)映射規(guī)則類似于直接映射,通過主存塊號對緩存組數(shù)取模運(yùn)算來確定組號 。例如,如果緩存被分成 8 個(gè)組,主存中的第 0 塊、第 8 塊、第 16 塊…… 都會(huì)被映射到緩存的第 0 組。
而在組內(nèi),數(shù)據(jù)塊的映射方式則采用了全相聯(lián)映射,也就是說,主存中的數(shù)據(jù)塊可以自由地映射到它所對應(yīng)的組內(nèi)的任意一個(gè)緩存塊中 。這種獨(dú)特的映射方式既保留了直接映射簡單快速的特點(diǎn),又具備了全相聯(lián)映射靈活高效的優(yōu)勢,有效地降低了緩存沖突的概率,提高了緩存的利用率 。
3.1實(shí)際工作機(jī)制
當(dāng) CPU 需要訪問數(shù)據(jù)時(shí),組相聯(lián)映射的工作機(jī)制開始發(fā)揮作用。CPU 首先會(huì)根據(jù)主存地址中的組索引字段找到對應(yīng)的緩存組,這個(gè)過程就像是在一個(gè)大型社區(qū)中找到對應(yīng)的樓棟。然后,它會(huì)在這個(gè)組內(nèi)逐一比較各個(gè)緩存塊的標(biāo)記(tag)與主存地址中的標(biāo)記 。這一步就像是在樓棟里找到對應(yīng)的房間,通過房間號(標(biāo)記)來確認(rèn)是否找對了地方。如果找到了匹配的標(biāo)記,并且該緩存塊的有效位為 1,那就意味著命中了,CPU 可以直接從這個(gè)緩存塊中讀取數(shù)據(jù);如果沒有找到匹配的標(biāo)記,那就表示未命中,CPU 需要從主存中讀取數(shù)據(jù),并將該數(shù)據(jù)所在的主存塊調(diào)入緩存中,同時(shí)更新緩存塊的標(biāo)記和有效位 。
3.2性能綜合評估
組相聯(lián)映射在性能上有著出色的表現(xiàn)。它有效地降低了緩存沖突率,相比于直接映射,它允許更多的主存塊映射到緩存中,減少了因沖突導(dǎo)致的數(shù)據(jù)替換,從而提高了緩存的命中率 。在一個(gè)程序頻繁訪問多個(gè)主存塊,但這些主存塊不會(huì)都映射到同一個(gè)緩存組的情況下,組相聯(lián)映射能夠很好地滿足數(shù)據(jù)訪問需求,使得數(shù)據(jù)能夠更快速地被 CPU 獲取,提升了系統(tǒng)的整體性能 。
在緩存利用率方面,組相聯(lián)映射也表現(xiàn)得相當(dāng)出色。由于組內(nèi)采用全相聯(lián)映射,主存塊可以更靈活地放置在緩存中,避免了直接映射中因固定映射導(dǎo)致的緩存空間浪費(fèi)問題,使得緩存空間得到了更充分的利用 。
當(dāng)然,組相聯(lián)映射也并非完美無缺。由于在組內(nèi)需要進(jìn)行標(biāo)記比較,這使得它的硬件復(fù)雜度要高于直接映射,需要更多的比較器和復(fù)雜的控制電路來實(shí)現(xiàn) 。查找數(shù)據(jù)的時(shí)間也會(huì)相對增加,因?yàn)槌艘业綄?yīng)的組,還需要在組內(nèi)進(jìn)行逐一比較 。但總體來說,它在沖突率、利用率和硬件復(fù)雜度之間取得了一個(gè)較好的平衡,在實(shí)際應(yīng)用中得到了廣泛的使用 。
四、三種映射方式的應(yīng)用場景與選擇策略
4.1不同場景下的適用性分析
在實(shí)際應(yīng)用中,不同的計(jì)算機(jī)系統(tǒng)和應(yīng)用場景對 Cache 的性能有著不同的要求,因此需要根據(jù)具體情況選擇合適的映射方式。
對于一些簡單的小型系統(tǒng)或嵌入式系統(tǒng),直接映射方式往往是一個(gè)不錯(cuò)的選擇。這些系統(tǒng)通常對成本非常敏感,并且數(shù)據(jù)訪問模式相對簡單,數(shù)據(jù)的訪問具有一定的規(guī)律性。在這樣的系統(tǒng)中,直接映射的簡單性和低成本優(yōu)勢就能夠得到充分體現(xiàn) 。一些簡單的微控制器系統(tǒng),它們的任務(wù)相對單一,數(shù)據(jù)訪問主要集中在幾個(gè)固定的區(qū)域,使用直接映射 Cache 可以在保證一定性能的前提下,大大降低硬件成本,提高系統(tǒng)的性價(jià)比 。
而對于那些對性能要求極高,對成本不太敏感的高性能計(jì)算系統(tǒng),全相聯(lián)映射則更能發(fā)揮其優(yōu)勢。在高性能計(jì)算中,程序通常需要處理大量復(fù)雜的數(shù)據(jù),數(shù)據(jù)訪問模式非常復(fù)雜且具有高度的隨機(jī)性。全相聯(lián)映射能夠提供極高的命中率,減少緩存未命中的情況,從而顯著提高系統(tǒng)的性能 。在一些超級計(jì)算機(jī)的緩存設(shè)計(jì)中,就可能會(huì)采用全相聯(lián)映射方式,以滿足其對高速數(shù)據(jù)訪問的嚴(yán)格要求 。
組相聯(lián)映射則在大多數(shù)現(xiàn)代計(jì)算機(jī)系統(tǒng)中得到了廣泛應(yīng)用,因?yàn)樗谛阅芎统杀局g取得了一個(gè)很好的平衡。無論是桌面計(jì)算機(jī)、服務(wù)器還是移動(dòng)設(shè)備,這些系統(tǒng)既需要一定的性能來保證用戶的使用體驗(yàn),又需要控制成本以滿足市場需求 。組相聯(lián)映射既能有效降低緩存沖突率,提高命中率,又不會(huì)像全相聯(lián)映射那樣帶來過高的硬件成本和復(fù)雜度,非常適合這類系統(tǒng)的需求 。在常見的個(gè)人電腦中,CPU 的一級緩存(L1 Cache)和二級緩存(L2 Cache)通常會(huì)采用組相聯(lián)映射方式,以提供良好的性能和合理的成本 。
4.2選擇時(shí)的關(guān)鍵考量因素
在選擇 Cache 映射方式時(shí),有幾個(gè)關(guān)鍵因素需要仔細(xì)考量。首先是成本因素,硬件成本在系統(tǒng)設(shè)計(jì)中是一個(gè)重要的制約因素。直接映射方式由于硬件實(shí)現(xiàn)簡單,所需的硬件資源最少,因此成本最低;全相聯(lián)映射則需要復(fù)雜的硬件電路和大量的比較器,成本最高;組相聯(lián)映射的成本介于兩者之間 。如果系統(tǒng)對成本控制較為嚴(yán)格,那么直接映射可能是首選;而對于那些追求極致性能且對成本不敏感的高端系統(tǒng),則可以考慮全相聯(lián)映射 。
性能是另一個(gè)至關(guān)重要的考量因素。性能主要體現(xiàn)在緩存命中率和訪問速度上。全相聯(lián)映射的命中率最高,因?yàn)樗梢詫⒅鞔鎵K自由地映射到緩存的任意位置,最大限度地減少了沖突,對于那些數(shù)據(jù)訪問模式復(fù)雜且隨機(jī)的應(yīng)用,能夠提供最佳的性能 。直接映射的訪問速度最快,因?yàn)樗挠成湟?guī)則簡單,每次訪問只需檢查一個(gè)固定的緩存塊位置,但由于沖突率高,命中率相對較低 。組相聯(lián)映射在命中率和訪問速度之間取得了平衡,它通過合理的分組和組內(nèi)全相聯(lián)映射,降低了沖突率,提高了命中率,同時(shí)訪問速度也不會(huì)太慢 。
緩存大小也會(huì)對映射方式的選擇產(chǎn)生影響。對于較小的緩存,全相聯(lián)映射可能更適用,因?yàn)樾【彺嬷械木彺鎵K數(shù)量有限,全相聯(lián)映射可以更充分地利用這些緩存塊,提高緩存的利用率和命中率 。而對于較大的緩存,直接映射可能會(huì)導(dǎo)致嚴(yán)重的沖突問題,降低緩存的性能,此時(shí)組相聯(lián)映射則是更好的選擇,它可以通過分組來減少?zèng)_突,提高緩存的整體性能 。
五、Cache映射案例分析
5.1實(shí)際例子
下面展示了現(xiàn)代 Intel 處理器的 CPU cache 是如何組織的。有關(guān) cache 的討論往往缺乏具體的實(shí)例,使得一些簡單的概念變得撲朔迷離。也許是我可愛的小腦瓜有點(diǎn)遲鈍吧,但不管怎樣,至少下面講述了故事的前一半,即 Core 2 的 L1 cache 是如何被訪問的:
5.2由索引揀選緩存組(行)
在 cache 中的數(shù)據(jù)是以緩存線(line)為單位組織的,一條緩存線對應(yīng)于內(nèi)存中一個(gè)連續(xù)的字節(jié)塊。這個(gè) cache 使用了 64 字節(jié)的緩存線。這些線被保存在 cache bank 中,也叫路(way)。每一路都有一個(gè)專門的目錄(directory)用來保存一些登記信息。你可以把每一路連同它的目錄想象成電子表格中的一列,而表的一行構(gòu)成了 cache 的一組(set)。列中的每一個(gè)單元(cell)都含有一條緩存線,由與之對應(yīng)的目錄單元跟蹤管理。圖中的 cache 有 64 組、每組 8 路,因此有 512 個(gè)含有緩存線的單元,合計(jì) 32KB 的存儲(chǔ)空間。
在 cache 眼中,物理內(nèi)存被分割成了許多 4KB 大小的物理內(nèi)存頁(page)。每一頁都含有 4KB / 64 bytes == 64 條緩存線。在一個(gè) 4KB 的頁中,第 0 到 63 字節(jié)是第一條緩存線,第 64 到 127 字節(jié)是第二條緩存線,以此類推。每一頁都重復(fù)著這種劃分,所以第 0 頁第 3 條緩存線與第 1 頁第 3 條緩存線是不同的。
在全相聯(lián)緩存(fully associative cache)中,內(nèi)存中的任意一條緩存線都可以被存儲(chǔ)到任意的緩存單元中。這種存儲(chǔ)方式十分靈活,但也使得要訪問它們時(shí),檢索緩存單元的工作變得復(fù)雜、昂貴。由于 L1 和 L2 cache 工作在很強(qiáng)的約束之下,包括功耗,芯片物理空間,存取速度等,所以在多數(shù)情況下,使用全相聯(lián)緩存并不是一個(gè)很好的折中。
取而代之的是圖中的組相聯(lián)緩存(set associative cache)。意思是,內(nèi)存中一條給定的緩存線只能被保存在一個(gè)特定的組(或行)中。所以,任意物理內(nèi)存頁的第 0 條緩存線(頁內(nèi)第 0 到 63 字節(jié))必須存儲(chǔ)到第 0 組,第 1 條緩存線存儲(chǔ)到第 1 組,以此類推。每一組有 8 個(gè)單元可用于存儲(chǔ)它所關(guān)聯(lián)的緩存線,從而形成一個(gè) 8 路關(guān)聯(lián)的組(8-way associative set)。當(dāng)訪問一個(gè)內(nèi)存地址時(shí),地址的第 6 到 11 位(譯注:組索引)指出了在 4KB 內(nèi)存頁中緩存線的編號,從而決定了即將使用的緩存組。舉例來說,物理地址 0x800010a0 的組索引是 000010,所以此地址的內(nèi)容一定是在第 2 組中緩存的。
但是還有一個(gè)問題,就是要找出一組中哪個(gè)單元包含了想要的信息,如果有的話。這就到了緩存目錄登場的時(shí)刻。每一個(gè)緩存線都被其對應(yīng)的目錄單元做了標(biāo)記(tag);這個(gè)標(biāo)記就是一個(gè)簡單的內(nèi)存頁編號,指出緩存線來自于哪一頁。由于處理器可以尋址 64GB 的物理 RAM,所以總共有 64GB / 4KB == 224 個(gè)內(nèi)存頁,需要 24 位來保存標(biāo)記。前例中的物理地址 0x800010a0 對應(yīng)的頁號為 524,289。下面是故事的后一半:
圖片
5.3在組中搜索匹配標(biāo)記
由于我們只需要去查看某一組中的 8 路,所以查找匹配標(biāo)記是非常迅速的;事實(shí)上,從電學(xué)角度講,所有的標(biāo)記是同時(shí)進(jìn)行比對的,我用箭頭來表示這一點(diǎn)。如果此時(shí)正好有一條具有匹配標(biāo)簽的有效緩存線,我們就獲得一次緩存命中(cache hit)。否則,這個(gè)請求就會(huì)被轉(zhuǎn)發(fā)的 L2 cache,如果還沒匹配上就再轉(zhuǎn)發(fā)給主系統(tǒng)內(nèi)存。通過應(yīng)用各種調(diào)節(jié)尺寸和容量的技術(shù),Intel 給 CPU 配置了較大的 L2 cache,但其基本的設(shè)計(jì)都是相同的。
比如,你可以將原先的緩存增加 8 路而獲得一個(gè) 64KB 的緩存;再將組數(shù)增加到 4096,每路可以存儲(chǔ) 256KB。經(jīng)過這兩次修改,就得到了一個(gè) 4MB 的 L2 cache。在此情況下,需要 18 位來保存標(biāo)記,12 位保存組索引;緩存所使用的物理內(nèi)存頁的大小與其一路的大小相等。(譯注:有 4096 組,就需要 lg (4096)==12 位的組索引,緩存線依然是 64 字節(jié),所以一路有 4096*64B==256KB 字節(jié);在 L2 cache 眼中,內(nèi)存被分割為許多 256KB 的塊,所以需要 lg (64GB/256KB)==18 位來保存標(biāo)記。)
如果有一組已經(jīng)被放滿了,那么在另一條緩存線被存儲(chǔ)進(jìn)來之前,已有的某一條則必須被騰空(evict)。為了避免這種情況,對運(yùn)算速度要求較高的程序就要嘗試仔細(xì)組織它的數(shù)據(jù),使得內(nèi)存訪問均勻的分布在已有的緩存線上。舉例來說,假設(shè)程序中有一個(gè)數(shù)組,元素的大小是 512 字節(jié),其中一些對象在內(nèi)存中相距 4KB。這些對象的各個(gè)字段都落在同一緩存線上,并競爭同一緩存組。如果程序頻繁的訪問一個(gè)給定的字段(比如,通過虛函數(shù)表 vtable 調(diào)用虛函數(shù)),那么這個(gè)組看起來就好像一直是被填滿的,緩存開始變得毫無意義,因?yàn)榫彺婢€一直在重復(fù)著騰空與重新載入的步驟。
在我們的例子中,由于組數(shù)的限制,L1 cache 僅能保存 8 個(gè)這類對象的虛函數(shù)表。這就是組相聯(lián)策略的折中所付出的代價(jià):即使在整體緩存的使用率并不高的情況下,由于組沖突,我們還是會(huì)遇到緩存缺失的情況。然而,鑒于計(jì)算機(jī)中各個(gè)存儲(chǔ)層次的相對速度,不管怎么說,大部分的應(yīng)用程序并不必為此而擔(dān)心。
一個(gè)內(nèi)存訪問經(jīng)常由一個(gè)線性(或虛擬)地址發(fā)起,所以 L1 cache 需要依賴分頁單元(paging unit)來求出物理內(nèi)存頁的地址,以便用于緩存標(biāo)記。與此相反,組索引來自于線性地址的低位,所以不需要轉(zhuǎn)換就可以使用了(在我們的例子中為第 6 到 11 位)。因此 L1 cache 是物理標(biāo)記但虛擬索引的(physically tagged but virtually indexed),從而幫助 CPU 進(jìn)行并行的查找操作。因?yàn)?L1 cache 的一路絕不會(huì)比 MMU 的一頁還大,所以可以保證一個(gè)給定的物理地址位置總是關(guān)聯(lián)到同一組,即使組索引是虛擬的。在另一方面 L2 cache 必須是物理標(biāo)記和物理索引的,因?yàn)樗囊宦繁?MMU 的一頁要大。但是,當(dāng)一個(gè)請求到達(dá) L2 cache 時(shí),物理地址已經(jīng)被 L1 cache 準(zhǔn)備(resolved)完畢了,所以 L2 cache 會(huì)工作得很好。
最后,目錄單元還存儲(chǔ)了對應(yīng)緩存線的狀態(tài)(state)。在 L1 代碼緩存中的一條緩存線要么是無效的(invalid)要么是共享的(shared,意思是有效的,真的 J)。在 L1 數(shù)據(jù)緩存和 L2 緩存中,一條緩存線可以為 4 個(gè) MESI 狀態(tài)之一:被修改的(modified),獨(dú)占的(exclusive),共享的(shared),無效的(invalid)。Intel 緩存是包容式的(inclusive):L1 緩存的內(nèi)容會(huì)被復(fù)制到 L2 緩存中。































