Skip to content

Fix allocation in DateTime.TryParse when it returns false #91303

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

Merged
merged 3 commits into from
Sep 6, 2023

Conversation

stephentoub
Copy link
Member

On some failure paths, it was boxing a char or an int that would have been used as part of creating an exception on a Parse path but that's ignored on a TryParse path. This avoids that boxing by storing those values into a dedicated int field on the DateTimeResult. While doing this, I also consolidated several other fields, such that this not only avoids the boxing, it also results in a net reduction of the size of DateTimeResult (it's passed around by ref, so this only slightly reduces a zeroing burden).

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);

[HideColumns("Error", "StdDev", "Median", "RatioSD")]
[MemoryDiagnoser(false)]
public class Tests
{
    [Benchmark]
    [Arguments("hello")]
    public bool TryParse(string input) => DateTime.TryParse(input, out _);
}
Method Toolchain input Mean Ratio Allocated Alloc Ratio
TryParse \main\corerun.exe hello 39.22 ns 1.00 24 B 1.00
TryParse \pr\corerun.exe hello 34.98 ns 0.89 - 0.00

Fixes #90907

On some failure paths, it was boxing a char or an int that would have been used as part of creating an exception on a Parse path but that's ignored on a TryParse path. This avoids that boxing by storing those values into a dedicated int field on the DateTimeResult. While doing this, I also consolidated several other fields, such that this not only avoids the boxing, it also results in a net reduction of the size of DateTimeResult (it's passed around by ref, so this only slightly reduces a zeroing burden).
@ghost
Copy link

ghost commented Aug 30, 2023

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

Issue Details

On some failure paths, it was boxing a char or an int that would have been used as part of creating an exception on a Parse path but that's ignored on a TryParse path. This avoids that boxing by storing those values into a dedicated int field on the DateTimeResult. While doing this, I also consolidated several other fields, such that this not only avoids the boxing, it also results in a net reduction of the size of DateTimeResult (it's passed around by ref, so this only slightly reduces a zeroing burden).

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);

[HideColumns("Error", "StdDev", "Median", "RatioSD")]
[MemoryDiagnoser(false)]
public class Tests
{
    [Benchmark]
    [Arguments("hello")]
    public bool TryParse(string input) => DateTime.TryParse(input, out _);
}
Method Toolchain input Mean Ratio Allocated Alloc Ratio
TryParse \main\corerun.exe hello 39.22 ns 1.00 24 B 1.00
TryParse \pr\corerun.exe hello 34.98 ns 0.89 - 0.00

Fixes #90907

Author: stephentoub
Assignees: -
Labels:

area-System.Globalization

Milestone: -

@ShreyasJejurkar
Copy link
Contributor

This is quite a good catch! 💯

@tarekgh tarekgh added this to the 9.0.0 milestone Aug 30, 2023
@stephentoub stephentoub merged commit f202f6b into dotnet:main Sep 6, 2023
@stephentoub stephentoub deleted the tryparsealloc branch September 6, 2023 04:03
@ghost ghost locked as resolved and limited conversation to collaborators Oct 6, 2023
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.

DateTime.TryParse allocates on some failure paths
3 participants