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

Performance differences between Android 14 X.A. build and net8-android build #9244

Open
gmck opened this issue Aug 23, 2024 · 9 comments
Open
Assignees
Labels
Area: App+Library Build Issues when building Library projects or Application projects.

Comments

@gmck
Copy link

gmck commented Aug 23, 2024

Android framework version

net8.0-android

Affected platform version

VS 2022 17.12.0 Prev 1.0

Description

I first encountered this problem about a year ago with net7 #8285. As I couldn’t solve the performance problem, I kept developing with X.A Android with Android 14 and published my app last June (https://play.google.com/store/apps/details?id=com.glmsoftware.obdnowpros - if you want to check the times). Since then, I've converted the app to net8-android. However, I’m still getting the very sluggish performance similar to the net7 version.

The following table (using profile.ps1 -package com.glmsoftware.obdnowpros -activity crc64953c68cad4e91ae3.MainActivity) shows very similar figures to that found in #8285. The only difference is that I now have a new table entry for the Net8 Build using a custom_aprof.

Xamarin.Android build - Android14

Pixel 8 - x.a.14 Initial Signed In Subscription Restored
Average 390.7 497.7 558.8
Std Err 3.8731 3.6485 5.8628
Std Dev 12.2479 11.5378 18.5400

Net8 Default build.

Pixel 8 - net8-android Initial Signed In Subscription Restored
Average 377.6 914.7 1266.4
Std Err 1.4 4.0826 6.7333
Std Dev 4.427 12.9103 21.292

Net8 Build using the custom.aprof.

Pixel 8 - net8-android Initial Signed In Subscription Restored
Average 295.4 812.9 1170.5
Std Err 1.8511 3.6192 4.7592
Std Dev 5.8537 11.4450 15.0499

The code is the same in both projects except where I was forced to change the X.A. code that was deprecated in Net7. Back then, I was advised to upload a speed scope file. I wasn't successful in getting adb reverse to work, so I wasn't able to produce any files. After watching Jonathan Pepper's video and installing VSCode, I can now get it to reverse very easily, so I can now successfully create speed scope files. Back then, there were some comments about problems with the HttpClient code that I presume have now been resolved in Net8. As the problem seems to be related to HttpClient, can you confirm that those problems have been resolved?

I don't have a problem with the start-up performance; if anything, according to the figures above, the net8 version is fractionally faster, and the custom. prof version is faster again. The performance problems only become apparent after logging in and then after restoring a subscription. Therefore, I thought I should only use nosuspend as in `adb shell setprop debug.mono.profile '127.0.0.1:9000, nosuspend, connect' after I've already logged in via Google Sign-In and again after restoring a subscription.

So after I send the nosuspend line, I start the app and then click on a couple of the NavigationView menu items. At that point, I then execute dotnet-trace collect -p 30436 --format speedscope and let it collect for, say 5 secs, then hit enter to write the speedscope file.

The problem with that result is that when I view the speedscope file, I don't see any of my code within any of the threads. The only code I see is low-level code. I'm presuming I'm doing something wrong, but I thought I did what Jonathan did in his video. For that sort of check, I found the Sandwich tab to be the most straightforward tab to use. You can quickly select each thread and check for your code.

On the other hand, if I use suspend, I do see my code and since this user is already signed in and has a subscription. I can sort of trace it all the way through. I'm certainly not fluent with speedcope and don't understand it well, but I was assuming that I would need to use nosuspend.

I've attached both speedscope files. The one ending 161412 is the suspend file and 165354 is the nosuspend.

However, none of the above explains why the app's overall performance is so slow compared to the X.A app. If you check the X.A app, you won't notice any delays when you select between the fragments controlled by the NavigationView. With the net8 version, you can see a menu item selection, unhighlight the current menu item and then highlight the selected menu item before the new fragment appears.

dotnet-dsrouter.exe_20240823_161412.speedscope.json
dotnet-dsrouter.exe_20240823_165354.speedscope.json

Steps to Reproduce

N/A

Did you find any workaround?

N/A

Relevant log output

N/A
@gmck gmck added Area: App+Library Build Issues when building Library projects or Application projects. needs-triage Issues that need to be assigned. labels Aug 23, 2024
@jonathanpeppers
Copy link
Member

Most the speedscope trace is broken with ?!?. Did you end dotnet-trace gracefully by hitting enter?

With the info there, the only interesting thing I see is:

image

Maybe you could time this method, specifically Xamarin vs .NET 8.

@gmck
Copy link
Author

gmck commented Aug 24, 2024

Thanks, Jonathan, for helping me out. I'm pretty sure I just hit enter, so I don't know why the speedscope trace is broken. I don't think I've even tried control C. I've created a new one, which doesn't have the ?!? anywhere.

My procedure is as follows - Terminal Window 2

  1. adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect'
  2. Start the app from a cold start - the app will hang on the splash screen
  3. dotnet-trace collect -p 30436 --format speedscope

The app stays on the splash screen while the trace is recording. After about 5-8 secs, I hit enter, and the app shows the ConnectionFragment or HomeFragment.

Is that the correct procedure?

It is interesting that you highlight AES.Decrypt because that is one of the changes I had to make because the X.A. version one was deprecated when I bought it over. Can I ask how you zeroed in AES.Decrypt?

I'm having a hard time understanding the numbers. With this new file, I see 2.96s (45%) AES.Decrypt on the Time Order tab and 5.08 (77%) for the Left Heavy and Sandwich tabs. I can't say I understand the difference and what that means.

OnDestinationChange calls CheckPreferenceChanges, so I've overlooked the fact that I'm calling it every time any fragment changes. I could simply change it to only run the decrypting when the destination fragment is the ConnectionFragment. That should at least speed up the NavigationView when I navigate to its other fragments.

Would the following be sufficient to get a speed scope file for the X.A. production build?

dotnet build -t:Run -c Release -p:AndroidEnableProfiler=true

dotnet-dsrouter.exe_20240824_115802.speedscope.json

@gmck
Copy link
Author

gmck commented Aug 26, 2024

@jonathanpeppers

Can you confirm that the new speedscope file I sent over the weekend is now correctly formed?

I gave up trying to create a speedscope file for the XA build, as I'm not even sure it is possible with an X.A. build. I hit all the problems I mentioned last year, in that it will never reverse. Whereas, with a net8 build, it reverses every time, and when you go back to terminal 1, it always shows executing adb reverse -- list. The ScantoolConnection.IsConnected() is called in multiple places throughout the app. And it calls GlmAccount.GetAccount(). GetAccount() is what causes the decrypting code to run. Four strings are decrypted each time. It must have seemed like a good idea at the time to add GetAccount(), but now, when I look at it, it was just unnecessary. I just want to confirm that I have a non-null email address, which I should have made as a separate condition. Obviously, it is stored encrypted, but even the encrypted value would provide the same result.

I tracked the decrypt with Stopwatch in both projects. The old XA method was around 30ms for the four strings, and the net8 build was 160ms, over five times slower. I certainly wasn't expecting that replacing an obsolete method with a newer one would get that sort of result. Do you think a single change like that would account for the poor overall performance of the net8 project?

Do you know of any other good resources/help etc., for a better understanding of speedscope files?

@jonathanpeppers
Copy link
Member

Yes, "left heavy" shows the same method taking a lot of time and no ?!?, but I can see deeper into the callstack now:

image

Is there anything you can do, to improve it? 5 seconds seems like a lot!

@gmck
Copy link
Author

gmck commented Aug 27, 2024

@jonathanpeppers

I commented GlmAccount.GetAccount() from ScantoolConnection.IsConnected(), which eliminates the aes.Decrypt() of 4 strings. That immediately fixed the sluggishness that the net8 build has always shown.

The following is the new table

Net8 Build using the custom.aprof.

Pixel 8 - net8-android Initial Signed In Subscription Restored
Average 292.0 304.9 493.7
Std Err 1.7701 1.8466 3.4125
Std Dev 5.5976 5.8395 10.7914

That is a stunning improvement. The app is now silky smooth and fast when navigating the NavigationView fragments. Comparing the above to the X.A. build also shows a really big improvement. I accidentally lost the latest speedscope file. I'll get it to you later today but I've got an appointment to get to.

How should I go about reporting the poor performance of the replacement AES method? Thanks so much for your help with this.

@dellis1972
Copy link
Contributor

@gmck that would probably need to be raised on the dotnet/runtime repo.
My advice would be to make it as easy as possible for them to repo, so if you can put a small repro together that would really help.

@gmck
Copy link
Author

gmck commented Aug 28, 2024

@jonathanpeppers
I'm attaching the missing speedscope file from my previous message. Regarding your comments about ?!?, the first attempt had them, so I repeated the test, and the second one doesn't have them. Both times, I definitely hit enter to write the file. I waited about 5 seconds before I hit enter. Can you suggest what else could cause producing a file containing ?!? characters?

dotnet-dsrouter.exe_20240829_093606.speedscope.json

@jonathanpeppers
Copy link
Member

@gmck if you want to investigate why the ?!? characters are there, we should just move the issue here:

The .NET diagnostics team would need to investigate.

@filipnavara
Copy link
Member

The last SpeedScope trace shows Rfc2898DeriveBytes taking a significant amount of time. Note that this was improved in .NET 9 significantly, specifically for Android: dotnet/runtime#103016.

@jpobst jpobst removed the needs-triage Issues that need to be assigned. label Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: App+Library Build Issues when building Library projects or Application projects.
Projects
None yet
Development

No branches or pull requests

5 participants