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

[release/7.0] [Android][libs] Introduce DateTimeOffset.Now temporary fast result #74965

Merged
merged 22 commits into from
Sep 12, 2022

Conversation

github-actions[bot]
Copy link
Contributor

@github-actions github-actions bot commented Sep 1, 2022

Backport of #74459 to release/7.0

/cc @mdh1418

Customer Impact

Significantly reduces the performance impact of DateTimeOffset.Now at first call to an avg 21.818ms (Issue reported 277ms).

Testing

Tested locally using speedscope to ensure that there was a significant performance improvement. Also tested scenarios in which multiple DateTimeOffset.Now calls are made to ensure locks/background threads worked properly with resilience to races and deadlocking.

Testing locally with the dotnet/runtime Android sample with this program

        Console.WriteLine($"The current time is `{DateTimeOffset.Now}`");
        Thread.Sleep(2000);
        var temp = DateTimeOffset.Now;
        Console.WriteLine($"Now the current time is `{temp}`");

The average time of the first call to DateTimeOffset.Now was 21.818ms
The average time of the next call to DateTimeOffset.Now after the background thread finished was 27.821ms
The issue's reported timing of DateTimeOffset.Now was 277ms

Screen Shot 2022-09-01 at 5 42 34 PM

Risk

Low, only impacts DateTimeOffset.Now on Android.

IMPORTANT: Is this backport for a servicing release? If so and this change touches code that ships in a NuGet package, please make certain that you have added any necessary package authoring and gotten it explicitly reviewed.

@dotnet-issue-labeler
Copy link

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.

@mdh1418 mdh1418 changed the title [release/7.0] [Android][libs] Introduce GetLocalUtcOffset temporary fast result [release/7.0] [Android][libs] Introduce DateTimeOffset.Now temporary fast result Sep 1, 2022
@carlossanlop
Copy link
Member

@eerhardt or @lambdageek can we get a code review sign off?

@steveisok
Copy link
Member

@marek-safar Can you please review / approve?

@marek-safar marek-safar added this to the 7.0.0 milestone Sep 6, 2022
// prevent two calls to DateTimeOffset.Now in quick succession
// from both reaching here.
s_loadAndroidTZData.Start();
s_startNewBackgroundThread = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What prevents the race condition where two threads both read s_startNewBackgroundThread as true? Seems like it'd be safer to have a local that determines whether this thread is the one that gets to start it, and that local is set appropriately inside of the above lock.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we made a change based on feedback from @grendello. I don't recall the specifics as to why.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feedback was about the previous state of the code, where the thread was started within the same lock that the thread then takes, which could end in a deadlock. The assumption here is that since .Start() doesn't block the current thread, the flag is set likely before the thread actually is started. Even in the unlikely situation when two threads would attempt to start the worker thread, the only harm would be a little time wasted inside the worker thread. This code could use a semaphore, for instance, but we felt that would be an overkill.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even in the unlikely situation when two threads would attempt to start the worker thread, the only harm would be a little time wasted inside the worker thread

Calling Start on a thread that's already started will result in an exception. So the concern I'm raising above is that this could lead to reliability problems, not just performance ones.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a very unlikely event, but sure, it is better to wrap it in in try/catch then and ignore the potential exception. Performance was the main point of this PR, so it would be a shame to sacrifice it to handle a very unlikely case with semaphores or similar mechanisms.

lock (s_localUtcOffsetLock)
{
s_loadAndroidTZData = null; // Ensure thread is cleared when cache is loaded
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why store the thread at all? You can use s_startNewBackgroundThread or equivalent for all coordination between threads.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was in response to review on the original PR, here.

@ghost
Copy link

ghost commented Sep 7, 2022

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

Backport of #74459 to release/7.0

/cc @mdh1418

Customer Impact

Significantly reduces the performance impact of DateTimeOffset.Now at first call to an avg 21.818ms (Issue reported 277ms).

Testing

Tested locally using speedscope to ensure that there was a significant performance improvement. Also tested scenarios in which multiple DateTimeOffset.Now calls are made to ensure locks/background threads worked properly with resilience to races and deadlocking.

Testing locally with the dotnet/runtime Android sample with this program

        Console.WriteLine($"The current time is `{DateTimeOffset.Now}`");
        Thread.Sleep(2000);
        var temp = DateTimeOffset.Now;
        Console.WriteLine($"Now the current time is `{temp}`");

The average time of the first call to DateTimeOffset.Now was 21.818ms
The average time of the next call to DateTimeOffset.Now after the background thread finished was 27.821ms
The issue's reported timing of DateTimeOffset.Now was 277ms

Screen Shot 2022-09-01 at 5 42 34 PM

Risk

Low, only impacts DateTimeOffset.Now on Android.

IMPORTANT: Is this backport for a servicing release? If so and this change touches code that ships in a NuGet package, please make certain that you have added any necessary package authoring and gotten it explicitly reviewed.

Author: github-actions[bot]
Assignees: -
Labels:

area-System.Runtime

Milestone: 7.0.0

@carlossanlop carlossanlop added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 9, 2022
@carlossanlop
Copy link
Member

Adding the label until the feedback is resolved and CI confirmed to be unrelated. Please ping me when ready so I can merge it.

@steveisok steveisok force-pushed the backport/pr-74459-to-release/7.0 branch from ddb4075 to eb5a67c Compare September 9, 2022 16:59
@steveisok steveisok removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 9, 2022
@steveisok
Copy link
Member

@carlossanlop this should be good to go once CI finishes.

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing my feedback.

@stephentoub
Copy link
Member

(We should make sure to keep main up to date with the changes made here.)

@steveisok steveisok merged commit 54e978c into release/7.0 Sep 12, 2022
@steveisok steveisok deleted the backport/pr-74459-to-release/7.0 branch September 12, 2022 13:19
steveisok pushed a commit to steveisok/runtime that referenced this pull request Sep 12, 2022
dotnet#74965 contained improvements for the routine. This change brings them back to main.
@ghost ghost locked as resolved and limited conversation to collaborators Oct 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.