初識pipeline


1、pipeline的產生

    從一個現象說起,有一家咖啡吧生意特別好,每天來的客人絡繹不絕,客人A來到櫃台,客人B緊隨其后,客人C排在客人B后面,客人D排在客人C后面,客人E排在客人D后面,一直排到店面門外。老板和三個員工首先為客人A准備食物:員工甲拿了一個干凈的盤子,然后員工乙在盤子里裝上薯條,員工丙再在盤子里放上豌豆,老板最后配上一杯飲料,完成對客人A的服務,送走客人A,下一位客人B開始被服務。然后員工甲又拿了一個干凈的盤子,員工乙又裝薯條,員工丙又放豌豆,老板又配上了一杯飲料,送走客人B,客人C開始被服務。一直重復下去。

 

    從效率方面觀察這個現象,當服務客人A時,在員工甲拿了一個盤子后,員工甲一直處於空閑狀態,直到送走客人A,客人B被服務。老板自然而然的就會想到如果每個人都不停的干活,就可以服務更多的客人,賺到更多的錢。老板通過不停的嘗試想出了一個辦法。以客戶A,B為例闡述這個方法:員工甲為客戶A准備好了盤子后,在員工乙開始為客戶A裝薯條的同時,員工甲開始為客戶B准備托盤。這樣員工甲就可以不停的進行生產。整個過程如下圖,客戶們圍着咖啡吧台排隊,因為有四個生產者,一個老板加三個員工,所以可以同時服務四個客戶。我們將目光轉向老板,單位時間從他那里出去的客戶數提高了將近四倍,也就是說效率提高將近四倍。

    pipeline的概念可以從這里抽象出來:將一件需要重復做的事情(這里指為客戶准備一份精美的食物)切割成各個不同的階段(這里是四個階段:盤子,薯條,豌豆,飲料),每一個階段由獨立的單元負責(四個生產者分別負責不同的環節)。所有待執行的對象依次進入作業隊列(這里是所有的客戶排好隊依次進入服務,除了開始和結尾的一段時間,任意時刻,四個客戶被同時服務)。對應到CPU中,每一條指令的執行過程可以切割成:fetch instruction、decode it、find operand、perform action、store result 5個階段。

2、將pipeline應用到CPU的計算單元中

    在未將pipeline應用到CPU之前,假如一個計算單元耗時300ps,將結果寫入到寄存器耗時20ps,那么一條指令的執行時間為320ps。吞吐量定義為單位時間內執行的指令的條數,一般其單位為GIPS(giga-instruction per second),那么其吞吐量為3.12 GIPS,也就是說每秒執行3.12 giga條指令,1 giga 個= 10^9 個。

    下面將pipeline應用到CPU,看計算單元的吞吐量會提高多少。我們將上圖的組合邏輯單元切割成三個小的組合邏輯單元,每個組合邏輯單元耗時100ps,另外為了使前后組合邏輯單元的執行不相互影響,需要在每一對的小單元中間插入一個寄存器(對於這一點的理解,看完下面關於使用pipeline的CPU的運行過程就可以理解)如下圖所示:

    運行原理:首先這里非常值得指出的是,這里對寄存器的模型表示有些不細膩,因為從上圖中並不能看出每個寄存器由輸入,狀態,和輸出三個小單元組成。對於I1,I2,I3三條指令,當時鍾迎來第一個上升沿時,I1首先進入組合邏輯A(如果這里不理解時鍾,暫且忽略,下面會講解),經過100ps后將結果花20ps寫入到第一個寄存器的輸入;當時鍾迎來第二個上升沿時,更新第一個寄存器的狀態和輸出,即把I1指令經過組合邏輯A 后的結果更新到第一個寄存器以作為組合邏輯單元B的輸入。與此同時,I2進入組合邏輯單元A,並在100ps后將結果花20ps寫入到第一個寄存器的輸入,這里注意,第一個寄存器的狀態和輸出並沒有發生變化。這種機制保證了前后指令的互不干擾性。當時鍾第三個上升沿來到時,I1進入邏輯單元C,I2進入邏輯單元B,I3開始進入邏輯單元A。

下面我們來計算使用pipeline的計算單元的吞吐量,由於每個階段都需要100ps+20ps=120ps的時間,我們可以選用使得系統吞吐量最大的周期為120ps的時鍾1/120*1000=8.3 GIPS,即每秒鍾執行8.3 giga條指令相比於未使用pipeline的3.12 GIPS,提高了2.67倍,大家可能有疑問為什么不是3倍,因為我們為了讓前后指令互不影響插入了兩個寄存器,所以達不到最大極限3。

上面兩幅圖中的兩幅b圖是專門用來表示pipeline中各個時刻各個指令所處狀態的pipeline diagram。

3、決定計算單元速度的是pipeline而不是系統時鍾的頻率

    我們以第2部分為背景來闡述這個問題,三個階段,每一階段耗時120 ps,如果時鍾周期高於120ps,那么將會出現寄存器值由於沒有來得及更新導致的指令執行混亂的情況。對於更一般的情況,比如從左向右,三個計算單元的執行時間是(120+20)+(80+20)+(100+20)=360,那么時鍾周期必須大於最大的單個組合邏輯單元的執行時間,否則就會出現階段執行不完整的情況,即140ps,所以說決定計算單元速度的是pipeline,更精確的說是pipeline中的最大的組合邏輯單元的執行時間。對於如何將計算單元切割成更小的執行時間幾乎相同的階段,對硬件設計者來說,是一個挑戰。

4、delay slot

    在上面的討論中我們都假設連續的指令間並沒有依賴關系,現在引入指令間的依賴關系。依賴關系可以分為兩種:data dependency, control dependency。

對於data dependency,我們用下面的指令序列作為例子

    圖中的小圓圈加箭頭表示了這種依賴關系,比如第二條指令的執行需要用到第一條指令的結果,所以第二條指令必須推遲進入pipeline的時間,稱為load/store delay slot,以獲得eax更新后的值,2條與第3條的數據依賴關系同理。

    對於control dependency,我們用下面的指令序列作為例子

    第3條指令為跳轉指令,第4條指令是否執行依賴於第三條指令的結果,即是否跳轉,所以第四條指令必須延遲進入pipeline的時間,稱為branch delay slot。

5、 參考資料

    《see mips run》

    《computer system: a programmer's perspective》p391-p400

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM