Closed halgari closed 8 months ago
I'm currently unable to reproduce with any of the following:
dotnet publish -c Release
dotnet publish -c Release -p:PublishReadyToRun=true
dotnet publish -c Release --self-contained
dotnet publish -c Release --self-contained -r win-x64
dotnet publish -c Release --self-contained -r win-x64 -p:PublishSingleFile=true
dotnet publish -c Release --self-contained -r win-x64 -p:PublishSingleFile=true -p:PublishReadyToRun=true
On either Windows or Linux.
Note: There are some publishing bugs:
Consider running git clean -xdf
between runs when testing these things
After building, I observe 2-4s delay in process creation (8s on a laptop), on Windows only:
I have identified it as hostile interference from Windows Defender.
It seems to halt startup:
I also replicated our CI setup as a sanity test.
dotnet tool install -g KuiperZone.PupNet
pupnet -y -k zip -p DefineConstants=INSTALLATION_METHOD_ARCHIVE
Our publish settings: https://github.com/Nexus-Mods/NexusMods.App/blob/75e7bf5948cc427286220b920ed4781eb07b340c/src/NexusMods.App/app.pupnet.conf#L32
Not sure why our settings have TieredCompilation=true
, it's redundant as TC has been on by default since .NET Core 3.0.
In any case, no issues with our CI setup.
I noticed the native .NET Runtime components are not in the output folder, i.e. clrgc.dll
and friends in single file builds.
In previous versions of .NET, these DLLs would be extracted to disk before being used if they are embedded (controlled via IncludeNativeLibrariesForSelfExtract
.csproj property). They would extract to %temp%/.net
.
Something probably changed regarding this in .NET 8
. So I did what any reasonable person would do (whipping out IDA, of course 😉). Anyway, turns out that the Runtime now uses a version of SingleFileHost (<= bootstrapper that runs SingleFile .NET Apps) with the native dependencies statically compiled, avoiding separate DLLs.
When investigating, I also considered what kind of differences there might be hardware wise between your machine, the Razer Blades at the office and what I have at home.
I figured the culprit might have been AVX512, so I kindly borrowed my elders' laptop (the only AVX512 machine in my household) to give it a go. I could not reproduce it there either; with all combinations.
~0.4s
Scenario | Time |
---|---|
No R2R | 1.5s |
R2R | 0.9s |
(There's also some additional process creation overhead, which is longer on Windows than on Linux, but that's kind of hard to even eyeball measure)
Assuming no interference from Defender of Background load. Assuming Single File, as multi-file performance is hard to predict (random reads are much more unpredictable than sequential).
R2R Self Contained:
Scenario | Time |
---|---|
NVMe | 0.09s |
SATA SSD | 0.64s |
HDD | 1.50s |
No R2R Self Contained:
Scenario | Time |
---|---|
NVMe | 0.05s |
SATA SSD | 0.30s |
HDD | 0.72s |
Bug Report
Summary
I've noticed some very bad startup times on the app, even during the sprint demo a few weeks back. I've replicated this locally by not publishing with
PublishReadyToRun
, or forgetting the-r <arch>
flag. We should verify that all this is being set correctly and that we are also using--self-contained
so that we don't require users to install .NET 8.0Steps to reproduce
Run the app with a normal publish command, and then again with the above flags. Startup times go from 20sec without those flags to .5 seconds with them.