Linux內(nèi)存系列2 - CPU Cache

CPU Cache

今天的CPU比25年前更復(fù)雜宠蚂。那時(shí)候,CPU內(nèi)核的頻率與內(nèi)存總線的頻率相當(dāng)童社。內(nèi)存訪問只比寄存器訪問慢一點(diǎn)求厕。但是,在90年代初期扰楼,CPU設(shè)計(jì)人員增加了CPU內(nèi)核的頻率呀癣,但內(nèi)存總線的頻率和RAM芯片的性能并沒有成比例增加,這種情況發(fā)生了巨大變化灭抑。這并不是因?yàn)闊o(wú)法構(gòu)建更快的RAM十艾,如前一節(jié)所述。這是可能的腾节,但不經(jīng)濟(jì)忘嫉。與當(dāng)前CPU內(nèi)核一樣快的RAM比任何動(dòng)態(tài)RAM都要昂貴幾個(gè)數(shù)量級(jí)。

如果選擇在具有非常小的案腺,非城烀幔快速的RAM的機(jī)器和具有大量相對(duì)快的RAM的機(jī)器之間進(jìn)行,則第二個(gè)將總是勝出劈榨,因?yàn)楣ぷ骷笮〕^小RAM大小時(shí)就會(huì)訪問次級(jí)存儲(chǔ)比如硬盤访递。這里的問題是二級(jí)存儲(chǔ)的速度,通常是硬盤同辣,用于保存工作集中被換出的部分拷姿。訪問這些磁盤的速度比DRAM訪問慢幾個(gè)數(shù)量級(jí)。

幸運(yùn)的是旱函,它不一定是一個(gè)全或無(wú)的決定响巢。除了大量的DRAM之外,計(jì)算機(jī)可以擁有少量的高速SRAM棒妨。一種可能的實(shí)現(xiàn)方式是將處理器地址空間的某個(gè)區(qū)域?qū)S脼榘琒RAM踪古,其余部分則用于DRAM。操作系統(tǒng)的任務(wù)將是優(yōu)化分配數(shù)據(jù)以利用SRAM券腔》拢基本上,在這種情況下纷纫,SRAM相當(dāng)于處理器寄存器組的擴(kuò)展枕扫。

雖然這是一個(gè)可能的實(shí)現(xiàn),但它不可行辱魁。忽略將這種SRAM支持的內(nèi)存的物理資源映射到進(jìn)程的虛擬地址空間(其本身非常困難)的問題铡原,該實(shí)現(xiàn)會(huì)需要每個(gè)進(jìn)程通過軟件來(lái)管理該內(nèi)存區(qū)域的分配偷厦。內(nèi)存區(qū)域的大小因處理器而異(即,處理器們具有不同數(shù)量的昂貴的SRAM支持的內(nèi)存)燕刻。程序的每個(gè)模塊都將聲明占有一部分快速內(nèi)存只泼,這將引來(lái)額外開銷因?yàn)樾枰M(jìn)行同步相關(guān)的操作÷严矗總之请唱,快速內(nèi)存帶來(lái)的收益將完全被資源管理的開銷所吞噬。

因此过蹂,與其將SRAM的管理給到操作系統(tǒng)或用戶十绑,不如將其變?yōu)橛商幚砥魍该魇褂貌⒂商幚砥鱬rocessor所管理。在這種模式下酷勺,SRAM被用做于主內(nèi)存中數(shù)據(jù)(即cache)的臨時(shí)拷貝本橙,這些數(shù)據(jù)可能很快會(huì)被處理器使用。這是完全可能的脆诉,因?yàn)槌绦虻拇a和數(shù)據(jù)具有時(shí)間和空間局部性temporal and spatial locality甚亭。這意味著,在很短的時(shí)間內(nèi)击胜,很有可能重復(fù)使用到相同的代碼或數(shù)據(jù)亏狰。對(duì)于代碼這意味著代碼中很可能存在循環(huán),因此相同的代碼會(huì)一遍又一遍地被執(zhí)行(這就是空間局部性spatial locality的完美情況 )偶摔。理想情況下暇唾,數(shù)據(jù)訪問也可能分布在一個(gè)小區(qū)域內(nèi)。即使短時(shí)間內(nèi)使用的內(nèi)存不夠緊鄰辰斋,同樣的數(shù)據(jù)還是有很大概率在不久的將來(lái)會(huì)被重用(時(shí)間局部性 temporal locality)策州。例如,對(duì)于代碼來(lái)說宫仗,這意味著在循環(huán)中進(jìn)行了一次函數(shù)調(diào)用够挂,該函數(shù)位于地址空間的某個(gè)地方。該函數(shù)在內(nèi)存中可能會(huì)比較偏僻锰什,但對(duì)該函數(shù)的調(diào)用將會(huì)在短時(shí)間內(nèi)再次發(fā)生。對(duì)于數(shù)據(jù)來(lái)說卿啡,這意味著一次使用的內(nèi)存總量(工作集大忻嗥!)在理想情況下是有限的贮乳,但是由于RAM 的隨機(jī)訪問特性,所使用的內(nèi)存并不是緊鄰的嫩码。意識(shí)到這兩個(gè)局部性是理解CPU caches概念的關(guān)鍵。

只需要一個(gè)簡(jiǎn)單的計(jì)算就可以展現(xiàn)出caches在理論上可以達(dá)到怎樣的高效性罪既。假設(shè)訪問主存需要200個(gè)周期铸题,訪問cache內(nèi)存需要15個(gè)時(shí)鐘周期铡恕。然后,如果沒有緩存丢间,代碼訪問到100個(gè)數(shù)據(jù)探熔,每個(gè)數(shù)據(jù)訪問100次,將在內(nèi)存操作上花費(fèi)2,000,000個(gè)周期烘挫,如果可以緩存所有數(shù)據(jù)诀艰,則只需要168,500個(gè)周期。這是91.5%的優(yōu)化饮六。

用于高速緩存的SRAM的大小比主存小很多倍其垄。依筆者在工作站上的CPU緩存相關(guān)經(jīng)驗(yàn),緩存大小總是主內(nèi)存大小的1/1000(現(xiàn)代:4MB緩存和4GB主內(nèi)存)卤橄。這本身并不是一個(gè)問題绿满。如果工作集的大小(當(dāng)前處理的數(shù)據(jù)集)小于緩存大小窟扑,則無(wú)關(guān)緊要喇颁。但電腦沒有理由沒有大的主存。工作集一定會(huì)大于緩存辜膝。對(duì)于運(yùn)行多個(gè)進(jìn)程的系統(tǒng)尤其如此无牵,這種情況下工作集的大小是所有進(jìn)程和內(nèi)核的工作集的總和。

解決緩存只有有限大小這個(gè)問題厂抖,我們需要一個(gè)好策略來(lái)決定在任何給定時(shí)間應(yīng)該緩存什么茎毁。由于并非所有工作集的數(shù)據(jù)都完全在同一時(shí)間使用, 因此我們可以使用技術(shù)臨時(shí)替換緩存中的某些數(shù)據(jù)忱辅。也許這可以在數(shù)據(jù)實(shí)際需要之前完成七蜘。這種預(yù)取將消除訪問主內(nèi)存的一些成本,因?yàn)樗c程序的執(zhí)行是異步的墙懂。所有這些技術(shù)(不僅于此)可以使緩存變得比看起來(lái)更強(qiáng)大橡卤。我們將在3.3節(jié)討論它們。一旦所有這些技術(shù)都被利用损搬,剩下的就看程序員的了碧库,并幫助處理器進(jìn)行決策。如何做到這一點(diǎn)將在第6節(jié)討論巧勤。

3.1 CPU Caches in the Big Picture

在深入討論CPU緩存實(shí)現(xiàn)的技術(shù)細(xì)節(jié)之前嵌灰,有些讀者可能會(huì)覺得首先更詳細(xì)地看到緩存如何適應(yīng)現(xiàn)代計(jì)算機(jī)系統(tǒng)的“大圖”(Big Picture)是有用的。

Figure 3.1: 最小Cache配置

圖3.1顯示了最簡(jiǎn)單的緩存配置颅悉。它對(duì)應(yīng)著最早期使用CPU cache的系統(tǒng)的架構(gòu)沽瞭。CPU內(nèi)核不再直接連接到主內(nèi)存。{ 在更早的系統(tǒng)中剩瓶,高速緩存被連接到系統(tǒng)總線驹溃,就像CPU和主存儲(chǔ)器一樣城丧。這使用了一個(gè)小技巧,并不是比真正的解決方案豌鹤。}所有的數(shù)據(jù)加載和存儲(chǔ)都必須經(jīng)過緩存亡哄。CPU核心與緩存之間的連接是一種特殊的快速連接。在一個(gè)簡(jiǎn)化的表示中傍药,主存和高速緩存連接到系統(tǒng)總線磺平,該系統(tǒng)總線也可用于與系統(tǒng)的其他組件進(jìn)行通信。我們引入了系統(tǒng)總線(現(xiàn)代叫做“FSB”); 參見第2.2節(jié)拐辽。在本節(jié)中拣挪,我們先忽略北橋; 假定它是存在的,來(lái)加快CPU與主存的通信俱诸。

盡管過去幾十年來(lái)計(jì)算機(jī)已經(jīng)使用馮諾依曼體系結(jié)構(gòu)菠劝,但經(jīng)驗(yàn)表明,分離用于代碼和數(shù)據(jù)的緩存是有利的睁搭。自1993年以來(lái)赶诊,英特爾一直使用獨(dú)立的代碼和數(shù)據(jù)緩存,并且從未回頭园骆。代碼和數(shù)據(jù)所需的內(nèi)存區(qū)域幾乎相互獨(dú)立舔痪,這就是獨(dú)立緩存更好地工作的原因。近年來(lái)出現(xiàn)了另一個(gè)優(yōu)點(diǎn):大多數(shù)常用處理器的指令解碼步驟很慢; 高速緩存已經(jīng)解碼的指令可以加速執(zhí)行锌唾,特別是當(dāng)由于錯(cuò)誤預(yù)測(cè)或不可預(yù)測(cè)的分支而導(dǎo)致pipeline為空時(shí)锄码。

引入緩存后不久,系統(tǒng)變得更加復(fù)雜晌涕。高速緩存和主存之間的速度差異再次增大滋捶,使得另一個(gè)級(jí)別的高速緩存不得不被添加進(jìn)來(lái),它比第一級(jí)高速緩存更大且更慢余黎。出于經(jīng)濟(jì)原因重窟,僅增加第一級(jí)緩存的大小不是一種選擇。今天惧财,甚至有機(jī)器在生產(chǎn)環(huán)境中使用了三級(jí)緩存巡扇。帶有這種處理器的系統(tǒng)如圖3.2所示。隨著單個(gè)CPU的內(nèi)核數(shù)量的增加垮衷,未來(lái)的緩存級(jí)別數(shù)量可能會(huì)增加厅翔。

圖3.2:具有3級(jí)緩存的處理器

圖3.2展示了三級(jí)緩存,并介紹了我們將在文章的后續(xù)部分將使用的術(shù)語(yǔ)帘靡。L1d是一級(jí)數(shù)據(jù)cache知给,L1i是一級(jí)指令cache瓤帚。請(qǐng)注意描姚,這只是一個(gè)示意圖; 現(xiàn)實(shí)中的數(shù)據(jù)流從core到主存的過程中不需要經(jīng)過任何更高級(jí)別的cache涩赢。CPU設(shè)計(jì)人員有很大的自由來(lái)設(shè)計(jì)cache的接口。對(duì)于程序員來(lái)說轩勘,這些設(shè)計(jì)選擇是不可見的筒扒。

另外,我們有擁有多個(gè)core的處理器绊寻,每個(gè)core可以有多個(gè)“線程”花墩。核心和線程之間的區(qū)別在于,獨(dú)立的核心具有所有硬件資源的獨(dú)立的副本(幾乎(早期的多核處理器澄步,甚至具有單獨(dú)的第二級(jí)緩存而沒有第三級(jí)緩存)冰蘑。)。核心可以完全獨(dú)立運(yùn)行村缸,除非它們?cè)谕粫r(shí)間使用相同的資源祠肥,例如與外部的連接。另一方面梯皿,線程們共享幾乎所有的處理器資源仇箱。英特爾的線程實(shí)現(xiàn)只為線程提供單獨(dú)的寄存器,甚至是有限的东羹,還有一些寄存器是共享的〖燎牛現(xiàn)代CPU的完整概貌如圖3.3所示。

圖3.3:多處理器属提,多核权逗,多線程

在這個(gè)圖中我們有兩個(gè)處理器,每個(gè)處理器有兩個(gè)內(nèi)核垒拢,每個(gè)內(nèi)核有兩個(gè)線程旬迹。線程共享一級(jí)緩存。核心(深灰色)具有單獨(dú)的1級(jí)高速緩存求类。CPU的所有核心共享更高級(jí)別的緩存奔垦。兩個(gè)處理器(兩個(gè)較大的灰色陰影箱)當(dāng)然不共享任何緩存。所有這些都很重要尸疆,特別是當(dāng)我們?cè)谟懻揷ache對(duì)多進(jìn)程和多線程應(yīng)用程序的影響時(shí)椿猎。

3.2 Cache Operation at High Level

要理解使用緩存的成本和節(jié)約,我們必須將第2節(jié)中關(guān)于機(jī)器體系結(jié)構(gòu)和RAM技術(shù)的知識(shí)與前一節(jié)中描述的緩存結(jié)構(gòu)相結(jié)合寿弱。

默認(rèn)情況下犯眠,CPU內(nèi)核讀取或?qū)懭氲乃袛?shù)據(jù)都存儲(chǔ)在緩存中。有些內(nèi)存區(qū)域不能被緩存症革,但這只是OS實(shí)現(xiàn)者需要關(guān)注的內(nèi)容; 它對(duì)應(yīng)用開發(fā)者來(lái)說是不可見的筐咧。還有一些指令允許程序員故意繞過某些特定緩存。這將在第6節(jié)中討論。

如果CPU需要數(shù)據(jù)字data word量蕊,則首先搜索高速cache铺罢。顯然,緩存不能包含整個(gè)主存的內(nèi)容(否則我們不需要緩存)残炮,但由于所有內(nèi)存地址都是可緩存的韭赘,因此每個(gè)緩存項(xiàng)都使用數(shù)據(jù)字在主存中的地址進(jìn)行標(biāo)記。這樣势就,對(duì)一個(gè)地址的讀取或?qū)懭胝?qǐng)求可以在緩存中搜索匹配的標(biāo)簽泉瞻。這種情況下的地址可以是虛擬地址或物理地址,根據(jù)緩存的實(shí)現(xiàn)而定苞冯。

由于除了實(shí)際內(nèi)存之外袖牙,標(biāo)簽還需要空間,因此選擇一個(gè)字word作為緩存的粒度效率是不高的舅锄。對(duì)于x86機(jī)器上的32位字贼陶,標(biāo)簽本身可能需要32位或更多位。此外巧娱,由于空間局限性是cache所基于的原則之一碉怔,因此不考慮這一點(diǎn)是不好的。由于相鄰內(nèi)存可能一起使用禁添,因此它應(yīng)該一起加載到緩存中撮胧。請(qǐng)記住我們?cè)诘?.2.1節(jié)中學(xué)到的東西:如果RAM模塊可以在沒有新CAS或甚至RAS的情況下連續(xù)傳輸多個(gè)數(shù)據(jù)字,信號(hào)老翘。所以存儲(chǔ)在緩存中的條目不是單個(gè)單詞芹啥,而是幾個(gè)連續(xù)單詞的“行”。在早期的高速緩存中铺峭,這些行長(zhǎng)度為32個(gè)字節(jié); 現(xiàn)在標(biāo)準(zhǔn)是64字節(jié)墓怀。如果內(nèi)存總線是64位寬,這意味著每個(gè)緩存行8個(gè)傳輸卫键。DDR有效地支持這種傳輸模式傀履。

當(dāng)處理器需要內(nèi)存內(nèi)容時(shí),整個(gè)緩存行將被加載到L1d中莉炉。通過根據(jù)高速緩存行大小屏蔽地址值來(lái)計(jì)算每個(gè)高速緩存行的存儲(chǔ)器地址钓账。對(duì)于64字節(jié)的高速緩存行,這意味著低6位被清零絮宁。丟棄的位用作緩存行的偏移量梆暮。其余的位在某些情況下用于定位緩存中的行和作為標(biāo)記。實(shí)際中地址值分為三部分绍昂。對(duì)于32位地址啦粹,它可能如下所示:

