當前位置:
首頁 > 科技 > 關於處理器流水線,此流水線非彼流水線

關於處理器流水線,此流水線非彼流水線

本文將討論處理器的一個重要的基礎知識:「流水線」。熟悉計算機體系結構的讀者一定知道,言及處理器微架構,幾乎必談其流水線。處理器的流水線結構是處理器微架構最基本的一個要素,猶如汽車底盤對於汽車一般具有基石性的作用,它承載並決定了處理器其他微架構的細節。本文將簡要介紹處理器的一些常見流水線結構,讓您真正讀懂處理器流水線。

1 從經典的五級流水線說起

流水線的概念來源於工業製造領域,以汽車裝配為例來解釋流水線的工作方式,假設裝配一輛汽車需要四個步驟:

第一步衝壓:製作車身外殼和底盤等部件。

第二步焊接:將衝壓成形後的各部件焊接成車身。

第三步塗裝:將車身等主要部件清洗、化學處理、打磨、噴漆和烘乾。

第四步總裝:將各部件(包括發動機和向外採購的零部件)組裝成車。

汽車裝配則同時對應需要衝壓、焊接、塗裝和總裝四個工人。最簡單的方法是一輛汽車依次經過上述四個步驟裝配完成之後,下一輛汽車才開始進行裝配,最早期的工業製造就是採用的這種原始的方式,即同一時刻只有一輛汽車在裝配。不久之後人們發現,某個時段中一輛汽車在進行裝配時,其它三個工人都處於閑置狀態,顯然這是對資源的極大浪費,於是思考出能有效利用資源的新方法,即在第一輛汽車經過衝壓進入焊接工序的時候,立刻開始進行第二輛汽車的衝壓,而不是等到第一輛汽車經過全部四個工序後才開始,這樣在後續生產中就能夠保證四個工人一直處於運行狀態,不會造成人員的閑置。這樣的生產方式就好似流水川流不息,因此被稱為流水線。

計算機體系結構教材中被提及最多的經典MIPS五級流水線如圖1所示。在此流水線中一條指令的生命周期分為:

取指:

指令取指(Instruction Fetch)是指將指令從存儲器中讀取出來的過程。

解碼:

指令解碼(Instruction Decode)是指將存儲器中取出的指令進行翻譯的過程。經過解碼之後得到指令需要的操作數寄存器索引,可以使用此索引從通用寄存器組(Register File,Regfile)中將操作數讀出。

執行:

指令解碼之後所需要進行的計算類型都已得知,並且已經從通用寄存器組中讀取出了所需的操作數,那麼接下來便進行指令執行(Instruction Execute)。指令執行是指對指令進行真正運算的過程。譬如,如果指令是一條加法運算指令,則對操作數進行加法操作;如果是減法運算指令,則進行減法操作。

在「執行」階段的最常見部件為算術邏輯部件運算器(Arithmetic Logical Unit,ALU),作為實施具體運算的硬體功能單元。

訪存:

存儲器訪問指令往往是指令集中最重要的指令類型之一,訪存(Memory Access)是指存儲器訪問指令將數據從存儲器中讀出,或者寫入存儲器的過程。

寫回:

寫回(Write-Back)是指將指令執行的結果寫回通用寄存器組的過程。如果是普通運算指令,該結果值來自於「執行」階段計算的結果;如果是存儲器讀指令,該結果來自於「訪存」階段從存儲器中讀取出來的數據。

在工業製造中採用流水線可以提高單位時間的生產量,同樣在處理器中採用流水線設計也有助於提高處理器的性能。以上述的五級流水線為例,由於前一條指令在完成了「取指」進入「解碼」階段後,下一條指令馬上就可以進入「取指」階段,依次類推,如圖2所示,如果流水線沒有停頓,理論上可以取得每個時鐘周期都完成一條指令的性能。

圖1 MIPS五級流水線結構圖

圖2 MIPS五級流水線運行圖

2 可不可以不要流水線——流水線和狀態機的關係

言及處理器微架構,幾乎必談流水線。那麼,我們能否挑戰一下權威提出一個有意思的問題:處理器難道就一定需要流水線嗎?可否不要流水線呢?

在回答這個問題之前,我們先探討下流水線的本質:

流水線並不限於處理器設計,在所有的ASIC電路實現中都廣泛採用流水線的思想。流水線本質上可以理解為是一種以面積換性能(Trade Area for Performance)、以空間換時間(Trade Space for Timing)的手段。

