JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

延遲、吞吐量,與效能鐵律

我們已經造出了一台快機器——但「快」到底是什麼意思?這篇導覽要把這個字釘死:延遲對上吞吐量、那一條主宰 CPU 時間的方程式、為什麼百萬赫茲與 MIPS 會對你撒謊,以及 Amdahl 定律如何替你能買到的加速設下天花板。

「快」到底是什麼意思?

走過前幾級,我們造出了一台真正的機器——一條接近每週期退役一條指令的管線、一塊餵它的快取、繞開停頓的亂序執行。工程師一路把每個把戲都叫做讓機器「更快」的辦法。但「快」是個滑溜的字,在我們能量度或改進效能之前,得先說清楚究竟指的是哪一種快。它有兩種,而且彼此並不相同。

第一種是延遲,也叫回應時間一個工作從開始到結束花多久。第二種是吞吐量,也叫頻寬:每單位時間有多少個工作完成。一位每台手術要花四小時的外科醫師,每位病人的延遲很高;一間同時有五十位外科醫師動刀的診所,無論任何一台手術多慢,吞吐量都很高。兩者可以各走各的——而管線化存在的全部理由,正是它提高吞吐量,卻讓單一指令的延遲文風不動,甚至還略差一點。

效能鐵律:一條主宰執行時間的方程式

如果你從這整一級只留下一條方程式,就留這條。一支程式在 CPU 上花的時間,恰好是三樣東西的乘積——這就是效能鐵律:CPU 時間 = 指令數 x CPI x 週期時間。指令數是程式執行了多少條指令;CPI 是平均每指令週期數;而週期時間是每個時脈週期的秒數,也就是時脈率的倒數。把每週期秒數乘上每指令週期數再乘上指令數,週期與指令兩個單位互相消去,剩下的就是秒。它不過是單位的記帳,卻冷酷無情。

效能鐵律之所以這麼好用,是因為每個因子分屬堆疊的不同層,而每一層只能推動自己那個因子。演算法與編譯器決定指令數。微架構——管線、快取、分支預測——決定 CPI。電路與製程技術決定週期時間。所以當有人說他加速了一支程式,誠實的問題永遠是:你動的是這三個因子裡的哪一個,又有沒有不小心讓另一個變糟?用一條花俏的指令砍掉指令數,往往抬高 CPI;提高時脈率,又常因更多停頓而逼高 CPI。

  CPU time  =  instruction count  x  CPI  x  cycle time
              (   how many   )    (cycles  )  (seconds )
              ( instructions )    (  per   )  (  per   )
              (    we run    )    (  instr )  ( cycle  )

  who controls each factor:
    instruction count  <-  algorithm + compiler + ISA
    CPI                <-  microarchitecture (pipeline, cache, branch pred.)
    cycle time         <-  circuits + process technology (the clock)

  example: 1e9 instrs  x  1.5 CPI  x  0.25 ns/cycle  =  0.375 s
效能鐵律,以及每個因子歸誰管。一次加速要真實,前提是你壓低一個因子卻沒有悄悄把另一個吹脹。

為什麼百萬赫茲與 MIPS 會撒謊

現在我們可以拆穿計算界最古老的行銷把戲:百萬赫茲迷思,也就是相信更高的時脈率意味著更快的機器。效能鐵律告訴你為什麼這是假的。時脈率只決定週期時間那個因子;它對另外兩個隻字未提。一顆需要每指令三個週期、又跑著臃腫程式碼的 4 GHz 晶片,輕易就會輸給一顆在更精簡程式碼上平均每指令一個週期的 3 GHz 晶片。提高時脈卻放任 CPI 或指令數膨脹,什麼也買不到——而把時脈往上推,通常還會高 CPI,因為時脈加快時記憶體並沒有變得更近。

它的表親是 MIPS,每秒百萬條指令。它聽起來像個速度,卻數的是指令數,而非完成的工作。回想RISC 對 CISC的設計,會用天差地別的指令數做同一件事——一個 MIPS 數值會獎勵一台跑了更多、更小指令的機器,哪怕程式根本沒變快,而且它在不同指令集之間根本無從比較。浮點的 FLOPS 也害著同一種病:它數的是算術運算,這只對數值密集的程式有意義,對其他一切視而不見。這兩個數字量的都是活動量,而非成就。

加速與 Amdahl 定律:改進的天花板

當我們改進一台機器,會想替「改進了多少」命名。加速比就是舊時間對新時間的比值:如果一支程式從 10 秒掉到 4 秒,加速比就是 10/4 = 2.5 倍。陷阱在於,我們通常只改進一支程式的一部分——把一個熱迴圈放到更多核心上跑,或加速浮點而非其餘部分。而這裡,一段美麗又令人洩氣的算術接管了一切:Amdahl 定律

Amdahl 定律說:若有一個比例 f 的工作被加速了 s 倍,而其餘的 (1 − f) 文風不動,整體加速比就是 1 / ((1 − f) + f/s)。把它推到極端走一遍。假設程式有 90% 完全可平行(f = 0.9),而你丟給它無限多核心(s 趨於無窮,於是 f/s 消失)。你所能達到的最佳加速比,就是 1 / (1 − 0.9) = 1 / 0.1 = 10 倍——再也不會更多,永遠不會,因為那 10% 的序列部分仍得跑。你沒去加速的那部分,變成了天花板,而那道天花板低得殘酷。

這正是為什麼更多核心鮮少買到成比例的加速,也是為什麼一顆塞滿上千個小工人的 GPU,碰上序列、滿是分支的程式碼就英雄無用武之地。它同時也是一句老架構師口號的深層理據——讓常見情況變快:在罕見情況上傾注心力毫無意義,因為 Amdahl 定律早就替那份心力的回報封了頂。改進的多寡,不由你把快的那部分弄得多快來決定,而由你留下多少程式仍然很慢來決定。

把基準測得對,以及誠實的綜合

既然沒有任何單一頭條數字可信,真正的量度就是跑一整組有代表性的程式並替它們計時——這叫基準測試。業界標準的那些,像 SPEC 系列,是一籃子真實應用,正是為了不讓任何單一工作負載獨大。但你要怎麼誠實地把許多程式的加速比熬成一個數字?不能用普通平均:如果程式 A 加速 10 倍而程式 B 慢到 0.1 倍,它們的算術平均是個誤導人的 5.05 倍,儘管把兩者合起來看,整體根本沒有變快。

解法是幾何平均——把這 n 個比值相乘再開 n 次方根。對我們的 10 倍與 0.1 倍而言,幾何平均就是 (10 x 0.1) 的平方根 = 1 的平方根 = 1 倍,誠實地報告「淨變化為零」。它有個關鍵性質:它產生的排名,不取決於你選了哪台機器當基準線。話雖如此,基準測試被無止盡地作弊:廠商調校編譯器去偵測基準程式碼,或挑選奉承自家晶片的測試組。一個基準測試,只有在它像你自己的工作時,才會對你自己的工作說真話。

於是我們停在誠實所要求的地方:一台電腦並不存在單一的「速度」。延遲,對等一個回覆的人重要;吞吐量,對服務數百萬人的資料中心重要;FLOPS,對物理學家重要;而能量,將在接下來的導覽裡最為重要。效能鐵律告訴你能動什麼、以及那歸哪一層管;Amdahl 定律告訴你動其中一部分最多能換回多少;基準測試與幾何平均則告訴你,你究竟有沒有真的動到它。對的指標從來不是放諸四海皆準的——而是那個量到了你真正在乎之物的指標。