Cache的三種映射和局部性
計算機存儲層級結(jié)構(gòu)

上圖是計算機的存儲的層次結(jié)構(gòu)圖,自上而下,運行速度越來越慢,存儲容量越來越大
其實CPU在運行時,所需要的操作數(shù)大多數(shù)是來自寄存器的,速度是很快的,而離CPU越遠的,運算速度越慢
就我個人的理解,cache就是我們CPU內(nèi)部的SRAM,主存是DRAM,也就是我們經(jīng)常聽說的內(nèi)存條,外存儲就是硬盤之類的
我們應該了解,計算機在運行時,操作指令多存放在主存(內(nèi)存條)中,再結(jié)合上圖可以發(fā)現(xiàn),主存并不是離寄存器最近的存儲器件,那么為了提高計算機的速度,應當將運行指令先從主存中拷貝到cache中,對DRAM和SRAM有過了解的小伙伴應該知道,SRAM運行速度快,但成本高;DRAM運行速度相對慢,但是價格相對便宜,因此cache的容量必定不會與主存的容量大小相同
那么如何保證從主存拷貝到cache中的指令和數(shù)據(jù)正是我們所需要的呢?
這就涉及到了程序訪問的局部性
程序訪問的局部性
分析結(jié)果表明:
在較短時間間隔內(nèi),程序產(chǎn)生的地址/所訪問數(shù)據(jù)往往幾種在存儲器的一個很小范圍內(nèi)
程序訪問局部性可以分為:時間局部性和空間局部性
時間局部性:剛被訪問過的存儲單元很可能不久后又被訪問
空間局部性:剛被訪問過的存儲單元臨近的單元很可能不就后被訪問
這里再來介紹個概念

CPU和cache之間是以字
進行指令/數(shù)據(jù)的傳輸
主存和cache之間是以塊
進行指令/數(shù)據(jù)的傳輸,每個塊中又包含多個字(單元)
當CPU要從主存中讀取指令/數(shù)據(jù)的時候,會先查看cache中有沒有,如果有直接調(diào)用cache中的指令/數(shù)據(jù),如果沒有則先從主存中拷貝到cache中,在從cache中調(diào)用
從兩個局部性分別來看
時間局部性:對于從主存拷貝到cache中的指令/數(shù)據(jù),如果不與映射方式?jīng)_突,不會在CPU調(diào)用完后就立即擦除(映射方式接下來會介紹),可以理解為,被CPU調(diào)用的指令/數(shù)據(jù)還是保留在cache中,如果下次再次調(diào)用這些指令/數(shù)據(jù),它們還在cache中,不用從主存取
空間局部性:因為從主存中拷貝到cache中的指令/數(shù)據(jù)是以塊為單位的,假如說一個塊中有10個數(shù)字,剛開始CPU想訪問在數(shù)字1位置的指令/數(shù)據(jù),而cache此時將數(shù)字0-9都拷貝進cache中,那么下次CPU想訪問在數(shù)組5中的指令/數(shù)據(jù)時,它們也都在cache中
cache與主存的映射
cache與主存可按三種方式進行映射:直接映射、全映射、組映射
直接映射
(直接從網(wǎng)上的視頻中摘個題目)

因為主存和cache之間是以塊為單位進行傳輸?shù)?,因此cache和主存中每個塊的大小要相同

這是直接映射的示意圖
從題目中給的計算結(jié)果看,cache共分為16個槽(也叫行),主存共分為2048個塊
將主存的塊根據(jù)cache的槽數(shù)進行塊群的劃分
128個塊群是由主存的2048個塊 / cache的16個槽
得來的,主存中每個塊群有16個塊
直接映射就是每個塊群的第幾個塊只能映射到cache的第幾個槽中
這么說有點抽象,換個說法
0塊是0塊群的第一個塊,那么0塊就只能映射到cache的第一個槽(0槽);16塊又是1塊群中的第一個塊,那么16塊也只能映射到cache的第一個槽(0槽)
在介紹局部性的時候,我有提過“如果不與映射方式?jīng)_突”,試想一下,按照直接映射的方式,CPU第一次訪問的是主存的0塊,下次訪問的是主存的16塊呢
接下來介紹地址

從這個圖中可以看到,地址分為:主存地址、主存塊號、主存標記、cache槽號、塊內(nèi)地址和cache地址
塊內(nèi)地址指出來每個塊中訪問的是第幾個單元
cache槽號指出存儲在第幾個槽中
cache槽號指出指令/數(shù)據(jù)存儲在cache中第幾個槽的第幾個單元中
主存標記指出訪問的是主存中的第幾個塊群
主存塊號(主存標記+cache槽號)指出訪問的是主存的第幾個塊
比如我們要對0220CH單元進行訪問
0220CH轉(zhuǎn)換成二進制是 0000_0010_0010_0000_1100B
主存標記是前7位 ?-> ?0000_001 (1塊群)
cache槽號是主存標記后面的4位 ? -> ?0_001 ?(1槽)
塊內(nèi)地址是最后的9位 ?-> ?0_0000_1100 ?(12單元)
主存塊號是前11位 ?-> ?0000_0010_001 ?(17塊)
即0220CH單元是主存中1塊群1塊(17塊)中的12單元
直接映射訪問方式:
假如CPU想訪問主存0塊中的12單元,CPU先查看cache的0槽(0塊應當映射到0槽中)是否存在0塊的內(nèi)容,如果沒有則先將主存0塊中的內(nèi)容拷貝到cache的0槽,在從cache中訪問
試想一下,假設我們的cache固定,就是16個槽,如果我們的主存非常大,要分很多塊群,是不是就大大增加了hit cache同一個槽的概率了
這也是直接映射的缺點
全映射

全映射是主存中任意一個塊都可以映射到cache中的任意一個槽中,沒有主存的某個塊只能映射到cache的一個槽中的限制
因此,對于全映射的地址來說,主存地址中不存在cache槽號的內(nèi)容
全映射訪問方式:
假如CPU想訪問主存0塊中的12單元,CPU會從cache的0槽到15槽依次查看0塊是否映射到cache中,如果都沒有,主存才會將0塊映射到cache中
試想一下,如果cache的槽號非常多,CPU每次要訪問主存中的某個塊里的單元,都要先將cache中的每個槽先查看一遍,是不是很浪費時間
組映射
組映射可以理解為是直接映射和全映射的結(jié)合體

在組映射中,會將cache進行分組,每組cache又會存在幾個槽
組映射時,主存和cache的組之間映射是直接映射,與cache組中每個槽之間的映射時全映射
就像之前的例子,我們將cache的16個槽分為8組,每組有2個槽,那么在進行組映射的時候,主存在中塊會先與cache的組進行直接映射,在確定要映射的組后,再與組內(nèi)的兩個槽進行全映射

這里地址中的標記位指出對應槽取自主存的哪個組群
聯(lián)想剛才在全映射和直接映射提出的兩個極端的情況:
如果主存很大(塊多),主存的塊hit cache同一個槽的概率增大,而在組映射的情況下,主存的塊hit的是cache的組,而cache的組內(nèi)有多個槽,主存的塊可以存放在cache組內(nèi)的任何一個槽中
如果cache很大(槽多),CPU要訪問主存的某個塊時,只需要先在cache的固定組中查看這個塊是否存在即可
對比三種映射的地址
直接放圖吧
