Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Mono.Android, monodroid] JNIEnv.Initialize optimization (#3729)
`JNIEnv.Initialize()` is part of the Xamarin.Android runtime startup sequence and it contributes a sizable chunk of time to it. Some code executed during startup wasn't as optimized as it could be, so fix all the low-hanging fruit in that area: * Don't use the `Logger` class: This removes one class instantiation which wasn't absolutely necessary. Calls to `Logger` are replaced with calls to a new native function `monodroid_log()`. * Use native functions for timing [^0]: This won't affect the user's code (unless it runs with timing enabled, of course) but will allow our timing to be more precise and have less impact on code performance. Implemented with two new native functions `monodroid_timing_start()` and `monodroid_timing_stop()`. * Remove calls to `Environment.GetEnvironmentVariable()` The calls took a non-trivial amount of time (around 4ms each) and were replaced by putting the environment variables in `libxamarin-app.so`, in the application environment block. * Do not fully initialize `UncaughtExceptionHandler` during init: The handler's initialization is quite heavy while the handler itself is going to be used only when there's an unhandled exception thrown. Delay full initialization to the point in time when the handler is actually needed. * Avoid parsing of the `PackageNamingPolicy` enum values at runtime: Instead, the desired value is placed in the application's environment configuration block and simply casts `int` -> enum. * Initialize `Logger` category lazily. The logging category is requested by `Logger` lazily instead of being set from `JNIEnv.Initialize()`. This allows the `Logger` class to not be instantiated during startup. * Avoid static initialization of the `Java.Interop.Runtime` class. * Avoid heavy static initialization of `Java.Interop.TypeManager`: This is done by initializing the type lookup dictionaries lazily, via another "proxy" class. * Improve Java class name lookup faster: This is done by moving the lookup (and processing) to native code and P/Invoking `monodroid_TypeManager_get_java_class_name()`. Other changes: * Remove dead code from `JNIEnv`: The `JAVA_INTEROP` symbol is always "defined" now, remove code used when it was not defined. * Introduce fast performance measurement for managed code: The timing code used by the native runtime is now exposed to managed land, thus allowing us fast and accurate (to the nanosecond level) timing measurement. * Update all `[DllImport("__Internal")]` declarations to specify `CallingConvention=CallingConvention.Cdecl`. `libmonodroid.so` functions all use the Cdecl calling convention, and for maximum sanity we should not rely on the Windows/.NET default of [CallingConvention.Winapi][1], which is always wrong on Windows. ~~ Startup Improvements ~~ Start the `tests/Xamarin.Forms-Performance-Integration` app 10 times on a Pixel 3 XL and average the **Runtime init** and **Displayed** times vs. commit 438a598: * `$(AndroidEnablePreloadAssemblies)`=True, 32-bit app: * Previous: Runtime init=218.804ms Displayed=852.70ms * Current: Runtime init=187.907ms [30.90ms faster] Displayed=828.90ms [23.8ms faster] * `$(AndroidEnablePreloadAssemblies)`=False, 32-bit app: * Previous: Runtime init=185.240ms Displayed=827.40ms * Current: Runtime init=154.718ms [30.52ms faster] Displayed=803.50ms [23.9ms faster] * `$(AndroidEnablePreloadAssemblies)`=True, 64-bit app: * Previous: Runtime init=201.779ms Displayed=783.20ms * Current: Runtime init=174.211ms [27.57ms faster] Displayed=754.50ms [28.7ms faster] * `$(AndroidEnablePreloadAssemblies)`=False, 64-bit app: * Previous: Runtime init=173.322ms Displayed=759.40ms * Current: Runtime init=144.158ms [29.16ms faster] Displayed=741.80ms [17.6ms faster] This is a ~14% reduction in `Runtime init` times and a 2-3% reduction in `Displayed` times. [^0]: `adb shell setprop debug.mono.log timing` [1]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.callingconvention?view=netframework-4.8
- Loading branch information