Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trimming Support #3767

Open
CasualPokePlayer opened this issue Sep 8, 2023 · 6 comments
Open

Trimming Support #3767

CasualPokePlayer opened this issue Sep 8, 2023 · 6 comments
Labels
App: EmuHawk Relating to EmuHawk frontend Meta Relating to code organisation or to things that aren't code Request: Feature/Enhancement For feature requests or possible improvements

Comments

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented Sep 8, 2023

Something to look at wrt .NET6 (see #1415). One benefit of .NET6 is the ability to do a "self-contained" build which packs in all the framework and runtime (so no need for a prereq installer) (see also #1415). This however makes the build much larger. One way to reduce this size is to enable trimming, which removes unused code. (perhaps this might even give us an overall size reduction compared to a framework deployed build?)

However, trimming comes with several limitations:

  • Blocked by single-file publishing
  • Built-in COM marshalling
    • Only used directly in BizHawk.Common, in ShellLinkImports.cs, Win32Imports.cs, and Win32ShellContextMenu.cs. No longer used since 4980725
    • Maybe used in some deps wrapping around DirectX APIs? (DirectSound/XAudio2/DirectInput/XInput/Direct3D9?)
      • DirectSound and Direct3D9 use SharpDX, which targets netstandard1.3/net40/net45, so wouldn't be compatible with trimming in the first place (although it doesn't seem to use built-in COM marshalling, so it probably would work if we just decided to fork it and compile it under net6.0).
      • DirectInput, XInput, and XAudio2 use Vortice.Windows. The version we currently use (2.4.2) targets netstandard20 /net6.0 (although the 3.x versions just target net7.0/net8.0), so it doesn't have that problem. It appears to not use built-in COM marshalling for the most part, but it does seem to use ComImport for IMMDeviceEnumerator (although it doesn't actually have any functions and its only usage is only for using the class's GUID to pass it onto CoCreateInstance, so it might just work regardless?)
    • WinForms uses COM marshalling heavily so WinForms projects can't be trimmed (BizHawk.Client.EmuHawk and BizHawk.Bizware.Graphics.Controls). See Epic - Make WinForms trim compatible dotnet/winforms#4649. Another reason to move away from WinForms.
  • WPF
    • Not used by BizHawk, but something to keep in mind when looking for WinForms alternatives, as some might just wrap around WPF on Windows (e.g. Eto), and so can't be trimmed.
    • Similarly we might not want to use UI frameworks which wrap around WinForms on Windows for the same reason.
  • Reflection
    • Reflection itself can often be made compatible with trimming, although we probably want to move away from reflection wherever possible.
    • Serializers (i.e. Newtonsoft.Json) often can't be made compatible however, but it should be easy enough to move to source generator alternatives (i.e. System.Text.Json).
  • Dynamic assembly loading and execution
    • i.e. External Tools, so we can't have External Tools if we do trimming?
    • Perhaps we could rework ApiHawk so it delivers APIs with any native library with a pre-defined C interface which allows them to receive APIs, making external tools language agnostic too (something native exports for .NET tools?)
    • Perhaps there's some workaround here? Can External Tools just package in the .NET framework/runtime code that they need? Would that create some conflict with BizHawk's own self contained framework/runtime code?
@YoshiRulz
Copy link
Member

YoshiRulz commented Sep 8, 2023

Worth noting that trimming is configurable; you can explicitly include symbols you know will be used.

I have some notes re: reflection, publishing/packaging, and Wasm.

@YoshiRulz YoshiRulz added Request: Feature/Enhancement For feature requests or possible improvements App: EmuHawk Relating to EmuHawk frontend Meta Relating to code organisation or to things that aren't code labels Sep 8, 2023
@Morilli
Copy link
Collaborator

Morilli commented Sep 10, 2023

WinForms projects can't be trimmed (BizHawk.Client.EmuHawk [...]

So this means it cannot be enabled AT ALL until we move away from winforms, right?

@CasualPokePlayer
Copy link
Member Author

I assume trimming can be controlled on a per project basis here? I assume regardless however we can't go enable AOT until the entirety of BizHawk is trimmable.

@Morilli
Copy link
Collaborator

Morilli commented Sep 10, 2023

Yeah I don't think trimming is gonna happen any time soon. Reflection is just one example of many patterns that are not compatible with trimming and are extremely hard to fix at the very least. If you haven't you could try to enable trimming on the .NET6 targeting branch and see how many errors you get.

CasualPokePlayer added a commit that referenced this issue Nov 15, 2023
…ostfix on relevant winapi functions/structs, put ExactSpelling = true for winapi functions.

We don't care for ANSI functions (no way somebody is going to run BizHawk on Windows 98/ME), and ExactSpelling = false (default) has a minor runtime cost, so this should be slightly more performant.
Also, replace ShellLink COM usage with custom COM interaction code. See #3767. The same is yet to be done for the two other COM usages.
@YoshiRulz
Copy link
Member

I tried adding

<EnableAotAnalyzer>true</EnableAotAnalyzer>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<TrimmerSingleWarn>false</TrimmerSingleWarn>

but it just gave me the NETSDK1210 "not supported for .NET Standard" warnings and nothing else. Not that I think it would have brought up anything actionable.

@CasualPokePlayer
Copy link
Member Author

CasualPokePlayer commented Jun 27, 2024

The trimming is somewhat weirdish. For each project you want to manually specify it in, you need to have at least .NET 6 targeted. However, in reality this isn't really needed per se (unless you're doing partial trimming and probably for warnings), since if you perform full trimming (the default), then specifying that for the exe project (assuming that is targeting .NET 6+) is enough for all assemblies used to be trimmed (even .NET Standard/.NET 5 and below ones).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
App: EmuHawk Relating to EmuHawk frontend Meta Relating to code organisation or to things that aren't code Request: Feature/Enhancement For feature requests or possible improvements
Projects
None yet
Development

No branches or pull requests

3 participants