當前位置:
首頁 > 知識 > 我是如何提升 Rust 編譯器的速度?

我是如何提升 Rust 編譯器的速度?

我是如何提升 Rust 編譯器的速度?

我是如何提升 Rust 編譯器的速度?

作者 | Nicholas Nethercote

譯者 | 彎月,責編 | 伍杏玲

出品 | CSDN(ID:CSDNnews)

【CSDN 編者按】本文是Rust的核心研發人員,在本文中,他將分享一下再2019年,他在提升 Rust 編譯器的速度上,做了哪些新的工作來優化它。

我是如何提升 Rust 編譯器的速度?

更快的Globals

libsyntax用一個全局數據結構Globals存儲了3個表,分別存儲了有關span(代碼位置)、符號和數據清理(與宏擴展相關)的信息。訪問這些表的代價很高,所以我找到了許多改進方法。

  • #59693(https://github.com/rust-lang/rust/pull/59693):AST中的每個元素都有一個span,描述了元素在原始源代碼中的位置。

    每個span由偏移、長度以及與宏擴展相關的值組成。這三個欄位共佔12個位元組,考慮到它需要添加到AST的每個元素上,12個位元組太多了,而且很多時候這三個欄位並不需要這麼多空間。

    因此,編譯器採用了只需4位元組的壓縮格式,而當長度超過4位元組時則採用備用策略——將其存儲到Globals中的哈希表中。而該PR將其改為了8個位元組。這會稍稍增加內存的使用量,但上述備用策略的執行率可以從10-20%降低到不足1%,這可以加速許多工作負載,最大可以提升14%。

  • #61253(https://github.com/rust-lang/rust/pull/61253):有許多操作都需要訪問數據清理信息,通常這些操作會調用兩次甚至三次,因此會造成重複查找數據清理信息。該PR引入了組合操作,可以避免重複查找。這可以將packed-simd上的速度提高10%,對於普通工作負載效率可以提高3%。

  • #61484(https://github.com/rust-lang/rust/pull/61484):與上述#61253類似,只不過這個PR在許多基準測試中都贏得了提高2%的好成績。

  • #60630(https://github.com/rust-lang/rust/pull/60630):編譯器有一個駐留的字元串類型,名叫符號(symbol)。編譯器對該類型的使用不太一致。因此,導致許多符號與普通字元串的比較需要逐個字元比較符號表中的字元串。

    實際上,符號與符號的比較的開銷很小,只需進行整數比較。該PR刪除了符號與字元串的比較操作,強迫編譯器更廣泛地使用符號類型。(幸運的是,大多數引入的符號都使用了靜態已知、預先駐留的字元串,因此沒有額外的成本。)該PR在各種基準測試中贏得了高達1%的效率提升,而且符號的使用也更為一致。

  • #60815(https://github.com/rust-lang/rust/pull/60815):與上述#60630類似,該PR也在各項基準測試中贏得了高達1%的效率提升。

  • #60467、#60910、#61035、#60973:這些PR避免了一些不必要的符號,可以進一步將編譯器的效率提高1%。

我是如何提升 Rust 編譯器的速度?

其他

以下各項提升沒有統一的主題。

  • #57719(https://github.com/rust-lang/rust/pull/57719):該PR將一個常用的函數改成了內聯函數,可以將一個工作負載的效率提高4%。

  • #58210(https://github.com/rust-lang/rust/pull/58210):該PR改變了一個常用的斷言(僅在調試版本中有效),可以將一個工作負載的效率提高20%!

  • #58207(https://github.com/rust-lang/rust/pull/58207):上述我曾提到了字元串駐留。Rust編譯器還會針對其他經常出現重複值的類型使用駐留,包括一種名叫LazyConst的類型。

    然而,intern_lazy_const函數有很多Bug,而且沒有真正執行駐留,它只是分配了一個新的LazyConst,而卻不會檢查之前是否遇到過!該PR修復了這個問題,大幅降低了內存使用率的峰值,而且頁錯誤還減少了59%。

  • #59507(https://github.com/rust-lang/rust/pull/59507):該美化輸出會針對每個縮進的空格調用write!,在某些工作負載上,縮進級別會超過100級。該PR能在絕大多數情況下將所有處理放到一個write!調用中。該PR可以在多個基準測試中體現出7%的提升。

  • #59626(https://github.com/rust-lang/rust/pull/59626):該PR更改了數據結構的預分配大小,以更好地滿足實際需要,在某些工作負載上,可以將內存使用量的峰值減少20 MiB。

  • #61612(https://github.com/rust-lang/rust/pull/61612):該PR優化了解析器中的熱路徑,因為常量標誌符會毫無目的地重複「這是不是一個關鍵字?」的測試,對於擁有大量常量的程序來說,該PR可以提升7%的性能。

