-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[Xamarin.Android] Performance decrease when compared with Xamarin.Forms #822
Comments
MAUI test app used in the tests |
This sounds exactly like the performance hit taken by using Microsfoft.Extensions.DependencyInjection package. The team are considering using an alternative DI container to circumvent this: #880 |
Is it possible for MAUI to depend only on This could be worth the effort if that's actually what's causing the performance issue. |
I'm not a big fan of DI, especially on mobile, but I realize it's a core design paradigm in XF/MAUI so it's here to stay. However, runtime detection of renderers (and other providers etc) in mobile apps makes for a large time and resource loss, because a mobile app is effectively frozen in time when it's installed. The app won't change unless it's reinstalled (for the most part - unless it downloads some assemblies/native libraries from the internet when it runs, which I hope no apps do) and so everything about it is known statically. Would it be possible to take advantage of .NET6 code generators on the build time to output code that tells MAUI everything it needs to know, so that it doesn't have to dynamically look on startup? |
They have looked into both options (other package and generators), but unfortunately the For a good discussion and performance metrics see dotnet/runtime#44432. My gut feeling is that they are trying to squeeze more performance out of the current design. David Fowler was speaking of 10x improvement for reflection, that must have an effect here... |
@AmrAlSayed0 quite some time ago I profiled Xamarin.Forms and the bulk of startup time was spent looking for types in assemblies that need to be registered. I haven't been able to profile MAUI yet (since .NET6 doesn't have a managed profiler for mobile that ships with it) but I will hopefully be able to do it soon. Dynamic DI involves a lot of I/O which is generally VERY slow on mobile (especially with the mid to low tier phones, but even high-end devices are blazingly very fast). Comparing Linux/Windows performance to mobile devices, thus, is not a good measure. Keep in mind that mobile devices want to first and foremost preserve the battery, so ideally they spend most time in as low power mode as possible. That means stepping down (and often turning off) CPU cores which are hot-plugged and stepped up only when needed (that's why mobile devices use the BIG.little architecture - they have a number of "slow" but low energy cores and a smaller number of high performance cores). This also includes power delivered to storage, WiFi, RAM, display etc. So when an application suddenly puts a demand for a large amount of I/O, the system needs to wake everything up and face the demand. If the application heavily uses threads and puts a real load on each thread, the system will have to wake up the CPU cores and crank their clocks up to meed the demand. All of this takes time and slows down, especially, application startup. Imagine a MAUI app that provides a notification service to the user. The app isn't running in the background, in fact, it might not be actually running most of the time - it wakes up only when some notification (or intent, on Android) is delivered and the application has to start in background. The simple MAUI app above takes around 1s to start, one with 5 more controls takes 1.5s. The startup performance is absolutely crucial also because it's the first impression of the end user about the app. It's crucial for a mobile app to
|
@rogihee MAUI is where breaking changes can, and should, happen but before it is released. NET6 is an opportunity to introduce breaking changes (and they are introduced) wherever it makes sense, like here. Also, source generators aren't the only option. It should be possible to introduce a post-build step (in the likeness of the managed linker) that runs over all the gathered assemblies and generates another assembly with the necessary information in as efficient form as possible (i.e. no LINQ, no parsing of strings, no reading of metadata, no reflection, no I/O etc). That single assembly is loaded at startup and its data accessed lazily. The data could be a serialized dictionary (binary serialization, no XML) or a simple array (less efficient, of course), or any other form of a data structure that's efficient to load (preferably in bulk) into memory and accessed quickly in a lazy manner. The generator could analyze the code that takes part in the startup (e.g. the main/launcher activity on Android), look which types are required for startup and prioritize that data (possibly putting it in a smaller, separate, data structure) so that the startup is faster. Even with more complexity involved in MAUI, there's no reason it has to be 5 times slower on startup than "pure" Xamarin.Android (which currently starts in around 300ms for a comparable application with one control and only slightly slower for a more complex app with a few controls) |
@grendello agree 100%, I have been chatting with the team in Discord and making this very point. |
I will hopefully be able to profile some MAUI samples soon and then we can see where it gets the hit |
Another idea for post-processing, a more complex one, is patching the application code after the build (e.g. with Cecil) so that references to the DI data are injected directly into the code (effectively replacing custom attributes). For instance (and I'm inventing it as I go because I don't know the specifics of MAUI code), whenever a renderer is needed instead of kicking off the DI registration run (e.g. with a call to I remember that Xamarin.Forms code had quite a few instances of dynamic platform checks, too ( |
If you use the new .NET5+ |
I've managed to get the new NET6 EventPipe profiler working with Xamarin.Android and profile the HelloMaui sample on a Pixel 3 XL device. The data is for a 64-bit Release build of the app. According to Android's displayed time, the app took 1.6s to start:
However, the above startup time is for the app when built with the Xamarin.Android property dotnet build -f net6.0-android \
/t:Install \
/bl \
/p:Configuration=Release \
/p:Enable64BitBuild=true \
/p:AndroidLinkResources=true \
/p:AndroidEnableProfiler=true In attachment you can find a zip with both the .nettrace and speedscope formatted data. The former can be loaded into Perfview on Windows, the latter can be opened in https://speedscope.app I haven't looked at MAUI code yet, but from looking at the "Sandwich" tab in https://speedscope.app, with data sorted in descending order on
All of the calls appear to be rooted in If there was a way of eliminating all of reflection use (and I imagine it's perfectly possible using code generated at build time) I think it should be realistic to achieve around 500ms startup time for MAUI (with plain Xamarin.Android startup time on Pixel 3 XL being around 300ms). |
For Invoke and CreateInstance calls, wouldn't the total time include the time spent inside the constructors themselves? There are a couple of low-hanging fruit that stood out in the stack trace:
|
Yes, it's very likely, but it can also include "backend" processing in e.g. XA runtime (type registration)
Yep, that should make a nice difference.
Yes and no. Internal filesystems are ext4 on Android, case-sensitive by default (ext4 supports case-insensitivity) but other filesystems may be e.g. |
The problem might also come from the new compiler, or android related libs and tools.
Now im still at xamarin, not maui but who knows maybe it's the same cause. UPDATE This was due to Visual Studio 22 Preview 17.2. After installing and recompiling in Visual Studio 22 17.1 everything went back to normal, app with DI without much lib assemblies starts in 2 secs! |
@taublast could you file a new issue with the problem you're facing here: https://github.com/xamarin/xamarin-android/issues This issue is more about tracking .NET MAUI performance. We're actively working on that. |
For updates on .NET MAUI performance, I have lots of numbers here: https://github.com/jonathanpeppers/maui-profiling The next preview TBA. |
MAUI is faster than Xamarin.Forms (especially in RC1 or newer), going to close this, thanks everyone! |
I recently tested Xamarin.Android NET6 performance to compare it with "legacy" Xamarin.Android. Two test applications use Xamarin.Forms and MAUI - a very simple layout with just a single Label, no resource dictionary. Unfortunately, MAUI appears to be approximately 100ms slower than Xamarin.Forms. Please take a look at the this gist which contains tables comparing performance of different apps (Xamarin.Forms and MAUI)
I plan to do some profiling of the MAUI app next week to find out where the most time is spent.
The text was updated successfully, but these errors were encountered: