Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[monodroid] Runtime startup performance improvements (#2515)
Fixes: #1443 Context: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/plot/Tests%20times/ A frequent complaint with Xamarin.Android is that application startup times can be slower than desired. For example, see the [Xamarin.Forms app startup data][xf-startup], in particular the **init-Release** column (times in milliseconds), which is the time at which the `Runtime.init: end native-to-managed transition` message is printed when `timing` messages are enabled. As of Jenkins build 1359, the **init-Release** value is 518ms. (Note that the times in that table are not necessarily useful, nor are they future proof: they come from the emulator that the Jenkins build machine uses, and that emulator *has* changed and *will* change in the future. Additionally, because it's an x86-accelerated emulator, times are not meaningful to Android hardware devices. The values also fluctuate a lot. Better than nothing? ¯\_(ツ)_/¯) Optimize some startup operations to reduce the **init-Release** value: * JNI Handling Improvements: * Reduce Java class lookup. * Don't lookup `android.os.Build.VERSION.SDK_INT` via JNI. * `jstring` handling improvements. * Review logging messages. * Improve package name hash generation. * Improve environment variable processing. * Mono Handling Improvements * Stop preloading all assemblies. * Avoid using "system properties" to control Mono features. * Desktop version is now a compile-time build option, not runtime. * Initialize `xamarin_getifaddrs()` on-demand, not at startup. [xf-startup]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/plot/Tests%20times/#plot-8694435842335223270.csv ~~ JNI Handling Improvements ~~ Previously, JNI was used to lookup the `android.os.Build.VERSION.SDK_INT` value. We now pass `Build.VERSION.SDK_INT` into `Runtime.init()`, avoiding the JNI calls. Previously, `JNIEnv::FindClass()` was used during process startup in order to lookup multiple types which are required for operation. These types are now fields on the `mono.android.Runtime` type, and `JNIEnv::GetStaticObjectField()` is used to obtain the `jclass`. Additionally, a handful of class field/method lookups were moved out of the init code so that the code that doesn't use them doesn't have to pay the tax. `jstring` and `jobjectArray`-of-`jstring` values are now handled by the new `jstring_wrapper` and `jstring_array_wrapper` types, which take care of efficiently caching the retrieved strings as well as of correctly deleting local references to the obtained objects. Both classes are optimized so that they compile into the equivalent of the current, hand-written, code. They also take care to make the minimum necessary number of calls in order to access the strings, both standalone and from arrays, as well as to release the resources. The string and array wrapper instances are passed around as references, thus using the minimum amount of memory. ~~ Log Messages ~~ Previously whenever any of the `log_{info,debug}()` functions were called we'd spend time preparing all the parameters to pass to the function, sometimes involving memory allocation, function calls, etc., only to discard all of that work **inside** the `log_*` call because the logging category used in that call was disabled. Now we check whether the category is enabled before we set out to construct the parameters. ~~ Environment Processing ~~ Since [2012-Aug-16][env-support], `@(AndroidEnvironment)` has worked by creating a file named `environment` within the `.apk` -- which is stored uncompressed within the `.apk` -- and the file is then processed, calling **setenv**(3) to store the recorded values. There's a fair bit of potentially hairy string manipulation here, from ***C***, which is not entirely ideal or performant. To speed the process up, this commit replaces the `environment` file with a Java class generated during application build which contains an array of `"name", "value"` pairs. The class is passed to `Java_mono_android_Runtime_init()` and its elements are used to create the requested environment variables. Some of these variables are special-cased; instead of using them for **setenv**(3), they control flags in the `AndroidSystem` class * `mono.aot`: The `$(AndroidAotMode)` value; which *kind* of AOT mono should support at runtime. * `mono.llvm`: The `$(EnableLLVM)` value; whether LLVM-generated AOT files should be used. * `__XA_DSO_IN_APK`: Support in-place reading of `.so` files; See commit 95ca102. [env-support]: xamarin/monodroid@dbd73ec ~~ Mono Handling Improvements ~~ During process startup startup, *every* assembly within the `.apk` would be loaded so that a `Java.Interop.__TypeRegistrations` type could be probed, and if it existed, the `__TypeRegistrations.RegisterPackages()` method would be invoked. This was done in order to [better support "type mappings"][typemaps] between Java names and C# names (and vice versa). However, this support hasn't been required since the introduction of the [`typemap.jm` and `typemap.mj` files][typemap-files]; we just hadn't gotten around to removing the `__TypeRegistrations.RegisterPackages()` invocation. *Not* loading every assembly on startup allows assemblies to be loaded on-demand, and improves startup times. [typemaps]: #1443 (comment) [typemap-files]: xamarin/monodroid@e69b76e ~~ Startup Time Summary ~~ Startup times for `tests/Xamarin.Forms-Performance-Integration`, average of 50 iterations of (uninstall app, install app, launch app): * Debug configuration: Old: 1s 440ms New: 1s 100ms * Release configuration: Old: 650ms New: 270ms
- Loading branch information
b90d3ab
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, has this commit made it to a release? We are seeing that our Android app is indeed loading all references at startup, which we believe is contributing to the slow start times of our app.