超标量处理器设计 姚永斌 第2章 Cache 摘录
2.1 Cache的一般設(shè)計(jì)
在超標(biāo)量處理器中,有兩個(gè)部件直接影響著性能,他們是分支預(yù)測(cè)和Cache??v觀每次Intel處理器升級(jí),都會(huì)使分支預(yù)測(cè)的精度更高,Cache的命中率更高。
Cache之所以存在,是因?yàn)樵谔幚砥髟谟?jì)算機(jī)的世界中,存在如下兩個(gè)現(xiàn)象:
(1) 時(shí)間相關(guān)性(temporal locality):如果一個(gè)數(shù)據(jù)現(xiàn)在被訪問了,那么在以后很有可能還會(huì)被訪問。
(2) 空間相關(guān)性(spatial locality):如果一個(gè)數(shù)據(jù)現(xiàn)在被訪問了,那么它周圍的數(shù)據(jù)在以后有可能也會(huì)被訪問。
Cache的出現(xiàn)可以說是一種無奈的妥協(xié),因?yàn)榇鎯?chǔ)器技術(shù)的發(fā)展比處理器技術(shù)的發(fā)展要慢。
尤其在超標(biāo)量處理器中,考錄到每周期需要從Cache中同時(shí)讀取多條指令,同時(shí)每周期也可能有多條load/store指令會(huì)訪問Cache,因此需要實(shí)現(xiàn)多端口的Cache,這給芯片面積的速度帶來了不小的挑戰(zhàn)。
現(xiàn)代的超標(biāo)量處理器都是哈佛結(jié)構(gòu),為了增加流水線的執(zhí)行效率,L1 Cache一般都包括兩個(gè)物理的存在,指令Cache(I-Cache)和數(shù)據(jù)Cache(D-Cache),本質(zhì)來說,他們的原理都是一樣的,但是D-Cache不僅需要讀取,還需要考慮寫入的問題,而I-Cache只會(huì)被讀取,并不會(huì)被寫入,因此D-Cache更復(fù)雜一點(diǎn)。
L1 Cache更靠近處理器,它是流水線的一部分,需要和處理器保持近似的速度,這注定了它的容量不能夠很大。L1 Cache一般是SRAM來實(shí)現(xiàn)的,容量大的SRAM需要更長的時(shí)間來找到一個(gè)指定地址的內(nèi)容,但是一旦不能和處理器保持速度上近似,L1 Cache就失去的了意義。對(duì)于L1 Cache而言,快就是硬道理。
L2 Cache則是為了求“全”。一般情況下,L2 Cache都是指令和數(shù)據(jù)共享,它和處理器的速度不必保持同樣的步調(diào),可以容忍更慢一些,它的主要功能是為了盡量保存更多的內(nèi)容。目前L2 Cache都是MB為單位的。在多核之間共享的L2 Cache就更復(fù)雜一點(diǎn),現(xiàn)在處理器一般都是共享L3 Cache。L1 Cache依舊是每個(gè)核“私有”的。
在超標(biāo)量處理器中,對(duì)于Cache有著特殊的要求。對(duì)于I-Cache來說,需要能夠每周期讀取多條指令,不過,它的延遲時(shí)間即使很大,在一般情況下也不會(huì)造成處理器性能的下降,仍舊可以實(shí)現(xiàn)每周期都可以讀取指令的效果。除非遇見預(yù)測(cè)跳轉(zhuǎn)的分支指令時(shí),這些延遲才會(huì)對(duì)性能造成影響。
對(duì)于D-Cache來說,它需要支持在每周期內(nèi)多條load/store指令的訪問,也就是需要多端口的設(shè)計(jì)。雖然在超標(biāo)量處理器中,多端口的部件很多,例如發(fā)射隊(duì)列Issue Queue,Store Buffer,寄存器堆Register File和重排序緩存ROB等等,但是這些部件的容量本身就很小,所以即使采用多端口設(shè)計(jì),也不會(huì)占用很大的空間。而D-Cache容量本身就很大,如果采用多端口設(shè)計(jì),則占用的硅片面積就很難接受,也會(huì)導(dǎo)致更大的延遲,這個(gè)延遲會(huì)直接暴露給流水線中后續(xù)的指令。一般load處于相關(guān)性的頂端,所以這回對(duì)處理器的性能造成負(fù)面的影響。而對(duì)于L2 Cache而言,它的被訪問頻率不是很高(L1?Cache的命中率是比較高的),所以它不需要多端口的設(shè)計(jì),它的延遲也不是特別的重要。因?yàn)橹挥邪l(fā)生L1 Cache?miss的時(shí)候才會(huì)訪問它。但是L2 Cache需要比較高的命中率,因?yàn)樵谒l(fā)生缺失時(shí)候會(huì)去訪問物理內(nèi)存DRAM,這個(gè)訪問時(shí)間會(huì)很長,因此盡量提高L2 Cache的命中率。
Cache主要由兩部分組成,Tag部分和Data部分。
Data部分就是用來保存一片連續(xù)地址的數(shù)據(jù),而Tag部分則是存儲(chǔ)著這片連續(xù)數(shù)據(jù)的公共地址。
一個(gè)Tag和它對(duì)應(yīng)的所有數(shù)據(jù)組成的一行稱為一個(gè)Cache?line。
而Cache?line中的數(shù)據(jù)部分稱為數(shù)據(jù)塊(Cache data block)。
如果一個(gè)數(shù)據(jù)可以存儲(chǔ)在Cache中的多個(gè)地方,這些被同一個(gè)地址找到的多個(gè)Cache?line稱為Cache Set。
?實(shí)際中,Cache有三種主要的實(shí)現(xiàn)方法,直接映射direct-mapped,組相連set-associative和fullt-associative Cache。
對(duì)于一個(gè)物理內(nèi)存而言,如果在Cache中只有一個(gè)地方可以容納它,它就是直接映射的Cache;如果有多個(gè)地方都可以放置這個(gè)數(shù)據(jù),它就是組相連的Cahce;如果Cache中任何地方都可以放置這個(gè)數(shù)據(jù),那么它就是全相連的Cache。
直接相連和全相連實(shí)際是組相連Cache中的特殊情況。現(xiàn)代Cache一般屬于上述三種方式中的某一個(gè),例如TLB和Victim Cache多采用全相連結(jié)構(gòu),而普通的I-Cache和D-Cache則采用組相連結(jié)構(gòu)等。
Cache只能保存最近被處理器使用過的內(nèi)容,由于它的容量有限,很多情況下,要找的指令或者數(shù)據(jù)并不在Cache中,這稱為Cache的缺失(Cache?miss)。在計(jì)算領(lǐng)域,影響Cache缺失的情況可以概括為:
(1)Compulsory,由于Cache只是緩存以前訪問過的內(nèi)容,第一次被訪問的指令或數(shù)據(jù)肯定就不會(huì)在Cache中,當(dāng)然可以采用預(yù)取prefetch的方法來盡量降低這種缺失發(fā)生的頻率。
(2)Capcacity,Cache容量越大,就可以緩存更多的內(nèi)容,因此容量是影響Cache缺失發(fā)生頻率的一個(gè)關(guān)鍵因素。例如程序頻繁使用的5個(gè)數(shù)據(jù)屬于不同的Cache?set,而Cache的容量只有4個(gè)Cache Set時(shí)。
(3)Conflict,為了解決多個(gè)數(shù)據(jù)映射到Cache中同一個(gè)位置的情況,一般使用組相連結(jié)構(gòu)的Cache,當(dāng)然考慮到實(shí)際硅片面積的限制,相連度不可能很高。例如,在一個(gè)有著兩路結(jié)構(gòu)(2-way)的Cahce中,如果程序頻繁使用的三個(gè)數(shù)據(jù)屬于同一個(gè)Cache?set,那么就肯定會(huì)發(fā)生缺失,此時(shí)可以使用Victim Cache來緩解這個(gè)問題。
盡管在超標(biāo)量處理器中,可以采用預(yù)期prefetch和victim?cache這兩種方法,但是仍然無法從根本上消除Cache缺失,只能盡量減少它發(fā)生的頻率而已。
2.1.1 Cache的組成方式
1.?直接映射
直接映射(direct-mapped)結(jié)構(gòu)的Cache是最容易實(shí)現(xiàn)的一種方式,處理器訪問存儲(chǔ)器的地址會(huì)被分為三部分,Tag、Index和Block Offset。使用Index來從Cahce中找到一個(gè)對(duì)應(yīng)的Cache?lline,但是所有的Index相同的地址都會(huì)尋址到這個(gè)Cache?line,因此Cache?line中還有Tag部分,用來和地址中的Tag進(jìn)行比較,只有它們是相等的,才表明這個(gè)Cache?line就是想要的那個(gè)。在一個(gè)Cache?line中有很多個(gè)數(shù)據(jù),通過存儲(chǔ)器地址中的Block Offset部分可以找到真正想要的數(shù)據(jù),它就可以定位到每個(gè)字節(jié)。在Cache?line中還有一個(gè)有效位valid,用來標(biāo)記這個(gè)Cache?line是否保存著有效的數(shù)據(jù),只有在之前被訪問過的存儲(chǔ)器地址,它的數(shù)據(jù)才會(huì)存在于對(duì)應(yīng)的Cache?line中,相應(yīng)的有效位也會(huì)被置為1了。
?對(duì)于所有Index相同的存儲(chǔ)器地址,都會(huì)尋址到同一個(gè)Cache?line中,這就會(huì)發(fā)生沖突,這也是直接映射結(jié)構(gòu)Cache的一大缺點(diǎn)。如果兩個(gè)Index部分相同的存儲(chǔ)器地址交叉訪問Cache,就會(huì)一直導(dǎo)致Cache缺失,嚴(yán)重地降低了處理器的執(zhí)行效率。、
下面通過一個(gè)實(shí)際的例子來說明存儲(chǔ)器地址的劃分對(duì)于Cache的影響,如圖所示一個(gè)32位存儲(chǔ)器地址,Block Offset有5位,所以Data?block的大小是2^5 = 32字節(jié),Index是6位,表示Cache中共有2^6=64個(gè)Cache?line(在直接映射中,Cache?line和Cache Set是同義的),存儲(chǔ)器地址中剩余的32-5-6=21位作為Tag值,因此這個(gè)Cache中可以存儲(chǔ)的數(shù)據(jù)大小為64*32=2048字節(jié),即2KB;而Tag部分的大小是64*21=1344位,約為1.3Kb;有效位占用的大小為64*1=64位,一般情況下,都是以數(shù)據(jù)部分的大小來表示Cache的大小,因此這個(gè)Cache被稱為一個(gè)2KB直接映射結(jié)構(gòu)的Cache,而實(shí)際它還額外占用多余1.3KB的存儲(chǔ)空間。
?直接映射結(jié)構(gòu)的Cache在實(shí)現(xiàn)上是最簡(jiǎn)單的,它都不需要替換算法,但是它的執(zhí)行效率也是最低的,現(xiàn)代的處理器很少使用這種方式了。
2.組相連
組相連(set-associative)的方式是為了解決直接映射結(jié)構(gòu)Cache的不足而提出的。存儲(chǔ)器中的一個(gè)數(shù)據(jù)不單單只能放在一個(gè)Cache?line中,而是可以放在多個(gè)Cache?line中,對(duì)于一個(gè)組相連結(jié)構(gòu)的Cache來說,如果一個(gè)數(shù)據(jù)可以放在n個(gè)位置,則稱這個(gè)Cache是n路組相連(n-way)。
?這種結(jié)構(gòu)依舊使用存儲(chǔ)器地址的Index部分對(duì)Cache進(jìn)行尋址,此時(shí)可以得到兩個(gè)Cache?line,這兩個(gè)Cache?line稱為一個(gè)Cache?set,究竟哪個(gè)Cache?line才是最終需要的,是根據(jù)Tag比較的結(jié)果來確定的,當(dāng)然,如果兩個(gè)Cache?line的Tag比較結(jié)果都不相等,那么發(fā)生了Cache缺失。
因?yàn)樾枰獜亩鄠€(gè)Cache?line中選擇一個(gè)匹配的結(jié)果,這種Cache的實(shí)現(xiàn)方式較之直接映射結(jié)構(gòu)的Cache,延遲會(huì)更大,有時(shí)候甚至需要將其進(jìn)行流水線,以便減少對(duì)處理器周期時(shí)間cycle?time的影響,這樣會(huì)導(dǎo)致load指令的延遲增大,一定程度上影響了處理器的執(zhí)行效率,但是這種方式的有點(diǎn)也很突出,它可以顯著減少Cache缺失發(fā)生的頻率,因此在現(xiàn)代處理器中得到了廣泛的應(yīng)用。
上面提到的Tag和Data部分可以分開放置,稱為Tag SRAM和Data SRAM,可以同時(shí)訪問這兩個(gè)部分,稱為并行訪問;相反如果縣訪問Tag SRAM部分,根據(jù)Tag比較的結(jié)果再去訪問Data SRAM部分,稱為串行訪問。
對(duì)于并行訪問結(jié)構(gòu),當(dāng)Tag部分的某個(gè)地址唄讀取的同時(shí),這個(gè)地址在Data部分對(duì)應(yīng)的所有數(shù)據(jù)也會(huì)被讀取出來,并送到一個(gè)多路選擇器上,這個(gè)多路選擇器受到Tag比較結(jié)果的控制,選出相應(yīng)的餓Data?block,然后根據(jù)存儲(chǔ)器地址中的Block?offset的值,選擇出合適的字節(jié),一般將選擇字節(jié)的這個(gè)過程稱為數(shù)據(jù)對(duì)齊data?alignment。
并行訪問Cache若在一個(gè)周期內(nèi)完成,則在現(xiàn)實(shí)當(dāng)中會(huì)占據(jù)很大延遲,要想使處理器運(yùn)行在較高的頻率下,Cache的訪問就需要使用流水線,前面說過,對(duì)于指令Cache來說,流水線的結(jié)構(gòu)不會(huì)有太大的影響,仍舊可以實(shí)現(xiàn)每周期讀取指令的效果;而對(duì)于數(shù)據(jù)Cache來說,使用流水線則會(huì)增大load指令的延遲,從而對(duì)處理器的性能造成負(fù)面影響。
流水線的地址計(jì)算Address Calculation階段可以計(jì)算得出存儲(chǔ)器的地址,接下來的Disambiguation階段對(duì)load/store指令之間存在的相關(guān)性進(jìn)行檢查,然后在下個(gè)流水線階段Cache Access就可以直接并行地訪問Tag SRAM和Data SRAM,并使用Tag比較的結(jié)果對(duì)輸出的數(shù)據(jù)進(jìn)行選擇,然后在下一個(gè)流水線階段Result Derive,使用存儲(chǔ)器地址中的block?offset值,從數(shù)據(jù)部分給出的data?block中選出最終需要的數(shù)據(jù)。將整個(gè)Cache的訪問放到幾個(gè)周期內(nèi)完成,可以降低處理器的周期時(shí)間。
?而對(duì)于串行訪問方法來說,首先需要對(duì)Tag SRAM進(jìn)行訪問,根據(jù)Tag比較的結(jié)果,就可以知道數(shù)據(jù)部分中,那一路是需要被訪問的,此時(shí)可以直接訪問這一路的數(shù)據(jù),這樣就不需要上圖中的多路選擇器了而且,只需啊喲訪問數(shù)據(jù)部分指定的那個(gè)SRAM,其他的SRAM由于都不需要被訪問,可以將它們的使能信號(hào)置為無效,這樣可以節(jié)省很多功耗。
完全串行Tag SRAM和Data SRAM這兩部分的訪問,它的延遲會(huì)更大,仍舊需要使用流水線的方式來降低對(duì)處理器的周期時(shí)間的影響,用流水線降低了訪問Tag SRAM和Data RAM的延遲,因?yàn)榇藭r(shí)已經(jīng)不再需要多路選擇器,這對(duì)降低處理器的周期時(shí)間是有好處的,但是這樣設(shè)計(jì)的一個(gè)明顯的缺點(diǎn)就是Cache的訪問增加了一個(gè)周期,這也就增大了load指令的延遲,因?yàn)閘oad指令處于相關(guān)性的頂端,會(huì)對(duì)處理器的執(zhí)行效率造成一定的負(fù)面影響。
并行訪問的方式會(huì)有較低的時(shí)鐘頻率和較大的功耗,但是訪問Cache的時(shí)間周期縮短了一個(gè)周期,但是考慮到在亂序執(zhí)行的超標(biāo)量處理器來說,可以將訪問Cache的這段時(shí)間通過填充其他的指令而掩蓋起來,所以對(duì)于超標(biāo)量處理器來說,當(dāng)Cache的訪問處理器的關(guān)鍵路徑上時(shí),可以采用串行訪問來提高處理器的時(shí)鐘頻率,同時(shí)并不會(huì)由于訪問Cache的時(shí)間增加了一個(gè)周期而引起性能的明顯降低;相反,對(duì)于普通的順序執(zhí)行的處理器來說,由于無法對(duì)指令進(jìn)行調(diào)度,訪問Cache如果增加了一個(gè)周期,就很有可能會(huì)引起處理器性能的降低,因此在這種處理器中使用并行訪問的方式就是一種比較合適的選擇。
3.全相連
在全相連full-associative的方式中,對(duì)于一個(gè)存儲(chǔ)器地址來說,它的地址可以放在任意一個(gè)Cache?line中。存儲(chǔ)器地址不在有Index部分,而是直接在整個(gè)Cache中進(jìn)行Tag比較,找到比較結(jié)果相等的那個(gè)Cache?line,相當(dāng)于直接使用存儲(chǔ)器的內(nèi)容來尋址,從存儲(chǔ)器中找到匹配的項(xiàng),這其實(shí)就是內(nèi)容尋址的存儲(chǔ)器Content Address Memory,CAM。實(shí)際當(dāng)中的處理器在使用全相連結(jié)構(gòu)的Cache時(shí),都是使用CAM來存儲(chǔ)Tag值,使用普通的SRAM來存儲(chǔ)數(shù)據(jù)。全相連結(jié)構(gòu)Cache有著最大的靈活度,它的延遲也是最大的,因此一般這種結(jié)構(gòu)的Cache不會(huì)有很大的容量,例如TLB就會(huì)使用這種全相連的方式來實(shí)現(xiàn)。
2.1.2 Cache的寫入
在一般的RISC處理器中,L1 Cache中的I-Cache都是不會(huì)被直接寫入內(nèi)容的,即使有自修改的情況出現(xiàn),也并不是直接寫入I-Cache,而是借助與D-Cache來實(shí)現(xiàn),將要改寫的指令作為數(shù)據(jù)寫到D-Cache中,然后將D-Cache中的內(nèi)容寫入到下級(jí)存儲(chǔ)器,例如L2 Cache。
對(duì)于D-Cache來說,它的寫操作和讀操作有所不同,當(dāng)執(zhí)行一跳store指令時(shí),如果只是向D-Cache中寫入數(shù)據(jù),而并不改變它的下級(jí)存儲(chǔ)器中的數(shù)據(jù),這樣就會(huì)導(dǎo)致D-Cache和下級(jí)存儲(chǔ)器中,對(duì)于這一個(gè)地址有著不同的數(shù)據(jù),這稱為不一致non-consistent。
要想保持一致性,最簡(jiǎn)單的方式就是當(dāng)數(shù)據(jù)在寫到D-Cache時(shí),也寫到它的下級(jí)存儲(chǔ)器中,這種方式稱為write-through寫通。缺點(diǎn)是處理器執(zhí)行效率不高。
如果在執(zhí)行store指令時(shí),數(shù)據(jù)被寫到D-Cache后,只是將被寫入的Cache?line做一個(gè)記號(hào),并不將這個(gè)數(shù)據(jù)寫入到更下級(jí)的存儲(chǔ)器中,只有當(dāng)Cache中這個(gè)被標(biāo)記的line要被替換時(shí),才將它寫到下級(jí)存儲(chǔ)器中,這種方式被稱為Write?back寫回,被標(biāo)記的記號(hào)在計(jì)算機(jī)中術(shù)語為dirty狀態(tài)。優(yōu)點(diǎn)可是減少寫慢速存儲(chǔ)器的頻率,缺點(diǎn)就是造成D-Cache和下級(jí)存儲(chǔ)器中有很多地址中的數(shù)據(jù)是不一致的,給存儲(chǔ)器的一致性管理帶來負(fù)擔(dān),以及設(shè)計(jì)復(fù)雜度高一點(diǎn)。
以上是假設(shè)寫D-Cache時(shí),要寫入的地址總是在D-Cache中,而實(shí)際當(dāng)中,有可能發(fā)現(xiàn)這個(gè)地址并不在D-Cache中,這就發(fā)生了寫缺失write?miss,此時(shí)最簡(jiǎn)單的處理方式就是將數(shù)據(jù)直接寫到下級(jí)存儲(chǔ)器中,而并不是寫到D-Cache中,這種方式稱為non-write?allocate。與之對(duì)應(yīng)為write?allocate,如果寫Cache時(shí)發(fā)生了缺失,會(huì)首先將下級(jí)存儲(chǔ)器中將這個(gè)發(fā)生缺失的地址對(duì)應(yīng)的數(shù)據(jù)塊data?block讀取出來,將要寫入到D-Cache中的數(shù)據(jù)合并到這個(gè)數(shù)據(jù)塊,然后將這個(gè)被修改過的數(shù)據(jù)塊寫到D-Cache。
此處的一個(gè)疑問,寫D-Cache而發(fā)生缺失時(shí),為什么不直接將D-Cache中找到一個(gè)line,將要寫入的信息直接寫到這個(gè)line中,同時(shí)也將它寫到下級(jí)存儲(chǔ)器中呢?為什么還要先從下級(jí)存儲(chǔ)器中讀取相對(duì)應(yīng)的數(shù)據(jù)塊并寫到D-Cache中?
這是因?yàn)樵谔幚砥髦?#xff0c;對(duì)于寫D-Cache來說,最多也就是寫入一個(gè)字,而如果按照上面方式,直接從D-Cache中找到一個(gè)line來存儲(chǔ)這個(gè)需要寫入的數(shù)據(jù),并將這個(gè)line標(biāo)記為dirty,那么就會(huì)導(dǎo)致這個(gè)line中,數(shù)據(jù)塊的其他部分和下級(jí)存儲(chǔ)器中對(duì)應(yīng)的地址的數(shù)據(jù)不一致,而且此時(shí)D-Cache中這些數(shù)據(jù)都是無效的,如果這個(gè)Cache?line由于被替換而寫回到下級(jí)存儲(chǔ)器時(shí),就會(huì)使下級(jí)存儲(chǔ)器中的正確數(shù)據(jù)被篡改。
對(duì)于Write?allocate方法來說,就需要在發(fā)生寫缺失時(shí),首先將缺失的地址對(duì)應(yīng)的數(shù)據(jù)塊從下級(jí)存儲(chǔ)器中讀取出來,這個(gè)過程是必不可少的。
對(duì)于D-Cache來說,一般情況下,write?through是和non-write?allocate一起使用的,它們都是直接將數(shù)據(jù)更新到下級(jí)存儲(chǔ)器中。
1.write?through和non-write?allocate配合工作流程圖:
?write-back是和write?allocate配合使用的,不管是讀取還是寫入時(shí)發(fā)生缺失,都需要從D-Cache中找到一個(gè)line來存放新的數(shù)據(jù),這個(gè)被替換掉的line如果是dirty,那么首先需要將其中的數(shù)據(jù)寫回到下級(jí)存儲(chǔ)器中,然后才能使用這個(gè)line存放缺失地址對(duì)應(yīng)的數(shù)據(jù)塊。也就是說,當(dāng)D-Cache中被替換的line是dirty,需要對(duì)下級(jí)存儲(chǔ)器進(jìn)行兩次訪問。對(duì)于寫D-Cache的操作來說,還需要將寫入的數(shù)據(jù)也放到這個(gè)line中,并將其標(biāo)記為dirty。
2.write-back與write?allocate工作流程圖:
在D-Cache中采用write?back方法時(shí),不管是讀取還是寫入時(shí)發(fā)生缺失,都需要從D-Cache中找到一個(gè)line來存放新的數(shù)據(jù),這個(gè)被替換的line如果此時(shí)是dirty,那么首先需要將其中的數(shù)據(jù)寫回到下級(jí)存儲(chǔ)器中,然后才能夠用這個(gè)line存放新的數(shù)據(jù)。
2.1.3 Cache的替換策略
不管是讀取還是寫入D-Cache時(shí)發(fā)生了缺失,都需要從有效的Cache?line中找到一個(gè)并替換之,這就是替換Cache replacement策略。
1.近期最少使用法
近期最少使用法Least Recently Used,LRU會(huì)選擇最近被使用次數(shù)最少的的Cahce?line,因此這個(gè)算法需要跟蹤每個(gè)Cache?libe的使用情況,為每個(gè)Cache?line都設(shè)置一個(gè)年齡age部分,每次當(dāng)一個(gè)Cache?line被訪問時(shí),它對(duì)應(yīng)的年齡部分就會(huì)增加,或者減少其他Cache?line的年齡值,這樣當(dāng)進(jìn)行替換時(shí),年齡值最小的那個(gè)Cache?line就是被使用次數(shù)最少了,會(huì)選擇它進(jìn)行替換。但是隨著Cache相關(guān)聯(lián)度增加,要精確實(shí)現(xiàn)這種LRU方式就非常昂貴了。因此在way的個(gè)數(shù)很多的情況下,都是使用偽LRU的方法。
在下面8-way組相連Cache中,對(duì)所有way進(jìn)行分組,共有三部分,分別介紹如下;
(1)首先將所有way分為兩組,每組有4個(gè)way;
(2)然后將每組中的way在分為兩組,也就是每組有2個(gè)way;
(3)繼續(xù)進(jìn)行分組,此時(shí)每組只有一個(gè)way了
2.隨機(jī)替換
在處理器中,Cache的替換算法一般都是使用硬件來實(shí)現(xiàn)的,因此如果做得很復(fù)雜,會(huì)影響處理器的周期時(shí)間,于是就有了隨機(jī)替換Random?replacement的實(shí)現(xiàn)方法,此算法無需記錄每個(gè)way的年齡信息,而是隨機(jī)地選擇一個(gè)way進(jìn)行替換,相比于LRU替換方法來說,這種方法發(fā)生缺失的頻率會(huì)更高一些,但是隨著Cache容量的增大,這個(gè)差距是越來越小的。實(shí)際設(shè)計(jì)很難做到嚴(yán)格的隨機(jī),一般采用一種稱為時(shí)鐘算法clock?algorithm的方法來實(shí)現(xiàn)近似的隨機(jī),工作原理本質(zhì)上一個(gè)計(jì)算器,計(jì)數(shù)器的的寬度由Cache的相關(guān)度,也就是way的個(gè)數(shù)來決定,例如8way就需要三位,每次當(dāng)Cache中的某個(gè)line需要被替換時(shí),就會(huì)訪問這個(gè)計(jì)數(shù)器,使用計(jì)數(shù)器當(dāng)前的值,從被選定的Cache?set找出要替換的line,這樣就近似地實(shí)現(xiàn)一種隨機(jī)的替換。理論上其性能不是最優(yōu),但是它的硬件復(fù)雜度比較低,也不會(huì)損失過多的性能。
?2.2 提高Cache的性能
在真實(shí)世界的處理器中,會(huì)采用更復(fù)雜的方法來提高Cache的性能,這些方法包括寫緩存write buffer、流水線pipeline cache、多級(jí)結(jié)構(gòu)multilevel cache、victim cache和預(yù)期prefetch。除此之外,對(duì)于亂序執(zhí)行的超標(biāo)量處理器來說,根據(jù)它的特點(diǎn),還有一些其他的方法來提高Cache的性能,例如非阻塞non-blocking cache、關(guān)鍵字優(yōu)先critical word first和提前開始early restart等方法。
2.2.1 寫緩存
不管是load或者store指令,當(dāng)D-Cache發(fā)生缺失時(shí),需要從下一級(jí)存儲(chǔ)器中讀取數(shù)據(jù),并寫到一個(gè)選定的Cache line中,如果這個(gè)line是dirty,那么首先需要將它寫到下級(jí)存儲(chǔ)器中,考慮一般的餓下級(jí)存儲(chǔ)器,例如L2 Cache或是物理內(nèi)存,一般只有一個(gè)讀寫端口,這就要求上面的過程是串行完成的。先將dirty的Cache line的數(shù)據(jù)寫到下級(jí)存儲(chǔ)器中,然后才能讀取下級(jí)存儲(chǔ)器而得到缺失的數(shù)據(jù),由于下級(jí)存儲(chǔ)器的訪問時(shí)間都比較長,這種串行的過程導(dǎo)致D-Cache發(fā)生缺失的處理時(shí)間變得很長,此時(shí)就可以采用write buffer寫緩存來解決這個(gè)問題,dirty的Cache line首先放到寫緩存中,等到下級(jí)存儲(chǔ)器有空閑的時(shí)候,才會(huì)將寫緩存中的數(shù)據(jù)寫到下級(jí)存儲(chǔ)器中。
對(duì)于write back類型的D-Cache來說,當(dāng)一個(gè)dirty的Cache line被替換的時(shí)候,這個(gè)line中的數(shù)據(jù)會(huì)首先放到寫緩存中,然后就可以從下級(jí)存儲(chǔ)器中讀數(shù)據(jù)了。
對(duì)于write?through類型的D-Cache來說,采用寫緩存之后,每次當(dāng)數(shù)據(jù)寫到D-Cache的同時(shí),并不會(huì)同時(shí)寫到下級(jí)存儲(chǔ)器中,而是將其放到寫緩存中,這樣就減少了write?through類型的D-Cache在寫操作時(shí)需要的時(shí)間,從而提高了處理器的性能,以及write?through類型的Cache由于便于進(jìn)行存儲(chǔ)器一致性的管理,所以在多核的處理器中,L1 Cache會(huì)經(jīng)常采用這種結(jié)構(gòu)。
加入寫緩存之后,會(huì)增加系統(tǒng)設(shè)計(jì)的復(fù)雜度,舉例來說,當(dāng)讀取D-Cache發(fā)生缺失時(shí),不僅需要從下級(jí)存儲(chǔ)器中查找這個(gè)數(shù)據(jù),還需要在寫緩存中也進(jìn)行查找。
寫緩存就相當(dāng)于是L1 Cache到下級(jí)存儲(chǔ)器之間的一個(gè)緩沖,通過它,向下級(jí)存儲(chǔ)器中寫數(shù)據(jù)的動(dòng)作會(huì)被隱藏,從而可以提升處理器的執(zhí)行效率,尤其是對(duì)于write?through類型的D-Cache而言。
2.2.2?流水線
對(duì)于讀取D-Cache來說,由于Tag SRAM和Data SRAM可以在同時(shí)進(jìn)行讀取,所以當(dāng)處理器的周期時(shí)間要求不是很嚴(yán)格時(shí),可以在一個(gè)周期內(nèi)完成讀取的操作;而對(duì)于寫D-Cache來說,情況就比較特殊了,讀取Tag SRAM和寫Data SRAM的操作只能串行地完成。只有通過Tag比較,確認(rèn)需要寫的地址在Cache中之后,才可以寫Data SRAM,在主頻比較高的處理器中,這些操作很難在一個(gè)周期內(nèi)完成。這就需要對(duì)D-Cache的寫操作采用流水線的結(jié)構(gòu)。比較典型的方式是將Tag SRAM的讀取和比較放在一個(gè)周期,寫D-Cache放在下一個(gè)周期。
需要注意當(dāng)執(zhí)行l(wèi)oad指令時(shí)候,它想要的數(shù)據(jù)可能正好處于store指令的流水線寄存器中,而不是來自于Data SRAM,因此需要機(jī)制能檢測(cè)到這種情況,將load指令所攜帶的地址和store指令的流水線寄存器進(jìn)行比較。
對(duì)寫D-Cache使用流水線之后,不僅增加了流水線本身的硬件,也帶來一些額外的硬件開銷。
2.2.3?多級(jí)結(jié)構(gòu)
現(xiàn)代處理器很渴望有一種容量大,同時(shí)速度又很快的存儲(chǔ)器,但在硅工藝條件下,對(duì)存儲(chǔ)器來說,容量和速度是一對(duì)相互制約的因素,容量大必然速度慢。
為了使處理器看起來使用了一個(gè)容量大同時(shí)速度快的存儲(chǔ)器,可以使用多級(jí)結(jié)構(gòu)的Cache:
?一般情況下,L1 Cache的容量很小,能夠和處理器保持在同樣速度等級(jí)上,L2 Cache的訪問通常需要消耗處理器的幾個(gè)時(shí)鐘周期,但是容量要更大一些,L1和L2 Cache都會(huì)和處理器放在同一芯片上,現(xiàn)在L3 Cache也放在片上。
一般在處理器中,L2 Cache會(huì)使用write?back方式,但是L1 Cache更傾向采用wirte?through,這樣可以簡(jiǎn)化流水線設(shè)計(jì),尤其在多核情況下,管理存儲(chǔ)器之間的一致性。
對(duì)于多級(jí)結(jié)構(gòu)的Multilevel Cache,還需要了解兩個(gè)概念,Inclusive和Exclusive:
Inclusive:如果L2 Cache包括了L1 Cache的所有內(nèi)容,則稱L2 Cache是Inclusive;
Exclusive:如果L2 Cache與L1 Cache的內(nèi)容互不相同,則稱L2 Cache是Exclusive;
Inclusive類型的Cache是比較浪費(fèi)硬件資源的,因?yàn)樗鼘⒁环輸?shù)據(jù)保存在兩個(gè)地方,優(yōu)點(diǎn)則是可以直接將數(shù)據(jù)寫到L1 Cache中,雖然此時(shí)會(huì)將Cache?line中原來的數(shù)據(jù)覆蓋掉,但是在L2 Cache中存有這個(gè)數(shù)據(jù)的備份,所以這樣的覆蓋不會(huì)引起任何問題(當(dāng)然,被覆蓋的line不能是dirty),以及也簡(jiǎn)化了一致性coherence的管理。
例如在多核的處理器中,執(zhí)行store指令改變了存儲(chǔ)器中的一個(gè)地址的數(shù)據(jù)時(shí),如果是Inclusive類型的Cache,那么只需檢查最低一級(jí)的Cache即可(L2 Cache),避免打擾上級(jí)Cache(L1 Cache)和處理器流水線的影響;
如果是Exclusive類型的Cache,很顯然要檢查所有的Cache,而檢查L1 Cache也就意味著干擾了處理器的流水線。如果處理器要讀取的數(shù)據(jù)不在L1 Cache中,而在L2 Cache中,那么在將數(shù)據(jù)從L2 Cache放到L1 Cache的同時(shí),也需要將L1 Cache中被覆蓋的數(shù)據(jù)寫到L2 Cache中,這樣數(shù)據(jù)交換很顯然會(huì)降低處理器的效率,但是Exclusive類型的Cache避免硬件的浪費(fèi),可以獲得更多可用的容量。
2.2.4 Victim Cache
Cache中被“踢出”的數(shù)據(jù)可能馬上又要被使用,因?yàn)镃ache中存儲(chǔ)的是經(jīng)常要使用的數(shù)據(jù)。例如對(duì)一個(gè)2-way組相連的D-Cache來說,如果個(gè)數(shù)據(jù)頻繁使用的3個(gè)數(shù)據(jù)恰好都位于同一個(gè)Cache?set中,那么就會(huì)導(dǎo)致一個(gè)way中的數(shù)據(jù)經(jīng)常被“踢出”Cache,然后又經(jīng)常地被寫回Cache。
這會(huì)導(dǎo)致Cache始終無法名字需要的數(shù)據(jù),顯然降低了處理器的執(zhí)行效率,如果為此增加Cache中的way個(gè)數(shù),又會(huì)浪費(fèi)大量的空間。Victim Cache正是要解決這樣的問題,它可以保存最近被踢出Cache的數(shù)據(jù),因此所有的Cache?set都可以利用它來提高way的個(gè)數(shù),通常Victim Cache采用全相連的方式,容量都比較小(一般存儲(chǔ)4~16個(gè)數(shù)據(jù))。?
Victim?Cache本質(zhì)上相當(dāng)于增加了Cache中way的個(gè)數(shù),能夠避免多個(gè)數(shù)據(jù)競(jìng)爭(zhēng)Cache中有限的位置,從而降低了Cache的缺失率。一般情況下,Cache和Victim Cache存在互斥關(guān)系,也就是它們不包含想同樣的數(shù)據(jù),處理器內(nèi)核可以同時(shí)讀取它們。
同樣,Victim Cache的數(shù)據(jù)會(huì)被寫到Cache中,而Cache中被替換的數(shù)據(jù)會(huì)寫到Victim Cache中,這就相當(dāng)于它們互換了數(shù)據(jù)。
還有一種更Victim Cache類似的設(shè)計(jì)思路,稱為Filter Cache,只不過使用在Cache之前,而Victim Cache使用在Cache之后,當(dāng)一個(gè)數(shù)據(jù)第一次使用時(shí),它并不會(huì)馬上放到Cache中,而是首先會(huì)被放到Filter Cache中,等到這個(gè)數(shù)據(jù)再次被使用時(shí),它才會(huì)被搬移到Cache中,這樣做可以防止那些偶然使用的數(shù)據(jù)占據(jù)Cache。
?2.2.5?預(yù)取
影響Cache缺失率的3C中一項(xiàng)為Compulsory,當(dāng)處理器第一次訪問一條指令或者一個(gè)數(shù)據(jù)時(shí),這個(gè)指令或數(shù)據(jù)肯定不會(huì)在Cache中,這種情況引起的缺失似乎不可避免,但是實(shí)際上使用預(yù)取prefetch可以緩解這個(gè)問題。所謂預(yù)取,本質(zhì)上也是一種預(yù)測(cè)技術(shù),它猜測(cè)處理器在以后可能會(huì)使用什么指令或數(shù)據(jù),然后提前將其放到Cache中,這個(gè)過程可以使用硬件或者軟件完成。
1.硬件預(yù)取
對(duì)于指令來說,猜測(cè)后續(xù)會(huì)執(zhí)行什么指令相對(duì)比較容易,因?yàn)槌绦虮旧硎谴袌?zhí)行的,雖然由于分支指令的存在,這種猜測(cè)有時(shí)候也會(huì)出錯(cuò),導(dǎo)致不會(huì)被使用的指令進(jìn)入了I-Cache,這一方面降低了I-Cache實(shí)際可用的容量,一方面又占用了本來可能有用的指令,這稱為“Cache污染”,不僅浪費(fèi)了時(shí)間,還會(huì)影響處理器的執(zhí)行效率,為了避免這種情況,可用將預(yù)取的指令放到一個(gè)單獨(dú)的緩存中。
?當(dāng)I-Cache發(fā)生缺失時(shí),處理將需要的數(shù)據(jù)塊data?block從下級(jí)存儲(chǔ)器取出并放到I-Cache中,還會(huì)降下一個(gè)數(shù)據(jù)塊也讀取出來,只不過它不會(huì)放到I-Cache中,而是放到Stream Buffer的地方。在后續(xù)執(zhí)行時(shí),如果在I-Cache中發(fā)生了缺失,但是在Stream Buffer找到了想要的指令,那么除了使用Stream Buffer中讀取的指令之外,還會(huì)將其中對(duì)應(yīng)的數(shù)據(jù)塊搬移到I-Cache中,同時(shí)繼續(xù)從下一級(jí)存儲(chǔ)器中讀取下一個(gè)數(shù)據(jù)塊放到Stream Buffer,當(dāng)程序中沒有遇到分支指令時(shí),這種方法會(huì)一直正確地工作,從而使I-Cache的缺失率得到降低。但是分支指令會(huì)導(dǎo)致Stream Buffer的指令編的無效,此時(shí)的預(yù)取相當(dāng)于做了無用功,浪費(fèi)了總線帶寬和功耗。預(yù)取是一把雙刃劍,它可能會(huì)減少Cache的缺失率,也可能由于錯(cuò)誤的預(yù)取而浪費(fèi)了功耗和性能。
不同于指令的預(yù)取,對(duì)于數(shù)據(jù)的預(yù)取來說,它的規(guī)律更難以進(jìn)行捕捉。一般情況下,當(dāng)訪問D-Cache發(fā)生缺失時(shí),除了將所需要的數(shù)據(jù)塊從下級(jí)存儲(chǔ)器中取出來之外,還會(huì)將下一個(gè)數(shù)據(jù)塊也讀取出來。Intel Pentium 4和IBM Power5處理器中,采用了一種稱為Strided Prefetch方法,它能夠使用硬件來觀測(cè)程序中使用數(shù)據(jù)的規(guī)律。
2.?軟件預(yù)取
使用硬件進(jìn)行數(shù)據(jù)的預(yù)取,很難得到滿意的結(jié)果,其實(shí)在程序的編譯階段,編譯器complier就可以對(duì)程序進(jìn)行分析,進(jìn)而知道哪些數(shù)據(jù)是需要進(jìn)行預(yù)取的,如果在指令集中有預(yù)取指令prefetch?instruction,那么編譯器就可以可以直接控制程序進(jìn)行預(yù)取。
應(yīng)用軟件預(yù)取方法有一種前提,就是預(yù)取的時(shí)機(jī)。如果預(yù)取數(shù)據(jù)的時(shí)間太晚,那么當(dāng)真正需要使用數(shù)據(jù)時(shí),有可能還沒有被預(yù)取出來,這樣預(yù)取就失去的意義;如果預(yù)取的時(shí)間太早,那么就有可能踢掉D-Cache中一些本來有用的數(shù)據(jù),造成Cache污染。
還需要注意,使用軟件預(yù)取的方法,當(dāng)執(zhí)行預(yù)取指令的時(shí)候,處理器需要能夠繼續(xù)執(zhí)行,也就是能繼續(xù)從D-Cache中讀取數(shù)據(jù),而不能讓預(yù)取指令阻礙了后面指令的執(zhí)行,這要求D-Cache是non-blocking結(jié)構(gòu)。
在實(shí)現(xiàn)虛擬存儲(chǔ)器Virtual?memory系統(tǒng)中,預(yù)取指令有可能會(huì)引起一些異常exception發(fā)生,例如Page?fault、虛擬地址錯(cuò)誤virtual?address?fault或者保護(hù)違例Protection Violation。此時(shí)若對(duì)異常進(jìn)行處理,就稱其為處理錯(cuò)誤的預(yù)取指令Faulting Prefetch Instruction,反之,稱為不處理錯(cuò)誤的預(yù)取指令nonfaulting?prefetch?instruction。
??2.3 多端口Cache
在超標(biāo)量處理器中,為了提高性能,處理器需要能夠在每周期同時(shí)執(zhí)行多條load/store指令,這需要一個(gè)多端口的D-Cache,以便支持多條load/stroe指令的同時(shí)訪問。
其實(shí)在超標(biāo)量處理器中,有很多重要部件都是多端口結(jié)構(gòu)的,比如寄存器堆register file、發(fā)射隊(duì)列issue queue和重排序緩存ROB等。由于這些部件本身容量不是很大,所以即使采用多端口結(jié)構(gòu),也不會(huì)對(duì)芯片的面積和速度產(chǎn)生太大的影響,但是D-Cache不同,它的容量本身就很大,如果采用多端口設(shè)計(jì),會(huì)有很大負(fù)面影響,因此需要采用一些辦法來解決這個(gè)問題,本節(jié)重點(diǎn)介紹True Multi-port、Multi Cache Copies和Multi-banking。
2.3.1 True Multi-port
雖然在現(xiàn)實(shí)中,不可能對(duì)Cache直接采用多端口設(shè)計(jì),但是本節(jié)還是看一下這種最原始的方法究竟有何缺點(diǎn),這種方法使用一個(gè)多端口的SRAM來實(shí)現(xiàn)多端口的Cache,以一個(gè)雙端口的Cache為例,所有在Cache中的控制通路和數(shù)據(jù)通路都需要進(jìn)行復(fù)制,這表示它有兩套地址解碼器address decoder,使兩個(gè)端口可以同時(shí)尋址Tag SRAM和Data SRAM;有兩個(gè)多路選擇器way mux,用來讀取兩個(gè)端口的數(shù)據(jù);比較器的數(shù)量也需要增加一倍,用來判斷兩個(gè)端口的命中情況:同時(shí)還需要有兩個(gè)對(duì)其器aligner等。Tag SRAM和Data SRAM本身并不需要復(fù)制一份,但是它們當(dāng)中的每個(gè)Cell都需要都是支持兩個(gè)并行的讀取操作,但是不需要兩個(gè)寫端口,因?yàn)闊o法對(duì)一個(gè)SRAM Cell同時(shí)寫兩次。
此種方法需要將很多電路進(jìn)行復(fù)制,因此增大了面積,且SRAM Cell需要驅(qū)動(dòng)多個(gè)讀端口,因此需要更長的訪問時(shí)間,功耗也隨之增大,所以一般不會(huì)直接采用這種方式來設(shè)計(jì)多端口Cache。
2.3.2 Multiple Cache Copies
將Tag SRAM和Data SRAM進(jìn)行了復(fù)制,與2.3.1節(jié)類似,不過是將Cache進(jìn)行復(fù)制,SRAM將不再需要使用多端口的結(jié)構(gòu),這樣可以基本上消除對(duì)處理器周期時(shí)間的影響。但是,這種方法浪費(fèi)了很多面積,而且需要保持兩個(gè)Cache間的同步。例如store指令需要同時(shí)寫到兩個(gè)Cache中,當(dāng)一個(gè)Cache?line被替換,也需要對(duì)另一個(gè)Cache進(jìn)行同樣的操作,此設(shè)計(jì)顯然非常麻煩,不是一個(gè)很優(yōu)化的方法,在現(xiàn)代處理器中很少被使用。
2.3.3 Multi-banking
此結(jié)構(gòu)是在現(xiàn)實(shí)當(dāng)中的處理器被廣泛使用的方法,它將Cache分為很多小個(gè)bank,每個(gè)bank都只有一個(gè)端口,如果在一個(gè)周期之內(nèi),Cache的多個(gè)端口上的訪問地址位于不同的bank之中,那樣就不會(huì)引起任何問題,只有當(dāng)兩個(gè)或多個(gè)端口的地址位于同一個(gè)bank之中時(shí),才會(huì)引起bank?conflict。
?使用這種方法,一個(gè)雙端口的Cache仍舊需要兩個(gè)地址解碼器、兩個(gè)多路選擇器、兩套比較器和兩個(gè)對(duì)齊器,而Data SRAM此時(shí)不需要多端口結(jié)構(gòu)了,這樣就提高了速度,并在一定程度上減少了面積。但是由于需要判斷Cache的每個(gè)端口是否命中,所以對(duì)于Tag SRAM來說,仍舊需要提供多個(gè)端口同時(shí)讀取的功能,也就是采用多端口SRAM來實(shí)現(xiàn)。
影響這種多端口Cache性能的一個(gè)關(guān)鍵因素就是bank沖突,可以采用更多的bank來緩解這個(gè)問題,使bank沖突發(fā)生的概率盡可能降低,并且還可以提高bank的利用效率,避免有用的數(shù)據(jù)都集中在一個(gè)bank的情況發(fā)生,同時(shí),由于每個(gè)端口都會(huì)訪問所有bank,這需要更多的布線資源,有可能對(duì)版圖設(shè)計(jì)造成一定的影響。
2.3.4?真實(shí)的例子AMD Opteron的多端口Cache
AMD的Opteron系列處理器是64位處理器,但是考慮到現(xiàn)實(shí)的需求,處理器的地址并沒有使用64位,它的虛擬地址virtual?address是48位,物理地址physical?address是40位,采用簡(jiǎn)化地址從而減少硅片面積。
Opteron處理器的D-Cache是雙端口的,每個(gè)端口都是64位的位寬,雙端口以為這這個(gè)Cache能夠在一個(gè)周期內(nèi)支持=兩條load/store指令同時(shí)進(jìn)行訪問,它使用了multi-banking的機(jī)制來實(shí)現(xiàn)這個(gè)多端口的功能。
在AMD Opteron處理器的這個(gè)Cache中,data?block的大小是64字節(jié),需要6位地址進(jìn)行尋址,每個(gè)data?block被封為8個(gè)獨(dú)立的bank,每個(gè)bank都是64位的單端口SRAM。
整個(gè)Cache的大小是64KB,采用2-way組相連,因此每一路的大小是32KB;使用Virtually-index,physically-tag的實(shí)現(xiàn)方式,直接使用VA虛擬地址來尋址Cache。因?yàn)槊恳宦肥?2KB大小,因此需要15位地址尋址,又因?yàn)槊總€(gè)data?block大小是64字節(jié),因此尋址其中的每個(gè)字節(jié)需要使用VA[5:0],剩下的VA[14:6]用來尋找每個(gè)Cache?set。
由于每個(gè)Cache?line中的data block被劃分為8個(gè)bank,每個(gè)bank是8字節(jié)寬的SRAM,所以很自然地使用VA[5:3]來找到某個(gè)bank,剩下的VA[2:0]用來從8字節(jié)中數(shù)據(jù)中找到某個(gè)字節(jié),這種方式將兩個(gè)連續(xù)的8字節(jié)數(shù)據(jù)放到兩個(gè)相鄰的不同的bank中,利用空間局部性原理,使得對(duì)這兩個(gè)8字節(jié)數(shù)據(jù)訪問落在不同的bank中。
由于Cache的每個(gè)端口在訪問時(shí)候,都會(huì)同時(shí)訪問兩個(gè)way中的數(shù)據(jù),然后根據(jù)Tag的比較結(jié)果來從兩個(gè)way中選擇命中的那個(gè),所以Cache的一個(gè)端口在訪問的時(shí)候,會(huì)同時(shí)訪問到兩個(gè)bank,每個(gè)way各一個(gè)。
在支持虛擬存儲(chǔ)器的處理器中,最常見的頁面大小page為4KB,這需要VA[11:0]來尋找頁面內(nèi)部,因此對(duì)于48位的虛擬地址來說,剩下的VA[47:12]就作為VPN(Virtual Page Number)來尋址TLB,得到物理地址中PFN(Physical Frame Number)[39:12],它用來和Tag部分進(jìn)行比較,判斷是否命中。
對(duì)于一個(gè)2-way組相連的Cache來說,相比于單端口的實(shí)現(xiàn)方式,兩個(gè)端口的實(shí)現(xiàn)方式所需要的控制邏輯電路基本上擴(kuò)大了一倍,需要兩個(gè)TLB、兩個(gè)Tag比較器,還需要兩倍Tag存儲(chǔ)器,Opteron處理器采用將Tag SRAM復(fù)制一份來實(shí)現(xiàn)雙端口的SRAM,當(dāng)然也可以采用真實(shí)的雙端口SRAM來實(shí)現(xiàn)這個(gè)功能,面積也不會(huì)減少多少,速度還會(huì)變慢。
除了Cache中存儲(chǔ)數(shù)據(jù)的Data SRAM沒有被復(fù)制之外,其他的電路基本上被復(fù)制一份,因此采用multi-banking方式來實(shí)現(xiàn)雙端口的Cache,面積會(huì)增大很度,但是它的好處是速度比較快,對(duì)處理器的周期時(shí)間有比較小的負(fù)面影響。
2.4 超標(biāo)量處理器的取指令
如果一個(gè)超標(biāo)量處理器在每周期可以同時(shí)解碼4條指令,這個(gè)處理器就稱為4-way的超標(biāo)量處理器,此處理器每周期應(yīng)該能夠從I-Cache中至少取得4條指令,才能喂飽后續(xù)的流水線,如果少于這個(gè)值,則會(huì)造成后面的流水線浪費(fèi)。
對(duì)于一個(gè)n-way超標(biāo)量處理器來說,它給出一個(gè)取指令的地址后,I-Cache應(yīng)該能夠至少送出n條指令,稱這n條指令為一組(fetch group)。I-Cahce支持這個(gè)功能最簡(jiǎn)單的方式就是使用data block的大小為n個(gè)字,每周期將其全部進(jìn)行輸出如果處理器送出的取指令地址是n字對(duì)齊的,那么此時(shí)就可以實(shí)現(xiàn)每周期從I-Cache中讀取n條指令的功能,在數(shù)據(jù)塊data block部分需要n個(gè)32位的SRAM,當(dāng)I-Cache命中時(shí),這些SRAM會(huì)同時(shí)進(jìn)行輸出。但是由于存在跳轉(zhuǎn)指令,處理器送出的取指令地址不可能總是n字對(duì)齊。
當(dāng)取指令的地址不再是是字對(duì)齊時(shí),一個(gè)組fetch group中的指令就可能落在兩個(gè)Cache line中,但是對(duì)于Cache來說,每周期只能訪問一個(gè)Cache line,這會(huì)導(dǎo)致在一個(gè)周期內(nèi)無法取出4條指令,使得后續(xù)流水線無法得到充足的指令,使部分資源空置。
處理器每周期取出的指令多余它能夠解碼的指令個(gè)數(shù),通過一個(gè)緩存來將多余的指令緩存起來,這樣就可以使后續(xù)的流水線得到充足的指令,避免了硬件資源的浪費(fèi),這些指令會(huì)存儲(chǔ)到一個(gè)稱為指令緩存Instruction Buffer,IB地方,后續(xù)的指令解碼器會(huì)從指令緩存中取指令。
即使當(dāng)前周期送出的取指令地址不是四字對(duì)齊,只要以后的周期中不出現(xiàn)引起指令的執(zhí)行順序改變的情況,例如分支指令和異常等情況,下個(gè)周期取指令的地址也會(huì)變成四字對(duì)齊,此時(shí)就可以在一個(gè)周期內(nèi)取出四條指令了。
其實(shí)在現(xiàn)實(shí)世界中,分支指令出現(xiàn)的頻率還是比較高的,這一方面會(huì)導(dǎo)致取指令的地址無法四字對(duì)齊,另一方面還會(huì)在分支指令執(zhí)行的時(shí)候?qū)е逻^多的無用指令進(jìn)入流水線,因此需要對(duì)分支指令進(jìn)行預(yù)測(cè)。
即使取指令的地址不是四字對(duì)齊的,仍舊可以在一個(gè)周期內(nèi)讀取4條指令,最簡(jiǎn)單的實(shí)現(xiàn)方法是使數(shù)據(jù)塊data?block大小變大,例如其包含8個(gè)字,只要取指令的地址不是落在數(shù)據(jù)塊的最后三個(gè)字,就可以在每周期內(nèi)讀取4條指令。這樣做的前提是增大了數(shù)據(jù)塊的容量,如果在Cache的總?cè)萘恳欢ǖ那闆r下,意味著Cache?set的個(gè)數(shù)會(huì)減少,可能會(huì)增大Cache?miss的概率。
而且,如果Cache的每個(gè)數(shù)據(jù)塊是8個(gè)字,是不是也需要使用8個(gè)32位的SRAM來實(shí)現(xiàn)呢??問題就是如果SRAM的個(gè)數(shù)過多,會(huì)導(dǎo)致保護(hù)電路也占用過多的面積,而且要從8個(gè)SRAM的輸出中選用4個(gè)字也是一件很浪費(fèi)電路的事情。
若一個(gè)Cache?line中包含的8個(gè)字實(shí)際上占據(jù)了SRAM的兩行,因此共使用了4個(gè)32位的SRAM。其中需要一段重排序的邏輯電路,對(duì)4個(gè)SRAM的4條指令進(jìn)行重排序,使它們滿足最原始的指令順序,這樣才能夠使后續(xù)的流水線得到正確的指令。此外,當(dāng)取指令的地址指向了Cache?line中最后的三條指令的某一條時(shí),此時(shí)本周期并不能輸出4條指令,因此在重排序邏輯電路中還需要假如指示每條指令是否有效的標(biāo)志信號(hào),這樣才能夠?qū)⒂行У闹噶顚懭氲胶罄m(xù)的指令緩存Instruction Buffer中。
為什么要實(shí)現(xiàn)分支預(yù)測(cè)呢?因此在超標(biāo)量處理器中,并行度很高,流水線很深,一條指令從進(jìn)入流水線直到結(jié)果被計(jì)算出來,中間會(huì)經(jīng)歷很多段流水線,如果使用最簡(jiǎn)單的靜態(tài)預(yù)測(cè)方法,那么一旦發(fā)現(xiàn)這條分支指令是需要執(zhí)行的,就需要將流水線中,在分支指令之后進(jìn)入流水線的所有指令都抹掉,也就是這段時(shí)間做了無用功。如果能夠提起知道在本周期取出的指令中,那條指令是分支指令,且可以預(yù)知這條分支指令的結(jié)果,那么就可以減少流水線被打斷的次數(shù)。
實(shí)現(xiàn)分支預(yù)測(cè)之后,從I-Cache中取指令的同時(shí),已經(jīng)可以知道當(dāng)前指令組fetch?group中那條指令時(shí)分支指令,如果它被預(yù)測(cè)執(zhí)行,那么指令組中位于它之后的指令就不應(yīng)該進(jìn)入到后續(xù)的流水線。
在實(shí)現(xiàn)虛擬存儲(chǔ)器VA的處理器中,處理器送出的取指令地址是虛擬地址,需要使用一定的方法將其轉(zhuǎn)換為物理地址,然后才能夠從存儲(chǔ)器中取指令,在這個(gè)轉(zhuǎn)換過程中可能發(fā)生很多事情,它們都可以打斷流水線的正常執(zhí)行。
總結(jié)
以上是生活随笔為你收集整理的超标量处理器设计 姚永斌 第2章 Cache 摘录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 易用性测试四大内容
- 下一篇: 国外 Warez 网站 杂集