Last active
October 8, 2019 14:06
-
-
Save Ruikuan/1066fb7af4deb0f6d50319ef1d98717b to your computer and use it in GitHub Desktop.
CorrelationIdGenerator.GenerateId Benchmark
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 BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
using System; | |
using System.Runtime.InteropServices; | |
namespace GenerateIdBenchmark | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var summary = BenchmarkRunner.Run<Generator>(); | |
} | |
} | |
[MemoryDiagnoser] | |
public class Generator | |
{ | |
private readonly static long _id = DateTime.UtcNow.Ticks; | |
[Benchmark(Baseline = true)] | |
public string GenerateId_Origin() => CorrelationIdGenerator_Origin.GenerateId(_id); | |
[Benchmark] | |
public string GenerateId() => CorrelationIdGenerator.GenerateId(_id); | |
} | |
internal static class CorrelationIdGenerator_Origin | |
{ | |
// Base32 encoding - in ascii sort order for easy text based sorting | |
private static readonly char[] s_encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV".ToCharArray(); | |
public static string GenerateId(long id) | |
{ | |
return string.Create(13, id, (buffer, value) => | |
{ | |
char[] encode32Chars = s_encode32Chars; | |
buffer[12] = encode32Chars[value & 31]; | |
buffer[11] = encode32Chars[(value >> 5) & 31]; | |
buffer[10] = encode32Chars[(value >> 10) & 31]; | |
buffer[9] = encode32Chars[(value >> 15) & 31]; | |
buffer[8] = encode32Chars[(value >> 20) & 31]; | |
buffer[7] = encode32Chars[(value >> 25) & 31]; | |
buffer[6] = encode32Chars[(value >> 30) & 31]; | |
buffer[5] = encode32Chars[(value >> 35) & 31]; | |
buffer[4] = encode32Chars[(value >> 40) & 31]; | |
buffer[3] = encode32Chars[(value >> 45) & 31]; | |
buffer[2] = encode32Chars[(value >> 50) & 31]; | |
buffer[1] = encode32Chars[(value >> 55) & 31]; | |
buffer[0] = encode32Chars[(value >> 60) & 31]; | |
}); | |
} | |
} | |
internal static class CorrelationIdGenerator | |
{ | |
// Base32 encoding - in ascii sort order for easy text based sorting | |
// 0123456789ABCDEFGHIJKLMNOPQRSTUV | |
// use this optimization: https://github.com/dotnet/roslyn/pull/24621 | |
private static ReadOnlySpan<byte> s_encode32Bytes => new byte[] { (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V' }; | |
public unsafe static string GenerateId(long id) | |
{ | |
return string.Create(13, id, (buffer, value) => | |
{ | |
Span<byte> bufferBytes = MemoryMarshal.Cast<char, byte>(buffer); | |
// ReadOnlySpan<byte> doesn't support long index, have to use pointer to avoid cast long to int. | |
fixed (byte* encode32Bytes = s_encode32Bytes) | |
{ | |
if (BitConverter.IsLittleEndian) | |
{ | |
bufferBytes[24] = encode32Bytes[value & 31]; | |
bufferBytes[22] = encode32Bytes[(value >> 5) & 31]; | |
bufferBytes[20] = encode32Bytes[(value >> 10) & 31]; | |
bufferBytes[18] = encode32Bytes[(value >> 15) & 31]; | |
bufferBytes[16] = encode32Bytes[(value >> 20) & 31]; | |
bufferBytes[14] = encode32Bytes[(value >> 25) & 31]; | |
bufferBytes[12] = encode32Bytes[(value >> 30) & 31]; | |
bufferBytes[10] = encode32Bytes[(value >> 35) & 31]; | |
bufferBytes[8] = encode32Bytes[(value >> 40) & 31]; | |
bufferBytes[6] = encode32Bytes[(value >> 45) & 31]; | |
bufferBytes[4] = encode32Bytes[(value >> 50) & 31]; | |
bufferBytes[2] = encode32Bytes[(value >> 55) & 31]; | |
bufferBytes[0] = encode32Bytes[(value >> 60) & 31]; | |
} | |
else | |
{ | |
bufferBytes[25] = encode32Bytes[value & 31]; | |
bufferBytes[23] = encode32Bytes[(value >> 5) & 31]; | |
bufferBytes[21] = encode32Bytes[(value >> 10) & 31]; | |
bufferBytes[19] = encode32Bytes[(value >> 15) & 31]; | |
bufferBytes[17] = encode32Bytes[(value >> 20) & 31]; | |
bufferBytes[15] = encode32Bytes[(value >> 25) & 31]; | |
bufferBytes[13] = encode32Bytes[(value >> 30) & 31]; | |
bufferBytes[11] = encode32Bytes[(value >> 35) & 31]; | |
bufferBytes[9] = encode32Bytes[(value >> 40) & 31]; | |
bufferBytes[7] = encode32Bytes[(value >> 45) & 31]; | |
bufferBytes[5] = encode32Bytes[(value >> 50) & 31]; | |
bufferBytes[3] = encode32Bytes[(value >> 55) & 31]; | |
bufferBytes[1] = encode32Bytes[(value >> 60) & 31]; | |
} | |
} | |
}); | |
} | |
} | |
} |
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
// * Summary * | |
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362 | |
Intel Core i7-3720QM CPU 2.60GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores | |
.NET Core SDK=3.0.100 | |
[Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT | |
DefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT | |
| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated | | |
|------------------ |---------:|----------:|----------:|------:|-------:|------:|------:|----------:| | |
| GenerateId_Origin | 18.19 ns | 0.1217 ns | 0.1079 ns | 1.00 | 0.0153 | - | - | 48 B | | |
| GenerateId | 16.50 ns | 0.0786 ns | 0.0697 ns | 0.91 | 0.0153 | - | - | 48 B | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment