dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.03k stars 1.73k forks source link

[Android] In debug the app is way way slower than in xf #20739

Open roubachof opened 7 months ago

roubachof commented 7 months ago

Description

I am currently doing the maui migration of an app running on a big but slow device for an important client. We have a big app running on a android device with tons of views. On XF it was slow, on MAUI it seems faster, but only when all the views are constructed, during the constructions of the views (meaning when the UI thread is loaded) it takes forever.

I am experiencing a very slow debugging experience in MAUI. In XF it wasn't great but with MAUI it's about 5x times slower.

The device is an old arm 32bits, a armeabi-v7a with 4 cores:

model name      : ARMv7 Processor rev 10 (v7l)
BogoMIPS        : 7.54
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x2
CPU part        : 0xc09
CPU revision    : 10

Here is the comparison of android studio cpu profiling for the same view:

This is the XF version:

image

This is the maui version:

image

We can see that maui is 8x times slower.

On XF we can see the dispatchMessage is short and some work is done each time.

On MAUI the dispatchMessage last forever and seem to be doing nearly nothing..

Is it something weird or maybe the way the looper and handlers are used in MAUI changed a lot compared to XF?

Steps to Reproduce

No response

Link to public reproduction project repository

No response

Version with bug

8.0.7 SR2

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

No response

Did you find any workaround?

I am developping in RELEASE mode :)

Relevant log output

No response

jfversluis commented 7 months ago

@jonathanpeppers ?

jonathanpeppers commented 7 months ago

@roubachof did you already review the section at the top of https://aka.ms/profile-maui?

Are you comparing Debug mode or Release mode?

roubachof commented 7 months ago

@jonathanpeppers yup, I have <UseInterpreter>false</UseInterpreter> in my csproj.

I'm comparing in DEBUG, in RELEASE performance between XF and MAUI are about the same.

jonathanpeppers commented 7 months ago

Did you record a .speedscope file to see what is slow?

roubachof commented 7 months ago

I tried but it makes the app crashes at the beginning...

jonathanpeppers commented 7 months ago

We are working on improving the Android docs here: https://github.com/xamarin/xamarin-android/pull/8713

ghost commented 7 months ago

Hi @roubachof. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

ghost commented 7 months ago

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. If it is closed, feel free to comment when you are able to provide the additional information and we will re-investigate.

roubachof commented 7 months ago

@jonathanpeppers I finally could make a successful speedscope file for our project startup \o/. Issue is: this is massive 300 meg. You can find it here: https://drive.google.com/file/d/1VF69PcyYRU-oO9q0G2d9yDmFlAcJXq6b/view?usp=sharing It's in DEBUG It takes 2 minutes to initialize 6 views (3 PodSourceView, 3 PodMeasureView), main thread seems to choke on this.

I made the same startup trace IN RELEASE, and it seems quite different. As I said earlier, in release we don't have any issue with the construction of the views, everything seems normal. https://drive.google.com/file/d/1UOL8bt3uVum3WzxVkI4wRCfqoBXmJtNo/view?usp=sharing It takes like 15 seconds to initialize our 6 big views (call to InitializeComponent).

Now, the big difference I am seeing is, in DEBUG, InitializeComponent seems to call a lot of XAML related stuff (LoadFromXaml, RootNode.Accept, etc).

image

Whereas in RELEASE there is no mention of XAML stuff:

image

Would it mean that it fails to compile XAML in DEBUG?

here is the Debug section of the csproj:

<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
    <TargetPlatformVersion>34</TargetPlatformVersion>
    <SupportedOSPlatformVersion>25.0</SupportedOSPlatformVersion>

    <AndroidKeyStore>true</AndroidKeyStore>
    <AndroidSigningKeyStore>POUET</AndroidSigningKeyStore>
    <AndroidSigningStorePass>POUET</AndroidSigningStorePass>
    <AndroidSigningKeyAlias>POUET</AndroidSigningKeyAlias>
    <AndroidSigningKeyPass>POUET</AndroidSigningKeyPass>

    <AndroidUseAapt2>true</AndroidUseAapt2>
    <AndroidAapt2LinkExtraArgs>--no-version-vectors</AndroidAapt2LinkExtraArgs>
    <MandroidI18n />

