地址空間的故事
時(shí)間:2022-08-11 07:51:01 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2022-08-11 07:51:01 來源:網(wǎng)站運(yùn)營
這一篇聊一下地址空間相關(guān)的知識(shí)。
每個(gè)程序都面對(duì)一個(gè)或者多個(gè)地址空間。你寫一個(gè)程序,說*(0x1234)=10,這里就索引了一個(gè)地址。所有可以被索引的地址,就構(gòu)成一個(gè)地址空間。一個(gè)CPU上的程序可能不止一個(gè)地址空間,比Intel支持LPC的指令,用inX和outX指令索引的地址空間和用movb索引的地址空間就是兩個(gè)相對(duì)獨(dú)立的地址空間。有些比如哈佛構(gòu)架的CPU,訪問指令和訪問數(shù)據(jù)內(nèi)存也會(huì)使用不同的地址空間。
一般馮諾伊曼計(jì)算機(jī)訪問內(nèi)存的是同一套指令,這套指令構(gòu)成一個(gè)地址空間。CPU的指令集就通過這個(gè)地址空間要求CPU訪問內(nèi)存。
最早的CPU的指令直接索引到物理內(nèi)存的地址,也就是說,指令說要訪問0x1234,訪問的就是物理內(nèi)存下標(biāo)為0x1234的那個(gè)單元的內(nèi)容。但我要請(qǐng)讀者注意的是,這里其實(shí)有兩個(gè)地址空間,一個(gè)是指令構(gòu)造的地址空間(我縮寫為ia),另一個(gè)是物理地址總線上發(fā)出的地址構(gòu)成的地址空間(我縮寫為pa),ia和pa不是完全一一對(duì)應(yīng)的。因?yàn)橹噶畹难葸M(jìn)具有滯后性,軟件是基于指令集寫的,寫好了,我希望未來做一個(gè)更強(qiáng)大的CPU的時(shí)候,不要讓我還要改寫軟件。所以比如你的物理地址只有10位,你不可能就做一個(gè)指令集,里面的地址都是10位的,以后要支持更多內(nèi)存,你把物理地址做成11位,你就要重新搞一個(gè)指令集。這樣軟件就沒有演進(jìn)性了。所以,ia空間是相對(duì)穩(wěn)定的,pa則變化得更快一些。我們后面說到的所有故事,都和這兩者的互相變化引起的。我需要讀者非常注意這個(gè)問題。
[段尋址]
PC行業(yè)興起的時(shí)候,常常使用16位ia的指令集,16位表示64K的空間,那個(gè)時(shí)候好大好大了,因?yàn)槲锢韮?nèi)存通常只有16K或者更低的,這時(shí)你如果做了14位的物理內(nèi)存地址空間,CPU發(fā)一個(gè)16位的地址下來,你只要不看最高兩位,你就可以尋址了。
但我們對(duì)內(nèi)存的猜測(cè)永遠(yuǎn)是缺乏想象力的(也是節(jié)省資源的需要了,這個(gè)我另外找地方介紹),很快物理內(nèi)存就超過16位了。但立即修改指令集會(huì)影響市場(chǎng),這時(shí),有什么辦法擴(kuò)展指令集,讓ia的空間補(bǔ)到和pa空間可以尋址一樣的長度呢?
對(duì)了,很自然的想法,加一個(gè)寄存器表示地址的高位就可以了:
所以,段地址這種東西,你不要被它那些什么權(quán)限啦,內(nèi)存分段啦這些概念蒙蔽,這就是個(gè)簡(jiǎn)單的地址擴(kuò)展方法,至于其他功能,段寄存器不可能做成4位,所以剩下的位,閑著也是閑著,就加點(diǎn)功能上去,如此而已。
[頁尋址]
段尋址的缺點(diǎn)是顯而易見的,你不可能每次尋址都分兩次來加載兩個(gè)數(shù)據(jù),這樣太麻煩了。所以才需要把高位地址封裝成“段”的概念,比如x86的意思是,你訪問代碼用cs寄存器,訪問數(shù)據(jù)用ds寄存器,這樣每次你就不用改這兩個(gè)寄存器玩了。但這樣整個(gè)程序也就只有128K而已,如果我的數(shù)據(jù)很大,超過64K的范圍,就又得切換這東西了,x86說,不夠是嗎?我再給你一個(gè)es寄存器……好吧,這樣和稀泥的方式是玩不久的。
很快MMU的概念就被提出來了。MMU是一個(gè)翻譯器,ia發(fā)出的地址,都經(jīng)過MMU進(jìn)行翻譯,變成pa。所以,MMU本質(zhì)上是一個(gè)函數(shù),實(shí)現(xiàn)pa=mmuf(ia)。
問題是,MMU基于什么算法來進(jìn)行翻譯?
我們用最“自由”的方式來定義這個(gè)算法,最好就是可以指定每個(gè)ia的pa是什么。但這樣就需要一張ia空間那么大的表。那么大的表,什么地方可以放得下呢?——也只有內(nèi)存了。但內(nèi)存填滿了這么一張表,還放什么呢?
所以一個(gè)ia對(duì)應(yīng)一個(gè)pa,這個(gè)算法在數(shù)理邏輯上就不合理。那我們可以退而求其次,每段連續(xù)的ia對(duì)應(yīng)一段連續(xù)的pa,這樣,這個(gè)段的大小,就是可以節(jié)省的映射表的項(xiàng)數(shù)了。比如,一個(gè)16位的ia,用10位作為一段,那么原來需要64K個(gè)映射項(xiàng),現(xiàn)在只需要64K/1K=64項(xiàng)而已。
由于每段的大小都固定了,我們把這種段稱為“頁”?,F(xiàn)在很多平臺(tái)都是用12位作為一頁,所以,現(xiàn)在很多系統(tǒng)都是4K為一頁,但這不是固定的,根據(jù)需要是可以變的。
基于頁尋址的方式,就稱為頁尋址,實(shí)現(xiàn)頁尋址的那個(gè)映射表,就稱為頁表,頁表放在內(nèi)存中。在長期的發(fā)展過程中,現(xiàn)在的頁表不是一個(gè)簡(jiǎn)單的數(shù)組,而是一個(gè)分層的數(shù)組,這些細(xì)節(jié),讀者可以自己看芯片編程手冊(cè),但本質(zhì)都只是為了實(shí)現(xiàn)ia到pa的對(duì)應(yīng),所有的優(yōu)化都是為了節(jié)省空間而已。
和段尋址一樣,既然頁表都發(fā)明出來了,和頁有關(guān)的一些保護(hù)措施也會(huì)依附上去,讓一個(gè)頁只讀啦,決定從這個(gè)地址發(fā)出去的請(qǐng)求能否合并啦,有沒有邊界效應(yīng)啦,這些都可以設(shè)置到頁表的對(duì)應(yīng)項(xiàng)中。但仍和段尋址一樣,這個(gè)問題不是頁尋址問題的本質(zhì)。
頁表的存在,導(dǎo)致所有的ia發(fā)出的地址和pa沒有直接的映射關(guān)系了,為了描述的方便,我們現(xiàn)在開始在這種情形下,把ia稱為虛擬地址,va。
[進(jìn)程空間]
有了頁尋址,進(jìn)程的概念很自然就被發(fā)明出來了。頁表是MMU的輸入,那么一個(gè)自然的想法,我們有多個(gè)頁表,一會(huì)兒用這個(gè),一會(huì)兒用那個(gè),這樣我們可以根據(jù)需要用不同的內(nèi)存,這個(gè)用來表達(dá)不同MMU的概念,體現(xiàn)在軟件的觀感上,就是進(jìn)程。
當(dāng)然,MMU封裝為進(jìn)程,還和軟件的“線程”概念進(jìn)行了一定程度上進(jìn)行了綁定,所以,軟件的進(jìn)程,不是簡(jiǎn)單的MMU的封裝,但我們?cè)诶斫鈱ぶ返母拍畹臅r(shí)候,是可以簡(jiǎn)單這樣認(rèn)為的。
有了頁尋址的概念,進(jìn)程的空間和物理地址看到的空間就很不一樣了:
這樣為前面談到的ia空間和pa空間的不匹配制造不少機(jī)會(huì)。比如32位的處理器,ia空間是32位的,但隨著發(fā)展,內(nèi)存越來越大,超過ia可以尋址的4G的空間了。但我們只要保證頁表中的pa超過32位,我們就可以讓多個(gè)進(jìn)程合起來使用超過4G的物理地址空間。Intel的PAE就是這樣的技術(shù),本質(zhì)上是擴(kuò)展頁表中pa的范圍。
[進(jìn)程的內(nèi)核空間]
所有從進(jìn)程發(fā)出的va訪問,都通過MMU翻譯,包括請(qǐng)求從一個(gè)進(jìn)程切換到另一個(gè)進(jìn)程。這樣一來,進(jìn)程的權(quán)力太大了。所以,還是很自然的,我們?cè)贛MU中可以設(shè)置一個(gè)標(biāo)志,說明某些地址是具有“更高優(yōu)先級(jí)”的,一般情況下不允許訪問,要訪問就要提權(quán),一旦提權(quán),代碼執(zhí)行流就強(qiáng)行切換到這片“高級(jí)內(nèi)存”的特定位置,這樣,就給一個(gè)進(jìn)程指定了兩個(gè)權(quán)限級(jí)別,一個(gè)是所謂的“用戶態(tài)”,一個(gè)是“內(nèi)核態(tài)”,用戶態(tài)用于一般的程序,內(nèi)核態(tài)用來做進(jìn)程的管理。
用戶態(tài)和內(nèi)核態(tài)都在同一個(gè)頁表中管理,所以,本質(zhì)上,它們屬于同一個(gè)進(jìn)程。只是它們屬于進(jìn)程的不同權(quán)限而已。
為了實(shí)現(xiàn)的方便,現(xiàn)在通常讓所有進(jìn)程的MMU頁表的內(nèi)核空間指向物理空間的同一個(gè)位置,這樣,看起來我們就有了一個(gè)獨(dú)立于所有進(jìn)程的實(shí)體,這個(gè)實(shí)體被稱為“操作系統(tǒng)內(nèi)核”,它是管理所有進(jìn)程的一個(gè)中心軟件。
其實(shí)操作系統(tǒng)內(nèi)核并不是必須做成全局唯一的,只是這樣設(shè)計(jì)最方便就是了。
內(nèi)核空間的存在分少了進(jìn)程的可用空間,本來一個(gè)32位進(jìn)程可以用4G的空間的,但由于要留一部分給內(nèi)核用,就不能是4G了。如何切分這個(gè)空間,是一個(gè)設(shè)計(jì)上的權(quán)衡。給用戶空間切少了,作為以用戶程序?yàn)橹行牡牟僮飨到y(tǒng)來說,這影響了競(jìng)爭(zhēng)力。給內(nèi)核空間切少了,內(nèi)核管理上不方便,能力降低?,F(xiàn)在Linux在32位系統(tǒng)上通常使用 3G:1G這樣的切分關(guān)系。
如果是微內(nèi)核操作系統(tǒng),由于內(nèi)核的功能少,這個(gè)比例可以進(jìn)一步降低,比如我們可以留1M給內(nèi)核,其他空間全部留給用戶態(tài)。這也算是微內(nèi)核操作系統(tǒng)的一個(gè)優(yōu)勢(shì)吧。
有人不明白為什么Linux內(nèi)核中需要有Himem這個(gè)概念,這樣一看也很好理解了,內(nèi)核有權(quán)訪問所有內(nèi)存,但它只有1G的虛擬空間,如果你的物理內(nèi)存不到1G,在它1G的va空間內(nèi),它可以對(duì)物理內(nèi)存做一一映射。但如果你的物理內(nèi)存超過1G,這種方法就不可行了,你只能根據(jù)需要把不同的物理內(nèi)存映射進(jìn)來使用。把線性映射的部分分開,不能線性映射的部分,我們就稱為Himem了。線性映射的部分和Himem在什么地方分解,又是一種權(quán)衡。但這種權(quán)衡,老實(shí)說,現(xiàn)在我們已經(jīng)不怎么關(guān)心了,因?yàn)楝F(xiàn)在已經(jīng)切換到64位系統(tǒng),虛擬空間高達(dá)16EB,分給內(nèi)核用綽綽有余(實(shí)際上,現(xiàn)在大部分64位系統(tǒng)的物理地址只有48位),內(nèi)核虛擬地址總是可以線性映射所有的物理地址的。
[ASID]
不知道讀者是否考慮過這個(gè)問題:頁表放在內(nèi)存中,MMU收到一個(gè)地址訪問請(qǐng)求,為了做翻譯,它首先要訪問內(nèi)存,得到對(duì)應(yīng)的翻譯項(xiàng),然后再去訪問內(nèi)存。這是不是表示每個(gè)地址訪問,其實(shí)要訪問兩次內(nèi)存?
訪問內(nèi)存是很慢的,MMU顯然不會(huì)干這種蠢事。所以,它使用了CPU設(shè)計(jì)者的萬能法寶:加個(gè)Cache唄。
MMU的Cache稱為TLB,MMU進(jìn)行翻譯的時(shí)候,首先從TLB里讀頁表項(xiàng),如果頁表項(xiàng)不在TLB中,再讀內(nèi)存,把內(nèi)存中的對(duì)應(yīng)項(xiàng)寫到TLB中,然后在用TLB中的數(shù)據(jù)進(jìn)行翻譯,這樣就不用每次做翻譯都要讀一次內(nèi)存了。
這樣的算法可以得以實(shí)施,取決于一個(gè)現(xiàn)實(shí),稱為程序的局部性原理,即假設(shè)程序在一段時(shí)間內(nèi),訪問的都是特定范圍內(nèi)的內(nèi)存,這樣MMU就不用經(jīng)常重新加載TLB了。
但這個(gè)局部性原理在特定的場(chǎng)景上是不成立的,一種情形是大型數(shù)據(jù)庫。數(shù)據(jù)庫有個(gè)很大的表在內(nèi)存中,經(jīng)常要跨越頁進(jìn)行隨機(jī)訪問,這樣就有很大的機(jī)會(huì)造成TLB失效(這種情形稱為Cache污染),操作系統(tǒng)解決這個(gè)問題的方法常常是使用HugePage,也就是讓特定的頁不止4K,比如可以是256M,這樣,256M的內(nèi)存僅僅需要一個(gè)TLB項(xiàng),甚至可以把這個(gè)TLB項(xiàng)鎖死在TLB中(不允許替換),這樣數(shù)據(jù)庫的性能就可以提高。
第二個(gè)影響局部性原理的場(chǎng)景是微內(nèi)核操作系統(tǒng)。微內(nèi)核操作系統(tǒng)不從內(nèi)核請(qǐng)求操作系統(tǒng)服務(wù)(微內(nèi)核操作系統(tǒng)的內(nèi)核僅僅提供進(jìn)程切換和進(jìn)程間通訊手段),而是直接從另一個(gè)進(jìn)程獲得這個(gè)服務(wù),這大大提高了進(jìn)程切換的頻度。問題是,A進(jìn)程向B進(jìn)程發(fā)出一個(gè)請(qǐng)求,B進(jìn)程1ms就搞定了,又切換回A進(jìn)程。但你切換進(jìn)程,我就得把整個(gè)TLB清掉,所以,為了這個(gè)1ms的請(qǐng)求,MMU就得重新加載進(jìn)程A需要的所有頁表項(xiàng),這個(gè)對(duì)性能的影響也太大了。
解決這個(gè)問題的方法是引入ASID,也就是讓MMU認(rèn)識(shí)進(jìn)程id。所以,在TLB的表項(xiàng)中,每個(gè)項(xiàng)都有一個(gè)ASID,當(dāng)你切換進(jìn)程的時(shí)候,你不需要清空TLB的,B進(jìn)程用不了里面A進(jìn)程的頁表項(xiàng),這樣你切換回A進(jìn)程的時(shí)候就不需要重新加載對(duì)應(yīng)的項(xiàng)了。
ASID這個(gè)概念在我們后面討論IOMMU/SMMU的時(shí)候有特別的作用。
[DMA]
好了,CPU和內(nèi)存的恩怨告一段落了?,F(xiàn)在我們?cè)摽纯赐庠O(shè)了。Intel最早的時(shí)候給了外設(shè)獨(dú)立的地址空間, 要訪問外設(shè)就用io指令,獨(dú)立指定要訪問的地址,和內(nèi)存訪問沒有關(guān)系。但這樣劃分沒有什么意義,所以現(xiàn)代的CPU通常把這兩個(gè)地址空間合并。只是在做頁表映射的時(shí)候,給外設(shè)空間特殊的設(shè)定(比如內(nèi)存讀,如果要求讀一個(gè)字節(jié),我讀64個(gè)字節(jié)也不會(huì)有錯(cuò),但外設(shè)就不行了,所以要進(jìn)行特殊的設(shè)定)。
讀寫外設(shè)空間是個(gè)很慢的動(dòng)作,因?yàn)閺目偩€上發(fā)出一個(gè)讀寫操作,都要等被讀寫一方響應(yīng)的,CPU做了很多優(yōu)化來優(yōu)化內(nèi)存訪問的QoS,但對(duì)外設(shè)是沒有什么辦法的(這玩意兒可以動(dòng)態(tài)插進(jìn)來的,沒法做任何假設(shè)),所以,遇到一個(gè)不好的設(shè)備,進(jìn)行io讀寫,可以導(dǎo)致整個(gè)指令停住不能動(dòng)。
現(xiàn)在更常見的方法是盡量不去碰外設(shè)的IO空間,而是把數(shù)據(jù)放在內(nèi)存中,讓外設(shè)自己去讀。這個(gè)動(dòng)作就稱為DMA,現(xiàn)代SoC中外設(shè)用來訪問內(nèi)存的部件,通常就叫DMA控制器。
早期的外設(shè)通常很簡(jiǎn)陋,它自己的DMA訪問內(nèi)存的總線常常比CPU的物理總線要短。比如你一個(gè)32位的CPU,物理總線是40位,但外設(shè)的DMA就只有16位。這樣如果CPU發(fā)起一個(gè)DMA請(qǐng)求,讓外設(shè)自己去讀一個(gè)超過16位的物理內(nèi)存地址的空間,這個(gè)外設(shè)根本就沒有能力訪問。
為了解決這個(gè)問題,Linux內(nèi)核為驅(qū)動(dòng)提供了DMA專門的內(nèi)存分配函數(shù)。保證你分配的空間在外設(shè)DMA可以訪問的范圍內(nèi)(這就是內(nèi)核分區(qū)ZONE_DMA的由來),這樣,你做DMA就能保證這個(gè)物理地址是可以被外設(shè)訪問到的。
現(xiàn)在的外設(shè)越來越強(qiáng)了,很多外設(shè)的DMA都擁有和CPU一樣長的地址,對(duì)于這樣的設(shè)備,就不需要用那個(gè)分配函數(shù)來解決問題了。
[IOMMU和SMMU]
外設(shè)沒有MMU,所以CPU要提供一個(gè)地址給外設(shè)訪問,必須使用物理地址。但使用物理地址是件很麻煩的事情,因?yàn)樵谔摂M地址上連續(xù)的地址,在物理地址上不一定連續(xù)。
所以,又作為一個(gè)“自然”的想法,有人就考慮把MMU移到設(shè)備DMA上來,這個(gè)概念就是IOMMU(AMD的概念)和SMMU(ARM的概念)了。由于我對(duì)ARM比較熟一點(diǎn),我們用SMMU舉例。
SMMU的原理和MMU一樣,只是作用在設(shè)備一側(cè),SMMU可以復(fù)用MMU的頁表,也可以自己創(chuàng)建頁表。通常我們不會(huì)選擇復(fù)用頁表,因?yàn)镾MMU是針對(duì)每個(gè)設(shè)備的,我們顯然希望設(shè)備只看到CPU希望給它看到的空間,而不是所有空間,否則一不小心我們插一個(gè)黑客設(shè)備進(jìn)來,整個(gè)操作系統(tǒng)就暴露了。
有了SMMU,我們對(duì)外設(shè)做DMA請(qǐng)求,就不需要使用物理地址了,使用和進(jìn)程一樣的虛擬地址就可以了。只要保證SMMU的頁表中對(duì)應(yīng)的設(shè)置和進(jìn)程一致就行。Linux內(nèi)核中做DMA請(qǐng)求之前,要求做dma_map,就是為了完成SMMU的對(duì)應(yīng)設(shè)置。
實(shí)際上,SMMU的問題比MMU的問題復(fù)雜??紤]這么一種情況:進(jìn)程A發(fā)起一個(gè)DMA請(qǐng)求,我們把這個(gè)頁表項(xiàng)放到設(shè)備的SMMU上了,現(xiàn)在CPU切換到進(jìn)程B,CPU的頁表變了,但設(shè)備不知道啊,設(shè)備還是向當(dāng)初的虛擬地址上寫。這時(shí)進(jìn)程B又發(fā)起一個(gè)DMA請(qǐng)求,在同一個(gè)虛擬地址上要求做DMA,設(shè)備不是暈菜了?
為了解決這個(gè)問題,那個(gè)ASID又被撿起來了,SMMU的頁表中帶上ASID,這樣,CPU一個(gè)時(shí)刻只有一個(gè)進(jìn)程的頁表在用,而設(shè)備卻同時(shí)用著好多的頁表。
[兩層MMU和SMMU]
MMU和SMMU的概念在虛擬化時(shí)代繼續(xù)進(jìn)行著演進(jìn)。如果用戶程序運(yùn)行在虛擬機(jī)中會(huì)怎么樣?ARMv7/v8提供兩層地址映射,虛擬機(jī)中的程序發(fā)出一個(gè)va,第一次翻譯為ipa(中間pa),如果下面是虛擬機(jī)創(chuàng)建的,虛擬機(jī)也可以給MMU/SMMU指定一個(gè)頁表,說明ipa如何翻譯為pa。這樣,虛擬機(jī)的效率就提高了,硬件就認(rèn)知了虛擬機(jī)的概念。va一次使用兩層的頁表,直接得到pa。這種情況下,實(shí)際上就有進(jìn)程,Hypervisor和物理三個(gè)地址空間了。
問題是,如果我要在虛擬機(jī)里面再跑一個(gè)虛擬機(jī)怎么辦呢?這個(gè)方案也在做。顯然我們不能無限增加MMU/SMMU的翻譯層數(shù)了,所以就只能在Hypervisor的調(diào)度上下功夫,虛擬機(jī)的頁表根據(jù)Hypervisor的調(diào)度進(jìn)行動(dòng)態(tài)的切換。類似這樣:
[從設(shè)備側(cè)發(fā)起缺頁]
設(shè)備使用虛擬地址,又再帶來一個(gè)問題,根據(jù)現(xiàn)代操作系統(tǒng)的管理方式,虛擬地址很可能是沒有分配物理空間的,在CPU一側(cè)如果發(fā)生這種事情,就通過缺頁例程來解決。但在設(shè)備側(cè)怎么辦呢?
一種簡(jiǎn)單的方法是發(fā)起DMA前,把虛擬空間先pin死到物理內(nèi)存中。
但這樣是有缺點(diǎn)的,因?yàn)槿绻淮笃瑑?nèi)存給了設(shè)備,設(shè)備只需要一頭一尾兩頁的內(nèi)存呢?那我不是白干了?
所以,更好的辦法是讓設(shè)備也有缺頁的能力。但設(shè)備缺頁是比CPU缺頁復(fù)雜的。CPU缺頁你只要在缺頁中斷中把頁加載進(jìn)來。但設(shè)備缺頁,設(shè)備可沒有能把缺掉的頁加載進(jìn)來。所以,CPU上需要一個(gè)代理(在PCIE的ATS標(biāo)準(zhǔn)中稱為TA,轉(zhuǎn)換代理),設(shè)備上進(jìn)行頁面轉(zhuǎn)換的裝置(稱為ATC,地址轉(zhuǎn)化客戶端)在發(fā)現(xiàn)缺頁的時(shí)候,通過對(duì)TA發(fā)送缺頁信息,讓TA通知CPU產(chǎn)生設(shè)備缺頁中斷,然后把對(duì)應(yīng)的LTB項(xiàng)發(fā)送給ATC,才能繼續(xù)下去。
x86在Linux中加入svm框架來處理這個(gè)過程(參考Linux內(nèi)核代碼中的driver/iommu/intel-svm.c),ARM也在準(zhǔn)備合入到這個(gè)框架中(參考:
http://www.spinics.net/lists/linux-pci/msg58650.html)。其實(shí)SVM是個(gè)比較容易搞定的事情,這個(gè)設(shè)計(jì)的主要難度在總線系統(tǒng)上,CPU的缺頁到異常的過程幾乎是原子或者同步的,但如果總線系統(tǒng)要經(jīng)過幾次消息交換來完成這個(gè)過程,就有很多出錯(cuò)的機(jī)會(huì)了。。
[統(tǒng)一內(nèi)存模型]
把上面的考慮綜合在一起,我們發(fā)現(xiàn)我們逐步走向一種“全局地址”的內(nèi)存模型了,也就是說,要加工的數(shù)據(jù),統(tǒng)統(tǒng)放在內(nèi)存里,CPU來動(dòng)一部分,GPU來動(dòng)一部分,F(xiàn)PGA來動(dòng)一部分,硬加速加速器來動(dòng)一部分。
這個(gè)設(shè)計(jì),就叫“統(tǒng)一內(nèi)存模型”,ARM聯(lián)盟的CCIX,HPE的Gen-Z,現(xiàn)在都在為最終的這種模型填磚加瓦,這也是我們未來追求的統(tǒng)一異構(gòu)計(jì)算的軟件模型。
所謂CCIX,其實(shí)是是PCIE的一個(gè)變種,PCIE總線的協(xié)議棧分4層,應(yīng)用,會(huì)話,鏈路和物理。CCIX替換了其中的應(yīng)用層和部分的會(huì)話層,實(shí)現(xiàn)可以深度不是那么深,但對(duì)于內(nèi)存是Cache Coherence的高速外設(shè)總線。從而讓基于CCIX的外設(shè)可以用更方便簡(jiǎn)單的方法修改加入內(nèi)存的協(xié)同訪問中。
而Gen-Z,是通過一個(gè)Fabric訪問更大的,非CC的內(nèi)存,讓全局的系統(tǒng)可以訪問到更大的內(nèi)存空間(比如256T)。
[小結(jié)]
我們這個(gè)文檔,我用得最多的一個(gè)描述,可能是“很自然……”,所以,說“道法自然”,確實(shí)是有事實(shí)依據(jù)的:)