高速緩存行大小為2 O時(shí) 偿荷,低位O位用作高速緩存行的偏移量。接下來(lái)的S位選擇“緩存集”唠椭。我們將很快詳細(xì)討論為什么集合遭顶,而不是單個(gè)插槽,用于緩存行±崮瑁現(xiàn)在理解有2 S組緩存行就足夠了。這留下了形成標(biāo)簽的最高32- S - O = T位喘批。這些T位是與每個(gè)高速緩存行相關(guān)的值撩荣,以區(qū)分所有 別名 { 具有相同S地址部分的所有高速緩存行都由相同的別名知道。}它們被緩存在同一個(gè)緩存集合中饶深。用于尋址緩存集的S位不必被存儲(chǔ)餐曹,因?yàn)樗鼈儗?duì)于同一組中的所有緩存行是相同的。

當(dāng)指令修改內(nèi)存時(shí)敌厘,處理器仍然必須首先加載高速緩存行台猴,因?yàn)闆]有指令立即修改整個(gè)高速緩存行(規(guī)則的例外:6.1節(jié)所述的寫入組合)。寫入操作之前的高速緩存線的內(nèi)容因此必須被加載俱两。高速緩存不可能容納部分高速緩存行饱狂。被寫入并且沒有被寫回到主存儲(chǔ)器的高速緩存行被認(rèn)為是“臟的”。一旦寫入宪彩,臟標(biāo)志被清除休讳。

為了能夠在緩存中加載新數(shù)據(jù),幾乎總是首先需要在緩存中騰出空間尿孔。從L1d逐出將緩存行向下推入L2(使用相同的緩存行大锌∪帷)。這當(dāng)然意味著必須在L2中創(chuàng)建空間活合。這反過來(lái)可能會(huì)將內(nèi)容推入L3并最終進(jìn)入主內(nèi)存雏婶。每次驅(qū)逐越來(lái)越昂貴。這里描述的是現(xiàn)代AMD和威盛處理器所偏好的獨(dú)占高速緩存模型 白指。英特爾實(shí)現(xiàn)了包含性緩存 { 這種推廣并不完全正確留晚。少數(shù)緩存是獨(dú)占的,一些包容性緩存具有獨(dú)占緩存屬性告嘲。} L1d中的每個(gè)緩存行也存在于L2中倔丈。因此從L1d驅(qū)逐要快得多。有了足夠的二級(jí)緩存状蜗,浪費(fèi)內(nèi)存在兩個(gè)地方的內(nèi)容的缺點(diǎn)是微乎其微的需五,并且在驅(qū)逐時(shí)可以帶來(lái)回報(bào)。獨(dú)占緩存的一個(gè)可能的優(yōu)點(diǎn)是加載新的緩存行只需要觸及L1d而不是L2轧坎,這可能會(huì)更快宏邮。

只要為處理器體系結(jié)構(gòu)定義的內(nèi)存模型沒有改變,CPU就可以隨心所欲地管理這些緩存。例如蜜氨,處理器利用很少或沒有內(nèi)存總線活動(dòng)并主動(dòng)將臟高速緩存行寫回主內(nèi)存是完全正常的械筛。x86和x86-64處理器之間,制造商之間甚至同一制造商型號(hào)之間的各種高速緩存體系結(jié)構(gòu)都證明了內(nèi)存模型抽象的力量飒炎。

在對(duì)稱多處理器(SMP)系統(tǒng)中埋哟,CPU的高速緩存不能獨(dú)立工作。所有處理器應(yīng)該始終都能看到相同的內(nèi)存內(nèi)容郎汪。這種統(tǒng)一的內(nèi)存視圖的維護(hù)稱為“緩存一致性”赤赊。如果一個(gè)處理器只是簡(jiǎn)單地看自己的緩存和主存,它就不會(huì)在其他處理器中看到臟緩存線的內(nèi)容煞赢。提供從另一個(gè)處理器直接訪問一個(gè)處理器的緩存將是非常昂貴和巨大的瓶頸抛计。相反,處理器會(huì)檢測(cè)另一個(gè)處理器何時(shí)想要讀取或?qū)懭肽硞€(gè)緩存行照筑。

如果檢測(cè)到寫入訪問并且處理器在其高速緩存中具有干凈的高速緩存行副本吹截,則此高速緩存行標(biāo)記為無(wú)效。未來(lái)的引用將需要重新加載緩存行凝危。請(qǐng)注意波俄,在另一個(gè)CPU上的讀取訪問不需要失效,可以很好地保留多個(gè)干凈的副本蛾默。

更復(fù)雜的緩存實(shí)現(xiàn)允許發(fā)生另一種可能性弟断。如果另一個(gè)處理器想要讀取或?qū)懭氲母咚倬彺嫘挟?dāng)前在第一個(gè)處理器的高速緩存中被標(biāo)記為臟,則需要采取不同的行動(dòng)趴生。在這種情況下阀趴,主存儲(chǔ)器已過期,而發(fā)出請(qǐng)求的處理器必須從第一個(gè)處理器獲取高速緩存行內(nèi)容苍匆。通過偵聽刘急,第一個(gè)處理器注意到這種情況,并自動(dòng)向請(qǐng)求處理器發(fā)送數(shù)據(jù)浸踩。此操作繞過主內(nèi)存叔汁,但在某些實(shí)現(xiàn)中,內(nèi)存控制器應(yīng)該注意到此直接傳輸并將更新的高速緩存行內(nèi)容存儲(chǔ)在主內(nèi)存中检碗。如果訪問用于寫入第一個(gè)處理器据块,則使其本地緩存行的副本無(wú)效。

隨著時(shí)間的推移折剃,許多高速緩存一致性協(xié)議已經(jīng)被開發(fā)出來(lái)另假。最重要的是MESI,我們將在3.3.4節(jié)中介紹怕犁。所有這些的結(jié)果可以總結(jié)為幾個(gè)簡(jiǎn)單的規(guī)則:

  • ?

  • 臟緩存線不存在于任何其他處理器的緩存中铸豁。

    ?

  • 清理同一緩存行的副本可以駐留在任意多個(gè)緩存中。

    ?

如果可以維護(hù)這些規(guī)則齿椅,那么即使在多處理器系統(tǒng)中,處理器也可以高效地使用它們的緩存凌受。所有處理器需要做的是監(jiān)視彼此的寫入訪問并將地址與本地緩存中的地址進(jìn)行比較。在下一節(jié)中思杯,我們將詳細(xì)介紹實(shí)施情況胜蛉,特別是成本。

最后色乾,我們至少應(yīng)該給出與緩存命中和未命中相關(guān)的成本的印象誊册。這些是英特爾為Pentium M列出的數(shù)字:

去哪里 周期
寄存器 <= 1
L1D ?3
L2 ?14
主內(nèi)存 ?240

這些是以CPU周期測(cè)量的實(shí)際訪問時(shí)間。值得注意的是杈湾,對(duì)于片上二級(jí)緩存,很大一部分(可能甚至是大部分)訪問時(shí)間是由延遲導(dǎo)致的攘须。這是一個(gè)物理限制漆撞,只能隨著緩存大小的增加而變得更糟。只有進(jìn)程縮杏谥妗(例如浮驳,從Merom 60納米到英特爾陣容中Penryn的45納米)才能改善這些數(shù)字。

表格中的數(shù)字看起來(lái)很高捞魁,但幸運(yùn)的是至会,每次發(fā)生緩存加載和丟失都不需要支付全部成本。成本的某些部分可以隱藏起來(lái)谱俭。當(dāng)今的處理器都使用不同長(zhǎng)度的內(nèi)部管線奉件,其中指令被解碼并準(zhǔn)備執(zhí)行。準(zhǔn)備工作的一部分是從內(nèi)存(或緩存)加載值昆著,如果它們被傳輸?shù)郊拇嫫鞯脑捪孛病H绻麅?nèi)存加載操作可以在管道中足夠早地啟動(dòng),則可能會(huì)與其他操作并行發(fā)生凑懂,并且負(fù)載的全部成本可能會(huì)被隱藏煤痕。L1d通常是可能的; 對(duì)于一些L2流水線長(zhǎng)的處理器也是如此。

盡早開始內(nèi)存讀取有許多障礙接谨。這可能很簡(jiǎn)單摆碉,因?yàn)闆]有足夠的資源來(lái)訪問內(nèi)存,或者可能由于另一條指令導(dǎo)致負(fù)載的最終地址變得遲了脓豪。在這些情況下巷帝,裝載成本無(wú)法完全隱藏。

對(duì)于寫入操作扫夜,CPU不一定要等到該值安全地存儲(chǔ)在內(nèi)存中锅睛。只要以下指令的執(zhí)行看起來(lái)與將值存儲(chǔ)在內(nèi)存中的效果相同埠巨,就沒有任何操作可以阻止CPU采取快捷方式。它可以盡早開始執(zhí)行下一條指令现拒。在影子寄存器的幫助下辣垒,這些寄存器可以保存常規(guī)寄存器中不再可用的值,甚至可以更改要存儲(chǔ)在不完整寫入操作中的值印蔬。

圖3.4:隨機(jī)寫入的訪問時(shí)間

有關(guān)緩存行為的影響的示例勋桶,請(qǐng)參見圖3.4。我們將討論后來(lái)生成數(shù)據(jù)的程序; 它是以隨機(jī)方式重復(fù)訪問可配置數(shù)量?jī)?nèi)存的程序的簡(jiǎn)單模擬侥猬。每個(gè)數(shù)據(jù)項(xiàng)具有固定大小例驹。元素的數(shù)量取決于所選的工作集大小。Y軸顯示處理一個(gè)元素所需的平均CPU周期數(shù); 注意Y軸的刻度是對(duì)數(shù)的退唠。這種情況在所有這類圖表中都適用于X軸鹃锈。工作集的大小始終以2的冪次顯示。

該圖顯示了三個(gè)不同的高原瞧预。這并不奇怪:特定處理器具有L1d和L2高速緩存屎债,但沒有L3。根據(jù)一些經(jīng)驗(yàn)垢油,我們可以推斷L1d的大小為2 13字節(jié)盆驹,而L2的大小為2 20字節(jié)。如果整個(gè)工作集適合L1d滩愁,則每個(gè)元素的每個(gè)操作的周期數(shù)低于10.一旦超過L1d大小躯喇,處理器必須從L2載入數(shù)據(jù),并且平均時(shí)間會(huì)跳到約28個(gè)硝枉。一旦L2不足時(shí)間再次超過480個(gè)周期和更多廉丽。這是當(dāng)許多或大多數(shù)操作必須從主存儲(chǔ)器加載數(shù)據(jù)時(shí)。更糟糕的是:由于數(shù)據(jù)正在被修改妻味,臟緩存行也必須被寫回雅倒。

此圖應(yīng)該提供足夠的動(dòng)機(jī)來(lái)研究有助于改進(jìn)緩存使用情況的編碼改進(jìn)。我們?cè)谶@里并不是在談?wù)搸讉€(gè)可憐的百分比弧可。我們正在討論有時(shí)可能的數(shù)量級(jí)的改進(jìn)蔑匣。在第6節(jié)中,我們將討論允許編寫更高效代碼的技術(shù)棕诵。下一節(jié)將介紹CPU緩存設(shè)計(jì)的更多細(xì)節(jié)裁良。本文其余部分的知識(shí)是有益的,但不是必需的校套。所以這部分可以跳過价脾。

3.3 CPU緩存實(shí)施細(xì)節(jié)

緩存實(shí)現(xiàn)者有一個(gè)問題,即巨大的主存中的每個(gè)單元都可能被緩存笛匙。如果一個(gè)程序的工作集足夠大侨把,這意味著有很多主要的內(nèi)存位置為緩存中的每個(gè)地方而戰(zhàn)犀变。以前有人指出,高速緩存與主內(nèi)存大小之比為1比1000并不少見秋柄。

3.3.1關(guān)聯(lián)性

有可能實(shí)現(xiàn)一個(gè)緩存获枝,其中每個(gè)緩存行可以保存任何內(nèi)存位置的副本。這被稱為全關(guān)聯(lián)緩存骇笔。要訪問緩存行省店,處理器內(nèi)核必須將每個(gè)緩存行的標(biāo)簽與請(qǐng)求地址的標(biāo)簽進(jìn)行比較。標(biāo)簽將包含地址的整個(gè)部分笨触,而不是緩存行的偏移量(也就是說懦傍, 3.2節(jié)的圖中的S為零)。

有像這樣實(shí)現(xiàn)的緩存芦劣,但通過查看當(dāng)前使用的L2的數(shù)字粗俱,將顯示這是不切實(shí)際的。給定具有64B緩存行的4MB緩存虚吟,緩存將具有65536個(gè)條目寸认。為了獲得足夠的性能,緩存邏輯必須能夠在幾個(gè)周期內(nèi)從所有這些條目中選擇與給定標(biāo)簽匹配的條目稍味。實(shí)施這個(gè)的努力將是巨大的废麻。

圖3.5:完全關(guān)聯(lián)緩存原理圖

對(duì)于每個(gè)高速緩存行荠卷,需要一個(gè)比較器來(lái)比較大標(biāo)記(注意模庐,S為零)。每個(gè)連接旁邊的字母以位為單位指示寬度油宜。如果沒有給出它是一個(gè)單一的位線掂碱。每個(gè)比較器必須比較兩個(gè)T位寬的值。然后慎冤,根據(jù)結(jié)果疼燥,選擇適當(dāng)?shù)木彺嫘袃?nèi)容并使其可用。這需要合并盡可能多的 O組數(shù)據(jù)線蚁堤,因?yàn)橛芯彺嫱白碚摺?shí)現(xiàn)單個(gè)比較器所需的晶體管數(shù)量很大,尤其是因?yàn)樗仨毠ぷ鞯梅浅披诗?烨思础]有迭代比較器可用。減少比較數(shù)量的唯一方法是通過迭代比較標(biāo)簽來(lái)減少它們的數(shù)量呈队。這不適用于迭代比較器不同的原因:它需要太長(zhǎng)時(shí)間剥槐。

完全關(guān)聯(lián)的緩存對(duì)于小型緩存很實(shí)用(例如,某些英特爾處理器上的TLB緩存是完全關(guān)聯(lián)的)宪摧,但這些緩存很小粒竖,非常小颅崩。我們最多在談?wù)搸资畟€(gè)條目。

對(duì)于L1i蕊苗,L1d和更高級(jí)別的緩存沿后,需要采用不同的方法∷昵福可以做的是限制搜索得运。在最極端的限制中,每個(gè)標(biāo)簽只映射到一個(gè)緩存條目锅移。計(jì)算很簡(jiǎn)單:考慮到具有65,536個(gè)條目的4MB / 64B高速緩存熔掺,我們可以通過使用地址(16位)的位6至21直接對(duì)每個(gè)條目進(jìn)行尋址。低6位是進(jìn)入緩存行的索引非剃。

圖3.6:直接映射緩存原理圖

這種直接映射的緩存如圖3.6所示置逻,實(shí)施起來(lái)速度快且相對(duì)容易。它只需要一個(gè)比較器备绽,一個(gè)多路復(fù)用器(在這個(gè)圖中兩個(gè)標(biāo)簽和數(shù)據(jù)是分開的券坞,但這對(duì)設(shè)計(jì)來(lái)說不是一個(gè)硬性要求),還有一些邏輯只選擇有效的緩存行內(nèi)容肺素。由于速度要求恨锚,比較器很復(fù)雜,但現(xiàn)在只有其中一個(gè); 因此可以花費(fèi)更多的精力來(lái)加快速度倍靡。這種方法的真正復(fù)雜性在于復(fù)用器猴伶。簡(jiǎn)單多路復(fù)用器中的晶體管數(shù)量隨O(log N)增加,其中N是緩存線的數(shù)量塌西。這是可以忍受的他挎,但可能會(huì)變慢,在這種情況下捡需,速度可以通過在多路復(fù)用器中的晶體管上花費(fèi)更多的空間來(lái)并行化一些工作并提高速度來(lái)增加办桨。隨著緩存容量的增加,晶體管的總數(shù)量可能會(huì)增長(zhǎng)緩慢站辉,這使得該解決方案非常吸引人呢撞。但是它有一個(gè)缺點(diǎn):只有當(dāng)程序使用的地址相對(duì)于用于直接映射的位均勻分布時(shí),它才能很好地工作饰剥。如果它們不是殊霞,并且通常是這種情況,則一些高速緩存條目被大量使用捐川,并因此被反復(fù)驅(qū)逐脓鹃,而其他條目幾乎不被使用或保持空著。

