Improve Utf8Parser UInt64 decimal performance - #132663
Open
thomhurst wants to merge 3 commits into
Open
Conversation
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @dotnet/area-system-buffers |
Author
|
@EgorBot -windows_x64 -windows_arm64 -linux_x64 -linux_arm64 -osx_arm64 using System.Buffers.Text;
using System.Text;
using BenchmarkDotNet.Attributes;
public class UInt64Utf8ParserBenchmarks
{
private byte[] _source = null!;
[ParamsAllValues]
public InputCase Input { get; set; }
[Params('\0', 'D', 'G')]
public char Format { get; set; }
[GlobalSetup]
public void Setup()
{
string text = Input switch
{
InputCase.Empty => "",
InputCase.Zero => "0",
InputCase.OneDigit => "7",
InputCase.FourDigits => "1234",
InputCase.NineDigits => "123456789",
InputCase.TenDigits => "1234567890",
InputCase.NineteenDigits => "1234567890123456789",
InputCase.Maximum => "18446744073709551615",
InputCase.Overflow => "18446744073709551616",
InputCase.TwentyOneDigits => "100000000000000000000",
InputCase.InvalidSuffix => "1234567890123456789x",
InputCase.InvalidAt7 => "1234567x901234567890",
InputCase.InvalidAt15 => "123456789012345x7890",
InputCase.LeadingZeros => "00000000000000000000",
_ => throw new InvalidOperationException(),
};
_source = Encoding.ASCII.GetBytes(text);
}
[Benchmark]
public ulong TryParse()
{
bool success = Utf8Parser.TryParse(_source, out ulong value, out int consumed, Format);
return value ^ ((ulong)(uint)consumed << 1) ^ (success ? 1UL : 0UL);
}
}
public enum InputCase
{
Empty,
Zero,
OneDigit,
FourDigits,
NineDigits,
TenDigits,
NineteenDigits,
Maximum,
Overflow,
TwentyOneDigits,
InvalidSuffix,
InvalidAt7,
InvalidAt15,
LeadingZeros,
} |
Keep short-input dispatch unchanged and resume scalar parsing after the last validated four-digit chunk instead of rescanning the prefix.
Author
|
@EgorBot -linux_amd -windows_intel -osx_arm64 using System.Buffers.Text;
using System.Text;
using BenchmarkDotNet.Attributes;
public class UInt64Utf8ParserBenchmarks
{
private byte[] _source = null!;
[ParamsAllValues]
public InputCase Input { get; set; }
[Params('\0', 'D', 'G')]
public char Format { get; set; }
[GlobalSetup]
public void Setup()
{
string text = Input switch
{
InputCase.Empty => "",
InputCase.Zero => "0",
InputCase.OneDigit => "7",
InputCase.FourDigits => "1234",
InputCase.NineDigits => "123456789",
InputCase.TenDigits => "1234567890",
InputCase.NineteenDigits => "1234567890123456789",
InputCase.Maximum => "18446744073709551615",
InputCase.Overflow => "18446744073709551616",
InputCase.TwentyOneDigits => "100000000000000000000",
InputCase.InvalidSuffix => "1234567890123456789x",
InputCase.InvalidAt3 => "123x5678901234567890",
InputCase.InvalidAt7 => "1234567x901234567890",
InputCase.InvalidAt11 => "12345678901x34567890",
InputCase.InvalidAt15 => "123456789012345x7890",
InputCase.LeadingZeros => "00000000000000000000",
_ => throw new InvalidOperationException(),
};
_source = Encoding.ASCII.GetBytes(text);
}
[Benchmark]
public ulong TryParse()
{
bool success = Utf8Parser.TryParse(_source, out ulong value, out int consumed, Format);
return value ^ ((ulong)(uint)consumed << 1) ^ (success ? 1UL : 0UL);
}
}
public enum InputCase
{
Empty,
Zero,
OneDigit,
FourDigits,
NineDigits,
TenDigits,
NineteenDigits,
Maximum,
Overflow,
TwentyOneDigits,
InvalidSuffix,
InvalidAt3,
InvalidAt7,
InvalidAt11,
InvalidAt15,
LeadingZeros,
}Note Benchmark request is AI-generated with Codex. |
Author
|
@EgorBot -linux_amd -windows_intel -osx_arm64 using System.Buffers.Text;
using System.Text;
using BenchmarkDotNet.Attributes;
public class UInt64Utf8ParserBenchmarks
{
private byte[] _source = null!;
[ParamsAllValues]
public InputCase Input { get; set; }
[Params('\0', 'D', 'G')]
public char Format { get; set; }
[GlobalSetup]
public void Setup()
{
string text = Input switch
{
InputCase.Empty => "",
InputCase.Zero => "0",
InputCase.OneDigit => "7",
InputCase.FourDigits => "1234",
InputCase.NineDigits => "123456789",
InputCase.TenDigits => "1234567890",
InputCase.NineteenDigits => "1234567890123456789",
InputCase.Maximum => "18446744073709551615",
InputCase.Overflow => "18446744073709551616",
InputCase.TwentyOneDigits => "100000000000000000000",
InputCase.InvalidSuffix => "1234567890123456789x",
InputCase.InvalidAt3 => "123x5678901234567890",
InputCase.InvalidAt7 => "1234567x901234567890",
InputCase.InvalidAt11 => "12345678901x34567890",
InputCase.InvalidAt15 => "123456789012345x7890",
InputCase.LeadingZeros => "00000000000000000000",
_ => throw new InvalidOperationException(),
};
_source = Encoding.ASCII.GetBytes(text);
}
[Benchmark]
public ulong TryParse()
{
bool success = Utf8Parser.TryParse(_source, out ulong value, out int consumed, Format);
return value ^ ((ulong)(uint)consumed << 1) ^ (success ? 1UL : 0UL);
}
}
public enum InputCase
{
Empty,
Zero,
OneDigit,
FourDigits,
NineDigits,
TenDigits,
NineteenDigits,
Maximum,
Overflow,
TwentyOneDigits,
InvalidSuffix,
InvalidAt3,
InvalidAt7,
InvalidAt11,
InvalidAt15,
LeadingZeros,
}Note Benchmark request is AI-generated with Codex. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Improves decimal
Utf8Parser.TryParsethroughput forulonginputs long enough to require overflow checks.The new long-input path validates and parses the first 16 digits four bytes at a time, then uses the existing overflow logic for the remaining bytes. Inputs with a non-digit in the first 16 bytes fall back to the existing parser. Dispatch happens above
TryParseUInt64D, preserving its leaf codegen for common shorter inputs.Local BenchmarkDotNet results on Windows x64, Intel Core i7-12700K, .NET 10 source-built baseline/candidate, R2R disabled, 1 launch / 5 warmups / 10 iterations:
ulong.MaxValueShorter cases were equivalent under the 5% Mann-Whitney threshold. No benchmark allocates.
Validation:
ulongformat/parse roundtrips