存儲之Cache


Cache存在的意義:根據局部性原理,對於當前訪問的存儲位置,接下來,它很可能會被多次訪問(時間局部性),它的相鄰位置也可能會被訪問(空間局部性)。由於訪問內存的速度遠大於訪問寄存器,所以在二者之間設置cache,來暫存一部分指令或數據。

內存:假設每個內存地址有\(m\)位,那么共有\(M=2^m\)個不同的地址,即內存容量為\(M\)字節。如下圖所示,\(m\)位地址划分為\(t\)標記\(s\)組索引\(b\)塊偏移,用於描述該地址所存數據(大小為byte)的副本在cache中的位置。

Cache:使用元組\((S,E,B,m)\)來描述,具體為:

  • \(S=2^s\)表示Cache共有\(S\)個高速緩存組(cache set)
  • \(E\)表示每組均有\(E\)個高速緩存行(cache line)
  • \(B=2^b\)表示每行均包含大小為\(B\)個字節的高速緩存塊(block)
  • 總容量為\(C=S*E*B\)個字節

特別注意:每個cache line包含兩部分,有效位/標記位+高速緩存塊;通常說line size是指高速緩存塊的大小,即\(B\)
1

假設指令指示CPU從地址A讀取一個數據,CPU將地址A發送到Cache,如果Cache含有該數據的副本,它將立即返回數據給CPU;那么Cache如何找到該數據的呢?

  • 組選擇,Cache根據地址A中的s位組索引定位到組
  • 行匹配,Cache根據地址A中的t位標記位定位到行(注意:當且僅當該行設置了有效位,並且該行的t位標記位與地址A的t位標記位完全相同時,該行才包含所需數據副本)
  • 取數據,Cache根據地址A中的b位塊偏移定位到該數據在block中的位置

Cache與內存的映射關系

首先要明確,cache有多個組,每個組有一個或多個行;內存有多個塊,每個塊的大小為\(B\)(即line size),塊的數量為\(2^m/B\)映射關系是內存塊與cache line的映射

一、直接映射高速緩存

\(E=1\),即cache中每組只有一行(即查取數據時沒有行匹配過程)。比如\((S,E,B,m)=(4,1,2,4)\),即cache有4組/4行,內存有8塊,則映射關系如下:
2

二、全相聯高速緩存

\(S=1\),即只有一個組;所以,查取數據時沒有組選擇過程,定位數據副本過程如下:
4

三、組相聯高速緩存

Cache包含多個組,每組又有多個行,所以查取數據時組選擇、行匹配都不會少,過程如下:
5
6

理解關鍵:以上就是CSAPP對cache的主要描述,此時我們對cache的實現原理已經比較清楚了,但是有個很關鍵且令人困惑的問題:一直在說查取數據,cache與內存的三種映射關系並沒有體現出來!我們在各種資料上常見的三張映射關系圖,如何與上述知識對接呢?關鍵就在於t位的標記位! 首先,\(t=m-s-b\),它的含義是每行(或者說每個cache line)可以與\(2^t=\frac{M}{S\cdot B}\)種不同的內存塊產生映射關系(注意,是種,不是個)。

  • 全相聯映射中,每個cache line可以與\(M/B\)(因為S=1)種內存塊(即所有內存塊!)產生映射
  • 直接映射和組相聯映射中,每個cache line可以與\(M/SB\)種內存塊產生映射。區別就在於前者的E=1,也就是說每組只有一行,即內存塊與cache line的映射等價於與組的映射。對於后者,所謂的n路組相聯,也就是說每組包含n個cache line,即內存塊先映射到一個組,然后與該組中的任意一個cache line產生映射。簡單描述就是:直接映射是內存塊直接與cache line映射;組相聯映射是內存塊先映射到組,再映射到cache line!
  • 假設cache中組的編號為0,1,2,...,S-1,對於直接映射和組相連映射,內存地址address映射到組編號為:\(address\ mod\ S\)

緩存缺失的分類