我是如何提升 Rust 編譯器的速度?

分析改進

下面的改進涉及一些分析工具。

  • #59899(https://github.com/rust-lang/rust/pull/59899):為了讓枚舉變數從大到小列舉,我修改了-Zprint-type-sizes的輸出。該PR可以方便你看到超大的變數,特別是對於有許多變數的枚舉。

  • #62110(https://github.com/rust-lang/rust/pull/62110):為了改進-Ztime-passes標誌的輸出,我刪除了一些無用信息的輸出,並添加了總編譯時間的度量。

此外,我還改進了rustc-perf基準測試套件中的分析支持。首先,我添加了OProfile性能分析的支持。我承認至今我還沒有發現顯著的提升。在運行時,大約有一半的幾率會出現錯誤,很讓人失望。

其次,我添加了新版DHAT性能分析的支持。雖然這篇文章寫自2019年,但值得一提的是,我於2018年對新DHAT的幫助做了一些改進,PR包括:#55167、#55346、#55383、#55384、#55501、#55525、#55556、#55574、#55604、#55777、#55558、#55745、#55778、#55905、#55906、#56268、#56090、#56269、#56336、#56369和#56737。

最後,我還寫了一篇有關Rust性能所有基準的概要描:https://github.com/rust-lang-nursery/rustc-perf/blob/master/collector/benchmarks/README.md

我是如何提升 Rust 編譯器的速度?

流水線編譯

上述改進(以及此前完成的所有改進)都屬於微優化,也就是說,我使用分析數據來優化一小段代碼。

但是,我們還應該考慮對Rust編譯器速度進行更大規模的系統性改進。今年第二季度的時候,我曾與Alex Crichton在流水線編譯項目上展開了合作,這一功能通過疊加依賴箱(crate)的編譯,提升了構建多箱Rust項目時的並行度。沒有流水線的編譯如下圖所示:

我是如何提升 Rust 編譯器的速度?

在使用了流水線後,編譯如下圖所示:

我是如何提升 Rust 編譯器的速度?

我承擔了Rust編譯器方面的工作,而Alex負責的是Cargo方面的工作。

如果你想了解其中的工作原理,以及使用方法和大量的測量數據,請閱讀這篇文章:https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199

其效果高度依賴於項目的箱結構以及編譯機器的配置。我們發現有些項目的性能提升可達1.84倍,而有些項目則沒有任何提升。在最差的情況下,還有可能導致速度出現幾乎可以忽略不計的減慢,但是無需擔心,因為它不會導致任何額外的工作,只是改變了某些工作的順序。

目前流水線編譯還處於不穩定階段,這篇文章記錄了我們發現的問題:https://github.com/rust-lang/rust/issues/60988

我是如何提升 Rust 編譯器的速度?

今後的工作

我想在第三季度的時候,展開下列的工作:

  • 對於流水線編譯,我想嘗試在編譯器前端,儘早推動元數據的創建,這有可能會進一步提高速度。

  • Rust編譯器經常使用memcpy,雖然不是直接使用,但生成的代碼經常為了移動值或其他原因使用memcpy。編譯器不會在「檢查」階段執行任何代碼生成,通常有2-8%的指令會發生在memcpy中。我想了解其中的原因,並看看是否可以改進。一種可能性是編譯器中移動了超大的類型;另一種可能性是代碼生成有問題。如果是前一種情況,則很容易修復;如果是後一種,則難度較大。但是,如果能修改好的話,許多Rust程序都會受益。

  • 增量編譯的效率有時不是很理想。在某些工作負載上,即便做了很微小的修改,但是重新編譯所需的時間與完整的非增量編譯大致相同。也許我可以通過增量實現的一個小改動來提升性能。

  • 我想看看解析器中是否還有其他可以改進的熱路徑,比如像#61612。

不過我還有各種Firefox的工作安排,不知道是否能順利完成上述的所有工作。

原文:https://blog.mozilla.org/nnethercote/2019/07/17/how-to-speed-up-the-rust-compiler-in-2019/

本文為 CSDN 翻譯,轉載請註明來源出處。

【END】

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

程序員爬取 3 萬條評論,《長安十二時辰》槽點大揭秘
Visual Basic 終於要衰落了嗎?

TAG:CSDN |