主頁 > .NET開發 > dotnet 使用 Crossgen2 對 DLL 進行 ReadyToRun 提升啟動性能

dotnet 使用 Crossgen2 對 DLL 進行 ReadyToRun 提升啟動性能

2022-06-21 09:45:37 .NET開發

我對幾個應用進行嚴格的啟動性能評估,對比了在 .NET Framework 和 dotnet 6 下的應用啟動性能,非常符合預期的可以看到,在用戶的設備上,經過了 NGen 之后的 .NET Framework 可以提供非常優越的啟動性能,再加上 .NET Framework 本身就是屬于系統組件的部分,很少存在冷啟動的時候,大部分的 DLL 都在系統里預熱,啟動性能方面,依然是 .NET Framework 比 dotnet 6 快非常多,而在破壞了 .NET Framework 的運行時框架層的 NGen 之后,可以發現 .NET Framework 的啟動性能就比不過 dotnet 6 的啟動性能,為了在 dotnet 6 下追平和 .NET Framework 的啟動性能差異,引入與 NGen 的同等級的 ReadyToRun 用來提升整體的性能,本文將告訴大家如何在 dotnet 6 的應用里面,使用 Crossgen2 工具,給 DLL 生成 AOT 資料,提升應用啟動性能

我預計本文是具有時效的,各個概念都在變更,本文是在 2022.05 撰寫的,如果你閱讀本文的時間距離本文撰寫時間過長,那請小心本文過期的知識誤導

開始之前,還請理清一下概念

在 dotnet 里面,這些概念都在變來變去,還沒有完全定下來,在聊 dotnet 里面的 AOT 之前,是必須先來做一個辟謠的,第一個謠言是 AOT 意味著性能更高? 其實不然,采用 AOT 能減少應用啟動程序中,從 IL 轉換為本機代碼的損耗,但通過分層編譯(TieredCompilation)技術,這部分的差異不會特別特別大,再加上 dotnet 6 引入 的 QuickJit 技術,還能進一步縮小差距,但即使這么說,啟動性能方面,采用 AOT 還是很有優勢的,因為啟動程序是性能敏感的,再加上大型專案在啟動程序中將需要執行大量的代碼邏輯,即使 JIT 再快和加上動態 PGO 的輔助下,依然由于需要作業的量太多而在性能上不如采用 AOT 的方式,由于 AOT 是生產靜態邏輯,只取平臺最小集,而無法和 JIT 一樣,根據所運行設備進行動態優化,這就是為什么運行程序中的性能,在 JIT 進入 Tier 2 優化之后的性能要遠遠超過 AOT 的方式,換句話說,全程都使用 AOT 而不加入任何 JIT 只是提升啟動性能,但是降低了運行程序的性能

那如果我啟動性能也要,運行程序的性能也要呢?這個就是 ReadyToRun 技術的概念了,在 DLL 的進入呼叫時,先采用 AOT 技術,將部分邏輯預先跑了 JIT 且將跑了之后的二進制邏輯也記錄到 DLL 里面,如此可以實作在首次呼叫方法時,減少 JIT 的戲份,盡可能使用之前 AOT 的內容,從而提升應用啟動性能,而在應用跑起來之后,依然跑的是 JIT 的優化,如此即可兼顧啟動性能和運行程序的性能

如何實作 ReadyToRun 這個概念?就需要用到幾項技術和工具,其中 Crossgen2 就是進行 ReadyToRun 的工具,通過 Crossgen2 工具,可以對 DLL 進行靜態 AOT 編入 DLL 內

但是如此做法也不是沒有缺點的,那就是額外編入 DLL 的 AOT 的內容,將會增大 DLL 的體積,而 DLL 體積的增大將會降低啟動程序中讀取檔案的性能,再加上 AOT 和 JIT 程序的切換也是需要判斷邏輯,加上了這部分損耗之后,再對比一下 QuickJit 技術,實際上采用 Crossgen2 進行 ReadyToRun 不是對所有的 DLL 都能提升啟動性能

為了解決以上問題,在 dotnet 里再引入了 PGO 的概念,啟動程序里面呼叫的方法是有限的,如果可以了解到應用啟動程序將會呼叫哪些方法,只是將這部分方法進行 AOT 那么對 DLL 體積的影響將會小非常多,這就是 PGO 需要解決的問題,通過引入 PGO 這個概念,在應用運行程序里面,了解應用啟動程序將會碰到哪些 IL 邏輯,將這部分邏輯記錄下來,用于指導 ReadyToRun 程序進行 AOT 哪些方法,從而讓 AOT 程序不需要針對所有的 IL 邏輯,而是僅對應用啟動程序需要用到的才進行 AOT 程序,如此即可更大的提升應用的啟動性能,不過 PGO 可以做的事情可不只是 ReadyToRun 的指導,還可以作為 JIT 程序中,讓 JIT 了解可以預先在后臺執行緒里面跑哪些 IL 轉換從而達到更高的啟動性能,必須說明的是,我詢問了幾位大佬了解到,當前的 PGO 還是一個玩具,雖然性能評測上可以達到很好的效果,然而還沒有具備發布環境使用的能力

