自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

大牛最新研究!提速Rust編譯器!

譯文 精選
開發(fā) 架構(gòu)
Nethercote發(fā)現(xiàn),很多時候,無法在編譯速度、內(nèi)存占用、編譯體積和質(zhì)量上都實現(xiàn)提升,一個指標(biāo)的提升,經(jīng)常伴隨另一個性能指標(biāo)的下降。盡管他沒有發(fā)現(xiàn)比現(xiàn)有方法更明顯的改進(jìn),但還是希望在未來繼續(xù)研究這個問題。

作者 | Nethercote

編譯 | 王瑞平、言征

Nethercote是一位研究Rust編譯器的軟件工程師。最近,他正在探索如何提升Rust編譯器的性能,在他的博客文章中介紹了Rust編譯器是如何將代碼分割成代碼生成單元(CGU)的以及rustc的性能加速。

他解釋了不同數(shù)量和大小的CGU之間的權(quán)衡以及Rustc是如何使用LLVM并行化代碼生成和優(yōu)化的。此外,Nethercote還探索了一些形成和排序CGU的替代方法,并報告了他的實驗結(jié)果。

Nethercote發(fā)現(xiàn),很多時候,無法在編譯速度、內(nèi)存占用、編譯體積和質(zhì)量上都實現(xiàn)提升,一個指標(biāo)的提升,經(jīng)常伴隨另一個性能指標(biāo)的下降。盡管他沒有發(fā)現(xiàn)比現(xiàn)有方法更明顯的改進(jìn),但還是希望在未來繼續(xù)研究這個問題。

如何提升Rust編譯器速度?這篇文章或許能幫助到你!

1、LLVM:Rust編譯加速的秘訣

Rust的MIR是HIR到LLVM IR的中間產(chǎn)物,將MIR轉(zhuǎn)換為LLVM IR,然后將其傳遞給LLVM,從而生成機(jī)器代碼。在此過程中,LLVM能通過處理多個模塊實現(xiàn)并行。Rustc使用LLVM加速Rust的編譯。我們稱其中的每個模塊為“代碼生成單元(CGU)”。

圖片圖片

圖:時間位于 x 軸上,每條水平線代表一個線程。主線程顯示在頂部,標(biāo)有 PID。它在開始時處于活動狀態(tài),時間足以產(chǎn)生另一個標(biāo)記為 的線程rustc。rustc底部顯示的線程在大部分執(zhí)行過程中都處于活動狀態(tài)。還有 16 個 LLVM 線程標(biāo)記opt cgu.00為 到opt cgu.15,每個線程都會在短時間內(nèi)處于活動狀態(tài)。

CGU實際上是如何形成的呢?粗略地說,Rust 程序由許多函數(shù)組成,這些函數(shù)形成一個有向圖,其中從一個函數(shù)到另一個函數(shù)的調(diào)用構(gòu)成了一條邊。我們需要將這個圖分割成塊(CGU),這是一個圖分區(qū)問題。我們希望創(chuàng)建大小大致相等的 CGU(因此 LLVM 處理它們所需的時間長度大致相同),并最大限度地減少它們之間的邊數(shù)(因為這使 LLVM 的工作更輕松,并帶來更好的代碼質(zhì)量) 。

實際上,由于我們上面看到的階梯效應(yīng),我們不希望 CGU 的大小完全相同。理想的情況是 CGU 大小存在與梯度相匹配的輕微梯度。這樣,所有 CGU 將完全相同地完成處理,以實現(xiàn)最大程度的并行化。

合并之前的CGU(9個)合并之前的CGU(9個)

Nethercote認(rèn)為在合并之前“調(diào)整”CGU可能會有所幫助,在某些情況下將函數(shù)從一個CGU移動到另一個。例如,如果在CGU A中被調(diào)用f的葉函數(shù)(即不調(diào)用任何其他函數(shù)的葉函數(shù))在CGU B中有一個調(diào)用方g,那么將f從A移動到B是有意義的,從而去除CGU間的邊。(還有其他類似的情況涉及非葉函數(shù),移動也有意義)。我實現(xiàn)了這一點,它給出了一些適度的改進(jìn),但我目前還沒有決定它是否值得額外的復(fù)雜性。

調(diào)整之后的CGU(5個)調(diào)整之后的CGU(5個)

在實現(xiàn)這一點的同時,我還花了一些時間來可視化調(diào)用圖。我從GraphViz開始。這些圖表對于非常小的程序來說看起來不錯,但對于較大的程序來說,它們很快就變得無法讀取和導(dǎo)航。我在Mastodon上抱怨過這一點,并得到了使用d2的建議,d2速度較慢,但圖形可讀性更強(qiáng)。

圖片圖片

2、后端并行方法的軟肋

圖劃分是一個 NP 難題。有幾種常見的算法,實現(xiàn)起來相當(dāng)復(fù)雜。相反,rustc 做了一些更簡單的事情。首先簡單地為每個 Rust 模塊創(chuàng)建一個 CGU:模塊中的每個函數(shù)都放入同一個 CGU 中。然后,如果 CGU 數(shù)量超過限制(默認(rèn)情況下,非增量構(gòu)建為 16 個,增量構(gòu)建為 256 個),它會重復(fù)合并兩個最小的 CGU,直到達(dá)到限制。這種方法簡單、快速,并以有用的方式利用特定領(lǐng)域的知識——程序模塊往往提供良好的自然邊界。

所有這一切都依賴于測量 CGU 大小的方法。目前使用CGU中的MIR語句的數(shù)量來估計LLVM處理CGU需要多長時間。這里有很大的設(shè)計空間,有許多其他可能的形成和規(guī)劃CGU 的方法。

圖片圖片

這種轉(zhuǎn)換對Rust眾多語法糖進(jìn)行了脫糖,并且極大精簡了Rust的語法(但并非其語法子集),是觀察和分析Rust代碼的常用手段,尤其是在控制流圖和借用檢查等方面。

在這篇文章的最后,Nethercote提供了幾個數(shù)據(jù)集的鏈接,每個數(shù)據(jù)集都記錄了編譯rust -performance基準(zhǔn)時每個CGU的測量值。這些數(shù)據(jù)集包括許多測量靜態(tài)代碼大小的輸入(獨立變量),例如,函數(shù)數(shù)量和MIR數(shù)量等。

Nethercote試著用scikit-learn做一些基本的分析。并且,通過這些基本的分析,能讓Nethercote仔細(xì)推敲到底應(yīng)該搜集哪些測量值。

通過一系列的改進(jìn)優(yōu)化,他獲得的最終數(shù)據(jù)集比剛開始時的數(shù)據(jù)更準(zhǔn)確。但是,并沒有通過這些數(shù)據(jù)獲得多少實際的結(jié)果。實際上,每次我對測量的內(nèi)容改變后都會得到完全不同的結(jié)果。

3、實現(xiàn)更快的Lexer

詞法分析(lexical analysis)是編譯器的第一個階段,實現(xiàn)詞法分析的代碼稱為lexer。

有人最近研究了logos(https://github.com/maciejhirsz/logos)這個在rust中廣受歡迎的lexer。

此前,logos聲稱其目標(biāo)是能比手動實現(xiàn)的lexer更快,作者提出了質(zhì)疑,因為在他看來,通用性和性能無法兼得。因此,他一步步實現(xiàn)了lexer,探索了多種優(yōu)化技巧,并與logos進(jìn)行了多輪性能對比。

最終的結(jié)果表明,手動實現(xiàn)的基于狀態(tài)機(jī)的lexer比logos實現(xiàn)了20%左右的性能提升。

4、從錯誤中學(xué)習(xí):使用Rust實現(xiàn)DLL注入

Rust是一種注重安全性的編程語言,但在某些情況下,開發(fā)人員可能需要使用unsafe關(guān)鍵字來執(zhí)行某些操作。unsafe可以提供更高的性能,但可能會犧牲安全性。因此,開發(fā)人員在使用時需要非常小心。幾個使用unsafe的常見場景包括:訪問裸指針、調(diào)用外部C函數(shù)等,并提供了一些建議和最佳實踐,以確保在使用unsafe時不會引入潛在的安全隱患。

舉個應(yīng)用方面的例子:原來,作者一直在用C++編寫逆向工具,但是,C++這門語言并不友好,于是研究了下如何使用Rust實現(xiàn)DLL注入的“工具”。

大致原理就是讓Rust首先生成一個C樣式的DLL,然后,使用unsafe操作裸指針,操作程序內(nèi)存,最后實現(xiàn)DLL注入就可以了。

5、期待更準(zhǔn)確的估計函數(shù)

Nethercote 希望具有數(shù)據(jù)分析專業(yè)知識的人可以做得更好,重點關(guān)注以下幾個方面:

1)更匹配的估計函數(shù)

2)想要使編譯器比現(xiàn)在更快,一個更好的估計函數(shù)也許不會達(dá)到預(yù)期的效果。我提出了一些更好的統(tǒng)計方法,但并沒有提升編譯速度,甚至變差。

3)CGU調(diào)度效果不可預(yù)測,你不能假設(shè)一個估計函數(shù)好幾個百分點就會使編譯器更快。話雖如此,我希望改進(jìn)力度足夠大,能夠轉(zhuǎn)化為實際的加速。

4)對于估計函數(shù)來說,最好高估CGU編譯所需的時間,而不是低估。

5)我很擔(dān)心過度擬合。數(shù)據(jù)集來自一臺機(jī)器,但實際上,rustc會運行在不同的機(jī)器上,具有各種各樣的體系結(jié)構(gòu)和微體系結(jié)構(gòu)。

6)這些數(shù)據(jù)集來自單一版本的rustc,使用單一版本的LLVM。我擔(dān)心隨著時間的推移準(zhǔn)確性可能會漂移。

7)我更喜歡不太復(fù)雜且易于理解的估計函數(shù)。當(dāng)前的函數(shù)非常簡單,在大多數(shù)情況下只是增加了基本模塊和語句的數(shù)量。例如:0大小的CGU應(yīng)該別估計為花費非常接近于0的時間。

8)估計函數(shù)有一個明確的問題,即如果不考慮其內(nèi)部公式,計算MIR語句可能非常不準(zhǔn)確。特別是,單個MIR語句可能變得很長。舉個例子:深度向量壓力測試的MIR包含一條語句,該語句定義了包含超過100,000個元素的向量字面量。不出所料,當(dāng)前的估計函數(shù)嚴(yán)重低估了編譯這個基準(zhǔn)所需的時間。

Nethercote最后提醒:希望以上的請求是合理的!

以下是上文提到的數(shù)據(jù)集:

  • 調(diào)試構(gòu)建,主要基準(zhǔn)測試

https://nnethercote.github.io/aux/2023/07/25/Debug-Primary.txt

  • 選擇構(gòu)建,主要基準(zhǔn)

https://nnethercote.github.io/aux/2023/07/25/Opt-Primary.txt

  • 調(diào)試構(gòu)建,二級基準(zhǔn)測試

https://nnethercote.github.io/aux/2023/07/25/Debug-Secondary.txt

  • 選擇構(gòu)建,二級基準(zhǔn)

https://nnethercote.github.io/aux/2023/07/25/Opt-Secondary.txt

  • 順便說一句:在這些數(shù)據(jù)集中,主要基準(zhǔn)測試比次要基準(zhǔn)測試更重要,次要基準(zhǔn)測試包括壓力測試、微基準(zhǔn)測試和其它不符合實際的代碼。

參考資料:

1.https://nnethercote.github.io/2023/07/25/how-to-speed-up-the-rust-compiler-data-analysis-assistance-requested.html

2.https://geo-ant.github.io/blog/2023/unsafe-rust-exploration/

3.https://nnethercote.github.io/2023/07/11/back-end-parallelism-in-the-rust-compiler.html

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2021-03-15 14:54:47

編譯器工具代碼

2010-02-02 17:08:26

Python靜態(tài)編譯器

2010-02-02 17:08:26

Python靜態(tài)編譯器

2023-08-22 08:00:00

編譯器開發(fā)RustOCaml

2020-12-01 10:56:37

Rust編程AWS

2010-01-13 14:35:10

Visual C++

2010-01-18 10:34:21

C++編譯器

2010-01-21 09:11:38

C++編譯器

2010-03-23 11:17:16

Python 動態(tài)編譯

2009-08-10 17:12:54

C#編譯器

2017-03-20 18:01:55

編譯器匯編

2013-03-29 10:02:37

編譯器語言編譯開發(fā)

2010-10-20 13:43:37

C++編譯器

2019-08-06 08:20:07

編譯器工具開發(fā)者

2010-09-16 15:57:25

Java編譯器

2010-03-02 10:55:47

Linux SkyEy

2022-03-28 10:25:27

前端文件編譯器

2009-08-06 14:59:36

C#編譯器

2011-05-18 11:06:25

java編譯器

2013-12-30 11:21:31

Go編譯器
點贊
收藏

51CTO技術(shù)棧公眾號