圖3.7:組關(guān)聯(lián)緩存原理圖

這個(gè)問題可以通過使緩存集關(guān)聯(lián)來(lái)解決古沥。集合關(guān)聯(lián)緩存結(jié)合了完整關(guān)聯(lián)緩存和直接映射緩存的特性瘸右,在很大程度上避免了這些設(shè)計(jì)的弱點(diǎn)娇跟。圖3.7顯示了一個(gè)關(guān)聯(lián)緩存的設(shè)計(jì)。標(biāo)簽和數(shù)據(jù)存儲(chǔ)被分成由地址選擇的組太颤。這與直接映射緩存類似苞俘。但是,對(duì)于緩存中的每個(gè)設(shè)置值只有一個(gè)元素龄章,而對(duì)于相同的設(shè)置值吃谣,緩存少量值。并行比較所有集合成員的標(biāo)簽做裙,這與全關(guān)聯(lián)緩存的功能類似岗憋。

結(jié)果是一個(gè)緩存不容易被不幸的或故意選擇的具有相同設(shè)置數(shù)的地址所破壞,同時(shí)緩存的大小不受可并行實(shí)現(xiàn)的比較器的數(shù)量的限制锚贱。如果緩存增長(zhǎng)仔戈,則(在該圖中)只有增加的列數(shù),而不是行數(shù)拧廊。只有緩存的關(guān)聯(lián)性增加時(shí)监徘,行數(shù)才會(huì)增加。今天吧碾,處理器對(duì)L2高速緩存或更高級(jí)別使用高達(dá)16的關(guān)聯(lián)級(jí)別凰盔。L1緩存通常與8。

Table 3.1: Effects of Cache Size, Associativity, and Line Size

考慮到我們的4MB / 64B高速緩存和8路集合相關(guān)性倦春,我們剩下的高速緩存擁有8,192個(gè)集合户敬,并且只有13個(gè)標(biāo)記位用于處理高速緩存集。為了確定高速緩存集合中的哪些(如果有的話)條目包含被尋址的高速緩存行8標(biāo)簽必須被比較溅漾。這在很短的時(shí)間內(nèi)是可行的山叮。通過實(shí)驗(yàn)我們可以看出這是有道理的著榴。

表3.1顯示了一個(gè)程序的二級(jí)高速緩存未命中的數(shù)量(根據(jù)Linux內(nèi)核人員的情況添履,在這種情況下,它們是最重要的基準(zhǔn))脑又,用于更改高速緩存大小暮胧,高速緩存行大小和關(guān)聯(lián)集大小。在第7.2節(jié)中问麸,我們將介紹用于模擬測(cè)試所需的緩存的工具往衷。

以防萬(wàn)一這還不明顯,所有這些值的關(guān)系是緩存大小

緩存行大小×關(guān)聯(lián)度×集數(shù)

地址通過使用映射到緩存

O = log 2緩存行大小
S = log 2組數(shù)

如3.2節(jié)所示严卖。

圖3.8:緩存大小vs關(guān)聯(lián)性(CL = 32)

圖3.8使得表格的數(shù)據(jù)更易于理解席舍。它顯示了32字節(jié)的固定高速緩存行大小的數(shù)據(jù)。通過查看給定緩存大小的數(shù)字哮笆,我們可以看到来颤,關(guān)聯(lián)確實(shí)可以幫助顯著減少緩存未命中的次數(shù)汰扭。對(duì)于從直接映射到雙向聯(lián)合緩存的8MB緩存,幾乎可以節(jié)省44%的緩存未命中福铅。與直接映射緩存相比萝毛,處理器可以使用組關(guān)聯(lián)緩存保留緩存中的更多工作集。

在文獻(xiàn)中偶爾可以看到滑黔,引入關(guān)聯(lián)性與緩存大小加倍相同笆包。在一些極端情況下,從4MB到8MB緩存的跳轉(zhuǎn)可以看出這一點(diǎn)略荡。但是庵佣,進(jìn)一步加倍聯(lián)合性肯定不是事實(shí)。正如我們?cè)跀?shù)據(jù)中看到的那樣汛兜,連續(xù)的收益要小得多秧了。不過,我們不應(yīng)該完全打折序无。在示例程序中验毡,峰值內(nèi)存使用量為5.6M。因此帝嗡,對(duì)于8MB緩存晶通,對(duì)于相同的緩存集不太可能有多個(gè)(多于兩個(gè))使用。使用更大的工作集時(shí)哟玷,節(jié)省可能會(huì)更高狮辽,因?yàn)槲覀兛梢詮母〉木彺娲笮〉年P(guān)聯(lián)性的更大好處中看出。

一般來(lái)說巢寡,增加8以上緩存的關(guān)聯(lián)性似乎對(duì)單線程工作負(fù)載影響不大喉脖。隨著采用共享L2的多核處理器的推出,情況發(fā)生了變化∫衷拢現(xiàn)在你基本上有兩個(gè)程序打在同一個(gè)緩存上树叽,導(dǎo)致實(shí)際中的關(guān)聯(lián)性減半(或四分之一核心處理器)。所以可以預(yù)料谦絮,隨著內(nèi)核數(shù)量的增加题诵,共享緩存的關(guān)聯(lián)性會(huì)增加。一旦這種情況不再可能(16路集相關(guān)性已經(jīng)很難了)层皱,處理器設(shè)計(jì)人員必須開始使用共享的L3緩存性锭,而L2緩存可能會(huì)被一部分內(nèi)核共享。

我們可以在圖3.8中研究的另一個(gè)影響是緩存大小的增加如何幫助提高性能叫胖。如果不知道工作集的大小草冈,則無(wú)法解釋這些數(shù)據(jù)。顯然,與主內(nèi)存一樣大的緩存會(huì)導(dǎo)致比較小的緩存更好的結(jié)果怎棱,所以通常對(duì)最大緩存大小沒有限制方淤,并具有可測(cè)量的益處。

正如上面已經(jīng)提到的那樣蹄殃,工作集的峰值大小是5.6M携茂。這不會(huì)給我們?nèi)魏谓^對(duì)數(shù)量的最大有益緩存大小,但它允許我們估計(jì)數(shù)量诅岩。問題是讳苦,并非所有使用的內(nèi)存都是連續(xù)的,因此吩谦,即使使用16M緩存和5.6M工作集鸳谜,也會(huì)產(chǎn)生沖突(請(qǐng)參閱雙向組關(guān)聯(lián)16MB緩存相對(duì)于直接映射版本的優(yōu)勢(shì)) 。但是可以肯定的是式廷,在相同的工作負(fù)載下咐扭,32MB緩存的好處可以忽略不計(jì)。但誰(shuí)說工作集必須保持不變滑废?隨著時(shí)間的推移蝗肪,工作量在不斷增加,緩存大小也應(yīng)該增加蠕趁。購(gòu)買機(jī)器時(shí)薛闪,必須選擇愿意支付的緩存大小连躏,因此測(cè)量工作集大小是值得的养篓。為什么這很重要可以在圖3.10的數(shù)字中看到誊爹。

圖3.9:測(cè)試內(nèi)存布局

運(yùn)行兩種類型的測(cè)試枉长。在第一次測(cè)試中,元素按順序處理杆查。測(cè)試程序遵循指針n也殖, 但數(shù)組元素被鏈接在一起既绕,以便它們按照在內(nèi)存中找到的順序遍歷缴挖。這可以在圖3.9的下半部分看到袋狞。有一個(gè)來(lái)自最后一個(gè)元素的引用。在第二個(gè)測(cè)試中(圖的上半部分)醇疼,數(shù)組元素以隨機(jī)順序遍歷硕并。在這兩種情況下法焰,數(shù)組元素形成一個(gè)循環(huán)的單鏈表秧荆。

3.3.2緩存效果的度量

所有數(shù)字都是通過測(cè)量一個(gè)程序來(lái)創(chuàng)建的,該程序可以模擬任意大小的工作集埃仪,讀取和寫入訪問以及順序或隨機(jī)訪問乙濒。我們已經(jīng)在圖3.4中看到了一些結(jié)果。該程序?qū)?chuàng)建一個(gè)與此類型元素的工作集大小相對(duì)應(yīng)的數(shù)組:

  struct l {
    struct l * n;
    長(zhǎng)整形墊[NPAD];
  };

所有條目都使用n元素鏈接在循環(huán)列表中,無(wú)論順序還是隨機(jī)順序颁股。從一個(gè)入口前進(jìn)到下一個(gè)入口始終使用指針么库,即使這些元素是按順序排列的。該元素是有效載荷甘有,它可以盡量增大诉儒。在一些測(cè)試中,數(shù)據(jù)被修改亏掀,而在其他測(cè)試中忱反,程序僅執(zhí)行讀取操作。

在性能測(cè)量中滤愕,我們正在討論工作集大小温算。工作集由一組struct l 元素組成。一個(gè)2 N字節(jié)的工作集包含

2 N / sizeof(struct l)

元素间影。顯然sizeof(struct l)取決于NPAD的值 注竿。對(duì)于32位系統(tǒng),NPAD = 7表示每個(gè)數(shù)組元素的大小為32個(gè)字節(jié)魂贬,對(duì)于64位系統(tǒng)巩割,大小為64個(gè)字節(jié)。

單線程順序訪問

最簡(jiǎn)單的情況是簡(jiǎn)單地遍歷列表中的所有條目付燥。列表元素按順序排列喂分,密集排列。無(wú)論處理順序是向前還是向后都無(wú)所謂机蔗,處理器可以很好地處理兩個(gè)方向蒲祈。我們?cè)谶@里測(cè)量的以及在所有以下測(cè)試中測(cè)量的是處理單個(gè)列表元素需要多長(zhǎng)時(shí)間。時(shí)間單位是一個(gè)處理器周期萝嘁。結(jié)果如圖3.10所示梆掸。除非另有說明,所有測(cè)量均在64位模式下牙言,這意味著結(jié)構(gòu)的奔騰4的機(jī)器上制成NPAD = 0是在大小的8個(gè)字節(jié)酸钦。

圖3.10:順序讀取訪問,NPAD = 0
圖3.11:幾種尺寸的順序讀取

前兩個(gè)測(cè)量值受噪聲污染咱枉。測(cè)量的工作量太小卑硫,無(wú)法過濾系統(tǒng)其余部分的影響。我們可以安全地假設(shè)這些值都處于4個(gè)周期的水平蚕断』斗考慮到這一點(diǎn),我們可以看到三個(gè)不同的層次:

  • ?

  • 最大工作集大小為2

    14

    字節(jié)亿乳。

    ?

  • 從2

    15

    字節(jié)到2

    20

    字節(jié)硝拧。

    ?

  • 從2

    21

    個(gè)字節(jié)起径筏。

    ?

這些步驟可以很容易地解釋:處理器具有16kB L1d和1MB L2。我們沒有看到從一個(gè)級(jí)別轉(zhuǎn)換到另一個(gè)級(jí)別的尖銳邊緣障陶,因?yàn)榫彺嬉脖幌到y(tǒng)的其他部分使用滋恬,因此緩存并非專門用于程序數(shù)據(jù)。具體來(lái)說抱究,二級(jí)緩存是一個(gè)統(tǒng)一的緩存恢氯,也用于說明(注意:英特爾使用包含緩存)。

可能不是所期望的是不同工作集規(guī)模的實(shí)際時(shí)間鼓寺。預(yù)計(jì)L1d命中次數(shù):P4命中L1d命中后的負(fù)載時(shí)間大約為4個(gè)周期酿雪。但是L2訪問呢?一旦L1d不足以保存數(shù)據(jù)侄刽,人們可能認(rèn)為每個(gè)元素需要14個(gè)周期或更多指黎,因?yàn)檫@是L2的訪問時(shí)間。但結(jié)果顯示只需要約9個(gè)周期州丹。這種差異可以通過處理器中的高級(jí)邏輯來(lái)解釋醋安。為了使用連續(xù)的存儲(chǔ)區(qū)域,處理器預(yù)取下一個(gè)緩存行墓毒。這意味著當(dāng)下一行被實(shí)際使用時(shí)吓揪,它已經(jīng)中途加載了。因此所计,等待下一個(gè)緩存行被加載所需的延遲遠(yuǎn)小于L2存取時(shí)間柠辞。

一旦工作集大小超過L2大小,預(yù)取的效果就更加明顯主胧。在我們說主存儲(chǔ)器訪問需要200+個(gè)周期之前叭首。只有有效的預(yù)取,處理器才有可能將訪問時(shí)間保持在9個(gè)周期的低位踪栋。正如我們從200和9之間的差異所看到的焙格,這很好地解決了問題。

我們可以在預(yù)取的同時(shí)觀察處理器夷都,至少是間接的眷唉。在圖3.11中,我們看到了相同工作集大小的時(shí)間囤官,但是這次我們看到了不同大小結(jié)構(gòu) l的圖冬阳。這意味著我們?cè)诹斜碇杏懈俚蟮脑亍2煌拇笮?huì)導(dǎo)致(仍然連續(xù))列表中n個(gè)元素之間的距離增大党饮。在圖的四種情況下肝陪,距離分別為0,56,120和248字節(jié)。

在底部劫谅,我們可以看到上一個(gè)圖形中的一行见坑,但這次它或多或少顯示為一條扁平線嚷掠。其他案件的時(shí)間則更加糟糕捏检。我們也可以在該圖中看到三個(gè)不同的級(jí)別荞驴,并且我們發(fā)現(xiàn)測(cè)試中的工作集規(guī)模較小時(shí)會(huì)出現(xiàn)大的錯(cuò)誤(再次忽略它們)。只要涉及到L1d贯城,線條或多或少都相互匹配熊楼。沒有必要預(yù)取,因此所有元素大小都會(huì)在每次訪問時(shí)觸及L1d能犯。

對(duì)于L2緩存命中鲫骗,我們看到三條新線都非常匹配,但它們處于更高的級(jí)別(約28)踩晶。這是L2的訪問時(shí)間級(jí)別执泰。這意味著從L2預(yù)取到L1d基本上是禁用的。即使NPAD = 7渡蜻,我們也需要為循環(huán)的每次迭代創(chuàng)建一個(gè)新的緩存行; 對(duì)于 NPAD = 0术吝,相反,在需要下一個(gè)高速緩存行之前茸苇,循環(huán)必須迭代八次排苍。預(yù)取邏輯無(wú)法在每個(gè)周期加載新的高速緩存行。因此学密,我們?cè)诿看蔚卸紩?huì)看到一個(gè)從L2加載的失速淘衙。

一旦工作集大小超過L2容量,它會(huì)變得更有趣∧迥海現(xiàn)在所有四條線路差別很大彤守。不同的元素尺寸在性能差異中扮演著重要的角色。處理器應(yīng)該識(shí)別步幅的大小哭靖,而不是為NPAD獲取不必要的緩存行``= 15和31遗增,因?yàn)樵卮笮⌒∮陬A(yù)取窗口(見6.3.1節(jié))。在元素大小妨礙預(yù)取努力的地方是硬件預(yù)取限制的結(jié)果:它不能跨越頁(yè)面邊界款青。每增加一個(gè)尺寸做修,我們都會(huì)將硬件調(diào)度程序的有效性降低50%。如果允許硬件預(yù)取器跨越頁(yè)面邊界并且下一頁(yè)不是駐留或有效的抡草,則操作系統(tǒng)將不得不參與查找頁(yè)面饰及。這意味著該程序會(huì)遇到一個(gè)它自己沒有啟動(dòng)的頁(yè)面錯(cuò)誤。這是完全不可接受的康震,因?yàn)樘幚砥鞑恢理?yè)面是不存在還是不存在燎含。在后一種情況下,操作系統(tǒng)將不得不中止該過程腿短。無(wú)論如何屏箍,對(duì)于NPAD來(lái)說= 7和更高绘梦,我們需要每個(gè)列表元素的一個(gè)緩存行,硬件預(yù)取器不能做太多赴魁。根本沒有時(shí)間從內(nèi)存加載數(shù)據(jù)卸奉,因?yàn)樗械奶幚砥鞫际亲x一個(gè)字,然后加載下一個(gè)元素颖御。