譬如,以5級流水線為例,其增加了5組寄存器,每一個流水線級數內部都有各自的組合邏輯數據通路,彼此之間沒有復用資源,因此,其面積開銷是比較大的,但是由於可以讓不同的流水線級數同時做不同的事情,而達到流水的效果,提高了性能,優化了時序,增加了吞吐率。

與流水線相對應的另外一種策略是狀態機,狀態機是流水線的「取反」,同樣在所有的ASIC電路實現中都廣泛採用。狀態機本質上可以理解為是一種以性能換面積(Trade Performance for Area)、以時間換空間(Trade Timing for Space)的手段。

「流水線」和「狀態機」的關係,還有一種說法稱之為「展開」和「摺疊」的關係。本質上都是一種電路設計時,選擇側重時間(性能)還是空間(面積)的一種取捨。

通過上述分析,假設處理器不採用流水線,而是使用一個狀態機來完成,則需要多個時鐘周期才能完成一條指令的所有操作,每個時鐘周期完成狀態機的一個狀態(譬如分別為取指、解碼、執行、訪存和寫回)。通過使用狀態機,可以省掉上述流水線中的寄存器開銷,還可以復用組合邏輯數據通路,因此面積開銷比較小,但是每條指令都需要5個周期才能完成,吞吐率和性能很差。

談及此處,就不得不提及8位單片機時代的傳奇老炮兒8051內核,早期原始的8051內核微架構就是採用了類似狀態機的實現方式而不是流水線。因此,回到最開始我們提出的問題,處理器可否不要流水線,答案是:當然可以,傳奇老炮兒8051內核就沒有流水線。

所以說從功能能上來講,處理器完全可以不使用流水線,而使用狀態機的方式來實現,只不過由於這種方式性能比較差,在現代處理器設計中比較罕見而已。

3 深處種菱淺種稻,不深不淺種荷花——流水線的深度

流水線的級數(又稱深度)多少最好呢?要回答這個問題,就需要了解流水線的深淺各自的優劣。此處有一個常見面試題,題目便是:處理器的流水線是否越深越好?在此我們給出答案:

早期的經典流水線是5級流水線,分別為取指、解碼、執行、訪存和寫回。現代的處理器往往具有極深的流水線級數,譬如高達十幾級,或者二十幾級的深度。流水線就像一根黃瓜,切五刀下去得到的每一截長度和切二十到下去得到的每一截長度肯定是不一樣的。當流水線的級數越多,那麼意味著流水線被切的很細,每一級流水線內容納的硬體邏輯便越少,熟悉數字同步電路設計的讀者應該比較熟悉,在兩級寄存器(每一級流水線由寄存器組成)之間的硬體邏輯越少,則意味能夠運行到更高的主頻。因此現代的處理器流水線極深主要是由於處理器追求高頻的指標所驅使,高端的ARM Cortex-A系列由於有十幾級的流水線,所以能夠運行到高達2GHz的主頻,而Intel的x86處理器甚至採用幾十級的流水線深度將主頻推到3-4GHz的高度。主頻越高也意味著流水線的吞吐率越高從而性能越高,這是流水線加深的正面意義。

由於每一級流水線都由寄存器組成,那麼意味著更多的流水線級數要消耗更多的寄存器,也意味著更多的面積開銷。這是流水線加深的負面意義。

同時流水線越深,由於每一級流水線需要進行握手,流水線最後一級的反壓信號可能會一直串擾到最前一級造成嚴重的時序問題,需要使用一些比較高級的技巧來解決此類反壓時序問題。這是流水線加深的負面意義。

較深的處理器流水線還有一個問題,由於在流水線的取指令階段無法得知條件跳轉的結果是跳還是不跳,因此只能進行預測,而到了流水線的末端才能夠通過實際的運算得知該分支是真的該跳還是不該跳,如果發現真實的結果(譬如該跳)與之前預測的結果(譬如預測為不跳)不相符,則意味著預測失敗,需要將所有預取的錯誤指令流全部丟棄掉,而重新取正確的指令流,這個過程叫做流水線沖刷(Pipeline Flush),雖然可以使用分支預測器來保證前期的分支預測儘可能的準確,但是也無法做到萬無一失。那麼,流水線的深度越深,則意味著已經預取了很多的錯誤指令流,需要將其全部拋棄然後重啟,不僅白白的浪費了功耗,還造成了性能的損失。流水線越深則意味著浪費和損失越嚴重,流水線越淺則浪費和損失越少。這是流水線加深的另一個主要的負面意義。

