對緩存的思考——提高命中率


開篇

編寫高效的程序並不只在於算法的精巧,還應該考慮到計算機內部的組織結構,cpu微指令的執行,緩存的組織和工作原理等。

好的算法在實際中不見得有高效率,如果完全沒有考慮緩存、微指令實現的話。

前兩篇博文

局部性原理淺析 介紹了程序的局部性原理,如何寫出局部性良好代碼。

提高程序性能、何為緩存 討論了存儲器層次結構,計算機內部的存儲結構、緩存的概念,簡單的介紹了緩存的工作機制。

建議先閱讀前兩篇博文,雖然他們之間聯系不大,在前面也有一些對本文的鋪墊。而且,這是一個系列的文章。旨在優化程序性能。

這篇博文主要介紹的是緩存的組織、工作原理。撥開迷霧,讓你更加清晰的認識緩存。

通用緩存結構

回顧

提高程序性能、何為緩存中提到:早起的cpu存儲層次只有三層,即cup的寄存器,DRAM主存和磁盤存儲。因為寄存器和主存之間的訪問時間開銷差距很大,於是設計者在寄存器(一個時鍾周期)和主存之間加入了L1緩存(2——4個時鍾周期),后來由於L1緩存和主存之間的差距,又在主存和L1之間加入了L2緩存,當然后面還有L3緩存,,,等等。

在這里為了簡單起見,假設CPU寄存器和主存之間只有一個L1緩存。

下圖是高速緩存存儲器的典型總線結構:

緩存結構

下圖清晰的說明了通用緩存的組織結構:

可以看到,緩存內部是以組的形式組織的。圖中的每一塊代表一組,每組由一到多行組成(當然圖中的是每組有多行)。

每一行包括

1 位標記位(valid bit)標明這行的信息是否有可用

t 位的標記,標明它是屬於這一組的哪一行

剩下的空間是存儲數據的數據的空間

可以看出在下面的圖中把數據地址分為了三部分,左邊 t 位是標記行號的,中間的 s 位標明組號,最后的 b 位則是數據塊在行內的偏移量。

通常來說,緩存器可描述為(S; E; B; m)其中S為緩存中的組數,E為每組的行數,B為每行存儲的字節數,m為緩存的地址位數。

所以緩存的容量為C=S*E*B。

從緩存中取數據

(這個過程在上一篇博文中就有簡單的介紹)當cpu需要從主存中取出地址為A的數據時,先把地址A發送給緩存,如果緩存中存有地址為A的數據,就從緩存中取出該數據傳給cpu。

那么,緩存是如何知道自己是否存有地址為A的數據呢?這就和緩存的組織有關系了,上文中緩存把地址組分為了三部分,t 、s 、b。

所以,只要簡單的檢查地址中的數據位,就能判斷該地址是否在緩存中,如果在的話,還能確定該數據的位置。

參數 s 、b 、m 把m個地址位分為三個字段。如下圖:

下面的詳細的尋址過程

地址A中的中間S 位標記了該地址在緩存中屬於哪一組,先通過s 確定這個地址在緩存中的哪一組。

通過上面一步確定了屬於的組后,地址A中的左邊 t 位標記了該地址在該組的哪一行。

最后由右邊的 b 指出地址A中的元素在該行的偏移位。也就是確定在這行的哪一個位置。

CPU從主存中讀數據的詳細過程

和上文中說的一樣,這里假設計算機的存儲結構只有:cpu寄存器,L1緩存,主存。

當cpu執行一條讀存儲器地址為A的指令,它向高速緩存請求該地址,如果緩存命中,緩存很快返回數據。如果緩存不命中,L1緩存向主存請求該數據,在這期間cpu必須等待。當被請求塊從主存到達緩存L1時,L1緩存將數據放在他的一個高速緩存行里,然后將數據從行中提取返回給cpu。也就是說,如果緩存不命中,先要把數據存入緩存,再返回給cpu。

概括的說,高速緩存確定一個請求是否命中有三個過程: 

1、組選擇

2、行匹配

3、字抽取

下面將會結合具體情況說明這一過程。

直接映射高速緩存

現在已經知道,我們用(S; E; B; m) 來描述緩存,這里就根據其中的E,也就是一組的行數, 把緩存分為不同的類別。

當E=1 時,也就是說每組只有一行的緩存組織形式,我們稱為直接映射高速緩存。因為容易理解,先對它進行介紹。

(圖片來源 《computer systems》)

正如上圖所示,直接映射高速緩存中每組只有一行。

直接映射高速緩存中取數據

下面將以直接映射高速緩存為例,一步步說明cup從高速緩存中取數據的過程。

1、組選擇

如上圖所示,緩存從地址A中抽取出中間的s 位,這 s 為的數值就標記了該地址所在的組。這里可以把緩存當作是一維數組,其中每個元素是一個組,而地址中的 s 位則是這些組的索引。如圖中的組標記為 0001 對應組 set1。這要把地址中間的 s 為提取,就能得到該地址在緩存中對應的組。

2、 行選擇

選好組 i 之后,就是確定地址A在組 i 的哪一行。因為直接映射緩存的每一組只有一個行。所以只要看A地址中的行標記是否和緩存中的行標記位匹配。匹配則地址A中的數據在緩存中。

3、字抽取

既然已知道了地址A中的數據在緩存中的位置,最后一步只要更具地址A中表示偏移量的位,從緩存中取出數據即可。

如下圖所示:

直接映射高速緩存不命中

當緩存不命中的時候,就要從下一層存儲中取出數據,放入緩存的某個位置中,放入的位置就由請求地址A中的組索引確定所在緩存的組,行所以確定應該放置的行。如果組中的行都是有效緩存行了,就必須要驅逐現有的一個行。對於直接映射高速緩存,每組包含一個行,替換策略就變的很簡單,用新來的行替換當前行。