經(jīng)濟(jì)放緩的另一個(gè)重要原因是TLB緩存未命中榄棵。這是一個(gè)緩存,其中存儲(chǔ)了將虛擬地址轉(zhuǎn)換為物理地址的結(jié)果潘拱,如第4節(jié)中詳細(xì)介紹的那樣.TLB緩存非常小疹鳄,因?yàn)樗仨毞浅?焖俾瘛H绻磸?fù)訪問更多的頁(yè)面比TLB緩存具有從虛擬地址到物理地址的翻譯必須不斷重復(fù)的條目瘪弓。這是一個(gè)非常昂貴的操作。對(duì)于更大的元素大小禽最,TLB查找的成本會(huì)在更少的元素上分?jǐn)傁偾印_@意味著每個(gè)列表元素必須計(jì)算的TLB條目總數(shù)更高。

要觀察TLB效應(yīng)弛随,我們可以運(yùn)行不同的測(cè)試瓢喉。對(duì)于一次測(cè)量,我們按照慣例順序排列元素舀透。對(duì)于占用一個(gè)整個(gè)緩存行的元素栓票,我們使用 NPAD = 7。對(duì)于第二次測(cè)量愕够,我們將每個(gè)列表元素放置在單獨(dú)的頁(yè)面上走贪。每個(gè)頁(yè)面的其余部分保持不變,我們不會(huì)將其計(jì)入工作集大小的總數(shù)中惑芭。{ 是的坠狡,這有點(diǎn)不一致,因?yàn)樵谄渌麥y(cè)試中遂跟,我們?cè)谠卮笮≈杏?jì)算結(jié)構(gòu)中未使用的部分逃沿,我們可以定義NPAD以便每個(gè)元素填充一個(gè)頁(yè)面。在這種情況下幻锁,工作集的大小將會(huì)非常不同凯亮。不過這并不是測(cè)試的要點(diǎn),而且由于預(yù)取無(wú)效哄尔,所以這沒什么區(qū)別假消。}結(jié)果是,對(duì)于第一次測(cè)量岭接,每個(gè)列表迭代都需要一個(gè)新的緩存行富拗,并且對(duì)于每64個(gè)元素來(lái)說臼予,一個(gè)新頁(yè)面。對(duì)于第二次測(cè)量啃沪,每次迭代都需要加載新頁(yè)面上的新緩存行粘拾。

圖3.12:順序讀取的TLB影響

結(jié)果可以在圖3.12中看到。測(cè)量在與圖3.11相同的機(jī)器上進(jìn)行谅阿。由于可用RAM的限制半哟,工作集大小必須限制在2 24個(gè)字節(jié)酬滤,這需要1GB將對(duì)象放置在不同的頁(yè)面上签餐。較低的紅色曲線完全對(duì)應(yīng)于圖3.11中的 NPAD = 7曲線。我們看到顯示L1d和L2高速緩存大小的不同步驟盯串。第二條曲線看起來(lái)完全不同氯檐。重要的特征是當(dāng)工作集合大小達(dá)到2 13時(shí)開始的巨大峰值字節(jié)。這是TLB緩存溢出的時(shí)候体捏。使用64字節(jié)的元素大小冠摄,我們可以計(jì)算出TLB緩存有64個(gè)條目。沒有頁(yè)面錯(cuò)誤影響成本几缭,因?yàn)槌绦蜴i定內(nèi)存以防止它被換出河泳。

可以看出,計(jì)算物理地址并將其存儲(chǔ)在TLB中所需的周期數(shù)非常高年栓。圖3.12中的圖表顯示了極端情況拆挥,但現(xiàn)在應(yīng)該清楚,較大NPAD值減速的一個(gè)重要因素是TLB緩存的效率降低某抓。由于在L2或主存儲(chǔ)器的高速緩存行可以被讀取之前必須計(jì)算物理地址纸兔,因此地址轉(zhuǎn)換懲罰是存儲(chǔ)器訪問時(shí)間的附加條件。這部分解釋了為什么NPAD = 31的每個(gè)列表元素的總成本高于RAM的理論訪問時(shí)間否副。

圖3.13:順序讀寫汉矿,NPAD = 1

通過查看列表元素被修改的測(cè)試運(yùn)行數(shù)據(jù),我們可以看到預(yù)取實(shí)現(xiàn)的更多細(xì)節(jié)备禀。圖3.13顯示了三條線洲拇。元素寬度在所有情況下都是16個(gè)字節(jié)。第一行是現(xiàn)在熟悉的列表行曲尸,作為基線赋续。標(biāo)記為“Inc”的第二行只是在進(jìn)入下一行之前遞增當(dāng)前元素的pad [0]成員。第三行標(biāo)記為“Addnext0”队腐,取下一個(gè)元素的 pad [0]列表元素蚕捉,并將其添加到當(dāng)前列表元素的pad [0]成員中。``

天真的假設(shè)是“Addnext0”測(cè)試運(yùn)行速度較慢柴淘,因?yàn)樗懈嗟墓ぷ饕銎妊汀T谇斑M(jìn)到下一個(gè)列表元素之前秘通,必須加載該元素的值。這就是為什么看到這個(gè)測(cè)試實(shí)際運(yùn)行是令人驚訝的敛熬,對(duì)于某些工作集的規(guī)模來(lái)說肺稀,它比“Inc”測(cè)試更快。對(duì)此的解釋是來(lái)自下一個(gè)列表元素的加載基本上是強(qiáng)制預(yù)取应民。每當(dāng)程序前進(jìn)到下一個(gè)列表元素時(shí)话原,我們都知道該元素已經(jīng)在L1d緩存中。因此诲锹,只要工作集大小適合L2高速緩存繁仁,我們就會(huì)看到“Addnext0”以及簡(jiǎn)單的“Follow”測(cè)試。

不過归园,“Addnext0”測(cè)試的運(yùn)行速度比“Inc”測(cè)試快黄虱。它需要從主內(nèi)存加載更多的數(shù)據(jù)。這就是為什么“Addnext0”測(cè)試達(dá)到28個(gè)周期級(jí)別的工作集大小為2 21字節(jié)庸诱。28個(gè)周期的水平是“Follow”測(cè)試達(dá)到的14個(gè)周期水平的兩倍捻浦。這也很容易解釋。由于其他兩個(gè)測(cè)試修改內(nèi)存桥爽,L2緩存逐出為新緩存線騰出空間不能簡(jiǎn)單地丟棄數(shù)據(jù)朱灿。相反,它必須寫入記憶钠四。這意味著FSB上的可用帶寬減半盗扒,因此將數(shù)據(jù)從主存儲(chǔ)器傳輸?shù)絃2的時(shí)間加倍。

圖3.14:更大的L2 / L3高速緩存的優(yōu)勢(shì)

順序形导,高效的緩存處理的最后一個(gè)方面是緩存的大小环疼。這應(yīng)該是顯而易見的,但仍需要指出朵耕。圖3.14顯示了具有128字節(jié)元素的增量基準(zhǔn)測(cè)試(64位機(jī)器上的NPAD = 15)的時(shí)序炫隶。這次我們看到來(lái)自三臺(tái)不同機(jī)器的測(cè)量結(jié)果。前兩臺(tái)機(jī)器是P4阎曹,最后一臺(tái)是Core2處理器伪阶。前兩個(gè)通過具有不同的緩存大小來(lái)區(qū)分它們自己。第一款處理器有32k L1d和1M L2处嫌。第二個(gè)有16k L1d栅贴,512k L2和2M L3。Core2處理器具有32k L1d和4M L2熏迹。

圖中有趣的部分并不一定是Core2處理器相對(duì)于其他兩個(gè)處理器表現(xiàn)得如何(盡管它令人印象深刻)檐薯。這里感興趣的主要問題是工作集大小對(duì)于相應(yīng)的最后一級(jí)緩存來(lái)說太大并且主存儲(chǔ)器被大量占用的區(qū)域。

Table 3.2: L2 Hits and Misses for Sequential and Random Walks, NPAD=0

正如預(yù)期的那樣,最后一級(jí)緩存越大坛缕,曲線停留在對(duì)應(yīng)于L2訪問成本的低級(jí)別的時(shí)間越長(zhǎng)墓猎。需要注意的重要部分是它提供的性能優(yōu)勢(shì)。第二個(gè)處理器(稍微老一點(diǎn))可以在2個(gè)20字節(jié)的工作集上執(zhí)行兩倍于第一個(gè)處理器的工作赚楚。這要?dú)w功于增加的最后一級(jí)緩存大小毙沾。帶有4M L2的Core2處理器性能更好。

對(duì)于隨機(jī)工作量來(lái)說宠页,這可能并不意味著太多左胞。但是,如果工作負(fù)載可以根據(jù)最后一級(jí)緩存的大小進(jìn)行調(diào)整举户,那么程序性能可以顯著提高烤宙。這就是為什么有時(shí)值得花費(fèi)額外的錢用于具有更大緩存的處理器的原因。

單線程隨機(jī)訪問測(cè)量

我們已經(jīng)看到敛摘,通過預(yù)取高速緩存行到L2和L1d门烂,處理器能夠隱藏大部分主內(nèi)存乳愉,甚至可以隱藏L2訪問延遲兄淫。但是,只有當(dāng)內(nèi)存訪問是可預(yù)測(cè)的時(shí)蔓姚,這才能正常工作捕虽。

圖3.15:順序隨機(jī)讀取台诗,NPAD = 0

如果訪問是不可預(yù)知的或隨機(jī)的揽祥,情況就大不相同。圖3.15將順序訪問的每個(gè)列表元素時(shí)間(與圖3.10相同)與列表元素隨機(jī)分布在工作集中的時(shí)間進(jìn)行比較袜硫。該訂單由隨機(jī)化的鏈接列表確定备闲。處理器無(wú)法可靠地預(yù)取數(shù)據(jù)晌端。這只能在偶然使用的元素在內(nèi)存中彼此靠近的情況下偶然運(yùn)行。

圖3.15中有兩點(diǎn)需要注意恬砂。首先咧纠,大數(shù)量是增長(zhǎng)工作集規(guī)模所需的周期。該機(jī)器可以在200-300個(gè)周期內(nèi)訪問主存儲(chǔ)器泻骤,但在這里我們可以達(dá)到450個(gè)周期以上漆羔。我們之前已經(jīng)看到過這種現(xiàn)象(比較圖3.11)。自動(dòng)預(yù)取實(shí)際上在這里處于劣勢(shì)狱掂。

第二個(gè)有意思的地方在于演痒,曲線在各個(gè)平臺(tái)上并不平坦,正如順序訪問的情況一樣趋惨。曲線不斷上升鸟顺。為了解釋這一點(diǎn),我們可以測(cè)量程序?qū)Ω鞣N工作集大小的L2訪問權(quán)限器虾。結(jié)果可以在圖3.16和表3.2中看到讯嫂。

如圖所示养筒,當(dāng)工作集大小大于L2大小時(shí),高速緩存失敗率(L2未命中/ L2訪問)開始增長(zhǎng)端姚。曲線與圖3.15中的曲線具有相似的形式:曲線快速上升晕粪,稍微下降,然后又開始上升渐裸。與每個(gè)列表元素圖的周期有很強(qiáng)的相關(guān)性巫湘。二級(jí)失誤率將增長(zhǎng)直至最終接近100%。給定一個(gè)足夠大的工作集(和RAM)昏鹃,隨機(jī)選取的任何高速緩存行位于L2或正在加載的過程中的概率可以任意減少尚氛。

僅僅增加的緩存缺失率就解釋了一些成本。但還有另一個(gè)因素洞渤。查看表3.2阅嘶,我們可以在L2 /#Iter列中看到每次迭代程序的L2使用總數(shù)正在增長(zhǎng)。每個(gè)工作組的尺寸是之前的兩倍载迄。所以讯柔,如果沒有緩存,我們會(huì)期望主內(nèi)存訪問量增加一倍护昧。通過緩存和(幾乎)完美的可預(yù)測(cè)性魂迄,我們可以看到順序訪問數(shù)據(jù)中L2使用的適度增加。增加是由于工作集規(guī)模的增加惋耙,而沒有其他捣炬。

圖3.16:L2d錯(cuò)誤率
圖3.17:Page-Wise隨機(jī)化,NPAD = 7

對(duì)于隨機(jī)訪問绽榛,每個(gè)元素時(shí)間每增加一倍工作集大小就會(huì)增加100%以上湿酸。這意味著每個(gè)列表元素的平均訪問時(shí)間會(huì)增加,因?yàn)楣ぷ骷笮≈粫?huì)增加一倍灭美。這背后的原因是TLB失誤率上升推溃。在圖3.17中,我們看到NPAD隨機(jī)訪問的成本 ``= 7冲粤。只有這一次美莫,隨機(jī)化被修改。在正常情況下梯捕,隨機(jī)化的整個(gè)列表作為一個(gè)塊(由標(biāo)記∞指示)厢呵,其他11條曲線顯示以較小塊執(zhí)行的隨機(jī)化。對(duì)于標(biāo)記為'60'的曲線傀顾,每組60頁(yè)(245.760字節(jié))被單獨(dú)隨機(jī)化襟铭。這意味著塊中的所有列表元素都會(huì)在轉(zhuǎn)到下一個(gè)塊中的元素之前遍歷。這具有在任何一個(gè)時(shí)間使用的TLB條目的數(shù)量有限的效果。

NPAD = 7 的元素大小為64個(gè)字節(jié)寒砖,對(duì)應(yīng)于緩存行大小赐劣。由于列表元素的隨機(jī)順序,硬件預(yù)取器不太可能產(chǎn)生任何效果哩都,但絕不僅限于少數(shù)幾個(gè)元素魁兼。這意味著L2緩存缺失率與一個(gè)塊中整個(gè)列表的隨機(jī)化沒有顯著差異。隨著塊大小的增加漠嵌,測(cè)試的性能逐漸接近單塊隨機(jī)化的曲線咐汞。這意味著后一個(gè)測(cè)試用例的性能受到TLB失誤的顯著影響。如果TLB缺失可以降低儒鹿,則性能顯著提高(在一項(xiàng)測(cè)試中化撕,我們稍后會(huì)看到高達(dá)38%)。

3.3.3寫行為

在我們開始查看多個(gè)執(zhí)行上下文(線程或進(jìn)程)使用相同內(nèi)存時(shí)的緩存行為之前约炎,我們必須研究緩存實(shí)現(xiàn)的細(xì)節(jié)植阴。緩存應(yīng)該是連貫的,并且這個(gè)一致性對(duì)于用戶級(jí)代碼應(yīng)該是完全透明的圾浅。內(nèi)核代碼是一個(gè)不同的故事; 它偶爾需要緩存刷新掠手。

這特別意味著,如果緩存行被修改贱傀,則在此時(shí)間點(diǎn)之后系統(tǒng)的結(jié)果與根本沒有緩存并且主內(nèi)存位置本身已被修改的結(jié)果相同惨撇。這可以通過兩種方式或策略來(lái)實(shí)現(xiàn):

  • 直寫緩存實(shí)現(xiàn);
  • 寫回緩存實(shí)現(xiàn)。

直寫式高速緩存是實(shí)現(xiàn)高速緩存一致性的最簡(jiǎn)單方法府寒。如果高速緩存行被寫入,處理器立即也將高速緩存行寫入主存儲(chǔ)器报腔。這確保了在任何時(shí)候主存儲(chǔ)器和高速緩存都是同步的株搔。只要緩存行被替換,緩存內(nèi)容就可以被丟棄纯蛾。這個(gè)緩存策略很簡(jiǎn)單纤房,但不是很快。例如翻诉,一個(gè)程序會(huì)重復(fù)修改一個(gè)局部變量炮姨,即使這些數(shù)據(jù)可能沒有在其他地方使用,并且可能是短暫的碰煌,也會(huì)在FSB上產(chǎn)生大量流量舒岸。

回寫政策更復(fù)雜。這里處理器不會(huì)立即將修改后的緩存行寫回主內(nèi)存芦圾。相反蛾派,緩存線只會(huì)被標(biāo)記為臟。當(dāng)將來(lái)某個(gè)時(shí)刻從高速緩存中刪除高速緩存行時(shí),臟位將指示處理器在當(dāng)時(shí)寫回?cái)?shù)據(jù)洪乍,而不是僅放棄內(nèi)容眯杏。

寫回緩存有機(jī)會(huì)顯著提高性能,這就是為什么系統(tǒng)中具有體面處理器的大多數(shù)內(nèi)存以這種方式被緩存的原因壳澳。處理器甚至可以利用FSB上的空閑容量來(lái)存儲(chǔ)高速緩存行的內(nèi)容岂贩,然后該行必須撤離。這允許清除臟位巷波,并且當(dāng)需要緩存中的空間時(shí)河闰,處理器可以放棄緩存行。

但是回寫實(shí)現(xiàn)存在一個(gè)重大問題褥紫。如果有多個(gè)處理器(或核心或超線程)可用并訪問相同的內(nèi)存姜性,則必須確保兩個(gè)處理器始終都能看到相同的內(nèi)存內(nèi)容。如果一個(gè)處理器上的高速緩存線是臟的(即髓考,它還沒有被寫回)部念,而第二個(gè)處理器試圖讀取相同的存儲(chǔ)器位置,則讀取操作不能僅僅出到主存儲(chǔ)器氨菇。而是需要第一個(gè)處理器的緩存行的內(nèi)容儡炼。在下一節(jié)中,我們將看到這是如何實(shí)現(xiàn)的查蓉。

在我們開始之前乌询,還有兩個(gè)緩存策略需要提及:

  • 寫結(jié)合; 和
  • 不可緩存。

這兩個(gè)策略都用于地址空間中沒有真實(shí)RAM支持的特殊區(qū)域豌研。內(nèi)核為地址范圍設(shè)置這些策略(在使用內(nèi)存類型范圍寄存器MTRR的x86處理器上)妹田,其余部分自動(dòng)發(fā)生。MTRR也可用于選擇直寫式還是回寫式策略鹃共。

寫入組合是在諸如圖形卡等設(shè)備上更經(jīng)常用于RAM的有限緩存優(yōu)化鬼佣。由于設(shè)備的傳輸成本遠(yuǎn)高于本地RAM訪問,因此避免進(jìn)行太多傳輸更為重要霜浴。如果下一個(gè)操作修改下一個(gè)單詞晶衷,則僅僅因?yàn)樵撔兄械膯卧~已被寫入而傳輸整個(gè)高速緩存行是浪費(fèi)的。人們很容易想象這是一種常見現(xiàn)象阴孟,屏幕上水平相鄰像素的存儲(chǔ)器在大多數(shù)情況下也是鄰居晌纫。顧名思義,寫入組合在高速緩存行被寫出之前結(jié)合了多次寫入訪問永丝。在理想情況下锹漱,整個(gè)緩存行是逐字修改的,并且只有在最后一個(gè)字被寫入后类溢,緩存行才寫入設(shè)備凌蔬。這可以顯著提高設(shè)備對(duì)RAM的訪問速度露懒。

最后還有不可緩存的內(nèi)存。這通常意味著內(nèi)存位置根本不受RAM支持砂心。它可能是一個(gè)特殊的地址懈词,它被硬編碼為在CPU之外具有某些功能。對(duì)于商品硬件辩诞,內(nèi)存映射地址范圍最常見的情況是轉(zhuǎn)換為訪問連接到總線(PCIe等)的卡和設(shè)備坎弯。在嵌入式主板上,有時(shí)會(huì)找到可用于打開和關(guān)閉LED的內(nèi)存地址译暂。緩存這樣的地址顯然是一個(gè)壞主意抠忘。在這種情況下,LED用于調(diào)試或狀態(tài)報(bào)告外永,并且希望盡快查看崎脉。PCIe卡上的內(nèi)存可以在沒有CPU交互的情況下更改,因此不應(yīng)該緩存該內(nèi)存伯顶。

3.3.4多處理器支持

在上一節(jié)中囚灼,我們已經(jīng)指出了當(dāng)多個(gè)處理器發(fā)揮作用時(shí)我們遇到的問題。即使是多核處理器也存在那些不共享的緩存級(jí)別(至少是L1d)的問題祭衩。

提供從一個(gè)處理器到另一個(gè)處理器的緩存的直接訪問是完全不切實(shí)際的灶体。一開始,連接速度不夠快掐暮。實(shí)際的替代方案是在需要時(shí)將緩存內(nèi)容傳輸?shù)狡渌幚砥餍椤U?qǐng)注意,這也適用于不在同一處理器上共享的緩存路克。

現(xiàn)在的問題是什么時(shí)候這個(gè)緩存行轉(zhuǎn)移必須發(fā)生樟结?這個(gè)問題很容易回答:當(dāng)一個(gè)處理器需要一個(gè)在另一個(gè)處理器的緩存中用于讀取或?qū)懭氲木彺嫘袝r(shí)。但是衷戈,處理器如何確定另一個(gè)處理器緩存中的緩存行是否臟狭吼?假設(shè)這只是因?yàn)楦咚倬彺嫘杏闪硪粋€(gè)處理器加載將是次優(yōu)的(最好)。通常殖妇,大部分內(nèi)存訪問都是讀取訪問,并且生成的高速緩存行不會(huì)變臟破花。高速緩存行上的處理器操作很頻繁(當(dāng)然谦趣,為什么我們有這篇文章?)座每,這意味著在每次寫入訪問后廣播關(guān)于更改后的高速緩存行的信息將是不切實(shí)際的前鹅。

多年來(lái)開發(fā)的是MESI緩存一致性協(xié)議(修改,獨(dú)占峭梳,共享舰绘,無(wú)效)蹂喻。該協(xié)議的命名方式是使用MESI協(xié)議時(shí),緩存行可以處于的四種狀態(tài):

  • ?

  • 修改:本地處理器已修改緩存行捂寿。這也意味著它是任何緩存中唯一的副本口四。

  • 獨(dú)占:高速緩存行未被修改,但已知未加載到任何其他處理器的高速緩存中秦陋。

  • 共享:高速緩存行未被修改蔓彩,可能存在于另一個(gè)處理器的高速緩存中。

  • 無(wú)效:緩存線無(wú)效驳概,即未使用赤嚼。

這個(gè)協(xié)議多年來(lái)從較簡(jiǎn)單的版本開發(fā)而來(lái),這些簡(jiǎn)單的版本不那么復(fù)雜但效率較低顺又。通過這四種狀態(tài)更卒,可以高效地實(shí)現(xiàn)寫回緩存,同時(shí)還支持在不同處理器上同時(shí)使用只讀數(shù)據(jù)稚照。

圖3.18:MESI協(xié)議轉(zhuǎn)換

處理器在監(jiān)聽或窺探其他處理器的工作時(shí)不需要太多努力即可完成狀態(tài)更改蹂空。處理器執(zhí)行的某些操作會(huì)在外部引腳上發(fā)布,從而使處理器的緩存處理對(duì)外可見锐锣。相關(guān)高速緩存行的地址在地址總線上可見腌闯。在以下關(guān)于狀態(tài)及其轉(zhuǎn)換的描述中(如圖3.18所示),我們將指出什么時(shí)候涉及到公共汽車雕憔。

最初所有的緩存行都是空的姿骏,因此也是無(wú)效的。如果將數(shù)據(jù)加載到緩存中以將緩存更改寫入修改斤彼。如果加載數(shù)據(jù)以讀取新狀態(tài)分瘦,則取決于另一個(gè)處理器是否也加載了緩存行。如果是這種情況琉苇,那么新的狀態(tài)是Shared嘲玫,否則是Exclusive。

如果從本地處理器讀取或?qū)懭胄薷牡母咚倬彺嫘胁⑸龋瑒t該指令可以使用當(dāng)前的高速緩存內(nèi)容去团,并且狀態(tài)不會(huì)更改。如果第二個(gè)處理器想要從高速緩存行讀取穷蛹,第一個(gè)處理器必須將其高速緩存的內(nèi)容發(fā)送給第二個(gè)處理器土陪,然后它可以將狀態(tài)更改為Shared。發(fā)送給第二處理器的數(shù)據(jù)也由存儲(chǔ)器存儲(chǔ)器中的內(nèi)存控制器接收和處理肴熏。如果沒有發(fā)生這種情況鬼雀,緩存行不能被標(biāo)記為共享。如果第二個(gè)處理器想寫入高速緩存行蛙吏,第一個(gè)處理器發(fā)送高速緩存行內(nèi)容并在本地將高速緩存行標(biāo)記為無(wú)效源哩。這是臭名昭著的“請(qǐng)求所有權(quán)”(RFO)操作鞋吉。在最后一級(jí)緩存中執(zhí)行此操作,就像I→M過渡相當(dāng)昂貴励烦。對(duì)于直寫緩存谓着,我們還需要增加將新緩存行內(nèi)容寫入下一個(gè)更高級(jí)緩存或主內(nèi)存所需的時(shí)間,從而進(jìn)一步增加成本崩侠。

如果高速緩存線處于共享狀態(tài)并且本地處理器從中讀取漆魔,則不需要進(jìn)行狀態(tài)更改,并且可以從高速緩存中完成讀取請(qǐng)求却音。如果高速緩存行本地寫入高速緩存行也可以使用改抡,但狀態(tài)更改為修改。它還要求其他處理器中緩存行的所有其他可能副本都標(biāo)記為無(wú)效系瓢。因此阿纤,寫入操作必須通過RFO消息通告給其他處理器。如果第二個(gè)處理器請(qǐng)求讀取高速緩存行夷陋,則不需要發(fā)生任何事情欠拾。主存儲(chǔ)器包含當(dāng)前數(shù)據(jù),并且本地狀態(tài)已經(jīng)被共享骗绕。如果第二個(gè)處理器想要寫入高速緩存行(RFO)藐窄,高速緩存行就被標(biāo)記為無(wú)效。不需要總線操作酬土。

獨(dú)占狀態(tài)幾乎等于一個(gè)關(guān)鍵的區(qū)別共享狀態(tài):本地的寫操作也沒有必須要在總線上公布荆忍。本地緩存副本被稱為是唯一的。這可能是一個(gè)巨大的優(yōu)勢(shì)撤缴,所以處理器會(huì)盡量在獨(dú)占狀態(tài)而不是共享狀態(tài)下保留盡可能多的緩存行刹枉。后者是在該時(shí)刻信息不可用的情況下的后備。獨(dú)占狀態(tài)也可以完全省去屈呕,不會(huì)造成功能問題微宝。由于E→M轉(zhuǎn)換比S→M轉(zhuǎn)換速度快得多,所以只會(huì)有性能受損虎眨。

從狀態(tài)轉(zhuǎn)換的這種描述中蟋软,應(yīng)該清楚多處理器操作特有的成本在哪里。是的嗽桩,填充緩存仍然很昂貴钟鸵,但現(xiàn)在我們還必須注意RFO消息。無(wú)論何時(shí)發(fā)送這樣的消息涤躲,事情都會(huì)變得緩慢。

有兩種情況需要RFO消息:

  • ?

  • 一個(gè)線程從一個(gè)處理器遷移到另一個(gè)處理器贡未,所有的高速緩存行必須移到新的處理器一次种樱。

    ?

  • 在兩個(gè)不同的處理器中真正需要高速緩存行蒙袍。{

    對(duì)于同一處理器上的兩個(gè)內(nèi)核來(lái)說,較小的級(jí)別也是如此嫩挤。成本只是小一點(diǎn)害幅。RFO消息可能會(huì)多次發(fā)送。

    }

    ?

在多線程或多進(jìn)程程序中岂昭,總是需要一些同步; 這個(gè)同步使用內(nèi)存來(lái)實(shí)現(xiàn)以现。所以有一些有效的RFO消息。他們?nèi)匀恍枰M可能不經(jīng)常保存约啊。不過邑遏,還有其他RFO消息來(lái)源。在第6節(jié)中恰矩,我們將解釋這些情景记盒。Cache一致性協(xié)議消息必須分布在系統(tǒng)的處理器之間。只有在系統(tǒng)中的所有處理器都有機(jī)會(huì)回復(fù)該消息時(shí)外傅,才能進(jìn)行MESI轉(zhuǎn)換纪吮。這意味著答復(fù)可能花費(fèi)的最長(zhǎng)時(shí)間決定了一致性協(xié)議的速度。{這就是我們現(xiàn)在看到的原因萎胰,例如碾盟,帶有三個(gè)插槽的AMD Opteron系統(tǒng)〖季梗考慮到處理器只有三個(gè)超鏈接冰肴,并且需要一個(gè)南橋連接,每個(gè)處理器只有一跳灵奖。}總線上的碰撞是可能的嚼沿,NUMA系統(tǒng)中的延遲可能很高,當(dāng)然純粹的流量可能會(huì)減慢速度瓷患。所有重要原因都是為了避免不必要的流量骡尽。

還有一個(gè)問題與多個(gè)處理器相關(guān)。這些影響具有很高的機(jī)器特定性擅编,但原則上問題始終存在:FSB是共享資源攀细。在大多數(shù)機(jī)器中,所有處理器都通過一條總線連接到內(nèi)存控制器(見圖2.1)爱态。如果單個(gè)處理器可以使總線飽和(通常就是這樣)谭贪,那么共享相同總線的兩個(gè)或四個(gè)處理器將會(huì)限制每個(gè)處理器可用的帶寬。

即使每個(gè)處理器都有自己的總線連接到內(nèi)存控制器锦担,如圖2.2所示俭识,仍然有總線連接到內(nèi)存模塊。通常這是一條總線洞渔,但即使在圖2.2的擴(kuò)展模型中套媚,對(duì)同一內(nèi)存模塊的并發(fā)訪問也會(huì)限制帶寬缚态。

對(duì)于每個(gè)處理器都有本地內(nèi)存的AMD型號(hào)也是如此。是的堤瘤,所有處理器都可以同時(shí)快速訪問其本地內(nèi)存玫芦。但多線程和多進(jìn)程程序 - 至少不時(shí) - 必須訪問相同的內(nèi)存區(qū)域才能同步碧囊。

并發(fā)受限于可用于實(shí)現(xiàn)必要同步的有限帶寬庞溜。程序需要仔細(xì)設(shè)計(jì),以盡量減少不同處理器和內(nèi)核對(duì)相同內(nèi)存位置的訪問蜀漆。以下測(cè)量結(jié)果將顯示與多線程代碼相關(guān)的其他緩存效果慎皱。

多線程測(cè)量

為了確保在不同處理器上同時(shí)使用相同的高速緩存行引入的問題的嚴(yán)重性老虫,我們將在這里查看與之前使用的相同程序的更多性能圖。但是宝冕,這一次张遭,不止一個(gè)線程正在同時(shí)運(yùn)行。測(cè)量的是任何線程的最快運(yùn)行時(shí)間地梨。這意味著所有線程完成時(shí)完成運(yùn)行的時(shí)間甚至更長(zhǎng)菊卷。該機(jī)器使用四個(gè)處理器; 測(cè)試最多使用四個(gè)線程。所有處理器共享一條總線到內(nèi)存控制器宝剖,并且內(nèi)存模塊只有一條總線洁闰。

圖3.19:順序讀取訪問,多線程

圖3.19顯示了128字節(jié)條目順序只讀訪問(64位機(jī)器上的NPAD = 15)的性能万细。對(duì)于一個(gè)線程的曲線扑眉,我們可以預(yù)期一條類似于圖3.11的曲線。測(cè)量是針對(duì)不同的機(jī)器的赖钞,因此實(shí)際數(shù)量會(huì)有所不同腰素。

這個(gè)圖中的重要部分當(dāng)然是運(yùn)行多個(gè)線程時(shí)的行為。請(qǐng)注意雪营,沒有修改內(nèi)存弓千,也沒有嘗試在走鏈接列表時(shí)保持線程同步。即使不需要RFO消息献起,并且所有高速緩存行都可以共享洋访,但在使用兩個(gè)線程時(shí),最高線程的性能會(huì)降低18%谴餐,而使用四個(gè)線程時(shí)高達(dá)34%姻政。由于不必在處理器之間傳輸高速緩存行,所以這種下降僅由兩個(gè)瓶頸中的一個(gè)或兩個(gè)引起:從處理器到存儲(chǔ)器控制器的共享總線以及從存儲(chǔ)器控制器到存儲(chǔ)器模塊的總線岂嗓。一旦工作集大小超過本機(jī)中的L3緩存汁展,所有三個(gè)線程將預(yù)取新的列表元素。

當(dāng)我們修改記憶時(shí),事情變得更加丑陋善镰。圖3.20顯示了順序增量測(cè)試的結(jié)果妹萨。

圖3.20:順序增量,多個(gè)線程

此圖對(duì)Y軸使用對(duì)數(shù)刻度炫欺。所以,不要被顯然微小的差異所愚弄熏兄。對(duì)于運(yùn)行兩個(gè)線程品洛,我們?nèi)匀挥写蠹s18%的處罰,現(xiàn)在運(yùn)行四個(gè)線程的處罰現(xiàn)在是93%摩桶。這意味著當(dāng)使用四個(gè)線程時(shí)桥状,預(yù)取流量和寫回流量幾乎使總線飽和。

我們使用對(duì)數(shù)刻度來(lái)顯示L1d范圍的結(jié)果硝清「ㄕ澹可以看出,只要多個(gè)線程運(yùn)行芦拿,L1d基本上無(wú)效士飒。僅當(dāng)L1d不足以保持工作集時(shí),單線程訪問時(shí)間超過20個(gè)周期蔗崎。當(dāng)多個(gè)線程正在運(yùn)行時(shí)酵幕,即使使用最小的工作集大小,這些訪問時(shí)間也會(huì)立即生效缓苛。

這里沒有顯示問題的一個(gè)方面芳撒。用這個(gè)特定的測(cè)試程序很難衡量。即使測(cè)試修改了內(nèi)存未桥,因此我們必須期待RFO消息笔刹,但是當(dāng)使用多個(gè)線程時(shí),L2范圍的成本并不高冬耿。該程序?qū)⒉坏貌皇褂么罅績(jī)?nèi)存舌菜,并且所有線程必須并行訪問相同的內(nèi)存。如果沒有大量的同步操作淆党,那么這將很難實(shí)現(xiàn)酷师,這將主導(dǎo)執(zhí)行時(shí)間。

圖3.21:隨機(jī)Addnextlast染乌,多個(gè)線程

最后在圖3.21中山孔,我們得到了隨機(jī)訪問內(nèi)存的Addnextlast測(cè)試的編號(hào)。這個(gè)數(shù)字主要是為了顯示驚人的高數(shù)字荷憋。在極端情況下台颠,現(xiàn)在大約需要1,500個(gè)周期來(lái)處理單個(gè)列表元素。更多線程的使用更加值得懷疑。我們可以總結(jié)一個(gè)表中多個(gè)線程使用的效率串前。

#Threads Seq Read Seq Inc 蘭德添加
2 1.69 1.69 1.54
4 2.98 2.07 1.65

表3.3:多個(gè)線程的效率

下表顯示了圖3.21中三個(gè)圖中的最大工作集大小的多線程運(yùn)行效率瘫里。該數(shù)字顯示了通過使用兩個(gè)或四個(gè)線程,測(cè)試程序?qū)τ谧畲蠊ぷ骷笮∷鶐?lái)的最佳加速荡碾。對(duì)于兩個(gè)線程谨读,加速的理論極限是2,對(duì)于四個(gè)線程坛吁,4.兩個(gè)線程的數(shù)量并不那么糟糕劳殖。但是對(duì)于四個(gè)線程來(lái)說,最后測(cè)試的數(shù)字表明它幾乎不值得超出兩個(gè)線程拨脉。額外的好處是微不足道的哆姻。如果我們用圖3.21來(lái)表示數(shù)據(jù)有點(diǎn)不同,我們可以更容易地看到這一點(diǎn)玫膀。

圖3.22:通過并行提速

圖3.22中的曲線顯示了加速因子矛缨,即與單線程執(zhí)行代碼相比的相對(duì)性能。我們必須忽略最小的尺寸帖旨,測(cè)量不夠準(zhǔn)確箕昭。對(duì)于L2和L3緩存的范圍,我們可以看到我們確實(shí)實(shí)現(xiàn)了幾乎線性的加速碉就。我們幾乎分別達(dá)到2和4的因子盟广。但一旦L3緩存不足以保存工作集,數(shù)字就會(huì)崩潰瓮钥。它們碰撞到兩個(gè)和四個(gè)線程的加速是相同的(見表3.3中的第四列)筋量。這就是為什么人們很難找到帶有超過四個(gè)CPU的插座的主板的原因之一,它們都使用相同的內(nèi)存控制器碉熄。具有更多處理器的機(jī)器必須以不同方式構(gòu)建(請(qǐng)參見第5節(jié))桨武。

這些數(shù)字不是通用的。在某些情況下锈津,即使是適合最后一級(jí)緩存的工作集也不允許線性加速呀酸。事實(shí)上,這是常態(tài)琼梆,因?yàn)榫€程通常不像本測(cè)試程序那樣解耦性誉。另一方面,可以使用大型工作集并仍然利用兩個(gè)以上的線程茎杂。但是错览,這樣做需要思考。我們將在第6部分討論一些方法煌往。

特例:超線程

超線程(有時(shí)稱為對(duì)稱多線程倾哺,SMT)由CPU實(shí)現(xiàn),并且是一種特殊情況,因?yàn)楦鱾€(gè)線程不能真正同時(shí)運(yùn)行羞海。除寄存器集外忌愚,它們幾乎都共享所有的處理資源。單獨(dú)的內(nèi)核和CPU仍然可以并行工作却邓,但是在每個(gè)內(nèi)核上實(shí)現(xiàn)的線程受限于此限制硕糊。理論上每個(gè)內(nèi)核可以有很多線程,但到目前為止申尤,英特爾的CPU最多每個(gè)內(nèi)核有兩個(gè)線程癌幕。CPU負(fù)責(zé)時(shí)間復(fù)用這些線程。盡管如此昧穿,這一點(diǎn)沒有多大意義。真正的優(yōu)勢(shì)在于橙喘,當(dāng)當(dāng)前運(yùn)行的超線程延遲時(shí)时鸵,CPU可以調(diào)度另一個(gè)超線程。在大多數(shù)情況下厅瞎,這是由內(nèi)存訪問引起的延遲饰潜。

如果兩個(gè)線程在一個(gè)超線程核心上運(yùn)行,則如果兩個(gè)線程的組合運(yùn)行時(shí)間低于單線程代碼的運(yùn)行時(shí)間和簸,則該程序僅比單線程代碼更高效 彭雾。這可以通過重疊通常會(huì)順序發(fā)生的不同存儲(chǔ)器訪問的等待時(shí)間來(lái)實(shí)現(xiàn)。一個(gè)簡(jiǎn)單的計(jì)算顯示了緩存命中率達(dá)到一定加速的最低要求锁保。

一個(gè)程序的執(zhí)行時(shí)間可以用一個(gè)簡(jiǎn)單的模型來(lái)近似薯酝,只有一個(gè)級(jí)別的緩存,如下所示(參見[htimpact]):

T exe = N [(1-F mem)T proc + F mem(G hit T cache +(1-G hit)T miss)]

變量的含義如下:

? = 指示數(shù)量爽柒。
F mem = 訪問內(nèi)存的N分?jǐn)?shù)吴菠。
G 命中 = 擊中緩存的負(fù)載的分?jǐn)?shù)。
T proc = 每條指令的周期數(shù)浩村。
T 緩存 = 緩存命中的周期數(shù)做葵。
T 小姐 = 緩存未命中的周期數(shù)。
T exe = 程序的執(zhí)行時(shí)間心墅。

為了使用兩個(gè)線程有意義酿矢,兩個(gè)線程中的每個(gè)線程的執(zhí)行時(shí)間必須至多為單線程代碼的一半。任何一方的唯一變量是緩存命中數(shù)怎燥。如果我們解決了不降低線程執(zhí)行速度50%或更多所需的最小緩存命中率的公式瘫筐,我們可以得到圖3.23中的圖。

圖3.23:加速的最小緩存命中率

X軸表示單線程代碼的緩存命中率G hit刺覆。Y軸顯示多線程代碼所需的緩存命中率严肪。此值永遠(yuǎn)不會(huì)高于單線程命中率,否則,單線程代碼也會(huì)使用該改進(jìn)的代碼驳糯。對(duì)于55%以下的單線程命中率篇梭,程序在所有情況下都可以使用線程。由于緩存未命中以啟用第二個(gè)超線程酝枢,CPU或多或少處于空閑狀態(tài)恬偷。

綠地是目標(biāo)。如果線程減速小于50%并且每個(gè)線程的工作量減半帘睦,則組合運(yùn)行時(shí)可能會(huì)小于單線程運(yùn)行時(shí)袍患。對(duì)于這里建模的系統(tǒng)(使用P4超線程的數(shù)字),對(duì)于單線程代碼竣付,命中率為60%的程序要求雙線程程序的命中率至少為10%诡延。這通常是可行的。但是古胆,如果單線程代碼的命中率為95%肆良,那么多線程代碼的命中率至少需要80%。這很難逸绎。尤其是惹恃,這是超線程的問題,因?yàn)楝F(xiàn)在每個(gè)超線程可用的有效高速緩存大泄啄痢(L1d在這里巫糙,實(shí)際上也是L2等等)被減半。兩個(gè)超線程都使用相同的緩存來(lái)加載其數(shù)據(jù)颊乘。

因此参淹,超線程僅在有限的情況下有用。單線程代碼的高速緩存命中率必須足夠低疲牵,以滿足上面的公式和減少的高速緩存大小承二,新的命中率仍然符合目標(biāo)。然后才能使用超線程才有意義纲爸。在實(shí)踐中結(jié)果是否更快取決于處理器是否足以將一個(gè)線程中的等待時(shí)間與其他線程中的執(zhí)行時(shí)間重疊亥鸠。并行化代碼的開銷必須添加到新的總運(yùn)行時(shí)間中,并且這種額外成本通常不能忽略识啦。

在第6.3.4節(jié)中负蚊,我們將看到一種技術(shù),線程密切協(xié)作颓哮,通過公共緩存實(shí)現(xiàn)緊密耦合實(shí)際上是一種優(yōu)勢(shì)家妆。如果只有程序員愿意投入時(shí)間和精力來(lái)擴(kuò)展他們的代碼,這種技術(shù)可以應(yīng)用于很多情況冕茅。

應(yīng)該清楚的是伤极,如果兩個(gè)超線程執(zhí)行完全不同的代碼(即蛹找,兩個(gè)線程被OS視為分開的處理器以執(zhí)行單獨(dú)的進(jìn)程),則高速緩存大小確實(shí)減半哨坪,這意味著高速緩存中的顯著增加未命中庸疾。除非緩存足夠大,否則這樣的操作系統(tǒng)調(diào)度實(shí)踐是有問題的当编。除非機(jī)器的工作負(fù)載由通過其設(shè)計(jì)確實(shí)可以從超線程中受益的進(jìn)程組成届慈,否則最好關(guān)閉計(jì)算機(jī)BIOS中的超線程。{ 保持超線程功能的另一個(gè)原因是調(diào)試忿偷。SMT在尋找并行代碼中的一些問題方面非常出色金顿。}

3.3.5其他細(xì)節(jié)

到目前為止,我們談到地址由三部分組成鲤桥,標(biāo)記揍拆,集合索引和緩存行偏移量。但是茶凳,實(shí)際使用的是什么地址礁凡?如今所有相關(guān)的處理器都為進(jìn)程提供虛擬地址空間,這意味著有兩種不同類型的地址:虛擬地址和物理地址慧妄。

虛擬地址的問題在于它們不是唯一的。隨著時(shí)間的推移剪芍,虛擬地址可以引用不同的物理內(nèi)存地址塞淹。不同進(jìn)程中的相同地址也可能指不同的物理地址。所以最好使用物理內(nèi)存地址罪裹,對(duì)吧饱普?

這里的問題是指令使用虛擬地址,這些地址必須借助內(nèi)存管理單元(MMU)轉(zhuǎn)換為物理地址状共。這是一個(gè)非平凡的操作套耕。在執(zhí)行指令的管道中,物理地址可能僅在稍后階段可用峡继。這意味著緩存邏輯必須非撤肱郏快速地確定內(nèi)存位置是否被緩存。如果可以使用虛擬地址碾牌,則高速緩存查找可以在管道中更早發(fā)生康愤,并且在高速緩存命中的情況下可以使存儲(chǔ)器內(nèi)容可用。結(jié)果是更多的內(nèi)存訪問成本可能被管道隱藏舶吗。

處理器設(shè)計(jì)人員目前正在為第一級(jí)緩存使用虛擬地址標(biāo)記征冷。這些緩存非常小,可以清除而不會(huì)造成太多的痛苦誓琼。如果進(jìn)程的頁(yè)表樹更改检激,至少需要部分清除緩存肴捉。如果處理器具有指定已改變的虛擬地址范圍的指令,則可以避免完全刷新叔收。鑒于L1i和L1d緩存的低延遲(?3個(gè)周期)齿穗,使用虛擬地址幾乎是強(qiáng)制性的。

對(duì)于包含L2今穿,L3缤灵,...緩存的較大緩存,需要物理地址標(biāo)記蓝晒。這些緩存具有更高的延遲腮出,虛擬→物理地址轉(zhuǎn)換可以及時(shí)完成。由于這些緩存較大(即芝薇,當(dāng)它們被刷新時(shí)會(huì)丟失大量信息)并且由于主要的內(nèi)存訪問延遲而重新填充它們需要很長(zhǎng)時(shí)間胚嘲,因此刷新它們往往會(huì)代價(jià)高昂。

一般來(lái)說洛二,不需要知道這些緩存中地址處理的細(xì)節(jié)馋劈。它們不能改變,影響性能的所有因素通常都應(yīng)該避免或者與高成本相關(guān)晾嘶。如果大多數(shù)已使用的高速緩存行落入同一組中妓雾,則溢出高速緩存容量是不利的,并且所有高速緩存都會(huì)提早出現(xiàn)問題垒迂。后者可以通過虛擬緩存來(lái)避免械姻,但用戶級(jí)進(jìn)程不可能避免使用物理地址尋址的緩存。唯一需要牢記的細(xì)節(jié)是机断,如果可能的話楷拳,不要將相同的物理內(nèi)存位置映射到同一進(jìn)程中的兩個(gè)或更多虛擬地址。

緩存的另一個(gè)細(xì)節(jié)吏奸,對(duì)程序員來(lái)說很不感興趣的是緩存替換策略欢揖。大多數(shù)緩存首先驅(qū)逐最近最少使用(LRU)元素。這總是一個(gè)很好的默認(rèn)策略奋蔚。隨著更大的關(guān)聯(lián)性(并且由于增加更多內(nèi)核她混,聯(lián)想性在未來(lái)幾年的確可能會(huì)進(jìn)一步增長(zhǎng)),維護(hù)LRU列表變得越來(lái)越昂貴旺拉,我們可能會(huì)看到采用不同的策略产上。

至于緩存替換,程序員可以做的并不多蛾狗。如果緩存使用物理地址標(biāo)記晋涣,則無(wú)法找出虛擬地址與緩存集關(guān)聯(lián)的方式〕磷溃可能是所有邏輯頁(yè)面中的高速緩存行都映射到相同的高速緩存集谢鹊,導(dǎo)致大部分高速緩存未使用算吩。如果有的話,操作系統(tǒng)的工作是安排這不會(huì)經(jīng)常發(fā)生佃扼。

隨著虛擬化的出現(xiàn)偎巢,事情變得更加復(fù)雜。現(xiàn)在甚至操作系統(tǒng)都不能控制物理內(nèi)存的分配兼耀。虛擬機(jī)監(jiān)視器(VMM压昼,又名管理程序)負(fù)責(zé)物理內(nèi)存分配。

程序員可以做的最好的做法是a)完全使用邏輯內(nèi)存頁(yè)面瘤运,并且b)盡可能大地使用頁(yè)面大小以盡可能多樣化物理地址窍霞。較大的頁(yè)面尺寸也有其他好處,但這是另一個(gè)話題(參見第4節(jié))拯坟。

3.4指令緩存