<!--    <TrimMode>partial</TrimMode>-->

    <RuntimeIdentifiers>android-arm</RuntimeIdentifiers>
    <RunAOTCompilation>false</RunAOTCompilation>
    <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
    <UseInterpreter>false</UseInterpreter>
  </PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(TargetFramework)|$(Platform)' == 'Debug|net8.0-android|AnyCPU' Or '$(Configuration)|$(TargetFramework)|$(Platform)' == 'Emulator|net8.0-android|AnyCPU' ">
    <AndroidEnableProfiler>True</AndroidEnableProfiler>
    <AndroidLinkMode>None</AndroidLinkMode>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>portable</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug</OutputPath>
    <DefineConstants>DEBUG;</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
    <DocumentationFile>bin\Debug\Triton.Instrument.Android.xml</DocumentationFile>
    <AndroidEnableSGenConcurrent>false</AndroidEnableSGenConcurrent>
  </PropertyGroup>

sensitive information has been poueted out. We have also [assembly: XamlCompilation(XamlCompilationOptions.Compile)] at the top of our MauiProgram.cs

jonathanpeppers commented 7 months ago

Would it mean that it fails to compile XAML in DEBUG?

Yes, XamlCompilation is off in Debug mode. I believe that might be a requirement for XAML Hot Reload to work.

The code that decides is:

https://github.com/dotnet/maui/blob/dabab4685883c0ab5dc956ed693523ccc598de00/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets#L150-L152

So you could try in your .csproj:

<_MauiForceXamlCForDebug>true</_MauiForceXamlCForDebug>
roubachof commented 6 months ago

YES! Now debug is acting normal again (few seconds to construct massive views). Thanks for your help, I will document that on my blog :)

developer9969 commented 6 months ago

@roubachof did you find it affected hot reload by any chance with this setting on? thanks

jonathanpeppers commented 6 months ago

@roubachof did you find it affected hot reload by any chance with this setting on? thanks

Yes, I was going to ask the same question. Does it break XAML hot reload?

C# hot reload would work if UseInterpreter is true (which is the default for Debug unless you changed it).

roubachof commented 6 months ago

I'm in the middle of a big merge so I will try it asap. But I don't think it should if UseInterpreter=true as mentioned. This decision was made for improving build and deploy times: https://github.com/dotnet/maui/issues/8633

As XamlC (XAML Compilation) is a perf enhancement, but comes at a compilation cost, we made some tradeoff vs what we were doing on Xamarin.Forms:

  • XAMLC is executed on DEBUG, so you get the compilation errors, but the generated IL isn't written to the assembly, and saves a lot of time in the developer loop (code-build-run)
  • For runtime builds, we enable XAMLC, and IL writing, for perf reasons
developer9969 commented 6 months ago

Just tried myself and my hotreload does not work in iOS..

roubachof commented 6 months ago

yup doesn't seem to work on Android neither... Even if I can be 100% sure cause HotReload only works sometimes usually

imuller commented 2 months ago

What is the reason that this worked on Xamarin and now is disabled by default in .NET MAUI on debug mode?

We also encountered this problem, that took us many hours to figure this out.. We found the solution by this blog post: https://www.sharpnado.com/net-maui-painfully-slow-debugging/ It would be better to have a faster debug experience.

roubachof commented 2 months ago

@imuller the weirdest part is xaml compilation was enabled in debug XF AND xaml hot reload was working....

imuller commented 2 months ago

@jonathanpeppers Can you clarify this?

jonathanpeppers commented 2 months ago

Here is the original PR (with some numbers) for the "validate-only" mode of XamlC:

My memory as a Xamarin customer, was I would watch XamlC run for as much as 30 seconds (maybe even a minute) on every build. This behavior was so bad we disabled XamlC in Debug mode anyway.

I don't work on XAML Hot Reload, so I'm not sure exactly why it doesn't work when XamlC is enabled.

drasticactions commented 2 months ago

I don't work on XAML Hot Reload, so I'm not sure exactly why it doesn't work when XamlC is enabled.

https://github.com/dotnet/maui/issues/21083

Because MAUI VisualDiagnostics doesn't provide source info when XamlC is enabled. Incremental Hot Reload depends on source info existing, so it can't work. There's not much you can do outside of it, it would need to be addressed within MAUI to be done "right."

I believe full page hot reload (Pressing the Hot Reload button, blasting the pages contents with a new version) should, AFAIK, work here. That was introduced after the bug I wrote above was written. It's not as elegant, but it should "do a thing"