Unladen Swallow項目計劃

原文鏈接:  http://code.google.com/p/unladen-swallow/wiki/ProjectPlan 譯文鏈接: http://danmarner.yo2.cn/unladen-swallow-project-plan 原著: Google  譯者: DaNmarner 歡迎轉載,請保留原/譯文鏈接。 =========================

Unladen Swallow項目計劃

優化Python計劃 注:所有引用資料的鏈接見相關論文

目標

我們要讓Python變的更快,同時我們也希望讓大型的,完好的現存應用無痛苦的轉而使用Unladen Swallow項目。

  1. 創建一個比CPython速度至少快5倍的新Python版本。
  2. Python應用的表現應該非常穩定。
  3. 維持與CPython應用程序在源代碼級別的兼容。
  4. 維持於CPython擴展模塊在源代碼級別的兼容。
  5. 我們並不是要維護一個長期的Python實現;我們把這個項目當作一個開發分支(branch),而不是一個版本分支(fork)。

項目概括

爲了實現我們對於性能和兼容性的目標,我們選擇對CPython進行修改,而不是從零開始開發這個實現。值得強調的是,我們選擇從CPython 2.6.1着手:Python 2.6與2.4/2.5(當前爲大多數有價值的應用使用)和Python 3.0(未來的終極版本)都有可以很好的共存。從一個CPython的版本着手可以是我們避免重新實現大量的內置函數,對象和標準庫的模塊,同時讓我們重用一些現存且常用的CPython的C語言擴展API。從一個2.x CPthon可以讓我們更輕鬆的遷移現存的應用程序;假設我們從3.x開始,並且要求大型應用程序的維護者們率先遷移他們的程序,那對我們項目的受衆來說是不切實際的。 我們的主要工作是集中力量提高Python代碼的執行速度,而不會在Python的運行時庫上過多的努力。我們的長期計劃是是使用一個創建在LLVM基礎上的JIT來代替CPython傳統的虛擬機,同時儘量少的影響Python的運行模式的其他部分。通過觀察,我們發現Python的應用程序把大量的運行時間花費在了主eval循環。尤其是,即對例如操作碼調度(opcode dispatch)這樣虛擬機部件的微小調整也能對Python的運行性能產生重大影響。我們相信通過LLVM的JIT引擎把Python代碼編譯爲機器碼將會帶來更多的益處。 一些顯著的好處:

  • 轉向JIT能讓我們把Python從基於堆棧的機(stack-based machine)轉爲一個基於寄存器的機(register machine),實踐證明這種轉變提升了另一個類似語言的性能。
  • 其他的先不提,單是消除對收發操作碼(opcodes)的需要本身已經是一項勝利。請參考http://bugs.python.org/issue4753上一個當前CPython對操作碼發送變化的敏感性的討論。
  • 目前的CPython虛擬機操作碼接受/發送限制使進進一步的性能優化變得幾乎不可能。舉例來說,我們想實現數據類型回饋(type feedback)和動態的重新編譯(dynamic recompilation ala SELF-93),但是我們認爲用CPython編譯的二進制代碼來實現多態性內聯高速緩存(polymorphic inline caches)將是無法接受的慢。
  • LLVM尤爲值得注意。那是因爲它爲多個平臺生成代碼功能(codegen)的易用性,和它具有把C和C++編譯爲同種中間代碼——這正是我們想要帶給Python的。它能夠讓內聯和交錯解析(inlining and analysis)成爲可能,消除這個當前Python和C之間的障礙。

有了產生機器碼的框架,我們就可以把Python編譯爲更加高效的實現。以以下這段代碼爲例:

for i in range(3):
  foo(i)

目前它將被低效的翻譯成這樣

$x = range(3)
while True:
  try:
    i = $x.next()
  except StopIteration:
    break
  foo(i)

一旦我們有了知道range()代表range()內置函數的辦法,我們可以把它變爲類似這樣

for (i = 0; i < 3; i++)
  foo(i)

在C語言裏,使用unboxed數據類型進行數學運算,可以把這個循環展開爲

foo(0)
foo(1)
foo(2)

我們有意將Unladen Swallow的內部結構設計爲支持多內核。服務器將來只會有越來越多的內核,我們要發掘這一點,從而可以在並行結構中完成更多的工作。例如,我們可以用一個內核作爲並行優化器,它能在代碼運行的時候進行日益昂貴(重要)的代碼優化,用另一個內核來執行代碼本身。我們也在考慮實現一個並行的GC,利用另一個內核來釋放內存模塊。由於大多數工業級的服務器都具有4到32個內核,我們相信這項優化的收益是一筆潛在的財富。然而,我們還是要關注高度並行的應用程序的需要,而不能盲目的消耗掉這些內核。 強調一下,這裏的很多領域已經被其他的一些動態語言考慮或者實現過了,例如jRubyRubiniusParrot, 更包括像JythonPyPyIronPython這些其他的Python實現。我們正在從這些其他實現裏尋找有關調試信息,正則性能以及其他提高動態語言性能的點子。這是一條已經被很多人走過的路,我們需要儘量避免重新發明輪子的困境。