對于 AOT 不可反編譯的辟謠,如勺ò干以看到 ReadyToRun 技術上,依然是保留 IL 邏輯,只是在 DLL 里面再加入 AOT 生成的二進制資料,從而減少啟動程序的 JIT 的損耗,也就是說如果采用 ReadyToRun 的技術,可以讓應用有更快(不一定是更快)的啟動性能,同時也擁有原本的運行程序的性能,但是否可以做到不可反編譯,自然是做不到的,原本的 IL 代碼依然還在,也就是說采用 ReadyToRun 技術,沒有任何額外的保護能力,那第二個問題,如果采用純 AOT 技術,能否達到代碼保護能力?嗯,能加一點點,如果配合上混淆的話,感覺上是差不多了,如果要說防破解能力的話,兩個的打分,一個是 60 分,一個是 70 分,滿分是 100 分,真要別人看不懂,代碼寫垃圾些就好了,我全力發揮的時候,保證連自己都看不懂

回到主題,如何在 dotnet 里面通過 Crossgen2 工具進行 ReadyToRun 提升應用性能? 千萬別被官方騙了,如果只是在 csproj 上或者是在發布的時候加上 ReadyToRun 的命令引數,恭喜你,是真的用了 Corssgen2 工具,但優化呢?只是優化了入口程式集而已

真的想要有比較大的優化,是需要將除了入口程式集之外的其他程式集也通過 Crossgen2 工具進行 ReadyToRun 才可以有比較大的提升的,例如我的一個大型應用,在啟動程序里面將 WPF 框架里面大概十分之一的模塊都碰了一次,使用 JitInfo.GetCompiledMethodCount 了解到,在第一個視窗 Show 出來之前就有 5 萬個方法呼叫,這個應用的入口程式集占比太小了,如果使用官方的方法,只是對入口程式集進行 ReadyToRun 那么性能上還真被 .NET Framework 完虐

為了讓 dotnet 6 應用的啟動性能能媲美 .NET Framework 應用的啟動性能,可以采用 ReadyToRun 對標 .NET Framework 的 NGen 技術,以下將告訴大家如何使用 Crossgen2 工具對 DLL 進行 ReadyToRun 提升啟動性能

默認的 Crossgen2 工具是采用 NuGet 分發的 DotnetPlatform 型別的 NuGet 包,里面包含了獨立發布的 Crossgen2 工具,換句話說,可以在 %localappdata%\..\..\.nuget\packages\microsoft.netcore.app.crossgen2.win-x64 找到此工具,如果沒有找到的話,那試試用一句 dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true 命令讓 dotnet 為了構建 ReadyToRun 而幫你將 Crossgen2 下載

以上的 Crossgen2 工具放在 microsoft.netcore.app.crossgen2.win-x64 檔案夾里面,這里的 win-x64 指的不是 Crossgen2 工具的能力,不是說這個檔案夾的工具只能構建出 win-x64 的,而是說這個工具本身是 win-x64 的,這個工具是能構建出其他的平臺的 AOT 的,換句話說是在 Windows 的 32 位系統里面,將會拉的工具是 microsoft.netcore.app.crossgen2.win-x86 的包

進入版本號檔案夾,再進入 Tools 檔案夾即可找到 Crossgen2.exe 可執行檔案,這就是工具本文,例如在我的設備上的工具路徑是

C:\Users\lindexi\.nuget\packages\microsoft.netcore.app.crossgen2.win-x64\6.0.5\tools\Crossgen2.exe

接下來將告訴大家如何使用這個工具

這個工具的使用需要傳入的引數推薦是一個 rsp 檔案,大概的命令列呼叫如下

C:\Users\lindexi\.nuget\packages\microsoft.netcore.app.crossgen2.win-x64\6.0.5\tools\Crossgen2.exe "@C:\lindexi\Fxx\F1.rsp"

具體的引數都放在 rsp 檔案里面,大概內容如下

--targetos:windows
--targetarch:x86
--pdb
-O
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-console-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-console-l1-2-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-datetime-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-debug-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-errorhandling-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-fibers-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-file-l1-1-0.dll"
-r:"C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\6.0.5\api-ms-win-core-file-l1-2-0.dll"
--out:"C:\Users\linde\AppData\Local\Temp\Crossgen2\Crossgen2\KokicakawheeyeeWhemhedawfelawnemhel.dll"
C:\lindexi\Code\empty\KokicakawheeyeeWhemhedawfelawnemhel\KokicakawheeyeeWhemhedawfelawnemhel\bin\release\net6.0-windows\win-x86\publish\KokicakawheeyeeWhemhedawfelawnemhel.dll

大概由以下幾個部分組成,每一行都是一個獨立的引數,分別內容如下

  • --targetos:windows: 準備執行的系統平臺,進行 ReadyToRun 將生成 AOT 代碼,這是平臺強相關的,必須說明是哪個平臺
  • --targetarch:x86: 準備生成的對應平臺,是 x86 還是 x64 等
  • --pdb: 這是可選的,表示要生成 PDB 符號檔案,如不加上這一句將不生成 PDB 檔案,生成的 PDB 檔案是 ni.pdb 檔案,配合原本的 DLL 的 PDB 檔案即可方便進行除錯
  • -O: 這是可選的,表示需要進行優化,相當于 Release 版本,推薦默認都加上,否則將幾乎沒有優化效果,或者說只有反向優化效果
  • -r:"xxx.dll": 這里將會重復很多行,一行一個程式集檔案的本地路徑,讓工具了解到有哪些參考可以去找到,工具在準備 AOT 程序,需要找到所參考的程式集,這些引數就是告訴工具對應的程式集放在哪,可以多加入很多程式集,因為只是給工具使用的參考參考,工具會根據自己的需求,去找到對應的程式集檔案,如果工具發現傳入的有多余的,那將會自動忽略多余的,推薦將整個 dotnet runtime 都加入,但是要注意加入的版本必須是和發布的版本是一致的,否則啟動程序如果炸了,那就涼涼,如果應用是獨立發布的,那就列出應用獨立發布檔案夾里面的所有 DLL 檔案,不需要加上額外的運行時檔案夾
  • --out:"xx.dll": 處理之后的輸出檔案路徑
  • xxxxx.dll 輸入程式集的路徑

構建出 rsp 檔案,作為引數,呼叫 Crossgen2 工具,即可完成對程式集的 ReadyToRun 程序,多個程式集就多次重復以上程序即可

必須畫重點的是,呼叫 Crossgen2 工具進行 ReadyToRun 是不一定能提升啟動性能的,這是一個需要測量的程序,每個 DLL 在呼叫了 Crossgen2 工具進行 ReadyToRun 是會修改檔案體積的,整個變更也是會影響啟動性能的,推薦在優化應用啟動性能,進行足夠的測量,方法如下

使用 Crossgen2 工具對每個 DLL 來一次,包括框架層的 DLL 也來一次,然后逐個 DLL 替換,測量應用啟動性能,如果發現某些 DLL 進行了 ReadyToRun 反而降低啟動性能,或者某些 DLL 加大的檔案體積對比啟動性能的優化來說不劃算,那就不對這些 DLL 進行優化

以下是測驗的對 dotnet runtime 底層和 WPF 框架的 DLL 進行 ReadyToRun 優化之后,對 walterlv 大佬的某個應用的啟動性能的影響,值得一提的是對于不同的應用,測驗的資料將會存在很大的出入,核心原因在于不同的應用啟動程序將訪問的模塊有所不同

這個資料是沒有多少參考價值的,因為對于不同的應用來說,以上的結果將會有變化,如果你想要采用 ReadyToRun 技術提升應用啟動性能,還請必須測量每個 DLL 在經過 ReadyToRun 對啟動性能的影響,如果你的時間充裕的話,還可以測量對多個 DLL 優化的組合對啟動性能的影響

我所在團隊的某個大型應用,在經過了 ReadyToRun 技術的優化,啟動性能提升百分之三十

但也必須說明的是,不是所有的應用使用 ReadyToRun 都能有優化啟動性能,例如我的一個小應用,只要采用了 ReadyToRun 技術,啟動性能基本上都是降低了,總的來說,采用 ReadyToRun 技術是需要進行性能測量的

參考檔案

WPF dotnet 使用本機映像 native 優化 dotnet framework 二進制檔案

WPF 通過 ReadyToRun 提升性能

Conversation about crossgen2 - .NET Blog

runtime/crossgen2-compilation-structure-enhancements.md at main · dotnet/runtime

runtime/Program.cs at main · dotnet/runtime

編譯配置設定 - .NET Microsoft Docs

ReadyToRun deployment overview - .NET Microsoft Docs

利用 PGO 提升 .NET 程式性能 - hez2010 - 博客園

JitInfo.GetCompiledMethodCount(Boolean) Method (System.Runtime) Microsoft Docs

博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

知識共享許可協議
本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/493767.html

標籤:.NET技术

上一篇:國內外組態軟體對比分析(InTouch、WinCC、iFix、iNeuOS)

下一篇:如何將陣列物件變成物件?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more