Cache entries
數據在主存和緩存之間以固定大小的”塊(block)”為單位傳遞,也就是每次從main memory讀取的最小數據的單元。每個塊的大小可能是4,8,16 Bytes或其他值,不同的CPU不盡相同,目前的x86 CPU cache line基本都是64 bytes。通常,人們更習慣稱之為cache行,或者cache line。根據前一篇文章的描述,每個cache line除了包含數據,還包含TAG(地址信息)和狀態信息。
關聯方式(Associativity)
Cache的替換策略決定了主存中的數據塊會拷貝到cache中的哪個位置,如果對于一塊數據(大小為一個cache line ),只有一個cache line與之對應,我們稱之為”直接映射 (Direct map)”;如果該數據塊可以和cache中的任意一個cache line對應,則稱之為”全相聯(Full-Associative)”而目前更多的實現方式是采用”N路組相連(N Way Set-Associative)”的方式,即內存中的某一塊數據可能在cache中的N個位置出現,N可能是2,4,8,12,或其他值。
直接映射
這是一種多對一的映射關系,在這種映射方式下,主存中的每個數據塊只能有一個cache line與之對應,因此直接映射也稱為”單路組相聯”。在1990年代初期,直接映射是當時最流行的機制,Alpha 21064、21064A和21164的L1 D Cache和I Cache都采用直接映射。它所需的硬件資源非常有限,每次對主存的訪問都固定到一個指定的cache line,這種簡單明了有一系列的好處,最大的優點是在200~300MHz CPU主頻的情況下,Load-Use Latency可以快到只需要1個cycle!
一般地,緩存索引I可以示為:
I =(Am÷ B)mod N
其中, Am為內存地址,B為cache line 大小,N為cache line 的總數。
隨著CPU主頻的提高,Load-Use Latency也在相對縮小,直接映射方式的優勢也就顯得不那么明顯,同時,成平方級別增長的主存容量使得cache的容量顯得越來越小。
由于沒有替換策略,主存的數據能存在哪個cache line根本沒得選 ,這也意味著當兩個變量映射到同一個cache line時,他們會不停地把對方替換出去。由于嚴重的沖突,頻繁刷新cache將造成大量的延時,而且在這種機制下,如果沒有足夠大的cache,程序幾乎無時間局部性可言。
如今直接映射機制正在逐漸退出舞臺。
2路組相聯
一個2組2路相聯的如上圖所示,cache分成s組,每組包含兩個cache line,也稱為兩路(2 ways),主存中的每個數據塊只能位于s個set中的某一個,但可以在指定set中的任意一個cache line中。
AMD Athlon的L1 cache所采用的就是這種2路組相聯的映射方式。
N路組相聯
相對于2路組相聯更通用的方式是n路組相聯:cache共分成s組,每組有n個cache line組成。
一般地,緩存索引I可以示為:
其中, Am為內存地址,B為cache line 大小, N表示每組含多少路數(ways),S為組數。
全相聯
全相聯是組相聯的一個極端,這種映射關系意味著主存中的數據塊可能出現在任意一個cache line中。這樣替換算法有最大的靈活度,也意味著可以有最低的miss 率。同時因為沒有索引可以使用,檢查一個cache是否命中需要在整個cache范圍內搜索,這帶來了查找電路的大量延時。因此只有在緩存極小的情況才有可能使用這種關聯方式。
小結
主存和cache的關聯方式的選擇,是多種因素互相妥協的結果。比如某種替換策略使得一個主存數據塊可以有10個cache line與之相對應時,處理器就必須想辦法查找這10個位置,看看是否在其中某一個命中。越多的查找,意味著需要越大的功耗,越大的芯片面積,以及越長的時間;而從另一個角度來看則是,越多的對應項可已有越低的miss,也就需要花費更少的時間來等待數據從低速主存獲取。
研究(參考1)表明將路數N增大一倍,對于cache命中率的提升效果和增大一倍cache面積幾乎相等。但是,當路數大于4以后,對于命中率的提高作用就不那么明顯。而另一些研究(參考2,3)則表明,就單級cache而言,8路組相聯的方式和全相聯從miss率上來看效果相當。不少CPU采用了16路甚至32路組相聯的關聯方式,并不是單單為了降低miss率。
前大部分cache使用的都是N路組相聯的方式。
N路組相聯的Cache結構
如上圖所示,一個cache line 分成兩部分存儲,RAT和Status狀態位存儲在CAM(Content Addressable Memory)中,以利于并行查找(Parallel search),相比較于串行查找(Sequential search),并行查找雖然可以獲得較快的速度,但當Way數較多時,需要占用相當多的物理資源。目前大部分的架構中,數據字段一般采用多端口,多Bank的SRAM陣列。
CAM分NAND和NOR兩種,NOR CAM使用并行查找,NAND CAM使用級聯查找。隨著每個cache line上包含的信息越來越多,使用NOR CAM時需要的功率越來越大,且由于實現方式的原因,路數越多會導致時延越大(參考4);而NAND CAM采用一推一的方式,對功耗的要求較低。
CAM除了需要判斷某一單元是否命中之外,就是查找電路的驅動問題,一個門電路的驅動能力和許多因 素有關,如電流、頻率、介質等。提升驅動能力的方法有很多,如采用金屬介質、適應多級驅動器,縮短走線距離等,但這些方法不是導致功耗變大,就是導致時延變長。當然還有人提出使用流水方式,使用更多的節拍來完成搜索,這顯然和各大廠家努力在盡可能少的節拍內完成cache讀寫操作的目標相悖。種種原因使得現代處理器中L1 cache的關聯路數不會太大。
目前大部分CPU采用的是2-Ways、4-Ways、8-Ways或者16-Ways組相聯的方式,路數多為2的冪,以便于硬件的實現,當然也不是沒有例外,個別CPU中就有10路或者12路的情況,出現這個現象的原因在于路數并非對。在一個外設中,CPU 和外設都可以訪問主存儲器,比如顯卡或者各類PCIe設備。這些訪問并不完全相同,多數情況下,CPU經過LSQ、FLC、MLCs之后通過LLC最終與主存交換數據,外設進行DMA訪問時,直接面對的是LLC和主存儲器,并對L1 cache產生間接影響。這些差異使得處理器中中LLC路數的構成是由若干而2的冪之和。
除了訪問路線的不一致,另一個使得非對等路數的原因是為了降低miss 率。如Skewed-Associative cache(參考5)使用兩種hash算法,分別映射一個組內的不同兩路,這樣可以在不增加組和路數的情況下有效降低miss率。
在某些情況下,cache miss導致的代價是無法忍受的,比如TLB miss,無論采用存軟件還是硬件輔助的形式,miss導致的代價都過于昂貴,最終人們選擇了全相聯的實現方式。TLB的設計還必須對Hit time和Hit rate進行折中,應此TLB分成兩級,L1-TLB的設計側重于使Hit time小一些,其目標就是盡可能快;而L2則需要進一步考慮命中率問題,通常比較大,而且是采用N路組相聯的方式。
參考1:《Phased set associative cache design for reduced power consumption》,鏈接
參考2:《Computer Architecture A Quantitative Approach》 David A. Patterson and John L. Hennessy [Jan. 2008]
參考3:《Cache Memories》 Alan Jay Smith [Sep. 1982], ACM Computing Surveys Volume 14 Issue 3.
參考4:《Cache Memory》 Wang Qi, Yang xi等 [Mar. 2010]
參考5:《A case for two-way skewed-associative caches》 Andre Séance [May. 1993]