基於緩存的存儲器層次結構
基於緩存的存儲器層次結構行之有效,是因為較慢的存儲設備比較快的存儲設備更便宜,還因為程序往往展示局部性:
時間局部性:被引用過一次的存儲器的位置很可能在不遠的將來被再次引用。
空間局部性:如果一個存儲器位置被引用了一次,那么程序很可能在不遠的將來引用附近的一個存儲器位置。
通用高速緩存存儲器結構
一個通用的高速緩存存儲器會有S = 2 ^ s個set(組)
每個set含有E個line(既通常所說的cache line)
每個line又包含1位vaild bit、 t位tag、B = 2 ^ b bytes cache block(真正存儲數據的地方)。
通常我們說的cache line 64位 32位,實際上是說的cache line中cache block是64位32位。
假設我們的存儲器地址有m位,共M = 2^m個不同的地址。我們看一下各個變量之間的關系。
cache緩存數據的大小C = (sizeof set * number of set) = (size of block * lines a set) * number of set = B * E * S
內存大小2^m Cache line大小2^b 內存的cache line個數2^(m-b)
2^(m-b)個cache line分到2^s個set里, 每個set會有2^(m - b –s)個cache line,這個數字不是E,是指會有2^(m – b –s)個cache line落到這個set 里面,那么就需要有m-b-s位tag,標記出當前是哪個cache line落到這個set里面了。也就是說t = m - b –s。
如上圖所示,m位地址的內存,需要s位做索引,選set,t位做tag,選cache line,然后b 位做偏移取具體地址的內存。
高速緩存的映射
高速緩存確定一個請求是否命中,然后抽取出被請求的字的過程,分為三步1)組選擇2)行匹配3)字抽取。
直接映射
直接映射每個組只有一行E=1
選組
地址中取s bits選組
選行
地址中取t bits與cache line中t bits tag匹配,匹配則命中,不匹配則cache miss
字抽取
地址中的b bits就是cache line中偏移,在命中的cache line中的取字。
直接映射不命中時,不需要什么策略,直接把索引的組中的cache line替換掉即可。
組相連映射
組相連映射中,一個組包括多個cache line,目前常見的有四路組相連映射,16路組相連映射,即一個set中有4個或16個cache line。對比直接映射,set 個數要比直接映射的少。因此s會小,相應的落到每個set中的cache line會多,因此t會大。
選組
組相連映射的組選擇與直接映射一致。
選行
cache line的選擇時,因為一個set中有多個cache line,因此需要搜索set中的每個cache line的tag,對比檢查是否命中。
字抽取
與直接映射一致
組相連映射對於一個index就會有多個行與之相對應,比較每行的tag是否與想要的地址相符合,這樣就會大大增加命中的幾率,避免了一小段程序中頻繁cache失效的問題。
組相連映射不命中時,由於索引到的組中會有多個cache line,因此會有多種算法選擇到底替換哪個cache line。
全相連映射
全相連映射就是組相連映射只有一個組的情況。
選組
全相連映射組選擇很簡單,只有一個組,不需要組索引,s = 0,地址只被划分為一個標記tag,和一個偏移。
選行
全相連映射cache line選擇時,需要多緩存中的所有cache line進行搜索對比。
字抽取
與之前一致
全相連映射需要大量的搜索cache line進行對比,導致構造一個又大又快的全相連高速緩存很困難,而且很昂貴。因此全相連緩存只適合做小的高速緩存,比如TLB。
Core i7的高速緩存特性
以上內容來自《深入理解計算機系統》6.4
以下內容來自互聯網
幾種cache方式
Virtual index virtual tagged
邏輯cache,Virtual index virtual tagged是純粹用虛擬地址來尋址,邏輯地址索引邏輯地址tag,這種方式帶來了很多的問題,每一行數據在原有tag的基礎上都要將進程標識加上以區分多個進程之間的相同地址,而在 處理共享內存時也比較麻煩,共享內存在不同的進程中的虛擬地址不相同,如何同步是個問題。
Physical index physical tagged
物理cache,Physical index physical tagged,物理地址索引和物理地址tag,是一種最容易理解的操作方式,cache針對物理地址進行操作,簡單粗暴,而且不會有歧義。但是這種方式的缺陷也很明顯,在多進程操作系統 中,每個進程擁有自己獨立的地址空間,指令和代碼都是以虛擬地址的方式存在,cpu發出的memory access的指令都是以虛擬地址的方式發出,這樣的話,對於每一個memory access的操作,都要先等待MMU將虛擬地址翻譯為物理地址,這是一種串行的方式,效率較低。
virtual index physical tagged
現在比較多的是采用virtual index physical tagged的方式,virtual index的含義是當cpu發出一個地址請求之后,低位地址去和cache中的index匹配, physical tagged是指虛擬地址的高位地址去和mmu中的頁表匹配以拿到物理地址(index和取物理地址這兩個過程是並行的),然后用從mmu中取到的物理地 址作為tag(或者tag的一部分)去和cache line的tag位匹配,這樣既保證了同一地址在cache中的唯一性(有個例外,cache alias)又能將mmu和cache並行工作,提高了效率。
這種方式帶來的唯一問題就是cache alias,即一個物理地址緩存到兩個cache line中。當進程間通過共享內存方式通信,或者一個進程通過mmap的方式內核與應用層共享內存,就會出現同同一塊物理內存,以多個虛擬地址訪問的情況。就容易導致一塊物理內存緩存到兩個cache line中。
由於共享內存是頁對其的,因此多個進程空間的共享內存,或者內核態用戶態的共享內存,其物理地址不同,但其頁偏移是相同的。
假如頁大小為P = 2^p 字節,cache line為 C = 2^c 字節,那么共享內存的不同虛擬地址其低p位是一致的,假如地址0 -> c位用於block offset,c -> p 位用於set index,那么就可以避免cache alias的問題。
但如果set index 位數 > p -c ,那肯定會出現cache alias的問題,因為同一塊物理內存,不同的虛擬地址,其set index不同。
針對於cache alias問題,目前的方案是由操作系統來保證,對於同一物理地址在不同進程空間的虛擬地址,要保證他們index相同,落在同一個set,就需要保證他們虛擬地址的差值是cache大小的整數倍。同時已經有些cpu廠商在開發監視模塊,試圖在硬件層面解決類似的同步問題。