-
Notifications
You must be signed in to change notification settings - Fork 128
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 BlazorWeather app is slow #2089
Comments
I suspect this is due to the new dataflow/diagnostics work but didn't validate that. /cc @vitek-karas |
Still no luck trying to repro this on Windows. I was able to build Trying to run the command line from the repro: error MSB4057: The target "Run" does not exist in the project. I also tried running a simple console app to maybe determine if this is a wider non-MAUI related issue. By default linker takes almost 2000ms to run:
Can't tell if "skip" is the mode used by Maui here though. If we can confirm that, I will look into why linker takes 700ms to run in that mode. Would it be possible to get the msbuild binlog for the run where linker is actually used? |
I had to add |
Thank a lot Filip. Still can't make it work on Windows (it builds but I don't see any linker invocation anywhere). But the binlog you sent helps a lot. The linker is running in the "copy" mode for all assemblies ( It still doesn't fully explain the 67 seconds runtime in the MAUI case though. I will have to play with that a little bit more. It's also true that the MAUI invocation is running some custom steps which might add to the runtime. It's unclear to me why MAUI enforces full copy mode on all assemblies in this case. |
There are custom steps for sure. The |
Thanks Filip. I was writing it down here more as a "documentation" of what's going on. I don't know if we can turn off the expensive analysis though. Even if all assemblies are "copy" the analysis might still add more assemblies which would otherwise be removed from the output. So from a correctness perspective most of the analysis still has to happen. But I guess we could try to disable parts which don't have a way to expand the assembly closure. |
It's non-trivial to untangle which of the custom steps may have some dependencies on the analysis. Doesn't the new data flow analysis only reduce the possible assembly closure as opposed to expanding it? If there's any data that I can gather I'd be happy to do so. The MSBuild log was generated with the shipped .NET 6 P4 but it would likely make sense to retry running it with P6 once all repositories branch and get the dependencies. Notably xamarin/xamarin-macios#11739 changed how the custom steps are called which may result in slightly different data. |
In most cases the data flow should make linker more precise, but it also started to recognize patterns which linker didn't know about before. For example it now correctly handles @sbomer for comments on the interactions between full copy mode and the new custom steps. |
Thanks for explanation. In the "Don't link" mode of Xamarin.iOS (which results in |
It sounds like running the linker is necessary even with I took a look at how this works with the legacy macios linker with
So one difference is that the legacy linker wouldn't set all assemblies to More importantly, the legacy linker doesn't even run Some possible ways we may be able to fix this:
|
A consequence of this seems to be that running the linker on an assembly can actually make the app larger... and then you run into a different correctness issue: the app might require the linker to run, to pull any additional assemblies into the app. For Apple platforms (iOS, tvOS, Mac Catalyst, macOS), I believe we can say that this is not something we need to support, we can require that all assemblies must be passed to the linker. |
@rolfbjarne what information you need to extract when running
How will the developers know they need to include an assembly manually in Debug mode? |
We need to:
If we run the static registrar (which is optional, but results in faster startup time), then the static registrar may need to inspect every assembly. It's not really feasible to limit exactly what the static registrar may or may not need to inspect.
I'm not sure I follow. I'm assuming that by Debug mode you mean that My point is that because user code such as
My suggestion is to disallow this scenario by asking the linker to not load any assembly the linker doesn't already know about. This way we get the same behavior between The end result here is that if the linker can assume that In other words, it's not wrong anymore to disable large parts of the analysis, like this statement says:
|
I'm not sure the
This is true, but it can only expand the closure up to the set of assemblies passed into it by the SDK. So the
When linking with trimming ( If the target doesn't support reflection, then in theory |
Ah ok, I thought it could expand it even further. That removes the concern I had about apps only working with the linker enabled.
I'm not quite sure I understand what you're saying here, but I believe you're saying that we have basically two options (with
In legacy Xamarin code we used option 2, and where "to be referenced by" meant either: a. An assembly reference. In .NET this has changed so that "to be referenced by" also means if there's a Is there any particular reason we can't go with what we do in legacy Xamarin? |
Is any of the illinker logic required in this special mode? It kind of feels like all of the logic we are talking about (computing stuff to pass to native linker) should actually be done by the AOT compiler (that's the one producing outputs for the native linker), but nobody wants to write that logic in C and ILLinker was a convenient place to put it in - "we have a C# app looking at all the assemblies, so we can make it do other stuff too". I kind of like Sven's option 3 - if we're not trimming, illinker should not run and if Xamarin has steps it still needs to run, maybe a small C#-based host that lets the custom steps execute would be a good way out without having to twist illinker arms to suppress behaviors its designed to do. |
Yup, thanks for laying it out so clearly. More specifically, option 2. (Prune assemblies that aren't referenced...) is only correct if we do handle I was also trying to point out that even if we are ok with ignoring 2.1 Prune assemblies that aren't referenced directly, keeping 2.1 could significantly improve perf (especially for small apps) compared to marking the whole universe like we do today, but still wouldn't get us to the legacy behavior. (Maybe worth measuring if we're ok with the correctness issue?) My point is that whether or not we prune references, we may need some way to avoid marking the kept assemblies.
I see two: 1. the correctness concern around not seeing |
Trying this on RC1 but I had a few (mostly fixed) issues.
@danroth27 any clue ? |
@sbomer @marek-safar are there been any updates on this from the your side? IIRC last we talked you were going to look at it and see if you could come up with something. |
I have a "hacky" solution here: https://github.com/vitek-karas/linker/tree/DisableMarkingOfCopyAssemblies On a Windows console hello world with "copy" action on everything:
|
@vitek-karas would it be possible to get packages with those changes somehow? |
Hmm - if the "solution" (as in relying on "copy" on everything and using the command line mentioned above) works for you, I think we could merge it into the product. Which branch do you rely on |
@vitek-karas We're still tracking |
I tried this, and the improvement is pretty substantial for a simple hello-world app: it went from building in 19s to 7.5s I think this is good to go in now :) |
Perfect - thanks a lot! Created #2370 to adds this to 6.0.2xx. If we need it sooner we can try that as well, once it's merged. |
@vitek-karas this fix doesn't seem to be in 6.0.2xx, as far as I can tell, #2370 went into your main branch, which is .NET 7.0. The 6.0.2xx release is using your release/6.0 branch: https://github.com/dotnet/installer/blob/38a612150c53bbadffce67143067cabeab6e2f9c/eng/Version.Details.xml#L138-L143 |
#2437 is the port of this to release/6.0.2xx branch. We will have to change the flow to get the dotnet/linker/release/6.0.2xx branch be the one which is picked by the release/6.0.2xx branch in the SDK/installer repo. |
The linker commit mentioned here: https://github.com/dotnet/sdk/pull/23303/files (5b33e3a) is a commit from main, not the release/6.0.2xx branch. Is that intentional? |
@agocke - did we set up DARC correctly? |
I think it was a commit from the 6.0.2xx branch, just with the wrong version number. Either way, the latest commit from SDK looks like it has the right version, and it was just merged a few hours ago: dotnet/sdk#23330 |
…don't link' scenario. (#14011) This speeds up builds significantly when the linker is disabled. Test case: building tests/dotnet/MySimpleApp for macOS. * Before: 37s * After: 9s * Difference: 26s (4x faster) Test case: run the .NET tests * Before: 2h55 * After: 1h43 * Difference: 1h12 (1.7x faster) Contributes towards #10251. Ref: dotnet/linker#2089
Repro:
dotnet build BlazorWeather.Maui -t:Run /bl
For me, the linker takes ~20 seconds:
For other people (with different hardware), it can be much worse:
This is a "don't link" scenario (
LinkMode=None
), so it shouldn't take this long.The text was updated successfully, but these errors were encountered: