-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[Android][libs] Introduce GetLocalUtcOffset temporary fast result #74459
Conversation
I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label. |
@grendello @lambdageek Would it be preferred to pass the Offset obtained through Java API as an AppContext key/value property or as part of |
7c6f200
to
9a2a8a2
Compare
_loadAndroidTZData = new Thread(() => { | ||
_localUtcOffset = GetCacheLocalUtcOffset(dateTime, flags); | ||
Thread.Sleep(1000); | ||
}); | ||
_loadAndroidTZData.IsBackground = true; | ||
_loadAndroidTZData.Start(); |
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.
@grendello what are your thoughts here on starting a Thread
?
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.
The thread idea was my suggestion and I think it's going to work quite OK, provided it's a bare thread as above and not part of a threadpool or TPL in general. It shouldn't hurt startup performance too much, although what I'd do would be to let it sleep first for 1 second and then start loading the TZ. The idea is that it should start after the main startup sequence of the app, and 1s should be enough time.
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.
If 1s isn't enough time, is this going to make launching the app even slower?
I'd prefer it to be part of |
Tagging subscribers to this area: @dotnet/area-system-runtime Issue DetailsFixes #71004 On Android, time zone data is loaded through AndroidTZData, and the time to load significantly impacts startup performance should one call an API reliant on We can leverage Java API to obtain an offset that is good enough for Testing through Android Sample App
speedscope: https://gist.github.com/mdh1418/473d097cbd1d7b1187c9d83ddb8da11b First call to DateTimeOffset.Now (Fast Path) 145.66msSecond call to DateTimeOffset.Now (After AndroidTZData loaded) 2.67msThis PR does the following:
|
I think it shouldn't be in it's faster to set in XA, but in mono we will still have to convert it to a string property in order to populate the managed AppContext. So we're just pushing the cost down one layer |
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs
Outdated
Show resolved
Hide resolved
That's the whole point, though :) To make the startup sequence of XA faster - what happens after the app is running can be slower without hurting the perceived app performance. |
This won't make the startup faster. We need to populate the AppContext during startup: we call |
src/native/public/mono/jit/details/mono-private-unstable-types.h
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.Android.cs
Outdated
Show resolved
Hide resolved
Leverage a boolean flag instead of && Start the background thread to avoid deadlocking
c03c802
to
ef7729e
Compare
@grendello, I tweaked a little bit to get the thread starting after the lock to work. Without a condition, it could crash with some test like
|
/azp run runtime-extra-platforms |
Azure Pipelines failed to run 1 pipeline(s). |
/azp run runtime-extra platforms |
No pipelines are associated with this pull request. |
Checks didn't run because of the migration, should run this time after merging main |
/azp run runtime-extra platforms |
No pipelines are associated with this pull request. |
/backport to release/7.0 |
Started backporting to release/7.0: https://github.com/dotnet/runtime/actions/runs/2974849069 |
@mdh1418 an error occurred while backporting to release/7.0, please check the run log for details! Error: @mdh1418 is not a repo collaborator, backporting is not allowed. If you're a collaborator please make sure your dotnet team membership visibility is set to Public on https://github.com/orgs/dotnet/people?query=mdh1418 |
/backport to release/7.0 |
Started backporting to release/7.0: https://github.com/dotnet/runtime/actions/runs/2974882914 |
Context: dotnet/runtime#74459 Context: dotnet/runtime#71004 Context: dotnet/runtime#54845 dotnet/runtime#54845 added support TimeZoneInfo support for Android. This was found to slow down initial use of `DateTimeOffset.Now` by ~277ms (dotnet/runtime#17004). dotnet/runtime#74459 started reducing this startup overhead by adding support for a new `System.TimeZoneInfo.LocalDateTimeOffset` property on `AppContext`: if `System.TimeZoneInfo.LocalDateTimeOffset` is set, it is used as the initial local DateTime Offset value. Update `mono.android.MonoPackageManager.LoadApplication()` and `libmono-android*.so` so that the `System.TimeZoneInfo.LocalDateTimeOffset` AppContext property is set during process startup. This can reduce `DateTimeOffset.Now` startup overhead from ~277ms to ~50ms. Note: `System.TimeZoneInfo.LocalDateTimeOffset` is fastest on API-26+ (Android 8.0+) targets, as it uses [`java.time.ZoneOffset.getTotalSeconds()`][0]. Note: `$(AndroidJavaRuntimeApiLevel)` is updated to API-26 so that `ZoneOffset.getTotalSeconds()` can be used. Care should be taken within `src/java-runtime` to ensure that Android API use is appropriately protected behind runtime version checks. [0]: https://developer.android.com/reference/kotlin/java/time/ZoneOffset#gettotalseconds
Context: dotnet/runtime#74459 Context: dotnet/runtime#71004 Context: dotnet/runtime#54845 dotnet/runtime#54845 added support TimeZoneInfo support for Android. This was found to slow down initial use of `DateTimeOffset.Now` by ~277ms (dotnet/runtime#17004). dotnet/runtime#74459 started reducing this startup overhead by adding support for a new `System.TimeZoneInfo.LocalDateTimeOffset` property on `AppContext`: if `System.TimeZoneInfo.LocalDateTimeOffset` is set, it is used as the initial local DateTime Offset value. Update `mono.android.MonoPackageManager.LoadApplication()` and `libmono-android*.so` so that the `System.TimeZoneInfo.LocalDateTimeOffset` AppContext property is set during process startup. This can reduce `DateTimeOffset.Now` startup overhead from ~277ms to ~50ms. Note: `System.TimeZoneInfo.LocalDateTimeOffset` is fastest on API-26+ (Android 8.0+) targets, as it uses [`java.time.ZoneOffset.getTotalSeconds()`][0]. Note: `$(AndroidJavaRuntimeApiLevel)` is updated to API-26 so that `ZoneOffset.getTotalSeconds()` can be used. Care should be taken within `src/java-runtime` to ensure that Android API use is appropriately protected behind runtime version checks. [0]: https://developer.android.com/reference/kotlin/java/time/ZoneOffset#gettotalseconds
Context: dotnet/runtime#74459 Context: dotnet/runtime#71004 Context: dotnet/runtime#54845 dotnet/runtime#54845 added support TimeZoneInfo support for Android. This was found to slow down initial use of `DateTimeOffset.Now` by ~277ms (dotnet/runtime#17004). dotnet/runtime#74459 started reducing this startup overhead by adding support for a new `System.TimeZoneInfo.LocalDateTimeOffset` property on `AppContext`: if `System.TimeZoneInfo.LocalDateTimeOffset` is set, it is used as the initial local DateTime Offset value. Update `mono.android.MonoPackageManager.LoadApplication()` and `libmono-android*.so` so that the `System.TimeZoneInfo.LocalDateTimeOffset` AppContext property is set during process startup. This can reduce `DateTimeOffset.Now` startup overhead from ~277ms to ~50ms. Note: `System.TimeZoneInfo.LocalDateTimeOffset` is fastest on API-26+ (Android 8.0+) targets, as it uses [`java.time.ZoneOffset.getTotalSeconds()`][0]. Note: `$(AndroidJavaRuntimeApiLevel)` is updated to API-26 so that `ZoneOffset.getTotalSeconds()` can be used. Care should be taken within `src/java-runtime` to ensure that Android API use is appropriately protected behind runtime version checks. [0]: https://developer.android.com/reference/kotlin/java/time/ZoneOffset#gettotalseconds
Fixes #71004
On Android, time zone data is loaded through AndroidTZData, and the time to load significantly impacts startup performance should one call an API reliant on
AndroidTzDataInstance
in the startup sequence.e.g. Displaying
DateTimeOffset.Now
->TimeZoneInfo.GetLocalUtcOffset
->cachedData.Local
->cachedData.CreateLocal
->GetLocalTimeZone
->GetLocalTimeZoneCore
->GetTimeZone
->AndroidTzDataInstance.GetTimeZoneData
We can leverage Java API to obtain an offset that is good enough for
GetLocalUtcOffset
and pass that during the mono runtime startup viamonovm_initialize
ormonovm_initialize_preparsed
as a "fast path". In the background, we load AndroidTZData, as it is necessary for handling any time zone changes during the app's duration.Testing through Android Sample App
speedscope: https://gist.github.com/mdh1418/473d097cbd1d7b1187c9d83ddb8da11b
First call to DateTimeOffset.Now (Fast Path) 145.66ms
Second call to DateTimeOffset.Now (After AndroidTZData loaded) 2.67ms
This PR does the following:
System.TimeZoneInfo.LocalDateTimeOffset
property to be passed from Java either as an AppContext property or as a part ofMonoCoreRuntimeProperties