Last active
April 5, 2018 06:41
-
-
Save Tornhoof/7bac156e3b664e3bef36f236de21cf42 to your computer and use it in GitHub Desktop.
Benchmark Integer Formatting
This file contains 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
using System; | |
using System.Runtime.CompilerServices; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace FormatIntegerPerformance | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
BenchmarkRunner.Run<Benchmark>(); | |
} | |
} | |
[MemoryDiagnoser] | |
public class Benchmark | |
{ | |
const int Number = 123456789; | |
private static readonly NumberFormatter Formatter = new NumberFormatter(); | |
[Benchmark(Description = "Integer Formatting in CoreCLR")] | |
public string CoreClr() | |
{ | |
Span<char> span = stackalloc char[21]; | |
int pos = 0; | |
Formatter.WriteInt64CoreClr(span, ref pos, Number); | |
return span.Slice(0, pos).ToString(); | |
} | |
[Benchmark(Description = "Integer Formatting in Utf8Json")] | |
public string Utf8Json() | |
{ | |
Span<char> span = stackalloc char[21]; | |
int pos = 0; | |
Formatter.WriteInt64Utf8Json(span, ref pos, Number); | |
return span.Slice(0, pos).ToString(); | |
} | |
[Benchmark(Description = "Integer Formatting in System.Buffeers.Text.Utf8Formatter")] | |
public byte[] Utf8Formatter() | |
{ | |
var result = new byte[21]; | |
Span<byte> span = result; | |
System.Buffers.Text.Utf8Formatter.TryFormat(Number, span, out var written); | |
return result; | |
} | |
} | |
public class NumberFormatter | |
{ | |
public void WriteInt64Utf8Json(Span<char> chars, ref int pos, long value) | |
{ | |
if (value < 0) | |
{ | |
chars[pos++] = '-'; | |
value = unchecked(-value); | |
} | |
WriteUInt64(chars.Slice(pos), ref pos, (ulong)value); | |
} | |
public void WriteInt64CoreClr(Span<char> chars, ref int pos, long value) | |
{ | |
value.TryFormat(chars.Slice(pos), out var written); | |
pos += written; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
// https://github.com/neuecc/Utf8Json/blob/master/src/Utf8Json/Internal/NumberConverter.cs | |
// or https://stackoverflow.com/questions/4351371/c-performance-challenge-integer-to-stdstring-conversion | |
private void WriteUInt64(Span<char> chars, ref int pos, ulong value) | |
{ | |
var num1 = value; | |
ulong div; | |
if (num1 < 10000) | |
{ | |
if (num1 < 10) | |
{ | |
goto L1; | |
} | |
if (num1 < 100) | |
{ | |
goto L2; | |
} | |
if (num1 < 1000) | |
{ | |
goto L3; | |
} | |
goto L4; | |
} | |
else | |
{ | |
var num2 = num1 / 10000; | |
num1 -= num2 * 10000; | |
if (num2 < 10000) | |
{ | |
if (num2 < 10) | |
{ | |
goto L5; | |
} | |
if (num2 < 100) | |
{ | |
goto L6; | |
} | |
if (num2 < 1000) | |
{ | |
goto L7; | |
} | |
goto L8; | |
} | |
else | |
{ | |
var num3 = num2 / 10000; | |
num2 -= num3 * 10000; | |
if (num3 < 10000) | |
{ | |
if (num3 < 10) | |
{ | |
goto L9; | |
} | |
if (num3 < 100) | |
{ | |
goto L10; | |
} | |
if (num3 < 1000) | |
{ | |
goto L11; | |
} | |
goto L12; | |
} | |
else | |
{ | |
var num4 = num3 / 10000; | |
num3 -= num4 * 10000; | |
if (num4 < 10000) | |
{ | |
if (num4 < 10) | |
{ | |
goto L13; | |
} | |
if (num4 < 100) | |
{ | |
goto L14; | |
} | |
if (num4 < 1000) | |
{ | |
goto L15; | |
} | |
goto L16; | |
} | |
else | |
{ | |
var num5 = num4 / 10000; | |
num4 -= num5 * 10000; | |
if (num5 < 10000) | |
{ | |
if (num5 < 10) | |
{ | |
goto L17; | |
} | |
if (num5 < 100) | |
{ | |
goto L18; | |
} | |
if (num5 < 1000) | |
{ | |
goto L19; | |
} | |
goto L20; | |
} | |
L20: | |
chars[pos++] = (char)('0' + (div = (num5 * 8389L) >> 23)); | |
num5 -= div * 1000; | |
L19: | |
chars[pos++] = (char)('0' + (div = (num5 * 5243L) >> 19)); | |
num5 -= div * 100; | |
L18: | |
chars[pos++] = (char)('0' + (div = (num5 * 6554L) >> 16)); | |
num5 -= div * 10; | |
L17: | |
chars[pos++] = (char)('0' + (num5)); | |
} | |
L16: | |
chars[pos++] = (char)('0' + (div = (num4 * 8389L) >> 23)); | |
num4 -= div * 1000; | |
L15: | |
chars[pos++] = (char)('0' + (div = (num4 * 5243L) >> 19)); | |
num4 -= div * 100; | |
L14: | |
chars[pos++] = (char)('0' + (div = (num4 * 6554L) >> 16)); | |
num4 -= div * 10; | |
L13: | |
chars[pos++] = (char)('0' + (num4)); | |
} | |
L12: | |
chars[pos++] = (char)('0' + (div = (num3 * 8389L) >> 23)); | |
num3 -= div * 1000; | |
L11: | |
chars[pos++] = (char)('0' + (div = (num3 * 5243L) >> 19)); | |
num3 -= div * 100; | |
L10: | |
chars[pos++] = (char)('0' + (div = (num3 * 6554L) >> 16)); | |
num3 -= div * 10; | |
L9: | |
chars[pos++] = (char)('0' + (num3)); | |
} | |
L8: | |
chars[pos++] = (char)('0' + (div = (num2 * 8389L) >> 23)); | |
num2 -= div * 1000; | |
L7: | |
chars[pos++] = (char)('0' + (div = (num2 * 5243L) >> 19)); | |
num2 -= div * 100; | |
L6: | |
chars[pos++] = (char)('0' + (div = (num2 * 6554L) >> 16)); | |
num2 -= div * 10; | |
L5: | |
chars[pos++] = (char)('0' + (num2)); | |
} | |
L4: | |
chars[pos++] = (char)('0' + (div = (num1 * 8389L) >> 23)); | |
num1 -= div * 1000; | |
L3: | |
chars[pos++] = (char)('0' + (div = (num1 * 5243L) >> 19)); | |
num1 -= div * 100; | |
L2: | |
chars[pos++] = (char)('0' + (div = (num1 * 6554L) >> 16)); | |
num1 -= div * 10; | |
L1: | |
chars[pos++] = (char)('0' + (num1)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment