?? ??相信各位一直會有相同疑惑:為何今天的x86 處理器市場,臺面上只剩下英特爾和AMD 兩家美國公司?頂多再加個存在感稀薄的臺灣VIA,和少人知悉的俄羅斯Elbrus?對技術有點基礎認知的人,多少會直接想到「x86 指令集很復雜很難搞,又有英特爾的授權問題,所以x86 處理器非常不好做」之類的標準答案。
當然,更不乏某些夜郎自大的高論,像「就算x86 指令集再復雜,控制單元也還是很好設計」、「微指令轉譯早就克服了所有x86 指令集的瓶頸」等。拜托,「做出勉強能動的東西」和「開發出有市場競爭力的產品」完全是天差地別的兩件事,要不然你以為英特爾和AMD 天文數字般的產品開發經費,都拿去填海了嗎?
總之,高效能x86 處理器之所以難做,混雜了諸多技術和商業因素,暗藏在臺面下的細節非外人足以道也。但我們可以回到x86 處理器最重要的歷史轉捩點:1993年Pentium 處理器,抽絲剝繭一般人難以察覺到的蛛絲馬跡。 以「唯偏執狂得以生存」(Only theParanoid Survive)留名于世的英特爾創辦人之一安迪·葛洛夫(Andy Grove) 曾經說,2003 年的Centrino 是英特爾的「第二個兒子」與「十年來最重要的品牌」 ,那「第一個兒子」和「十年前最重要的品牌」,想當然爾就是1993 年的Pentium 了。
Pentium 之名起源于希臘文的Penta(意思是「五」),再加上拉丁文的ium 結尾,意指「第五代x86 處理器」,英特爾自此也不再使用80×86 來定義處理器世代(要不然現在還真的講不出來到底是「幾86」)。而Pentium 也在不知不覺中,一步步轉型為入門級低價處理器品牌,更不再受限于1993 年的P5,進而橫跨歷代英特爾的超標量(Superscalar)x86 微架構。
原始Pentium 里的P5 處理器微架構,并沒有像后繼Pentium Pro 的P6 活得如此之長,影響又如此深遠(到2011 年Sandy Bridge 才結束)。但Pentium 問世的時機,卻是眾多歷史機運的集大成:
「x86 處理器走向高效能化」。
「x86 開始與RISC 正面競爭」。
「x86 指令集的缺陷讓廠商感到棘手」。
「x86 處理器進軍多處理器平臺」。
「個人電腦市場因Windows 95 的問世而蓬勃成長」。
「筆記本電腦即將逐漸普及」。
「英特爾默默埋下讓擅長改良的以色列海法研發團隊,主導x86 處理器技術發展」。
「x86指令集的兼容性,成為其他競爭者的潛在障礙,也造成軟件開發商的困擾」。
這些因素交錯,奠定了之后25 年技術演進與市場發展的基礎邏輯,連時下「AMD 處理器的核心太多,竟然造成Windows 操作系統的大麻煩」,也和Pentium 留下的遺產,多少有些千絲萬縷的糾結。 既然連AMD Zen成功的背后,都有這么多不為人知的故事,了解英特爾「Landmark」芯片Pentium的軌跡,將有助跳脫琳瑯滿目的技術營銷名詞,重新建立屬于自己的「x86處理器世界觀」,值得各位細細品味。
x86 指令集先天不足后天失調的原罪
催生「計算機結構」(ComputerArchitecture)一詞的「指令集架構」(Instruction Set Architecture),為「電腦的基礎語言」與「軟硬件中間的接口」(Interface Between Hardware and Software),相同指令集的電腦理應可執行一樣軟件,具備彼此兼容性,對電腦與處理器微架構(Microarchitecture)的未來發展有舉足輕重的影響力。
不同的時空背景,也會產生相異的指令集設計理念,沒有絕對的優劣對錯──x86算是少見的例外,另一個則是DEC VAX,兩者的共同點只有「著毋庸議」的糟糕,英特爾IA-64(Itanium)和DEC Alpha的激烈反動,足以證明連生父都如此厭惡小孩。
? 說到指令集架構如何影響處理器微架構的設計,這幾年來最有名的實例,就是蘋果利用充分掌握封閉平臺的優勢在「最短時間內驅逐32位元應用程序」,掌握ARM指令集邁向64位元的過程帶來的改革與機會,讓A7之后的自家ARM處理器,徹底為64位元的ARMv8-A量身訂做,研發出一系列能同時有效處理更多指令的先進微架構。
所謂的CISC(復雜指令集電腦)出自存儲器容量稀少、缺乏成熟的高級語言編譯器、大多數人使用語言撰寫程序的時空背景,程序設計者寄望直接用透過微碼(Microcode)組成功能強大的單一指令,像十進位數字和復雜字串處理等,撰寫應用程序。 相較之下,RISC(精簡指令集電腦)則是在「萬事皆備」的環境,追求更快更便宜的電腦,將晶體管預算砸在「最經常被使用的簡單指令和運算元定址模式」的刀口上,盡量用硬件線路去取代微碼,并藉由強制僅載入(Load)/儲存(Store)指令可存取存儲器,搭配大型化的數據寄存器與快取存儲器,填補處理器和存儲器之間越來越大的效率鴻溝。
時過境遷,在x86 主宰云端數據中心、中低端服務器、工作站、桌面機一路到筆電的今日,可能已經沒有多少人能回想起「RISC 與CISC 之爭」曾發生在1990 年代初期的史跡,但畢竟x86 指令集公認是充滿缺陷的產物,連當代最偉大的計算機結構教科書都「白紙黑字」并「燒錄」于無數莘莘學子的腦中,而AMD K5 的創造者更是用一句「毫無道理可循」(it just doesn'tmake a lot of sense)一錘定音,幾無爭議空間。 讓人滿臉黑線的,只有動輒揮出「逆向思考全壘打」的大恩大德,將x86 的市場勝利,視為「x86 指令集架構優良」佐證的天真論點,并時有所聞,連ARM 都比x86 更「存儲器存取密集」(Memory-Intensive)這種話都講得出口。
我們先來瞧瞧當年AMD K5 的總工程師Mike Johnson 怎么評論x86 指令集,由設計x86 處理器的大師級人物(他本人的確是超標量流水線技術的先驅者,那份變成首本超標量技術專書的史丹佛大學博士論文非常有名,附錄更深度分析設計超標量x86 處理器的困難點)寫出來的批評,特別有說服力,也一再被后人引述:
從這短短一段話,可看到幾個重點: 「毫無道理可循」(doesn't make a lotof sense):相較于指令編碼程度統──4 Bytes(32 bits)的多數RISC體系,x86指令集的格式和編碼極度混亂,長短粗細肥瘦不一,從1~17 Bytes都有可能。影響所及,遍及所有的環節,從快取存儲器擷取指令、實作指令流水線化,到處理器發生中斷例外時要迅速儲存執行狀態并盡快回復等,都造成非常嚴重的后遺癥,激增研制高效能x86處理器的門檻,也增加驗證產品的時間與成本。
「缺乏足夠的寄存器」(the lack ofregisters):一般RISC指令集都會定義32個通用數據寄存器(講的精確一點是31個)或浮點運算寄存器,但x86在64位元和AVX之前,怎么樣都只有少少的8個(因為要扣掉ESP和EBP,說6個或許比較貼切)。當引進指令流水線化和更先進的超標量流水線后,自然就激增了寄存器沖突的機率,這也是激發x86處理器擁有強大非循序指令執行(寄存器重新更名)與高效率存儲器子系統的主因。
「讓人感到極度痛苦的定址模式」(extremelypainful addressing scheme):定址模式講得白話一點是「存取所需運算元(運算的目標,例如某個寄存器或某個存儲器位址)的方式」,歷經多年疊床架屋的x86定址模式,尤其是惡名昭彰的節區存儲器(Segmentation),不只加重產生有效位址的工作負荷,也激增整數邏輯運算(ALU)和控制單元的復雜度,「副作用」跟第一項「毫無道理可尋」可謂不相上下。
這些燙手山竽,就是1980 年代末期和1990 年代初期,眾多企圖研制高效能x86 處理器的有志之士,包含不小心制造出這些「炸彈」的英特爾,不得不面對并設法克服的挑戰,身為x86 世界首顆「超標量(Superscalar)流水線」處理器的Pentium,則是第一個提出的「有效解決方案」,英特爾為此付出了不小代價。
一個時鐘周期執行一個以上指令的「超標量流水線」 近似近代工業生產線的概念,讓所有人都「閑閑有事做」的流水線化(Pipeline)一直是提高效率的最基本手段,80386 的預先指令擷取(Prefetch)已有雛型,而80486 是x86世界首款真正達成指令流水線化的處理器,為了確保存儲器跟得上運算需求,也配置指令/數據共用的第一階快取存儲器,雖然真正「每個時鐘周期都可穩定輸出」者,也只限于簡單的整數邏輯運算指令。
「一個時鐘周期內執行一個以上指令」的超標量流水線(Superscalar),早在1965 年發跡于RISC 始祖的CDC6600,1980年代陸續出現在RISC 處理器,如1985 年Power 前身的IBM「America」計劃(也是「超標量」一詞由來)、1988 年Motorola MC88100、1989 年英特爾i960CA、1990年AMD 29050 等。各位絕對沒看錯,英特爾、AMD 也做過RISC 處理器。 指令流水線化、超標量流水線、非循序指令執行、大型化快取存儲器等常見的效能加速手段,清一色優先降臨RISC 處理器的原因,也很簡單:RISC 指令集的單純性與簡潔性,讓設計者更輕易導入這些技術,并用更短的時間完成產品開發與驗證。
1990 年代上半期,一提到高效能處理器,幾乎都由RISC 獨領風騷,像至今碩果僅存的IBM Power、HP 的PA-RISC、SGI 的MIPS、Sun 的UltraSPARC、Fujitsu 的SPARC64及充滿傳奇色彩的DEC Alpha 等,這也是「RISC 優于CISC」的理論基礎。 但「理論」是一回事,不代表CISC 的x86「實務上」做不到,更何況又是擁有一整支龐大「研發軍隊」的英特爾,革命性的第五世代x86處理器Pentium 在1993年3 月22 日登上歷史舞臺,不只要迎擊來自AMD、Cyrix、NexGen(被AMD 購并,Nx686 變成K6)的競爭產品(之后還多出Centaur 和Transmeta),更要面對AIM 聯盟(Apple、 IBM、Mororola,不是美國的空對空飛彈)PowerPC 的挑戰,后者享有威鎮四方的「RISC 王者」IBM Power 當強大后盾,市面更不乏「專書」鼓吹PowerPC 相對x86 的優越性,把Pentium批評得一文不值。
更扯的是,意圖搶奪英特爾勢力范圍的IBM 還開發了「腳位與Pentium 兼容,可以同等效率硬件執行x86 程序碼,并兼具32 / 64 位元PowerPC 指令集兼容性」的PowerPC 615,要不是微軟可能覺得難搞,不符成本效益,拒絕支持這顆處理器,導致永遠無法量產,英特爾的處境會更危險。至于PowerPC 615 取消后,研發團隊就投靠Transmeta,接著就無疾而終了。
也許各位難以想像「為什么x86 會受PowerPC 威脅,不是屬于不同市場嗎」,但此時此刻,沒半個正常人會將連服務器市場邊都沾不上的x86 和「高效能」三個字聯想在一起,甚至連那時候英特爾內部,都很少人愿意相信x86 還有未來性,否則也不會出現IA-64 指令集和Itanium 處理器了。況且微軟1993 年7 月發表未來操作系統基礎的WindowsNT,打從一開始就同時支持x86、MIPS 和Alpha 三版本,之后還加碼PowerPC 和IA-64,「不將雞蛋放在同一個籃子里」意圖太明顯了。
換句話說,英特爾當時的戰略地位,并不像今天如此牢不可破,更早在1990 年同步啟動第六世代Pentium Pro 研發案,完全沒有承受失敗的本錢與余裕。 天底下沒有白吃的午餐 Pentium 是如假包換的x86 世界首款超標量處理器,可在同一個時鐘周期內執行最多兩個指令,整體結構近似雙重流水線的「放大發展版」80486,但也因扛著x86指令集的原罪,由外到內付出了不少代價。爬文至此,建議各位回頭復習一次Mike Johnson 評論的3 個重點,你一定會更有感觸。
我們光從初代Pentium(P5)的晶粒圖,即可清楚看到x86 兼容性的代價:大型化的快取存儲器(盡管實質容量不高,但內部結構卻出奇復雜)、巨大的指令擷取單元、解碼與復雜指令微碼控制單元(Complex Instruction Support),這也是日后所有高效能x86 處理器的共同特色。
? 指令/數據分而治之的第一階快取存儲器:x86指令集因缺乏足夠的數據寄存器,且包含了大量「寄存器/存儲器互通有無」與直接以存儲器為運算目標的指令,不像RISC的「載入/儲存」架構「一次從存儲器抓了大量數據進來,算完后再一次性丟回存儲器」,特別需要強力的存儲器子系統,所以采用指令/數據分開的第一階快取存儲器,確保兩邊足以喂飽個別的需求。而Pentium的指令快取和數據快取,更是各自大有文章。
前面有提及「x86 指令最大長度是17Bytes」,Pentium 第一階指令快取的內部結構,是以兩個最小存取單位16Bytes 區塊,組成單一32Bytes 的快取線(Cache-Line),假若發生最糟糕的情況,17Bytes 長度的指令「橫跨」了兩條32Bytes 快取線,但仍希望一次擷取到指令流水線,那該怎么辦?Pentium 導入跨指令線分離式擷取(Split Fetch),可連續讀取橫跨邊界的兩條16Bytes 最小區塊,而指令讀取緩沖區也是4 倍于80486 的128Bytes,以確保擷取指令的效率可「喂飽」兩條流水線的指令解碼器。
? 順便對照一下從NexGen Nx686 發展而來的AMD K6。AMD 取消了兩倍核心時鐘頻率的第一階快取存儲器,但除了既有的預先解碼位元(Pre-decoded Bits)用來標定指令邊界,再追加第二個指令存取埠,以應付這種狀況。反正各家廠商都各顯神通,直到可降低指令解碼器使用率的微指令快?。╱Op cache)同時成為英特爾和AMD 的制式武裝為止。 數據快取亦不遑多讓,數據快取具備3 個存取埠,可同時應付來自快取數據一致性協定與雙重執行流水線的需要,更進一步將每條32Bytes 快取線,切成彼此交錯的8 個獨立4Bytes「Bank」,只要兩個數據存取需求不會同時使用同一個Bank,即可在單一時鐘周期內搞定。
這是計算機工業史上的第一次嘗試,但這也大幅加重了快取存儲器的復雜度,也連帶不得不強化配置數據快取的虛擬/實體位址轉換緩沖區(TLB,Translation-Lookaside Buffer ),并新增判斷Bank 是否發生沖突的功能電路。 巨大的微程序只讀存儲器:基于「加速常用的簡單指令」的理念,Pentium 的指令解碼器可直接硬體解碼大多數「寄存器→存儲器」與「存儲器→寄存器」之類的「相對簡單」運算指令,但 x86 歷代累積下來的龐大復雜指令,還是需要動用微碼組成微程序產生控制訊號。 Pentium 的單一微碼字元長度是 92Bits,總共存放了 4K 數量。換言之,產生了高達 47kB 容量的只讀存儲器(ROM)空間,還遠多于第一級快取記憶體的容量(8kB+8kB),相當驚人,老舊指令兼容性帶來的巨大負擔,由此可見一斑,這就是維持回溯兼容性,所必須付出的昂貴代價。
4 個輸入的位址計算單元:一套所謂「復雜」的指令集,除了不規則的指令編碼長度,亂無章法的運算元定址模式和存儲器定址,更是必備的條件(可回顧一下 AMD Mike Johnson 講過的話)。實現高效能的超標量流水線 x86 處理器,并非只需弄好流水線前端的指令擷取、解碼,與執行階段的存取存儲器,高效率的有效位址計算(Address Calculation)能力,更是 x86 有別于 RISC 體系的一大差異點,坊間人云亦云、積非成是的「x86 處理器只有指令解碼器比較難做」完全是大錯特錯的誤解。
為了加速存儲器位址計算,讓執行單位盡快得到「運算目標」,Pentium 的兩條指令流水線個別有一套 4 個輸入值的加法器(4-Input Address Adder),對應 x86 指令集產生有效位址的 4 個數字: 節區描述器(Segment Descriptor)提供的基底值(Base)。 來自通用寄存器的基底位址(Base Address)。 取自通用寄存器的索引值(Index,再加上scale)。 指令編碼附上的的移位值(Displacement)。 因此部分僅支持 3 個輸出值的 486,需耗費兩個時鐘周期完成位址計算的復雜指令,Pentium 只需一個時鐘周期週期即可,更利于流水線化執行指令。 ?
? 但慘劇尚未劃下句點,x86 的節區存儲器(Segment),必須強制檢驗每個節區的大小,確保存儲器運算元落在節區描述器所定義的存儲器范圍內。80286 時代的保護模式,節區描述器會影響節區位置與體積的參數,總計有:
32 位元基底值(Base)。
20 位元范圍值(Limit)。
范圍值單位Page 或Byte(前者上限4GB,后者則1MB)。
針對堆疊(Stack)數據結構的向下擴展(Expand-Down)欄位。
處理器需采取不同的方式計算最高與最低位址,結果Pentium的兩條指令流水線,為此個別又得「再」加上一套4 個輸入值的加法器(4-Input Segment-Check Adder) ,為檢查節區正確性之用,而486的情況如上述位址產生器,須耗費更多時鐘周期做這件事。
? 為何「位址計算單元」一向是歷代x86 處理器增加執行單元的重頭戲,原因就在此。Windows 95 刺激個人電腦普及的年代,「32 位元最佳化」的Pentium Pro 被批評「16 位元效能不佳」就因動到數據節區寄存器的指令,無法被非循序預測執行,會讓隨后的指令上演大塞車,到了Pentium II 才修正。即使假以時日,這些老舊包袱的使用率只會越來越低,也早不再是改善效能的重點,但也沒人膽敢冒著犧牲軟件兼容性的風險,根除這些歷史遺跡。
正面對決PowerPC 且落居下風 相較于同時期且較早推出的超標量RISC 處理器,就可明顯看出x86 指令集的復雜度造成的負面影響。 以1993 年秋季上市的IBM PowerPC 601 為例,晶體管數目僅280 萬,采用0.6um(600nm)制程時的晶粒面積僅121 平方公厘,卻有比晶體管310 萬的Pentium 更高的80MHz時鐘頻率、更大一倍的32kB 指令/數據共用式第一階快取存儲器,與1.5 倍的指令執行能力,而采用0.8um(800nm)制程的初代Pentium是一顆16.7×17.6mm、294平方公厘的巨大芯片,完全瞠乎其后。英特爾當時就表示,相較于同等級RISC 處理器,Pentium 有約30% 晶體管都「貢獻」給x86 指令集的兼容性。
不難想見那時候的「RISC 十字軍」有多high。 而Pentium 的雙重超標量指令流水線也是限制重重,只有主流水線「U Pipe」可以執行所有的x86 指令,副流水線「V Pipe」僅能負責比較簡單者,而要這兩條流水線一起動,還需要依循指令配對規則,講白了就是「兩邊都要跑簡單指令」,且涉及寄存器和存儲器兩邊數據互相搬移的指令也無能為力,就是要強迫其中一條流水線「發呆」兩個時鐘周期給你看。PowerPC 601「理所當然」比較沒有這樣的煩惱。
? 80×87 浮點指令集更是x86 處理器追求高效能浮點運算的罩門,因「英特爾內部溝通不良」(英特爾美國加州總部和以色列海法之間實在太遠了,1970 年代末期的聯絡手段又沒像今天這么方便)誕生的「極度愚蠢」堆疊式(Stack)寄存器架構(附贈讓人摸不著頭緒的80 位元延伸雙倍精確度浮點格式),強迫多數浮點指令的運算元,其中一個非得指定放在堆疊寄存器的頂端不可。
? 英特爾在Pentium 加入FXCH 指令用來交換置頂寄存器,原本僅內建一組浮點運算單元,流水線不能同時執行兩個浮點運算指令的Pentium,簡單的浮點運算指令可和FXCH 一同塞進兩條指令流水線,但實際上也只有執行一個有效浮點運算,況且后頭接連著的整數指令,都會被延誤最少一個時鐘周期。 判斷分支條件需「借用」整數運算通用寄存器與執行單元,則是80×87 另一個弱點,從一個浮點運算設定條件碼、將浮點運算的執行資訊搬移至通用寄存器、傳送至條件碼寄存器,再依據其結果,啟動正常的分支處理流程,Pentium 整整耗時9 個時鐘周期。
當然可透過「插入」其他整數指令來降低效能損失,但無法彌補當執行條件判斷密集的程序,整數浮點單元之間反覆「踢皮球」的傷害。 這些在今天只會讓人覺得很荒謬的往事,讓Pentium 的浮點性能仍遠遠不及同時期的RISC 處理器,只能在x86 的世界當大王,這宿疾到了新一代Pentium Pro 依舊無解,同期MIPS R10000 的SPECfp92 浮點效能還是Pentium Pro 的「3 倍」以上,還因為PowerPC「外掛」AltiVec 而一度被拉開差距到差點看不見車尾燈的程度。
直到Pentium III(Katmai)開始擴充SIMD(單一指令,多重數據流)浮點指令集SSE、初代Pentium 4(Willamette)的SSE2 新增雙倍精確度浮點格式,一路到Sandy Bridge 的AVX,引入VEX (VectorExtension)標頭,一口氣解放了過去x86 指令編碼帶來的重重枷鎖,才算功德圓滿。
? 但即使看似出師不利,x86 指令集的沉重包袱,并未讓英特爾就此停下腳步,依然持續精進Pentium 處理器,就算沒有一鼓作氣打開天堂大門,卻也讓緊閉已久的門縫滲出充滿希望的曙光。 從企圖殺入很長一段時間內「可遠觀不可褻玩焉」的服務器市場,預期Windows 95 激發個人電腦市場爆發性成長時,補足高效能桌機和筆記型電腦需要的基本功能,到迎合「多媒體」的新潮技術營銷名詞,無不是英特爾1990 年代初期念茲在茲的技術發展重點。這些努力的痕跡,統統一字不漏深深刻在Pentium和整個計算機工業的歷史上。
原汁原味的多處理器支持性
「多處理器支持性」是進入工作站與服務器市場的最低門檻入門票,而Pentium 則是x86 歷史上首度「原生支持(Glueless)多處理器」的先行者,但嚴格說來,這到了0.5 um 制程的第二代Pentium(P54C)才實現,而在此之前,也并不是沒有「多處理器x86」的存在,只是需要外掛特制的系統芯片組,或連操作系統都要特殊版本。 一個便于實作的「無需外掛額外芯片」(Glueless)的多處理器(或多核心)環境,需具以下條件:
分配、協調各I/O 周邊裝置存取處理器需求的能力,發出中斷(Interrupt)時,知道該由哪個處理器負責:標準化的中斷處理機制。
快取存儲器數據一致性協定(Cache ? ? Coherence Protocol):回寫式(Write-Back)快取存儲器常見的MESI(Modified, Exclusive, Shared, ? ? Invalid)協議。
低成本多處理器系統的根基:可讓多處理器共享的系統總線。
3 項條件之一,最重要者莫過于第一項。1983 年,17 名因英特爾極具野心的「32 位元微電腦大型主機」iAPX432 計劃失敗而離職的員工,創立的Sequent ComputerSystems(1999 年被IBM 購并,研發高階英特爾處理器的系統芯片組),就曾推出一系列采用80386 與80486 的多處理器產品線,但這些花費不菲的專屬方案,仰賴特制系統芯片組與定制化過的操作系統,才能正確的將系統中斷(System Interupt)傳送到各處理器,多處理器x86 平臺仍缺標準化的中斷處理機制,并非可長可久的解決之道。
? 1993 年10 月27 日,也是初代Pentium 發表后的半年,英特爾首度公開第一版「多處理器規范」(MPS,Multi-Processor Specification)與最重要的「處理器本地端先進可程序化中斷控制器」(Local APIC,Local Advanced ProgrammableInterrupt Controller)與I/O 專屬的I/OAPIC,取代老舊的8259 PIC。 每個Pentium 或80486 處理器起碼要有一個Local APIC,與系統I/O 芯片組的I/O APIC,透過獨立于系統總線的3 位元APIC Bus,I/OAPIC 將周邊裝置的中斷需求傳遞給處理器的Local APIC,以決定中斷服務需求該指派給那些處理器,踏出了低成本多x86 處理器系統的第一步。
英特爾的競爭對手并非沒有替代方案,1996 年上市的Cyrix 6×86 依據OpenPIC規范,支持自家定義的SLiC,但也只有VIA 的Apollo 芯片組對應此規格,基本上有跟沒有一樣,而AMD的x86 多處理器環境,更是要等到1999 年采用Alpha EV6 總線、理論上最多支持14 顆處理器的K7了。
不過初代Pentium 并未內建Local APIC,同時期系統芯片組也沒有I/O APIC,要打造多顆Pentium 平臺,每一顆Pentium 需外掛一顆單價高達26 美元、兼具Local APIC 與I/OAPIC 兩者功能的82498DX,I/O 也需動用一顆。換句話說,雙處理器系統就需要用到3 顆,怎么看都不算便宜,還會占用不少主機板空間。 ? 后來0.5um 制程的第二代Pentium(P54C)變成史上第一顆整合Local APIC 的x86 處理器,對應的系統芯片組也陸續在南橋(South Bridge)內建I/O APIC(未內建者,可選配專用的82093AA I/O APIC),總算讓雙Pentium 搖身一變,成為「Glueless」的多處理器平臺。
受制于缺陷重重的系統架構,如效率不足的系統總線、處理器缺乏非循序存儲器存取能力、處理器共享外部的第二級快取存儲器讓總線問題更加雪上加霜等等,并未讓Pentium 在服務器市場取得重大突破,到了Pentium Pro 面世后才迎刃而解,開啟Xeon 統治服務器市場之路,那又是另一段截然不同的故事了。
決定處理器核心/線程上限的Local APIC 與闖禍的操作系統支持性 處理器核心持續激增的今日,Local APIC 最重要的角色在于決定處理器的核心與線程上限。原先最早的APIC 上限是15,2000 年Pentium 4 開始出現的xAPIC(將APIC 的3 位元專屬總線直接「融入」系統總線的通訊協定,避免APIC 運作時影響存儲器存取效能)增加到255,2008 年Nehalem 的x2APIC更多達4294967295,可視為「無限大」。 假如各位想多學些對親朋好友炫耀的「無用知識」,稍微花點腦筋,牢記一下這3 個數字的由來:
APIC:Pentium和Pentium Pro(與Pentium II、Pentium III、P6核心的Xeon)動用Local APIC的ID寄存器24-27四個位元,16進位的0xF(10進位制的15)用做廣播,所以2 4 ?1=15。
xAPIC:Pentium 4到Penryn用到Local APIC的ID寄存器24-31八個位元,16進位的0xFF(10進位制的255)用做廣播,所以2 8 ?1=255。
x2APIC:Nehalem開始使用存于MSR(Model-Specific Register)的32位元x2APIC ID,16進位的0xFFFFFFFF(10進位制的4294967295)用做廣播,所以2 32 ?1=4294967295。
但帳面上的「理論值」讓人看得很爽是一回事,微軟這些操作系統廠商是否乖乖買單又是另一回事。很不幸的,AMD Zen2 世代EPYC 與Threadripper將單顆處理器的實體核心術/邏輯處理器,一舉推進到64 核/128緒,就變成微軟Windows 的災難了。
一臺2 顆EPYC 7742 或7702 的服務器,擁有128 個處理器核心和256 條線程,但是Windows Server 2016 和2012 R2 并不支持「AMD 新型平臺的x2APIC」,無法吃下這么多邏輯處理器。 事實上,根據微軟的EPYC 性能調校文件,Windows Server 2019 之前的舊版Windows Server,只能支持2 顆48 核心的EPYC 和192 個邏輯處理器。安裝2019 年9月前的Windows Server 2019,也需要事先在BIOS關閉x2APIC 和多線程,安裝完畢并裝完所有的系統更新檔,重新開機進BIOS 恢復功能,才能在工作管理員的效能選單看到全部CPU。
再次同場加映AMD。剛好前陣子Anandtech 有特別報導的EPYC 在Windows 10 發生的災情(盡管這和APIC 沒有關系)。Windows 系統核心會預設64 個CPU組成一個「Windows Processor Group」,當邏輯處理器超過64 個,會將多出余數包成另一群,像一顆64 核/128 緒的Threadripper,就會變成一顆實體CPU 有「兩包」64 個邏輯處理器。
? 但Windows 10 要企業版(Enterprise)才提供此功能,家用版(Home)和專業版(Professional)會將「滿出來的部分」,誤判為占用另一個處理器腳位的實體CPU,意思就是誤解成「兩顆」處理器的系統,將誤導操作系統的線程排程,降低系統效能,這時關掉多線程,很可能表現還比較好。
在計算機的世界,任何「看起來很棒」的技術和功能,無不是「軟硬兼備」的成果,當入手頂規的硬件時,也請多多關心手上的軟件環境是否可發揮最高效益。筆者現在都可以猜到花大錢買TR 3990X 的「長輩」急著升級Windows 10 企業版的畫面了。 「讓人比較有感」的指令集擴展 如果能讓筆者選擇,其實x86 指令集擴張史中最重要的一幕,絕對是邁向32 位元的80386、虛擬86 模式(Virtual 8086 Mode)與具備分頁表的虛擬存儲器。
但事隔多年,印象最深刻的,依舊對個人電腦市場規模爆炸式成長、使用者急速增加的1990 年代,英特爾在Pentium 家族干的一堆好事,包括極具歷史意義的第一次SIMD 擴張:MMX。
相信各位不可能不知道CPUID 這經常用來辨識處理器廠牌、功能、版本與規格的好工具,但你們知道背后作這件事的「CPUID」指令,就是從Pentium 開始登場的嗎?眾多程序設計師計算指令執行周期數的RDTSC(Read Time-Stamp Counter),也伴隨著Pentium 而生。用在操作系統避免不同線程同時對共用資源讀寫「互斥鎖」的CMPXCHG8B(Compare and Exchange 8 Bytes),也是小有名氣,WindowsXP 就是因這個必備指令,無法執行于Pentium 之前的所有x86處理器。
前面有提到MSR(Model-Specific Register),意指在x86 架構處理器中,一系列用于控制處理器執行、功能開關、除錯、追蹤程序執行、監測處理器效能等功能的寄存器。MSR 的雛形始于80386 和80486,到了Pentium,英特爾新增RDMSR(ReadMSR)和WRMSR(Write MSR)指令用于讀寫MSR,使其真正的實用化。此外,軟件可透過前述的CPUID 指令,查詢處理器可支持的功能,并確認這些功能對應的MSR 是否存在。 同時英特爾在Pentium「復刻」筆電專用的80386SL 和80486SL 處理器,那獨立于真實模式和保護模式,干了哪些好事,連操作系統都不知情的系統管理模式(SMM,System Management Mode)。
英特爾制定SMM 的初衷,在于讓筆電OEM 廠商自訂必備的電源管理與周邊裝置管理,如為了省電,動態關閉用不到的周邊設備,需要時再重新啟動等,將SMM 從「特殊武器」提拔成「制式裝備」,暗示英特爾認定筆電即將普及化的未來。 順道一題,相對于x86 指令集在節區定址定義4 層權限的Ring 0 到Ring 3(數字越小權力越大),SMM 的權限經常戲稱為Ring -2,那Ring -1 跑到哪去了?答案是x86 硬件虛擬化技術用來攔截「在使用者模式仍會更動系統底層的危險指令」的Hypervisor 權限。
這些指令集擴張看似微不足道,遠不如那票SIMD(MMX、SSE、SSE2、SSE3、SSE4、AVX、AVX-512)「華麗壯大」,卻也是不可或缺的基本功,同為「高效能處理器不可被分割的一部分」。但Pentium 史上最知名的指令集MMX,就是一場歡樂異常的連續劇了。
為了MMX 讓Pentium 被迫大興土木、脫胎換骨 Windows 95 帶動個人電腦的多媒體需求,英特爾自然不能免俗,勢必要讓處理器跟「多媒體」沾上邊,試圖推動主機板加掛一顆來自第三方的數位訊號處理器(DSP),專門處理即時性影音應用程序。但因為NSP 的運作模式是獨立于操作系統的化外之民,等于需要操作系統開后門,微軟為此拒絕買單,因此胎死腹中,才出現了MMX。
打從英特爾在1996 年,拋出MMX 這從未講清楚說明白的「無意義技術營銷商標」,全名一直眾說紛紜、莫衷一是,還先后出現3 個版本:
MultiMedia eXtension
Multiple Math eXtension
Matrix Math eXtension
名稱怎樣不重要,各位只要記得一件事:為了操作系統兼容性,MMX指令集借用x87 浮點運算寄存器(80 位元中的64 位元)的SIMD「整數」運算,這樣就夠了。英特爾定義全新SIMD 寄存器,從Pentium III「Kaimai」的SSE(KNI,Katmai New Instructions)才開始。
指令集的編碼空間畢竟有限,英特爾要從哪里擠出這57 個指令的位置?英特爾將腦袋動到「0Fh」開頭的運算碼(Opcode),這卻造成前所未見的麻煩:過去0Fh 的主要用途「當處理器的解碼器收到時,自動將該指令執行流程跳到外掛的輔助處理器」,當初英特爾就靠這招來處理8087 浮點輔助處理器,0Fh 開頭的x86指令都不是什么「需要追求效率」者,也因此,Pentium 的指令解碼器也沒有特別「關照」它們,意味著難以迅速完成解碼MMX 指令的重責大任。
主導Pentium MMX(P55C)研發的以色列海法團隊,不得不大興土木,將指令流水線深度從五階延長到六階,爭取足夠的指令解碼時間。多這一階并非有害無益,因為執行單元將有更充裕的時間存取數據快取,并縮短電路的關鍵路徑,利于提高時鐘頻率,讓Pentium MMX 最終可到達300MHz,比前代P54C 多出整整50%。
? 但延長指令流水線也帶來更嚴重的分支預測錯誤代價,英特爾索性將「流水線深度長達12 階」的第六世代Pentium Pro 搭載的雙層動態分支預測與副程序返回位址緩沖區等先進技術,原封不動的逆向移植到Pentium MMX,亦倍增快取存儲器和數據寫回緩沖區,轉換虛擬和實體存儲器位址的TLB,也強化為可同時處理兩種不同分頁大小的版本,種種改進項目仿佛威而剛,讓吃下藍色小藥丸的Pentium MMX 搖身一變成「5.5 代」x86 處理器。
? 為了減少耗電與發熱,英特爾將MMX 執行單元與實體寄存器獨立于x87 浮點運算器,執行MMX 指令時,因指令集定義「邏輯上MMX 和x87 浮點無法同時執行」,可關閉「吃電如喝水」般的浮點單元以節約電力,可是結合加倍的快取存儲器和種種增強方案,P55C 晶體管數從P54C 的330 萬激增到450 萬,制程從「不計多出10%芯片面積以追求最高時鐘頻率」的350 納米BiCMOS 改進為「自此英特爾轉向追求更低成本并降低耗電」的280 納米CMOS,芯片面積和制造成本仍足足比P54C 多50%。
Pentium MMX 在1997 年1 月上市沒多久,同年5 月同樣支持MMX的Pentium II 就以「塑膠大彈夾」外觀,現身于各地電腦賣場的玻璃柜,無論怎么看,Pentium MMX 都是過渡期強烈的尷尬產物。
(Source:Flickr/AndyRogers??CC BY 2.0) 但Pentium MMX 對英特爾在以色列海法的研發團隊而言,卻是極為重要的歷史里程碑,建立起「擅長精煉現有架構壓榨更多價值」的名號,接連重塑P6 微架構成為Centrino 心臟的PentiumM (Banias, Dothan)、當英特爾在Pentium4(NetBurst)慘遭滑鐵盧的危急存亡之秋端出Core 2(Merom, Conroe, Woodcrest)救駕成功、融合P6 與NetBurst 之長的Sandy Bridge 終結AMD K8 的輝煌歲月、直到「奮六世之余烈」集大成的「終極x86 微架構」Skylake,清一色都是出自以色列海法團隊的不朽杰作。
x86 指令集長期欠缺標準造成競爭對手與軟件開發商的困擾 Pentium 的「歷史地位」倒是值得另外添一筆:x86 指令集欠缺公開業界標準,搞死不少人的陳年舊帳,終于正式浮上臺面。 Pentium Pro 總工程師之一的Robert Colwell 回憶錄《The Pentium Chronicles》說過,開發一顆x86 處理器,最艱巨的挑戰在于「如何保證可兼容所有舊程序」。特別早期x86 處理器,很多未定義的運算碼(Opcode)并沒有遮掉,被人發現又拿來用了,以后的處理器開發人員就只能乖乖想辦法「塞」進去,前提是你也要知道這些陷阱到底藏在哪里。
各位是否天真的以為所有x86 處理器廠商的產品,都保證彼此兼容,可執行一模一樣的軟件?很遺憾的,這種好事從來就不存在英特爾統治的x86 世界(最起碼,前陣子讓Linus Torvalds 大暴走的AVX-512,AMD 現有產品也是付之闕如),英特爾在Pentium 時代的所作所為就是最好例證,讓初版使用者手冊描述新增指令的「附錄H」故意保持完全空白,英特爾的競爭者與軟件開發商紛紛變成倒霉的苦主。
英特爾并不像那票會定期推出版本演進與相關規范的RISC 指令集(有關心ARM 的讀者應該很清楚)、積極推廣自家指令集給其他潛在競爭對手,而是完全不管其他人死活。想研發x86 兼容處理器的有志之士,假若沒有跟英特爾簽訂互相授權協議,只有兩條路可選:乖乖用電子顯微鏡默默研究英特爾處理器的晶粒,嘗試逆向工程,要不然就干脆不支持不顧兼容性,碰到就視為非法指令,剩下的爛攤子就丟給操作系統廠商傷透腦筋了。
像Cyrix 在被National Semiconductor 購并前,壓根沒有英特爾技術授權,只能悶著頭逆向工程慢慢搞,自然也無法100% 兼容,讓號稱「第六世代」的6×86,連CPUID 和RDTSC都殘缺不全,指令集兼容水準只有80486 等級,甚至還得逼迫軟件廠商撰寫修正程序。同時期的AMD 則是不計代價拼死拼活,都要藉由逆向工程擠出100% 兼容性,下場就是產品上市延誤,錯失商機,還虧當初Compaq 傻傻不肯推出Pentium 個人電腦,寧愿癡癡等待AMD K5,更慘的是,撐到最后還是等不到。
英特爾競爭者也都不是省油的燈,不遑多讓搶著跳出來扮演「麻煩制造者」,自行定義「兄弟獨有之創見」的自家指令,不僅企圖爭奪x86 指令集的主導權,并強化產品效能及營銷籌碼,像AMD K6 的3DNow!、AMD K8 的x86-64,Cyrix 6x86MX 的EMMI 與CyrixIII 的MMX-FP,Centaur 一度想不開的57 個SIMD 浮點指令和22 個自定義浮點寄存器,都是斑斑可考的歷史陳跡。 AMD 還一度想不開,搶先注冊「SSE5」,擺明跟英特爾AVX 打對臺,還好在2009 年5 月6 日緊急采煞車,宣布「皈依」AVX,但還是忍不住撈過界「補完」被英特爾廢除的四運算元指令格式(xmm1=xmm2×xmm3+m32)。AMD 要開始支持亂成一團的AVX-512并完全兼容,大概也是很久以后的未來了。
? 回顧這些年來的x86 指令集擴充戰爭,唯一從英特爾手上搶下先機的,也只有AMD x86-64 那次,還是微軟私下威脅「不打算支持兩種不同的64 位元x86」(英特爾本來有自己的Yamhill,但為了保護IA-64 遲遲不肯拿出來)強迫英特爾接受的結果。 最初英特爾多心不甘情不愿、打死都不承認 64 位元 x86 存在的「IA-32e」和 AMD x86-64 也并非一模一樣,英特爾獨占 CMPXCHG16B(Pentium 那個 CMPXCHG8B 的進階版)和 SSE3,AMD 多出分頁表 NX(No Execute)保護位元和 3DNow!。談到 x86 處理器廠商要彼此 100% 水乳交融,說有多麻煩就有多麻煩,說微軟有多火大就有多火大。
不過亂象還是持續延燒,還燒到虛擬化領域,近十多年來虛擬化應用快速普及,然后 2005 年英特爾 VT-x(Vanderpool)和 2006 年 AMD AMD-V(Pacifica),雙方根本就是各搞各的,老死不相往來,讓 VMware vMotion 此類不停機的虛擬機動態遷移技術,遲遲跨越不了不同 x86處理器廠商的邊界,無形中也侷限了 x86 處理器「向上發展」的潛力,目睹此景,IBM 應該會繼續開心下去。
重塑x86 處理器世界觀的歷史認知
行文至此,想必各位看官臉上已掛著顫抖的嘴角與充滿劫后馀生的表情,或多或少逐步解構并重組過往對個人電腦市場與 x86 處理器演進史的認知,有可能瞬間茅塞頓開,也有可能繼續滿頭問號。 本文并非教科書,而是經由複習坊間甚少重視的歷史背景與不容易注意到的細節,體認到平日陪伺在旁、習以為常的 x86 處理器,能走到今天是多麼不容易的一件事。羅馬不是一天造成,英特爾的霸權也不是平白從天上掉下來,這些年來我們一同擠過這麼多條牙膏,更不是毫無苦衷。 身為英特爾 1990 年代「Landmark」芯片與無數潛藏已久歷史暗流的縮影,Pentium 帶來 x86 世界太多「第一次」,承先啟后,奠定 25 年技術演進與市場發展的基礎邏輯。畢竟電腦是人類創造的東西,背后的人性和思維遠遠超越技術。
英特爾可靠開創新局的 Pentium 與繼往開來的 Pentium Pro,在眾多敵人環伺下殺出一條通往全新市場血路過程中「產生的價值」,如「技術領先無法保證商業勝利」和「成功的產品往往是折衷妥協后的產物」,統統很有意思,更值得各位細細品味。 關于Pentium,似乎筆者不小心遺漏了什麼,聽說跟浮點除法(FDIV)有關?算了,就當作提醒世人吧。
編輯:黃飛
?
評論