Conroe強在哪兒?Core vs K8架構解析
自從采用 P6 微架構的 Pentium Pro 處理器之后,X86 處理器開始擁有亂序發(fā)射和執(zhí)行指令的能力。不過,亂序緩沖區(qū)內平均大約三分之一的指令很難重排序——就是那些 load 操作。把 load 操作提前執(zhí)行可以極大的提高性能。與需要數(shù)據(jù)的時候才進行 load 操作相比,盡可能早的開始 load 操作十分有用,因為這可以更有效的把一級緩存及二級緩存的延遲隱藏掉。
這很容易理解。假設現(xiàn)在有一個 ALU 操作需要某數(shù)據(jù),可是該數(shù)據(jù)不在一級緩存中。如果 load 該數(shù)據(jù)的操作在該 ALU 操作之前就已經(jīng)執(zhí)行完畢,那么訪問二級緩存的延遲就不會對性能產(chǎn)生影響。不過,需要注意的是,如果 load 操作針對的數(shù)據(jù)在程序中還有 store 操作要對其進行寫入,那么就不能把 load 操作提前到該 store 操作之前執(zhí)行。因為這樣的情況下,如果提前執(zhí)行 load 操作的話,意味著你得到的會是錯誤的數(shù)據(jù),而不是最新的。

Intel 內存相關性預測技術
上圖中的 Load 2 操作不能提前執(zhí)行,因為它操作的數(shù)據(jù)與 Store 1 操作的數(shù)據(jù)相同,需要等待 Store 1 操作先完成。只有 Store 1 執(zhí)行完畢,數(shù)據(jù)Y才擁有正確的值。不過 Load 4 操作沒有理由不能提前進行,它不需要等待 Store 1 或者 Store 3 操作完成。這樣,通過把 Load 4 操作提前,load 單元有更多的時間去獲得正確的操作數(shù)。
不過,之前的處理器在這種情況下——有 store 操作存在——都不會把 load 操作提前。因為處理器不知道 store 操作針對的數(shù)據(jù)單元與 load 操作是否相同。如果想要搞清楚是否相同的話,需要計算存儲器地址。這十分困難,因為在指令亂序和調度的時候,存儲器地址還是未知的。
這時需要注意一個事實:load 操作讀取到一個錯誤數(shù)據(jù)的概率相當小,只有1%到2%。所以,Intel 的 Core 微架構設計師 Jack Doweck 決定,允許所有的 load 操作提前執(zhí)行,假設所有的 load 操作讀取到的數(shù)據(jù)都是正確的。而為了應對錯誤的發(fā)生,Intel 加入了一個預測器。
根據(jù) Jack Doweck 的描述,以及我們對以前的 P6 微架構和 Pentium M 處理器的了解,我們制作了下面的圖表。注意這并非 Intel 官方的圖表。
Core 微架構亂序執(zhí)行引擎
預測器做出預測,并指示亂序緩沖區(qū)是否可以把某 load 操作提前執(zhí)行。在 load 操作提前執(zhí)行之后,沖突監(jiān)測單元會掃描MOB(Memory Reorder Buffer),查看是否有 store 操作與 load 操作沖突。如果有沖突發(fā)生的話,load 操作必須重新執(zhí)行,這時大約會損失20個時鐘周期。不過與之前的處理方式相比,Core 微架構采用的這種處理方式總體上肯定可以提高處理器的效率。
檢測某 load 操作和某 store 操作是否是針對同一內存地址的行為稱作內存相關性預測(memory disambiguation)。Core 微架構允許 load 操作提前到 store 操作之前執(zhí)行的處理方式可以帶來性能上的巨大提升。在某些測試代碼中,這個提升甚至達到了40%。雖然我們在實際的應用程序中不會看到如此大的提升,但是無疑這項技術會帶來令人印象深刻的提升——我們可以期待10%到20%的性能提升。
不要忘記,load 操作可能是所有操作中最重要的操作。不僅僅因為 load 指令占了X86處理器內所有微指令的三分之一強,還因為當 load 操作發(fā)生時可能導致的巨大延遲會引起處理器的等待。那么,這項極其靈活的 load 操作亂序執(zhí)行技術與其它架構的處理器相比是什么情況呢?

Load 操作處理方式比較
舊的 P6 微架構和 Penium M 處理器也已經(jīng)可以較好的處理 load 操作,可以把某 load 操作提前到另外的 load 操作之前進行,也可以提前到已知不會發(fā)生沖突的 store 操作之前進行。P6 微架構的內存亂序緩沖區(qū)(Memory Reorder Buffer,簡稱MOB)采用如下的規(guī)則:如果在亂序執(zhí)行窗口中存在與某load操作內存地址相同的store操作,則該load操作不能提前執(zhí)行;如果在亂序執(zhí)行窗口中存在內存地址未知的store操作,則任何load操作不能提前執(zhí)行;某store操作不能提前到另外一個store操作之前執(zhí)行。
相比之下,K8 處理器要遜色的多,它只能把 load 操作移動到不相關的 ALU 操作之前進行,而不能移動到其它 load 操作之前,當一個 load 操作等待某 store 操作執(zhí)行的時候,處理器會浪費大量的時鐘周期。這意味著 K8 處理器在指令亂序這方面受到極大的限制。
這也許是 K8 處理器在游戲和整數(shù)計算等方面輸給 Core 微架構的最重要的原因之一,盡管它擁有延遲更低的內存子系統(tǒng)和更多的整數(shù)執(zhí)行資源。整數(shù)運算進行的存儲器操作經(jīng)常有許多未知的地址需要計算,而浮點運算則不是這樣,它對存儲器的訪問是更加規(guī)范的。這也是 K8 處理器在浮點運算方面不輸給 Dothan 處理器的原因之一。
當 load 操作和 store 操作都已經(jīng)進入 Load/Store 單元的隊列中的時候,K8 處理器允許 load 操作在不沖突的 store 操作之前執(zhí)行。不幸的是,這時把 load 操作提前執(zhí)行已經(jīng)不能隱藏緩存缺失所帶來的延遲。你可以認為這是 K8 處理器擁有的 Load/Store 亂序機制,但是它在流水線中的位置太靠后,比起 P6 微架構、Pentium M 處理器和 Core 微架構所采用的技術相差甚遠。
關注我們
