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

我對幾個應用進行嚴格的啟動性能評估,對比了在 .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 大佬的某個應用的啟動性能的影響,值得一提的是對于不同的應用,測試的數據將會存在很大的出入,核心原因在于不同的應用啟動過程將訪問的模塊有所不同

02ee4f4e593262a63a289e86b3033955.png

這個數據是沒有多少參考價值的,因為對于不同的應用來說,以上的結果將會有變化。如果你想要采用 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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285531.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285531.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285531.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用myeclipse建立maven項目(重要)

maven是管理項目的,myeclipse是編寫代碼的。第一次寫項目都要配置好多東西,很麻煩,now 來看看怎樣新建一個maven項目。 工具/原料 myeclipsemaven方法/步驟 因為教程使用的maven是自己下載配置的,并沒有使用myeclipse自帶的&#…

LeetCode 每日一題 Day 22 || 枚舉(數學方法)/二分

1954. 收集足夠蘋果的最小花園周長 給你一個用無限二維網格表示的花園,每一個 整數坐標處都有一棵蘋果樹。整數坐標 (i, j) 處的蘋果樹有 |i| |j| 個蘋果。 你將會買下正中心坐標是 (0, 0) 的一塊 正方形土地 ,且每條邊都與兩條坐標軸之一平行。 給你…

不用@微信官網了,用python給自己的微信頭像加個小國旗

國旗LOGO(png透明格式): 微信頭像 合成結果: import base64 import os import re from io import BytesIO from PIL import Image import tkinter as tk from tkinter import filedialog# 水印圖片 可以自己指定 #markImageImage…

getContentResolver().query()方法selection參數使用詳解(轉)

如何在managedQuery()和getContentResolver().query()方法中實現結果去重 有時候,我們需要對查詢的數據庫結果進行去重。在SQL中我們可以通過distinct關鍵字實現,但是當我們使用android提供的managedQuery()或getContentResolver().query()方法對數據庫進…

C語言試題106之有一對兔子問題

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:有一對兔子,從出生后第 3 個月起每個月都生一對兔子,小兔子長到第三個月 后每個月又…

【C#程序設計】教學講義——第二章:簡單C#程序設計

教學目錄 2.1 面向對象的概念2.2 建立簡單的應用程序2.3 窗體和Label控件2.4 文本框-屬性2.5 按鈕控件本章小結2.1 面向對象的概念 2.1.1 對象和類 1.對象 對象是客觀世界中對象的模型化。對象是有著特殊數據(屬性)與操作(行為)的實體,對象的操作(行為)稱為方法。 程…

Blazor University (34)表單 —— 獲得表單狀態

原文鏈接&#xff1a;https://blazor-university.com/forms/accessing-form-state/獲得表單狀態源代碼[1]有時&#xff0c;我們需要獲得 <EditForm> 子內容中的表單狀態。最常見的用途是當我們需要訪問輸入的 CSS 類時&#xff0c;指示輸入是否被修改或有效/無效。例如&a…

[轉]c# 中間件 的擴展模型(.net webapi/.net Core 的 MiddleWare 處理模型)

在學習 asp.net WebApi 或者asp.net Core 的時候&#xff0c;它們管道的處理模型跟 asp.net MVC/WebForm 的管道模型是不一樣的。 asp.net WebApi 或者asp.net Core 他們使用了一種叫做“中間件”的處理模型&#xff0c;相對于傳統管道模型&#xff0c;剔除了很多非必要的處理…

AIX 環境下遇到Device Busy問題

IBM AIX v5.3操作系統環境下在對網絡或網卡進行操作過程中經常遇到"Device Busy"而終止操作例如:#rmdev -l ent1遇到如下返回信息Method error (/etc/methods/ucfgdevice):0514-062 Cant perform the requested function because the speciafield.device is busy. 解…

mykernel編譯過程中問題解決

fatal error: linux/compiler-gcc5.h: No such file or directorycompilation terminated.解決方法:https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/plain/include/linux/compiler-gcc5.h?id2c07053b8e1e0c22bb54dfbdf8e86a70f8bf00fc復制內容保存為c…

C#中的 Attribute 與 Python/TypeScript 中的裝飾器是同個東西嗎

前言最近成功把「前端帶師」帶入C#的坑&#xff08;實際是前端帶師開始從cocos轉unity游戲開發了&#xff09;某天&#xff0c;「前端帶師」看到這段代碼后問了個問題&#xff1a;[這個是裝飾器]&#xff1f;[HttpGet] public Response Get() {return ... }我第一反應覺得不是&…

【ArcGIS Engine二次開發】入門基礎(1):ArcGIS Engine簡介及開發環境搭建

文章目錄ArcGIS Engine概述ArcGIS Engine與ArcObjects的關系ArcGIS Engine下載及安裝ArcGIS Engine概述 ArcGIS Engine簡介 ArcGIS Engine是ESRI公司在2004年推出的用于開發C/S架構GIS應用軟件的工具包&#xff0c;是將用于構建ArcGIS整套產品的組件庫——ArcObjects的比分功…

微軟Visual Studio 2019版本16.3 正式發布,支持 .NET Core 3.0

微軟正式發布了Visual Studio 2019 16.3版本&#xff0c;主要更新內容如下&#xff1a; .NET Core 3.0 Visual Studio版本16.3包括對 .NET Core 3.0 的支持。 注意&#xff1a;如果使用的是.NET Core 3.0&#xff0c;則需要使用Visual Studio 16.3或更高版本。 .NET Core桌…

C語言試題120之輸入兩個正整數 m 和 n,求其最大公約數和最小公倍數

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:輸入兩個正整數 m 和 n,求其最大公約數和最小公倍數 分析:利用輾除法 2 、溫馨提示…

spring+springMvc+mybatis 調用oracle 存儲過程

最近在項目中遇到在mybatis中調用oracle存儲過程的問題&#xff0c;網上各種查詢&#xff0c;最終解決了問題&#xff0c;在我們項目中我只需要oracle 的存儲過程返回一個字符串用來存入數據庫作為表數據的主鍵&#xff0c; 接下來整理代碼&#xff1a; 首先構建存儲過程getSeq…

OSChina 周一亂彈 ——致我們終將逝去的青春

2019獨角獸企業重金招聘Python工程師標準>>> 我們的青春是這樣的。 從幼兒園午睡開始&#xff0c; 做了一萬遍的廣播體操&#xff0c; 一條充滿了“血”和“淚”的三八線 遍地開花的煎餅果子攤 五毛錢只能養活三天的小雞 象征著財富和地位的彈珠 放學后 奔向世界 放…

【ArcGIS Engine二次開發】入門基礎(2):ArcGIS開發方式(VBA、DLL、Add-in、Engine)對比

文章目錄2.1 使用VBA進行桌面軟件開發2.1.1 VBA開發方式2.1.1 VBA代碼的安全性2.2 使用DLL進行桌面軟件開發2.2.1 DLL開發方式2.2.2 DLL功能的應用部署2.3 使用Add-in進行桌面軟件開發2.4 使用ArcGIS Engine構建獨立應用程序對于桌面GIS應用來說&#xff0c;ArcGIS平臺不僅提供…

使用.Net驅動Jetson Nano的OLED顯示屏

背景最近幾年&#xff0c;邊緣計算的需求急劇爆發。人工智能、物聯網和 5G 的演進給邊緣計算帶來了無限的可能性。因為工作原因&#xff0c;有幸在2019開始接觸了英偉達 Jetson 家族的各種邊緣計算設備&#xff1a;Nano&#xff0c;TX2&#xff0c;AGX&#xff0c;NX等&#xf…

工程測量不用愁,120個視頻動畫幫你忙,簡單易學直觀明了!

工程測量不用愁,120個視頻動畫幫你忙,簡單易學直觀明了!文末提供下載地址。

2016-2017-2學期《程序設計與數據結構》教學進程

2016-2017-2學期《程序設計與數據結構》教學進程 目錄 考核方式課前準備教學進程 第00周學習任務和要求第01周學習任務和要求第02周學習任務和要求第03周學習任務和要求第04周學習任務和要求第05周學習任務和要求第06周學習任務和要求第07周學習任務和要求第08周學習任務和要求…