Let's talk performance

Posts

Heya @DavidOrtinau@EZHart - Thanks for the focus on performance. I just opened a bug where one line of code (Google.MobileAds.MobileAds.Configure) on a default new solution causes a second delay in Entry control focus.

I was testing Xamarin.Forms performance on Android today and wanted to see where my app spent its time during startup. After inserting a few lines of code into a demo app I created to get some real numbers I noticed that the app spends a lot of time on startup creating the first view.

In my example I have a simple view with a ListView containing five text items, a few Labels and a custom made activity indicator. Loading the view took ~1 second. Removing these user interface elements (a few layouts created by my MVVM Framework were still in place) reduced the time to create the view down to ~0.5 seconds. The total loading time of the app was around ~2.0 seconds on average. (this was all measured in Release mode).

I tried to see if the new fast renderers in the latest prerelease of Xamarin would help, but could not see any significant changes (as I expected since I'm not using a lot of controls in the startup screen).

After looking at the output from the app I saw that the term AOT was part of a lot of the lines in my output window and this led me to think about the AOT and LLVM Compiler options found in the build section in Xamarin Studio. The compilation took a while (as expected) after turning these options on, but the startup time for the app decreased. The app now loaded in ~0.4 seconds with all the user interface elements in place.

From the documentation I see that the AOT feature is still marked as experimental, but I would belive that focusing on moving this feature into a production-ready state would be a great solution for the Android startup issues people are having with Xamarin.Forms.

I would be grateful if the AOT/LLVM feature could be part of this performance discussion, and would be interested in other experiences with this feature.

@ChristianFalch Ahead-of-time (AOT) compilation will definitely reduce the startup time of your application, because your application won't be spending as much time on just-in-time (JIT) compilation. However, there are trade-offs; if you look at the size of the generated application, I'm guessing it's much larger with AOT enabled.

That said, we'd be very interested to hear more feedback on everyone's experiences with AOT enabled.

I saw that the term AOT was part of a lot of the lines in my output window

@EZHart I noticed the increase in size, my app grew from ~19 to ~29 megs - caused by the inclusion of the JIT'ed code. This is in my opinion a lot less scary than having a startup time around 3-4 seconds. In addition it should be possible to reduce the code size a little bit by using a tool like ProGuard.

I'd really like to test out the AOT feature on some of my production apps, but I'm a little bit scared to make my customers my test bed for experimental stuff. Any background on why this is still experimental?

@ChristianFalch AOT LLVM for us on production works really well! That said, it only does after you spend a week making sure the settings are correct and nothing is getting taken out that you use in reflection or the like. Also you will need to download proguard directly and use that as the one included with the android SDK is too old.

OK so after all that our speeds improved greatly! We would never release without it. Which leads to the next problem...

The last release of Xamarin.Android breaks AOT with or without LLVM. So you cannot AOT anymore. You will need to switch back to VS 2015 and the last stable Xamarin.Android release(not the current stable) if you want to test it.

@DH_HA1 said:@ChristianFalch what is the size of your app on the device? When I did those options it ballooned to 150MB

Holly Sheep-deep Batman! Are you seeing that in the Application Manager? I see 1/3rd of that in an app that does continuous GPS tracking and transmitting, runs a USB scanner, does messaging back to a dispatcher, connects to engine ODBII port and polls for data, bunches of other REST, a few custom renderers, calls, blah... blah... blah...

What the heck does your app do, to be that big? That's a massive amount of code. Or does it have a huge amount of hi-res images in the resources?

@ClintStLaurent I think you need to deploy the Release version without shared runtime and fast deployment to get the real size of your app when deployed to a device. When trying to use AOT/LLVM on a debug build I don't see any difference in the output nor in the startup speed for the app.

@DH_HA1 I see that the size grows on the device after deployment, but I'm not really scared of numbers like 150 megs on the device - the important part for me is the size to download (.apk) and the startup time.

@BradChase.2654 Sorry, I wasn't clear about that. Yes - the entire directory structure, up to and including the project folders themselves.

I fired up a new project in the default VS 2015 location ("\Visual Studio 2015\Projects"), and AOT failed with the invalid characters error. I moved that project to a folder without spaces in the path and it worked just fine.

Again, that's with VS 2015 and the latest stable release; I haven't tried it against VS 2017.

@ChristianFalch what is the Android Store apk download size difference you see between, with and without AOT? Is that the "store apk download size" you mentioned grew from ~19 to ~29 megs? I am also concerned only startup time and the download size. I understand it is very much a normal behavior to have a bigger size in "application manager" for any apps, even the apps which are built with Java.

@ChristianFalch Thanks! I initially did not pay much attention to AOT, however after reading your post I thought to give it a try. So when compiled my ~29mb all abi apk goes to ~152 megs, and other abi apks go from ~21-24mb to ~46-50mb.

My current apks without AOT with the size of ~21-24mb, shows on store as <10 mb. I am little concerned if I publish the new apks with AOT, it increases the size by more than 10 mb.

@AbdullahNA As stated previously, startup time is a more pressing concern than increasing the download size.

@EZHart What about looking into a partial AOT to increase startup like @JonathanPryor wrote in the above link, automating the process as part of the build could be of great help.

Another question that I haven't found the answer to is: Is the JIT'ed code cached in any way so that it can be reused? If so the startup time should be long the first time the app starts, and subsequent launches should be really speedy. Wouldn't that be a good compromise between startup time and deployment size?

@ChristianFalch said:@ClintStLaurent I think you need to deploy the Release version without shared runtime and fast deployment to get the real size of your app when deployed to a device. When trying to use AOT/LLVM on a debug build I don't see any difference in the output nor in the startup speed for the app.

Wholly carp.... You weren't kidding. I learned a lesson there. I keep looking for a decimal point and don't see one. Its 10x the size.

Great work, @ClintStLaurent! As expected the size of the app when using the shared Mono Runtime will be a lot smaller than when building in release mode, but still a huge difference between the two release mode examples.

What we could try to do is to create the same infographic for a blank, new app and for one of the samples from Xamarin - this would make it easier for people to compare with their own work.

Looking forward to hear more about how JIT'ed code is cached on the device (if it is cached) at runtime - @JonathanPryor or @EZHart?

@ChristianFalch said:
What we could try to do is to create the same infographic for a blank, new app and for one of the samples from Xamarin - this would make it easier for people to compare with their own work.

I'm happy to do that off company time. I can run that up tonight from home. Though it will be on VS2017 (latest v 15.1) since that is what I run at home.

There are now up to three renderers for some controls. How are component vendors supposed to specify the right renderer?
In MR.Gestures I need a custom renderer for each and every control. For AppCompat I created separate controls (MR.Gestures.AppCompatButton) which use other renderers (MR.Gestures.Android.Renderers.AppCompatButtonRenderer which inherits from Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer). This is pretty awkward but with only the ExportRendererAttribute and without knowing if the end user uses AppCompat or not I cannot do anything better.

Will this become even worse with the FastRenderers? Is there a better way how I can configure the correct renderer?
It would be great if I could do

(MR.Gestures.Android.Renderers.AppCompatButtonRenderer which inherits from Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer).

Oh boy... More long-arse file paths to fail. By the time this gets nested...F:\TFSworkspace\Clients\CoolCompanyName\2016\WhizBangApp\WhizBangApp.droid\Renderers\MR.Gestures.Android.Renderers.AppCompatButtonRenderer

I'm not getting on Michael... I'm pointing out how what he needs to do because of the multiple renderers will eventually result in issues for developers.

Several packages have issues with long file names for similar reasons and that issue could use some attention.

@MichaelRumpler - The short answer is "change your AppCompat custom renderer to derive from the fast renderer".

If I'm understanding your question correctly, you've already got two custom renderers. One is based on Xamarin.Forms.Platform.Android.ButtonRenderer and the other is based on Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer. If you don't change anything at all, these will continue to work as they always have.

The "fast" button renderer is intended to replace the AppCompat button renderer. If you want to take advantage of the "fast" button renderer, you would just change from