Mac OS X 背後的故事

發表於2013-01-23

來源: 《程式設計師》雜誌

作者王越,美國賓夕法尼亞大學計算機系研究生,中國著名 TeX 開發者,非著名 OpenFOAM 開發者。

Mac OS X 背後的故事(一)力挽狂瀾的 Ellen Hancock

故事還得從 20 世紀 90 年代說起。Ellen Hancock 是本文的主人公,也是一位女英雄。她因在 IBM 的經歷而被人們所熟悉。1966-1995 年間,Ellen Hancock 在 IBM 共工作了 29 年。1985 年,她成為 IBM 的副主席。在 1986-1988 年間,Ellen Hancock 擔任過 IBM 通訊產品的主席,並在 1992 年被選為資深副總裁。1995 年 9 月,她被時任美國國家半導體(National Semiconductor)CEO的 Gil Amelio 忽悠,跳槽來到這個企業,做執行副總裁。她在這裡帶領團隊完成了 CompactRISC 架構,這個架構事後成為 ARM7 系列的前身。很多人早已經把她忘了,也很少有人能夠在回憶時將她和 Mac OS X 聯絡起來。但事實上,她是讓蘋果放棄 Copland 轉而購買 NeXT 的關鍵人物。

Mac OS X 背後的故事

Ellen Hancock曾任蘋果公司技術總監

早在 1994 年,Gil Amelio 就找好了下家 Apple,成為 Apple 董事會的成員。1997 年 2 月,Gil Amelio 從 National Semiconductor 辭職,併成為 Apple 的 CEO。為了緊跟老闆的召喚,Ellen Hancock 再次被忽悠,來到了當時危機四伏的 Apple。這時是 1996 年 5 月,為什麼是危機四伏呢?還得從早先的事情說起。

20 世紀 80 年代,賣可樂的 John Sculley 成為 Apple 的 CEO,隨之 Steve Jobs 被轟出Apple。畢竟可樂和計算機不是一回事,因此不管是硬體還是 Mac OS,整個公司的開發專案越來越受阻。而且由於先天的不足,Mac OS 從誕生之初就不具有一個現代作業系統所應有的特性。所以,在 1987 年,開發下一代作業系統的計劃呼之欲出。具體的規劃是,把新的系統所需要的功能,寫在一堆卡片上。短期可實現的目標,比如增加顏色支援(當時計算機仍是黑白的),寫在藍色的卡片上;長期的目標,比如多工功能,寫在粉色的卡片上;而在可預見的未來都無法實現的長期的目標,比如加一個純物件導向的檔案系統,就寫在紅色的卡片上。在這樣的思路下,Mac OS 的開發團隊馬上就被分成兩個組,一個叫藍組,目標是在 1991 年,釋出一個關於 Mac OS 的更新版本;另一個叫粉組,和藍組同時工作,計劃在 1993 年,釋出一個全新的作業系統。

1991 年 5 月 13 日,藍組順利按時完成開發任務,釋出了 Mac OS 7(一般被稱為 System 7),而粉組卻沒做出什麼有實際用途的東西來,因此接連跳票。而且,由於 Mac OS 7 的釋出缺乏人手,為了保持正常釋出,常常需要從粉組抽調人員參加藍組的開發,再加上 Apple 當時把重心放在了和 IBM 等公司的合作上(Taligent 專案)而不是在粉組上,最終導致了粉組專案夭折。而本來 Apple 指望和 IBM 合作的Taligent 專案能開發出一個可用的新系統,但後來 IBM 不跟 Apple 繼續玩了,因而 Taligent 的果子又吃不到,Apple 相當鬱悶。這時由於 Mac OS 有先天不足(單任務,沒有記憶體保護),再加上 Apple 以及第三方軟體的無限量增加(在這段時期,單 Apple 自己就已經加入了 QuickDraw、PowerTalk、QuickTime 等軟體和技術,每一個都比 Mac OS 本身來得大),Mac OS 的問題終於大爆發。上個世紀 90 年代,Mac OS 給人的印象就是很不穩定、經常崩潰,同 Windows 95 留給 PC 使用者的印象差不多,甚至更甚。

Taligent 專案掛掉後,Apple 自己嘗試過十多個不同的內部專案,但大多沒做多久就夭折了。而這時正是 Windows NT 走向成熟的關鍵時期。眼看著日子逐漸變得不好過了,Apple 開始重新開始考慮建立下一代作業系統的事情。1994年,Mac OS 7.5(Mozart)釋出後,Apple 推出新規劃,建立一個全新的作業系統,以 Copland 命名(紀念 Aaron Copland,Mac OS 的釋出以音樂家名字命名,和 Mac OS X 後使用貓科動物名字很不一樣),這個專案將有一個全新的核心,具有類似 Windows NT 核心的所有高階特性,而老的軟體都當作獨立的程式模擬執行。這個專案時間緊、任務重,1995 年 3 月公佈計劃,預期 1996 年釋出。而 Copland 後的版本 Gershwin(紀念 George Gershwin),預計 1997 年釋出,將重寫 Mac 的所有系統主要部件,以適合新核心的各種特性。

Copland 將使用微核心技術,只做任務和記憶體分配。除此之外的所有功能,比如檔案系統、硬體驅動等作為微核心上的服務執行。而 Mac OS 的所有使用者介面功能將成為一個獨立的框架,稱為藍盒(Blue Box,今後介紹 Mac OS X 時,我們還會遇到這個詞)。所有的任務相互獨立,佔用獨立記憶體,也可以用 IPC 相互交流。學過作業系統的人都知道,微核心是當時的一個熱詞,一個系統只有被稱為微核心才可被看作是先進的,當時還有針對 Linux 系統的著名的 Tanenbaum-Torvalds 筆戰。但事實證明,所有本來想做成微核心系統的成功專案都放棄了原先的設計(包括 NeXTSTEP、Windows NT),因為這種類似 Mach 微核心的系統往往難產,GNU/Mach + Hurd 之類的專案做到現在經過了20年,仍未成事,一年內搞一個微核心系統談何容易。

微核心還沒搞成,Apple 幾乎所有開發組的成員都來添亂。大家都說自己做的東西很重要,一定要加入 Copland 開發組,所以 QuickDraw GX、OpenDoc 之類的開發組產品成為新系統的核心元件,甚至類似使用者介面皮膚之類的開發組都來湊熱鬧,馬上就使 Copland 成為一個無法維護的專案。開出的計劃越來越長,專案越來越多,但相關進展越來越少,完成速度越來越慢。即便做出了產品,連測試人手都不夠。1995 年就有工程師指出,在 1996 年釋出 Copland 純粹是幻想,能 1997 年釋出就不錯了。

1996年,Gil Amelio 已經掌權。在蘋果電腦全球研發者大會上他開心地宣佈,傳說中的 Copland,也就是 System 8 的開發版會在當年夏天釋出,而正式版在秋天就可以送到每位使用者手上。時任 TidBITs 編輯的 Matt Neuburg 有幸見到了這個傳說中的系統。令他大吃一驚的是,這個系統在當時只能開啟或關閉檔案,而無法對文字檔案進行編輯,甚至所有使用者介面的文字框都不能輸字。哪怕什麼都沒做,整個系統也會隨機崩潰,而崩潰甚至會造成檔案系統損壞。參加演示的蘋果員工,則需要不斷守在旁邊,他們的工作是不斷地格式化已崩潰的計算機磁碟,然後重灌系統。那年夏天,第零個測試版送到一小簇不明真相的開發者手中,把那些脆弱的沒見過世面的人嚇得半死。就連 Apple 內部都開玩笑說 Copland 的正式釋出日期可能得推遲到 2030 年。

Gil Amelio 心急如焚,希望 Copland 快點走到正道上來。作為 Gil Amelio 永遠的好朋友,Ellen Hancock 就在這個亂糟糟的時候來到了 Apple。她的職務,正是擔任這個亂糟糟專案的負責人。她親自下訪各小組體察民情,瞭解情況。畢竟在 IBM 幹了近三十年,她依靠自己過人的判斷力在 2~3 個月內便得出結論,Copland 這個專案是沒有指望的,就按目前 Apple 這樣的狀態,Copland 永遠都不可能釋出,還不如早點取消了好。在短期內,先把 Copland 中的一些有用的成果一點點合併到老的 Mac OS 中,並且抓緊從外部購買一個全新系統來滿足 Apple 的需要。正是她的這個結論,結束了 Apple 長達五年的糾結,使公司重新走向正軌。整個 PC 的黃金時代已經過去,Apple 想要翻身,還有很長一段路要走。Gil Amelio 支援了 Ellen Hancock 的計劃。1996 年 8 月,Apple 取消 Copland 專案。開發預覽版的 CD 封套都已制完,每個郵包上的地址都已列印就續,而 CD 卻從未曾製出。

1996-1998 年是 Apple 最混亂的幾年。在商業上,有一陣曾傳出 Apple 要被 Sun 收購的訊息。更有意思的是,《連線》雜誌在 1997 年的六月還發表了一篇文章,名為《101 種拯救 Apple 的方法》,其中一條說最好的方式是 Apple 讓自己被 Motorola 買下,成為 Motorola 的一個部門,做 PowerPC 系列產品。以當時的眼光來看這些建議非常諷刺好笑,以今天的眼光看更為好笑。而 Ellen Hancock 在這段時間內的出色工作,成功地挽救了 Apple。

首先,Ellen Hancock 的對內政策是繼續 Mac OS 7.5 的開發工作,一步步把 Copland 中的技術併到 7.5 中。同時,也大量購買第三方的系統增強包,包括外掛管理工具、層次化選單等技術。Apple 把它們買過來,整合到現有的系統中。整個老系統在新系統尚未完成的時候不斷更新,至 2000 年已出到 9.0 版,儘可能地留住了老使用者。並且,前面提到的藍盒(Blue Box)也作為後來新 Mac OS X 系統的一部分,支援使用者執行經典 Mac OS 的程式。

而對外政策更是一個大手筆。Ellen Hancock 協助 Gil Amelio 在 Apple 之外找尋作業系統技術。在 IBM 和 Microsoft 合作 Big Blue 的經驗告訴她,購買一個作業系統的使用權問題多多,最好的計劃是整個一併買下來。因此,Gil Amelio 開始和當時看好的 Be 談,卻因價格問題沒有成功,最終轉而收購了 NeXT。而 Apple 合併 NeXT 後,NeXTSTEP 就演化為 Rhapsody,並最終成為 Mac OS X。這些事情我們今後會詳細再談。

買完 NeXT 後,Steve Jobs 執政,Gil Amelio 因任 CEO 期間 Apple 虧損嚴重而被炒。Steve Jobs 把信得過的人(很多是前 NeXT 員工)拉攏到周圍,開始新政,而同 Gil Amelio 有關的 Ellen Hancock 則在人事變動中被疏遠。Steve Jobs 甚至在很多場合稱她為“笨蛋”。Ellen Hancock 最終於 1998 年主動辭職。事後同 Gil Amelio 以及 Apple 的創始人之一 Steve Wozniak 一同創業,但始終不景氣,她的輝煌時代已經過去。

Gil Amelio 總結他在 Apple 時期的工作時說:“Apple 是一艘底部有洞漏水的船,而我的工作是把這船引向正道。”(Apple is like a ship with a hole in a bottom, leaking water, and my job is to get this ship pointed in the right direction. )Ellen Hancock 雖然同 Gil Amelio 一樣,不知如何去堵這個漏水的洞,但正是由於她在 Apple 的出色表現,不但把船引到了正道上,還找來了有能力堵這個洞的人。

Mac OS X 背後的故事(二)——Linus Torvalds的短視

本文主要的故事來源是 Linus Torvalds 的自傳《Just for Fun: The Story of an Accidental Revolutionary》。

Mac OS X 背後的故事

Steve Jobs 於 1997 年迴歸 Apple

Steve Jobs對Mac OS X的考慮

1997 年,Steve Jobs 迴歸,開發下一代作業系統的工作被提上日程。此刻的時代背景是像 Linux 這樣的開源軟體大行其道。隨著網路的發展,使得像 Red Hat、VA Linux 之類的企業成為爆發戶,把泡沫越吹越大。Steve Jobs 承認 Linux 的好處,甚至在若干年後介紹 Mac OS X 底層的 Darwin 時還不忘在幻燈片上寫道:Darwin 是類似 Linux 的系統。而當時精明的 Steve Jobs 在考慮下面幾個問題。

第一,NeXTSTEP 的核心和外圍工具中,BSD 程式碼維護起來需要大量人力,而且各分支的 BSD 發展顯然不如 Linux 快。很多功能都沒有,需要 Apple 自己做。

第二,像 Apple 這樣的小公司,需要借力打力。Apple 的主要競爭對手是 Microsoft,而開源軟體的矛頭也是 Microsoft,如果聯合起來幹革命,不但能讓自己得到一個好名聲(Apple 事後一直自稱是最大的開源軟體公司),也可以獲得可觀利益,從而對 Microsoft 造成壓力。

第三,也是最重要的,聯合各開源組織能夠推動 Mac OS 的發展。畢竟開源軟體中像 GCC 之類都是很成熟的專案,Apple 用起來省時省力,投點錢就有大效益,多好。

所以,把 Linux 核心作為 Mac OS X 的重要組成部分的想法被這位偉大的智者想了出來。Apple 之前也有開發 Linux 的經驗,比如在 Steve Jobs 迴歸之前,Apple 就和 OSF 合作開始把 Mach 核心移植到 PowerPC 上(Apple 是最大的 PowerPC 玩家,而 OSF 是最大的 Mach 玩家),並把 Linux 作為服務跑在 Mach 上。這個系統就是 MkLinux,我們在後續的連載中還會提到這個系統,因為它不但對 Linux 的移植性作出了重要的貢獻,也對後來的 Mac OS X 的 XNU 核心技術起到了相當重要的作用。

如果可以採用 Linux 作為系統重要組成部分,並且這個構想能夠取得在開源軟體界呼風喚雨的 Linus Torvalds 的認同,就能靠他在社群鼓動一大群開發者皈依 Apple 麾下,這是 Apple 很想看到的給力結局。有了這個指導思想,他便讓祕書給 Linux 的開發者 Linus Torvalds 發了一個郵件,問他是不是有一到兩小時的時間和 Steve Jobs 會面。不明真相的 Linus Torvalds 收到郵件後相當高興,因為這是他第一次有機會去矽谷觀摩。

無果而終的會面

Apple 總部 Infinity Loop 終於迎來了這位稀客,Steve Jobs 親自接見,而先前任 NeXT 技術總監的 Avie Tevanian(這人的故事我們今後會提到)也參加了這次會談。不用多說,這次討論的內容自然是還處於未知狀態的 Mac OS X。討論算不上正式,但 Linus Torvalds 的憤青個性,卻讓談判陷入僵局。

Steve Jobs 自然搬出他 1997 年迴歸之際在 MacWorld 講話時的那套理論,Apple 雖然很頹,但骨子裡是個牛逼的公司。全世界桌面領域的真正玩家就兩個,一個是 Apple,另一個是 Microsoft,兩者加起來,構成百分之百的桌面使用者群。所以,Linus 同學,你就從了我們吧,如果你從了我們,讓我們把 Mac 架在 Linux 上,一大批桌面使用者就是 Linux 使用者啦,前景可是一片大好!

而 Linus Torvalds 那時候牛啊,諸多大公司如 IBM、Red Hat 都圍著他轉。他可是企業家中的大紅人,像 Apple 這樣的企業根本就不在他眼裡。作為一個開源軟體的革命家,在他的想象中 Linux 的潛在使用者應該比 Apple 還多。他始終相信,按照目前開源軟體的發展態勢,自己很快就能在桌面領域分到一杯羹。而且這個命題在他這種古怪性格下的直接推論是,即使我能佔領桌面領域,我也要擺出一副不在乎這個領域的態度來。所以實際上 Steve Jobs 的開場白一開始就失敗了。

接著,Avie Tevanian 向 Linus Torvalds 介紹了整個計劃。他們想把 Mach 和 Linux 核心合併起來作為 Mac OS X 的基礎,我估計 Linus Torvalds 是聽錯了(因為 Avie Tevanian 很早就意識到相比於微核心,混合核心有明顯優勢),他以為 Apple 想把 Linux 作為 Mach 的一個服務來跑(當然我個人認為,即使是合併 Mach 和 Linux 成為混合核心,依 Linus Torvalds 的憤青性格,依然是不可能接受的),這正讓他回想到先前和 Tanenbaum 教授的筆戰。並且,他也知道 Apple 和 IBM 合搞的失敗專案 Taligent 正是用 Mach 的。

Linus Torvalds 對於微核心有他自己的看法,之前也曾在不同的地方表述過。若把關於微核心的筆戰去掉限制級敏感詞的話可概括成兩方面。一方面,設計一個微核心和相關的服務,可能造成各種設計上的災難。GNU/Hurd 早在八十年代末就考慮嘗試在 Mach 上寫一系列 Unix 的服務層,結果他們始終無法搞明白到底是讓這些服務先發訊息到另幾個服務呢,還是考慮其他方案。所以直到 2011 年我寫這篇文章時,Hurd 專案依然處於半死不活的狀態。而另一方面,微核心的效率無法和傳統核心相比,最簡單的系統呼叫會涉及一系列底層服務的互相通訊。所以很多研究者著手研究如何把微核心的效率提上去,結果就導致微核心變得更加複雜。能提高微核心效率的很多研究成果都已在 Mach 專案中實現了。而在 Linus Torvalds 看來這恰使 Mach 成為了一個非常複雜的專案,並且效率也不怎麼高。

會談時坐一旁的 Avie Tevanian 事實上是 Mach 最早的開發者之一,他熱情地給 Linus 講述 Mac OS X 系統藍圖。而 Linus 實際上早就不耐煩了。比如,Mac OS X 中,有一個模擬層,可讓使用者使用經典的 Mac OS 程式。這個技術極類似於現在跑在 Unix 系統上執行 Windows 程式的 Wine 。Apple 當時的考慮是這樣,因為老的 Mac OS 在設計 API 時,就沒有考慮到類似記憶體保護之類的問題,所以這層 API 必須廢掉,Mac OS X 中所有的新程式必須採用 NeXT 的那套更先進的 API(根據我的考證,當時還沒有 Carbon 這樣的想法,而且事實上 Carbon 不管在 API 還是 ABI 上都和經典 Mac OS 不相容)。而短期內已有的軟體又不可能快速重寫遷移至 Mac OS X。所以,如果使用者需要使用老版 Mac OS 的第三方應用程式,就可以使用 Apple 提供的這個相容層。但是由於剛才提到的原因,老版程式並不享受新版程式的待遇,因為模擬器本身執行多個老 Mac OS 任務時,和原先老版 Mac OS 一樣,實際上只有一個程式,沒有記憶體保護。這樣做的好處是明顯的,因為一方面老的程式在 Mac OS X 釋出之初還能用,另一方面 Apple 又和老技術劃清了界限,逼著開發者使用新技術,技術方面的原因是最重要的。但這個看似很正確的技術在 Linus Torvalds 看來是古怪的,他想當然地認為,完全可以執行多個不同的模擬器程式,來執行不同的任務,使得每個任務都可以享受記憶體保護。這種浪漫主義情調讓他無比鄙視 Apple 員工的智商。而事後當筆者使用早期版本的 Mac OS X 時,發現 Linus Torvalds 的想法完全是不切實際的。因為這個模擬層本來就要佔用不少的記憶體和 CPU,在處理器速度不及今日手機、記憶體無比精貴的 90 年代末,跑一堆模擬器程式無異於是和自己過不去。

Steve Jobs 考慮到 Linus Torvalds 是開源軟體的領軍人物,便繼續以開源為話題,動之以情,曉之以理。他告訴 Linus Torvalds,我們這個系統做出來後呢,所有的 Unix 層(非圖形介面層),都會開源,所以事實上你加入我們,也是在給開源做貢獻啊!而由於在開源圈子混久了,Linus Torvalds 對此絲亳不領情,他認為,有誰會想用一個底層是開源而圖形介面是不開源的系統呢?所以,像筆者這樣的使用者被“代表”了。

Mac OS X 與 Linux 分道揚鑣

總之,這次會面完全談崩,兩人站在不同的角度去看問題,加上 Steve Jobs 和 Linus Torvalds 都是個性鮮明、唯我獨尊的人,技術和商業上的考慮都不同,所以會談中雙方簡直就是雞同鴨講。這次討論也使得 Apple 放棄 Linux,轉而採用 FreeBSD 技術,並在 2001 年任命 FreeBSD 的發起者、領軍人物 Jordan Hubbard 為 BSD 技術小組的經理,並在後來升為 Unix 技術總監。至於 Apple 的核心技術後來走向何方,我們下期再講。

筆者認為,Apple 和 Linus Torvarlds 的商談破裂,以今天的眼光來看,是因 Linus Torvarlds 的自命清高和短視造成的。他不懂得尊重其他開發者的意見,並且不斷抬扛。包括後來關於 C++ 的論戰。Mac OS X 釋出後,Linus Torvalds 又數次嘲笑 Mac 的技術落後,並說這些他在當年和 Steve Jobs 開會時就預料到了。直到最近,他終於有些成熟,對 Mac OS X 的觀點開始緩合,但還是不忘批評 Mac 的檔案系統就是垃圾(事實上,Linux 的也沒好到哪去,至少 Apple 還搞過一陣 ZFS)。這種性格最終導致在 Mac OS X 和 iOS 大行其道的時候,Linus Torvalds 連兔子湯都不曾分到。

而事實上這對 Apple 也是件好事。Apple 重要的是利益而不是折騰,即使是開源也是利益驅動。像類似 Linux 開發組那樣自以為是但程式碼又寫得差的開源專案,Apple 事後也遇到不少,比如 GCC 編譯器專案組。雖然大把鈔票扔進去,在先期能夠解決一些問題,但時間長了這群人總和 Apple 過不去,並以自己在開源世界的地位恫嚇之,最終 Apple 由於受不了這些專案組人員的態度、協議、程式碼質量,覺得還不如自己造輪子來得方便,因此 Apple 推動了類似 LLVM 這樣巨集偉的專案,並且在短短几年內,使其成為最領先的開源軟體技術。這無異於扇了 Linux 小組、GCC 小組一記響亮的耳光。

