microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.85k stars 328 forks source link

Support IL trimming #2478

Closed mikebattista closed 1 month ago

mikebattista commented 2 years ago

Overview

Apps built with the Windows App SDK should have competitive disk footprint with other frameworks and platforms.

.NET apps that use the Windows App SDK implicitly depend on several large binaries:

This disk footprint is inherited whether you use APIs in these binaries or not, which can inflate even new projects to unreasonable levels relative to other frameworks. The cost is amplified when apps are published ReadyToRun which includes both IL and native code versions of the assemblies.

IL trimming is a feature of .NET that can remove or trim unused code from applications, drastically reducing their disk footprint. This is not supported currently due to gaps in WinUI and C#/WinRT, so apps must pay the full disk footprint cost.

The MAUI team did some analysis with IL trimming and found that their self-contained dotnet new maui template without trimming has an installation size of 111MB, while the same template with trimming has an installation size of only 63MB. ReadyToRun inflates the untrimmed template to 155MB, while ReadyToRun with trimming results in 118MB. When you consider the untrimmed disk footprint will be carried by every MAUI application on Windows, you can see the impact not trimming can have on Windows fundamentals. MAUI also trims on other platforms already, so not trimming is a competitive disadvantage on Windows.

Furthermore, IL trimming is a prerequisite for NativeAOT which is .NET 7's ahead-of-time compilation solution. NativeAOT boosts startup and runtime performance by compiling code ahead-of-time (compared to just-in-time with JIT) and is the expected replacement for .NET Native from UWP. Apps migrating from UWP/.NET Native to .NET 6 JIT have reported 2x degradation in startup performance in some cases. NativeAOT should mitigate those issues.

We should support IL trimming for the disk footprint benefits it brings as well as the runtime performance benefits it would enable via NativeAOT.

Developer Experience

The developer experience for enabling trimming should align with https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained. As of WinAppSDK 1.1, we do not yet support dotnet publish or the Publish... dialog, but we do support setting related properties in publish profiles (e.g. SelfContained). The minimum bar is that we support setting <PublishTrimmed>true</PublishTrimmed> in publish profiles. We should also strive to support dotnet publish and the Publish... dialog for a more consistent and flexible developer experience.

The .NET model today requires apps be self-contained to participate in IL trimming. In an ideal world, though, apps could choose to be framework-dependent on .NET while trimming out unused code from other binaries. In terms of .NET runtime libraries, a framework-dependent app will always have a lower disk footprint than a trimmed self-contained app.

Deliverables

hez2010 commented 2 years ago

Note that WinRT.Runtime in CsWinRT heavily relies on reflection to lookup types/ABI types during runtime, which makes it impossible to be trimming compatible. It leads to a huge trimming-incompatible Microsoft.Windows.SDK.NET.dll.

I used to do some investigation in my WinUI 3 app NativeAOT experiment (despite failure). Instead of using the Type.GetType("ABI." + type.FullName) and MakeGenericType stuff, a possible solution is to use an interface to connect the type with its ABI type so all types usage can be statically analyzed during compilation:

interface IWinRTImpl<T> { ... }
class SomeWinRTType : IWinRTImpl<ABI.SomeWinRTType> { ... }

And in my experiment, after NativeAOT the compiler only produced a 9mb single self-contained exe which is very promising (though it failed to run due to some necessary types got trimmed away).

AdamBraden commented 2 years ago

cswinrt link - https://github.com/microsoft/CsWinRT/issues/373

Balkoth commented 2 years ago

I think this is absolutely neccessary, as i have a taken winforms app to winui3 where the size of the resulting binary exploded from 700 Kilobytes to 44 Megabytes.

kant2002 commented 2 years ago

I would like that microsoft.windowsappsdk provide small change in buildTransitive\Microsoft.WinUI.AppX.targets to provide escape hatch for these who willing to play with NativeAOT and maybe contribute to CsWinRT Right now ILtrimming completely blocked, understandbly why. But if change blocking part to

<Target Name="ValidateNoPublishTrimmed" BeforeTargets="PrepareForBuild" 
    Condition="'$(PublishTrimmed)'=='true' and '$(_SuppressILTrimDisabling)' != 'true'">
  <Error Text="Publishing with IL trimming is not yet supported."/>
</Target>

so somebody extremely enthusiastic can try use WinUI in NativeAOT context without hacking MSbuild targets. That's similar to how WinForms and WPF block linking, since they are not ready yet for it.

dotMorten commented 2 years ago

@kant2002 just double-click the error in VS, and it'll take you right to this bit of code inside the nuget, and you can just delete it and save. That would enable you to locally "play" with trimming.

manodasanW commented 2 years ago

You can also try out WinAppSDK 1.2 preview 2 where that target should have been removed and IL trimming is now supported. Here is a pointer to the release notes that talks about it.

dotMorten commented 2 years ago

Curious if anyone actually got that to work? I’ve been unable to get a trimmed WinUI app published. Lots of trim warnings and ultimately build errors

JasonWei512 commented 2 years ago

I tried enabling trimming and now my app crashes on launch.

manodasanW commented 2 years ago

@dotMorten what are the build errors you are seeing? And what type of trim warnings are you seeing?

@JasonWei512 Have you been able to get a call stack and exception message for where you are seeing a crash or determine which type is causing the crash?

ocdtrekkie commented 2 years ago

Built a toy MAUI app with three textboxes and SQLite, and it is a whopping 300 MB (127 MB zipped) to set a couple values in a database. Meanwhile, I wrote a whole home automation system with WinForms and .NET Framework which fits in like a 7 MB zip file. I can't imagine MAUI being taken seriously as a development platform on Windows while this is an open issue. Hoping this makes it to stable channel really soon.

adamplonka commented 1 year ago

Curious if anyone actually got that to work? I’ve been unable to get a trimmed WinUI app published. Lots of trim warnings and ultimately build errors

I managed to make it run after some experimenting. First I set the following project properties:

   <PublishTrimmed>true</PublishTrimmed>
   <TrimMode>partial</TrimMode>

and published the project. It reduced the size of Microsoft.Windows.SDK.NET from 20334KB down to 351KB and Microsoft.WinUI from 6385KB to 1007KB. Then I recompiled the application normally and copied the trimmed files back into framework dependent version, it saved over 25MB from the app size and the application works normally. It's around 68MB self-contained with WindowsAppSDK or 48MB runtime dependent (sample project with DataGrid and settings page using Template Studio).

I couldn't make it run with full TrimMode; tried to play with TrimmerRootAssembly list but nothing works. Also it looks like the compiler doesn't see properly any of the components used in XAML. I guess a code generator could be used to workaround this and statically reference any components used. Anyway the size of improperly fully trimmed application is 67.2MB (70,503,216 bytes) and after partial trimming it's 67.6 MB (70,885,342 bytes). I guess it's not worth the hassle. 99MB for ready to run single file self-contained x64 (39.8 MB zipped), or 70MB for self-contained single-file x64 without aot (27.8 MB zipped), not so bad.

tipa commented 1 year ago

It's around 68MB self-contained with WindowsAppSDK or 48MB runtime dependent (sample project with DataGrid and settings page using Template Studio).

99MB for ready to run single file self-contained x64 (39.8 MB zipped), or 70MB for self-contained single-file x64 without aot (27.8 MB zipped), not so bad.

I don't know... A 70 MB "sample project with DataGrid and settings page" doesn't sound that great to me. And the fact that this was only achieved with some hacks makes it even worse. Given there seems to be zero activity on this issue, I will be sticking with UWP for much much longer than I hoped...

karmeye commented 7 months ago

How come trimming is not supported for framework-dependent deploys. A simple app produces lots of dlls that not half of it is used:

Screenshot 1

mominshaikhdevs commented 3 months ago

@mikebattista @codendone since https://github.com/microsoft/CsWinRT/issues/373 is closed, should this issue be closed too?