runtime: Performance regression: DateTime.UtcNow and DateTimeOffset.UtcNow 2.5x slower
DateTime.UtcNow
and DateTimeOffset.UtcNow
are 2.5x slower compared to 2.2
[Benchmark]
public DateTimeOffset GetUtcNow() => DateTimeOffset.UtcNow;
[Benchmark]
public DateTime GetUtcNow() => DateTime.UtcNow;
Repro
git clone https://github.com/dotnet/performance.git
cd performance
# if you don't have cli installed and want python script to download the latest cli for you
py .\scripts\benchmarks_ci.py -f netcoreapp2.2 netcoreapp3.0 --filter *GetUtcNow*
# if you do
dotnet run -p .\src\benchmarks\micro\MicroBenchmarks.csproj -c Release -f netcoreapp2.2 --filter *GetUtcNow* --runtimes netcoreapp2.2 netcoreapp3.0 --join
BenchmarkDotNet=v0.11.3.1003-nightly, OS=Windows 10.0.18362
Intel Xeon CPU E5-1650 v4 3.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=3.0.100-preview8-013262
[Host] : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
Job-BYJCMJ : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
Job-JSSCYO : .NET Core 3.0.0-preview8-27916-02 (CoreCLR 4.700.19.36302, CoreFX 4.700.19.36514), 64bit RyuJIT
Type | Method | Toolchain | Mean |
---|---|---|---|
Perf_DateTime | GetUtcNow | netcoreapp2.2 | 25.12 ns |
Perf_DateTime | GetUtcNow | netcoreapp3.0 | 70.91 ns |
Perf_DateTimeOffset | GetUtcNow | netcoreapp2.2 | 38.19 ns |
Perf_DateTimeOffset | GetUtcNow | netcoreapp3.0 | 91.96 ns |
/cc @danmosemsft
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 2
- Comments: 20 (20 by maintainers)
Commits related to this issue
- make few methods used by DateTime.UtcNow inlinable to minimize the leap second performance regression impact, related to #25728 — committed to adamsitnik/coreclr by adamsitnik 5 years ago
- make DateTime.UtcNow 5% faster to minimize the leap second performance impact (#26046) * make few methods used by DateTime.UtcNow inlinable to minimize the leap second performance regression impact, ... — committed to dotnet/coreclr by adamsitnik 5 years ago
Just to make sure I confirm that OSes other than Windows are not affected:
System.Tests.Perf_DateTime.GetUtcNow
System.Tests.Perf_DateTimeOffset.GetUtcNow
I moved this to future milestone for now. feel free to bring it back if you feel otherwise.
@stephentoub also reminded me about, there is a way to disable the leap seconds handling on the machine. That should give the perf back if anyone really sensitive to that.
https://techcommunity.microsoft.com/t5/Networking-Blog/Leap-Seconds-for-the-IT-Pro-What-you-need-to-know/ba-p/339811
@adamsitnik @DrewScoggins Heads up, as soon as your perf infrastructure takes https://github.com/dotnet/runtime/commit/eed3c7642ada205a4645dc3153fcb4c3c04c363c you’ll see the
DateTime.UtcNow
benchmarks change. Here’s what you should expect:If you see any change at all (good or bad) on non-Win10 platforms, let us know so that we can double-check that we didn’t inadvertently change these code paths.
If you see a regression on Win10, let us know because it probably means we have a problem in our caching logic. (A cache miss in this logic is very expensive, but they should happen so infrequently that they shouldn’t show up at all in benchmarks.)
@tarekgh thanks for the explanation!
@adamsitnik
Here are some clarifications may help explaining why we did what that. there are 2 conditions we need to do when reporting the time through UtcNow:
DateTime in general encapsulate the time as ticks which are the number of the 100 nanoseconds with the notion the minutes are always 60 seconds (0 to 59). i.e. we never have second
60
at all. This design we cannot change because many apps today depend on that and they use ticks directly and always assuming the minute is 60 seconds when doing any manual conversion to time parts (hours, minutes, seconds…etc.). changing this design will be a major app compat concern and systems interacting with each other’s will be no longer can exchange the time because one system can be enabled for leap seconds and other is not. we already discussed that with .NET ship room.Windows introduced the leap seconds support, which means when any Windows system enable the leap seconds, the reported time will include the leap seconds. in other word, the minutes can have 61 seconds when we encounter a leap second. That means when we read the time from system, we must map that to our DateTime which require the minutes always 60 seconds.
Before we did the leap seconds support in .NET, what we used to do is we just call GetSystemTimePreciseAsFileTime which return the time 100 nanoseconds that we just use directly in DateTime (as the ticks) and there is not any conversion needed. When you run on a system support leap seconds and there are already some leap seconds reported in this system, you will start see some shift in the reported .NET time because we converted the ticks came from GetSystemTimePreciseAsFileTime assuming every minute is 60 seconds while this is not the case anymore.
To make .NET work with systems have leap seconds enabled, we had 2 options:
We have chosen the second solution because users cared more about the precision. you can see that on the issue which required us to use GetSystemTimePreciseAsFileTime instead of using GetSystemTimeAsFileTime which we use in the .NET desktop.
Here are the answers for your questions:
First, RtlGetSystemTimePrecise is undocumented API which we cannot use. but even if we can use it will not help much because this will give use the time as ticks anyway and we’ll still need to convert it. so, this is not buying us anything.
Yes, that is possible, but we’ll lose the precision which we have tried to not do that in the first place.
No, this condition must be done anyway either in native or manager code, so I don’t believe this will make any difference. Also, in the code you are suggesting
This condition is always false because DateTime never reprot second number greater than 59.
We are asking Windows to expose some API to us something like GetSystemTimePrecise() and return the system time directly with the high precision. That is what I mentioned in my previous comments
till we get more new Windows APIs which may help.
.I guess it’s a cost of https://github.com/dotnet/coreclr/pull/21420 (leap seconds support)