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

Improve performance of integer formatting #76726

Merged
merged 3 commits into from
Oct 11, 2022

Conversation

stephentoub
Copy link
Member

Follow-up to #76519 (comment)

  1. The DivRem(..., 10) for each digit in the number ends up being the most expensive aspect of formatting. This employs a trick other formatting libraries use, which is to have a table for all the formatted values between 00 and 99, and to then DivRem(..., 100) to cut the number of operations in half, which for longer values is meaningful.
  2. Avoids going through the digit counting path when we know at the call site it won't be needed.
  3. Employs a branch-free, table-based lookup for CountDigits(ulong) to go with a similar approach added for uint.

The numbers from thesebenchmarks are almost all wins. The main exception is that the TryFormat, 1 digit, no format specifier case gets a little slower... it's repeatable on my machine, but also sub-ns.

private ulong[] _uint32Values = new ulong[]
{
    1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890,
};
private ulong[] _uint64Values = new ulong[]
{
    1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890,
    12345678901, 123456789012, 1234567890123, 12345678901234, 123456789012345, 1234567890123456, 12345678901234567, 123456789012345678, 1234567890123456789, 12345678901234567890,
};
private char[] _scratch = new char[32];

[Benchmark]
public int UInt32AllLengthsToString()
{
    int sum = 0;
    foreach (ulong value in _uint32Values) sum += value.ToString().Length;
    return sum;
}

[Benchmark]
public bool UInt32AllLengthsTryFormat()
{
    bool success = true;
    foreach (ulong value in _uint32Values) success |= value.TryFormat(_scratch, out _);
    return success;
}

[Benchmark]
public int UInt64AllLengthsToString()
{
    int sum = 0;
    foreach (ulong value in _uint64Values) sum += value.ToString().Length;
    return sum;
}

[Benchmark]
public bool UInt64AllLengthsTryFormat()
{
    bool success = true;
    foreach (ulong value in _uint64Values) success |= value.TryFormat(_scratch, out _);
    return success;
}

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
public string UInt32ToString(uint value) => value.ToString();

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
public bool UInt32TryFormat(uint value) => value.TryFormat(_scratch, out _);

[Benchmark]
[Arguments(1, "D")]
[Arguments(255, "D3")]
[Arguments(12345, "D5")]
[Arguments(1234567890, "D10")]
public bool UInt32TryFormatSpecifier(uint value, string format) => value.TryFormat(_scratch, out _, format);

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
[Arguments(12345678901)]
[Arguments(123456789012)]
[Arguments(1234567890123)]
[Arguments(12345678901234)]
[Arguments(123456789012345)]
[Arguments(1234567890123456)]
[Arguments(12345678901234567)]
[Arguments(123456789012345678)]
[Arguments(1234567890123456789)]
[Arguments(12345678901234567890)]
public string UInt64ToString(ulong value) => value.ToString();

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
[Arguments(12345678901)]
[Arguments(123456789012)]
[Arguments(1234567890123)]
[Arguments(12345678901234)]
[Arguments(123456789012345)]
[Arguments(1234567890123456)]
[Arguments(12345678901234567)]
[Arguments(123456789012345678)]
[Arguments(1234567890123456789)]
[Arguments(12345678901234567890)]
public bool UInt64TryFormat(ulong value) => value.TryFormat(_scratch, out _);