緩存不命中時,常用的替換策略有:最不常使用(LFU)策略,最近最少使用(LRU)策略等。

  • 強制缺失:CPU第一次訪問時的不命中,數據全在內存中,還未緩存
  • 容量缺失:某個cacheline被替換時,其他組(set)全滿,再次訪問該cacheline時發生缺失,即cache不能存放程序運行所需的所有塊
  • 沖突缺失:某個cacheline被替換時,其他組(set)仍有空的cacheline,再次訪問該cacheline時發生缺失,即映射到同一組中的數據塊個數超過組內可容納塊數時,競爭所導致的缺失
  • 一致性缺失:真假共享所導致的缺失,兩個核共享同一個數據為真共享,兩個核共享的數據在同一個cacheline中為假共享

全相聯映射中,除了第一次的強制缺失,其他全是容量缺失(因為只有一個組)。直接相聯映射和組相聯映射中,缺失必定發生在某個組(set):如果其他組全滿,則為容量缺失;反之,為沖突缺失。

有關寫的問題

問題1:假設要寫一個已經緩存的字w(寫命中,write hit),那么在cache中更新副本后,如何更新低一層的副本呢?

  • 方法1:直寫(write through),更新cache中對應的數據副本,並直接將塊寫入存儲器。
  • 方法2:寫回(write back),僅更新cache中對應的數據副本,當所在塊將要被替換時,才寫入存儲器。

方法2相比方法1減少了總線流量,但是增加了復雜性,cache必須為每個cache line維護一個額外的修改位(dirty bit),表明這個高速緩存塊被修改過。此外,在多級cache系統中,存在緩存一致性的問題。
這兩種策略都使用了一種寫緩沖區(write buffer),將數據放入這個緩沖區后,馬上就可以進行緩存操作,而不需要等待將數據寫入存儲器的全部延遲時間。

問題2:如何處理寫不命中?

  • 方法1:寫分配(write-allocate),加載低一層中相應的塊到cache中,然后更新cache。
  • 方法2:非寫分配(non-write-allocate),避開cahce,直接寫到低一層中。

方法1的缺點是每次不命中都會導致一個塊從低一層移動到cache中;方法2的缺點是非常耗時。直寫通常是非寫分配的,寫回通常是寫分配的。
由於cpu中cache對程序員是透明的,建議默認使用寫回+寫分配的模型。原因:一是直寫太耗時;二是與讀相對應。

cache優化

命中率(hit rate):命中的數量/內存訪問的數量
缺失率(miss rate):1-命中率
命中時間(hit time):從高速緩存傳送一個字到CPU所需的時間,包括組選擇、行確認和字選擇的時間。
缺失代價(miss penalty):缺失所需要的額外的時間。

\(存儲器平均訪問時間=命中時間+缺失率\times 缺失代價\)

六種基本緩存優化的方法

其中:6降低命中時間、1-3降低缺失率、4-5降低缺失代價:

  1. 增大塊大小,利用了空間局部性,可以減少強制缺失。但是增加了不命中的處罰。
  2. 增大cache大小,可以減少容量缺失,但是會增加命中時的查找時間。
  3. 提高相聯程度,可以減少沖突缺失,但是也會增加命中時的查找時間。
  4. 采用多級緩存,可以降低缺失代價。\(平均存儲器訪問時間=命中時間_{L1}+缺失率_{L1}\times (命中時間_{L2}+缺失率_{L2}\times 缺失代價_{L2})\)
  5. 為讀取缺失指定高於寫入操作的優先級,降低缺失代價。
  6. 在緩存索引期間避免地址轉換,使用頁偏移地址(虛擬地址與物理地址相同的部分)來索引,減少命中時間。

十種高級優化方法

除了命中時間、缺失率和缺失代價這三個指標,引入緩存帶寬功耗兩個度量。

  1. 降低命中時間:小而簡單的L1 cache、路預測(通常可降低功耗)
  2. 增加緩存帶寬:流水化緩存、多組緩存、無阻塞緩存(對功耗具有不確定性影響)
  3. 降低缺失率:編譯器優化(縮短編譯時間可降低功耗)
  4. 降低缺失代價:關鍵字優化、合並寫緩沖區(對功耗影響很小)
  5. 通過並行降低缺失率或缺失代價:硬件預取、編譯器預取(通常會增加功耗)


免責聲明!

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



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