Closed irodai-majom closed 3 weeks ago
Span
Convert.FromHexString
Used following bechmark to check the speedup:
HexToBytesSubstring
HexToBytesSlice
HexToBytesConvert
Results are:
| Method | N | Mean | Error | StdDev | Median | Allocated | |-------------------- |----- |-------------:|-----------:|-----------:|-------------:|----------:| | HexToBytesSubstring | 100 | 1,132.54 ns | 22.490 ns | 47.440 ns | 1,110.33 ns | 3328 B | | HexToBytesSlice | 100 | 583.82 ns | 11.586 ns | 23.668 ns | 570.63 ns | 128 B | | HexToBytesConvert | 100 | 35.21 ns | 0.570 ns | 0.818 ns | 34.87 ns | 128 B | | HexToBytesSubstring | 200 | 2,223.98 ns | 10.471 ns | 9.282 ns | 2,224.93 ns | 6624 B | | HexToBytesSlice | 200 | 1,154.18 ns | 5.493 ns | 4.587 ns | 1,152.19 ns | 224 B | | HexToBytesConvert | 200 | 61.24 ns | 0.875 ns | 0.731 ns | 60.86 ns | 224 B | | HexToBytesSubstring | 1000 | 12,626.88 ns | 220.443 ns | 195.417 ns | 12,550.49 ns | 33024 B | | HexToBytesSlice | 1000 | 5,764.04 ns | 10.413 ns | 8.696 ns | 5,764.74 ns | 1024 B | | HexToBytesConvert | 1000 | 296.51 ns | 0.337 ns | 0.315 ns | 296.47 ns | 1024 B |
You can notice improvement in both execution time and memory allocated.
Benchmark code:
using System.Globalization; using System.Text; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; namespace N_m3u8DL-RE.Benchmark; static class HexStingUtil { public static byte[] HexToBytesSubstring(string hex) { hex = hex.Trim(); if (hex.StartsWith("0x") || hex.StartsWith("0X")) hex = hex.Substring(2); byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < hex.Length; i += 2) { var hexDigit = hex.Substring(i, 2); bytes[i / 2] = Convert.ToByte(hexDigit, 16); } return bytes; } public static byte[] HexToBytesSlice(string hex) { var hexSpan = hex.AsSpan().Trim(); if (hexSpan.StartsWith("0x") || hexSpan.StartsWith("0X")) { hexSpan = hexSpan.Slice(2); } byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < hex.Length; i += 2) { ReadOnlySpan<char> hexDigit = hexSpan.Slice(start: i, length: 2); var val = byte.Parse(hexDigit, NumberStyles.HexNumber); bytes[i / 2] = val; } return bytes; } public static byte[] HexToBytesConvert(string hex) { var hexSpan = hex.AsSpan().Trim(); if (hexSpan.StartsWith("0x") || hexSpan.StartsWith("0X")) { hexSpan = hexSpan.Slice(2); } return Convert.FromHexString(hexSpan); } } [MemoryDiagnoser(false)] public class HexStringToBytesBenchmark { [Params(100, 200, 1000)] public int N; private string hexString; [GlobalSetup] public void Setup() { var buffer = new byte[N]; new Random().NextBytes(buffer); hexString = Convert.ToHexString(buffer); } [Benchmark] public byte[] HexToBytesSubstring() => HexStingUtil.HexToBytesSubstring(hexString); [Benchmark] public byte[] HexToBytesSlice() => HexStingUtil.HexToBytesSlice(hexString); [Benchmark] public byte[] HexToBytesConvert() => HexStingUtil.HexToBytesConvert(hexString); } public class RunBenchmark { public static void Main(string[] args) { var summary = BenchmarkRunner.Run<HexStringToBytesBenchmark>(); } }
Thx.
Span
Convert.FromHexString
vectorized functionUsed following bechmark to check the speedup:
HexToBytesSubstring
is existing implementationHexToBytesSlice
usesSpan
HexToBytesConvert
usesSpan
andConvert.FromHexString
library functionResults are:
You can notice improvement in both execution time and memory allocated.
Benchmark code: