網(wǎng)站制作NEWS
利用 PGO 提升 .NET 程序性能
.NET 6開始引入了PGO(Profile Guided Optimization),這是一種通過收集運行時信息來指導(dǎo)JIT如何優(yōu)化代碼的技術(shù)。相比之前沒有PGO的情況,現(xiàn)在可以完成更多以前難以完成的優(yōu)化。
為了測試.NET 6中的PGO,我們使用了nightly build版本6.0.100-rc.1.21377.6。
.NET 6提供了靜態(tài)PGO和動態(tài)PGO。靜態(tài)PGO通過工具收集profile數(shù)據(jù),然后應(yīng)用到下一次編譯中,指導(dǎo)編譯器進行代碼優(yōu)化;動態(tài)PGO則直接在運行時收集profile數(shù)據(jù)并進行優(yōu)化。此外,從.NET 5開始引入了OSR(On Stack Replacement),可以在運行時替換正在運行的函數(shù),允許將低優(yōu)化代碼遷移到高優(yōu)化代碼。
.NET從Core 3.1開始引入了分層編譯,程序啟動時JIT首先快速生成低優(yōu)化的tier 0代碼,隨著程序運行,對多次調(diào)用的方法進行再次JIT產(chǎn)生高優(yōu)化的tier 1代碼。然而,這樣做對于程序的性能幾乎沒有提升,只是改善了延時。因此,在開發(fā)客戶端類程序時通常關(guān)閉分層編譯,而在開發(fā)服務(wù)器程序時開啟分層編譯。.NET 6引入PGO后,分層編譯的機制變得非常重要。
由于tier 0的代碼是低優(yōu)化代碼,因此更能夠收集到完整的運行時profile數(shù)據(jù),指導(dǎo)JIT做更全面的優(yōu)化。例如,在tier 1代碼中,某方法B被某方法A內(nèi)聯(lián),運行期間多次調(diào)用方法A后收集到的profile將只包含A的信息,而沒有B的信息;又例如在tier 1代碼中,某循環(huán)被JIT做了loop cloning,那此時收集到的profile則是不準確的。
為了發(fā)揮PGO的最大效果,我們需要開啟分層編譯,并給循環(huán)啟用Quick Jit在一開始生成低優(yōu)化代碼。
下面通過一個測試代碼的例子來說明如何使用.NET 6的PGO。
測試環(huán)境:不使用PGO,關(guān)閉分層編譯,使用動態(tài)PGO,使用靜態(tài)PGO + AOT編譯。
測試結(jié)果顯示,啟用PGO后,性能得到了顯著提升,性能提升幅度達到了322%。
總結(jié):有了PGO之后,之前的很多性能經(jīng)驗就不再有效。借助PGO,我們可以預(yù)見大幅度的執(zhí)行效率提升。在后續(xù)版本中,.NET將會帶來更多基于PGO的優(yōu)化。
多重隨機標簽