在一切開始之前,首先最重要的是需要去明白和掌握內存的塊的定義:內存被分為若干塊,這些塊:1.大小相等,2.每塊由若干字組成,3.塊的長度成為塊長,塊的長度是指由幾個字組成就是多長,比如一個塊由x個字組成,那么塊長為x.4.每個塊由連續的字組成。在Cache中這種塊被某些替換原則替換進入Cache之后,稱為Cache的行(有些書上也稱為塊,這里就用行表示,以免混淆)。有以下幾個特點:
1.塊長(一般是取一個存取周期內從主存調出的信息長度,和交互存取有關系)與行長相等,這點和物理頁和邏輯頁的頁內地址的長度是一樣的原理類似。
2.Cache中行的位數=行號+行內地址 內存中塊的位數=塊號+塊內地址。
3.塊內地址的位數由塊的長度決定(設塊的長度為x,塊內地址的位數其實就是用幾位能表示x的問題),塊號的位數由塊的數目決定(比如塊的數目是x,塊號其實就是用幾位二進制數能表示x個數的問題),行號的位數由行數決定。塊里的內容就是行的內容,行內地址和塊內地址相同。、
標記位是什么?先記住一點,標記位和cache的地址沒有一點關系。每個行對應一個標記位。后面會進行說明
CPU與內存以及Cache之間的交互方式
好了,明白了塊和行的定義之后,我們來看看CPU與內存和Cache之間的交互:1.CPU同時(也有可能不是同時,這時事先訪問cache cahce里面沒有再對主存進行訪問,如果缺失的話訪存時間會長一點)向Cache和內存發出讀請求。把地址同時送給Cache和內存。2.Cache控制邏輯(由硬件實現)判斷此內存地址是否在Cache中,在則立馬將此內存的字送給CPU,與此同時,終止訪問內存。3.若不在Cache中,用主存讀取周期從主存中將字取出送往CPU,與此同時,把含有這個字的整個數據塊通過Cache與主存的直接通路送到Cache中。(由這個交互過程我們可以看到,主存和Cache與CPU交互的時候傳送的是字,但是Cache和主存交互傳送的是塊)
了解了過程之后我們來看看映射關系是什么,映射關系是CPU在訪存時,將主存地址變換成Cache地址的過程。對應第二步的判斷是否在Cache中的其中一部。
三種映射關系。1.直接映射。2.全相聯映射。3.組相聯映射。
1.全相聯映射
將塊內地址直接變為Cache的行內地址,同時將塊號直接放進Cache的標記位(這個時候標記位就是內存地址的塊號)里去,直接將主存里的一個快包括內容直接拷貝到Cache里的任意一行里去(一般是弄成連續的),這樣相當於相當於建立了一個標記位和行之間的對應關系表,訪問一個內存地址上的字,只要從內存地址中取出塊號,然后在標記位和行之間的對應關系里查表,就能找到這個字所在的行,然后用快內地址(其實就是快內偏移量)找到行中對應的字的地址。
例如,主存現有256個塊(得出塊號為8位),每個快有256個字(得出塊內地址8位),所以內存地址總位數為16位,所以cache塊內地址應該有8位,設它有8行,行號有3位,所以cache地址長度為3 + 8 =11位,標記位為塊號。可以隨便映射到任意一個Cache的行,建立這個塊號(也就是標記位)與映射到的行的對應關系,標記位的內容為塊號(即內存地址的前八位),這個就是簡單的全相聯映射。 此時,主存容量為塊數(256)*塊長(256)為64K,Cache容量為行數 (8)*行長(256)為2K(不包括標記位)。(為什么是K 不是KB?其實寫成64KB 2KB也可以,畢竟表示的是容量,寫成64K 2K就意味着,有64個字的容量,或者有2K個字的容量,因為有些計算機一個字可能不是8位。本例子中是一個字8位)
如何訪問內存中一個字怎么找到他對應的cache的地址呢?(由硬件實現),有一個比較器,1.CPU訪問按內存地址,將其塊號放到比較器中,然后比較器將塊號和標記位與行之間的對應關系表中的標記位一個一個比較,如果有一個標記位和塊號一樣,則說明這個字所在的塊在Cache里,然后用地址的低八位(快內地址,也叫做快內偏移量)找到行中的那個字的地址 然后讀入CPU。2.如果沒有標記位和塊號一樣,說明不在Cache里,通過16位地址直接訪問內存送CPU,同時將這個字所在的塊整個搬入Cache里(硬件實現)。這種方法命中率高,但是比較器電路設計復雜。因為對應關系表中一個標記位就要連一條線,最簡單的比較器就是兩個數比較最簡單,所以有了直接映射。
舉個例子:比如 addr1:0010 1101 0010 1110 addr2:1101 1111 1111 1010 cache 有8行。
划分內存地址 紅色為標記位,黃色為塊內偏移量。剛開始cache為空,訪問addr1 addr2,不命中,從內存讀取塊,開始全相聯映射,比如addr1,他屬於塊0010 1101 0000 0000 ----- 0010 1101 1111 1111,隨機放入一行中,假設放入了101行,那么101行 也就是101 0000 0000 ----- 101 1111 1111這一行的標記位就為 0010 1101,同理 假設addr2放入的行是111,那么標記位就 為 1101 1111,建立標記位和行的對應關系,相當於打表,表中有兩項,0010 1101 對應 101 0000 0000,1101 1111對應 111 0000 0000 .第二次訪問addr2的時候,遍歷這張表,找到標記位與addr2前八位相同的表項 ,取出行號111 ,再與其塊內偏移量一拼,就得到了cache中的地址111 1111 1010,這個地址上就是我們要訪問的字。
2.直接映射
指的是 主存里的一個塊能通過一個式子的映射能放在Cache中的一個特定的行里(這個邏輯由硬件實現)Cache的行號 i 和主存塊號j存在關系 i=j mod n n為總行數,比如43號塊,cache中有10行,說明43 必須放入第行號為3的那一行行,而且23 13 53等都是這樣。
例子:
內存地址16位,Cache行數8行,內存地址低八位位塊內地址,高八位位塊號。這時,塊號8位中的低三位,其實是塊號除於八的余數(000-111),所以可以直接用內存地址當中的這三位來表示cache的行號,都不用算 ,結果剩下5位是標記位,內存的塊往cache放的時候,內存地址的高八位中的的低三位是多少就往第幾行放(硬件實現),吧剩下五位當做標記位,建立標記位與行的映射關系,便於查找。
原理。拿到16位地址之后,取出高八位的低三位確定行號去找第幾行。吧這一行的標記位拿出來通過比較器和地址前五位比較,如果一樣,則命中,不一樣不命中,若命中,再根據塊內地址(快內偏移)找到字送給cpu,不命中,訪問內存,把包含這個字的整個塊放到剛才我們找的那一行里面去(硬件實現)
比較器簡單,只用比較兩個數,但是不靈活,會產生抖動,沖突率最高,空間利用率最低。同時注意不需要替換算法。
舉個例子:比如 addr1:0010 1101 0010 1110 addr2:1101 1111 1111 1010
兩個內存地址:划分內存地址 紅色為標記位,藍色為行號,黃色為塊內偏移量,cache一開始為空的時候 訪問這個兩個地址,不命中,開始直接映射,內存地址划分之后紅色表示的是標記位,藍色表示的是組好,黃色表示的是塊內地址,那么addr1就是應該映射到行號為101的cache行,意思是整塊映射到地址為101 0000 0000 -----101 1111 1111的cache行中, addr2 映射到行號為111的cache行,意思是整塊映射到地址為111 0000 0000 ----- 111 1111 1111的行中,然后建立起標記位和行的對應關系,00101 對應101 0000 0000 (相當於把這一行的起始地址與標記位對應) 11011 對應111 0000 0000 ,當訪問addr1的時候 獲得組號10,查表,通過硬件直接得到 101行的標記位00101,命中,然后快內偏移位0010 1110 直接與101 連接起來 得到最終要的要訪問的字所在的cache地址 101 0010 1110 。
3.組相聯映射
是折中的方法,將cache的8行分為4組,沒組2行,這叫做2路組相聯,(一組4行叫做,4路組相聯)。然后用內存地址的塊號處於總組數,余數是幾就往第幾組放,組里面隨便放。組內相當於全相聯,組間直接映射。
內存地址,16位分隔為3部分:6位(直接作為標記位)+2位(用來確定組號)+塊內8位。看組號是幾,就放第幾組,組里面隨便放。將剩下6位當做cache標記位。二路組相聯比一路的組號少一位,4路的少二位。。。類推
查找過程:獲得16位內存地址,由組號是幾就找第幾組,將里面兩個行的標記位和內存地址的前6位比較,如果有一個一樣,說明命中。由塊內地址找到字。兩號標記位都不一樣,就在內存中讀出數據同時將字所在的整個塊放到我們剛才找的那個組里面去,兩行隨便放(硬件實現)
舉個例子:比如 addr1:0010 1101 0010 1110 addr2:1101 1111 1111 1010
兩個內存地址:紅色表示的是標記位,藍色表示的是組好,黃色表示的是塊內地址,第一次訪問addr1 addr2 未命中,將內存塊放入cache,那么addr1就是應該映射到組號為01的組,也就是第一組 意思在地址為010 0000 0000 ----- 010 1111 1111的cache行和地址為 011 0000 0000 ----- 011 1111 1111的cache行中, addr2 映射到組號為11的cache行,也就是第3組 意思是在地址為110 0000 0000 ----- 110 1111 1111的行以及111 0000 0000 ----- 111 1111 1111的行中。組內隨便放,比如addr1 ,他所在的塊0010 11 ...... 放入的是011 0000 0000 ---- 011 1111 1111的cache行中,那么他的這一行的標記位為0010 11,進建立對應關系,下次訪問addr1的時候 直接得到組號,然后找到組好對應的兩個行,取出標記位,與紅色區域進行對比,然后與塊內地址一拼接,就得到了字所在的地址。
計算問題
在cache的試題當中,我們會發現很多寸步難行的地方,主要的原因還是對於cache的地址的不了接所造成的。比如要你求cache的總容量你會怎么求呢。比如告訴你cache的總容量為16KB你就會說這么簡單,不就是cache的地址是14位嗎?的確有道理,因為不管你划分什么鬼標記位,塊內地址,甚至是什么片選信號位,以及頁號等等等,其實實質上都是一個地址對應一個字的數據,比如1100 1100 0011 0101這個地址,你無論怎么划分標記位什么的,其實就是相當於給整個存儲系統分了幾個部分。僅此而已,所以有道理。但是其實錯了,為什么,這下我要告訴你cache的地址的真正構成,這個地方是本人經過很多題目的訓練和網上尋找答案總結出來的東西,都是干貨
大家都知道cache中的一行由標記位和塊內地址組成,但是大家知道嗎,其實一行中,有很多個字節,但是標記位只有一個,而不是每個字都對應一個相同的標記位。什么意思呢?就是cache的總容量首先有塊內地址的容量,比如一個行長是64B的cahce,他的塊內地址的容量就是512bit,這叫做每行存儲的數據,也叫做數據塊的位數但是在這一個快中,只有一個標記位,這個標記位,其實實質上不屬於cache的地址。只是一個內容。(詳情見王道P119)所以
cache的總容量=(有效位(每個行一般會加上一個有效位)+臟位+替換控制位+標記位的位數+數據塊總位數。(一般題目會要求“若不考慮用雨cache的一致性維護和替換算法的控制位”,如果沒有這個條件,但是他也沒說寫策略用的是哪個,或者沒說替換策略用的是哪一個,那么久當做只有 有效位來處理))X行數;
所以,如有上面那句話,
cache的總容量=(有效位(每個行一般會加上一個有效位)+標記位位數+數據塊總位數)X行數。
例:塊長(有些書上稱行為快)為64B(行長一般是K做單位,表示字的個數,但是題目有時候會用B ,bit KB MB這個意思就是一個行的有效容量,也就是一般所說的容量,還有數據塊的位數),主存256MB,按字節編址(一般默認是這樣,除非題目說明了按字編址或者說是出現了aMXbB這樣的描述內存大小的方式)。有8行。求cache總容量和容量(若不考慮用雨cache的一致性維護和替換算法的控制位)
第一步一般求主存地址位數:主存256MB可得,256M=2的28次方,所以主存地址位數為28位。
第二部一般就塊內地址位數:很可能用到行長來反推塊長,因為兩者相等。所以行長=塊長=64,所以塊內地址為6位。
第三部求標志位數(這個指的是主存地址的標志位,所以不用加1):28-行號位數(3位)-6(塊內地址)=19位。
第四部求出cache行標記位的組成:19位+1,一定要注意加上有效位。
第五步求總容量=(20+64x8)x8
容量很簡單1.塊長x行數=64Bx8,
注意一般為cache的地址就是cache的塊內地址。因為這才是他的有效數據位,還有問的是主存的標志位還是cache的標志位,還有就是塊號和行號以及第幾塊一般是從0開始(一般題目會說,但是也可能不會說)
有一種情況就是告訴你cache的容量為16B這下你可以直接得出cache的地址位數為4位,如果是總容量就不行
關於最常考的關於c語言與cache的映射結合起來的方式,就是循環和求缺失率:
比如for(in=0;i<100;i++)
a[i]=a[i]+k;
這種就是,這里相當於每執行一次賦值語句,就訪問兩次a[i],比如如果是int類型的數組,一個數4B,但是塊的長度為16B,就是說一個快中有4個a數組的數,這時候他會問你,如果求cache的訪問缺失率,主要是一點,不要去算總的訪問次數和缺失次數或者命中次數,一次走那個語句的命中率久可以代表所有的命中率或者缺失率,這里假設一開始cache為空,為直接映射,他訪問a[0]時候 ,未命中,於是到內存里將含有這個數的整個塊調入cache中,所以就把這個數a[0]以及后面三個數a[1] a[2] a[3]全部掉入了cache里,所以每訪問四個數,就只有第一次訪問是缺失的,后面的7次都是命中,四個數總共訪問8次a數組,所以命中率為1/8.