直接映射緩存尋址示例

通過上面的介紹,已經基本了解了緩存的組織形式以及如何從緩存中取出數據,但是上面都只是理論上的闡述。

為了能更好的了解,這里會有一個具體的示例。誠然,學習一種只是最好的方式就是應用它。 如果你已經對上面的知識有所了解,那么請繼續吧。下面的內容會讓你更清楚的了解到緩存工作的機制。

假設我們有一個直接映射的高速緩存,描述如下

(S; E; B; m)=(4;1;2;4)

也就是說:該緩存有4個組(s=4),每組有一行(E=1),每一塊有兩個字節(B=2)存儲器的地址是4位的(m=4)

該狀態有圖描述如下:

其中最左邊的一列是地址,中間的三列是地址的二進制表示形式。最右邊的一列是虛擬存儲器的塊的標號。

和上文中說的一樣,緩存尋址時,把地址分為了三個部分。分別表示該地址在緩存中所在的組、行、以及偏移。和上圖所對應是四位的地址,

行:其中最高的一位標記所在的行,因為是直接映射高速緩存,每組只有一行,所以一位就能表示。

:中間的兩位表示地址所在的組。從圖中可以看出,擁有相同組的地址有四個,比如組號為00 的地址有四個,為0、2、8、9

偏移:偏移位由最右邊的一位表示。每行中有兩個數據塊,所以偏移位用一位也就能表示。

看這個表的時候有一點提示:中間的三列其實是第一列地址的二進制表示形式。

下面是對這個特定緩存的一點分析:

(S; E; B; m)=(4;1;2;4)

該緩存有四個組,每組一行。有圖中可知,要放入緩存的地址為16個。所以每組對應四個地址。在圖中的表現就是:四個相同的地址有相同的組索引。

每行有兩個數據塊,用地址最低位表示(0表示第一個,1為第二個)。

看組索引為00的地址,為0 、1 和 8 、9。0和1有相同的行標記0,8和9有相同的行標記1.所以地址為0、1的數據要么都在組00中,要么多不在。地址為8、9的也一樣。說明了0、1是一個整體,8、9也一樣。如果在,都在;不在,都不在。這兩個整體通過最高位(標記為)來標明。

下面是尋址實例

剛開始時,緩存是空的,也就是還沒有預熱,如下圖所示

1)讀地址0的字

地址0的為 0 00 0 對應緩存中第0組,行標記位為0的,偏移為0的位置。顯然,現在緩存還是空的(標志位 valid 都為0)。緩存不命中,所以緩存先從下一級的存儲中取出改行對應的所有地址的元素,放入緩存中。(也就是地址為0 和1 的元素)。然后再從緩存中取出數據m[0],傳遞給cpu。

進過對地址0的讀操作后,緩存的組織情況如下所示

這也驗證了上文的說法,地址0 和1 是一體的,他們要么都在,要么都不在。因為他們有相同的組索引、行索引。

2)讀取地址1的字

地址1為0 00 1 對應緩存中的第0組,行標記為0,偏移為1。這次緩存命中,從緩存返回m[1]

3)讀地址13的字

地址13為1 10 1 對應緩存中的第2組 行標記為1 偏移為1。同1)一樣,緩存不命中,從低一級存儲中取出 組索引為10 行為1 的數據放入緩存,然后返回m[13]

對地址13進行操作后的緩存情況為

4)讀地址為8的字

地址8為 1 00 0 組索引為00 行標記為1 偏移為0 在看上圖的緩存組織情況,可判讀發生緩存不命中。於是從低一級存儲中取出組索引為00 行標記為1 的數據,也就是m[8]、m[9]放入第一行中,然后返回m[8]

操作后的緩存組織為

通過上面的示例,應該對緩存的工作原理有一定了解了把。

其實就是吧地址分為不同的部分,划分為表示組、行 和偏移。然后根據這些去判斷所需地址是否在緩存中。如果在,則返回數據,不在則從低一級的存儲中取出數據放入緩存中(放入的位置由地址確定)。然后返回地址。

組相聯高速緩存

 剛才討論的直接映射高速緩存可以看作是緩存中的一個特例,因為每組只有一行。這里介紹一下更普遍的緩存結構:組相連高速緩存。

其實就是每一組有多行。如下圖是E =2 的緩存

同樣的,當要從緩存中取地址為A的數據時,

1)先確定地址A所在的組,如下圖所示

2)確定行

3)抽取字(偏移)

全聯高速緩存

 全聯高速緩存中的S =1 ,也就是說,全聯高速緩存只有一個組。

全聯高速緩存中對數據的操作和之前討論過的兩種情況大同小異,主要就是三部。這里就不說了。

小結

這篇博文先介紹了緩存內部的組織形式,並介紹了從緩存中讀取數據的方式,主要包括1)組選擇2)行匹配 3)字抽取

緩存可以用形如(S; E; B; m)的形式表述。其中S代表緩存中的組數,E為每組的行數,B為每個緩存塊的大小。

更具E的不同可將緩存分類。

這篇文章主要介紹的是緩存的工作機制。在以后的文章中會介紹如何寫出緩存友好的代碼

 

全文完。

 

 對於如何寫出緩存友好的代碼,對緩存的思考【續】——編寫高速緩存友好代碼中做出了詳細討論

 

參看資料:computer systems

如有轉載請注明出處:http://www.cnblogs.com/yanlingyin/

一條魚、尹雁鈴@ 博客園 2012-2-12

 E-mail:yanlingyin@yeah.net

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM