免费色播,亚洲国产欧美国产第一区二区三区,毛片看,日本精品在线观看视频,国产成人精品一区二区免费视频,日本黄色免费网站,一级毛片免费

探秘X86架構(gòu)CPU流水線

來源:網(wǎng)絡(luò)

點(diǎn)擊:1472

A+ A-

所屬頻道:新聞中心

關(guān)鍵詞: X86架構(gòu),CPU

      作為程序員,CPU 在我們的工作中扮演了核心角色,因此了解處理器內(nèi)部的工作方式對(duì)程序員來說不無裨益。

      CPU 是如何工作的呢?一條指令執(zhí)行需要多長時(shí)間?當(dāng)我們討論某個(gè)新款處理器擁有 12 級(jí)流水線還是 18 級(jí)流水線,甚至是更深的 31 級(jí)流水線時(shí),這到些都意味著什么呢?

      應(yīng)用程序通常會(huì)將 CPU 看作是黑盒子。程序中的指令按照順序依次進(jìn)入 CPU,執(zhí)行完之后再按順序依次從 CPU 中出來,而內(nèi)部到底發(fā)生了什么,我們通常并不了解。

      對(duì)我們程序員來說,尤其是對(duì)做程序性能調(diào)優(yōu)工作的程序員來說,學(xué)習(xí) CPU 內(nèi)部的細(xì)節(jié)非常必要。否則,如果你不知道 CPU 的內(nèi)部結(jié)構(gòu),那如何才能針對(duì) CPU 做性能優(yōu)化?

      本文所關(guān)注的就是專門針對(duì) X86 處理器流水線的工作原理。

      你需要掌握的預(yù)備知識(shí)

      首先,閱讀本文你需要了解編程,最好了解一點(diǎn)匯編語言。如果你還不知道指令指針(instruction pointer)是什么,那么本文對(duì)你來說可能有些難。你需要知道什么是寄存器,指令和緩存,如果不明白它們是什么,你需要盡快查找資料了解一下。

      第二,CPU 的工作原理是一個(gè)非常龐大和復(fù)雜的話題,本文僅僅是匆匆一瞥,很難以用一篇文章詳盡敘述。如果我有什么疏漏,請(qǐng)通過評(píng)論告訴我。

      第三,我僅僅關(guān)注英特爾處理器及其 X86 架構(gòu)。當(dāng)然除了 X86,還有很多其他架構(gòu)的處理器。雖然 AMD 公司引入了很多新特性到 X86 架構(gòu),但是 X86 架構(gòu)是 Intel 公司發(fā)明,并且創(chuàng)造了 X86 指令集,其中絕大多數(shù)特性是由 Intel 引入的。所以為了保持?jǐn)⑹龅暮唵魏鸵恢滦裕覂H關(guān)注 Intel 的處理器。

      最后,當(dāng)你讀到這篇文章時(shí),它已經(jīng)是過時(shí)的了。更新款的處理器已經(jīng)設(shè)計(jì)出來,其中一些會(huì)在未來幾個(gè)月之內(nèi)發(fā)布。我很高興技術(shù)能如此快速的發(fā)展,我希望有一天所有這些技術(shù)都會(huì)過時(shí),創(chuàng)造出擁有更驚人計(jì)算能力的 CPU.

      處理器流水線基礎(chǔ)

      從一個(gè)非常廣的角度來說,X86 處理器架構(gòu)在近 35 年來并沒有變化太多。雖然 X86 架構(gòu)被附加了很多新功能,但是最初的設(shè)計(jì)(包括幾乎所有最初的指令集)仍然基本上是完整保留的,即使在最新的處理器上仍然被支持。

      最初的 8086 處理器支持 14 個(gè)寄存器,這些寄存器在如今最新的處理器中仍然存在。這 14 個(gè)寄存器中,有 4 個(gè)是通用寄存器:AX,BX,CX 和 DX;有 4 個(gè)是段寄存器,段寄存器用來輔助指針的實(shí)現(xiàn):代碼段(CS),數(shù)據(jù)段(DS),擴(kuò)展段(ES)和堆棧段(SS);有 4 個(gè)是索引寄存器,用來指向內(nèi)存地址:源引用(SI),目的引用(DI),基指針(BP),棧指針(SP);有 1 個(gè)寄存器包含狀態(tài)位;最后是最重要的寄存器:指令指針(IP)。

      指令指針寄存器是一個(gè)擁有特殊功能的指針。指令指針的功能是指向?qū)⒁\(yùn)行的下一條指令。

      所有的 X86 處理器都按照相同的模式運(yùn)行。首先,根據(jù)指令指針指向的地址取得下一條即將運(yùn)行的指令并解析該指令(譯碼)。在譯碼完成后,會(huì)有一個(gè)指令的執(zhí)行階段。有些指令用來從內(nèi)存讀取數(shù)據(jù)或者向內(nèi)存寫數(shù)據(jù),有些指令用來執(zhí)行計(jì)算或者比較等工作。當(dāng)指令執(zhí)行完成后,這條指令會(huì)通過退出(retire)階段并將指令指針修改為下一條指令。

      譯碼,執(zhí)行和退出三級(jí)流水線組成了 X86 處理器指令執(zhí)行的基本模式。從最初的 8086 處理器到最新的酷睿 i7 處理器都基本遵循了這樣的過程。雖然更新的處理器增加了更多的流水級(jí),但基本的模式?jīng)]有改變。

      35 年來發(fā)生了什么改變

      相較于現(xiàn)今的標(biāo)準(zhǔn),最初的處理器設(shè)計(jì)顯得太過簡單。最初的 8086 處理器的執(zhí)行過程可以簡述為從當(dāng)前指令指針取得指令,通過譯碼,執(zhí)行最后退出,然后繼續(xù)從指令指針指向的下一條指令處取得指令。

      新的處理器增加了新的功能,有些增加了新的指令,有些增加了新的寄存器。我將主要關(guān)注和本文主題有關(guān)系的改變,這些改變影響了 CPU 指令執(zhí)行的流程。其他的一些變化比如虛擬內(nèi)存或者并行處理雖然都很有意義而且有趣,但是并不在本文主題的范圍內(nèi)。

      指令緩存在 1982 年被加入到處理器中。通過指令緩存,處理器可以一次性從內(nèi)存讀取更多指令并放在指令緩存中,而不用每條指令都從內(nèi)存中取。指令緩存僅有幾個(gè)字節(jié)大小,只能容納數(shù)條指令,但是因?yàn)橄酥竺看稳≈竿祪?nèi)存和處理器的時(shí)間,極大的提高的效率

      1985 年的 386 處理器引入了數(shù)據(jù)緩存,而且擴(kuò)展了指令緩存的設(shè)計(jì)。數(shù)據(jù)訪存請(qǐng)求通過一次性讀取更多的數(shù)據(jù)放在數(shù)據(jù)緩存中,從而提升了性能。而且,數(shù)據(jù)緩存和指令緩存都從幾個(gè)字節(jié)擴(kuò)大到幾千字節(jié)。

      19巴久年推出的 i486 處理器引入了五級(jí)流水線。這時(shí),在 CPU 中不再僅運(yùn)行一條指令,每一級(jí)流水線在同一時(shí)刻都運(yùn)行著不同的指令。這個(gè)設(shè)計(jì)使得 i486 比同頻率的 386 處理器性能提升了不止一倍。五級(jí)流水線中的取指階段將指令從指令緩存中取出(i486 中的指令緩存為 8KB);第二級(jí)為譯碼階段,將取出的指令翻譯為具體的功能操作;第三級(jí)為轉(zhuǎn)址階段,用來將內(nèi)存地址和偏移進(jìn)行轉(zhuǎn)換;第四級(jí)為執(zhí)行階段,指令在該階段真正執(zhí)行運(yùn)算;第五級(jí)為退出階段,運(yùn)算的結(jié)果被寫回寄存器或者內(nèi)存。由于處理器同時(shí)運(yùn)行了多條指令,大大提升了程序運(yùn)行的性能。

      1993 年 Intel 推出了奔騰(Pentium)處理器。由于訴訟問題,Intel 無法繼續(xù)沿用原來的數(shù)字編號(hào)。因此,用奔騰替代了 586 作為新款處理器的代號(hào)。奔騰處理器相對(duì) i486 處理器對(duì)流水線做出了更多修改。奔騰處理器架構(gòu)增加了第二條獨(dú)立的超標(biāo)量流水線。主流水線工作方式類似于 i486,第二條流水線則并行的運(yùn)行一些較簡單的指令,比如說定點(diǎn)算術(shù),而且該流水線能更快的進(jìn)行該運(yùn)算。

      1995 年 Intel 推出了奔騰 Pro (Pentium Pro)處理器。和之前的處理器相比,奔騰 Pro 采用了完全不同的設(shè)計(jì)。該處理器采用了諸多新特性以提高性能,包括亂序(Out-of-Order, OOO)執(zhí)行的部件以及猜測(cè)執(zhí)行。流水線擴(kuò)展到了 12 級(jí),而且引入了“超標(biāo)量流水線”的概念,使得許多指令可以被同時(shí)處理。我們稍后將詳盡的介紹亂序執(zhí)行的部件。

      在 1995-2002 年之間,亂序執(zhí)行部件經(jīng)過了數(shù)次重大改進(jìn)。處理器中加入了更多的寄存器;單指令多數(shù)據(jù)(Single Instruction Multiple Data, or SIMD)的引入使得一條指令可以進(jìn)行多組數(shù)據(jù)運(yùn)算;現(xiàn)有的緩存變得更大而且引入了新的緩存;有些流水級(jí)被拆分成更多流水級(jí),有些流水級(jí)被合并,使得更加適合實(shí)際的應(yīng)用。這些改變對(duì)整體性能的提升有重要作用,但它們都沒有從根本影響數(shù)據(jù)在處理器中的流動(dòng)方式。

      2002 年發(fā)布的奔騰 4 處理器引入了超線程技術(shù)。亂序執(zhí)行部件的設(shè)計(jì)使得指令被執(zhí)行的速度比處理器能夠提供指令的速度更快。因此對(duì)于大部分應(yīng)用,CPU 的亂序執(zhí)行部件在大部分時(shí)間處于空閑狀態(tài),甚至在高負(fù)載的情況下也不能充分利用。為了讓指令流能充分的流入亂序執(zhí)行部件,Intel 加入了第二套前端部件(譯注:在處理器結(jié)構(gòu)中,前端是指取指,譯碼,寄存器重命名等模塊,經(jīng)過前端部件的處理后,指令等待發(fā)射進(jìn)入亂序執(zhí)行部件)。雖然實(shí)際上只有一個(gè)亂序執(zhí)行部件,但對(duì)于操作系統(tǒng)來說,它能看到兩個(gè)處理器。前端部件包含兩組同樣功能的 X86 寄存器,兩個(gè)指令譯碼器根據(jù)兩個(gè)指令指針指向的地址分別處理。所有的指令被一個(gè)共享的亂序執(zhí)行部件執(zhí)行,但對(duì)應(yīng)用程序來說并不知情。當(dāng)亂序執(zhí)行部件執(zhí)行完成,像之前一樣退出流水線后,最終結(jié)果返回虛擬的兩個(gè)處理器。

      2006 年 Intel 發(fā)布了酷睿(Core)微架構(gòu)。為了品牌效應(yīng),它被稱做酷睿2(二總比一好)。令人驚訝的是,處理器頻率不升反降,而且超線程也被去掉了。通過降低時(shí)鐘頻率,每一級(jí)流水線可以做更多工作。亂序執(zhí)行部件也被擴(kuò)展的更寬。各種不同的緩存和隊(duì)列都相應(yīng)做的更大。而且處理器被重新設(shè)計(jì),以適應(yīng)雙核和四核的共享緩存結(jié)構(gòu)。

      2008 年,Intel 開始用酷睿 i3, i5, i7 的方式來命名新的處理器。新處理器重新引入了超線程。這三個(gè)系列的處理器主要區(qū)別在于內(nèi)部緩存大小不同。

      未來的處理器:Intel 的下一代微結(jié)構(gòu)被稱為 Haswell.Haswell 據(jù)稱將于 2013 年發(fā)布。目前已知的文檔說明它將擁有 14 級(jí)流水級(jí)的亂序執(zhí)行部件,所以它仍然遵循從奔騰 Pro 以來的基本設(shè)計(jì)思路。

      那么,流水線到底是什么?亂序執(zhí)行部件是什么?他們?nèi)绾翁嵘颂幚砥鞯男阅苣兀?/span>

      CPU 指令流水線

      根據(jù)之前描述的基礎(chǔ),指令進(jìn)入流水線,通過流水線處理,從流水線出來的過程,對(duì)于我們程序員來說,是比較直觀的。

      I486 擁有五級(jí)流水線。分別是:取指(Fetch),譯碼(D1, main decode),轉(zhuǎn)址(D2, translate),執(zhí)行(EX, execute),寫回(WB)。某個(gè)指令可以在流水線的任何一級(jí)。

    探秘X86架構(gòu)CPU流水線

      但是這樣的流水線有一個(gè)明顯的缺陷。對(duì)于下面的指令代碼,它們的功能是將兩個(gè)變量的內(nèi)容進(jìn)行交換。

      XOR a, b

      XOR b, a

      XOR a, b

      從 8086 直到 386 處理器都沒有流水線。處理器一次只能執(zhí)行一條指令。再這樣的架構(gòu)下,上面的代碼執(zhí)行并不會(huì)存在問題。

      但是 i486 處理器是首個(gè)擁有流水線的 x86 處理器,它執(zhí)行上面的代碼會(huì)發(fā)生什么呢?當(dāng)你一下去觀察很多指令在流水線中運(yùn)行,你會(huì)覺得混亂,所以你需要回頭參考上面的圖。

      第一步是第一條指令進(jìn)入取指階段;然后在第二步第一條指令進(jìn)入譯碼階段,同時(shí)第二條指令進(jìn)入取指階段;第三步第一條指令進(jìn)入轉(zhuǎn)址階段,第二條指令進(jìn)入譯碼階段,第三條指令進(jìn)入取指階段。但是在第四步會(huì)出現(xiàn)問題,第一條指令會(huì)進(jìn)入執(zhí)行階段,而其他指令卻不能繼續(xù)向前移動(dòng)。第二條 xor 指令需要第一條 xor 指令計(jì)算的結(jié)果a,但是直到第一條指令執(zhí)行完成才會(huì)寫回。所以流水線的其他指令就會(huì)在當(dāng)前流水級(jí)等待直到第一條指令的執(zhí)行和寫回階段完成。第二條指令會(huì)等待第一條指令完成才能進(jìn)入流水線下一級(jí),同樣第三條指令也要等待第二條指令完成。

      這個(gè)現(xiàn)象被稱為流水線阻塞或者流水線氣泡。

      另外一個(gè)關(guān)于流水線的問題是有些指令執(zhí)行速度快,有些指令執(zhí)行速度慢。這個(gè)問題在奔騰處理器的雙流水線架構(gòu)下顯得更加明顯。

      奔騰 Pro 擁有 12 級(jí)流水線。當(dāng)這個(gè)數(shù)字被首次宣布后,所有的程序員都倒抽了一口氣,因?yàn)樗麄冎莱瑯?biāo)量流水線是如何工作的。如果 Intel 仍然按照以前的思路設(shè)計(jì)超標(biāo)量流水線的話,流水線的阻塞和執(zhí)行速度慢的指令會(huì)嚴(yán)重影響執(zhí)行速度。但同時(shí),Intel 宣布了完全不同的流水線設(shè)計(jì),叫做亂序執(zhí)行部件(Out-of-Order core)。單從敘述上很難理解這些改變帶來的好處,但 Intel 確信這些改進(jìn)是令人激動(dòng)的。

      讓我們來更深入的看看這個(gè)亂序執(zhí)行的部件吧!

      亂序執(zhí)行流水線

      在描述亂序執(zhí)行流水線時(shí),往往是一圖勝千言。所以我們主要以圖例進(jìn)行介紹。

      CPU 流水線圖例

      I486 處理器擁有 5 級(jí)流水線。這種設(shè)計(jì)在現(xiàn)實(shí)世界中的其他處理器中很常見,而且效率不錯(cuò)。

    探秘X86架構(gòu)CPU流水線

      而奔騰處理器的流水線比 i486 更好。兩條流水線可以并行運(yùn)行,而且每條流水線可以同時(shí)有多條指令在不同流水級(jí)執(zhí)行。它幾乎可以同時(shí)執(zhí)行比 i486 多一倍的指令。

    探秘X86架構(gòu)CPU流水線

      能夠快速完成的指令需要等待前面執(zhí)行慢的指令即使在并行流水線中也仍然是一個(gè)問題。流水線仍然是線性的,導(dǎo)致處理器面臨性能瓶頸難以逾越。

      亂序執(zhí)行部件和之前處理器設(shè)計(jì)中的線性通路有很大不同,它增加了一些復(fù)雜度,引入了非線性的通路。

    探秘X86架構(gòu)CPU流水線

      第一個(gè)改變是指令從內(nèi)存中取到處理器的指令緩存的過程?,F(xiàn)代處理器能夠檢測(cè)何時(shí)會(huì)產(chǎn)生一個(gè)大的分支跳轉(zhuǎn)(比如函數(shù)調(diào)用),然后提前將跳轉(zhuǎn)目的地的指令加載到指令緩存中。

      譯碼級(jí)有一些略微的修改。不同于以往處理器僅僅譯碼指令指針指向的指令,奔騰 Pro 處理器每一個(gè)時(shí)鐘周期最多能譯碼 3 條指令。現(xiàn)今的處理器(2008-2013 年)每個(gè)時(shí)鐘周期最多可以譯碼 4 條指令。譯碼過程產(chǎn)生很多小片的操作,被稱作微指令(micro-ops, ?-ops)。

      下一級(jí)(或者好幾級(jí))被稱為微指令翻譯,接著是寄存器重命名(register aliasing)。許多操作同時(shí)執(zhí)行,并且執(zhí)行的順序是亂序的,所以有可能出現(xiàn)一條指令讀一個(gè)寄存器的同時(shí),另外一條指令正在對(duì)這個(gè)寄存器進(jìn)行寫操作。在處理器內(nèi)部,這些原始的寄存器(如 AX,BX,CX,DX 等)被翻譯(或者重命名)成為內(nèi)部的寄存器,而這些寄存器對(duì)程序員是不可見的。寄存器和內(nèi)存地址需要被映射到一個(gè)臨時(shí)的地方用于指令執(zhí)行。當(dāng)前每個(gè)始終周期可以翻譯 4 條微指令。

      當(dāng)微指令翻譯完成后,它們會(huì)進(jìn)入一個(gè)重排序緩存(Reorder Buffer, ROB),ROB 可以存儲(chǔ)最多 128 條微指令。在支持超線程的處理器上,ROB 同樣可以重排來自兩個(gè)虛擬處理器的指令。兩個(gè)虛擬處理器在 ROB 中將微指令匯集到一個(gè)共享的亂序執(zhí)行部件中。

      這些微指令已經(jīng)準(zhǔn)備好可以執(zhí)行了。它們被放在保留站中(Reservation Station, RS)。RS 最多可以同時(shí)存儲(chǔ) 36 條微指令。

      現(xiàn)在才開始亂序執(zhí)行部件神奇的部分。不同的微指令在不同的執(zhí)行單元中同時(shí)執(zhí)行,而且每個(gè)執(zhí)行單元都全速運(yùn)行。只要當(dāng)前微指令所需要的數(shù)據(jù)就緒,而且有空閑的執(zhí)行單元,微指令就可以立即執(zhí)行,有時(shí)甚至可以跳過前面還未就緒的微指令。通過這種方式,需要長時(shí)間運(yùn)行的操作不會(huì)阻塞后面的操作,流水線阻塞帶來的損失被極大的減小了。

      奔騰 Pro 的亂序執(zhí)行部件擁有 6 個(gè)執(zhí)行單元:兩個(gè)定點(diǎn)處理單元,一個(gè)浮點(diǎn)處理單元,一個(gè)取數(shù)單元,一個(gè)存地址單元,一個(gè)存數(shù)單元。這兩個(gè)定點(diǎn)處理單元有所不同,一個(gè)能夠處理復(fù)雜定點(diǎn)操作,一個(gè)能同時(shí)處理兩個(gè)簡單操作。在理想狀況下,奔騰 Pro 的亂序執(zhí)行部件可以在一個(gè)時(shí)鐘周期內(nèi)執(zhí)行 7 條微指令。

      現(xiàn)今的亂序執(zhí)行部件仍然擁有 6 個(gè)執(zhí)行單元。其中取數(shù)單元,存地址單元,存數(shù)單元沒有變,另外 3 個(gè)多少發(fā)生了變化。這三個(gè)執(zhí)行單元都可以執(zhí)行基本算術(shù)運(yùn)算,或者執(zhí)行更復(fù)雜的微指令。但每個(gè)執(zhí)行單元擅長執(zhí)行不同種類的微指令,使得它們能更高效的執(zhí)行運(yùn)算。在理想狀況下,現(xiàn)今的亂序執(zhí)行部件可以在一個(gè)時(shí)鐘周期內(nèi)執(zhí)行 11 條微指令。

      最終微指令會(huì)得到執(zhí)行,在經(jīng)過數(shù)個(gè)流水級(jí)之后,最終會(huì)退出流水線。這時(shí),這條指令完成并且遞增指令指針。但從程序員的角度來說,指令僅僅是從一端進(jìn)入 CPU,從另一端退出,就像老的 8086 一樣。

      如果你仔細(xì)看過上面的內(nèi)容,你會(huì)注意到上面提到過很重要的一個(gè)問題:如果執(zhí)行指令的位置發(fā)生了跳轉(zhuǎn)會(huì)發(fā)生什么?例如,當(dāng)指令運(yùn)行到“if”或者是“switch”時(shí),會(huì)發(fā)生什么呢?在較老的處理器中這意味著清空流水線,等待新的跳轉(zhuǎn)目的指令的取指執(zhí)行。

      當(dāng) CPU 指令隊(duì)列中存儲(chǔ)了超過 100 條指令時(shí),發(fā)生流水線阻塞帶來的性能損失是極其嚴(yán)重的。所有的指令都需要等待跳轉(zhuǎn)目的的指令取回并且重啟流水線。在這種情況下,亂序執(zhí)行部件需要將跳轉(zhuǎn)指令之后但是已經(jīng)執(zhí)行的微指令全部取消掉,返回到執(zhí)行前的狀態(tài)。當(dāng)所有亂序執(zhí)行的微指令都退出亂序執(zhí)行部件之后,將它們丟棄掉,然后從新的地址開始執(zhí)行。這對(duì)于處理器來說是相當(dāng)困難的,而且發(fā)生的頻率很高,因此對(duì)性能的影響很大。這時(shí),引入了亂序執(zhí)行部件的另外一個(gè)重要功能。

      答案就是猜測(cè)執(zhí)行。猜測(cè)執(zhí)行意味著當(dāng)遇到一個(gè)分支指令后,亂序執(zhí)行部件會(huì)將所有分支的指令都執(zhí)行一遍。一旦分支指令的跳轉(zhuǎn)方向確定后,錯(cuò)誤跳轉(zhuǎn)方向的指令都將被丟棄。通過同時(shí)執(zhí)行兩個(gè)跳轉(zhuǎn)方向的指令,避免了由于分支跳轉(zhuǎn)導(dǎo)致的阻塞。處理器設(shè)計(jì)者還發(fā)明了分支預(yù)測(cè)緩存,當(dāng)面臨多個(gè)分支時(shí)進(jìn)行預(yù)測(cè),進(jìn)一步提高了性能。雖然 CPU 阻塞仍然會(huì)發(fā)生,但是這個(gè)解決方案將 CPU 發(fā)生阻塞的概率降到了一個(gè)可以接受的范圍。

      最后,擁有超線程的處理器將兩個(gè)虛擬的處理器暴露給共享的亂序執(zhí)行部件。它們共享一個(gè)重排序緩存和亂序執(zhí)行部件,讓操作系統(tǒng)認(rèn)為它們是兩個(gè)獨(dú)立的處理器,看上去就像這樣:

    探秘X86架構(gòu)CPU流水線

      超線程的處理器擁有兩個(gè)虛擬的處理器,從而可以給亂序執(zhí)行部件提供更多的數(shù)據(jù)。超線程對(duì)一般的應(yīng)用程序都有性能提升,但是對(duì)一些計(jì)算密集型的應(yīng)用,則會(huì)迅速使得亂序執(zhí)行部件飽和。在這種情況下,超線程反而會(huì)略微降低性能。但這種情況畢竟是少數(shù),超線程對(duì)于日常應(yīng)用來講通常都能夠提供大約一倍的性能。

      一個(gè)示例

      這一切看上去有點(diǎn)令人感到困惑,那么我們舉一個(gè)例子來讓這一切變得清晰起來。

      從應(yīng)用程序的角度來看,我們?nèi)匀皇沁\(yùn)行在指令流水線上,就想老的 8086 處理器那樣。處理器就是一個(gè)黑盒子。黑盒子會(huì)處理指令指針指向的指令,當(dāng)處理完之后,會(huì)在內(nèi)存里找到處理的結(jié)果。

      但是從指令本身的角度來講,這個(gè)過程可謂歷經(jīng)滄桑。我們下面介紹對(duì)于現(xiàn)今的處理器(大約在 2008-2013 年之間),一條指令在其內(nèi)部的過程。

      首先,你是一條指令,你所屬的程序正在運(yùn)行。

      你一直在耐心的等待指令指針會(huì)指向自己,等待被 CPU 運(yùn)行。當(dāng)指令指針距離你還有 4KB 遠(yuǎn)的時(shí)候(這大約是 1500 條指令),你被 CPU 從內(nèi)存取到指令緩存中。雖然從內(nèi)存加載進(jìn)入指令緩存需要一段時(shí)間,但是現(xiàn)在距離你被執(zhí)行的時(shí)刻還很遠(yuǎn),你有足夠的時(shí)間。這個(gè)預(yù)取的過程屬于流水線的第一級(jí)。

      當(dāng)指令指針離你越來越近,距離你還有 24 條指令的時(shí)候,你和你旁邊的 5 個(gè)指令會(huì)被放到指令隊(duì)列里面。

      這個(gè)處理器有 4 個(gè)譯碼器,可以容納一個(gè)復(fù)雜指令和最多三個(gè)簡單指令。你碰巧是一條復(fù)雜指令,通過譯碼,你被翻譯成 4 個(gè)微指令。

      譯碼的過程可以劃分為多步。譯碼過程中的一步是檢查你需要的數(shù)據(jù)和猜測(cè)你可能會(huì)產(chǎn)生一個(gè)地址跳轉(zhuǎn)。譯碼器一旦檢測(cè)到需要的額外數(shù)據(jù),不需要讓你知道,這個(gè)數(shù)據(jù)就開始從內(nèi)存加載到數(shù)據(jù)緩存中了。

      你的四個(gè)微指令到達(dá)寄存器重命名表。你告訴它你需要讀哪個(gè)內(nèi)存地址(比如說 fs:[eax+18h]),然后寄存器重命名表將這個(gè)地址轉(zhuǎn)換為臨時(shí)地址供微指令使用。地址轉(zhuǎn)化完成后,你的微指令將進(jìn)入重排序緩存(Reorder Buffer, ROB)并記錄指令次序。接著第一時(shí)間進(jìn)入保留站(Reservation Station, RS)。

      保留站用于存儲(chǔ)已經(jīng)準(zhǔn)備就緒可以執(zhí)行的指令。你的第三條微指令被立即選中并送往端口5,這個(gè)端口直接執(zhí)行運(yùn)算。但是你并不知道為什么它會(huì)被首先選中,無論如何,它確實(shí)被執(zhí)行了。幾個(gè)時(shí)鐘周期之后你的第一條微指令前往端口2,該端口是讀單元(Load Address地址 execution unit)。剩余的微指令一直等待,同時(shí)各個(gè)端口正在收集不同的微指令。他們都在等待端口 2 將數(shù)據(jù)從緩存和內(nèi)存中加載進(jìn)來并放在臨時(shí)存儲(chǔ)空間內(nèi)。

      他們等了很久……

      相當(dāng)久的時(shí)間……

      不過在他們等待第一條微指令返回?cái)?shù)據(jù)的時(shí)候,又有其他的新指令又進(jìn)來。好在處理器知道如何讓這些指令亂序執(zhí)行(即后到達(dá)保留站的微指令被優(yōu)先執(zhí)行)。

      當(dāng)?shù)谝粭l微指令返回了數(shù)據(jù),剩余的兩條微指令被立即送往執(zhí)行端口 0 和1.現(xiàn)在這 4 條微指令都已經(jīng)運(yùn)行,最終它們會(huì)返回保留站。

      這些微指令返回后交出他們的“票”并給出各自的臨時(shí)地址。通過這些地址,你作為一個(gè)完整的指令,將他們合并。最后 CPU 將結(jié)果交給你并使你退出

      當(dāng)你到達(dá)標(biāo)有“退出”的門的時(shí)候,你會(huì)發(fā)現(xiàn)這里要排一個(gè)隊(duì)列。你進(jìn)入后發(fā)現(xiàn)你剛好站在你前面進(jìn)來指令的后面,即使執(zhí)行中的順序可能已經(jīng)不同,但你們退出的順序繼續(xù)保持一致。看來亂序執(zhí)行部件真正知道自己做了什么。

      每條指令最終離開 CPU,每次一條指令,就和指令指針指向的順序一樣!

      結(jié)論

      希望這篇小文能夠給讀者展示一些處理器工作的奧秘,要知道,這并不是魔術(shù)。

      讓我們回到最初的問題,現(xiàn)在我們應(yīng)該可以給出一些較好的答案了。

      處理器內(nèi)部是如何工作的呢?在這個(gè)復(fù)雜的過程中,指令首先被分解為更小的微指令命令,這些微指令以亂序的方式盡可能快的被執(zhí)行,然后按照原始的順序提交執(zhí)行結(jié)果。因此,從外部看來,所有的指令都是按照順序的方式執(zhí)行的。但是現(xiàn)在我們知道,處理器內(nèi)部是以亂序的方式處理指令的,有時(shí)甚至以猜測(cè)的方式來運(yùn)行分支代碼。

      運(yùn)行一條指令究竟需要多長時(shí)間呢?對(duì)于沒有使用流水線技術(shù)的處理器來說,這是一個(gè)容易回答的問題,但對(duì)于現(xiàn)代的處理器來說,一條指令的執(zhí)行時(shí)間與它周圍指令的內(nèi)容以及臨近 cache 的大小和內(nèi)容都有關(guān)。一條指令通過處理器有一個(gè)最小的時(shí)間,但只能粗略的說這個(gè)時(shí)間是恒定的。一個(gè)好的程序員和編譯器可以讓很多條指令同時(shí)運(yùn)行,從而使每條指令的分?jǐn)倳r(shí)間幾乎為零。這里說的幾乎為零的執(zhí)行時(shí)間并不是指一條指令的總的執(zhí)行時(shí)間很短,相反,通過整個(gè)亂序部件和等待內(nèi)存讀寫數(shù)據(jù)是需要花費(fèi)很多時(shí)間的。

      一個(gè)新的處理器擁有 12 級(jí)或者 18 級(jí)、甚至更深的 31 級(jí)流水線意味著什么呢?這意味著更多的指令可以被同時(shí)送進(jìn)加工廠。一個(gè)非常深的流水線可以讓幾百條指令同時(shí)被處理。當(dāng)一切順利時(shí),一個(gè)亂序部件可以保持高速運(yùn)轉(zhuǎn),從而獲得驚人的吞吐量。不幸的是,深的流水線同時(shí)意味著流水線停頓會(huì)從一個(gè)相對(duì)可以容忍的性能損失變成一個(gè)可怕的性能噩夢(mèng)。因?yàn)閹装贄l指令都不得不停頓下來,等待流水線恢復(fù)運(yùn)轉(zhuǎn)。

      我怎么根據(jù)這些信息來優(yōu)化程序呢?幸運(yùn)的是,CPU 可以在大部分常見情況下工作良好,并且編譯器已經(jīng)為亂序處理器優(yōu)化了近 20 年。當(dāng)指令和數(shù)據(jù)按照順序(沒有煩人的跳轉(zhuǎn))執(zhí)行時(shí),CPU 可以獲得最好的性能。因此,首先,使用簡單的代碼。簡單直接的代碼會(huì)幫助編譯器的優(yōu)化引擎識(shí)別并優(yōu)化代碼。盡量不使用跳轉(zhuǎn)指令,當(dāng)你不得不跳轉(zhuǎn)時(shí),盡量每次跳轉(zhuǎn)到同樣的方向。復(fù)雜的設(shè)計(jì),例如動(dòng)態(tài)跳轉(zhuǎn)表,雖然看起來很酷并且的確可以完成非常強(qiáng)大的功能,但不管是處理器還是編譯器,都無法進(jìn)行很好的預(yù)測(cè)處理,因此復(fù)雜的代碼很可能導(dǎo)致流水線停頓和猜測(cè)錯(cuò)誤,從而極大的損害處理器性能。其次,使用簡單的數(shù)據(jù)結(jié)構(gòu)。保持?jǐn)?shù)據(jù)順序、相鄰和連續(xù)可以阻止數(shù)據(jù)停頓。使用正確的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)分布可以獲得很大的性能提升。只要保持代碼和數(shù)據(jù)結(jié)構(gòu)盡量簡單,剩下的工作就可以放心地交給編譯器的優(yōu)化引擎來完成了。
     

    (審核編輯: 智匯李)

    聲明:除特別說明之外,新聞內(nèi)容及圖片均來自網(wǎng)絡(luò)及各大主流媒體。版權(quán)歸原作者所有。如認(rèn)為內(nèi)容侵權(quán),請(qǐng)聯(lián)系我們刪除。