Mac OS X 背後的故事(三)Mach 之父 Avie Tevanian

1975 年,美國羅徹斯特大學紐約分校,一組研究員正在做一個名為 RIG(Rochester’s Intelligent Gateway)的專案,它由 Jerry Feldman 主持設計。RIG 的目標是給所有本地以及遠端的計算裝置(比如磁碟、列印機、磁帶、繪圖機等)提供一組統一的訪問方式,其作業系統稱為 Aleph。為了實現所需要的功能,Aleph 的核心主要構建了一個程式互動(Interprocess Communication,IPC)的機制。RIG 的各程式,只要設定了目標埠,就可以彼此間傳送資訊。RIG 專案沒過幾年就被判了死刑,主要是缺少很多有用的功能,比如埠沒有保護機制,一次最多隻能傳送 2KB 大小的資訊(受硬體限制),也沒有很好的網路支援等。不過在 20 世紀 70 年代,這個系統依然代表著當時作業系統設計的先進水平,比如除了程式互動外,每個程式還有記憶體保護的功能,這足以讓 20 世紀 90 年代末都沒有做出記憶體保護技術的 Apple 公司汗顏。

Mac OS X 背後的故事

該專案後來失敗了,隨後在 1979 年,RIG 的 Richard Rashid 博士畢業到卡內基-梅隆大學當教授,開始做 Accent 專案。它是一個網路作業系統,於 1981 年 4 月開始活躍開發。受 RIG 的影響,Accent 系統的亮點也在於可以使用 IPC,而且解決了很多 RIG 的不足。比如每個程式有 4GB 的虛擬記憶體空間,而且甚至連核心自已都可以被存入快取頁面,記憶體有先進的更新前拷貝(Copy-on-Write)功能,可以實現程式間大資訊的傳送等。讀者可以把 Accent 理解為支援虛擬記憶體技術,並且具有網路透明 IPC 功能的 RIG 核心。

但過了幾年,開發者們越來越對 Accent 失去興趣。在 1980 年初,很多人覺得多核計算是計算機未來發展的潮流,但 Accent 核心在設計時並沒有考慮到這些問題。而且,隨著許多實驗室紛紛購置效能更強勁的計算機,這就意味著 Accent 需要移植到新的目標架構上。此外,Unix 正大行其道,不管是在作業系統理論上還是在使用者程式上,都成為最為流行的作業系統模式,而 Accent 並不是一個 Unix 系統,所以無法享受 Unix 世界的諸多美好。為了解決這個問題,研究人員決定把所有設計推翻重來,於是就有了一個全新的系統。

在匹茲堡的一個雨天,卡內基-梅隆大學的 Avie Tevanian,此係統的最主要開發者,正打著傘和同學們在去吃午飯的路上。他們一邊繞著無數的泥塘,一邊構思給這個新系統取什麼名字好。靈感突來, Avadis Tevanian 建議把這個系統叫作 Muck,引得同學們哈哈大笑。後來,Richard Rashid 和一位義大利同事 Dario Giuse 說起這玩笑,結果這位同事不經意地把 Muck 發為 Mach,遂把 Richard Rashid 笑翻,偉大的 Mach 系統因此得名。

Mach 是一個受 Accent 啟發而搞出的Unix相容系統。那年,Unix 已經十六歲,而且依然是作業系統理論與實踐開發的主要陣地。Unix 核心由於新加入的功能越來越多,變得越來越複雜。而 Mach 的一個主要目標就是儘量縮減 Unix 的各項服務,以使核心變得簡單可維護。此專案從 1984 年開始,目標主要是包含完整的多工支援、良好的硬體移植性,並要把大量服務移出核心作為跑在核心上的服務,以及提供與 Unix 的相容性。

Mach 使用純 C 編寫,所以在一定程度上保證了可移植性,這事實上為後面的 NeXT 向 PowerPC 移植以及 2005 年的向 Intel 移植提供了很重要的前提。而為了縮減核心該管的任務,Mach 做得很絕,只提供記憶體和處理器管理。類似於檔案系統、網路、輸入輸出等功能都作為單個的系統程式,獨立執行於核心之上。Mach 的開發過程以 4.3 BSD 作為起點,以 RIG 的 Accent 作為參考,採納 DEC 的虛擬記憶體設計思路,逐步開發,以新寫的程式碼代替 BSD 的程式碼。兩年後的 1986 年,雖然沒能把系統服務完全分離於核心之外,但已頗見成效。Mach 第一版大功告成,組員發表會議論文,成為作業系統史上里程碑式的經典,引發作業系統業界的“微核心”學潮,如今學習作業系統設計的皆需學習此文,二十五年來被引用一千二百餘次。

這篇文章主要講了兩方面內容:IPC 和虛擬記憶體。在 IPC 方面,Mach 把複雜的訊息傳送機制分為四個獨立的清晰概念—任務、執行緒、埠、資訊。任務是擁有一組系統資源的物件,允許執行緒在其中執行;執行緒是執行的基本單位,擁有一個任務的上下文,並且共享任務中的資源。

由於該論文的影響力,所以專案得到了 OSF(Open Software Foundation)在內的很多投資。當然了,學術和工程永遠存在差距,所以即使是最受歡迎的 Mach 2.5 其實仍然是一個包括大多數 BSD 服務層的單核心。但包括 NeXTSTEP、OSF/1 在內的很多作業系統都採用 Mach 作為其核心技術,原因是廣大研究人員依然相信微核心代表著未來。雖然 Mach 2.5 的效率比傳統的 Unix 系統稍低一些,但研究者們表示情緒淡定,因為 Mach 支援多處理器系統,可以利用多執行緒把任務處理得飛快,相比之下其他 Unix 核心並沒有多處理器的完善支援,因此 Mach 效率稍低完全可以接受。但隨著真正把 Mach 和 BSD 服務完全脫離的 Mach 3 微核心面世,研究人員們的情緒就再也淡定不起來了。因為服務和核心分離後,任務間的 IPC 數量暴漲,一個簡單的 Unix 系統呼叫要涉及到十多個開埠、設許可權、傳送、收取訊息的操作,哪怕是使用數年後的 1997 年的硬體,跑一個系統呼叫密集的程式,Mach 的效率要比一般的 Unix 系統慢 50%,而且根本沒有什麼好方法來解決這個問題。

所以 Mach 3 出來後,雖有少數微核心信徒繼續執著地改進 Mach,或者開始其他微核心比如 L4 的研究。但學術界對 Mach 的興趣大減,因而 Mach 3 也成為最後一版。專案解散後,Richard Rashid 去了微軟研究院。