計劃藍圖

Unladen Swallow 將會每3個月發行一個新版本,發行期間進行bug修復。 2009 第一階段(Q1) Q1主要用來對顯存的CPython實現進行相對小的修改。我們的目標是在目前的基線上實現25-35%的性能提升。這個階段的目標是相對保守的,我們想儘可能快的給客戶應用程序一些看得見的性能優化,而不是要他們等到整個項目完成。 2009 第二階段(Q2) Q2會集中力量來廢除Python的虛擬機,並用一個具有相同功能的基於LLVM的實現將其代替。我們預期將會有一些性能提升,不過那不是2009Q2的主要任務。我們主要是要得到一個建立在LLVM之上的可以運行的東西。給它提速是本階段之後的人物。 2009 第三階段(Q3)以及將來 從Q3開始的任務將是“簡單的“做好這些作業。我們不渴望做原創工作,而是儘可能的利用近30年來的研究成果。請移步相關論文來瀏覽我們打算實現內容的論文清單的一部分(遠不及全部)。 我們計劃強調對正則引擎何其他被確定爲性能瓶頸的擴展模塊的考慮。然而,正則表達式已經被確定爲一個很好的目標並且會是我們考慮第一個進行優化的領域。 另外,我們打算去除Python的GIL和多線程的狀態。我們相信通過實現一個更高級的GC,這一點是可以實現的,類似IBM的Recycler。 我們的長期目標是讓Python的速度快到可以從把那些爲了速度而使用C實現的類型重新用Python取代。 2009Q3準確的性能優化目標會在Q2的期間確定。

計劃細節

一旦我們我們取得了一定的進展並且吸引了一部分人來採用我們的Python,我們將開始向LLVM的轉換,也許會從一個開發分支開始。這將經歷很多階段:

  1. 在Python中添加llvmmodule和llvmfunction類型,它們爲LLVM的模塊函數類型提供了界面。教llvmmodule讀取二進制文件(bitcode)並且對它們進行美麗輸出。(讀取bitcode對下一步並不至關重要,但它有助於測試。)

llvn-py具有類似的包裝類型,但是在覈心解釋器中使用Python定義的類型是十分困難的,所以我們需要我們自己的實現。這個實現不會是全部的包裝(留給llvp-py好了)。它將僅僅是爲了方便和有效的調試。

添加一個compile_llvm內置對象,它的大部分代碼將和目前內置的compile對象相同,然而它會生成LLVM IR(同llvmmodule或llvmfunction數據類型)。我們可以一步一步的進行這項工作從而在整個進程中都保持一個可用的Python解釋器。與此同時,我們可能會針對每一個操作碼將其原本的實現轉換爲一個IRBuilder的實現,不過對於一些比較困難的情況我們也許只是向一個轉換函數發送請求。我們也許需要/必須把這一步和下一步結合起來。有幾個特別的Python結構可能帶來麻煩
  • Generator:目前還沒有一個針對generator的計劃。我們必須要保留PC,寄存器和局部變量,問題是LLVM並沒有定義一個PC,而只有標籤,所以我們大概會給每一次yield一個索引然後調用當前索引來返回它。我們也可能要求所有的寄存器變量在那個時候已經被放出了。但是我們對實現細節還沒有什麼概念。我們預期到時候我們會想出一些主意來。
  • Closures:一個closure就是一個函數加一個預先賦值的參數,用來代表環境。
  • Exception處理
  • 函數調用問題
增加一個調用llvmfunction類型的辦法。LLVM解釋器也許還不能在我們需要的時候調用外部函數,使用JIT也許更加困難。我們會選擇一個最簡單的辦法。我們只是想讓一切運行起來。寫上一堆測試代碼。 用新的LLVM編譯器取代Python用來編譯二進制代碼 (bitcode)的編譯器,可能會附加一個標記。Talin建議使用一個代碼/函數對象裏的標記來解決調用和運行哪個編譯器的問題。 想出一個最簡單的可行的.pyc保存辦法。我們希望最直接的辦法——把python模塊當成LLVM模塊以二進制形式保存在硬盤上——就能用。我們可以在以後再添加那個高級的數據記錄和預先優化代碼(階段12) 讓Python知道到底應該快速JIT還是慢速JIT編譯某個函數(向JIT::create傳遞fast==true)。Nlewcky說“代碼生成模式(codegen)大概要比快速編譯模式快上3倍(注:這是在debug模式下,而不是在release模式下,所以還不能確定)。”我認爲我們確實應該花一些功夫來獲得一個平衡。我希望Python在這個階段能比我們最初的版本要快。 開始優化。Talin指出,實現定義的這些優化措施實現起來會很困難,因爲Python的函數調用都是非直接進行的。這個關鍵讓我們決定使用類型識別,從而讓我們能直接的調用函數。