不僅緩存處理器使用的數(shù)據(jù)但金,處理器執(zhí)行的指令也被緩存。但是郁季,這個(gè)緩存比數(shù)據(jù)緩存的問題少得多冷溃。有幾個(gè)原因:

  • ?

  • 執(zhí)行的代碼數(shù)量取決于所需代碼的大小。代碼的大小通常取決于問題的復(fù)雜程度梦裂。問題的復(fù)雜性是固定的似枕。

    ?

  • 雖然程序的數(shù)據(jù)處理是由程序員設(shè)計(jì)的,但程序的指令通常由編譯器生成年柠。編譯器編寫者知道有關(guān)良好代碼生成的規(guī)則菠净。

    ?

  • 程序流程比數(shù)據(jù)訪問模式更具可預(yù)測(cè)性。今天的CPU非常擅長(zhǎng)檢測(cè)模式彪杉。這有助于預(yù)取。

    ?

  • 代碼總是具有相當(dāng)好的空間和時(shí)間局部性牵咙。

    ?

    ?

程序員應(yīng)遵循一些規(guī)則派近,但這些規(guī)則主要由如何使用這些工具的規(guī)則組成。我們將在第6節(jié)討論它們洁桌。這里我們只談?wù)勚噶罹彺娴募夹g(shù)細(xì)節(jié)渴丸。

自從CPU的核心時(shí)鐘大幅增加,并且緩存(即使是第一級(jí)緩存)和內(nèi)核之間的速度差異增大后另凌,CPU也一直處于流水線狀態(tài)谱轨。這意味著指令的執(zhí)行分階段進(jìn)行。首先解碼指令吠谢,然后準(zhǔn)備參數(shù)土童,最后執(zhí)行。這樣的流水線可能相當(dāng)長(zhǎng)(對(duì)于英特爾的Netburst體系結(jié)構(gòu)工坊,這種流水線可能需要20個(gè)階段)献汗。長(zhǎng)管道意味著如果管道停滯(即通過它的指令流中斷)敢订,需要一段時(shí)間才能重新加速。例如罢吃,如果下一條指令的位置不能被正確預(yù)測(cè)楚午,或者如果加載下一條指令需要很長(zhǎng)時(shí)間(例如,必須從存儲(chǔ)器中讀饶蛘小)矾柜,管道延遲就會(huì)發(fā)生。

因此就谜,CPU設(shè)計(jì)人員在分支預(yù)測(cè)上花費(fèi)了大量的時(shí)間和芯片空間怪蔑,以便盡可能少地發(fā)生流水線延遲。

在CISC處理器上吁伺,解碼階段也需要一些時(shí)間饮睬。x86和x86-64處理器尤其受到影響。因此篮奄,近年來(lái)捆愁,這些處理器不會(huì)緩存L1i中的指令的原始字節(jié)序列,而是緩存經(jīng)解碼的指令窟却。在這種情況下苍碟,L1i被稱為“跟蹤緩存”蹂安。跟蹤緩存允許處理器在緩存命中的情況下跳過流水線的第一步,如果流水線停滯,則特別好裸卫。

如前所述,L2上的緩存是包含代碼和數(shù)據(jù)的統(tǒng)一緩存聚至。顯然這里的代碼是以字節(jié)序列的形式緩存的化戳,而不是解碼的。

為了達(dá)到最佳性能切平,只有幾條與指令緩存相關(guān)的規(guī)則:

  1. ?

  2. 生成盡可能小的代碼握础。為了使用流水線而使用軟件流水線需要?jiǎng)?chuàng)建更多代碼或使用小代碼的開銷太高時(shí),也有例外悴品。

    ?

  3. 只要有可能禀综,請(qǐng)幫助處理器做出好的預(yù)取決定。這可以通過代碼布局或顯式預(yù)取來(lái)完成苔严。

    ?

這些規(guī)則通常由編譯器的代碼生成來(lái)強(qiáng)制執(zhí)行定枷。程序員可以做幾件事情,我們將在第6節(jié)中討論它們届氢。

3.4.1自修改代碼

在早期的計(jì)算機(jī)時(shí)代欠窒,內(nèi)存很貴。人們竭盡全力減小節(jié)目的規(guī)模退子,為節(jié)目數(shù)據(jù)騰出更多空間贱迟。經(jīng)常部署的一個(gè)技巧是隨著時(shí)間的推移改變程序本身姐扮。這種自修改代碼(SMC)有時(shí)仍然可以找到,目前主要是出于性能原因或安全漏洞衣吠。

一般應(yīng)避免使用SMC茶敏。雖然它通常被正確地執(zhí)行,但是有邊界情況缚俏,如果不正確惊搏,會(huì)造成性能問題。顯然忧换,被更改的代碼不能保存在包含解碼指令的跟蹤緩存中恬惯。但即使未使用跟蹤緩存,因?yàn)榇a根本沒有執(zhí)行(或一段時(shí)間)亚茬,處理器可能會(huì)有問題酪耳。如果即將到來(lái)的指令在進(jìn)入流水線時(shí)發(fā)生改變,處理器必須丟掉大量工作并重新開始刹缝。甚至有些情況下碗暗,處理器的大部分狀態(tài)必須被拋棄。

最后梢夯,由于處理器假定 - 出于簡(jiǎn)單的原因言疗,并且因?yàn)樵?9.9999999%所有情況下都是這樣 - 代碼頁(yè)是不可變的,所以L1i實(shí)現(xiàn)不使用MESI協(xié)議颂砸,而是使用簡(jiǎn)化的SI協(xié)議噪奄。這意味著如果檢測(cè)到修改,就必須做出很多悲觀的假設(shè)人乓。

強(qiáng)烈建議盡可能避免使用SMC勤篮。內(nèi)存不再是稀缺資源。根據(jù)具體需要編寫單獨(dú)的函數(shù)而不是修改一個(gè)函數(shù)會(huì)更好色罚。也許有一天SMC的支持可以做成可選的叙谨,我們可以通過這種方式來(lái)檢測(cè)利用代碼來(lái)修改代碼。如果必須使用SMC保屯,則寫入操作應(yīng)繞過緩存,以免在L1i中需要的L1d中的數(shù)據(jù)產(chǎn)生問題涤垫。有關(guān)這些說明的更多信息姑尺,請(qǐng)參閱第6.1節(jié)。

通常在Linux上很容易識(shí)別包含SMC的程序蝠猬。所有程序代碼在使用常規(guī)工具鏈構(gòu)建時(shí)都是寫保護(hù)的切蟋。程序員必須在鏈接時(shí)執(zhí)行重要的魔術(shù)來(lái)創(chuàng)建可執(zhí)行代碼頁(yè)可寫的可執(zhí)行文件。當(dāng)發(fā)生這種情況時(shí)榆芦,現(xiàn)代英特爾x86和x86-64處理器具有專用的性能計(jì)數(shù)器柄粹,可以計(jì)算自修改代碼的使用喘鸟。在這些計(jì)數(shù)器的幫助下,即使程序由于放松的權(quán)限而成功驻右,也很容易用SMC識(shí)別程序什黑。

3.5緩存小姐因素

我們已經(jīng)看到,當(dāng)內(nèi)存訪問錯(cuò)過高速緩存時(shí)堪夭,成本飛漲愕把。有時(shí)候這是不可避免的,重要的是了解實(shí)際成本以及可以采取哪些措施來(lái)緩解問題森爽。

3.5.1高速緩存和內(nèi)存帶寬

為了更好地理解處理器的功能恨豁,我們測(cè)量了最佳環(huán)境下的可用帶寬。這種測(cè)量特別有趣爬迟,因?yàn)椴煌奶幚砥靼姹静顒e很大橘蜜。這就是為什么這個(gè)部分充滿了幾臺(tái)不同機(jī)器的數(shù)據(jù)。衡量性能的程序使用x86和x86-64處理器的SSE指令一次加載或存儲(chǔ)16個(gè)字節(jié)付呕。就像在我們的其他測(cè)試中一樣计福,工作集從1kB增加到512MB,并且每個(gè)周期可以加載或存儲(chǔ)多少字節(jié)凡涩。

圖3.24:Pentium 4帶寬

圖3.24顯示了64位Intel Netburst處理器的性能棒搜。對(duì)于適合L1d的工作集大小,處理器能夠讀取每個(gè)周期全部16個(gè)字節(jié)活箕,即每個(gè)周期執(zhí)行一個(gè)加載指令(movaps指令一次移動(dòng)16個(gè)字節(jié))力麸。測(cè)試對(duì)讀取的數(shù)據(jù)沒有任何作用,我們只測(cè)試讀取指令本身育韩。一旦L1d不夠用克蚂,性能就會(huì)急劇下降到每個(gè)周期少于6個(gè)字節(jié)。2 18的步驟字節(jié)是由于DTLB緩存耗盡筋讨,這意味著每個(gè)新頁(yè)面需要額外的工作埃叭。由于讀取順序預(yù)取可以完美地預(yù)測(cè)訪問,并且FSB可以為所有大小的工作集以每個(gè)周期大約5.3字節(jié)的速度對(duì)內(nèi)存內(nèi)容進(jìn)行流式處理悉罕。但是赤屋,預(yù)取的數(shù)據(jù)不會(huì)傳播到L1d。這些當(dāng)然是在真實(shí)程序中永遠(yuǎn)不可能實(shí)現(xiàn)的數(shù)字壁袄。將它們視為實(shí)際限制类早。

寫入和復(fù)制性能比讀取性能更驚人。即使對(duì)于小的工作集大小嗜逻,寫入性能也不會(huì)超過每個(gè)周期4個(gè)字節(jié)涩僻。這表明,在這些Netburst處理器中,英特爾選擇為L(zhǎng)1d使用Write-Through模式逆日,其性能明顯受到L2速度的限制嵌巷。這也意味著從一個(gè)存儲(chǔ)器區(qū)域復(fù)制到另一個(gè)不重疊的存儲(chǔ)器區(qū)域的復(fù)制測(cè)試的性能不會(huì)顯著更差。必要的讀取操作速度非呈页椋快搪哪,可以與寫入操作部分重疊。寫入和復(fù)制測(cè)量結(jié)果最值得注意的細(xì)節(jié)是L2緩存不夠用時(shí)的低性能狠半。性能下降到每個(gè)周期0.5個(gè)字節(jié)噩死!這意味著寫操作比讀操作慢10倍。這意味著優(yōu)化這些操作對(duì)于程序的執(zhí)行更為重要神年。

在圖3.25中已维,我們?cè)谕粋€(gè)處理器上看到了結(jié)果,但有兩個(gè)線程在運(yùn)行已日,其中一個(gè)固定在處理器的兩個(gè)超線程中垛耳。

圖3.25:帶有2個(gè)超線程的P4帶寬

該圖以與前一圖相同的比例顯示,以說明差異飘千,并且由于測(cè)量?jī)蓚€(gè)并發(fā)線程的問題堂鲜,曲線有點(diǎn)緊張。結(jié)果如預(yù)期护奈。由于超線程共享除寄存器以外的所有資源缔莲,因此每個(gè)線程只有一半高速緩存和可用帶寬。這意味著即使每個(gè)線程都必須等待很長(zhǎng)時(shí)間并且可以授予其他線程執(zhí)行時(shí)間霉旗,但這并沒有什么區(qū)別痴奏,因?yàn)槠渌€程也必須等待內(nèi)存。這確實(shí)顯示了超線程可能使用最糟糕的情況厌秒。

圖3.26:核心2帶寬

與圖3.24和3.25相比读拆,圖3.26和3.27的結(jié)果看起來(lái)與英特爾酷睿2處理器完全不同。這是一個(gè)共享L2的雙核處理器鸵闪,它是P4機(jī)器上L2的4倍檐晕。這只是解釋了寫入和復(fù)制性能的延遲下降。

有更大的差異蚌讼。整個(gè)工作集范圍內(nèi)的讀取性能在每個(gè)周期的最佳16字節(jié)周圍徘徊辟灰。2 20字節(jié)之后的讀取性能下降也是由于DTLB的工作集太大而導(dǎo)致的。實(shí)現(xiàn)這些高數(shù)字意味著處理器不僅能夠預(yù)取數(shù)據(jù)并及時(shí)傳輸數(shù)據(jù)篡石。這也意味著數(shù)據(jù)被預(yù)取到L1d中芥喇。

寫入和復(fù)制性能也非常不同。處理器沒有Write-Through策略; 寫入的數(shù)據(jù)存儲(chǔ)在L1d中夏志,并且必要時(shí)僅驅(qū)逐。這允許寫入速度接近每個(gè)周期的最佳16字節(jié)。一旦L1d不夠用沟蔑,性能就會(huì)顯著下降湿诊。與Netburst處理器一樣,寫入性能也顯著降低瘦材。由于高讀取性能厅须,這里的差別更大。事實(shí)上食棕,即使L2不夠用朗和,速度差也會(huì)增加到20倍!這并不意味著Core 2處理器表現(xiàn)不佳簿晓。相反眶拉,他們的表現(xiàn)總是比Netburst核心更好。

圖3.27:2線程的核心2帶寬

在圖3.27中憔儿,測(cè)試運(yùn)行兩個(gè)線程忆植,Core 2處理器的兩個(gè)核心中的每一個(gè)都有一個(gè)線程。雖然兩個(gè)線程都訪問相同的內(nèi)存谒臼,但不一定完全同步朝刊。讀取性能的結(jié)果與單線程案例沒有區(qū)別。在任何多線程測(cè)試用例中蜈缤,可以看到幾個(gè)更多的抖動(dòng)拾氓。

有趣的一點(diǎn)是適用于L1d的工作集大小的寫入和復(fù)制性能。從圖中可以看出底哥,性能與數(shù)據(jù)必須從主存儲(chǔ)器中讀取的性能相同咙鞍。兩個(gè)線程都爭(zhēng)奪相同的內(nèi)存位置,并且必須發(fā)送緩存行的RFO消息叠艳。問題在于這些請(qǐng)求沒有以L2緩存的速度處理奶陈,即使兩個(gè)內(nèi)核共享緩存。一旦L1d高速緩存不夠用附较,修改的條目就會(huì)從每個(gè)核心的L1d刷新到共享的L2中吃粒。此時(shí),由于L2緩存滿足L1d未命中拒课,并且僅在數(shù)據(jù)尚未刷新時(shí)才需要RFO消息徐勃,所以性能顯著提高。這就是為什么我們看到這些尺寸的工作組速度降低了50%早像。

由于一家供應(yīng)商的處理器版本之間存在顯著差異僻肖,因此也值得關(guān)注其他供應(yīng)商的處理器的性能。圖3.28顯示了AMD家族10h Opteron處理器的性能卢鹦。該處理器具有64kB L1d臀脏,512kB L2和2MB L3。三級(jí)緩存在處理器的所有內(nèi)核之間共享。性能測(cè)試的結(jié)果可以在圖3.28中看到揉稚。

圖3.28:AMD系列10h Opteron帶寬

關(guān)于數(shù)字的第一個(gè)細(xì)節(jié)是秒啦,如果L1d緩存足夠,處理器每周期能夠處理兩條指令搀玖。讀取性能每個(gè)周期超過32個(gè)字節(jié)余境,甚至寫入性能也是每個(gè)周期18.7個(gè)字節(jié)。盡管如此灌诅,讀取曲線很快變平芳来,每個(gè)周期2.3個(gè)字節(jié)的數(shù)據(jù)相當(dāng)?shù)汀4藴y(cè)試的處理器不會(huì)預(yù)取任何數(shù)據(jù)猜拾,至少不會(huì)有效即舌。

另一方面寫入曲線根據(jù)各種高速緩存的大小執(zhí)行。對(duì)于L1d的全部大小達(dá)到峰值性能关带,對(duì)于L2侥涵,每個(gè)周期對(duì)于L2為6個(gè)字節(jié),對(duì)于L3為每個(gè)周期2.8個(gè)字節(jié)宋雏,并且如果甚至L3不能保存所有數(shù)據(jù)芜飘,則最后每個(gè)周期0.5個(gè)字節(jié)。L1d緩存的性能超過(較舊的)Core 2處理器的性能磨总,L2訪問速度相當(dāng)快(Core 2具有較大的緩存)嗦明,L3和主內(nèi)存訪問速度較慢。

復(fù)制性能不能比讀取或?qū)懭胄阅芎抿窖唷_@就是為什么我們看到最初由讀取性能占主導(dǎo)地位的曲線娶牌,隨后是寫入性能。