綜上,所謂深處種菱淺種稻,不深不淺種荷花,流水線的不同深度皆有其優缺點,需要根據不同的應用背景合理地進行選擇。

由於處理器流水線深淺的不同優劣,根據不同的應用場景,當今處理器的流水線深度在向著兩個不同的極端發展,一方面級數越來越深,另一方面又越來越淺,下面我們結合不同的商用處理器例子予以探討。

4 向上生長——越來越深的流水線

現代的高性能處理器相比最早期的處理器明顯存在著流水線越來越深的現象,其驅動因素很簡單,那就是追求更高的主頻以獲取更高的吞吐率和性能。

以最知名的ARM Cortex-A系列處理器IP為例,Cortex-A7主打的低功耗前提下的能效比,其流水線級數為8級;而Cortex-A15主打高性能,其流水線深度為15級。

當然流水線越來越深也需有其限度,曾有某些商業處理器產品一味地追求極端流水線深度(達到幾十級)反而遭遇失敗的例子。目前最新的Intel處理器和ARM 高性能Cortex-A系列處理器的流水線深度都在十幾級的範圍左右。

5 向下生長——越來越淺的流水線

現代低功耗處理器的另外一個趨勢也存在著流水線越來越淺的現象,其驅動因素同樣很簡單,那就是在性能夠用的前提下追求極低的功耗。

以最知名的ARM Cortex-M系列處理器IP為例,2004年發布的Cortex-M3處理器核的流水線級數只有3級,2009年發布的Cortex-M0處理器核的流水線級數也只有3級,而2012年發布的Cortex-M0+處理器核的流水線級數反而只有2級,變得越來越少了,正因為此ARM也宣傳Cortex-M0+處理器核為世界上能效比最高的處理器核。

2級的流水線深度似乎已經淺到底了,讀者可能會問,那是不是接下來要發布只有1級深度的流水線了?當深度變為1之後也就談不上流水線了,其整體也就變成一個單周期的組合邏輯了,在眾多的計算機體系結構教學案例中我們確實見到過很多流水線深度為1的處理器核,從功能上來說其仍然可以完成處理器的所有功能,只不過主頻相當之低而已。

6 處理器流水線中的反壓

隨著流水線越深,由於每一級流水線都需要進行握手,流水線最後一級的反壓信號可能會一直串擾到最前一級造成嚴重的反壓(Back-pressure)時序問題,需要使用一些比較高級的技巧來解決這些時序問題。在現代處理器設計中,通常有如下若干種方法:

取消握手:此方法能夠徹底杜絕反壓的發生,時序表現非常好。但是取消握手即意味著流水線中的每一級並不會與其下一級進行握手,因此可能會造成功能錯誤或者指令丟失。因此這種方法往往需要配合其他的機制,譬如重執行(Replay),預留大緩存等等。簡而言之,此方法比較激進,輔以一系列其他的配置機制,硬體總體的複雜度會比較大。只有在一些非常高級的處理器設計中才會用到。

加入乒乓緩存:加入乒乓緩存(Ping-pong Buffer)是一種用面積換時序的方法,也是解決反壓最簡單的方法。通過使用乒乓緩存(有兩個表項)替換普通的一級流水線(只有一個表項),可以使得此級流水線向上一級流水線的握手接受信號僅僅需要關注乒乓緩存中是否有一個以上有空的表項即可,而無需將下一級的握手接受信號串擾至上一級。

加入前向旁路緩存:加入前向旁路緩存(Forward Bypass Buffer)也是一種用面積換時序的方法,這是在解決反壓時一種非常巧妙的方法。旁路緩存僅有一個表項,由於增加了這一個額外的緩存表項,可以將後向的握手信號時序路徑砍斷,但是對前向路徑不產生影響,因此,可以廣泛使用於握手介面。蜂鳥E200即於設計中採用此方法,有效地解決了多處反壓造成的時序瓶頸。

以上解決反壓的技術方法,不僅在處理器設計中能夠用到,而且在普通的ASIC電路設計中也會經常用到。

7 處理器流水線中的衝突

處理器的流水線設計中另外一個問題便是流水線中的衝突(Hazards),主要分為資源衝突和數據衝突。

7.1 流水線中的資源衝突

資源衝突是指流水線中硬體資源的衝突,最常見的是運算單元的衝突,譬如除法器需要多個時鐘周期才能完成運算,因此在前一條除法指令運算完成之前,新的除法指令如果也需要除法器則會存在著資源衝突。在處理器的流水線中硬體資源衝突種類還有較多,在此不做一一贅述。解決資源衝突的方法可以通過複製硬體資源或者流水線停頓等待硬體資源的方法解決。