[Benchmark]
[Arguments(1ul, "D")]
[Arguments(255ul, "D3")]
[Arguments(12345ul, "D5")]
[Arguments(1234567890, "D10")]
[Arguments(12345678901234567890ul, "D20")]
public bool UInt64TryFormatSpecifier(ulong value, string format) => value.TryFormat(_scratch, out _, format);
Method Toolchain value format Mean Median Ratio
UInt32AllLengthsToString \main\corerun.exe ? ? 127.515 ns 127.328 ns 1.00
UInt32AllLengthsToString \pr\corerun.exe ? ? 109.178 ns 109.004 ns 0.86
UInt32AllLengthsTryFormat \main\corerun.exe ? ? 83.914 ns 84.299 ns 1.00
UInt32AllLengthsTryFormat \pr\corerun.exe ? ? 57.439 ns 56.949 ns 0.68
UInt64AllLengthsToString \main\corerun.exe ? ? 420.978 ns 415.873 ns 1.00
UInt64AllLengthsToString \pr\corerun.exe ? ? 307.218 ns 305.810 ns 0.71
UInt64AllLengthsTryFormat \main\corerun.exe ? ? 295.845 ns 294.455 ns 1.00
UInt64AllLengthsTryFormat \pr\corerun.exe ? ? 177.322 ns 176.300 ns 0.60
UInt32TryFormatSpecifier \main\corerun.exe 1 D 12.108 ns 12.058 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 1 D 11.463 ns 11.436 ns 0.95
UInt64TryFormatSpecifier \main\corerun.exe 1 D 12.808 ns 12.757 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 1 D 11.599 ns 11.601 ns 0.91
UInt32ToString \main\corerun.exe 1 ? 1.019 ns 1.010 ns 1.00
UInt32ToString \pr\corerun.exe 1 ? 1.026 ns 1.003 ns 1.01
UInt32TryFormat \main\corerun.exe 1 ? 1.854 ns 1.840 ns 1.00
UInt32TryFormat \pr\corerun.exe 1 ? 2.548 ns 2.543 ns 1.37
UInt64ToString \main\corerun.exe 1 ? 1.586 ns 1.578 ns 1.00
UInt64ToString \pr\corerun.exe 1 ? 1.535 ns 1.532 ns 0.97
UInt64TryFormat \main\corerun.exe 1 ? 2.457 ns 2.452 ns 1.00
UInt64TryFormat \pr\corerun.exe 1 ? 3.296 ns 3.282 ns 1.34
UInt32ToString \main\corerun.exe 12 ? 9.503 ns 9.473 ns 1.00
UInt32ToString \pr\corerun.exe 12 ? 9.503 ns 9.493 ns 1.00
UInt32TryFormat \main\corerun.exe 12 ? 2.773 ns 2.769 ns 1.00
UInt32TryFormat \pr\corerun.exe 12 ? 2.795 ns 2.780 ns 1.01
UInt64ToString \main\corerun.exe 12 ? 10.107 ns 10.103 ns 1.00
UInt64ToString \pr\corerun.exe 12 ? 9.406 ns 9.416 ns 0.93
UInt64TryFormat \main\corerun.exe 12 ? 3.778 ns 3.771 ns 1.00
UInt64TryFormat \pr\corerun.exe 12 ? 3.798 ns 3.778 ns 1.01
UInt32ToString \main\corerun.exe 123 ? 10.188 ns 10.195 ns 1.00
UInt32ToString \pr\corerun.exe 123 ? 10.194 ns 10.182 ns 1.00
UInt32TryFormat \main\corerun.exe 123 ? 3.459 ns 3.451 ns 1.00
UInt32TryFormat \pr\corerun.exe 123 ? 3.407 ns 3.390 ns 0.99
UInt64ToString \main\corerun.exe 123 ? 10.809 ns 10.777 ns 1.00
UInt64ToString \pr\corerun.exe 123 ? 10.284 ns 10.265 ns 0.95
UInt64TryFormat \main\corerun.exe 123 ? 4.772 ns 4.766 ns 1.00
UInt64TryFormat \pr\corerun.exe 123 ? 4.230 ns 4.219 ns 0.89
UInt64TryFormatSpecifier \main\corerun.exe 12345 D5 16.781 ns 16.779 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 12345 D5 16.955 ns 16.897 ns 1.01
UInt32TryFormatSpecifier \main\corerun.exe 255 D3 14.805 ns 14.808 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 255 D3 12.477 ns 12.435 ns 0.84
UInt32ToString \main\corerun.exe 1234 ? 10.775 ns 10.771 ns 1.00
UInt32ToString \pr\corerun.exe 1234 ? 10.641 ns 10.637 ns 0.99
UInt32TryFormat \main\corerun.exe 1234 ? 4.211 ns 4.187 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234 ? 3.637 ns 3.636 ns 0.86
UInt64ToString \main\corerun.exe 1234 ? 12.227 ns 12.224 ns 1.00
UInt64ToString \pr\corerun.exe 1234 ? 10.310 ns 10.298 ns 0.84
UInt64TryFormat \main\corerun.exe 1234 ? 6.090 ns 6.068 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234 ? 4.471 ns 4.469 ns 0.74
UInt32TryFormatSpecifier \main\corerun.exe 12345 D5 16.310 ns 16.266 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 12345 D5 13.192 ns 13.180 ns 0.81
UInt32ToString \main\corerun.exe 12345 ? 11.502 ns 11.499 ns 1.00
UInt32ToString \pr\corerun.exe 12345 ? 11.027 ns 10.963 ns 0.96
UInt32TryFormat \main\corerun.exe 12345 ? 4.964 ns 4.958 ns 1.00
UInt32TryFormat \pr\corerun.exe 12345 ? 4.295 ns 4.287 ns 0.86
UInt64ToString \main\corerun.exe 12345 ? 13.390 ns 13.332 ns 1.00
UInt64ToString \pr\corerun.exe 12345 ? 11.527 ns 11.536 ns 0.86
UInt64TryFormat \main\corerun.exe 12345 ? 7.249 ns 7.241 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345 ? 5.703 ns 5.690 ns 0.79
UInt32ToString \main\corerun.exe 123456 ? 13.331 ns 13.307 ns 1.00
UInt32ToString \pr\corerun.exe 123456 ? 12.316 ns 12.260 ns 0.92
UInt32TryFormat \main\corerun.exe 123456 ? 5.853 ns 5.844 ns 1.00
UInt32TryFormat \pr\corerun.exe 123456 ? 4.527 ns 4.523 ns 0.77
UInt64ToString \main\corerun.exe 123456 ? 14.744 ns 14.736 ns 1.00
UInt64ToString \pr\corerun.exe 123456 ? 12.577 ns 12.558 ns 0.85
UInt64TryFormat \main\corerun.exe 123456 ? 8.527 ns 8.477 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456 ? 5.943 ns 5.939 ns 0.70
UInt32ToString \main\corerun.exe 1234567 ? 14.198 ns 14.181 ns 1.00
UInt32ToString \pr\corerun.exe 1234567 ? 13.033 ns 13.019 ns 0.92
UInt32TryFormat \main\corerun.exe 1234567 ? 6.850 ns 6.792 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234567 ? 5.151 ns 5.135 ns 0.75
UInt64ToString \main\corerun.exe 1234567 ? 15.767 ns 15.794 ns 1.00
UInt64ToString \pr\corerun.exe 1234567 ? 13.776 ns 13.722 ns 0.87
UInt64TryFormat \main\corerun.exe 1234567 ? 9.584 ns 9.585 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567 ? 6.925 ns 6.874 ns 0.72
UInt32ToString \main\corerun.exe 12345678 ? 15.101 ns 15.073 ns 1.00
UInt32ToString \pr\corerun.exe 12345678 ? 13.021 ns 12.951 ns 0.86
UInt32TryFormat \main\corerun.exe 12345678 ? 7.677 ns 7.667 ns 1.00
UInt32TryFormat \pr\corerun.exe 12345678 ? 5.568 ns 5.504 ns 0.72
UInt64ToString \main\corerun.exe 12345678 ? 16.790 ns 16.739 ns 1.00
UInt64ToString \pr\corerun.exe 12345678 ? 13.571 ns 13.555 ns 0.81
UInt64TryFormat \main\corerun.exe 12345678 ? 10.555 ns 10.514 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678 ? 7.175 ns 7.176 ns 0.68
UInt32ToString \main\corerun.exe 123456789 ? 15.594 ns 15.568 ns 1.00
UInt32ToString \pr\corerun.exe 123456789 ? 13.681 ns 13.660 ns 0.88
UInt32TryFormat \main\corerun.exe 123456789 ? 8.559 ns 8.530 ns 1.00
UInt32TryFormat \pr\corerun.exe 123456789 ? 5.962 ns 5.959 ns 0.70
UInt64ToString \main\corerun.exe 123456789 ? 17.546 ns 17.532 ns 1.00
UInt64ToString \pr\corerun.exe 123456789 ? 15.114 ns 15.159 ns 0.86
UInt64TryFormat \main\corerun.exe 123456789 ? 11.878 ns 11.811 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789 ? 8.062 ns 8.017 ns 0.68
UInt32TryFormatSpecifier \main\corerun.exe 1234567890 D10 20.536 ns 20.496 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 1234567890 D10 16.416 ns 16.252 ns 0.80
UInt64TryFormatSpecifier \main\corerun.exe 1234567890 D10 23.154 ns 23.004 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 1234567890 D10 16.658 ns 16.666 ns 0.72
UInt32ToString \main\corerun.exe 1234567890 ? 17.062 ns 17.014 ns 1.00
UInt32ToString \pr\corerun.exe 1234567890 ? 15.110 ns 15.119 ns 0.89
UInt32TryFormat \main\corerun.exe 1234567890 ? 9.702 ns 9.671 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234567890 ? 6.775 ns 6.677 ns 0.70
UInt64ToString \main\corerun.exe 1234567890 ? 19.921 ns 19.510 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890 ? 16.077 ns 16.049 ns 0.79
UInt64TryFormat \main\corerun.exe 1234567890 ? 12.984 ns 12.954 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890 ? 8.585 ns 8.460 ns 0.67
UInt64ToString \main\corerun.exe 12345678901 ? 20.863 ns 20.869 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901 ? 16.707 ns 16.585 ns 0.80
UInt64TryFormat \main\corerun.exe 12345678901 ? 14.031 ns 13.914 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901 ? 9.301 ns 9.254 ns 0.66
UInt64ToString \main\corerun.exe 123456789012 ? 22.401 ns 22.378 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012 ? 17.247 ns 17.150 ns 0.77
UInt64TryFormat \main\corerun.exe 123456789012 ? 15.201 ns 15.173 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012 ? 9.663 ns 9.629 ns 0.64
UInt64ToString \main\corerun.exe 1234567890123 ? 23.388 ns 23.385 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123 ? 17.558 ns 17.511 ns 0.75
UInt64TryFormat \main\corerun.exe 1234567890123 ? 17.178 ns 16.888 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123 ? 10.494 ns 10.417 ns 0.60
UInt64ToString \main\corerun.exe 12345678901234 ? 25.390 ns 25.387 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234 ? 18.676 ns 18.537 ns 0.74
UInt64TryFormat \main\corerun.exe 12345678901234 ? 17.851 ns 17.828 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234 ? 10.769 ns 10.739 ns 0.60
UInt64ToString \main\corerun.exe 123456789012345 ? 25.880 ns 25.859 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012345 ? 19.617 ns 19.537 ns 0.76
UInt64TryFormat \main\corerun.exe 123456789012345 ? 18.584 ns 18.576 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012345 ? 11.664 ns 11.620 ns 0.63
UInt64ToString \main\corerun.exe 1234567890123456 ? 27.938 ns 27.902 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123456 ? 19.998 ns 19.892 ns 0.72
UInt64TryFormat \main\corerun.exe 1234567890123456 ? 20.263 ns 20.143 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123456 ? 11.900 ns 11.896 ns 0.59
UInt64ToString \main\corerun.exe 12345678901234567 ? 29.970 ns 29.987 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234567 ? 21.236 ns 21.208 ns 0.71
UInt64TryFormat \main\corerun.exe 12345678901234567 ? 21.718 ns 21.708 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234567 ? 13.200 ns 13.172 ns 0.61
UInt64ToString \main\corerun.exe 123456789012345678 ? 31.832 ns 31.719 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012345678 ? 21.725 ns 21.723 ns 0.68
UInt64TryFormat \main\corerun.exe 123456789012345678 ? 23.249 ns 23.249 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012345678 ? 13.124 ns 13.092 ns 0.56
UInt64ToString \main\corerun.exe 1234567890123456789 ? 33.333 ns 33.298 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123456789 ? 24.673 ns 24.061 ns 0.75
UInt64TryFormat \main\corerun.exe 1234567890123456789 ? 24.515 ns 24.524 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123456789 ? 14.243 ns 14.203 ns 0.58
UInt64TryFormatSpecifier \main\corerun.exe 12345678901234567890 D20 35.477 ns 35.049 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 12345678901234567890 D20 23.631 ns 23.265 ns 0.67
UInt64ToString \main\corerun.exe 12345678901234567890 ? 35.382 ns 35.413 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234567890 ? 23.183 ns 23.105 ns 0.66
UInt64TryFormat \main\corerun.exe 12345678901234567890 ? 27.412 ns 27.096 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234567890 ? 14.574 ns 14.427 ns 0.54
UInt64TryFormatSpecifier \main\corerun.exe 255 D3 15.476 ns 15.294 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 255 D3 13.534 ns 13.323 ns 0.88

1. The DivRem(..., 10) for each digit in the number ends up being the most expensive aspect of formatting.  This employs a trick other formatting libraries use, which is to have a table for all the formatted values between 00 and 99, and to then DivRem(..., 100) to cut the number of operations in half, which for longer values is meaningful.
2. Avoids going through the digit counting path when we know at the call site it won't be needed.
3. Employs a branch-free, table-based lookup for CountDigits(ulong) to go with a similar approach added for uint.
@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.

@ghost
Copy link

ghost commented Oct 6, 2022

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

Issue Details

Follow-up to #76519 (comment)

  1. The DivRem(..., 10) for each digit in the number ends up being the most expensive aspect of formatting. This employs a trick other formatting libraries use, which is to have a table for all the formatted values between 00 and 99, and to then DivRem(..., 100) to cut the number of operations in half, which for longer values is meaningful.
  2. Avoids going through the digit counting path when we know at the call site it won't be needed.
  3. Employs a branch-free, table-based lookup for CountDigits(ulong) to go with a similar approach added for uint.

The numbers from thesebenchmarks are almost all wins. The main exception is that the TryFormat, 1 digit, no format specifier case gets a little slower... it's repeatable on my machine, but also sub-ns.

private ulong[] _uint32Values = new ulong[]
{
    1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890,
};
private ulong[] _uint64Values = new ulong[]
{
    1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890,
    12345678901, 123456789012, 1234567890123, 12345678901234, 123456789012345, 1234567890123456, 12345678901234567, 123456789012345678, 1234567890123456789, 12345678901234567890,
};
private char[] _scratch = new char[32];

