操作系统原理_读懂操作系统之缓存原理(cache)(三)
緩存原理
高速緩存被劃分為多個(gè)塊,其大小可能不同,緩存中的塊數(shù)通常為2的冪。如下為一個(gè)具有八個(gè)塊的高速緩存,每個(gè)塊包含一個(gè)字節(jié)。通過(guò)本節(jié)對(duì)緩存原理的學(xué)習(xí)我們能夠?qū)W習(xí)到四點(diǎn):【1】當(dāng)我們將數(shù)據(jù)塊從主存儲(chǔ)器復(fù)制到緩存,我們到底應(yīng)該放在哪里?【2】如何判斷一個(gè)字是否已經(jīng)在緩存中,或者它是否必須首先從主存儲(chǔ)器中獲取?【3】較小的緩存最終會(huì)填滿(mǎn), 需要至從主存加載新塊,我們必須替換緩存中現(xiàn)有的哪個(gè)塊?【4】存儲(chǔ)系統(tǒng)如何處理寫(xiě)操作?數(shù)據(jù)放在緩存哪里?
緩存最簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)是直接映射:其中每個(gè)存儲(chǔ)器地址僅僅對(duì)應(yīng)到緩存中的一個(gè)位置。例如如下,16個(gè)字節(jié)的主存和4個(gè)字節(jié)的緩存(每個(gè)塊一個(gè)字節(jié)),內(nèi)存地址為0、4、8、12分別映射到緩存中為0的塊,而地址1、5、9、13被映射到塊1
等等,我們是不是講解的太快了,上述地址怎么就劃分到比如塊0或塊1了呢?要找出緩存所在塊采取取模法:(塊地址)mod (緩存中的塊數(shù)),如果緩存包含2k塊,則內(nèi)存地址i處的數(shù)據(jù)將進(jìn)入緩存塊索引為i mod 2k。還是不懂?我們來(lái)舉個(gè)例子,如下緩存有4個(gè)塊,那么地址為14將映射到塊2即(14 mod 4 = 2)。為便于大家理解如上為10進(jìn)制表示內(nèi)存地址,將內(nèi)存地址映射到緩存塊中實(shí)際等效的方式是將內(nèi)存地址中的最低有效k位(二進(jìn)制)進(jìn)行映射。正如下面我們所看到的,內(nèi)存地址14(1110,二進(jìn)制)將最低有效位10作為塊中的索引
怎樣找到緩存中數(shù)據(jù)
到目前為止我們知道了將地址利用直接映射的結(jié)構(gòu)映射到緩存中,那么我們找到數(shù)據(jù)是否在緩存中呢?如果要讀取內(nèi)存地址i,則可以使用mod技巧來(lái)確定哪個(gè)緩存塊將包含i,如上所述,若其他地址也可能映射到相同的緩存塊,那么我們?nèi)绾螀^(qū)分它們呢?例如如下內(nèi)存地址2、6、10、14都在緩存塊2中
為了解決這個(gè)問(wèn)題,我們需要向高速緩存中添加標(biāo)記(tag),通過(guò)內(nèi)存地址的高位來(lái)提供標(biāo)記位,以使我們能夠區(qū)分映射到同一高速緩存塊的不同存儲(chǔ)位置。例如如下。內(nèi)存地址6即(0110,二進(jìn)制),將低位10作為索引(index),高位01作為標(biāo)記(tag)。我們通過(guò)將高速緩存塊標(biāo)記(tag)與塊索引(index)組合起來(lái),可以準(zhǔn)確地知道主存儲(chǔ)器的哪些地址存儲(chǔ)在高速緩存中。
當(dāng)程序加載到內(nèi)存中時(shí),緩存為空,不包含有效數(shù)據(jù),我們應(yīng)該通過(guò)為每個(gè)緩存塊添加一個(gè)有效位來(lái)解決這個(gè)問(wèn)題,系統(tǒng)初始化時(shí),所有有效位均設(shè)置為0,當(dāng)數(shù)據(jù)加載到特定的緩存塊中時(shí),相應(yīng)的有效位設(shè)置為1。當(dāng)CPU嘗試從內(nèi)存中讀取數(shù)據(jù)時(shí),該地址將被發(fā)送到緩存控制器,地址的最低k位將在緩存中索引一個(gè)塊,如果該塊有效且標(biāo)簽與m位地址的高(m-k)位匹配,則該數(shù)據(jù)將被發(fā)送到CPU,如下為一個(gè)32位內(nèi)存地址和210字節(jié)高速緩存的圖。
到這里我們會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,將每一個(gè)字節(jié)對(duì)應(yīng)一字節(jié)緩存塊并沒(méi)有很好的利用空間局部性,要是訪(fǎng)問(wèn)一個(gè)地址后將訪(fǎng)問(wèn)附近的地址,我們又該怎么辦?我們要做的是將緩存塊的大小要大于1個(gè)字節(jié)。如下,我們使用兩個(gè)字節(jié)的塊,因此我們可以用兩個(gè)來(lái)加載緩存一次讀取一個(gè)字節(jié),如果我們從內(nèi)存地址12讀取數(shù)據(jù),則地址中的數(shù)據(jù)12和13都將被復(fù)制到緩存塊2。現(xiàn)在,我們又該如何確定數(shù)據(jù)應(yīng)放在緩存中的位置?現(xiàn)在演變成塊地址,如果緩存塊大小為2n字節(jié),我們也可以在概念上將主內(nèi)存也劃分成2n字節(jié)塊,要確定字節(jié)地址i的塊地址,可以進(jìn)行整數(shù)除法(i / 2n),如下示例中有2個(gè)字節(jié)的緩存塊,因此我們可以將16個(gè)字節(jié)的主存儲(chǔ)器視為8塊主存儲(chǔ)器,例如,存儲(chǔ)器地址12和13都對(duì)應(yīng)于塊地址6,因?yàn)?2 / 2 = 6和13 / 2 = 6。?
現(xiàn)在我們知道了塊地址,就可以像上述一樣將其映射到緩存:找到塊地址除以緩存塊數(shù)后的余數(shù)。在如下示例中,內(nèi)存塊6屬于緩存塊2,因?yàn)? mod 4 =2,這對(duì)應(yīng)于將來(lái)自存儲(chǔ)器字節(jié)地址12和13的數(shù)據(jù)都放入高速緩存塊2中。當(dāng)我們?cè)L問(wèn)內(nèi)存中的一個(gè)字節(jié)數(shù)據(jù)時(shí),我們會(huì)將其整個(gè)塊復(fù)制到緩存中以達(dá)到充分利用空間局部性。在我們的示例中,如果程序從字節(jié)地址12讀取,我們會(huì)將所有存儲(chǔ)塊6(地址12和13)都加載到緩存塊2中(注意:字節(jié)地址13對(duì)應(yīng)于相同的存儲(chǔ)塊地址)因此,對(duì)地址13的讀取也會(huì)導(dǎo)致將存儲(chǔ)塊6(地址12和13)加載到高速緩存塊2中。為了簡(jiǎn)化起見(jiàn),存儲(chǔ)塊的字節(jié)i始終存儲(chǔ)在相應(yīng)高速緩存塊的字節(jié)i中。假設(shè)我們有一個(gè)包含2k塊的緩存,每個(gè)塊包含2n個(gè)字節(jié),我們可以通過(guò)查看其在主內(nèi)存中的地址來(lái)確定該緩存中一個(gè)字節(jié)的數(shù)據(jù)位置,地址的k位將選擇2k個(gè)高速緩存塊之一,最低的n位現(xiàn)在是一個(gè)塊偏移量,它決定了高速緩存塊中的2n個(gè)字節(jié)中的哪個(gè)將存儲(chǔ)數(shù)據(jù)。我們來(lái)舉個(gè)例子加深理解,如下示例使用22塊高速緩存,每個(gè)塊占21字節(jié),因此,存儲(chǔ)器地址13(1101)將存儲(chǔ)在高速緩存塊2的字節(jié)1中。到這里為止,我們才算分析清楚了緩存中有效位、標(biāo)記位、索引、偏移它們的由來(lái)以及實(shí)際作用。同時(shí)對(duì)于緩存采用的直接映射(direct mapped)結(jié)構(gòu):索引和偏移量可以使用位運(yùn)算符或簡(jiǎn)單的算術(shù)運(yùn)算,因?yàn)槊總€(gè)內(nèi)存地址都恰好屬于一個(gè)塊。實(shí)際上我們可以將一個(gè)塊放置到緩存中的任何一個(gè)位置,這種機(jī)制稱(chēng)為全相聯(lián)(fully associative)。全相聯(lián)的高速緩存允許將數(shù)據(jù)存儲(chǔ)在任何高速緩存塊中,而不是將每個(gè)內(nèi)存地址強(qiáng)制映射到一個(gè)特定的塊中,從內(nèi)存中獲取數(shù)據(jù)時(shí),可以將其放置在高速緩存的任何未使用塊中。這樣,我們將永遠(yuǎn)不會(huì)在映射到單個(gè)緩存塊的兩個(gè)或多個(gè)內(nèi)存地址之間發(fā)生沖突,在上述示例中,我們可能將內(nèi)存地址2放在緩存塊2中,并將地址6放在塊3中。然后對(duì)2和6的后續(xù)重復(fù)訪(fǎng)問(wèn)將全部命中而不是未命中,如果所有塊都已被使用,則使用LRU算法進(jìn)行替換。但是在全相聯(lián)緩存中要查找一個(gè)指定的塊,由于該塊存放在緩存中的任何位置,因此需要檢索緩存中的所有項(xiàng),為了是檢索更加有效,它是由一個(gè)與緩存中每個(gè)項(xiàng)都相關(guān)的比較器并行完成的,這些比較器加大了硬件開(kāi)銷(xiāo),因而,全相聯(lián)只適合塊數(shù)較少的緩存。介于直接映射和全相聯(lián)之間的設(shè)計(jì)是組相聯(lián)(set associative)。在組相聯(lián)緩存中,每個(gè)塊可被放置的位置數(shù)固定,每個(gè)塊有n個(gè)位置可放的緩存被稱(chēng)作n路組相聯(lián),一個(gè)n路組相聯(lián)緩存由很多組組成,每個(gè)組有n個(gè)塊。通過(guò)上述對(duì)直接映射的講解,最終我們得出指定內(nèi)存地址所在存儲(chǔ)的塊號(hào)為:(塊號(hào)) mod (緩存中的塊數(shù)),而組相聯(lián)對(duì)于存儲(chǔ)塊號(hào)是:(塊號(hào)) mod (緩存中的組數(shù))。如下為8塊高速緩存的組織組相聯(lián)實(shí)際上就是將塊進(jìn)行分組,比如如上第一個(gè)圖則是直接映射(我們大可將其看做是每一個(gè)塊就是一個(gè)組,所以是1路8組相聯(lián)),而第二張圖則是每2個(gè)塊作為一組,所以是2路4組相聯(lián),同理第三張圖是4路2組相聯(lián)。換句話(huà)說(shuō),若每組有2n塊,那么就是2n路相聯(lián)。通過(guò)對(duì)組相聯(lián)的講解,我們?cè)贁?nèi)存地址在組相聯(lián)緩存中的位置。如果我們有2s組并且每塊有2n字節(jié),那么內(nèi)存地址映射在緩存中的位置則是如下這般現(xiàn)在我們運(yùn)算則是計(jì)算緩存中的組索引而非再是塊,上述Block offset(在組中塊偏移)= 內(nèi)存地址 mod 2n,塊地址 = 內(nèi)存地址 / 2n,set index(組索引) = 塊地址 mod 2s。我們還是通過(guò)圖解來(lái)進(jìn)行敘述,假設(shè)有一個(gè)8塊的高速緩存,然后每個(gè)塊是16個(gè)字節(jié),那么內(nèi)存地址為6195的數(shù)據(jù)存儲(chǔ)在緩存哪里呢?首先我們將6195轉(zhuǎn)換為二進(jìn)制? = 110000?011?0011,因每個(gè)塊是16字節(jié)即24,所以塊偏移量為4位即0011若采用1路8組相聯(lián)(直接映射)那么其組索引就是(6195 mod 8) = 3,取6195轉(zhuǎn)換而二進(jìn)制去除偏移量4位,所以為011,同理(根據(jù)上述給定計(jì)算公式)對(duì)于2路4組相聯(lián)其組索引為(11),4路2組相聯(lián)其組索引為(1),如下:到這里我們知道將數(shù)據(jù)進(jìn)行緩存我們可以采取直接映射、組相聯(lián)、全相聯(lián)的機(jī)制,通過(guò)增加相聯(lián)度通常可以降低緩存缺失率,但是增加相聯(lián)度也就增加了每組中的塊數(shù),也就是并行查找時(shí)同時(shí)比較的次數(shù),相聯(lián)度每增加兩倍就會(huì)使得每組中的塊數(shù)加倍而使得組數(shù)減半,所以增大了訪(fǎng)問(wèn)時(shí)間的開(kāi)銷(xiāo)。如何找到一個(gè)塊,當(dāng)然也就依賴(lài)于所使用的將塊放置的機(jī)制(直接映射、組相聯(lián)、全相聯(lián)),相較于全相聯(lián)而言,它使用復(fù)雜的替換策略而降低缺失率且很容易被索引,而不需要額外的硬件,也不需要進(jìn)行查找。因此虛擬存儲(chǔ)系統(tǒng)通常使用全相聯(lián)映射,而組相聯(lián)映射通常應(yīng)用于緩存和TLB。緩存缺失和寫(xiě)操作
緩存缺失被分為以下三類(lèi)(3C模型,three Cs model),因其三類(lèi)名稱(chēng)以字母c開(kāi)頭而得名強(qiáng)制缺失(compulsory miss):對(duì)從沒(méi)有在緩存中出現(xiàn)的塊第一次進(jìn)行訪(fǎng)問(wèn)引起的缺失,也稱(chēng)為冷啟動(dòng)缺失(cold-start miss)
容量缺失:(capacity miss):由于緩存容納不了一個(gè)程序執(zhí)行所需要的所有塊而引起的緩存缺失,當(dāng)某些塊被替換出去,隨后再被調(diào)入時(shí),將發(fā)生容量缺失
沖突缺失(conflict miss):在組相聯(lián)或者直接映射的緩存中,多個(gè)競(jìng)爭(zhēng)同一個(gè)組時(shí)而引起的緩存缺失。沖突缺失在直接映射或組相聯(lián)緩存中存在,而在同樣大小的全相聯(lián)緩存中不存在,這種緩存缺失也稱(chēng)為碰撞缺失(collision miss)
改變緩存設(shè)計(jì)的某一方面就能直接影響這些缺失的原因。沖突缺失是因?yàn)闋?zhēng)用同一個(gè)緩存塊而引起的,因此提高相聯(lián)度可以減少?zèng)_突缺失,然后提高相聯(lián)度會(huì)延長(zhǎng)訪(fǎng)問(wèn)時(shí)間,導(dǎo)致整個(gè)性能的降低,容量缺失可以簡(jiǎn)單地通過(guò)增大緩存容量來(lái)減少,當(dāng)然緩存容量增大的同時(shí)必然導(dǎo)致訪(fǎng)問(wèn)時(shí)間的增加,也將導(dǎo)致整體性能的降低。
在相聯(lián)的緩存中發(fā)生缺失時(shí),我們必須決定替換哪一塊,如若是全相聯(lián),那么所有的塊都是被替換的候選者,如若是組相聯(lián),我們必須在某一組的塊中進(jìn)行選擇,當(dāng)然,直接映射的緩存替換很簡(jiǎn)單,因?yàn)橹挥幸粋€(gè)可以替換的候選者。因此在全相聯(lián)或組相聯(lián)緩存中 ,有兩種主要的替換策略
隨機(jī)法:隨機(jī)選擇候選塊,可能使用一些硬件來(lái)協(xié)助實(shí)現(xiàn),例如TLB缺失、MIPS支持隨機(jī)替換
LRU(最近最少使用算法):被替換的塊是最久沒(méi)有被使用過(guò)的塊 (在大多虛擬存儲(chǔ)器中,對(duì)于LRU都是通過(guò)提供引用位來(lái)近似實(shí)現(xiàn)(比如TLB))
指令緩存缺失(數(shù)據(jù)缺失也類(lèi)似如此)處理步驟如下:
【1】將程序計(jì)數(shù)器(PC)的原始值送到寄存器
【2】通知主存執(zhí)行一次讀操作,并等待主存訪(fǎng)問(wèn)完成
【3】寫(xiě)緩存項(xiàng),將從主存取回的數(shù)據(jù)寫(xiě)入緩存中存放數(shù)據(jù)的部分,并將高位(從ALU中得到)寫(xiě)入標(biāo)記域,設(shè)置有效位
【4】重啟指令執(zhí)行第一步,重新取指,這次該指令發(fā)生在緩存中
數(shù)據(jù)訪(fǎng)問(wèn)是對(duì)緩存的控制基本相同:發(fā)生缺失時(shí),處理器發(fā)生阻塞,直到從存儲(chǔ)器中取回?cái)?shù)據(jù)后才響應(yīng)。在執(zhí)行寫(xiě)操作時(shí),如果有一個(gè)存儲(chǔ)指令,我們只將數(shù)據(jù)寫(xiě)入緩存而不改變主存中的內(nèi)容,那么在寫(xiě)入緩存后將導(dǎo)致緩存和主存被認(rèn)為不一致,保持主存和緩存一致性最簡(jiǎn)單的方法是將數(shù)據(jù)同時(shí)寫(xiě)入主存和緩存中,這種方法稱(chēng)為【寫(xiě)直達(dá)】法。但是這種方法無(wú)法提供良好的性能,因?yàn)槊看螌?xiě)操作都要把數(shù)據(jù)寫(xiě)入主存中,這些寫(xiě)操作將花費(fèi)大量的時(shí)間,可能至少花費(fèi)100個(gè)處理時(shí)鐘周期,并且大大降低了機(jī)器速度,解決這個(gè)問(wèn)題的方案之一是采用【寫(xiě)緩沖:一個(gè)保存等待寫(xiě)入主存數(shù)據(jù)的緩沖隊(duì)列】,當(dāng)一個(gè)數(shù)據(jù)在等待寫(xiě)入緩存時(shí),先將其寫(xiě)入緩沖中,當(dāng)數(shù)據(jù)寫(xiě)入緩存和緩沖后,處理器可以繼續(xù)執(zhí)行,當(dāng)寫(xiě)主存操作完成后,寫(xiě)緩沖里的數(shù)據(jù)項(xiàng)也得到有效釋放。如果寫(xiě)緩沖已經(jīng)滿(mǎn)了,那么當(dāng)處理器執(zhí)行到一個(gè)寫(xiě)操作時(shí)就必須停下來(lái)直到寫(xiě)緩沖中有一個(gè)空位置,當(dāng)然,如果存儲(chǔ)器完成寫(xiě)操作的速度比處理器產(chǎn)生寫(xiě)操作的速度慢,那么再多的緩沖器也無(wú)用,因?yàn)楫a(chǎn)生寫(xiě)操作比存儲(chǔ)系統(tǒng)接收它們更快。除了寫(xiě)直達(dá)方法外,另外一種可選擇的方法是【寫(xiě)回】,在寫(xiě)回機(jī)制中,當(dāng)發(fā)生寫(xiě)操作時(shí),新值僅僅被寫(xiě)入到緩存塊中,只有當(dāng)修改過(guò)的塊被替換時(shí)才需要寫(xiě)到磁盤(pán)上,寫(xiě)回機(jī)制可提高系統(tǒng)性能,尤其是當(dāng)處理器寫(xiě)操作的速度和主存處理寫(xiě)操作速度一樣快甚至更快時(shí),但是,寫(xiě)回機(jī)制的實(shí)現(xiàn)比寫(xiě)直達(dá)要復(fù)雜得多。大部分寫(xiě)回機(jī)制的緩沖也是使用寫(xiě)緩沖,當(dāng)在發(fā)生缺失替換一個(gè)被修改的塊時(shí),寫(xiě)緩沖可以起到降低缺失代價(jià)的作用。在這種情況下,被修改的數(shù)據(jù)塊移入與緩存相聯(lián)的寫(xiě)回緩沖器,同時(shí)從主存中讀出所需要的數(shù)據(jù)塊。隨后,寫(xiě)回緩沖器再將數(shù)據(jù)寫(xiě)入主存,如果下一次缺失沒(méi)有立刻發(fā)生,當(dāng)臟數(shù)據(jù)塊必須被替換時(shí),這種方法可以減少一半的缺失代價(jià)。【1】一個(gè)緩存塊可以放在何處:一個(gè)位置(直接映射),一些位置(組相聯(lián)),任何位置(全相聯(lián))。【2】如何找到一個(gè)塊:索引(直接映射的緩存中),有限的檢索(組相聯(lián)的緩存中),全部檢索(全相聯(lián)的緩存中)、專(zhuān)用查找頁(yè)表。【3】緩存缺失時(shí)替換哪一塊:隨機(jī)選取、LRU【4】寫(xiě)操作如何處理:寫(xiě)直達(dá)或?qū)懟夭呗员疚奈覀兎浅T敿?xì)的講解了緩存的基本原理,當(dāng)然對(duì)于如何處理緩存一致性并未涉及(大多采用監(jiān)聽(tīng)協(xié)議)。總結(jié)
以上是生活随笔為你收集整理的操作系统原理_读懂操作系统之缓存原理(cache)(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Silverlight 全屏显示
- 下一篇: 《JS高级程序设计》PART3.对象基础