Opteron處理器的多線程性能如圖3.29所示馆纳。

圖3.29:具有2個(gè)線程的AMD Fam 10h帶寬

讀取性能基本不受影響诗良。每個(gè)線程的L1d和L2都像以前一樣工作,而L3緩存在這種情況下也不會(huì)很好地預(yù)取鲁驶。兩條線不會(huì)過分強(qiáng)調(diào)L3的目的鉴裹。這個(gè)測(cè)試中最大的問題是寫入性能。線程共享的所有數(shù)據(jù)必須通過L3緩存钥弯。這種共享似乎相當(dāng)?shù)托Ь独螅驗(yàn)榧词筁3高速緩存大小足以容納整個(gè)工作集,成本也遠(yuǎn)高于L3接入脆霎。將該圖與圖3.27進(jìn)行比較总处,我們看到Core 2處理器的兩個(gè)線程以共享L2高速緩存的速度運(yùn)行,適用于適當(dāng)范圍的工作集大小睛蛛。Opteron處理器的性能水平僅適用于非常小的工作集規(guī)模鹦马,即使在這種情況下也可以實(shí)現(xiàn)

只有

L3的速度比Core 2的L2慢胧谈。

3.5.2關(guān)鍵字加載

內(nèi)存從主內(nèi)存?zhèn)鬏數(shù)叫∮诰彺嫘写笮〉膲K中的緩存中。今天64 一次傳輸荸频,高速緩存行大小為64或128 字節(jié)第岖。這意味著每個(gè)緩存行需要8或16次傳輸。

DRAM芯片可以在突發(fā)模式下傳輸這些64位塊试溯。這可以填充緩存線,而不需要來(lái)自存儲(chǔ)器控制器的任何進(jìn)一步命令以及可能的相關(guān)延遲郊酒。如果處理器預(yù)取緩存行遇绞,這可能是最好的操作方式。

如果程序?qū)?shù)據(jù)或指令的高速緩存訪問存在錯(cuò)誤(這意味著燎窘,它是強(qiáng)制高速緩存未命中摹闽,因?yàn)閿?shù)據(jù)首次使用,或容量高速緩存未命中褐健,因?yàn)橛邢薜母咚倬彺娲笮⌒枰鸪龈咚倬彺嫘校┣闆r不同付鹿。程序繼續(xù)所需的高速緩存行中的單詞可能不是高速緩存行中的第一個(gè)單詞。即使在突發(fā)模式和雙倍數(shù)據(jù)傳輸速率下蚜迅,單個(gè)64位塊也會(huì)在明顯不同的時(shí)間到達(dá)舵匾。每個(gè)塊到達(dá)4個(gè)CPU周期或比以前更晚。如果程序需要繼續(xù)的字是高速緩存行的第八個(gè)字節(jié)谁不,則在第一個(gè)字到達(dá)后坐梯,程序必須等待另外30個(gè)周期或更長(zhǎng)時(shí)間。

事情不一定非要這樣刹帕。內(nèi)存控制器可以按不同的順序請(qǐng)求緩存行的單詞吵血。處理器可以傳送程序等待的 關(guān)鍵字和存儲(chǔ)器控制器可以首先請(qǐng)求該字偷溺。一旦這個(gè)單詞到達(dá)蹋辅,程序可以繼續(xù)執(zhí)行,而其余的緩存行到達(dá)并且緩存還沒有處于一致的狀態(tài)挫掏。這種技術(shù)被稱為第一批和第一批重新啟動(dòng)侦另。

當(dāng)今的處理器實(shí)現(xiàn)了這種技術(shù),但有些情況下這是不可能的砍濒。如果處理器預(yù)取數(shù)據(jù)淋肾,則不知道關(guān)鍵字。如果處理器在預(yù)取操作正在進(jìn)行的時(shí)間內(nèi)請(qǐng)求高速緩存行爸邢,它將不得不等待直到關(guān)鍵字到達(dá)而不能影響訂單樊卓。

圖3.30:緩存行結(jié)束時(shí)的關(guān)鍵字

即使進(jìn)行了這些優(yōu)化,關(guān)鍵字在緩存行上的位置也很重要杠河。圖3.30顯示了順序和隨機(jī)訪問的Follow測(cè)試碌尔。顯示的是在第一個(gè)字中追逐的指針與指針在最后一個(gè)字中的情況下運(yùn)行測(cè)試的速度減慢浇辜。元素大小為64字節(jié),對(duì)應(yīng)于緩存行大小唾戚。這些數(shù)字相當(dāng)嘈雜柳洋,但可以看出,只要L2不足以保持工作集大小叹坦,關(guān)鍵詞在結(jié)尾處的情況的表現(xiàn)大約慢0.7%熊镣。順序訪問似乎受到了一些影響。這與預(yù)取下一個(gè)緩存行時(shí)的上述問題一致募书。

3.5.3緩存放置

高速緩存與超線程绪囱,核心和處理器之間的關(guān)系不在程序員的控制之下。但程序員可以確定線程的執(zhí)行位置莹捡,然后緩存與使用的CPU相關(guān)變得很重要鬼吵。

這里我們不會(huì)詳細(xì)討論何時(shí)選擇運(yùn)行線程的內(nèi)核。我們只會(huì)描述程序員在設(shè)置線程親和性時(shí)必須考慮的體系結(jié)構(gòu)細(xì)節(jié)篮赢。

根據(jù)定義齿椅,超線程除了寄存器組之外共享一切。這包括L1緩存启泣。這里沒有更多要說的涣脚。樂趣開始于處理器的各個(gè)核心。每個(gè)核心至少擁有自己的L1緩存寥茫。除此之外涩澡,今天還沒有很多共同的細(xì)節(jié):

  • ?

  • 早期的多核處理器具有單獨(dú)的L2高速緩存并且沒有更高的高速緩存。

    ?

  • 后來(lái)英特爾的型號(hào)共享了雙核處理器的L2緩存坠敷。對(duì)于四核處理器妙同,我們必須為每對(duì)雙核處理單獨(dú)的L2高速緩存。沒有更高級(jí)別的緩存膝迎。

    ?

  • AMD的家庭10h處理器具有獨(dú)立的L2緩存和統(tǒng)一的L3緩存粥帚。

    ?

處理器供應(yīng)商的宣傳材料中已經(jīng)寫了很多關(guān)于各自型號(hào)優(yōu)點(diǎn)的文章。如果核心處理的工作集不重疊限次,則單獨(dú)的L2高速緩存具有優(yōu)勢(shì)芒涡。這適用于單線程程序。由于今天這仍然是現(xiàn)實(shí)卖漫,所以這種方法不會(huì)表現(xiàn)得太差费尽。但總是有一些重疊。高速緩存都包含公共運(yùn)行時(shí)庫(kù)最常用的部分羊始,這意味著某些高速緩存空間被浪費(fèi)了旱幼。

與英特爾的雙核處理器完全共享L1旁邊的所有緩存可以有很大優(yōu)勢(shì)。如果在兩個(gè)核心上工作的線程的工作集顯著重疊突委,則可用緩存總量將增加柏卤,并且工作集可以更大冬三,而不會(huì)降低性能。如果工作集不重疊英特爾的高級(jí)智能高速緩存管理應(yīng)該防止任何一個(gè)內(nèi)核獨(dú)占整個(gè)高速緩存缘缚。

但是勾笆,如果兩個(gè)內(nèi)核在其各自的工作集中使用大約一半的緩存,則存在一些摩擦桥滨。緩存不斷必須衡量?jī)蓚€(gè)內(nèi)核的緩存使用情況窝爪,并且作為此次重新平衡的一部分執(zhí)行的逐出可能選擇不當(dāng)。為了看到問題齐媒,我們看看另一個(gè)測(cè)試程序的結(jié)果酸舍。

圖3.31:兩個(gè)進(jìn)程的帶寬

測(cè)試程序有一個(gè)過程不斷讀取或?qū)懭耄褂肧SE指令里初,一個(gè)2MB的內(nèi)存塊。選擇2MB是因?yàn)檫@是該Core 2處理器的L2緩存的一半大小忽舟。這個(gè)過程被固定到一個(gè)核心双妨,而另一個(gè)過程被固定到另一個(gè)核心。這第二個(gè)進(jìn)程讀取和寫入可變大小的內(nèi)存區(qū)域叮阅。該圖顯示了讀取或?qū)懭朊總€(gè)周期的字節(jié)數(shù)刁品。顯示了四個(gè)不同的圖表,每個(gè)過程讀取和寫入的組合浩姥。讀/寫圖用于后臺(tái)進(jìn)程挑随,該進(jìn)程始終使用2MB工作集進(jìn)行寫入,并將測(cè)量的進(jìn)程設(shè)置為可讀工作集勒叠。

圖中有趣的部分是2 20和2 23字節(jié)之間的部分兜挨。如果兩個(gè)內(nèi)核的L2緩存完全分離,我們可以預(yù)期所有四個(gè)測(cè)試的性能將在2 21和2 22之間下降字節(jié)眯分,這意味著一旦L2緩存耗盡拌汇。如圖3.31所示,情況并非如此弊决。對(duì)于后臺(tái)進(jìn)程寫入的情況噪舀,這是最明顯的。在工作集大小達(dá)到1MB之前飘诗,性能開始惡化与倡。這兩個(gè)進(jìn)程不共享內(nèi)存,因此進(jìn)程不會(huì)生成RFO消息昆稿。這些都是純粹的緩存驅(qū)逐問題纺座。智能緩存處理的問題在于,每個(gè)核心的有經(jīng)驗(yàn)高速緩存大小接近于1MB溉潭,而不是每個(gè)可用的2MB核心比驻。人們只能希望该溯,如果內(nèi)核之間共享的緩存仍然是即將到來(lái)的處理器的特性,則用于智能緩存處理的算法將得到修復(fù)别惦。

擁有帶兩個(gè)L2緩存的四核處理器只是在引入更高級(jí)別的緩存之前的一個(gè)解決方案狈茉。與單獨(dú)的套接字和雙核處理器相比,此設(shè)計(jì)沒有明顯的性能優(yōu)勢(shì)掸掸。兩個(gè)核心通過同一條總線進(jìn)行通信氯庆,在外部,F(xiàn)SB可見扰付。沒有特別的快速數(shù)據(jù)交換堤撵。

未來(lái)的多核處理器緩存設(shè)計(jì)將在更多的層次上。AMD的10h系列處理器開始了羽莺。我們是否會(huì)繼續(xù)看到處理器內(nèi)核子集共享較低級(jí)別的緩存仍有待觀察实昨。由于高速和經(jīng)常使用的高速緩存不能在多個(gè)內(nèi)核之間共享,因此需要額外的高速緩存盐固。表現(xiàn)會(huì)受到影響荒给。它還需要具有高關(guān)聯(lián)性的非常大的緩存。這兩個(gè)數(shù)字(緩存大小和關(guān)聯(lián)性)都必須隨共享緩存的核心數(shù)量一起擴(kuò)展刁卜。使用大型L3高速緩存和合理大小的L2高速緩存是合理的折衷志电。L3緩存速度較慢,但理想情況下不如L2緩存那樣頻繁使用。

對(duì)于程序員來(lái)說,所有這些不同的設(shè)計(jì)在進(jìn)行調(diào)度決策時(shí)意味著復(fù)雜宾尚。人們必須知道機(jī)器架構(gòu)的工作負(fù)載和細(xì)節(jié)才能實(shí)現(xiàn)最佳性能。幸運(yùn)的是鱼蝉,我們支持確定機(jī)器架構(gòu)。接口將在后面的章節(jié)介紹箫荡。

3.5.4 FSB影響

FSB在機(jī)器的性能中扮演著重要角色蚀乔。緩存內(nèi)容只能在與內(nèi)存連接允許的情況下才能存儲(chǔ)和加載。我們可以通過在兩臺(tái)只有內(nèi)存模塊速度不同的機(jī)器上運(yùn)行程序來(lái)顯示多少菲茬。圖3.32顯示了在64位機(jī)器上對(duì)NPAD = 7 的Addnext0測(cè)試的結(jié)果(將下一個(gè)元素pad [0]元素的內(nèi)容添加到自己的pad [0]元素中) 吉挣。兩款機(jī)器均配備英特爾酷睿2處理器,第一款采用667MHz DDR2模塊婉弹,第二款采用800MHz模塊(增加20%)睬魂。

圖3.32:FSB速度的影響

這些數(shù)字表明,當(dāng)FSB對(duì)于大型工作集規(guī)模確實(shí)存在壓力時(shí)镀赌,我們確實(shí)看到了很大的收益氯哮。在這個(gè)測(cè)試中測(cè)得的最大性能增加是18.2%,接近理論最大值商佛。這表明喉钢,更快的FSB的確可以彌補(bǔ)大部分時(shí)間姆打。當(dāng)工作集適合高速緩存時(shí)(并且這些處理器具有4MB L2)并不重要。必須記住肠虽,我們?cè)谶@里測(cè)量一個(gè)程序幔戏。系統(tǒng)的工作集包含所有同時(shí)運(yùn)行的進(jìn)程所需的內(nèi)存。通過這種方式税课,使用更小的程序很容易可以超過4MB內(nèi)存或更多闲延。

今天,英特爾的一些處理器支持FSB速度高達(dá)1333MHz韩玩,這意味著又增加了60%垒玲。未來(lái)將會(huì)看到更高的速度。如果速度很重要找颓,并且工作集規(guī)模較大合愈,快速RAM和高FSB速度肯定是物有所值的。但是击狮,必須小心佛析,因?yàn)榧词固幚砥骺赡苤С指叩腇SB速度,主板/北橋也可能不支持帘不。檢查規(guī)格至關(guān)重要。

繼續(xù)第3部分(虛擬內(nèi)存)杨箭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寞焙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子互婿,更是在濱河造成了極大的恐慌捣郊,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慈参,死亡現(xiàn)場(chǎng)離奇詭異呛牲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驮配,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門娘扩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人壮锻,你說我怎么就攤上這事琐旁。” “怎么了猜绣?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵灰殴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我掰邢,道長(zhǎng)牺陶,這世上最難降的妖魔是什么伟阔? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮掰伸,結(jié)果婚禮上皱炉,老公的妹妹穿的比我還像新娘。我一直安慰自己碱工,他們只是感情好娃承,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著怕篷,像睡著了一般历筝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廊谓,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天梳猪,我揣著相機(jī)與錄音,去河邊找鬼蒸痹。 笑死春弥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叠荠。 我是一名探鬼主播匿沛,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼榛鼎!你這毒婦竟也來(lái)了逃呼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤者娱,失蹤者是張志新(化名)和其女友劉穎抡笼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黄鳍,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡推姻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了框沟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藏古。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖忍燥,靈堂內(nèi)的尸體忽然破棺而出校翔,到底是詐尸還是另有隱情,我是刑警寧澤灾前,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布防症,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蔫敲。R本人自食惡果不足惜饲嗽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奈嘿。 院中可真熱鬧貌虾,春花似錦、人聲如沸裙犹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叶圃。三九已至袄膏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掺冠,已是汗流浹背沉馆。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留德崭,地道東北人斥黑。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像眉厨,于是被迫代替她去往敵國(guó)和親锌奴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,371評(píng)論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,096評(píng)論 1 32
  • 老公是一個(gè)注重感覺的人憾股,遇到不想做的事情鹿蜀,他經(jīng)常會(huì)說,沒那個(gè)心情荔燎。對(duì)此我常常嗤之以鼻耻姥,甚為不屑销钝。而最近自己也掉入情...
    無(wú)知者的自我救贖閱讀 237評(píng)論 0 0
  • 扭曲的畫面蒸健,一雙因?yàn)轶@恐而瞪大的雙眼座享,一個(gè)面容近于骷髏的人物,雙手捂著耳朵似忧,站在一條看不到頭尾的公路橋上渣叛,似乎受到...
    三月時(shí)候閱讀 4,843評(píng)論 0 2
  • 在這之間我想要對(duì)我的電影進(jìn)行一個(gè)漫談點(diǎn)評(píng),今天去看了一場(chǎng)電影盯捌,奇跡男孩——我相信淳衙,每一個(gè)人都已值得被愛的權(quán)利,如果...
    歸處有星火閱讀 227評(píng)論 0 0