[Benchmark]
public int UInt32AllLengthsToString()
{
    int sum = 0;
    foreach (ulong value in _uint32Values) sum += value.ToString().Length;
    return sum;
}

[Benchmark]
public bool UInt32AllLengthsTryFormat()
{
    bool success = true;
    foreach (ulong value in _uint32Values) success |= value.TryFormat(_scratch, out _);
    return success;
}

[Benchmark]
public int UInt64AllLengthsToString()
{
    int sum = 0;
    foreach (ulong value in _uint64Values) sum += value.ToString().Length;
    return sum;
}

[Benchmark]
public bool UInt64AllLengthsTryFormat()
{
    bool success = true;
    foreach (ulong value in _uint64Values) success |= value.TryFormat(_scratch, out _);
    return success;
}

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
public string UInt32ToString(uint value) => value.ToString();

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
public bool UInt32TryFormat(uint value) => value.TryFormat(_scratch, out _);

[Benchmark]
[Arguments(1, "D")]
[Arguments(255, "D3")]
[Arguments(12345, "D5")]
[Arguments(1234567890, "D10")]
public bool UInt32TryFormatSpecifier(uint value, string format) => value.TryFormat(_scratch, out _, format);

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
[Arguments(12345678901)]
[Arguments(123456789012)]
[Arguments(1234567890123)]
[Arguments(12345678901234)]
[Arguments(123456789012345)]
[Arguments(1234567890123456)]
[Arguments(12345678901234567)]
[Arguments(123456789012345678)]
[Arguments(1234567890123456789)]
[Arguments(12345678901234567890)]
public string UInt64ToString(ulong value) => value.ToString();

[Benchmark]
[Arguments(1)]
[Arguments(12)]
[Arguments(123)]
[Arguments(1234)]
[Arguments(12345)]
[Arguments(123456)]
[Arguments(1234567)]
[Arguments(12345678)]
[Arguments(123456789)]
[Arguments(1234567890)]
[Arguments(12345678901)]
[Arguments(123456789012)]
[Arguments(1234567890123)]
[Arguments(12345678901234)]
[Arguments(123456789012345)]
[Arguments(1234567890123456)]
[Arguments(12345678901234567)]
[Arguments(123456789012345678)]
[Arguments(1234567890123456789)]
[Arguments(12345678901234567890)]
public bool UInt64TryFormat(ulong value) => value.TryFormat(_scratch, out _);

[Benchmark]
[Arguments(1ul, "D")]
[Arguments(255ul, "D3")]
[Arguments(12345ul, "D5")]
[Arguments(1234567890, "D10")]
[Arguments(12345678901234567890ul, "D20")]
public bool UInt64TryFormatSpecifier(ulong value, string format) => value.TryFormat(_scratch, out _, format);
Method Toolchain value format Mean Median Ratio
UInt32AllLengthsToString \main\corerun.exe ? ? 127.515 ns 127.328 ns 1.00
UInt32AllLengthsToString \pr\corerun.exe ? ? 109.178 ns 109.004 ns 0.86
UInt32AllLengthsTryFormat \main\corerun.exe ? ? 83.914 ns 84.299 ns 1.00
UInt32AllLengthsTryFormat \pr\corerun.exe ? ? 57.439 ns 56.949 ns 0.68
UInt64AllLengthsToString \main\corerun.exe ? ? 420.978 ns 415.873 ns 1.00
UInt64AllLengthsToString \pr\corerun.exe ? ? 307.218 ns 305.810 ns 0.71
UInt64AllLengthsTryFormat \main\corerun.exe ? ? 295.845 ns 294.455 ns 1.00
UInt64AllLengthsTryFormat \pr\corerun.exe ? ? 177.322 ns 176.300 ns 0.60
UInt32TryFormatSpecifier \main\corerun.exe 1 D 12.108 ns 12.058 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 1 D 11.463 ns 11.436 ns 0.95
UInt64TryFormatSpecifier \main\corerun.exe 1 D 12.808 ns 12.757 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 1 D 11.599 ns 11.601 ns 0.91
UInt32ToString \main\corerun.exe 1 ? 1.019 ns 1.010 ns 1.00
UInt32ToString \pr\corerun.exe 1 ? 1.026 ns 1.003 ns 1.01
UInt32TryFormat \main\corerun.exe 1 ? 1.854 ns 1.840 ns 1.00
UInt32TryFormat \pr\corerun.exe 1 ? 2.548 ns 2.543 ns 1.37
UInt64ToString \main\corerun.exe 1 ? 1.586 ns 1.578 ns 1.00
UInt64ToString \pr\corerun.exe 1 ? 1.535 ns 1.532 ns 0.97
UInt64TryFormat \main\corerun.exe 1 ? 2.457 ns 2.452 ns 1.00
UInt64TryFormat \pr\corerun.exe 1 ? 3.296 ns 3.282 ns 1.34
UInt32ToString \main\corerun.exe 12 ? 9.503 ns 9.473 ns 1.00
UInt32ToString \pr\corerun.exe 12 ? 9.503 ns 9.493 ns 1.00
UInt32TryFormat \main\corerun.exe 12 ? 2.773 ns 2.769 ns 1.00
UInt32TryFormat \pr\corerun.exe 12 ? 2.795 ns 2.780 ns 1.01
UInt64ToString \main\corerun.exe 12 ? 10.107 ns 10.103 ns 1.00
UInt64ToString \pr\corerun.exe 12 ? 9.406 ns 9.416 ns 0.93
UInt64TryFormat \main\corerun.exe 12 ? 3.778 ns 3.771 ns 1.00
UInt64TryFormat \pr\corerun.exe 12 ? 3.798 ns 3.778 ns 1.01
UInt32ToString \main\corerun.exe 123 ? 10.188 ns 10.195 ns 1.00
UInt32ToString \pr\corerun.exe 123 ? 10.194 ns 10.182 ns 1.00
UInt32TryFormat \main\corerun.exe 123 ? 3.459 ns 3.451 ns 1.00
UInt32TryFormat \pr\corerun.exe 123 ? 3.407 ns 3.390 ns 0.99
UInt64ToString \main\corerun.exe 123 ? 10.809 ns 10.777 ns 1.00
UInt64ToString \pr\corerun.exe 123 ? 10.284 ns 10.265 ns 0.95
UInt64TryFormat \main\corerun.exe 123 ? 4.772 ns 4.766 ns 1.00
UInt64TryFormat \pr\corerun.exe 123 ? 4.230 ns 4.219 ns 0.89
UInt64TryFormatSpecifier \main\corerun.exe 12345 D5 16.781 ns 16.779 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 12345 D5 16.955 ns 16.897 ns 1.01
UInt32TryFormatSpecifier \main\corerun.exe 255 D3 14.805 ns 14.808 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 255 D3 12.477 ns 12.435 ns 0.84
UInt32ToString \main\corerun.exe 1234 ? 10.775 ns 10.771 ns 1.00
UInt32ToString \pr\corerun.exe 1234 ? 10.641 ns 10.637 ns 0.99
UInt32TryFormat \main\corerun.exe 1234 ? 4.211 ns 4.187 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234 ? 3.637 ns 3.636 ns 0.86
UInt64ToString \main\corerun.exe 1234 ? 12.227 ns 12.224 ns 1.00
UInt64ToString \pr\corerun.exe 1234 ? 10.310 ns 10.298 ns 0.84
UInt64TryFormat \main\corerun.exe 1234 ? 6.090 ns 6.068 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234 ? 4.471 ns 4.469 ns 0.74
UInt32TryFormatSpecifier \main\corerun.exe 12345 D5 16.310 ns 16.266 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 12345 D5 13.192 ns 13.180 ns 0.81
UInt32ToString \main\corerun.exe 12345 ? 11.502 ns 11.499 ns 1.00
UInt32ToString \pr\corerun.exe 12345 ? 11.027 ns 10.963 ns 0.96
UInt32TryFormat \main\corerun.exe 12345 ? 4.964 ns 4.958 ns 1.00
UInt32TryFormat \pr\corerun.exe 12345 ? 4.295 ns 4.287 ns 0.86
UInt64ToString \main\corerun.exe 12345 ? 13.390 ns 13.332 ns 1.00
UInt64ToString \pr\corerun.exe 12345 ? 11.527 ns 11.536 ns 0.86
UInt64TryFormat \main\corerun.exe 12345 ? 7.249 ns 7.241 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345 ? 5.703 ns 5.690 ns 0.79
UInt32ToString \main\corerun.exe 123456 ? 13.331 ns 13.307 ns 1.00
UInt32ToString \pr\corerun.exe 123456 ? 12.316 ns 12.260 ns 0.92
UInt32TryFormat \main\corerun.exe 123456 ? 5.853 ns 5.844 ns 1.00
UInt32TryFormat \pr\corerun.exe 123456 ? 4.527 ns 4.523 ns 0.77
UInt64ToString \main\corerun.exe 123456 ? 14.744 ns 14.736 ns 1.00
UInt64ToString \pr\corerun.exe 123456 ? 12.577 ns 12.558 ns 0.85
UInt64TryFormat \main\corerun.exe 123456 ? 8.527 ns 8.477 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456 ? 5.943 ns 5.939 ns 0.70
UInt32ToString \main\corerun.exe 1234567 ? 14.198 ns 14.181 ns 1.00
UInt32ToString \pr\corerun.exe 1234567 ? 13.033 ns 13.019 ns 0.92
UInt32TryFormat \main\corerun.exe 1234567 ? 6.850 ns 6.792 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234567 ? 5.151 ns 5.135 ns 0.75
UInt64ToString \main\corerun.exe 1234567 ? 15.767 ns 15.794 ns 1.00
UInt64ToString \pr\corerun.exe 1234567 ? 13.776 ns 13.722 ns 0.87
UInt64TryFormat \main\corerun.exe 1234567 ? 9.584 ns 9.585 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567 ? 6.925 ns 6.874 ns 0.72
UInt32ToString \main\corerun.exe 12345678 ? 15.101 ns 15.073 ns 1.00
UInt32ToString \pr\corerun.exe 12345678 ? 13.021 ns 12.951 ns 0.86
UInt32TryFormat \main\corerun.exe 12345678 ? 7.677 ns 7.667 ns 1.00
UInt32TryFormat \pr\corerun.exe 12345678 ? 5.568 ns 5.504 ns 0.72
UInt64ToString \main\corerun.exe 12345678 ? 16.790 ns 16.739 ns 1.00
UInt64ToString \pr\corerun.exe 12345678 ? 13.571 ns 13.555 ns 0.81
UInt64TryFormat \main\corerun.exe 12345678 ? 10.555 ns 10.514 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678 ? 7.175 ns 7.176 ns 0.68
UInt32ToString \main\corerun.exe 123456789 ? 15.594 ns 15.568 ns 1.00
UInt32ToString \pr\corerun.exe 123456789 ? 13.681 ns 13.660 ns 0.88
UInt32TryFormat \main\corerun.exe 123456789 ? 8.559 ns 8.530 ns 1.00
UInt32TryFormat \pr\corerun.exe 123456789 ? 5.962 ns 5.959 ns 0.70
UInt64ToString \main\corerun.exe 123456789 ? 17.546 ns 17.532 ns 1.00
UInt64ToString \pr\corerun.exe 123456789 ? 15.114 ns 15.159 ns 0.86
UInt64TryFormat \main\corerun.exe 123456789 ? 11.878 ns 11.811 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789 ? 8.062 ns 8.017 ns 0.68
UInt32TryFormatSpecifier \main\corerun.exe 1234567890 D10 20.536 ns 20.496 ns 1.00
UInt32TryFormatSpecifier \pr\corerun.exe 1234567890 D10 16.416 ns 16.252 ns 0.80
UInt64TryFormatSpecifier \main\corerun.exe 1234567890 D10 23.154 ns 23.004 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 1234567890 D10 16.658 ns 16.666 ns 0.72
UInt32ToString \main\corerun.exe 1234567890 ? 17.062 ns 17.014 ns 1.00
UInt32ToString \pr\corerun.exe 1234567890 ? 15.110 ns 15.119 ns 0.89
UInt32TryFormat \main\corerun.exe 1234567890 ? 9.702 ns 9.671 ns 1.00
UInt32TryFormat \pr\corerun.exe 1234567890 ? 6.775 ns 6.677 ns 0.70
UInt64ToString \main\corerun.exe 1234567890 ? 19.921 ns 19.510 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890 ? 16.077 ns 16.049 ns 0.79
UInt64TryFormat \main\corerun.exe 1234567890 ? 12.984 ns 12.954 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890 ? 8.585 ns 8.460 ns 0.67
UInt64ToString \main\corerun.exe 12345678901 ? 20.863 ns 20.869 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901 ? 16.707 ns 16.585 ns 0.80
UInt64TryFormat \main\corerun.exe 12345678901 ? 14.031 ns 13.914 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901 ? 9.301 ns 9.254 ns 0.66
UInt64ToString \main\corerun.exe 123456789012 ? 22.401 ns 22.378 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012 ? 17.247 ns 17.150 ns 0.77
UInt64TryFormat \main\corerun.exe 123456789012 ? 15.201 ns 15.173 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012 ? 9.663 ns 9.629 ns 0.64
UInt64ToString \main\corerun.exe 1234567890123 ? 23.388 ns 23.385 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123 ? 17.558 ns 17.511 ns 0.75
UInt64TryFormat \main\corerun.exe 1234567890123 ? 17.178 ns 16.888 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123 ? 10.494 ns 10.417 ns 0.60
UInt64ToString \main\corerun.exe 12345678901234 ? 25.390 ns 25.387 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234 ? 18.676 ns 18.537 ns 0.74
UInt64TryFormat \main\corerun.exe 12345678901234 ? 17.851 ns 17.828 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234 ? 10.769 ns 10.739 ns 0.60
UInt64ToString \main\corerun.exe 123456789012345 ? 25.880 ns 25.859 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012345 ? 19.617 ns 19.537 ns 0.76
UInt64TryFormat \main\corerun.exe 123456789012345 ? 18.584 ns 18.576 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012345 ? 11.664 ns 11.620 ns 0.63
UInt64ToString \main\corerun.exe 1234567890123456 ? 27.938 ns 27.902 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123456 ? 19.998 ns 19.892 ns 0.72
UInt64TryFormat \main\corerun.exe 1234567890123456 ? 20.263 ns 20.143 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123456 ? 11.900 ns 11.896 ns 0.59
UInt64ToString \main\corerun.exe 12345678901234567 ? 29.970 ns 29.987 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234567 ? 21.236 ns 21.208 ns 0.71
UInt64TryFormat \main\corerun.exe 12345678901234567 ? 21.718 ns 21.708 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234567 ? 13.200 ns 13.172 ns 0.61
UInt64ToString \main\corerun.exe 123456789012345678 ? 31.832 ns 31.719 ns 1.00
UInt64ToString \pr\corerun.exe 123456789012345678 ? 21.725 ns 21.723 ns 0.68
UInt64TryFormat \main\corerun.exe 123456789012345678 ? 23.249 ns 23.249 ns 1.00
UInt64TryFormat \pr\corerun.exe 123456789012345678 ? 13.124 ns 13.092 ns 0.56
UInt64ToString \main\corerun.exe 1234567890123456789 ? 33.333 ns 33.298 ns 1.00
UInt64ToString \pr\corerun.exe 1234567890123456789 ? 24.673 ns 24.061 ns 0.75
UInt64TryFormat \main\corerun.exe 1234567890123456789 ? 24.515 ns 24.524 ns 1.00
UInt64TryFormat \pr\corerun.exe 1234567890123456789 ? 14.243 ns 14.203 ns 0.58
UInt64TryFormatSpecifier \main\corerun.exe 12345678901234567890 D20 35.477 ns 35.049 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 12345678901234567890 D20 23.631 ns 23.265 ns 0.67
UInt64ToString \main\corerun.exe 12345678901234567890 ? 35.382 ns 35.413 ns 1.00
UInt64ToString \pr\corerun.exe 12345678901234567890 ? 23.183 ns 23.105 ns 0.66
UInt64TryFormat \main\corerun.exe 12345678901234567890 ? 27.412 ns 27.096 ns 1.00
UInt64TryFormat \pr\corerun.exe 12345678901234567890 ? 14.574 ns 14.427 ns 0.54
UInt64TryFormatSpecifier \main\corerun.exe 255 D3 15.476 ns 15.294 ns 1.00
UInt64TryFormatSpecifier \pr\corerun.exe 255 D3 13.534 ns 13.323 ns 0.88
Author: stephentoub
Assignees: stephentoub
Labels:

area-System.Runtime

Milestone: -

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Nice!

@stephentoub stephentoub merged commit 5892ef2 into dotnet:main Oct 11, 2022
@stephentoub stephentoub deleted the fasterintegerformatting branch October 11, 2022 04:05
@ghost ghost locked as resolved and limited conversation to collaborators Nov 10, 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.

4 participants