(階段8及以後可以同時開始嘗試,大概會在2009Q2接近尾聲的時候開始)

生成比直接翻譯CPython二進制碼更好的LLVM IR。 想出爲特定類型指定函數的辦法,這樣有利於內聯(inline)。我們將能非常輕易的做到和psyco一樣好,因爲我們可以直接用他們的算法。 a. 允許用戶通過註釋函數來告訴解釋器該用哪種編譯方案。 b. 記錄函數調用並且推斷共同的參數類型。 如果優化措施的消耗大到了讓JIT傷害到啓動時間,我們可以記錄那些耗時的函數從而只對它們進行優化。這裏借鑑了HotSpot的工作原理。 階段9b和階段10要求我們同時保持不同版本的代碼來滿足所有的函數和已經存在的調用者。我們可能想要GC這些不同的版本,情況會變得很有趣。 把生成並優化的IR保存在硬盤上來充當.pyc文件的角色,也許還要包括進一些沿途生成的紀錄。這可以讓以後的運行享受到之前運行時進行的優化帶來的好處。這也應了LLVM的“夠程序一輩子的分析和轉化的編譯框架”的標榜。 :)

測試與考量

性能

Unladen Swallow包含了一個具有很多有趣的性能測試的tests目錄。pref.py是我們所關心的基準的主要界面,它將負責調配運行,清理*.py[co]文件和利用測試結果來獲取我們感興趣的數據。 Unladen Swallow的基準套件被設計爲致力於主流熱門的Python程序,尤其是web應用。我們調查過的主流Web應用顯示出他們主要的性能瓶頸在template系統上,所以我們初期的套件將集中精力在這方面:

  • Django和Spitfire的template。 兩種大相徑庭的實現Template語言的方式。
  • 2to3。 把Python 2的源碼翻譯爲Python 3。具有一個很有意思的,大量依賴對象和方法的純Python內核。
  • Pickle及逆Pickle。 大塊頭的Web應用依靠memcache,而後者用Python的pickle格式進行序列化。

除此之外,我們的基準套件裏還包含了幾個很一般的庫,例如Richards,PyStone還有PyBench;我們包含這些僅僅是爲了保持完整性和與其他 Python版本的兼容性,其他版本確實使用他們。Unladen Swallow認爲這些基準庫並不能衡量真實世界的Python應用或Python實現的性能,並且我們不會以默認狀態運行它們或者把他們納入決策因素。 有關項目長期表現的統計,Unladen Swallow利用了Google內部的標準性能考量框架。項目組成員將在郵件列表定期發佈性能上的進展。對於一些小修改的測試,按照基準頁面的描述使用perf.py就足夠了。

準確性

爲了保證實現的準確性,Unladen Swallow同時使用標準的Python測試組建和一些知名的Python 2.6第三方庫。 值得一提的是,我們會測試第三方的C擴展庫,因爲這些庫是最容易因爲C語言中無法探明的變化而垮掉的。 隨着我們在JIT實現上的進展,我們將在常規測試中引入一個參數測試器(fuzzer)。我們計劃儘可能的重用Victor Stinner的Python的Fusil,因爲 a)它是即成的, b)曾經被用來發現真實的Python缺陷。 Unladen Swallow還維護了一個BuildBot實例用來針對每一次對主版本的代碼提交運行以上的測試。

風險

可能會不能和主線版本融合。 可能有一些有意見的,保守的高級Python核心開發成員會反對我們項目的融合,因爲它會帶來過於重大的變化。這是件好事!對變化的反抗在這種情況下是一 件非常好的事情,因爲它會帶來對我們的版本及其對CPython長遠衝擊的一次完全,公開的檢驗——這是開源社區,永遠歡迎不同的聲音。我們相信我們能證 明我們所提倡的改變,並且通過和Guido以及其他維護Python的高級成員保持密切的溝通,我們希望能把我們的工作侷限在那些有希望能被接受的改變 上。然而,一些補丁還是可能被拒絕。如果是這樣,我們將陷入支持一個與事實標準的不同Python的實現的境地, 或者不能變得像我們計劃的那麼快。C'est la vie。 LLVM有很多未知的方面: 對擴展庫的影響?JIT在多線程應用的行爲?對Python啓動時間的影響? Windows支持: CPython目前具有很好的Windows支持,我們爲了能和主線版本融合不得不維護這一狀態。由於Unladen Swallow的工程師基本上對Windows開發甚至Windows的系統都沒有多少經驗,保持Windows支持在一個可接受的水平可能會減慢我們的 工作進程或者迫使我們在Windows上去除一部分有利於提高性能的代碼。社區的貢獻也許能幫的上忙。

信息交流

所有有關Unladen Swallow的信息交流都將在Unladen Swallow列表上進行。在這裏會進行設計上的討論,發佈開發的最新進展,性能數據,代碼評價以及所有其他一切該開源項目的細節。

發佈了10 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章