再說我們的主角 Avie Tevanian,他 1987 年博士畢業去了 NeXT。這家公司剛剛由 Steve Jobs 成立兩年,這兩年 Steve Jobs 啥正經事都沒幹,只是花了十萬美元僱 Paul Rand 設計了一個公司商標。直到 Avie Tevanian 加入後,這個公司才開始幹實事。1987 年公司確認要開發一個面向研究人員使用的計算機工作站,於是軟硬體的開發工作緊鑼密鼓地展開。硬體組由領導過 Apple Lisa 的 Rich Page 原班人馬負責,而軟體則由 Avie Tevanian 負責,計劃開發一個有圖形介面的作業系統 NeXTSTEP。由於 Avie Tevanian 是 Mach 主要的開發者,自然 NeXTSTEP 就基於 Mach 了。1988 年 10 月 12 日,NeXT 釋出預覽版(0.8版),並於 1989 年 9 月 18 日釋出 1.0 版(注:http://en.wikipedia.org/wiki/NeXTSTEP)。

作為 NeXTSTEP 系統的核心,NeXT 分支的 Mach 經歷了不少變化。NeXTSTEP 0.8 主要使用 Mach 2.0 版,而稍後的 NeXTSTEP 1.0 版主要基於 Mach 2.5 版,包含一個自己定製的當時最新的 4.3 BSD 服務層。從 3.1 版開始,NeXT 分支的 Mach 還包括一個全新的裝置驅動框架, 名為 Driver Kit,僅供 x86 系列的硬體使用。和 Mach 以及 BSD 程式碼不同,Driver Kit 是使用 Objective-C 寫的。為什麼是一個物件導向的語言呢?看 NeXTSTEP 3.3 的 DriverKit 文件。讀者大概就會發現,NeXTSTEP 把所有硬體裝置理解為物件,而我們知道,物件之間有繼承關係,比如,磁碟(IODisk物件)屬於輸入輸出裝置(IODevice物件)的子物件,而磁碟(IODisk)本身又是邏輯磁碟(IOLogicalDisk)的父物件。硬體的初始化對應於每個物件的初始化(init方法),硬體又有讀、寫,所以可以用 getter/setter 的方法。因此,DriverKit 是一個非常有特色的實現。而且由於 Objective-C 的效率很高,依賴很少(Objective-C 程式可以直接被編譯器翻譯成等價的C語言程式並編譯,而 Objective-C 的執行庫 libobjc 也以高效著稱),所以也是編寫驅動的良好選擇。幾年後的 IOKit 其實就是個 DriverKit 的翻版。

這時,NeXTSTEP 作業系統大獲成功,風險投資商們紛紛購買,但硬體卻始終賣不出去(注:Aaron Hillegass《Cocoa Programming for Mac OS X》前言),所以 NeXT 砍掉了硬體部門專做軟體,更是使 NeXTSTEP 發展到了巔峰時期,同時支援 68K、x86、PA-RISC 和 SPARC 等硬體,但頗有意味的是它就是不支援 PowerPC 架構。它可以同時產生一個包含所有架構可執行碼的二進位制檔案,來使開發的程式在所有平臺上執行。這個功能也影響了後來 Mac OS X 的技術。Mac OS X 10.4 時代有兩件跨時代意義的事情,一件是 Apple 搞出了 64 位的 Power Mac,開發者可以釋出一個包含64位和32位程式的單一可執行檔案,而無需讓使用者去區分;另一件是和 Intel 合作。Apple 正式發表了 Universal Binary 技術,可以一個 Mach-O 檔案同時包含 Intel 和 PowerPC 的指令。這非常貼心的設計(要知道,大多數電腦使用者根本不知道 Intel、PowerPC、64位、32位等技術)就是來自於 Mach 的技術。

NeXTSTEP 3.3 後,NeXTSTEP 因為 NeXT 和 Sun 的合作改名為 OPENSTEP,1996 年釋出 4.0 版,到 1997 年 2 月 4 日,NeXT 被 Apple 收購之前,期間核心改進除原始碼同步到 Mach 3.0 版外不明,而且出於不知道的原因,我手頭的 OPENSTEP 正式版光碟中,居然找不到 DriverKit 的釋出說明和程式設計文件,故不作詳述。不過這段時間,Apple 的活動值得好好一說。之前在《Linus Torvalds的短視》中,我們曾提到,1996 年,Apple 和 OSF 曾經合作,把 Mach 移到 PowerPC Mac 上,再把 Linux 作為單一的服務跑在 Mach 上,這個專案叫做 MkLinux。在 1996 年釋出基於 Mach 3.0 和 Linux 1.3 的預覽版,並更新到 2002 年結束其歷史使命,對 Mach 在 PowerPC 的移植性上做出了重要貢獻。這個 PowerPC 版的 Mach 被叫作 osfmk 分支,也正是現在 Mac OS X 中用的分支。當然了,NeXT 被合併後做了大量修改。

Apple 收購 NeXT 後,Mach 被確定作為未來的作業系統核心。Avie Tevanian 被選為軟體開發部的總裁。合併所有專案的號角吹響後,上層的 OpenStep API 和老版 Mac OS 的部件開始合併,而 Mach 也經歷重大變化。主要是一方面,Mach 使用了 osfmk 分支,但依然包含 4.3 BSD 服務;另一方面,DriverKit 被 IOKit 取代。這是 Apple 走得很被動的一步。因為當時外界普遍對 Objective-C 不看好,逼著 Apple 走老版 Mac OS  API 的老路。而 Apple 自己對 Objective-C 也很不自信,甚至想索性換用 Java 了事(我們以後會談及這段不自信的歷史)。所以 IOKit 是一個 C++ 的驅動架構,來符合大眾口味。這些改變最早在 Rhapsody 中出現(我們以後也會有一期 Rhapsody 的專題)。但由於 C++ 是門很恐怖的語言,所以 Apple 又把 C++ 給閹割了,去掉了多重繼承、模板、執行時動態以及異常,讓開發者使用這種對於 Objective-C 來說換湯不換藥的 Clean C++ 來做驅動。但公正地說,IOKit 對於 Driver Kit 是有不少改進的,比如 IOKit 可以寫在使用者空間跑的驅動(雖然大多仍是跑在核心空間上的),因而驅動掛了而系統不會掛。另外 IOKit 考慮到了計算機發展的趨勢,所以在電源管理、即插即用、動態載入上做得更好。

但各位也知道,C++ 程式得用專門的執行庫才能跑,所以 Mach 中又加入了一個叫作 libkern 的庫負責 C++ 相關的功能,同時,還有一個 libsa 的庫提供一些類似二分查詢、排序等基本演算法之類的功能。最後和硬體相關的還有一個叫作 pexpert(Platform Expert)的庫,負責收集硬體裝置列表、檢測機器種類(比如處理器速度等)、解析啟動引數等雜活。

至此,Mac OS X 的核心完全形成,形成 BSD、IOKit、Mach osfmk 三足鼎立的態勢,並有 pexpert、libkern、libsa 作為基礎。Apple 稱它的核心傑作為 XNU。其程式碼開源,請讀者移步http://www.opensource.apple.com/source/xnu/xnu-123.5/,每個部分的程式碼都獨立存放在一個資料夾中,條理清晰,不妨一讀。

由於 4.3 BSD 已是過眼煙雲,Apple 後來投入大量資源扶持 FreeBSD 開發。2001 年,Apple 將 FreeBSD 的發起者、領軍人物 Jordan Hubbard 收入麾下,並在 Mac OS X 10.3 時基本同步到 FreeBSD 5 的程式碼(注:http://osxbook.com/book/bonus/ancient/whatismacosx/arch_xnu.html)。

另外,Apple 的開發也同時反饋到 FreeBSD 小組,包括 FreeBSD 6.2 核心引入的 AUDIT (man audit 或參見http://manpages.unixforum.co.uk/man-pages/unix/freebsd-6.2/4/audit-man-page.html),後來 FreeBSD 8引入的 libdispatch (http://wiki.freebsd.org/GCD, 在 Apple 這項技術叫 Grand Central Dispatch,是 Mac OS X 10.6 主推的新功能,FreeBSD 基本在 Mac OS X 10.6 上市的同時就擁有這項最新技術),以及 FreeBSD-CURRENT 中的 LLVM-Clang,全是 Apple 的手筆。從 1999 年開始,FreeBSD 原始碼倉庫可以搜尋到 Apple 提供的大量的補丁以及新功能。

Mac OS X 早期版本不太穩定,所以會核心崩潰。10.0 版本會直接像 Linux 或者 BSD 那樣打出回溯資訊,很不美觀,所以 Apple 在 10.2 版本開始設計了一個多國語言的圖片告訴使用者你的核心崩潰了,以讓核心崩得看起來更優雅一點。由於包含四國語言,被國內使用者戲稱為“四國”(注:優雅的圖片見下圖,詳見 http://support.apple.com/kb/ht1392),這是 XNU 的 Mach osfmk 部分的功能。但從 10.3~10.4 版本開始,系統越發穩定,正常使用已很少見到核心崩潰。而且,核心提供的服務也越來越多,使得 Mac OS X 成為一個完善的系統。

Mac OS X 背後的故事

21 世紀 XNU 架構方面的最重大改動是支援了 PPC64(10.4 版本時代)、x86 架構(其實本來也一直支援的,以後講 Apple 的 Intel 遷移時詳談)、x86_64(64位支援是蘋果長年努力逐步展開的。10.4 時代 32 位核心支援載入 64 位的使用者程式,10.5 系統提供 64 位的Cocoa框架,但系統大部分程式都是 32 位的,10.6 時代核心支援以 64 位模式啟動,但在不少硬體上這是非預設的方式,但系統大量程式已被改寫並編譯為 64 位的二進位制程式,10.7 時代核心預設以 64 位模式啟動。)和 ARM 架構(iPhone 和 iPad 使用 XNU 核心)等多個新架構。

而其中 ARM 架構的支援別具意義。但 2006 年 5 月 31 日,功成名就的 Avie Tevanian 離開 Apple 另謀發展,此時,離 Apple 的 iPhone 奇蹟發生,只有不到一年時間。

Mac OS X 背後的故事(四)—— 政客的跨界

2000 年,美國總統大選,由於選票設計問題,時任美國副總統的 Al Gore 敗北。2000 年 12 月 13 日,在一番重新計票的大折騰不起作用後,曾經意氣風發的 Al Gore 拖著疲憊的身子,走上講臺,發表了認輸講話(參見 Al Gore《2000 Presidential Concession Speech》),從此退出政壇。一般國家領導人的退政生活其往往鬆愉快,出出日記,學用哲學,或者像多才多藝的李嵐清不但去各地推廣古典音樂,更是玩起了篆刻(參見《南方週末》2006 年 5 月 11 日《老常委的卸任生活》),克林頓先生都成立個基金會來幫助社會預防和治療愛滋。 Al Gore 也沒閒著,他找到了讓他感興趣的去處——Apple 總部,併成為董事之一。

Mac OS X 和 Al Gore 的雙贏

2003 年 5 月 19 日,Apple 的啟示中罕見性地登出了《前總統 Al Gore 加入 Apple 董事會》的快訊。文中提到,Al Gore 總統是一個正宗果粉,他一直用 Mac 計算機,而且還會用 Final Cut Pro 來編輯他的視訊。Al Gore 也不掩飾他對 Apple 技術的熱愛,他表示對 Mac OS X 的開發極感興趣,並且也對 Apple 在開放原始碼運動中的貢獻喜聞樂見。他虛心地說,想在這個讓 Apple 起死回生的董事會好好觀摩並學習。

Mac OS X 背後的故事

Al Gore 的加盟讓 Apple 一躍成為電子產品的代言人

蘋果公司的 CEO Steve Jobs 表示 Al Gore 曾經管理過世界最大的組織——美國政府,期間顯示出的經驗和智慧對蘋果公司是筆巨大的財富。Al Gore 將成為出色的董事會主席,蘋果將以他把蘋果公司作為職業生涯的開始為榮。

這之後,Al Gore 在 Apple 內部的決策究竟起了什麼作用,和 Mac OS X 的開發有何關聯,在正式的渠道很少有史料,但是他後來的各種公開活動,卻給 Mac OS X 的技術做足了廣告,而且很多證據表明,他正是使 Apple 從被綠色人士攻擊的眾矢之的的狀態,成為業界注重電子產品環保領頭羊的主要推手。

Al Gore 重新進入普通人的視野是在 2006 年,他推出了自己參與制作和演出的紀錄片《An Inconvenient Truth》(《難以忽視的真相》)和同名書籍。這部長達 94 分鐘的影片,在西方國家引起了廣大的迴響,以 Al Gore 的一場演講和人生的回憶作為兩條主線,詳細、科普地向民眾介紹了全球變暖問題的科學證據及美國政府掩蓋問題的真相。該片以發人深省的立意、詳盡的科學資料、平實的講演風格,加上蘋果高超的技術,而獲得了廣泛的好評並一舉獲得年度奧斯卡最佳紀錄片獎,使得這位美國前副總統搖身一變,成為好萊塢明星。

為什麼單單一場簡單的講話,就能做出一部電影,還能得到奧斯卡這樣學院藝術獎的親睞?是因為講話內容無懈可擊麼?事後有很多科學家站出來表示,雖然影片內容有積極的意義,但其實也有很多被誇大的科學資料、假設和結論。試思索,該片之所以成功,甚至成為諸多演講培訓機構的重要分析案例,除了資料、觀點、論述外,還有以下幾個原因。

首先,這場演講由蘋果主導的技術和藝術的設計。Al Gore 向來以說不清想表達的內容而著稱。他經常因為講得過於專業或者缺乏好的表述方法以致於民眾完全不懂他在講些什麼。他的早期講話用現在的眼光看就是個少將體,比如“網際網路…網…我…這個…那個…那個…怎麼說呢…我想這個…這…這…這…我啊…我啊…就是說…網際網路是我發明的!”因此作為蘋果展現公司軟實力的重要機會,蘋果非常重視這場講話,請公司的圖形設計小組帶領完成各種所需設計,蘋果甚至特地請來了專業的設計公司 Duarte 來進行講稿和講話內容的安排。因此,不管是內容安排、圖形設計還是技術支援,Al Gore 都有強有力的後盾,他們能夠幫助Al Gore 完成任何想達到的目標。不論是 FinalCut 還是 Keynote,一旦缺少任何 Al Gore 想要的功能,Apple 都可以給他開小灶實現。在片末的走馬燈字幕中,有大量 Apple 的 Keynote 組、Final Cut 組和圖形設計組的員工名字,以示鳴謝。

其次,上面這些資源的相互合作,也使得 Al Gore 的這場講話的講稿被精心製作,體現了精心設計的電子稿演講所能達到的最高成就。蘋果公司向來重視演講,也是各大企業中最會通過演講來營銷產品的公司。每年的 MacWorld 和 WWDC 的 Steve Jobs 講話都會吸引百萬人在計算機前觀看。每場講話都好戲連連,臺下的觀眾的歡呼和掌聲不亞於著名歌星的演唱會。這種風格顯然給 Al Gore 的講話風格帶來很大的影響。在影片中,觀眾看不到一個傳統的 bulletpoint(PowerPoint 使用者常愛使用的表示講話結構的方法),取而代之的是高清的照片、視訊,來展現環境的嚴峻性。觀眾不再會為枯燥無味的技術詞語而搞得昏昏欲睡,因為螢幕上的一切都是如此真實,各種科學現象由動畫效果配合,使其淺顯易懂。另外,所有的資料、圖表都精心使用軟體製作,使其一目瞭然,表現準確而美觀大方,而且 Al Gore 時而還會玩些小噱頭,比如講到現在的溫室氣體濃度是多麼高時,他甚至爬上工作人員為他準備的升降機,升到舞臺頂端,來告訴觀眾,資料已經突破圖表的頂端了。現在距筆者觀賞完這部影片,已經五年過去了,但影片中的災難場景、冰川融化的影片段落、海平面上升的計算機模擬、二氧化碳濃度的資料圖表,至今都記得一清二楚,足以見得其表現力是何等深入人心。甚至有人在調侃他在 2000 年的競選演說是怎麼回事?難道就是缺少了這些科技元素?

最後,Mac OS X 的各項技術也是這部片子的重要保證。Duarte 公司的 Ted Boda 表示(該幻燈片的設計師之一),Mac OS X 系統本身的反鋸齒功能把文字、圖片、向量圖示表現得栩栩如生,使得幻燈片充滿美感。QuickTime 技術作為 Mac OS X 的一塊重要基石,又使得 Keynote 不需任何外掛就能引入任何圖片和影像,所以類似使用 Illustrator、Photoshop、AfterEffects 等軟體做出的圖片、影像或動晝,不需要任何轉換過程就能直接拖到 Keynote 中。哪怕 1920×1080 的高清視訊,都可以輕鬆插入,流暢播放。他們組根本想象不出在 Windows上 使用 PowerPoint 會成什麼樣子。

可以說,沒有 Mac OS X,就沒有這部電影。而實際上這部電影的作用遠勝過任何一部 Apple 公司的廣告。片中 Al Gore 時時拿著 PowerBook 的筆記本,在辦公室用 Safari 查網頁,字型渲染真實而美觀,甚至在車上都不忘開啟筆記本用 Keynote 做幾張幻燈片,就更不用說電影中 Keynote 幻燈片曾經迷倒多少 Windows 使用者了。向筆者推薦這部電影的好朋友瞭解到這些全是 Apple 技術的功勞時,擁有一臺 Mac 就成為其人生夢想。

環保衛士的 Apple 之路

作為環保人士,Al Gore 對 Apple 的策略的影響也不容忽視。Apple 向來被各環保組織長期批評,即使 Apple 長年不斷地改進這方面問題,但綠色人士依然不買帳。哪怕在稍後的 2007 年,也仍有包括 GreenPeace 在內的七十多個組織聯名寫信給 Al Gore,敦促 Apple 更重視環境問題,信中指責 Apple 仍在大量使用 PVC 和 BFRs 等對環境有害的材料,也不注重對自家產品的回收。由於 Al Gore 是 Apple 董事會成員,使得這個問題受到了 Apple 的廣泛關注。Apple 在 2007 年後史無前例地邁開大步,大力推廣環保計劃(要求全世界的 IT 製造商們逐步棄用 PVC 等有毒的化學用品進行生產),讓 Apple 一躍成為注重電子產品環境保護問題的領頭羊。

從製造材料上,2007 年 8 月釋出的 iMac 成為分水嶺。這款產品的設計主要使用可完全被回收的玻璃屏和鋁外框,減小了塑料等不環保物質的使用,此後蘋果一發不可收拾,把這項革命進行到底,從手機到筆記本,都全番設計。2008 年的 MacBook Air 引出的 Unibody 技術是這場革命的代表產品,不但在外觀上還是工程上做到極致,在環保上更是讓各綠色組織無可挑剔。

在造勢上,Apple 現在每項主要產品的都有“環境”的標籤頁,從製造、運輸、耗電、回收等效能情況分產品詳細列出。Apple 甚至在包裝上都動足腦筋,儘量減少每個產品的包裝,使得同一架飛機可以運輸更多的產品,從而在運輸相同數量產品的情況下減少飛機溫室氣體的總排放量。

Mac OS X 的各項節電功能的開發更是不用說了。休眠、調整空閒時的螢幕亮度、硬碟轉速等常規功能自然越做越好。而系統的多項技術能使程式更優地分配使用中央處理器和顯示卡。甚至系統還能在使用者打字時,每兩鍵之間的空隙減少處理器的佔用從而節省擊鍵之間的功耗,這使得 Mac OS X 不但更節約能源,筆記本的電池使用時間也不斷提高。而這一切的變化,和 Al Gore 似乎都有著千絲萬縷的聯絡。

由於《An Inconvenient Truth》中的講話讓 Al Gore 的觀點深入人心,同時也對美國政府在京都議定的決策產生重大的壓力,挪威諾貝爾委員會決定把 2007 年的諾貝爾和平獎頒給了 Al Gore,以表彰其在全球環境問題方面的努力,同時蘋果的主頁上全版刊發新聞,以示祝賀。賀詞如下:

Al has put his heart and soul, and much of his life during the past several years, into alerting and educating us all on the climate crisis. We are bursting with pride for Al and this historic recognition of his global contributions. (Al Gore 在過去幾年殫心積慮,全身心地投入對公眾關於氣候危機的警示和教育中。我們為他這次所得的榮譽和他全球性貢獻的歷史性承認感到無比自豪。)

或許,由於 Al Gore 在計算機領域的一貫低調(他也是 Google 的高階顧問),他在這些企業的工作很少被報導出來,但是他在政界的跨界身份是顯而易見的。Al Gore 在他的人生道路將何去何從,我們不得而知,但是從各種媒體資訊的披露可以看出,Al Gore 對計算機事業的熱衷,對環保問題的投入,可能是美國曆任領導人中最突出的。

Mac OS X 背後的故事(五)Jean – Marie Hullot 的 Interface Builder 神話

Interface Builder,是用於蘋果公司 Mac OS X 作業系統的軟體開發程式,Xcode 套件的一部分,於 1988 年創立。它的創造者 Jean-Marie Hullot 自稱是“一個熱愛旅行、充滿激情的攝影師”,本篇分享 Hullot 熱愛技術的那一面——創造 Interface Builder 的過程。

因勢而動

1981年, Jean-Marie Hullot 拿到巴黎第十一大學的電腦科學博士資格後,開始了法國國家資訊與自動化研究所(INRIA)的研究生活。

Mac OS X 背後的故事

Jean-Marie Hullot 的名字似乎不為大眾所熟知,但他設計的 Interface Builder 卻深入人心,創造了一個個軟體神話。

20 世紀 70 年代初,正是物件導向程式設計開始走上歷史舞臺的時期。許多現代計算機技術的誕生地 Xerox PARC(施樂帕洛阿爾託研究中心)的 Alan Kay、Dan Ingalls、Ted Kaehler 、Adele Goldberg 等人,從 1969 年開始研發一款物件導向的程式語言 Smalltalk,並於 1980 年正式公佈。這是一個完整地實現物件導向範型的程式設計套件,包含了一種物件導向的程式設計語言、一種程式設計庫和一個應用開發環境(ADE)。

雖然當時的機器跑得巨慢無比,但 Smalltalk 先進的思想對其他眾多的程式設計語言(Objective-C、Actor、Java 和 Ruby)的產生起到了極大的推動作用,對計算機工業界的發展產生了非常深遠的影響。我們將會在今後介紹 Objective-C 時,詳細介紹 Smalltalk 及其對 Objective-C 的影響,這裡先一筆帶過。

Smalltalk 的釋出在業界一石激起千層浪,也給 Jean-Marie Hullot 幼小的心靈帶來了巨大的震撼。他立即明白了物件導向思想所代表的先進生產力,一定會改變今後數十年的程式設計流程,他毫不猶豫地成為物件導向程式設計模式的早期粉絲。

SOS 的助力

那時,Jean-Marie Hullot 使用早期的 Macintosh 計算機進行開發。不過他很快就和其他開發者一樣,發現雖然 Mac 的使用者介面做得不錯,但開發程式實在是太糟糕了。他說:“當 Macintosh 被發明出來時,計算機和先前就大不一樣了,你至少需要花 60%~70% 的時間在使用者介面部分的程式碼上。”在 Macintosh 被發明之前,使用者介面是相當簡單的,只需要在命令列下面打一串字元,計算機就會回應出一行行的資訊。所以在那個時代,開發者完全不需要專注於使用者介面。而 Mac 一經發布,隨之而來的眾多的視窗和選單,讓整個世界都不一樣了。雖然對於使用最終產品的使用者而言是簡單方便的,但對於碼工來說簡直是個噩夢。每次他們需要一個視窗或者選單,都要從零開始構建。

聰明的 Hullot 開始動腦筋改進 Mac 編寫使用者程式難的現狀。他開發了一個程式,有點像現在 Windows 系統中的“畫板”。一側的工具條,是類似選單這樣的大量可重用的物件;而另一側,則是程式設計師想構建的使用者程式介面。只要把工具條上的工具拖放到程式介面中,那麼類似“開啟”、“列印”等相關的功能,就可以被新增到使用者介面中。事實上,這個程式,是最早的一批能通過滑鼠把控制元件拖入介面設計視窗實現相應功能的商業程式,是使用者介面設計軟體的先驅。

這個跨時代的發明被稱作 SOS,用 Lisp 語言編寫【注:What are we going to called this thing 中認為此時就是 Interface Builder,但據 The NeXTonian 等多處資料表明,在 Steve Jobs 見到以前,該程式名為 SOS】。當時,ExperTelligence 開發了一種叫做 ExperLisp 的方言,SOS 即用此語言寫成【注:http://en.wikipedia.org/wiki/Interface_Builder】。

此時 Hullot 忽然意識到,他設計的東西事實上很強大,其重要性簡直可以和 Smalltalk 這樣的發明相比——Smalltalk 讓開發者嚐到了面嚮物件語言的甜頭,而 SOS 則是直接把物件放到了開發者手邊。有了這麼拽的東西,Hullot 意識到如果他只在研究所窩著,那隻能讓十幾個人享受這一成果,而如果他跳槽,把這個工具公開,那對天下的碼工來說可是大福音。

誕生之源

經過不斷努力,Hullot 找到了一個值得推銷自己發明的好地方——劍橋的蘋果大學聯盟(Apple University Consortium)。這個蘋果和大學合作的組織看到 Hullot 的創作後反響很好,就推薦他去見 Jean-Louis Gassee。 Jean-Louis Gassee 是個法國人,時任蘋果開發研究院主任,見到 SOS 後也認為這是個好東西,便說服他去美國闖一闖。經過幾次的鼓勵和推薦,加上美國對 Hullot 來說又不陌生,於是他就買了機票跳上飛機就奔赴美國。

不過當 Jean-Marie Hullot 來到美國加州蘋果總部時,他卻認為這不是一個工作的好地方——蘋果已經是一個很龐大的企業,很難再有所創新發展。他最終決定不留在那兒,轉而在美國尋找一個能把這個產品賣出去的人。四處推銷之後,找到他用來寫 SOS 的 Lisp 直譯器的生產商,就是剛才提到的位於 Santa Barbara 的軟體公司 ExperTelligence。

事實上,當時的 ExperTelligence 正在尋找合作商賣自已的 Lisp,而 Hullot 也在找合作商賣自已的 SOS,兩者一拍即合,隨即打電話給 NeXT,共同推銷自家的產品。

NeXT 在 Palo Alto 總部的產品市場部人員接待了 Jean-Marie Hullot 和兩位來自 ExperTelligence 的員工,被 SOS 的理念鎮住,遂打電話請 Steve Jobs 下來看。Jean-Marie Hullot 像復讀機一樣又把自己的大作秀了一遍。老謀深算的 Steve Jobs 事實上早就看中了 SOS,但他對 ExperTelligence 的 Lisp 一點興趣都沒有。所以他裝作對這場演示毫無興致【注:這有很多引用該文的翻譯譯錯,原文說 nonplussed,字面意思為驚異,但在美國非正式表述中,此字表毫無興致】,揮揮手就把這三個人打發走了。

但當他們一行人走到停車場時,Steve Jobs 讓他手下把 Hullot 追了回來,當他隻身回到 NeXT 總部時,發現 Steve Jobs 正恭敬地等著他。

“我想要你計算機上那個程式”【注:http://rixstep.com/2/0/people/】,Steve Jobs 說道:“你大概什麼時候能開始給我們工作?”

Hullot 回答說自己翌日就要離開去度假。

“好吧,我兩週後給你打電話,”Steve Jobs 說。

“不行,老喬”,Hullot 表示:“我不遊美國,我可要環遊歐洲,你七個禮拜後再打給我吧。”

Steve Jobs 雖然一骨子傲氣,但他明白一個簡單的道理:21世紀最缺的是什麼——是人才!即使 Jean-Marie Hullot 玩起了大牌,這電話自然還是要打的。Hullot 剛一度完假回來,Steve Jobs 的電話就如期而至。

如此三顧茅廬般的熱情,把 Jean-Marie Hullot 感動得第二天就登上了去美國的飛機。合約簽了半年,但實際上他最終在 NeXT 整整待了十年。在 NeXT 工作期間,他使用 Objective-C 和 NeXTSTEP 框架重寫了 SOS,命名為 Interface Builder。由此,Interface Builder 成為 NeXT 整合開發環境 Project Builder 標準套件之一。

進階與探索

Interface Builder 和 SOS 一樣,提供了一個工具箱,包含一系列使用者控制元件物件。工具箱並不是官方定死的,而是可以任意擴充套件的,比如如果使用者想使用類似 Safari 中的 toolbar,而這不是官方提供的,則下載第三方的 PSMTabBar 即可實現,甚至連 Cappuccino 這樣的網頁框架也可以用 Interface Builder 來完成設計。開發者只要把控制元件比如選單和文字框拖入專案檔案就能完成使用者介面設計,節省了幾乎所有和控制元件放置有關的程式碼。

開發者拖拽滑鼠,將控制元件可提供的動作(IBAction)和另一個物件的介面(IBOutlet)連在一起, 則建立了一個繫結。這樣,一旦動作被激發(比如使用者點了按鈕),那介面中相應的方法則會被執行。所以,大量物件關聯的程式碼也能被省去。

有了這樣的模式後,Interface Builder 和 Cocoa 可以比後來出現的 Microsoft Visual Studio 或 Qt Designer 等軟體走得更遠——只要是物件,Interface Builder 就能夠操控它們,不需要一定是一個介面的控制元件。比如,資料庫的資料來源、佇列等,都可以在 Interface Builder 中連線起來,於是很多原本需要上千行的複雜應用(比如用來顯示、修改企業中職工姓名、部門、電話、地址、頭像等資訊 SQL 資料庫的使用者介面程式),數分鐘內就可以寫完,不用一行程式碼。不信?讓 1992 年的 Steve Jobs 親自做給你看【注:http://www.youtube.com/watch?v=j02b8Fuz73A, 第 23 分鐘~第 29 分鐘】。

NeXT 被 Apple 收購後,蘋果把下一代作業系統建立在 NeXTSTEP 的基礎上。Objective-C 和 Cocoa 被作為主要框架,而 Interface Builder 和 Project Builder 也因此受到重用。就官方的工具箱而言,支援 Objective-C/Cocoa、Carbon 的 HIToolbox 和 WebObject。

2008 年 3 月 27 日,蘋果釋出首個 iPhone SDK,設計 Cocoa Touch 介面的,也正是 Interface Builder。可以說,Interface Builder 一直隨著公司產品的發展而不斷拓新。

Jean-Marie Hullot 是在 NeXT 被收購時進入蘋果的。Steve Jobs 令他率領在法國的一個小團隊,祕密為 Mac OS X 10.2 開發一個辦公軟體。以往這樣量級的程式,都是由蘋果加州總部的大班人馬完成。而這次,為了向世人表明他的 Interface Builder 有多強大,iCal 橫空出世,展示覆雜的介面元素(日曆、可拖拽的任務、五花八門的分類)和諸多功能(網路同步、Apple Script 指令碼控制)可以用相當快速的時間內開發出來【注:http://www.appleinsider.com/articles/07/10/17/road_to_mac_os_x_leopard_ical_3_0.html&page=2】。

最後,在 iCal 小組打完醬油的 Jean-Marie Hullot 榮升蘋果軟體開發部技術長。

Project Builder 在 Mac OS X 10.3 時被重新命名為現在大家所熟知的 Xcode。Xcode 3 以前,Interface Builder 使用一種名為 nib 格式的二進位制檔案格式。不過由於 nib 不能用肉眼讀,也不方便使用版本管理工具來管理,所以 Xcode 3 開始新加入一種名為 xib 的文字檔案格式,最後再在專案編譯階段輸出為 nib 格式。和產生靜態介面佈局程式碼的工具(如 MSVC、QtDesigner、 Delphi 等類似的軟體)很不同,nib 是不被轉譯成相應 Objective-C 程式碼的。使用者程式執行時,nib 檔案被讀入,解包,並且喚醒【注:awake,即載入 nib 會自動呼叫程式中 awakeFromNib 方法】,所以 nib 檔案是在執行時動態載入的。

長期以來,Xcode 環境和 Interface Builder 是兩個獨立但相互工作的程式。而 2010 年釋出的 Xcode 4 預覽版中,Xcode 和 Interface Builder 合二為一,成為一個一體化的程式設計環境。所以現在,開發者甚至可以只用滑鼠在使用者介面和程式碼間來回拖拽就能完成,這樣一來 Interface Builder 對使用者程式碼的解釋也比先前更正確。比早期分離的程式使用起來確實方便很多。

當然,一個負面的影響是,這樣用一體化整合開發環境寫程式,往往會發現螢幕空間是不夠的,所以像我這樣用 11 寸 Air 或者 13 寸 Macbook Pro 的人,出去打招呼都不好意思說自己是做 Mac 開發的。

下一個海闊天空

在而後的歲月裡,Interface Builder 創造了一個又一個應用軟體神話,小到官方教程中的匯率計算器,大到蘋果所有的家用、專業軟體,都由 Interface Builder 完成。

在風起雲湧的 1989 年,歐洲核子研究組織(CERN)工作的科學家 Emilio Pagiola 忽悠經費,買來研究所的第一臺 NeXT 計算機——當時 NeXT 計算機在 CERN 可是個新鮮事物——那裡的科學家們紛紛前來把玩,普通青年發現裡面有全本的韋氏詞典,並可自動檢查使用者輸入的拼寫錯誤,技術青年發現它跑的是 Unix 系統,還有一個可讀寫的光碟機,文藝青年更是發現裡面居然預裝了莎翁全集。不過畢竟像 Emilio Pagiola 這樣忽悠鉅款買 NeXT 機器的青年不多,所以大家圍觀完了,也就回去該幹嘛幹嘛了。

但 Tim Berners-Lee 和別人不一樣,他不僅圍觀了那臺計算機,還看到了 Jean-Marie Hullot 設計的 Interface Builder,研究了 Objective-C,發現了物件導向程式設計正規化開發環境的最高成就。這情景讓他心中漾起了巨大的波瀾,最終化為激情澎湃的投入,匯成了一行行物件導向的程式碼,一瀉千里,奔向未來。

一年後,世界首個 HTTP 服務在 CERN 的 NeXT 計算機執行起來,而使用 Objective-C 和 Interface Builder 所編寫的超文字語言編輯器兼瀏覽器同步發行。他給這個主從式架構起了個好聽的名字——World Wide Web(全球資訊網)。

Mac OS X 背後的故事(六)上善若水

Aqua 是 Mac OS X Public Beta 全新使用者介面的名字,英文中為水的詞根,寓意以水為靈感,精心設計。Steve Jobs 曾介紹說,Aqua 的設計是如此之美好,初次見它甚至有想親吻的衝動。本篇 Cordell Ratzlaff 引發的 Aqua 革命(上)介紹的是 Aqua 的起源和來歷,在下篇中,我們將展示 Aqua 的具體設計過程。

“Mac OS 的圖形介面就是你們那麼業餘的人設計的嗎?” Steve Jobs 開門見山地問。

Mac OS X 背後的故事

包括 Cordell Ratzlaff 在內的設計師們怯怯地點頭稱是。“你們就是一群白痴!” Steve Jobs 罵道。

這個場景發生在 Steve Jobs 迴歸不久的圖形介面組組會上,前文提到的罵人的話,是他送給圖形介面設計組的見面禮。【注:參見 http://www.cultofmac.com/how-mac-os-x-came-to-be-exclusive-10th-anniversary-story/87889How Mac OS X Came To Be,Leander Kahney

不進則退的局面

Mac OS 曾是圖形介面設計的先驅。

從 System 1 開始,Mac 就打破了字元終端的模式,使用圖形介面和使用者互動設計。但自 System 1 到 System 7,10年過去了,介面卻始終沒有顯著的變化。設計組一直認為,為尊重使用者的習慣,定下的規矩不要輕易改動。但同時,Microsoft 的變化可以說是天翻地覆,從黑屏的 DOS,到全螢幕的 Windows 1,再到成熟的 Windows 3,最後演變到奠定當今 Windows 介面基礎的炫麗多彩的 Windows 95。用當時的眼光來看,這個變化是相當驚人的。由於因循守舊,Mac OS 在介面設計上從領先掉到了最後。舊的介面原語,一成不變的介面風格,讓 Mac OS 的圖形介面在 Windows 前顯得黯然無光。【注:參見 http://vimeo.com/21742166

於是,在圖形介面組的組會上,Steve Jobs 抨擊了老 Mac OS 介面的各種不是——幾乎所有的地方都被罵了一遍。眾矢之的是各種開啟視窗和資料夾的方式。在 Mac OS 中有至少 8 種開啟視窗和訪問資料夾的方式,如彈出選單、下拉選單、DragStrip、Launcher、Finder 等不同的程式。

Cordell Ratzlaff 作為主管,他一開始擔心是不是會被 Steve Jobs 炒掉(傳聞說 Steve Jobs 剛進入蘋果時最愛炒人,經常會發生一些“神奇”的情況,比如有員工和他一同進了電梯,等一同出電梯時,該員工已被炒掉)。不過批評大會進行到第 20 分鐘時,Cordell Ratzlaff 轉為淡定,因為他意識到如果 Steve Jobs 要炒他,不用廢那麼多話,早就可以動手了。

其實 Cardell Ratzlaff 是 Apple 內部較早意識到小組設計不思進取的人之一。他意識到蘋果有三個重要的設計問題【注:參見 Designing Interactions 第二章 My PC 附錄訪談】。第一、Apple 的很多介面語言不明確。例如,在老 Mac OS 中,刪除檔案的動作是把檔案圖示拖到廢紙簍裡,但當磁碟和光碟彈出時,居然也是把圖示拖到廢紙簍裡。第二、老 Mac OS 不會對問題進行變通,如果有幾個圖示同時顯示,視窗還容易操作,但如果有幾十個圖示或視窗,以相同的方式顯示出來,那麼在繁雜的頁面中找尋所需內容,對使用者則是巨大的挑戰。第三、Mac OS 的介面過於古板,看上去還是停留在 Windows 3.0 階段。總之,當時的 Mac OS 已經不能代表先進的生產力,也不能代表科技的前進方向,更不能讓廣大使用者得到更多的利益。在 Cardell Ratzlaff 看來, Mac OS 的介面面臨不進則退的重大困局,非改不可。

Cordell Ratzlaff 的試水

收購 NeXT 以後,Apple 開始考慮如何把 NeXTSTEP 作業系統變為下一代的 Apple 作業系統,但介面設計組的倦怠又浮出水面。設計組認為,這是一個浩大的工程,所以他們決定照著 Mac OS 8 的樣子改 NeXTSTEP 的程式碼,把 NeXTSTEP 改成 System 8 的樣子。這並不困難,組裡只需一個人就能完成這項任務,這人的工作極其無聊——像小孩子描紅模,把新介面的樣子臨摹得和老介面一模一樣。事實上,當 Apple 釋出 Rhapsody 和 Mac OS X Server 初版時,經典 Mac OS 的介面已經被學得惟妙惟肖了。

Cordell Ratzlaff 認為這種混搭,是一個極其讓蘋果丟顏面的事情。所以,除了那個搞山寨的人以外,他召集其他人做新介面設計的圖樣。而由於 NeXTSTEP 具有強大的圖形處理和動畫能力,因此很多新的圖樣是在新系統上完成的。

Mac OS X 背後的故事

Apple 將“What’s not a computer!”(看起來不是電腦的電腦)的概念應用在硬體外觀上,設計出具有浪漫主義氣質,半透明“果凍” 式且具有藝術美感的 iMac,這成了 Aqua 設計靈感的來源。

20世紀 90 年代初,Apple 和 Microsoft 的作業系統都素面朝天,色調簡單,統一的矩形視窗。到 1997~1998 年,Apple 的硬體外觀設計取得重大進展:由後來成為金牌設計師的 Jonathan Ive 領銜,設計出具有浪漫主義氣質、五彩斑瀾的、半透明外殼、具有曲線美感的 iMac,這個設計成為 Cordell Ratzlaff 和他的同事們設計的靈感,他們馬上就作出了一個全新的介面圖樣來。【注:參見http://en.wikipedia.org/wiki/IMac_G3

與此同時,Cordell Ratzlaff 著手解決前文提到的三個設計問題。第一、他提出了一個叫“實時狀態”的概念。當使用者拖動檔案時,廢紙保持原樣,而如果拖動的是磁碟,那廢紙簍的圖示變成“彈出”的圖示。第二、視窗的問題統一採用動畫加以解決。比如視窗的最小化和還原都配有動畫,告訴使用者視窗的來去方向。當 Dock 專案有所增減時,專案長度和元素也會隨之改變。第三、Mac OS 一改死板面孔,呈現多彩的、小清新的圖形介面,所有尖銳的直角都被打磨成圓弧,並且有像 iMac 外殼一樣半透明的選單。當時有評論指責 Apple 的設計太卡通缺乏權威感,其變化之大可見一斑。【注:參見http://www.aresluna.org/attached/files/usability/papers/onethousandsquarepixelsofcanvas.pdfOne thousand square pixels of canvas On evolution of icons in graphical interfaces by Marcin Wichary 第五頁】

Cocoa 之父 Bertrand Serlet,作為 Cordell Ratzlaff 的上司,對新介面很滿意。但當時,他們認為這個新介面實現起來難度很大,既沒有時間也沒有資源把這個想法在 Mac OS X 中付諸實現。於是先前那位孤獨的照葫蘆畫瓢的設計者只好繼續工作。

Aqua 只是個設想(PS 出來的圖樣+模擬出來的視訊),還不是能用的程式碼。

Steve Jobs 的怒火和 Aqua 的源頭

幾個月以後,Apple 舉辦了一個所有開發小組參加的長達兩天的彙報大會。Cordell Ratzlaff 彙報的時間被排在兩天的最後壓軸出場。大多數工程師對這長達兩天的大會報告早已疲倦,感嘆 Mac OS X 剩下的的工作很艱鉅,認為釋出遙遙無期。於是,Cordell Ratzlaff 報告成了整個報告會的最大笑場,所有工程師使出咆哮體來評價這個工作——“啊!!!你看這新介面多出位啊!!!有沒有有沒有!!!居然用的透明通道!!!還搞個實時的動畫!!!你難道不知道你這些永遠是天方夜譚不可能完成嗎???我們工程師傷不起啊傷不起!!!”這個新設計就這樣在所有 Apple 頂級工程師的鄙視下被廢了。

無奈於此,只好無聊地讓那位開發者繼續複製全套經典 Mac OS 介面,而當 Steve Jobs 召集所有設計組負責人時,這個山寨版 Mac OS 的展示把 Steve Jobs 看得情緒激動,就發生了文章開頭的那一幕。

Cordell Ratzlaff 前來解釋壓軸報告的尷尬局面,暗示千里馬常有而伯樂不常有的處境,還讓 Steve Jobs 觀摩了他的傑作。果然 Steve Jobs 看了這幾張圖例後大為驚異,拍著 Cordell Ratzlaff 的肩說:“很好!很強大!”然後讓設計組不惜一切代價做成試驗品。

在加班奮戰的三週後,設計組用 Macromedia Director 完成了一個試驗品。Steve Jobs 親自來 Cordell Ratzlaff 辦公室視察了一下午。結果是他激動地握著 Cordell Ratzlaff 的手,吐露心聲:“你是蘋果裡我見到的第一個智商是三位數字的人。”得到了 Steve Jobs 的支援,Apple 的 Mac OS X 開發團隊,更加緊密地圍繞在以 Cordell Ratzlaff 為核心的介面設計概念周圍,開發作業系統。

有緣千里來相會,無緣對面不相識。Steve Jobs 和 Cordell Ratzlaff 算是相見恨晚。這樣由 Cordell Ratzlaff 主導的新介面,在 Steve Jobs 的支援下,橫掃一切困難,成為新版作業系統介面的最大亮點。

從這時到 Steve Jobs 正式在舞臺上秀他的 Mac OS X Public Beta,還有 18 個月。此時,系統介面革命的旅程已經開始,一道神祕的天光射向 Infinity Loop,千古傑作 Aqua 就要在這裡誕生,其光輝歷程,我們下篇再談。

Mac OS X 背後的故事(七)上善若水下——Cordell Ratzlaff 引發的 Aqua 革命

在前一節中講到,Cordell Ratzlaff 新介面方案得到 Steve Jobs 的高度肯定,Steve Jobs 讓各開發組緊緊圍繞在介面設計組周圍,共同建造 Mac OS X。此時,離 Mac OS X 第一個公共測試版的釋出,僅有一年半時間。這時蘋果的設計構想,還僅僅是個概念,在本篇中我們將展示 Aqua 的具體設計過程。

設計與軟體的融合

開發分設計和軟體兩條路並行走,“兩手抓,兩手都要硬”。

設計是個有趣的領域。有些人認為,設計就是產品的外觀看上去什麼樣。但其實,如果細想一下,你會發現設計其實是有關產品如何工作的學問。

  ——Steve Jobs

首先,蘋果定下計劃,並規劃整個介面設計元素的方案,把設想通過可操作性強的材料讓工程師來實現。

Cordell Ratzlaff 每週都要和 Steve Jobs 開會,向他展示介面設計小組最新成果。任何大家現在見到的各介面控制元件,如選單、按鈕、進度條、Steve Jobs 都一一過目,毫不馬虎。針對每一個控制元件,Cordell Ratzlaff 會要求拿出多套方案來,讓 Steve Jobs 選出他中意的。Steve Jobs 也會提出各種他自己的見解和改進建議,而 Cordell Ratzlaff 則會根據這些回饋不斷修改,直到 Steve Jobs 滿意為止。

與此同時,軟體工程師也以越來越重的比例加入到這個設計行列中。

圖形介面設計小組使用的設計軟體是 Macromedia Director。它能做出演示用的動畫,可以演示開啟、關閉視窗、下拉選單等模擬效果,但這些並不是可供使用者使用的最終軟體。軟體工程師需要把圖形介面設計師的設計,變為一行行程式碼,運用到 Mac OS X 中。所以每次會議的 Macromedia Director 動畫演示機旁,還會有一臺計算機,預裝了軟體工程師轉換的程式碼。當工程師們向 Steve Jobs 展示最新程式碼如何工作時,Steve Jobs 會身體前傾,鼻子快貼到熒幕上,觀察細微到“畫素級別”來比較軟體的表現和之前的設計是否完全一致。如果他有發現任何細微的差錯,一陣類似“你們全是一幫白痴”的腥風血雨就會在辦公室中展開。

設計整套方案是一個令人難以置信的漫長過程,尤其是遇到追求完美的 Steve Jobs。Mac OS X 中有一個控制元件叫滾動條(NSScroller)。當需要顯示的內容長於當前控制元件大小時就會出現滾動條,可上下翻閱內容。這是一個非常不起眼的控制元件,大多數時間,使用者甚至注意不到它的存在,甚至在十年後的今天它都被預設不顯示了(關於 Lion 圖形介面的改動受 iOS 思潮的影響我們今後會提到)。但哪怕是這種不起眼的細節,Steve Jobs 都偏執地當個大專案來做。Mac OS X 的介面設計是有史以來最複雜的一個,需要考慮諸多因素——比如所在視窗的活動與否,都會影響這個控制元件的顏色等屬性。就滾動條而言,箭頭的大小、位置的變化、顏色的啟用等全都是活動的屬性,牽一髮而動全身。一根看似簡單得不能再簡單的滾動條,設計組花了整整六個月來修改。

當時,Mac OS X 的使用者介面有兩個重大的設計目標:第一是讓老使用者沒有壓力地遷移過來,且倍感新介面的好用;第二是讓那些從未摸過 Mac 的人儘快上手,並稱贊這介面很好很強大。所以,整個介面設計保留了老 Mac OS 介面元素的設計理念,但同時又對很多有問題的老設計進行了革新。比如,在老版 Mac OS 中,各種系統設定選項是隱藏在不計其數的系統擴充套件、控制皮膚,以及很多系統元件中的。使用者要想聯個網,要去五六個地方設網路、設 IP、設連線設密碼,而在 Mac OS X 中,所有這些設定都被分門別類地規類到一個單一的程式——系統首選項(System Preferences),讓使用者“足不出戶”,就能進行一切相關設定。

精簡的狂熱追求和大膽的設計創新

Apple 偏愛最簡化的設計,而往往滿屏的視窗讓 Steve Jobs 忍無可忍。又酷又炫的 Dock 橫空出世,巧妙地解決了這個問題。Dock 的設計源於 Mac OS X 的前身 NeXTSTEP,但在 Mac OS X 中完全被重寫,並重定義了它的功能。Dock 提供使用者一個放置常用軟體圖示、閒置視窗、文件的場所,Steve Jobs 說“任何東西都能被拉進 Dock”。但 Dock 真正神奇的,是它猶如多拉A夢的口袋,有無限的承載能力。當放入 Dock 中的東西變多時,它會自動把橫向寬度變長、圖示變小,可承載幾十個視窗。當視窗縮入和還原時,都配有“精靈”一樣的動畫——在 Dock 的圖示多的時候,每個圖示很小,使用者就很難找到需要的——靈動且放大動畫可以讓使用者能快速地找到所需。

另外,起初版本的 Dock 中每個圖示都是正方形的方塊,被換成半透明的背景,看得人垂涎欲滴。這些經典的設計,影響了整整一代圖形介面設計者,被各山寨介面抄了一遍又一遍,甚至又活在當今的 Ubuntu Linux 的 Unity 和 Windows 7 中。

Apple 追求清爽甚至到了發瘋的地步,在最初版的 Mac OS X Public Beta 中,每個視窗有一個按鈕,只要按下,除了當前視窗外,其它一切都會飛入 Dock。因此,只要一鍵,“整個世界都清靜了”。而在後來每個版本的 Mac OS X 中,都有大的更新來防止視窗或其他介面元素的堆積。10. 4 時代的 Expose10. 5 時代的 Stack 和 Spaces,10.6 時代的 Expose 和 Dock 相結合雙管齊下,到 10.7 時代的 Mission Control,都是用來解決果面精簡這一個問題的。

而很多傳統的介面控制元件也被賦予了新的含義。比如 Steve Jobs 覺得,“最大化”一個視窗沒有實際意義,而且把整個視窗最大化,也會擋住後面的視窗(直到 2011 年,Apple 用“全屏”來重新定義傳統的“最大化”)。而 Mac OS X 沒有所謂的“最大化”,取而代之的是自動計算後調整視窗到所需大小的“最適化按鈕”。而關閉一個視窗的含意也不該是關閉一個程式,而只應是結束目前的內容。Apple 的許多設計都格外具有魄力,完全重寫了介面設計的教科書。當然,有許多地方 Apple 確實做得矯枉過正,比如 Apple 一直是我見過的只有拖住右下角才能改動視窗大小的唯一系統。這個置使用者於不顧的狂妄設計,一直在十年後釋出的 Lion 中,才得以改變。

Steve Jobs 一直是介面設計的重要顧問。他有時候會提出一些看似稀奇古怪的意見,但往往最終又被證明是好的。比如,有一次他在會上指出,視窗左上角的“關閉”、“最小化”、“最適化”三個按鈕的顏色都是一樣的灰色,不容易區分他們。他建議把三個按鈕變成交通燈的顏色,並且當滑鼠移到附近時,顯示出相應的圖形指示。當 Cordell Ratzlaff 一群人聽到這個主意後面色大變,認為簡直是計算機圖形設計史上最好笑的段子——誰會把電腦當交通燈使啊。不過改完後,他們對 Steve Jobs 心悅誠服——“紅燈給使用者一個終止的警示,這個視窗要被關掉;黃燈表示這個視窗要被放入等待佇列,以便以後再通行;最適化則是給這個視窗大開綠燈”——這樣高明的比喻,使 Cordell Ratzlaff 對 Steve Jobs 崇拜得五體投地。

18個月轉瞬即逝,“你們就是一群白痴”的罵聲依舊清晰,而此時的 Mac OS X 的圖形介面,已今非昔彼。

“語靜聲息。我走上舞臺。依著那開啟的門,我試圖探測回聲中,蘊涵著什麼樣的未來。”(北島翻譯的帕斯捷爾納克的《哈姆雷特》)。

18 個月後的 2000 年 1 月,新世紀的鐘聲剛剛敲響,Steve Jobs 鎮定地走上 MacWorld 大會的舞臺,獨領風騷的新世紀的經典大作 Aqua,此時,就要被他揭開帷幕。

Mac OS X 背後的故事(八)三好學生 Chris Lattner 的 LLVM 編譯工具鏈

2011年 12 月 3 日,LLVM 3.0 正式版釋出,完整支援所有 ISO C++ 標準和大部分 C++ 0x 的新特性, 這對於一個短短几年的全新專案來說非常不易。

開發者的驚愕

在 2011 年 WWDC(蘋果全球開發者大會)的一場與 Objective-C 相關的講座上,開發者的人生觀被顛覆了。

作為一個開發者,管理好自己程式所使用的記憶體是天經地義的事,好比人們在溜狗時必須清理狗的排洩物一樣(美國隨處可見“Clean up after your dogs”的標誌)。在本科階段上 C 語言的課程時,教授們會向學生反覆強調:如果使用 malloc 函式申請了一塊記憶體,使用完後必須再使用 free 函式把申請的記憶體還給系統——如果不還,會造成“記憶體洩漏”的結果。這對於 Hello World 可能還不算嚴重,但對於龐大的程式或是長時間執行的伺服器程式,洩記憶體是致命的。如果沒記住,自己還清理了兩次,造成的結果則嚴重得多——直接導致程式崩潰

Objective-C 有類似 malloc/free 的對子,叫 alloc/dealloc,這種原始的方式如同管理C記憶體一樣困難。所以 Objective-C 中的記憶體管理又增加了“引用計數”的方法,也就是如果一個物件被別的物件引用一次,則引用計數加一;如果不再被該物件引用,則引用計數減一;當引用計數減至零時,則系統自動清掉該物件所佔的記憶體。具體來說,如果我們有一個字串,當建立時,需要使用 alloc 方法來申請記憶體,引用計數則變成了一;然後被其他物件引用時,需要用 retain 方法去增加它的引用計數,變成二。當它和剛才引用的物件脫離關聯時,需使 release 方法減少引用計數,又變回了一;最後,使用完這個字串時,再用 release 方法減少其引用計數,這時,執行庫發現其引用計數變為零了,則回收走它的記憶體。這是手動的方式

這種方式自然很麻煩,所以又設計出一種叫做 autorelease 的機制(不是類似 Java 的自動垃圾回收)。在 Objective-C 中,設計了一個叫做 NSAutoReleasePool 的池,當開發者需要完成一個任務時(比如每開啟一個執行緒,或者開始一個函式),可以手動創立一個這樣的池子, 然後通過顯式宣告把物件扔進自動回收池中。NSAutoReleasePool 內有一個陣列來儲存宣告為 autorelease 的所有物件。如果一個物件宣告為 autorelease,則會自動加到池子裡。如果完成了一個任務(結束執行緒了,或者退出那個函式),則開發者需對這個池子傳送一個 drain 訊息。這時,NSAutoReleasePool 會對池子中所有的物件傳送 release 訊息,把它們的引用計數都減一 ——這就好比游泳池關門時通知所有客人都“滾蛋”一樣。所以開發者無需顯式宣告 release,所有的物件也會在池子清空時自動呼叫 release 函式,如果引用計數變成零了,系統才回收那塊記憶體。所以這是個半自動、半手動的方式

Objective-C 的這種方式雖然比起 C 來進了一大步,我剛才花了幾分鐘就和讀者講明白了。只要遵守上面這兩個簡單的規則,就可以保證不犯任何錯誤。但這和後來的 Java 自動垃圾回收相比則是非常繁瑣的,哪怕是再熟練的開發者,一不小心就會弄錯。而且,哪怕很簡單的程式碼,比如物件的 getter/setter 函式,都需要使用者寫上一堆的程式碼來管理接收來的物件的記憶體。

經典教材《Cocoa Programming for Mac OS X》用了整整一章節的篇幅,來講解 Objective-C 中記憶體管理相關的內容,但初學者們看得還是一頭霧水。所以,在 2007 年 10.5 釋出時,Objective-C 做出了有史以來最大的更新,最大的亮點是它的執行庫 libobjc 2.0 正式支援自動垃圾回收,也就是由執行庫在執行時隨時偵測哪些物件需要被釋放。聽上去很不錯,可惜使用這個技術的專案卻少之又少。原因很簡單,使用這個特性,會有很大的效能損失,使 Objective-C 的記憶體管理效率低得和 Java 一樣,而且一旦有一個模組啟用了這個特性,這個程式中所有的地方都要啟用這個特性——因此如果你寫了一個使用垃圾回收的庫,那所有引用你庫的程式就都得被迫使用垃圾回收。所以 Apple 自己也不使用這項技術,大量的第三方庫也不使用它。

這個問題隨 Apple 在移動市場的一炮走紅而變得更加嚴峻。不過這次,Apple 和與會的開發者講,他們找到了一個解決問題的終極方法,這個方法把從世界各地專程趕來聆聽聖諭的開發者驚得目瞪口呆——你不用寫任何記憶體管理程式碼,也不需要使用自動垃圾回收。因為我們的編譯器已經學會了上面所介紹的記憶體管理規則,會自動在編譯程式時把這些程式碼插進去。

這個編譯器,一直是 Apple 公開的祕密——LLVM。說它公開,是因為它自始至終都是一個開源專案;而祕密,則是因為它從來沒公開在 WWDC 的 Keynote 演講上亮相過 。

一直關注這系列連載的讀者一定還記得,在第二篇《Linus Torvalds 的短視》介紹 Apple 和 GPL 社群的不合時,提到過“自以為是但程式碼又寫得差的開源專案,Apple 事後也遇到不少,比如 GCC 編譯器專案組。雖然大把鈔票扔進去,在先期能夠解決一些問題,但時間長了這群人總和 Apple 過不去,並以自己在開源世界的地位恫嚇之,最終 Apple 由於受不了這些專案組的態度、協議、程式碼質量,覺得還不如自己造輪子來得方便。”LLVM 則是 Apple 造的這個輪子,它的目的是完全替代掉 GCC 那條編譯鏈。它的主要作者,則是現在就職於 Apple 的 Chris Lattner。

編譯器高材生 Chris Lattner

2000年,本科畢業的 Chris Lattner 像中國多數大學生一樣,按部就班地考了 GRE,最終前往 UIUC(伊利諾伊大學厄巴納香檳分校),開始了艱苦讀計算機碩士和博士的生涯。在這階段,他不僅周遊美國各大景點,更是努力學習科學文化知識,翻爛了“龍書”(《Compilers: Principles, Techniques, and Tools》),成了 GPA 牛人【注:最終學分積 4.0 滿分】,以及不斷地研究探索關於編譯器的未知領域,發表了一篇又一篇的論文,是中國傳統觀念裡的“三好學生”。他的碩士畢業論文提出了一套完整的在編譯時、連結時、執行時甚至是在閒置時優化程式的編譯思想,直接奠定了 LLVM 的基礎。

LLVM 在他念博士時更加成熟,使用 GCC 作為前端來對使用者程式進行語義分析產生 IF(Intermidiate Format),然後 LLVM 使用分析結果完成程式碼優化和生成。這項研究讓他在 2005 年畢業時,成為小有名氣的編譯器專家,他也因此早早地被 Apple 相中,成為其編譯器專案的骨幹。

Apple 相中 Chris Lattner 主要是看中 LLVM 能擺脫 GCC 束縛。Apple(包括中後期的 NeXT) 一直使用 GCC 作為官方的編譯器。GCC 作為開源世界的編譯器標準一直做得不錯,但 Apple 對編譯工具會提出更高的要求。

一方面,是 Apple 對 Objective-C 語言(甚至後來對 C 語言)新增很多特性,但 GCC 開發者並不買 Apple 的帳——不給實現,因此索性後來兩者分成兩條分支分別開發,這也造成 Apple 的編譯器版本遠落後於 GCC 的官方版本。另一方面,GCC 的程式碼耦合度太高,不好獨立,而且越是後期的版本,程式碼質量越差,但 Apple 想做的很多功能(比如更好的 IDE 支援)需要模組化的方式來呼叫 GCC,但 GCC 一直不給做。甚至最近,《GCC 執行環境豁免條款 (英文版)》從根本上限制了 LLVM-GCC 的開發。 所以,這種不和讓 Apple 一直在尋找一個高效的、模組化的、協議更放鬆的開源替代品,Chris Lattner 的 LLVM 顯然是一個很棒的選擇。

剛進入 Apple,Chris Lattner 就大展身手:首先在 OpenGL 小組做程式碼優化,把 LLVM 執行時的編譯架在 OpenGL 棧上,這樣 OpenGL 棧能夠產出更高效率的圖形程式碼。如果顯示卡足夠高階,這些程式碼會直接扔入 GPU 執行。但對於一些不支援全部 OpenGL 特性的顯示卡(比如當時的 Intel GMA 卡),LLVM 則能夠把這些指令優化成高效的 CPU 指令,使程式依然能夠正常執行。這個強大的 OpenGL 實現被用在了後來釋出的 Mac OS X 10.5 上。同時,LLVM 的連結優化被直接加入到 Apple 的程式碼連結器上,而 LLVM-GCC 也被同步到使用 GCC 4 程式碼。

LLVM 真正的發跡,則得等到 Mac OS X 10.6 Snow Leopard 登上舞臺。可以說, Snow Leopard 的新功能,完全得益於 LLVM 的技術。而這一個版本,也是將 LLVM 推向真正成熟的重大機遇。

關於 Snow Leopard 的三項主推技術(64位支援、OpenCL,以及 Grand Central Dispatch)的細節,我們會在下一次有整整一期篇幅仔細討論,這次只是點到為止——我們告訴讀者,這些技術,不但需要語言層面的支援(比如 Grand Centrual Dispatch 所用到的“程式碼塊”語法, 這被很多人看作是帶 lambda 的 C),也需要底層程式碼生成和優化(比如 OpenCL 是在執行時編譯為 GPU 或 CPU 程式碼併發執行的)。而這些需求得以實現,歸功於 LLVM 自身的新前端——Clang。

優異的答卷——Clang

前文提到,Apple 吸收 Chris Lattner 的目的要比改進 GCC 程式碼優化巨集大得多——GCC 系統龐大而笨重,而 Apple 大量使用的 Objective-C 在 GCC 中優先順序很低。此外 GCC 作為一個純粹的編譯系統,與 IDE 配合得很差。加之許可證方面的要求,Apple 無法使用 LLVM 繼續改進 GCC 的程式碼質量。於是,Apple 決定從零開始寫 C、C++、Objective-C 語言的前端 Clang,完全替代掉 GCC。

正像名字所寫的那樣,Clang 只支援 C,C++和 Objective-C 三種C家族語言。2007年開始開發,C 編譯器最早完成,而由於 Objective-C 相對簡單,只是 C 語言的一個簡單擴充套件,很多情況下甚至可以等價地改寫為C語言對 Objective-C 執行庫的函式呼叫,因此在 2009 年時,已經完全可以用於生產環境。C++ 的支援也熱火朝天地進行著。

Clang 的加入代表著 LLVM 真正走向成熟和全能,Chris Lattner 以影響他最大的“龍書”封面【注:見 http://en.wikipedia.org/wiki/Dragon_Book_(computer_science)】為靈感,為專案選定了圖示——一條張牙舞爪的飛龍

Clang 一個重要的特性是編譯快速,佔記憶體少,而程式碼質量還比 GCC 來得高。測試結果表明 Clang 編譯 Objective-C 程式碼時速度為 GCC 的 3 倍【注:http://llvm.org/pubs/2007-07-25-LLVM-2.0-and-Beyond.pdf】,而語法樹(AST)記憶體佔用則為被編譯原始碼的 1.3 倍,而 GCC 則可以輕易地可以超過 10 倍。Clang 不但編譯程式碼快,對於使用者犯下的錯誤,也能夠更準確地給出建議。使用過 GCC 的讀者應該熟悉,GCC 給出的錯誤提示基本都不是給人看的。

比如最簡單的:

struct foo { int x; }

typedef int bar;

如果使用 GCC 編譯,它將告訴你:

t.c:3: error: two or more data types in declaration specifiers

但是 Clang 給出的出錯提示則顯得人性化得多:

t.c:1:22: error: expected ‘;’ after struct

甚至,Clang 可以根據語境,像拼寫檢查程式一樣地告訴你可能的替代方案。

比如這個程式:

#include <inttypes.h>

int64 x;

GCC 一樣給出亂碼似的出錯提示:

t.c:2: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘x’

而優雅的 Clang 則用彩色的提示告訴你是不是拼錯了,並給出可能的變數名:

t.c:2:1: error: unknown type name ‘int64′; did you mean ‘int64_t’?

int64 x;^~~~~int64_t

更多的例子可以參考 http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-recovery.html。 而同時又因為 Clang 是高度模組化的一個前端,很容易實現程式碼的高度重用。所以比如 Xcode 4.0 的整合程式設計環境就使用 Clang 的模組來實現程式碼的自動加亮、程式碼出錯的提示和自動的程式碼補全。開發者使用 Xcode 4.0 以後的版本,可以極大地提高程式設計效率,儘可能地降低編譯錯誤的發生率。

支援 C++ 也是 Clang 的一項重要使命。C++ 是一門非常複雜的語言,大多編譯器(如 GCC、MSVC)用了十多年甚至二十多年來完善對 C++ 的支援,但效果依然不很理想。Clang 的 C++ 支援卻一直如火如荼地展開著。2010 年 2 月 4 日,Clang 已經成熟到能自舉(即使用 Clang 編譯 Clang,到我發稿時,LLVM 3.0 釋出已完整支援所有 ISO C++ 標準,以及大部分C++ 0x 的新特性。

這對於一個短短几年的全新專案來說是非常不易的。得益於本身健壯的架構和 Apple 的大力支援,Clang 越來越全能,從 FreeBSD 到 Linux Kernel , 從 Boost 到 Java 虛擬機器, Clang 支援的專案越來越多。

Apple 的 Mac OS X 以及 iOS 也成了 Clang 和 LLVM 的主要試驗場——10.6 時代,很多需要高效執行的程式比如 OpenSSL 和 Hotspot 就由 LLVM-GCC 編譯來加速的。而 10.6 時代的 Xcode 3.2 諸多圖形介面開發程式如 Xcode、Interface Builder 等,皆由 Clang 編譯。到了 Mac OS X 10.7,整個系統的的程式碼都由 Clang 或 LLVM-GCC 編譯【注:http://llvm.org/Users.html】。

LLVM 周邊工具

由於受到 Clang 專案的威脅,GCC 也不得不軟下來,讓自己變得稍微模組化一些,推出外掛的支援,而 LLVM 專案則順水推舟,索性廢掉了出道時就一直作為看家本領的 LLVM-GCC,改為一個 GCC 的外掛 DragonEgg。 Apple 也於 Xcode 4.2 徹底拋棄了 GCC 工具鏈。

而 Clang 的一個重要衍生專案,則是靜態分析工具,能夠通過自動分折程式的邏輯,在編譯時就找出程式可能的 bug。在 Mac OS X 10.6 時,靜態分析被整合進 Xcode 3.2,幫助使用者查詢自己犯下的錯誤。其中一個功能,就是告訴使用者記憶體管理的 Bug,比如 alloc 了一個物件卻忘記使用 release 回收。這已經是一項很可怕的技術,而 Apple 自己一定使用它來發現並改正 Mac OS X 整個系統各層面的問題。但許多開發者還不滿足——既然你能發現我漏寫了 release,你為什麼不能幫我自動加上呢?於是 ARC 被整合進 Clang,發生了文章開頭開發者們的驚愕——從來沒有人覺得這件事是可以做成的。

除 LLVM 核心和 Clang 以外,LLVM 還包括一些重要的子專案,比如一個原生支援除錯多執行緒程式的偵錯程式 LLDB,和一個 C++ 的標準庫 libstdc++,這些專案由於是從零重寫的,因此要比先前的很多專案站得更高,比如先前 GNU、Apache、STLport 等 C++ 標準庫在設計時,C++0x 標準還未公佈,所以大多不支援這些新標準或者需要通過一些骯髒的改動才能支援,而 libstdc++ 則原生支援C++0x。而且在現代架構上,這些專案能動用多核把事情處理得更好。

不單單是 Apple,諸多的專案和程式語言都從 LLVM 裡取得了關鍵性的技術。Haskell 語言編譯器 GHC 使用 LLVM 作為後端,實現了高質量的程式碼編譯。很多動態語言實現也使用 LLVM 作為執行時的編譯工具,較著名的有 Google 的 Unladen Swallow【注:Python 實現,後夭折】、PyPy【注:Python 實現】,以及 MacRuby【注:Ruby 實現】。例如 MacRuby 後端改為 LLVM 後,速度不但有了顯著的提高,更是支援 Grand Central Dispatch 來實現高度的並行執行。由於 LLVM 高度的模組化,很方便重用其中的元件來作為一個實現的重要組成部分,因此類似的專案會越來越多。

LLVM 的成熟也給其他痛恨 GCC 的開發專案出了一口惡氣。其中最重要的,恐怕是以 FreeBSD 為代表的 BSD 社群。BSD 社群和 Apple 的聯絡一向很緊密,而且由於程式碼相似,很多 Apple 的技術如 Grand Central Dispatch 也是最早移植到 FreeBSD 上。BSD 社群很早就在找 GCC 的替代品,無奈大多都很差(如 Portable C Compiler 產生的程式碼質量和 GCC 不能同日而語)。

一方面是因為不滿意 GCC 的程式碼品質【注:BSD 程式碼整體要比 GNU 的高一些,GNU 程式碼永無休止地出現各種嚴重的安全問題】,更重要的是協議問題。BSD 開發者有潔癖的居多,大多都不喜歡 GPL 程式碼,尤其是 GPL 協議第三版釋出時,和 FreeBSD 的協議甚至是衝突的。這也正是為什麼 FreeBSD 中包含的 GNU 的 C++ 執行庫還是 2007 年以 GPLv2 釋出的老版本,而不是支援C++0x 的但依 GPLv3 協議釋出的新版本。因此歷時兩年的開發後,2012年初發布的 FreeBSD 9.0 中,Clang 被加入到 FreeBSD 的基礎系統。 但這只是第一步,因為 FreeBSD 中依然使用 GNU 的 C++ STL 庫、C++ 執行庫、GDB 偵錯程式、libgcc/libgcc_s 編譯庫都是和編譯相關的重要底層技術,先前全被 GNU 壟斷,而現在 LLVM 子專案 lldb、libstdc++、compiler-rt 等專案的出現,使 BSD 社群有機會向 GNU 說“不”,因此一個把 GNU 元件移出 FreeBSD 的計劃被構想出來,並完成了很大一部分。編寫過《Cocoa Programming Developer’s Handbook》的著名 Objective-C 牛人 David Chisnall 也被吸收入 FreeBSD 開發組完成這個計劃的關鍵部分。 預計在 FreeBSD 10 釋出時,將不再包含 GNU 程式碼。

LLVM 在短短五年內取得的快速發展充分反映了 Apple 對於產品技術的遠見和處理爭端的決心和手腕,並一躍成為最領先的開源軟體技術。而 Chris Lattner 在 2010 年也贏得了他應有的榮譽——Programming Languages Software Award(程式設計語言軟體獎)。

Mac OS X 背後的故事(九)半導體的豐收

  半導體的豐收(上)

在美國賓夕法尼亞州的東部,有一個風景秀美的城市叫費城。在這個城市誕生了一系列改變世界的奇蹟:第一個三權分立的國家——美立堅合眾國,就在第五街的路口誕生;舉世聞名的費城交響樂團,1900年在市中心的 Academy of Music 奏響了他們的第一個音符。而寫這篇文章時,我正坐在三十四街的賓夕法尼亞大學計算機系的一樓實驗室,面前擺放著世界上第一臺電子計算機——ENIAC。

1946年 2 月 14 日,ENIAC 問世,每秒可執行 5000 次加法運算或 500 次乘法運算,面積達 170 平方米,重約 30 噸,拉開了計算機處理器革命的序幕。這場革命是各處理器廠商長達數十年的競賽,而摩爾定律從一開始就準確地預測了這場比賽的走勢。根據摩爾定律,同樣價格的積體電路上可容納的電晶體數目,每隔約 18 個月便會增加一倍,效能也將提升一倍。但事實上,並無法用老路子來保持這個增長速度,因為會遇到包括能耗、散熱等各種技術瓶頸。所以每隔幾年就會有用來繞過這些瓶頸的新一代產品推出。如採用超純量(superscala)、指令管線化快取等。這些技術通過一定程度的高效並行來挖掘計算機處理器的速度所能達到的高度,以促使使用者更新換代。

Mac OS X 背後的故事

世界上第一臺計算機 ENIAC,1946年 2 月 14 日誕生於賓夕法尼亞大學

和 66 年前的 ENIAC 相比,今天的處理器已有了質的飛越。而 21 世紀的前十年,我們更是見證了個人計算機處理器的三次重大革命——64位處理器、多核心和高效圖形處理器在個人電腦出現。在這樣的背景下,賈伯斯在 2008 年 WWDC(蘋果全球開發者大會)上,宣佈下一代 Mac 作業系統 Mac OS X 10.6 將被命名為 Snow Leopard(雪豹)來適應硬體架構的革新。就在那天下午,Bertrand Serlet 在一場開發者內部講座上透露,和先前兩個發行版包含大量的新功能(10.4 Tiger 包含 150 個新功能,10.5 Leopard 包含 300 個新功能)不同,Snow Leopard 不含任何新功能,僅是對 Leopard 中諸多技術的重大更新,以使其在現代架構上更穩定、高效。 在這十年的最後一年,2009 年 8 月 28 日,蘋果釋出了 Mac OS X 10.6 來有效地支援這三項技術,而本文將為讀者介紹其對應的三項軟體技術——64位架構、Grand Central Dispatch,以及 OpenCL。 其他 Mac OS X 10.6 技術更新,如全新的 QuickTime X 和跳票的 ZFS,有著更復雜的歷史背景(以後再為讀者介紹)。

64 位架構出現的緣由

前文提到,根據摩爾定律,同樣價格的積體電路上可容納的電晶體數目,約每隔 18 個月便會增加一倍,效能也將提升一倍。事實上,儲存器的容量增長可能更快,每過 15 個月就會翻一番。有了更快更強的電腦,可能會讓數值計算的科學家們喜出望外,但對普通大眾來說,摩爾定律給普通消費者一個假象——如果你覺得 1000 美元的蘋果電腦太貴,那等上 18 個月就可以用 500 美元買到同樣的電腦。十年前你在用電腦寫 Word 文件,十年後你還在用電腦寫 Word 文件,反正計算機不是耗材,一臺電腦只要不壞,就不用去買新的。計算機產業的巨頭們自然知道摩爾定律對他們造成的致命打擊,因此,一個陰謀被以 Intel 和 Microsoft 為首的巨頭們構想出來——Intel 負責把硬體越做越快,而 Microsoft 則負責把自己的軟體越做越臃腫、越做越慢——至於你信不信,反正我是信的。因此,使用軟體、服務等,直接促進計算機產業的消費,使得計算機產業走上可持續發展的道路。這在計算機產業被稱為 Andy-Bill 定律,分別以 Intel 和 Microsoft 總裁的名字命名。

當然,軟體公司未必真心欺騙消費者,故意把軟體做大做慢——為了實現一個新功能,軟體勢必會比原先龐大。但現代軟體的速度、大小和其增加的功能並不成比例。比如對終端使用者來講,Windows Vista 到底比 Windows XP 多了多少功能呢?可能只有 20%~30%。Word 2007 對比 Word 2003 多了多少功能呢?可能也只有 20%~30%。但 Windows Vista、Word 2007 佔用的 CPU、記憶體、磁碟空間,卻比 Windows XP 和 Word 2003 翻了幾番。究其原因,為了能趕快把新功能帶給使用者,我們不惜使用更方便但低效的程式語言(.NET、Java 等依賴虛擬機器的語言就要比 C 慢許多,Python 等動態語言比 C 慢的不是一星半點)、快速開發(我們原先處理一個大文字,先分塊,一點一點讀到記憶體中,然後把處理完的部分寫回磁碟,清空記憶體;而現在直接把它全讀進來處理,開發方便,執行也快)。而使用者必須為這些新功能買不成比例的單。64 位就是在這個背景下迅速走入尋常百姓家的——程式佔用越來越多的記憶體,而 32 位的定址空間已不能滿足軟體執行的需要了。

64位 CPU 是指 CPU 內部的通用暫存器的寬度為 64bit,支援整數的 64bit 寬度的算術與邏輯運算。早在 1960 年代,64位架構便已存在於當時的超級電腦,且早在 1990 年代,就有以 RISC 為基礎的工作站和伺服器。2003 年才以 x86-64 和 64 位元 PowerPC 處理器架構(在此之前是 32 位元)的形式引入到個人電腦領域。從 32 位元到 64 位元架構的改變是一個根本的改變,因為大多數作業系統必須進行全面性修改以取得新架構的優點。

成功的遷移

蘋果向 64 位處理器的遷移花了整整 6 年時間,遠長於該公司其他技術的遷移——向 Intel 的遷移僅用了一年時間,從經典 Mac OS 到 Mac OS X 也僅用了三年時間。總而言之,這場遷移是非常成功的:一方面,使用者基本無痛苦,老的 32 位程式在目前最新版的 Mac OS X Lion 中依然可以完全相容地執行;另一方面,對開發者而言,基本只需做微小的調整,重新編譯程式,而且若干技術如 Universal Binary,使他們釋出程式非常方便。當然,對於某些大量使用過時技術的公司,如 Adobe 和 Microsoft,這場遷移則要折騰得多。

這場遷移整整用了四個發行版的時間(10.3 至 10.6),不同於 Windows 或 Linux,Mac OS X 對 64 位的遷移自下而上,再自上而下。先是核心擴充套件,逐漸上升至 Unix 空間,然後上升至使用者介面,再上升至整個應用程式生態,最後完成核心的遷移。要提醒讀者的是,Mac OS X 的 32 位和 64 位核心空間與使用者空間的分配和實現,和 Windows 存在本質的區別,但在本期介紹中,我們儘可能少地把 Mac OS X 的 64 位遷移和 Windows 進行比較,不拘泥於技術細節,對此區別有興趣的讀者,請移步 AppleInsider 的系列專題

2003 年,蘋果釋出了其第一款 64 位計算機工作站 Power Mac G5。同期釋出的 Mac OS X 10.3 也因此增加了非常簡單的 64 位支援,於是 XNU 核心開始支援 64 位的暫存器和整數計算。但對於使用者空間而言,程式可見的地址依然是 32 位的。程式當然可以使用大於 4GB 的記憶體(Power Mac G5 最高可達 8GB 定址空間),但這要求程式手動地在兩個 32 位記憶體空間中來回轉換。

兩年後,蘋果釋出了當時最成功的 Mac OS X 發行版 Mac OS X 10.4 Tiger。10. 4 的核心是革命性的,除了增加對核心並行多執行緒的支援,它把使用者空間可見的地址空間擴充套件到了 64 位,因此理論上使用者程式可以以 64 位方式執行。當然,在這個時期,幾乎系統內的所有程式,哪怕是核心,依然是 32 位的。系統中唯一帶的 64 位二進位制檔案是名為 libSystem.dylib 的系統庫。它是 Mac OS X 上對 C 標準和 POSIX 標準的支援庫,由 libc、libinfo、libkvm、libm 和 libpthread 五部分組成。但這僅有的 libSystem.dylib 理論上就能讓所有僅使用 C 標準庫和 POSIX 標準庫的程式以 64 位模式執行。當時,使用者對 64 位的需求較少,主要限於科學計算或圖形處理等需要大陣列的領域。因此,10.4 能較好地滿足這部分使用者的需求。但如果程式需要呼叫除 BSD Unix 以外的系統呼叫,比如想用 Cocoa 來畫圖形介面,那麼該程式僅能以 32 位方式執行了。對於一些需要 64 位定址空間的科學計算程式,比如 Mathematica,就需要採用一些比較麻煩的做法:用一個程式呼叫 32 位的 Cocoa 畫圖形介面,用另一個程式呼叫 64 位的 libSystem 來進行運算和 Unix 系統呼叫,並用 Unix 管道或程式間通訊的方式管理兩個程式間的輸入/輸出。

蘋果在 Mac OS X 10.4 釋出同期的另一項重要決策是向 Intel 平臺 x86 及 x86_64架構的遷移。為了幫助開發者和使用者順利遷移,蘋果正式公佈了 Universal Binary。Universal Binary 技術是 Mach-O 二進位制檔案早就具有的特性,只是在這個場合作為一個商業詞彙進行宣傳。NeXT 時代 NeXTSTEP 作業系統就支援許多種不同的硬體架構,自然可以要求開發者對每個平臺釋出一個獨立的版本,但這樣的分發模式很麻煩,消費者也需要搞清到底購買哪種平臺的軟體。因此 NeXT 的 Mach 核心所支援的 Mach-O 二進位制檔案格式引入了一種叫 fat binary 的特性,說白了就是在一個平臺架構上分別交叉編譯所有平臺的二進位制格式檔案,然後把每個檔案都打包成一個檔案。Universal Binary 就是指同時打包 Intel 平臺和 PowerPC 平臺的二進位制檔案。Mac OS X 10.4 最終支援四個平臺的 BSD 系統呼叫——32 位 Power PC、64 位 PowerPC、32 位 x86 和 64 位 x86_64。作為終端使用者,無須搞清這些區別,因為使用 Universal Binary 技術,買回來的軟體直接會解出相應平臺程式的二進位制檔案並執行。這是蘋果很成功的一步——不像 Windows 系統中要用不同的路徑(\Windows\System、\Windows\System32、\Windows\System64)分別存放不同架構的二進位制庫,並且使用者還需在 32 位版和 64 位版之間猶豫不決。

Mac OS X 10.5 Leopard 經過一系列跳票終於在 2007 年末釋出,跳票主要原因是當時蘋果投入了大量人力和物力去做 iPhone,以至於 10.5 跳票了整整一年。10.5 包含了約 300 項新功能,而最重要的一項是蘋果把對 64 位的支援帶入了 Cocoa 層面。因此,幾乎系統中所有的庫都有四個平臺的版本。在 WWDC 上賈伯斯親自向與會者介紹遷移到 64 位的好處,而能使用更大的記憶體自然是一項重要優勢,程式可以申請更大的記憶體,把所有資料一併讀入記憶體中操作,而無須分塊後來來回回地在記憶體和磁碟搬運資料。另外,對 Intel 平臺來說,x86 架構只有 8 個暫存器,而 x86_64 平臺有 16 個暫存器,這也就意味著,對該平臺來說,只要重新編譯程式,程式就能自由排程比原先翻倍的暫存器數量而無須快取或在記憶體中來回查詢和讀寫。根據粗略估算,一般涉及大量數值計算的程式會加快一倍。所以他很開心地勸說所有的開發者都遷移到 64 位架構。

歷時整整 6 年時間,蘋果完成了向 64 位處理器的遷移,同時這也給蘋果提供了良好的清理門戶的機會——清理過時的技術和 API。

徹底的清理

同時,蘋果做出了一個大膽的舉動——Carbon 框架並未出現在這次遷移中。Carbon 是 Mac OS X 誕生之初為了幫助 Mac OS 開發者把老程式遷移到新的 Mac OS X 作業系統上所提出的一個相容 API,這套 API 長得很像經典 Mac OS 的 API,但能夠得到 Mac OS X 平臺提供的一切新特性,Adobe、Microsoft 等都是通過 Carbon 把它們經典的 Mac OS 程式移植到 Mac OS X 上的。蘋果的本意是希望開發者用 Carbon 遷移老程式,用 Cocoa 開發新程式,但在 Carbon 誕生之初,其受關注度遠大於 Cocoa,據 TeXShop 開發者 Dick Koch 回憶,在 Mac OS X 剛誕生的開發者大會上,Carbon 講座的教室擠滿了人,而 Cocoa 相關的講座上聽者無幾。維護兩套雷同的 API 的代價自然很高,所以砍掉一個是大勢所趨。Carbon 和 Java 的熱度甚至一度讓蘋果產生索性把 Cocoa 或 Objective-C 砍掉的想法。大量蘋果自家的程式如 Finder、iTunes、Final Cut、QuickTime 等也都是用 Carbon 寫成的。不過在此後由於大量湧現在 Mac OS X 平臺上的新程式都是 Cocoa 寫的,導致 Cocoa 技術不斷走高。2007年的 iPhone 也完全依賴於 Objective-C 和 Cocoa 的一個裁剪版 Cocoa Touch。因此在 WWDC 2006 上,蘋果在 Mas OS X Leopard 10.5 的開發預覽版中包含了測試版本的 64 位 Carbon 庫,甚至還有講座教如何開發 64 位的 Carbon 程式。但蘋果卻在 2007 年告訴 Carbon 開發者,他們的程式將不可能再被編譯成 64 位,要做到這點,必需先把程式用 Cocoa 重寫。

這個突然的決定激怒了很多開發者,尤其是以 Microsoft 和 Adobe 這些巨頭為代表的公司。Adobe 全套的 Creative Suite 和 Microsoft 全套的 Microsoft Office 是很多蘋果使用者必備的軟體,數百萬行程式碼全是用 Carbon 寫的。所以直到今天,除了 Adobe Photoshop 等少數程式終於在 2010 年全面移植到 Cocoa 後做出了 64 位版,其他大部分程式依然停留在 Carbon 的 32 位模式。

蘋果也花了很長時間來重寫 Finder、FinalCut、iTunes、QuickTime 等程式或技術,耗費了大量精力。當 Adobe 釋出 64 位的 Lightroom 2.0 時,蘋果還在手忙腳亂地重寫 Aperture。不過公正地講,長痛不如短痛,砍掉對 Carbon 的支援能夠使蘋果把更多精力放在該做的事上,也使得 Mac OS X 的結構更簡潔,並且事實上,64 位的遷移為蘋果提供一個砍去老 API 的機遇,哪怕對 Cocoa 也是。一方面,Cocoa 框架中很多類不是使用類似 Carbon 的 API,就是依賴於用 Carbon 實現(注意,和傳統觀念不同,Carbon 和 Cocoa 在早期 Mac OS X 上是相互依賴的,比如選單 NSMenu 就使用了 Carbon 的選單管理器),這些 API 在 64 位得到了徹底清理,QuickTime 相關的 C 介面全被砍去。Cocoa 經過很長時間的發展,自然也保留了很多過時的 API 以保證和原先的產品相容,而這次機會給蘋果足夠的理由徹底推翻原先的設計。在 Mac OS X 10.5 中, Objective-C 的執行庫 libobjc 更新到 2.0,提供了全新的併發、異常處理、自動記憶體回收、屬性(property)等新機制,其中很多新特性只供64位享用。同時,所有 int 都被改為 NSInteger,Core Graphics 中的 float 都改為 CGFloat,以保持 API 統一,這些都是 64 位架構上的改動。因此 64 位遷移給蘋果一個很好的清理門戶的機會。

作為相反的例子,這次清理也有不徹底的地方。比如從老版 Mac OS 中混進來的 Keychain 庫,甚至具有 Pascal 風格的 API,由於沒有替代品,它也得到了 64 位的更新。所以類似 keychain 這樣的庫成了現在 Mac OS X 程式設計師的噩夢。我每次用到 Keychain 都有痛不欲生的感覺。

而 2009 年釋出的 Mac OS X 10.6 Snow Leopard 則是對 64 位真正完整的支援。Unix 層雖然 10.4 就提供了 64 位的 libSystem,但所有的 Unix 使用者空間工具包括 ls、Python 等,以及 Xcode 中的 gcc,也都是以 32 位二進位制的模式釋出的。圖形介面層,在 10.5 Leopard 中,雖然整個系統的庫都遷移到 64 位,以 32 位和 64 位的混合模式釋出,但使用者應用程式依然是 32 位的。只有 Chess、Java、Xcode 套件等少數程式以 64 位編譯。但在 10.6 中,基本所有的應用程式都被遷移到 64 位,不管是 Safari、Mail、Dock,還是 TextEdit。當然,各種 Unix 工具包括 LLVM、GCC 等也都以 64 位的模式釋出。10.6 只有四個 Carbon 程式(Front Row、iTunes、DVD Player 以及 Grapher)未得到 64 位升級【2009 年查閱,現頁面已更新至 10.7】。其中, Front Row 在 Mac OS X 10.7 Lion 中被砍掉, iTunes 在 10.7 釋出時依然以 32 位模式釋出,在 2011 年末的更新中才遷至 64 位。

為了使應用支援 64 位,蘋果不遺餘力地改寫了大量程式碼,Snow Leopard 中最重要的重寫當屬 Finder,這個程式自 Mac OS X 釋出以來就一直是一個 Carbon 程式,並且蘋果一直不停地改進它以展示 Carbon 無所不能。但自從 10.5 時代蘋果下決心砍掉 Carbon 後,該程式被完整地重寫。新的 Finder 和 Carbon 版的 Finder 看上去並沒有太大差別,但 Finder 使用 Cocoa 重寫後,不僅速度更快,而且增加了許多 Cocoa 新特性,比如加入了更多的 Core Animation 特效來平滑過渡動畫。總之,雖然蘋果在 10.6 期間沒有提供太多新功能,但這樣大規模的重寫,為今後程式碼的可維護性奠定了良好的基礎。

Mac OS X 10.6 發行版也完成了 64 位化的最後一步——核心的 64 位化。

半導體的豐收(中)

經過 6 年時間,4 個發行版,蘋果終於完成了向 64 位的遷移,並隨著 Snow Leopard 的釋出推出瞭解決並行程式設計問題的 Grand Central Dispatch(簡稱 GCD)技術,釋放了多核系統的潛力。

和 10.5 一樣,在 10.6 Snow Leopard 中,蘋果繼續利用 64 位的遷移砍掉了諸多老技術,很多新技術僅以 64 位的模式被支援。例如重寫的 QuickTime X 框架,雖然 QuickTime X 應用程式以 32 位和 64 位的模式釋出,但其 API 僅暴露給 64 位。另一個例子是 Objective-C 2.1 的執行庫,快速 Vtable 排程,新的和 C++ 統一的異常處理模型,以及徹底解決物件的 FBI 問題等,都僅限 64 位程式使用。

核心的 64 位化

讀者應該發現,經過這 4 個發行版,Mac OS X 自下而上地對整個系統向 64 位遷移。10.3 核心空間提供了 64 位整數運算的支援。10.4 允許程式以 64 位模式執行在使用者空間,並且提供了 64 位的 libSystem 使得開發者可以開發 64 位的 Unix 程式,而 10.5 中系統所有未廢棄的函式庫、框架都提供 64 位版本,到了 10.6,所有使用者空間的程式,包括 Unix 層和圖型介面層,基本都更新到 64 位。細心的讀者不禁會問—那核心是 64 位的嗎?是的,自下而上支援 64 位後,10.6 又從上往下,遷移了整個系統中最後一個也是最重要的部分—核心。

核心 64 位化的意義

對於 Windows、Linux,以及 FreeBSD 等作業系統,64位實現的第一步是實現 64 位的核心。然而 Mac OS X 卻反其道而行。主要原因是,反正 32 位的核心也能以非模擬、非相容的方式原生地執行 64 位使用者空間程式,而核心和與核心動態連結的驅動,很少需要用到 64 位的定址空間(你什麼時候見過核心本身使用 4GB 記憶體?),所以該問題可以暫緩。

但要記住,使用者空間的記憶體是由核心管理的,虛擬記憶體、記憶體分頁等機制,都是由核心一一實現的。一旦在不久的將來,隨著使用者空間的記憶體佔用越來越多,虛擬記憶體的分頁比也會不斷膨脹。比方說,一個使用者程式使用 4GB 的空間,每個分頁包含 4KB 的頁面,那麼總共有 1M 個頁面。因此,假設一個頁面需要 64B 的 PTE 來記錄該頁的位置,那總共也就需要 64MB 的核心空間來記錄這個使用者空間程式的虛擬記憶體,不算太多。而在不久的將來,如果一個 64 位使用者程式使用 128GB 的空間,則需要 32M 個頁面,每個頁面 64B 的 PTE 會導致 2GB 的核心地址空間來定址(暫不考慮大分頁)。32 位的核心就顯得非常緊張。

另外,上一期我們也提到 64 位的 Intel 架構提供了比 32 位多一倍的暫存器,因此,使用者空間程式對 64 位核心的系統呼叫也會更快。根據蘋果的資料,系統呼叫的響應速度比原先快了 250%,而使用者空間和核心空間的資料交換也快了 70%,因此,64位核心要比 32 位核心更快。

核心完成 64 位遷移

雖然在 Mac OS X 10.6 中,蘋果提供了 64 位模式執行的核心,但在大部分蘋果計算機上,這個特性並不預設啟用。其原因是,雖然 64 位程式和 32 位程式可以在計算機上同時執行,但 64 位的程式只可以載入 64 位的庫或外掛,32位程式只能載入 32 位的庫或外掛。因此,如果預設使用 64 位模式啟動,則諸多第三方的 32 位驅動或核心模組將無法使用。當然,使用者可以通過修改 com.apple.Boot.plist、nvram,或開機按住 6 和 4 強制載入 64 位核心,不過蘋果並不推薦這樣的方式。直到 Mac OS X 10.7 時,第三方核心擴充套件已趨完善,大部分的 Mac 才預設使用 64 位核心模式啟動。

蘋果用了整整 6 年的時間完成 64 位的遷移,在 2009 年 WWDC 的一個講座上,Bertrand Serlet 告訴開發者,我們這個 64 位技術的講座,只針對 Mac OS X,而 iPhone、iPad 等 iOS 裝置,由於使用 ARM 平臺,在可預見的未來可能並不會支援 64 位技術。

不過兩年之後的 2011 年 10 月 27 日,ARM v8 釋出,ARM 正式宣佈支援 64 位。未來會不會出現基於 ARM 的 Mac,或是 64 位的 iPad,除了蘋果,誰知道呢?

Mac OS X 背後的故事

Bertrand Serlet 在 WWDC 2009 上介紹 Snow Leopard 的 64 位和 Grand Central Dispatch 技術

GCD(Grand Central Dispatch) 來臨

很長一段時間以來,處理器靠更快的執行時鐘來獲得更高的效率。軟體開發者無需改動或重新編譯他們的程式碼,就能得到摩爾定律許諾他們的好處,因為處理器順序地執行計算機指令,新一代的處理器就自動會跑得比原先更快。後來每每達到一個技術極限時,總有一些聰明的方法繞過這些極限,比如超純量、指令管線化、快取等,不是悄無聲息地把多條互相獨立的指令同時執行,就是隱藏掉資料讀寫的延時。

GCD 出現的緣由

到了 21 世紀,能想的辦法基本都想盡了——現代處理器已經足夠並行了,也採取了各項優化來不斷提升各種預測器的準確率,而時脈頻率卻是不能無限提高的——提高時脈頻率會極大地增加處理器的產熱,使得伺服器機房或筆記本的散熱成為一個頭痛的問題。同時對於便攜裝置而言,高頻也意味著短得多的電池時間,因此摩爾定律正在經受重大的考驗。

因此大約在 21 世紀頭十年過掉一半時,“多核”處理器,終於開始躍入普通消費者的視線。“多核”顧名思義,就是把原先單核的半導體線路複製多份排於同一裸片上,每個核相互獨立,又能彼此通訊。多核處理器的出現,有效緩解了計算機處理器生產商的設計和製造壓力,從而達到忽悠消費者買更新款產品這一不可告人的目的。

但這一次技術革新,並不如之前那麼順利,因為程式並不會自動在多核系統上跑得更快,甚至有很多程式每一步都有前後依賴,不能高效地並行執行。即使能夠高效並行的程式,也需要大規模改寫才能充分利用多核所帶來的優勢。

傳統的併發程式設計模式,就是學習使用執行緒和鎖。這聽起來很簡單,幾句話能說明白:

● 把每個任務獨立成一個執行緒;

●不允許兩個執行緒同時改動某個變數,因此得把變數“鎖”起來;

●手動管理執行緒的先後併發順序和併發數量,讓它們均勻地佔滿系統資源;

●最好系統中只有這個程式在執行,否則你精心設計好的執行緒管理演算法往往不能達到原來該有的效果;

●最後祈禱程式在使用者那兒不出問題。

但是實際操作起來,多執行緒程式的編寫要比單執行緒難上不止一個數量級。一方面,呼叫大量記憶體和資料反覆的加解鎖本身效率就非常低下;另一個重要原因在於,由於多執行緒程式可能以任意的次序交錯執行,程式再也無法像順序執行時那樣產生確定的結果。多執行緒程式看似容易編寫,但難分析、難除錯,更容易出錯。即使是最熟練的開發者,在茫茫執行緒和鎖之間,也會迷失方向。且程式的錯誤在很多時候甚至是不可重現的。所以,程式設計師使用執行緒和鎖機制編寫並行程式的代價是很高的。

GCD 就是在這種背景下被蘋果提出來的。2008年最初提出但未公佈細節時,很多人懷疑它是 FreeBSD 的 ULE 排程器在 Mac OS X 上的實現。ULE 是 FreeBSD 當時最新的核心排程器,用來替換掉老一代的 4BSD 排程器,當時使 FreeBSD 上跑多執行緒程式的效率獲得了重大的效能提高,遠高於同期 Linux 和 Solaris 的演算法效率。但當時我就認為 GCD 依賴 FreeBSD 這項技術的可能性不大,因為 Mac OS X 中管理程式和執行緒主要用的是 Mach 而不是 BSD。不過後來證實我只猜對了一半,GCD 的實現,實際上是依賴於 FreeBSD 的另一項技術 kqueue。kqueue 是一個由 FreeBSD 4 時代引入的新功能,核心級別地支援訊息通訊管理。GCD 的佇列,其實就是用 kqueue 實現的。

GCD 出現的意義

在 GCD 中,開發者不再管理和建立執行緒,而是將要實現的運算抽象成一個個任務,一起扔給作業系統,轉而讓作業系統管理,這在電腦科學中,被稱為執行緒池管理模式

在 GCD 中,開發者使用很簡單的方式就能描述清應用程式所需執行的任務,以及任務之間的相互關聯。每一個任務在程式碼中被描述成塊(block),然後開發者把一個一個塊顯式地按順序扔到佇列(queue)中。使用塊和佇列兩個抽象的表述,開發者無須建立執行緒,也無須管理執行緒,更無須考慮資料的加解鎖。換之而來的,是更簡短可讀的程式碼。剩下的事,全都扔給作業系統去完成。

在作業系統那邊,GCD 在程式執行時,管理著一定數量的執行緒,執行緒的數量是自動分配的,取決於使用者計算機的配置和使用者程式執行時的負載。多核工作站每個程式配到的執行緒,自然就會比單核手機或雙核筆記本來得多。而且這個執行緒的數量是會動態變化的。當程式非常忙時,執行緒數會相應增多,而當程式閒置時,系統會自動減少其執行緒數量。然後,GCD 會一一從佇列中讀入需要執行的塊,然後扔到執行緒上併發執行。

相信讀者已經看出 GCD 和傳統執行緒-鎖機制的區別來了。傳統的方式按勞分配,強調程式自由獨立地管理,妄想通過“無形的手”把系統資源平均分配,走的是資本主義市場經濟的道路。而 GCD 按需分配,真正實現了社會主義計劃經濟管理模式。因此在政治上 GCD 就是一個代表先進生產力的計算機技術(我被自己雷了,但事實就是這樣)。

GCD 是一個自底向上的技術,它實際上由以下 6 個部分組成。

  1. 編譯器層面,LLVM 為 C、Objective-C 和 C++ 提供了塊語法,這個內容等下會介紹。
  2. 執行庫方面,有一個高效分配管理執行緒的執行庫 libdispatch。
  3. 核心方面,主要基於 XNU 核心 Mach 部分提供的 Mach semaphores 和 BSD 部分提供的 kqueue () 機制。
  4. dispatch/dispatch.h 提供了豐富的底層程式設計介面。
  5. 在 Cocoa 層面,NSOperation 被重寫,因為使用 libdispatch,所以先前使用 NSOperation 的程式不需改動,就自動享受 Grand Central Dispatch 的最新特性。
  6. Instruments 和 GDB 提供了非常完整的分析和除錯工具。

GCD 還有一些工程上的優勢。首先,程式的響應速度會更快。GCD 讓程式設計師更方便地寫多執行緒程式,因此寫一個多執行緒程式來實現前後臺簡單多了,極大改善了 Mac OS X 上應用程式的生態環境。而且 GCD 的程式碼塊佇列開銷很小,比傳統執行緒輕量得多。統計表明,傳統的 Mac OS X 上使用的 POSIX 執行緒需要數百個計算機彙編指令,佔用 512KB 的記憶體,而一個程式碼塊佇列才用 256 位元組的長度,把塊加入佇列,只需要 15 個計算機彙編指令,因此開成百上千個也不費什麼事。

其次,執行緒模式是一種靜態的模式,一旦程式被執行,其執行模式就被固定下來了。但使用者的計算機配置各不相同,執行時別的程式有可能耗用大量的計算資源。這些都會影響該程式的執行效率。而動態分配系統資源則能很好地解決這個問題。蘋果自然也是不遺餘力地忽悠開發者使用 GCD,因為各個軟體共享多核運算的資源,如果 GCD 被更多的開發者採用,整個蘋果平臺的生態也就更健康。

而最重要的,還是 GCD 採用的執行緒池模式極大簡化了多執行緒程式設計,也降低了出錯的可能性。著名 FreeBSD 開發者 Robert Watson 還發布了一個他修改過的 Apache,並釋出了補丁,聲稱只需原先 1/3 至 1/2 的程式碼量,就實現了原先的多執行緒模組,並比原先的效率更好。

如何應用 GCD

當然,老王賣瓜,自賣自誇,沒有實際的例子,是不能讓讀者信服的。下面我們就來簡單講解 GCD 的技術。

首先是塊狀語法,是一個對 C、C++ 和 Objective-C 語言的擴充套件。用來描述一個任務,用^引導的大括號括起來。比如最簡單的:

則 x 就變成了一個塊。如果執行:

那麼程式會列印 hello world 出來。當然,blcok 像函式一樣,可以跟引數,比如:

這裡 MyBlock 是一個帶引數的程式碼塊。

Mac OS X 背後的故事

讀者看到這裡不禁要問,塊到底有什麼好處?它和 C 的函式指標有什麼不同?我們依然用上面的例子來說明問題,雖然後面我們把 spec 變數改為 0,但事實上在 MyBlock 創立時,已經生成了一個閉包,因此它最後輸出的結果,仍是 16,不受 spec 值改動的影響。這對於搞函數語言程式設計的人來說再熟悉不過了,因此很多開發者親切地稱呼塊語法的 C 擴充套件為“帶 lambda 的C”。

有了閉包功能的 C 頓時牛起來——你可以把函式和資料包裝在一起——這就是塊的真正功能。因為只要一個閉包包含了程式碼和資料,它的資料就不會被別的閉包輕易改動,所以在它執行時,你根本不用為資料上鎖解鎖。

有了一系列的程式碼塊後,接下來的事是把程式碼塊扔到佇列裡。比如最簡單的:

dispatch_queue_t queue = dispatch_get_global_queue (0,0);

來建立一個輕量級的佇列,然後

dispatch_async (queue,

^{printf (“hello world\n”);});

那這個程式碼塊就被扔進 queue 這個佇列中了。你可以手動依次新增任意多個專案,比如“帶著老婆”、“出了城”、“吃著火鍋”、“唱著歌”、“突然就被麻匪劫了”等。當然在更多的場合,你會更傾向於使用自動事件源,每當一個事件觸發時(比如定時器到點、網路傳來包裹,或者使用者點選了按鈕),相應的程式碼塊被自動新增到佇列中。

Mac OS X 背後的故事

 

一旦佇列不是空的,GCD 就開始分配任務到執行緒中。拿上面的例子來說,“老婆”、“城”等變數可是封在閉包裡的,所以在執行時,不用考慮它們被某個別的閉包改掉(當然也有方法來實現這個功能)。總體而言,這個模式比執行緒-鎖模型簡單太多——它的執行是並行的,但思維卻是傳統的非同步思維,對沒有學習過系統多執行緒程式設計的開發者來說,依然能很容易地掌握。

讀者可能要問,如果閉包之間有複雜的依賴關係,需要申明某兩個操作必須同步或非同步怎麼辦?比如“出了城”必須在“吃著火鍋”之前。在 GCD 中,可以使用 dispatch_async 和 dispatch_sync 來描述這樣的依賴關係,而在 Cocoa 層面,NSOperation 中的佇列依賴關係甚至可以被描述成有向圖。

GCD 得到廣泛應用

GCD 一經推出就得到了廣泛的應用。蘋果自家的軟體 Final Cut Pro X、Mail 等軟體,都採用 GCD 來實現任務併發和排程,因此 Mac OS X 10.6 成為了有史以來最快的發行版。從 iOS 4 開始,iPhone 和 iPad 也加入了 GCD 的支援。更別提原來使用 Cocoa 的 NSOperation 相關介面的程式,無需改動即享受 GCD 的優惠。

GCD 在 Mac OS X 10.6 釋出後,又以 libdispatch 為名,作為一個獨立的開源專案釋出。 所需的外圍程式碼,如編譯器的塊支援、執行庫的塊支援、核心的支援,也都能在 LLVM 和 XNU 等開源專案程式碼中找到,所以很快被別的作業系統採用。作為 Mac OS X 的近親, FreeBSD 在一個月後即完整移植了整套 GCD 技術,並最終在 FreeBSD 9.0 和 8.1 中出現。諸多 Linux 發行版也提供 libdispatch 的包,使用 Linux 核心的 epoll 來模擬 FreeBSD 的 kqueue。2011年 5 月 5 日, Windows 的移植工作也宣告完成

另外,GCD 也成為拯救動態語言的重要法寶。由於受 GIL(全域性解釋鎖)的限制,動態語言雖然有作業系統原生執行緒,但不能在多核處理器上並行執行。而 GCD 成功繞開了這個限制,如加入 GCD 支援的 Ruby 實現 MacRuby 就能在多核處理器上高效執行。 因此,在蘋果生態圈以外,GCD 也會得到越來越多的應用。

半導體的豐收(下)

隨著 CPU 與 GPU 合併成技術發展的趨勢,蘋果開發出了 OpenCL 框架,能夠進行高速並行處理的能力使 OpenCL 成為了業界標準,被廣泛應用。

最近幾年,GPU 的發展吸引了很多來自科學計算界人士的目光。GPU 有穩定的市場推動力——公眾喜聞樂見的電子遊戲產生了源源不斷的升級 GPU 的需求——因此比 CPU 的更新步伐更快。從技術上講,GPU 本身就是多核架構,高階顯示卡往往有五百多個核心,即使低端的整合 GPU 也有二三十個核心,所以能夠通過並行來高效處理成千上萬的執行緒。同時,對於科學技算中的浮點計算,GPU 往往通過硬體加速使其效率比傳統 CPU 更高,因為圖形渲染等工作基本都是浮點計算。

GPGPU 浮出水面

早期的 GPU 只能執行固定的程式,而不開放給程式設計師程式設計。隨著時代的發展,影像處理有時需要對著色器進行程式設計以實現一些特效,因此需要程式設計師可以使用 GPU 的組合語言寫簡單的著色程式。這自然對程式設計師要求過高,所以一些高階的著色語言又被 GPU 廠商開發出來。比如微軟和 NVIDIA 共同開發的 Cg 語言,就能為頂點和畫素編寫專門的著色程式。這類技術雖然面向圖形渲染工作者,卻吸引了一小簇科學計算研究者的興趣。以計算流體力學為例,它是用納維斯托克斯方程【注:把牛頓第二定律和質量守恆應用到流體後,所得到的偏微分方程】來求解流體力學問題的一種演算法,廣泛用於天氣預報、F1 方程式賽車設計等工程領域。同時,對於電影製片特效,計算流體力學也是最基本的用來模擬流體流動特放的演算法,皮克斯動畫工作室的《尋找尼莫》中的海洋流動和水花等,都是使用納維斯托克斯方程來模擬的。

首先,對於一個幾何空間進行網格化,每個網格中的流體,都可以列出納維斯托克斯方程,把這些方程聯立起來進行求解,即可得到各點的溫度、壓力、溼度、速度等流體資訊。整個求解過程可以高度並行,因為每個網格的控制方程是完全一樣的;同時也牽涉大量的浮點運算。但 Cg 這類語言並非面向普通的計算,其變數都是顏色、頂點、畫素等圖形學專用變數。來自北卡羅萊那大學教堂山分校的 Mark Harris 突發奇想:可以把流體力學中每個網格的速度、壓力等變數,存成 RGBA 顏色後讓 Cg 去處理,所以他在《GPU Gems》中著名的一章,公佈了使用 Cg 來高速實現計算流體力學運算的成果,吸引了大量計算界的目光。然而,這種程式設計模式對科技工作者來說很不友好,因為這要求一個學力學的、學生物的、學化學的學生,先要明白複雜的 GPU 渲染原理,瞭解圖形學中材質、頂點、合成、畫素、光柵化、光線跟蹤等深奧的理論,才能編寫他們專業相關的 GPU 程式。

GPU 生產廠商洞察到了 GPU 高速並行浮點數運算的潛力,所以 GPGPU(General Purposed Graphics Processing Unit)概念終於浮出水面。一方面 GPU 設計一代比一代可程式設計化,另一方面各公司也在加緊研製新一代 GPU 程式語言。新一代的語言對比 Cg,去掉了對於渲染相關的知識要求,獨立於圖形學之外,是純粹的普通語言,比如變數不再是畫素、頂點、面等型別,而是 C/C++ 語言開發者喜聞樂見的浮點陣列、整形陣列等。這一時期為代表的語言,主要是 CUDA(Compute Unified Device Architecture)。CUDA 是 NVIDIA 在 2007 年公佈的一項面對科學計算工作者的程式設計框架。通過該技術,使用者可利用 NVIDIA 的 GeForce 8 以後的 GPU 和較新的 Quadro GPU 進行高效能程式設計。使用者先編寫一個特殊的 C++ 程式碼檔案,副檔名為 cu,檔案中需要申明建立的變數、GPU 計算核心(kernel)以及使用給定的程式設計介面來實現變數在 CPU 和 GPU 中的傳送。然後通過 NVIDIA 自家的編譯器編譯這個程式碼,連結到 NVIDIA 自家的庫上,即可把該運算核心編譯為 GPU 彙編語句扔到特定型號的 GPU 上高度執行。其他廠家也緊隨其後,比如 AMD 為 ATI 生產的 GPU 卡提供了一個類似的框架叫 Stream SDK(先前被命名為 CTM, Close to Metal, ATI Stream Computing – Technical Overview, 03/20/2009 http://en.wikipedia.org/wiki/Close_to_Metal)。而微軟更是趁 Vista 和 Win7 推出了DirectCompute,作為旗下 DirectX 技術的一部分。

CUDA 並不完美

對科學工作者來說,CUDA 比 Cg 友好太多。使用 CUDA 加速流體力學運算相關的論文更是雨後春筍般湧現。然而不久後,我發現它存在許多問題。

首先,對初學者來說,CUDA 程式設計模式很容易學混。因為一個 GPU 陣列和一個 CPU 陣列在 CUDA 中的表述都是同樣的C指標,但對於 GPU 陣列和 CPU 陣列,CUDA 的處理模式完全不同,CPU 陣列使用常規的 malloc 來初始化,而 GPU 陣列得使用 CUDA 提供的 malloc。所以程式寫著寫著,就忘了一個變數到底是給 CPU 用的還是給 GPU 用的,這無疑增加了學習難度。同時,CUDA 對 C/C++ 語言進行了一系列擴充套件,這不但意味著寫的程式不再具有 C/C++ 那樣良好的可移植性,而且這種計算核心和傳統 C 程式混寫的程式語言很不美觀。

其次,CUDA 這類語言的實現各自為政。如果你寫了一個 CUDA 程式,就意味著這個程式碼只能執行在 NVIDIA 的顯示卡上。如果想使用 ATI 的顯示卡呢?沒門,請用 ATI Stream SDK 重寫。

再次,CUDA 是在編譯時就靜態產生 GPU 程式碼的,所以只能產生特定的 GPU 程式碼。如果你釋出了一個 CUDA 程式,它僅對某幾種 NVIDIA 顯示卡進行特定的程式碼優化。如果 NVIDIA 自家出了一種新顯示卡,很抱歉,哪怕新顯示卡可能相容老顯示卡的彙編指令而你的程式恰巧可以在新顯示卡上跑起來,你也無法發揮新顯示卡的所有特性。必須用針對新顯示卡的編譯器重新編譯原始碼,才能夠保證程式在新顯示卡上高效執行。

最後,CUDA 這類語言僅能產生高效的 GPU 程式碼,而無法產生 CPU 程式碼,即:寫完的程式碼只能跑在 GPU 上,在 CPU 上只能“模擬執行”,僅供除錯用。所以在一臺不具備給定 GPU 的機器上,無法高效執行 CUDA 程式。同樣,如果你有一個效能很強的工作站,那麼你的 CPU 亳無用處——CUDA 不可能分配一部分任務給 CPU 完成。

另外還有未來計算機架構的不確定性。當時,GPU 越來越一般化,可以跑多種數值計算程式,而 CPU 隨著多核成為主流也越來越像 GPU。所以很多廠家在考慮 CPU 和 GPU 合併的可能性。

當時轟動一時的熱門事件,是 CPU 廠商 AMD 買下了 GPU 廠商 ATI,來開發下一代處理器 AMD Fusion,把 GPU 和 CPU 合併到一起。Intel 自然不甘示弱,做出了 Nehalem 平臺,在該平臺上,CPU 和整合 GPU 處於同一個包裝中,外界一度猜測這樣可使合併後的 CPU 具有圖形處理工能,從而使用者購置計算機就不用再考慮配一塊 GPU 了。

更強大的是,當時 Intel 還公佈了 Larrabee 計劃,讓 GPU 支援 x86 指令,使得一個常規的 x86 平臺的程式不需要修改和重新編譯便可在 GPU 上執行。

雖然事實和這些預期有稍許出入,但當時的技術趨勢是:在將來可能出現一種新的合併 GPU/CPU 的技術,能夠並行高速地執行一般的計算機程式,而面對這樣新的可能的平臺,我們如何準備?

OpenCL 誕生

OpenCL 則是蘋果為這個新局面畫下的藍圖。這項技術初期全稱為 Open Computing Library(如果留意蘋果早期宣傳廣告的話),後改名為 Open Computing Language。這項技術從本質上來說,和 CUDA 並沒有太多的兩樣,但由於蘋果在借鑑他人技術並把他人技術改得更棒這一點上是出了名的,所以 OpenCL 很好地解決了以上所有問題。

下面簡單介紹一下這個框架。OpenCL 技術的結構十分清晰,對程式設計師來說,它是一個 Mac OS X 的 Framework,定義了兩套標準,一套是一個 C 語言的程式設計介面(API),使得開發者建立、拷貝、回收 GPU 使用的物件,同時也包含檢測處理器、為該處理器編譯並呼叫核心程式(kernel)相關的介面;另一套是 OpenCL 核心程式語言的定義,是一套基於 C99 發展而來的語言。

例如我們有兩個大陣列,1024 維的 a 和 1024 維的 b(當然,1024不算大,OpenCL 往往用來處理十萬、百萬數量級的任務),我們把兩個陣列對應的元素加和,結果是一個 1024 維的陣列c。C 程式設計師很容易能寫出下面的程式:

OpenCL 的核心程式,則是取每個獨立的可並行的迴圈分支,即上面程式中的 c[i]=a[i]+b[i]。所以核心程式大概是下面這樣:

其中,get_global_id () 函式可以返回當前函式是全域性中的第幾個元素。把該程式儲存為 add.cl,就是一個 OpenCL 的核心程式,為 C99 語言的一個子集。

使用 OpenCL 的 API 就能呼叫這個核心程式。每個 OpenCL 程式基本上是模式化地照搬下面流程:

1. 探測硬體(用 clGetDeviceIDs 函式護取計算裝置(可以指定使用 GPU 或是 CPU),用 clCreateContext 函式來新建一個上下文(context),用 clCreateCommandQueue 函式針對裝置和上下文新建一個命令佇列);

2. 編譯核心(讀入 add.cl,用 clCreateProgram-WithSource 和 clBuildProgram 以及 clCreateKernel 來編譯讀進來的字串,產生一個核心程式);

3. 寫入陣列(用 clCreateBuffer 建立a、b、c三個記憶體物件,用 clEnqueueWriteBuffer 把 C 陣列寫到記憶體物件中);

4. 執行核心(把記憶體物件作為核心程式函式的輸入引數執行這個核心,程式會併發為 1024 個執行緒,每個執行緒執行一次相應的加法運算);

5. 讀出結果(用 clEnqueueReadBuffer 讀取c記憶體對向,寫為C的陣列);

6. 回收記憶體。

OpenCL 之美

讓我們逐條來看前面那些問題是如何被解決的。

首先,OpenCL Framework 由 C API 和 OpenCL 語言組成,涇渭分明,所有的 GPU 變數在 C API 中,都是記憶體物件的形式出現,有別於 C 自建的陣列。因此,你永遠不會搞混兩者。同理,OpenCL 核心程式是獨立在 C 源程式之外的,不僅美觀,也能保證你的 C 程式能被所有 C 編譯器編譯,因為呼叫 OpenCL 庫和呼叫其他 C 的函式庫沒有任何不同。

其次,蘋果開發出 OpenCL 後,覺得該技術甚好,索性聯合 AMD、ARM、ATI、TI、Intel、IBM、Nokia 等公司,把它做成一個由 Khronos 組織主持的開放標準。不管電腦上用的顯示卡是 ATI 的還是 NVIDIA 的,OpenCL 都能像 OpenGL 那樣在你的裝置上無縫執行。事實上,OpenCL 已同 OpenAL 和 OpenGL 一樣,成為 Khronos Group 旗下的三大業界標準。

再次,CUDA 是在編譯時就靜態產生 GPU 程式碼的,所以只能產生特定的 GPU 程式碼。而 OpenCL 的核心程式(kernel)是在執行時被編譯成 GPU 指令的。由於 kernel 所用的 OpenCL 語言,僅是 C99 的一個子集,所以負責編譯這個程式的是 OpenCL 執行庫自帶的 LLVM-Clang。這樣做的好處是明顯的,舉例來說,如果使用者有一堆 OpenCL 的程式,比如蘋果最新的 Final Cut Pro X 就在許多地方採用了 OpenCL,如果某一天硬體廠商釋出了一個全新的 GPU 架構,那麼使用者安裝顯示卡後,只要下載或更新相關的驅動程式和執行庫即可,而不需要再求軟體廠商釋出一個新版本的 Final Cut Pro X。因為 OpenCL 在執行時,會根據顯示卡廠商提供的驅動和新執行庫自動優化程式到特定架構上。所以,程式相容性問題也被圓滿解決。

最後,由於 OpenCL 是個開放標準,也支援 CPU 和其他任何計算裝置,比如數字訊號處理晶片(DSPs)和各種專門的處理器架構。所以只要有相關的驅動和執行庫,OpenCL 程式可以高效地並行執行在任何架構的運算裝置上。由於 OpenCL 和 GCD 的程式設計模式是一樣的,因此當 OpenCL 程式在 CPU 上執行時,是跑在 GCD 佇列上的。

由於 OpenCL 能高速地進行並行處理(如 http://macresearch.org/opencl_episode1 的演示,OpenCL 編寫的 GPU 程式比單核 CPU 能快上數十至數百倍,筆者的論文 Yue Wang, Ali Malkawi, Yun Yi, Implementing CFD (Computational Fluid Dynamics) in OpenCL for Building Simulation, 12th Conference of International Building Performance Simulation Association, 2011 也得出了類似的結論),OpenCL 被廣泛地使用在很多產品中,蘋果也是 OpenCL 的主要使用者之一。如上面提到的 Final Cut Pro X 就是個典範,使用 GCD 和 OpenCL 進行大量並行的流媒體處理。在老版本 Final Cut 中,每當使用者執行一次流媒體操作,都會彈出一個進度條來告訴使用者剩餘的處理時間,而 Final Cut Pro X 優化後的速度是如此實時,以至於這個進度條被去除了。Mac OS X 許多的底層庫也使用 OpenCL 重寫,如 Core Image,本身也是一個 GPU 加速庫,使用 OpenCL 後相比原來,依然獲得了可觀的效能提升

Snow Leopard 的釋出標誌著第一個 OpenCL 框架的完整實現,OpenCL 成為業界標準後,AMD 拋棄了原先的策略,投入開放標準的懷抱,一連放出了幾個測試版本的整合 OpenCL 的 ATI Stream SDK,並在 2009 年年底釋出了穩定版,2011年 8 月 8 日宣佈廢除原先的 Close to Metal 相關技術。NVIDIA 也是早早地在 CUDA SDK 中加入了 OpenCL 相關的庫。CUDA 越來越不被看好,所以 NVIDIA 索性把 CUDA 釋出為一個開源專案,並把 CUDA 架構在 LLVM 之上。這和 OpenCL 近幾年的走強有很大關係。

開發者的瓶頸

目前看來,OpenCL 雖然解決了上面的所有問題且速度飛快,但對普通程式設計師來說,依然是非常底層的技術。而且由於硬體的限制(顯示卡不支援指標運算),很多 C 的標準並未在 OpenCL 中出現,寫連結串列還需要用整數去模擬地址。程式設計師需要手動管理記憶體,處理底層的核心呼叫以及資料讀寫。而顯示卡廠商也大多不願公開 GPU 的技術細節,因此不像 CPU 程式很容易通過彙編指令分析計算機底層幹了什麼,顯示卡對於開發者純粹是個黑盒,把整個問題分成多少個執行緒併發也沒有一個規律可循,有可能不起眼的改動會使程式執行瞬間變快或變慢數十倍,開發者也不知道其中的原因,只能憑經驗操作。而且由於不存在良好的除錯工具,所以很難改正程式的錯誤。

顯示卡作為系統最為重要的共享資源之一,不像現代作業系統那樣提供記憶體保護機制,因此一個使用者 OpenCL 程式的錯誤很容易導致整個計算機崩潰,所以經常是程式跑一遍後發現作業系統掛了,重啟後發現了一個可能的錯誤,改完後編譯執行,作業系統又掛了。我用 OpenCL 編寫科學計算程式時,大量時間是在重啟電腦而不是寫程式。這些問題仍然阻礙著 OpenCL 被廣泛採納,不過,在科學計算界,已經湧現出了越來越多相關的論文和技術,相信在不久的將來,情況會有所改觀。

結語

當寫完這篇技術長文時,天色已晚,走出教室,和 ENIAC 擦肩而過。ENIAC 的出現激勵了之後一次次的處理器革命。2009 年釋出的 Snow Leopard 可能在整個 Mac OS X 發行版歷史中不算最出彩,卻是對於半導體積體電路革命的一次重大收穫。

Mac OS X背後的故事(十)Mac OS X 檔案系統的來龍去脈

(上)

HFS+ 和 UFS 檔案系統同時被引入早期的 Mac OS X,隨著若干年的發展,HFS+ 提供的功能已超越 UFS,使其在 Mac OS X 10.5 之後成為成為唯一正式的 Mac OS X 系統,但因為其揹負許多的歷史包袱,為考慮相容性,這些陳舊的設計並不能被推翻重來,所以蘋果開始祕密研發下一代的檔案系統。

Mac OS X 背後的故事

著名 BSD 開發者 Marshall Kirk McKusick

UFS:經典的 Unix 檔案系統

在 Unix 系統剛誕生的遠古時期,檔案系統被簡單地稱為 FS。FS 只包括啟動塊、超級塊(處於硬碟分割槽開頭用來儲存檔案系統資訊)、inodes(索引節點)及資料。FS 檔案系統在 Unix 系統剛誕生時還能滿足新老客戶的需求,但隨著科學技術的進步,FS 已不能符合現代檔案系統的需求,且會導致抖動等一系列問題。當時還是加州大學伯克利分校研究生,後成為著名 BSD 開發者 Marshall Kirk McKusick 在 BSD 4.1b 上承接傳統的 FS 檔案系統實現了 FFS(Fast File System),妥善地解決了這一難題,把先前整塊的磁碟檔案系統分為小塊,每塊包含自已的索引節點和資料,因而增加了檔案的區域性性,減少了尋道時間。由於 Marshall Kirk McKusick 的 FFS 檔案系統很好很強大,所以立即被各大 Unix 系統所使用。SunOS/Solaris、System V Release 4、HP-UX 及 Tru64 UNIX 都使用它,也成為當今各 BSD 分支(FreeBSD、OpenBSD、NetBSD 及 DragonFlyBSD)的標準檔案系統。每個不同的系統,無論開源與否,又會在 FFS 檔案系統上增加各種擴充套件,這些擴充套件往往不互相相容,但神奇的是,大家又都使用和原版同樣的塊大小和資料塊寬度。因此在很大程度上,這些山寨版 FFS 檔案系統又相互相容,至少在一個作業系統上能對另一作業系統的檔案系統執行只讀操作。因此,FFS 事實上已經成為 Unix 系統的標準檔案系統,故它有了一個更廣泛的稱謂——UFS(Unix File System,即 Unix 檔案系統)。

UFS 在後來的若干年又取得了長足的發展。Sun 公司在 Solaris 7 系統中,給 UFS 提供了簡單的日誌功能。日誌檔案系統指在檔案系統發生變化時,先把相關的資訊寫入一個被稱為日誌的區域,然後再把變化寫入主檔案系統的檔案系統。在檔案系統發生故障(如核心崩潰或突然停電)時,日誌檔案系統更容易保持一致性,並且可以較快恢復。Marshall Kirk McKusick 又實現了 BSD 一度引以為豪的 Soft Update功能,來保證計算機掉電或系統崩潰時,通過使後設資料按依賴順序更新來確保磁碟上總的檔案系統保持一致的實現機制。Soft Update 的目標和日誌類似,但實現代價比日誌輕量許多。不過這項功能有所代價,主要是需要引入一個後臺 FSCK 檢查。

2009 年,Jeff Roberson 正式發表了對 UFS 的一項改進,為 Soft Update 加入了日誌功能,並消除了對 FSCK 的依賴,這項改進最終整合進了 FreeBSD 9 中。TrustedBSD 專案又為 BSD 分支的檔案系統設計了 ACL 訪問控制表功能(Access Control Lists)。先前,Unix 檔案系統的訪問控制是非常簡單的,其許可權管理分為三個不同的類別:使用者、同組使用者以及其他使用者,對每個類別,Unix 檔案系統提供讀、寫、執行三種許可權的管理。這樣的許可管理過於粗糙,無法指定某一使用者訪問的許可權,也無法指定更為細緻的許可權內容(例如准許對一檔案實行刪除操作)。為解決這個問題,訪問控制表被增加到檔案系統中,使用以存取控制矩陣為基礎的存取控制方法。存取控制串列描述每一個檔案物件各自的存取控制,並記錄可對此物件進行存取的所有主體對物件的許可權。總之,UFS 與時俱進,不斷增加新的功能。

HFS+:更現代的 HFS

作為 Mac OS X 的老祖宗 NeXTSTEP,因為基於 BSD,所以自然也使用 UFS。而老版的 Mac OS 則使用一個叫做 HFS 的檔案系統。HFS 是一個比較古老且不思進取的檔案系統,因此,在 20 世紀 90 年代末已不能滿足當時的需要。在《Mac OS X 背後的故事(一)》中我們提到,為了實現 Mac OS 的現代化,Copland 專案被提出。Copland 專案的子專案 Sequoia 旨在 HFS 的基礎上,加入現代檔案系統所必需的新功能,如大檔案支援、Unicode 檔名支援、長檔名支援、32 位檔案對映表支援等。Sequoia 專案即成為後來熟知的 HFS+,由 Don Brady 領導,這個團隊先花了 6 個月時間把 HFS 專案原本的 Mac 使用的 68K 處理器彙編碼改寫成 C 程式碼,然後逐漸加入新功能

後來由於 Copland 被力挽狂瀾的 Ellen Hancock 給廢了,所以一些有用的更新,如 HFS+ 即被整合到 Mac OS 8.1 中。在 Mac OS X 誕生初期,HFS+ 和 UFS 檔案系統同時被引入早期的 Mac OS X 中。不過由於 HFS+ 根植 Mac OS,缺乏 Unix 檔案系統所必需的功能,如符號連結、硬連結及其他各種 POSIX 相容性,所以 HFS+ 開發組又花了一些工夫在不影響和 Mac OS 相容性的情況下引入了這些功能。由於 HFS+ 是對 HFS 的擴充套件,故 HFS+ 支援 Mac OS 至 Mac OS X 的平滑過渡,所以 Mac OS X 一直預設使用 HFS+。但當時的 UFS 提供比 HFS+ 更先進的功能,因此 Mac OS X 10.0 至 10.4,也都支援把系統安裝在 UFS 系統上。

Mac OS X 10.0 釋出後,蘋果不遺餘力地對 HFS+ 進行大規模的擴充套件和維護,增加了很多 UFS 獨有的功能。這些新功能使得檔案系統更加安全穩定可靠。例如 Mac OS X 10.2.2 中,HFS+ 支援日誌。日誌功能在 Mac OS X 10.2 伺服器版中可以簡單地設定,但在普通桌面版中需要使用命令列進行操作。在 Mac OS X 10.3 中,帶日誌功能的 HFS+(被稱為 HFSJ,即 HFS+ volume with journal)成為預設設定。Mac OS X 10.3 亦增加檔名、目錄名區分大小寫及 Unicode 3.2 的支援。Mac OS X 10.4 中,HFS+ 更是增加了 ACL 訪問控制表功能,提供更復雜的對傳統 Unix 檔案系統許可權的擴充套件。

檔案系統除了讓使用者供穩定地存放檔案這一目標以外,還是各項作業系統功能的基礎。Mac OS X 每個大發行版都要增加數百項新功能,許多新功能嚴重依賴於檔案系統的實現。Mac OS X 10.3 提供了FileVault 來加密使用者檔案,因此使用者主目錄被儲存在一個 HFS+ 檔案系統加密映象中。Mac OS X 10.4 提供了系統內建的 Spotlight 桌面搜尋搜尋功能,能讓使用者對整個磁碟系統進行快速搜尋、隨打即顯。這項功能要求檔案系統提供任意長度檔案後設資料(metadata)的支援。Mac OS X 10.4 轉向了對 Intel 處理器的支援,因此蘋果釋出了一個測試版本的 BootCamp 來讓使用者安裝 Mac OS X、Windows 雙系統,並在 Mac OS X 10.5 正式整合進系統。

哪怕在 Mac OS X 系統執行,BootCamp 也可以實時調整系統主分割槽的大小,來空出磁碟空間給 Windows,因此,HFS+ 又需要支援動態分割槽大小調整。在 Mac OS X 10.5 中整合了 Time Machine,它是蘋果公司所推出備份的工具程式,於 2006 年 8 月 7 日在蘋果計算機全球研發者大會(WWDC)中首次公開,成為當天觀眾歡呼聲最高的功能。Time Machine 對於修改過的檔案會在備份盤上儲存一個新拷貝,而對於不變的內容,僅在備份盤上存一個指向先前檔案的硬連結。因此每一次快照只儲存改動的檔案,而別的檔案只儲存佔用空間很少的硬連結。但 Unix 一般只支援檔案的硬連結而不支援目錄的硬連結。因此 HFS+ 在這點上走得比 Unix 檔案系統更遠,提供了對於目錄的硬連結支援。在 Mac OS X 10.6 中,HFS+ 甚至支援檔案系統壓縮,使得安裝後佔用比 Mac OS X 10.5 少得多的空間。Mac OS X 10.7 提出了 FileVault2,能加密整個磁碟而不是一個使用者目錄。這些功能我們在為讀者介紹每個發行版時亦會提到,但總之讀者看到,HFS+ 的功能隨著 Mac OS X 的商業需求不斷被擴充套件。“我在做了這麼多工作後回想才發現,我們為 HFS+ 增加了那麼多新功能,”蘋果前檔案系統開發者 Don Brady 如是說。

由於 HFS+ 經過後來若干年的發展,提供的功能已不遜於 UFS,甚至更多更好,故至 Mac OS X 10.5 砍掉了安裝至 UFS 的支援。HFS+ 成為唯一正式的 Mac OS X 系統。

HFS+ 並不完美

HFS+ 自發布以來,幾乎每個發行版都有令人欣喜的改動。它也逐漸成為一個非常完善的檔案系統。但 HFS+ 立足於 HFS 設計,HFS 已有 27 年的歷史,HFS+ 亦有 14 年曆史。這個檔案系統有太多的歷史包袱,為考慮相容性,這些陳舊的設計並不能被推翻重來。

HFS+ 基於B-樹實現,當查詢B-樹中未使用的節點時,HFS+ 只能每次處理 16 位,原因是老 Mac 使用的 Motorola 的 68K 晶片原生支援 16 位的資料操作。但不管是 PowerPC 還是 Intel,暫存器都支援 256 位寬的暫存器。

HFS+ 的後設資料(metadata)都以大位元組序儲存,原因是 Motorola 的 68k 和後來 Mac 使用的 PowerPC 都使用大位元組序。但經過 Intel 遷移後,當今的 Mac 都使用 Intel 晶片,而 Intel 晶片是使用小位元組序的。因此每當資料讀取或存入時,還要經過小位元組序和大位元組序的轉換。遠古時期磁碟很慢,計算機處理器的速度也很低,因此進行一次磁碟操作會佔用較多的時間,HFS+ 的時間解析度為一秒,但當今的磁碟、處理器處理一次檔案系統操作的時間遠小於一秒,因此所有主流磁碟檔案系統的時間解析度都是一至數百納秒級別的。

HFS+ 的後設資料有全域性鎖,同一時間只有一個程式可以訪問更新檔案系統。在單核處理器連手機平板都較少見到的當今,這種設計顯得很幼稚。

HFS+ 亦沒有稀疏檔案的支援。例如我們在 SQL 中建立了一個資料庫,SQL 分配了 10GB 的檔案給這個資料庫,並且在檔案頭和檔案尾寫上一些位元組的資料。而由於我們還沒有給這個資料庫新增新的資料,所以這 10GB 的檔案除了頭尾外其他位元組都為0。現代的檔案系統基本都支援稀疏檔案,也就是說,當處理這個資料庫操作時,事實上往磁碟寫入的資料只有那檔案頭和檔案尾的若干位元組。而 HFS+ 則需要把那些 0 也寫上,因此會完整寫入 10GB 的資料,耗費長得多的時間。

此外,HFS+ 不具備後設資料校驗功能、快照功能、寫入時複製功能、就地執行功能邏輯卷管理功能等很多現代磁碟系統所具備的功能,也不能動態調整檔案塊大小。這些功能的加入並不容易。

其中最要命的是,HFS+ 不像一些先進的檔案系統,支援寫入時複製事務模型,也沒有快照和克隆。這使得使用者資料時時處於風險之中。例如由於因為斷電、核心崩潰等原因,檔案系統上寫到一半的資料,小則導致個別檔案損壞,大則導致整個檔案系統崩潰。在生產領域,這樣不可靠的檔案系統,很有可能帶來致命的災難。

正是由於上述這些原因,連我們介紹過的短視的 Linus Torvalds 都認為 HFS+ 是個垃圾檔案系統。蘋果自然受不了這種侮辱,因此,幹掉 HFS+ 勢在必行。用什麼取代 HFS+ 呢?蘋果開始祕密研發下一代的檔案系統。

(下)

由於各種缺點,幹掉 HFS+ 勢在必行,然而用什麼取代 HFS+ 呢?蘋果開始祕密研發下一代的檔案系統——ZFS,然而在諸多因素的干擾下,Mac OS X 的 ZFS 支援卻只是曇花一現,未來檔案系統之路將走向何方?

檔案系統的新時代——ZFS

為了代替 HFS+,蘋果開始為研發下一代檔案系統招兵買馬,準備大幹一場。但這時 Sun 公司的工作讓蘋果的員工們為之一振。

2004 年,Sun 公司發表了其傑出的檔案系統ZFS。這是一個 128 位的檔案系統,本為 Solaris 作業系統開發,於 2005 年 10 月 31 日併入了 Solaris開發的主幹原始碼。後成為一個使用 CDDL 協議條款授權的開源專案。

ZFS 是一個具有高儲存容量、檔案系統與卷管理概念整合、嶄新的磁碟邏輯結構的輕量級檔案系統,同時也是一個便捷的儲存池管理系統。

ZFS 的一個重大特點就是擁有大容量。ZFS 是一個 128 位的檔案系統,這意味著它能儲存 1800 億億(18.4×1018)倍於當前 64 位檔案系統的資料。ZFS 的設計如此超前以至於這個極限就當前現實而言可能永遠無法遇到。專案領導 Bonwick 曾說:“要填滿一個 128 位的檔案系統,將耗盡地球上所有儲存裝置,除非你擁有煮沸整個海洋的能量。”假設每秒鐘建立 1000 個新檔案,達到 ZFS 檔案數的極限需要約 9000 年。

此外,ZFS 的一個重要指導思想是不單單去做一個檔案系統,而是實現一套完整的卷管理方案。不同於傳統檔案系統需要駐留於單獨裝置或者需要一個卷管理系統去使用一個以上的裝置,ZFS 建立在虛擬的被稱為“zpools”的儲存池之上。每個儲存池由若干虛擬裝置組成。這些虛擬裝置可以是原始磁碟,也可能是一 RAID1 映象裝置,或是非標準 RAID 等級的多磁碟組。於是 zpool 上的檔案系統可以使用這些虛擬裝置的總儲存容量。

有了卷管理方案後,ZFS 走得更遠,加入了快照和克隆等實用的檔案系統功能。當 ZFS 寫新資料時,包含舊資料的塊被保留,磁碟只寫入修改過的那部分資料塊。所以快照的建立非常快,只儲存兩個快照間的資料差異,因此快照也是空間優化的。克隆指兩個獨立的檔案系統共享一些列的塊。當任何一個克隆版本的檔案系統被改變時,只建立改動的資料塊,因此非常快速,也佔用少得多的空間。

而 ZFS 最大的貢獻在於它是第一個支援寫入時複製功能(COW,copy on write)的檔案系統。所有檔案系統中的塊都包括 256 位的校驗值。含有活動資料的塊從來不被覆蓋;而是分配一個新塊,並把修改過的資料寫在新塊上。所有與該塊相關的後設資料塊都被重新讀、分配和重寫。因此,當一個資料寫入時發生了任何意外錯誤,原先的資料依然可以被訪問,且檔案系統知道哪個操作出了錯誤而沒有完成。ZFS 的快照和克隆正是因此項技術而得以實現。

ZFS 對於使用者而言,介面友好。先前 Unix的卷管理非常煩瑣,FreeBSD 因此還建了一套巨集偉的框架,給邏輯卷管理做深層次的抽象。而 ZFS 檔案系統自帶卷管理方案,幾乎所有煩瑣複雜的操作都能在一兩條命令內完成,我用傳統的卷管理工具已有近十個年頭,第一次使用 ZFS 時,完全被其易用性震撼,所以我毫不猶豫地把手頭所有的伺服器遷移到了 ZFS。

由於 ZFS 各種美好,加上其開源性質,所有的作業系統都想支援它。Solaris、OpenSolaris 專案一直作為標準實現供其他系統參考。Pawe Jakub Dawidek 把 ZFS 移到 FreeBSD,並在 2009 年進入了 FreeBSD 7,作為 FreeBSD 第七版最耀眼的三項功能之一(另一項功能是我們先前提到的 ULE,以及 Sun DTrace 的移植工作)。NetBSD 在 2009 年正式收納 ZFS。Linux 則麻煩得多,因為 Linux 核心的協議 GPL 是個和很多協議都水火不容的奇葩協議,ZFS 分發所採用的 CDDL 和 GPL 會產生衝突,所以一方面 FUSE 提供了使用者空間層面的支援;另一方面,由 Oracle 牽頭,專為 Linux 開發 Btrfs,事實上就是一個 ZFS 的山寨版,可惜折騰了幾年,Oracle 自己又把 Sun 收購了,且到我撰寫此文時 Btrfs 依然沒有正式的穩定版本釋出。

曇花一現的 ZFS 夢

剛才提到,蘋果在招兵買馬,僱員工開發新一代的檔案系統,而 Chris Emura(Apple CoreOS 的檔案系統開發經理)及 Don Brady(先前提到,此人領導 HFS+ 的開發)兩個富有經驗的檔案系統開發者卻被衣服一樣晾在了一邊無所事事。2006 年,剛剛提到的 Pawe Jakub Dawidek 正在往 FreeBSD 遷移 Sun 的 ZFS,這項工作立刻引起了 Chris Emura 及 Don Brady 的高度興趣。由於 ZFS 在 Unix 系統高度的可移植性,加上 Mac OS X 本就是 FreeBSD 的近親,閒得發慌的兩人立即打算往 Mac OS X 移植 ZFS。在 2007 年 4 月 6 日,FreeBSD 的移植宣告完成,等待合併進主幹。一週後,兩位蘋果員工亦成功地完成了 Mac OS X 的移植。

蘋果一看兩人的 ZFS 的移植工作大有前途,立即跟進。2007 年的蘋果全球開發者大會上,蘋果讓 Chris Emura 及 Don Brady 舉辦了一場小型講話,介紹 Mac OS X 對 ZFS 的支援。這場講話先前並沒有在官方宣告中告示,但講話的報告廳依然擠滿了聽眾。隨後 ZFS 移植的原始碼在 Mac OS Forge 公佈。在最終版的 Mac OS X 10.5 帶有試驗性的 ZFS 只讀支援,以命令列方式提供。使用者可以掛載 ZFS 的儲存池,並對池中的檔案系統進行讀取操作。

蘋果一直使移植並使用 Sun 的關鍵技術,除了 Java 以外,Mac OS X 10.5 的 Xcode 套件也加入了 DTrace 的支援,並提供了一個好用的圖形介面 Instruments 讓開發者更方便地呼叫 DTrace。ZFS 除了解決 HFS+ 的所有問題,提供安全可靠的檔案系統基礎外,還可以簡化蘋果許多軟體的實現。例如前文提到的 Mac OS X 10.5 的 Time Machine,實現頗為煩瑣,依賴於給 HFS+ 提供新功能,功能層也需要增加很多的和備份相關的程式碼。而 ZFS 預設就支援快照,將大大簡化 Time Machine 的實現,並使該功能更穩定可靠。事實上在 2008 年 11 月 25 日,Sun 釋出了 OpenSolaris 2008.11 版,其中給 GNOME 的 Nautilus 增加了一個使用 ZFS 的快照功能的圖形介面外掛名為 Time Slider,和蘋果的 Time Machine 提供了非常相近的功能,我在使用後感覺不錯。

因此在 WWDC 2008 上,Snow Leopard 被提出,其中一項很重要的賣點就是對 ZFS 的完整的讀寫支援。在 Mac OS X 的伺服器版,蘋果也將提供一套圖形介面工具來方便維護人員管理 ZFS 儲存池。在當時的 Snow Leopard Server 主頁上,蘋果宣告 ZFS 將作為一項主推功能。

但好景不長,一年後的蘋果開發者大會時,ZFS 相關的內容被悄悄從任何公開的文件、網站、釋出會中撤下,沒有給出任何的理由。Mac OS Forge 上的 ZFS 程式碼和頁面也被蘋果移除。外界有很多對此的猜測,但沒有任何猜測得到蘋果官方的或是哪怕離職員工的證實。

猜測之一是當時 Sun 剛被 Oracle 收購,而 Oracle 長期投資 ZFS 的競爭產品 Btrfs。因此蘋果覺得 ZFS 的前途不甚明朗。

猜測之二是 ZFS 的關鍵技術 Copy On Write 有專利問題,NetApp 聲稱他們擁有 COW 的專利因此在起訴 Sun,蘋果不想在當中冒風險。

猜測之三是 ZFS 和蘋果的 XNU 核心有協議衝突。我雖然不學法律,但我認為這個說法不完全對,因為 ZFS 和 DTrace 一樣,是以 CDDL 釋出的開源軟體,既然 DTrace 可以無後顧之憂地加入到 XNU 中,ZFS 也沒有理由不可以。事實上,除了 Linux 這種少數使用 GPL 這類奇葩協議的核心,大多數系統的協議都不和 CDDL 衝突。FreeBSD 也好,Mac OS X 10.5 也罷,都把 ZFS 加入核心釋出。

但事實上,如果把三種猜測並在一起,我們可以看到一個更全域性的可能性:對於猜測之二,蘋果可能並非想使用 CDDL,而是想從 Sun 買下一個私有的協議,這樣一來,Sun 不但提供更好的技術支援,出了問題(比如猜測二中的專利問題)也可以讓 Sun 為自己背黑鍋。結果 Sun 可能和蘋果價格談不攏,加上猜測之一提到的 Sun 大勢已去,讓蘋果覺得還不如自己造個輪子來得方便。Sun 公司開發 ZFS 的主力 Jeff Bonwick 雖不能提供詳細的資訊,但他基本證實了這種說法。

無論如何,Mac OS X的 ZFS 支援,如曇花一現般消失了。

未來檔案系統之路走向何方

雖然 Mac OS X的 ZFS 支援被砍了,開源社群依然想繼續開發 Mac OS Forge 先前版本的移植。如 MacZFS 專案不遺餘力地給 Mac OS X 10.5~10.7 提供 ZFS 讀寫支援。Don Brady 在蘋果將對 ZFS 的支援砍掉之後從工作了 20 多年的蘋果離職,開了一家名為 Ten’s Complement 的公司,該公司提供 Z-410,較 MacZFS 提供更新更穩定的移植。

不過,砍了 ZFS 後的蘋果目標也變得更清晰——和 Sun 的談判讓蘋果覺得與其支付高額的協議費,還不如僱人自己做個新的,再說了,作為比 Sun 大得多的 IT 公司,蘋果可以輕而易舉地搞個更強大的東西滅了它,因為 ZFS 其實也不如傳說中的那樣好。

首先,時代在進步。ZFS 之後,又有很多新的和檔案系統相關的研究,如 Ohad Rodeh 的論文,即成為後來 BtrFS 實現的基礎,可能比 ZFS 做得更好。

其次,ZFS 是十年前開始設計的檔案系統,但十年中,儲存工具已發生了重大的變化。ZFS 為傳統磁碟設計,但傳統磁碟的市場空間已不斷被 SSD、快閃記憶體的吞食。尤其是 MacBook Air 中使用的 Flash 儲存器便宜好用又小巧,可能將來會在 MacBook Pro 甚至 iMac 中得到更大的推廣。採用為傳統磁碟優化的 ZFS 就不顯得那麼有吸引力。

最後,ZFS 和蘋果有不同的使用者群。ZFS 目標使用者是大企業的工作站和伺服器。在那裡,大容量的儲存空間、高階的卷管理顯得非常重要,但蘋果面對的基本都是個人使用者——先前蘋果還賣伺服器,但後來 Xserve 都被蘋果砍了。有幾個個人使用者需要使用到 ZFS 這些高階的功能呢?更重要的,蘋果的主要利潤將移到 iPhone、iPod、iPad、Apple TV 這些小裝置上,ZFS 需要佔用大量的記憶體來實現檔案系統操作,在這些小裝置上,記憶體很少,ZFS 根本跑不起來。

蘋果非常清楚這些問題,工程師們現在一定在緊鑼密鼓地開發下一代檔案系統。在 10.7 及 10.8 中,這套檔案系統並未浮出水面,但一些細節值得留意。在 10.7 中,蘋果釋出了 Core Storage,但並未聲張。這是一套邏輯卷管理工具,類似於前文提到的 FreeBSD 的 GEOM。這個版本的 File Vault 2 亦使用 Core Storage 重寫。可以看到雖然蘋果在上層不斷地淡化檔案系統的概念,例如 iCloud 的釋出和 iOS 中對於檔案這一概念的故意忽略,但蘋果在底層檔案系統上的動作越來越大,想必在將來,蘋果定會讓我們感到重大的驚喜。

相關文章