Skip to content

Instantly share code, notes, and snippets.

@medigor
Last active January 8, 2021 11:22
Show Gist options
  • Save medigor/0e421617de8ecf6ff57af4773fa20934 to your computer and use it in GitHub Desktop.
Save medigor/0e421617de8ecf6ff57af4773fa20934 to your computer and use it in GitHub Desktop.
#nowarn "9"
open System
open System.Globalization
open Microsoft.FSharp.NativeInterop
open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Running
let inline private stackalloc<'a when 'a: unmanaged> size =
let p = NativePtr.stackalloc<'a> size |> NativePtr.toVoidPtr
Span<'a>(p, size)
let inline hexToDec(hex: byte) =
if hex > '9'B then
hex - 'a'B + 10uy
else
hex - '0'B
let inline hexToInt64 (bytes: ReadOnlySpan<byte>) =
let mutable x = 0L
let last = bytes.Length - 1
for i = 0 to last do
x <- x + (int64(hexToDec bytes.[i]) <<< 4*(last - i))
x
let inline hexTo (f: byte-> ^a) (bytes: ReadOnlySpan<byte>): ^a =
let mutable x = LanguagePrimitives.GenericZero
let last = bytes.Length - 1
for i = 0 to last do
x <- x + (f(hexToDec bytes.[i]) <<< 4*(last - i))
x
[<MemoryDiagnoser>]
type Tests() =
member _.Data() = seq {
"243c104b2d800"B
}
[<Benchmark(Baseline = true)>]
[<ArgumentsSource("Data")>]
member _.HexToInt64(bytes: array<byte>) =
hexToInt64 (ReadOnlySpan(bytes))
[<Benchmark>]
[<ArgumentsSource("Data")>]
member _.HexToInt64Generic(bytes: array<byte>) =
hexTo int64 (ReadOnlySpan(bytes))
[<Benchmark>]
[<ArgumentsSource("Data")>]
member _.ConvertToInt64(bytes: array<byte>) =
let a = Text.Encoding.UTF8.GetString(ReadOnlySpan(bytes))
Convert.ToInt64(a, 16)
[<Benchmark>]
[<ArgumentsSource("Data")>]
member _.Int64Parse(bytes: array<byte>) =
let a = Text.Encoding.UTF8.GetString(ReadOnlySpan(bytes))
Int64.Parse(a, NumberStyles.HexNumber, CultureInfo.InvariantCulture)
[<Benchmark>]
[<ArgumentsSource("Data")>]
member _.Int64ParseAllocFree(bytes: array<byte>) =
let input = ReadOnlySpan(bytes)
let a = stackalloc<char> bytes.Length
for i = 0 to bytes.Length - 1 do
a.[i] <- char(input.[i])
Int64.Parse(Span.op_Implicit a, NumberStyles.HexNumber, CultureInfo.InvariantCulture)
[<EntryPoint>]
let main argv =
BenchmarkRunner.Run<Tests>() |> ignore
let t = Tests()
let bytes = t.Data() |> Seq.head
t.HexToInt64 bytes |> Console.WriteLine
t.HexToInt64Generic bytes |> Console.WriteLine
t.ConvertToInt64 bytes |> Console.WriteLine
t.Int64Parse bytes |> Console.WriteLine
t.Int64ParseAllocFree bytes |> Console.WriteLine
0
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-4771 CPU 3.50GHz (Haswell), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.101
  [Host]     : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT DEBUG
  DefaultJob : .NET Core 5.0.1 (CoreCLR 5.0.120.57516, CoreFX 5.0.120.57516), X64 RyuJIT

Method bytes Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
HexToInt64 Byte[13] 19.09 ns 0.370 ns 0.346 ns 1.00 0.00 - - - -
HexToInt64Generic Byte[13] 19.04 ns 0.217 ns 0.181 ns 1.00 0.02 - - - -
ConvertToInt64 Byte[13] 76.62 ns 1.287 ns 1.483 ns 4.01 0.11 0.0114 - - 48 B
Int64Parse Byte[13] 64.19 ns 1.220 ns 1.141 ns 3.36 0.06 0.0114 - - 48 B
Int64ParseAllocFree Byte[13] 41.94 ns 0.845 ns 0.791 ns 2.20 0.06 - - - -
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment