流水線技術是提升效能的銀彈嗎?它透過把一條指令的操作切分成更細的多步,可避免CPU“浪費”。
每個細分的流水線步驟都很簡單,單個時鐘週期時間就可設得更短,變相地讓CPU主頻提升很快。
這一系列優點,引出現代桌面CPU最後大戰:Intel Pentium 4 V.S AMD Athlon。
技術上,Intel輸得徹底,Pentium 4系列及後續Pentium D系列所使用的NetBurst架構被完全拋棄。但商業層面,Intel卻透過遠超過AMD的財力、原本就更大的市場份額、無所不用的競爭手段,以及最終壯士斷腕般放棄整個NetBurst架構,最終依靠新的酷睿品牌戰勝了AMD。
此後,整個CPU領域競爭焦點,不再是Intel和AMD的桌面CPU。
ARM架構透過智慧手機普及,後來居上,超越Intel,移動時代CPU變成高通、華為麒麟和三星之間的“三國演義”。
“主頻戰爭”帶來的超長流水線
其實並不能簡單透過CPU主頻,就衡量CPU乃至計算機整機效能。
不同CPU實際體系架構和實現都不同。同樣CPU主頻,實際效能可能差別很大。
更好的衡量方式是用SPEC這樣跑分程式,從多個不同實際應用場景衡量效能。
但跑分對消費者還是太複雜。Pentium 4的CPU面世前,絕大部分消費者並不根據跑分判斷CPU效能,通常只看CPU主頻。而CPU的廠商們也不停提升主頻,當成技術競賽核心指標。
Intel一向在“主頻戰爭”中保持領先,但1999年,AMD釋出基於K7架構的Athlon處理器,綜合性能超越當年的Pentium III。
2000年,大部分CPU還在500~850MHz,AMD推出第一代Athlon 1000處理器,成為第一款1GHz消費級CPU。
2000年前後,AMD的CPU不但效能和主頻比Intel的要強,價格還往往只有2/3。
壓力下,Intel在2001年推出新一代NetBurst架構CPU,即Pentium 4和Pentium D。Pentium 4CPU最大特點高主頻。
2000年的Athlon 1000的主頻在當時是最高的,1GHz,Pentium 4設計最高主頻10GHz。
為達到10GHz,Intel工程師做了一個重大錯誤決策,就是在NetBurst架構上,使用超長流水線,有多長呢?
Pentium 4之前的Pentium III CPU,流水線深度11級:一條指令最多拆成11個更小步驟操作,而CPU同時也最多會執行11條指令的不同Stage。
今天日常手機ARM的CPU或者Intel i7伺服器的CPU,流水線深度14級。
20年,技術進步,現代CPU還是增加了一些流水線深度。
2000年的Pentium 4的流水線深度20級,比Pentium III多了一倍,而到了代號為Prescott的90奈米工藝處理器Pentium 4,Intel更是把流水線深度增加到31級。
增加流水線深度,在同主頻下,其實是降低CPU的效能。因一個Pipeline Stage,就需一個時鐘週期。
把任務拆成31個階段,就要31個時鐘週期才能完成一個任務;
而把任務拆分成11個階段,就只要11個時鐘週期完成任務。
這種情況下,31個Stage的3GHz主頻的CPU,其實和11個Stage的1GHz主頻的CPU,效能差不多。因為每個Stage都要有對應Pipeline暫存器的開銷,這時,更深的流水線效能可能還會更差。
流水線技術並不能縮短單條指令的響應時間,但可增加在執行很多條指令時候的吞吐率。
因為不同指令,實際執行需要時間不同。如順序執行這樣三條指令:
- 一條整數的加法,200ps
- 一條整數的乘法,300ps
- 一條浮點數的乘法,600ps
若在單指令週期CPU執行,最複雜指令浮點數乘法,那就要600ps。
那這三條指令,都要600ps。三條指令的執行時間,就要1800ps。
若採用6級流水線CPU,每個Pipeline的Stage都只需100ps。則這三個指令的執行過程中:
- 指令1的第一個100ps的Stage結後,第二條指令就開始執行了
- 第二條指令的第一個100ps的Stage結束後,第三條指令就開始執行了
這種情況下,這三條指令順序執行所需要的總時間,就是800ps。在1800ps內,使用流水線的CPU比單指令週期的CPU就可以多執行一倍以上的指令數。
雖然每條指令從開始到結束拿到結果的時間並沒有變化,即響應時間沒變。但同樣時間內,完成指令數增多,即吞吐率上升。
冒險和分支預測
這樣不是很好麼?Intel CPU支援2000多條指令。有些指令簡單,執行很快,如無條件跳轉指令,不需透過ALU,只要更新PC暫存器內容。
有些指令很複雜,比如浮點數運算,需進行指數位比較、對齊,然後對有效位進行移位,然後再計算。兩者執行時間相差二三十倍也很正常。
既然這樣,Pentium 4的超長流水線看起來很合理呀,為什麼Pentium 4最終成為Intel在技術架構層面的大失敗:
功耗問題
提升流水線深度,必須要和提升CPU主頻同時進行。因為單個Pipeline Stage能夠執行的功能變簡單了,也意味單個時鐘週期內能夠完成的事情少了。
所以,只有提升時鐘週期,CPU在指令的響應時間這個指標上才能保持和原來相同的效能。
由於流水線深度增加,需要電路數量變多,即電晶體多了。
主頻的提升和電晶體數量的增加都使得CPU功耗變大。導致Pentium 4在整個生命週期裡,嚴重耗電和散熱。
Pentium 4是在2000~2004年作為Intel的主打CPU出現在市場上的。這個時間段,正是膝上型電腦市場快速發展的時間。在膝上型電腦上,功耗和散熱比起桌上型電腦是更嚴重問題。
流水線技術帶來的效能提升,是理想情況
實際程式執行中,並不一定能夠做得到。
剛才舉的三條指令。若這三條指令,是下面程式碼,會發生什麼情況呢?
int a = 10 + 5; // 指令1
int b = a * 2; // 指令2
float c = b * 1.0f; // 指令3
發現,指令2不能在指令1的第一個Stage執行完成後進行。
因為指令2依賴指令1的計算結果。
同樣指令3也要依賴指令2計算結果。
這樣,即使採用流水線技術,這三條指令執行完成的時間,也是 200 + 300 + 600 = 1100 ps,而不是 800ps。
若指令1和2都是浮點數運算,需要600ps。那這個依賴關係會導致我們需要的時間變成1800ps,和單指令週期CPU時間一樣。
這就是冒險(Hazard)問題。這列舉在資料層面的依賴,即資料冒險,還有結構冒險、控制冒險等其他依賴問題。
對這些冒險問題,也有在亂序執行、分支預測等相應解決方案。
但流水線越長,冒險問題越難解決。因為同一時間同時在執行的指令太多。若只有3級流水線,可把後面沒有依賴關係的指令放到前面執行。這個就是我們亂序執行技術:
int a = 10 + 5; // 指令1
int b = a * 2; // 指令2
float c = b * 1.0f; // 指令3
int x = 10 + 5; // 指令4
int y = a * 2; // 指令5
float z = b * 1.0f; // 指令6
int o = 10 + 5; // 指令7
int p = a * 2; // 指令8
float q = b * 1.0f; // 指令9
可不先執行1、2、3指令,而是在流水線裡,先執行1、4、7,這三條指令無依賴關係。
再執行2、5、8及3、6、9。
這又能夠充分利用CPU計算能力。
但若有20級流水線,要確保這20條指令之間無依賴關係。挑戰變大很多。畢竟我們平時撰寫程式,通常前後的程式碼都有一定依賴關係,幾十條沒有依賴關係的指令可不好找。
所以超長流水線執行效率發而會降低。
總結
流水線技術和其他技術一樣,都講究一個“折衷”(Trade-Off)。一個合理的流水線深度,會提升我們CPU執行計算機指令的吞吐率。我們一般用IPC(Instruction Per Cycle)來衡量CPU執行指令的效率。
IPC呢,其實就是我們之前在第3講講的CPI(Cycle Per Instruction)的倒數。也就是說, IPC = 3對應著CPI = 0.33。Pentium 4和Pentium D的IPC都遠低於自己上一代的Pentium III以及競爭對手AMD的Athlon CPU。
過深流水線,不僅不能提升計算機指令的吞吐率,還會加大計算的功耗和散熱問題。
而流水線帶來吞吐率提升,只是個理想情況下的理論值。在實踐的應用過程中,還需要解決指令之間的依賴問題。這個使得我們的流水線,特別是超長的流水線的執行效率變得很低。要想解決好冒險的依賴關係問題,我們需要引入亂序執行、分支預測等技術,這也是我在後面幾講裡面要詳細講解的內容。
參考
Modern Microprocessors, A 90-Minute Guide