7.2 流水線中的數據衝突

數據衝突是指不同的指令之間的操作數存在數據相關性造成的衝突。常見的數據相關性包括:

WAR(Write-After-Read)相關性,又稱先讀後寫相關性:表示「後序執行的指令需要寫回的結果寄存器索引」與「前序執行的指令需要讀取的源操作數寄存器索引」相同造成的數據相關性。因此,從理論上來講,在流水線中「後序指令」一定不能比和它有WAR相關性的「前序指令」先執行,否則「後序指令」先寫回了結果至通用寄存器組中,「前序指令」再讀取操作數時,就會讀到錯誤的數值。

WAW(Write-After-Write)相關性,又稱先寫後寫相關性:表示「後序執行的指令需要寫回的結果寄存器索引」與「前序執行的指令需要寫回的結果寄存器索引」相同造成的數據相關性。因此,從理論上來講,在流水線中「後序指令」一定不能比和它有WAW相關性的「前序指令」先執行,否則「後序指令」先寫回了結果至通用寄存器組中,「前序指令」再寫回結果至通用寄存器組中就會將其覆蓋。

RAW(Read-After-Write)相關性,又稱先寫後讀相關性:表示「後序執行的指令需要讀取的源操作數寄存器索引」與「前序執行的指令需要寫回的結果寄存器索引」相同造成的數據相關性。因此,從理論上來講,在流水線中「後序指令」一定不能比和它有RAW相關性的「前序指令」先執行,否則「後序指令」便會從通用寄存器組中讀回錯誤的源操作數。

以上的三種相關性中,RAW屬於真數據相關。

解決數據衝突的常見方法如下:

WAW和WAR可以通過寄存器重命名的方法將相關性去除,從而無需擔心其執行順序。

寄存器重命名技術在Tomasulo演算法中通過保留站和ROB(Re-Order Buffer)完成,或者採用純物理寄存器(而不用ROB)的方式完成。

之所以RAW稱之為真數據相關,是因為其沒有辦法通過寄存器重命名的方法將相關性去除。一旦產生RAW相關性,後序的指令一定要使用和它有RAW數據相關性的前序指令執行完成的結果,從而造成流水線的等待停頓。為了能夠儘可能的減少流水線停頓帶來的性能損失,可以使用「動態調度」的方法。動態調度的思想本質上可以歸結於以下方面:

一方面採用數據旁路傳播(Data Bypass and Forward)技術儘可能的讓前序指令的計算結果更快的旁路傳播給後序相關指令的操作數;

另一方面儘可能的讓後序相關指令在等待的過程中不阻塞流水線而讓其他無關的指令能夠繼續順利執行。

早期的Tomasulo演算法中通過保留站可以達到這兩方面的功效,但是保留站由於保存了操作數無法做到很大的深度(否則面積和時序的開銷巨大)。

最新的高性能處理器普遍採用在每個運算單元前配置亂序發射隊列(Issue Queue)的方式,發射隊列僅追蹤RAW相關性而並不存放操作數,因此可以做的很深(譬如16個表項)。在發射隊列中的指令一旦相關性解除之後,再從發射隊列中發射出來讀取物理寄存器組(Physical Register File),然後發送給運算單元開始計算。

有關處理器的數據相關性問題和包括動態調度技術在內的解決方法,如果闡述清楚幾乎可以單獨成書,本文限於篇幅只能提綱挈領式的予以簡述。有關Tomasulo演算法的細節請參見維基百科詞條網頁(https://en.wikipedia.org/wiki/Tomasulo_algorithm),有關物理寄存器重命名的細節請參見維基百科詞條網頁(https://en.wikipedia.org/wiki/Register_renaming),感興趣的讀者可以自行查閱。

本文試圖以最通俗化的方式對處理器流水線進行介紹,首先討論了處理器流水線概述,包括:從經典的五級流水線說起、可不可以不要流水線——流水線和狀態機的關係、深處種菱淺種稻,不深不淺種荷花——流水線的深度、向上生長——越來越深的流水線、向下生長——越來越淺的流水線。然後本文介紹了處理器流水線設計的兩大難題及其多種解決方法:處理器流水線中的反壓、處理器流水線中的衝突。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 電子產品世界 的精彩文章:

可編程邏輯實現數據中心互連
從不受影響到不存在漏洞,談何為CPU信息安全的主動防禦

TAG:電子產品世界 |