從單一核心到一支專家團隊
本梯級前幾篇已替專用化立下了論據:Dennard 縮放已終結、摩爾定律趨緩,你不能再只是乾等一顆更快的通用核心,而功率牆意味著一顆晶片無論如何都有大片得閒置變暗。答案是別再造一台樣樣都做得「還可以」的機器,改為在同一片矽上造好幾台機器,每台都把某一件事做到極致。那種混合晶片就是異質系統,而學會善用它,正是現代計算機結構的核心技能。
把它想成一間醫院,而不是一位單打獨鬥的家庭醫師。CPU 是那位什麼病人上門都能應付的醫師——處理分支多、循序、難以預測的程式碼,正是天才全才勝過上千實習生的那種工作。GPU 是當同一套程序必須一次套到洪流般的大量資料上時,表現最出色的團隊。而硬體加速器則是只做某一種手術、又快又省、但別的都不會的專科外科醫師。異質系統就是把這些人全都留在編制裡、並把每個病人導向對的那位的那間醫院。
你先前見過的彈性光譜,定下了這場取捨。CPU 什麼程式都能跑,但它大部分能量都花在開銷上——取指、解碼、預測分支、重排序——而非真正的算術。FPGA 是可重新組態的硬體,比 CPU 更快更省,但比固定的矽慢。ASIC 則被凍結成單一功能,是其中最快也最省的,代價是不可更改且設計昂貴。你越往右走,效率越高、放棄的彈性越多。異質性讓你把工作負載的每一塊都放在這道光譜上對的那一點,而不是為所有東西付同一個固定價碼。
每一次都是同一套配方
第 3 篇已萃取出領域特定架構的設計準則,而令人驚訝的是它們有多普適。無論目標是深度學習、影片還是密碼學,同樣的四個動作一再出現——因為它們攻擊的都是通用核心永遠打不贏的同一個敵人:被浪費的能量,以及記憶體牆。把這四點記在心裡,幾乎任何加速器都不再神秘。
- 使用專屬、由軟體管理的記憶體。用編譯器明確掌控的小型暫存記憶體(scratchpad)取代那層層疊疊的通用記憶體階層,讓資料恰好落在需要它的地方,於是你永遠不必為一次沒要求的快取未命中或推測式預取付帳。
- 把省下來的電晶體花在更多的算術單元上。CPU 把大部分面積給了控制邏輯與快取;加速器則讓晶粒上佈滿並行運轉的加法器與乘法器,因為那才是真正做事的地方。
- 善用該領域本來就有的平行性。若工作負載像矩陣乘法那樣天生就是資料平行的,就把硬體造成恰好吻合那個形狀的樣子,而非像亂序執行那樣不得不在執行期才重新發掘平行性。
- 降到該領域能容忍的最低精度。若應用對 8 位整數或 16 位浮點就滿意了,降精度單元就更小、更快,搬資料也更便宜——而一個更小的數,在它經過的每一條線上都是更小的能量帳單。
招牌範例:深度學習加速器
要一次看齊這四條準則,最清楚的舞台就是深度學習加速器,而其中最有名的是 Google 的張量處理器(TPU)。神經網路把絕大部分時間都花在一種運算上:矩陣相乘,而那不過是一大堆「先乘再加」的步驟。第 4 篇已剖開 TPU 的核心,那個脈動陣列——一格格微小的乘加單元組成的網格,資料有節奏地泵流而過,於是每個數從記憶體只讀一次,接著就被它流經的每一格重複使用,而不必一遍又一遍重新取進來。
把 TPU 對照這四個動作,每一個都在場。專屬記憶體:一塊大型、由軟體管理的暫存記憶體餵養陣列,沒有快取在旁邊瞎猜。更多算術:CPU 只有寥寥幾個乘法器,這陣列卻塞了數萬個。領域平行性:網格的形狀根本就是矩陣乘法的形狀,因此不需要任何執行期排程。還有降精度:權重與激活值以 8 位整數(int8)或 bfloat16 運轉——後者是一種 16 位浮點,保留了 32 位浮點完整的指數範圍,卻丟掉了網路不會想念的尾數位。結果是一顆晶片在同樣的工作負載上,每瓦能交出遠多於任何通用核心的有用算術。
這裡最深的一課是:瓶頸鮮少是乘法本身——而是餵料給陣列。一個有數萬格的脈動陣列,若因缺料而挨餓便毫無用處,所以大部分設計心力都投在記憶體頻寬與重用上:把高頻寬記憶體堆疊到緊貼運算的地方、精準編排每一個權重與激活值何時抵達、並把每個載入的數重複用在盡可能多的乘法上。先前的屋頂線模型精準刻畫了這點:一個算術強度低(每取一位元組只做幾次運算)的核心受頻寬束縛,再多的乘法器也救不了它。說到底,加速器設計大多是「把資料搬得更少」的藝術。
晶片上的其他專家
機器學習搶盡了版面,但加速器其實由來已久、無處不在,你的手機裡就塞滿了它們。數位訊號處理器(DSP)為音訊、無線電與感測器訊號中那大量乘加的濾波運算而調校。影片編解碼器是壓縮、解壓串流的固定功能硬體;用軟體跑 4K 影片會把電池榨乾,所以一個微小的專屬區塊只用一丁點能量就把它做完。密碼引擎在硬體裡跑 AES 加密與雜湊,讓安全連線不致拖累 CPU。而 SmartNIC 或 DPU 則是網路卡上的一台小電腦,負責封包處理、加密與儲存流量,把主 CPU 釋放出來去做真正的應用工作。
這些專家全都同住在一顆系統單晶片——SoC——上,那單一片晶粒如今是每支手機、多數筆電的心臟。SoC 把 CPU 核心、GPU 與各加速器圍繞著一條共享的晶片內互連與一條通往記憶體的共同路徑綁在一起,於是一個區塊能把結果直接交給鄰居,不必昂貴地離開晶片走一趟。藝術在於佈線:誰共享哪塊記憶體、誰透過晶片網路對話,以及DMA 引擎如何在區塊間搬運大批資料,而核心同時去忙別的。
不過異質晶片並不會自動變快。它的各區塊仍透過共享的互連與記憶體對話,所以多核心那幾篇的危害一樣適用:資料在 CPU 與加速器之間傳遞時必須保持一致,而一次來回複製資料的主機-裝置傳輸,可能把加速效果完全抹除。更糟的是,暗矽(dark silicon)的現實意味著在功率預算內並非每個區塊都能同時運轉——一顆晶片可能搭載遠多於它所能同時點亮的加速器,只點亮當前工作所需的那位專家,其餘任其變暗。
協同設計,以及加速器何時才真的划算
通用 CPU 遵守一份凍結的合約:指令集架構是固定的,編譯器必須讓任何程式去配合它。加速器把這道分隔丟掉了。軟硬體協同設計意味著把矽與驅動它的軟體當成同一個專案一起設計,彼此塑形以契合對方。TPU 的硬體是繞著神經網路框架表達模型的方式而建的,而那些框架也被擴充,好發出 TPU 能原生執行的程式碼。兩者單獨都說不通;加速的效果就活在它們之間的那道接縫裡。
但每位架構師首先必須誠實回答的問題是:到底要不要做加速器,而答案通常是「不要」。一個客製區塊的設計與驗證所費不貲,且一旦出貨就再也不能更改,所以它只有在三個條件同時成立時,才賺得回那個代價。工作負載必須夠大——總工作量得多到足以攤平設計成本。它必須穩定——演算法不能一直變,否則你的矽還沒流片就已過時。而且它必須平行且規律——滿是獨立、形狀一致、硬體能鋪成網格的運算。少了其中任何一個,一顆有彈性的 CPU 或 GPU 都是更明智的選擇。
這梯級,乃至整道階梯的大半,便在這裡歇腳。約莫 2005 年以來,計算機結構的故事是一場被迫的遷徙:單一、不斷變快的核心已不再供應,於是這個領域先轉向多核心、再轉向 GPU,如今轉向塞滿專家的異質晶片。這門手藝不再是把一台通用機器擠得更快——而是把你的工作負載理解得夠深,好決定哪些部分配得上自己的矽、哪些更該保留彈性。協同設計就是這門手藝的具體化身:硬體與軟體,彼此塑形,在這個免費速度已耗盡、唯有巧思尚存的後摩爾時代。