Skip to content

Optimize Random.GetHexString #116192

Open
Open
@skyoxZ

Description

@skyoxZ

Random.Shared.GetHexString can be optimized by:

  1. Getting 2 (instead of 1) hex chars from every random byte.
  2. Taking advantage of the magic in HexConverter.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<Benchmarks>();

public class Benchmarks
{
    [Params(2, 5, 8, 16, 32, 64)]
    public int HexStringLength;

    [Benchmark]
    public char Main()
    {
        Span<char> buffer = stackalloc char[HexStringLength];
        Random.Shared.GetHexString(buffer);
        return buffer[0];
    }

    [Benchmark]
    public char Opt()
    {
        Span<char> buffer = stackalloc char[HexStringLength];
        Random_GetHexString(buffer);
        return buffer[0];
    }

    private static void Random_GetHexString(Span<char> destination, bool lowercase = false)
    {
        // Scale the string length up to the nearest multiple of 16.
        // For production code, we should slice destionation into small pieces first in case it's large.
        Span<byte> source = stackalloc byte[((destination.Length + 15) & -16) / 2];
        Random.Shared.NextBytes(source);
        if (destination.Length % 2 == 1)
        {
            destination[^1] = GetHexChoices(lowercase)[source[^1] & 15];
        }
        source = source[..(destination.Length / 2)];
        _ = lowercase ? Convert.TryToHexStringLower(source, destination, out _)
            : Convert.TryToHexString(source, destination, out _);
    }

    private static ReadOnlySpan<char> GetHexChoices(bool lowercase) =>
        lowercase ? "0123456789abcdef" : "0123456789ABCDEF";
}
Method HexStringLength Mean Error StdDev
Main 2 8.284 ns 0.0285 ns 0.0252 ns
Opt 2 7.438 ns 0.0108 ns 0.0101 ns
Main 5 10.838 ns 0.0071 ns 0.0066 ns
Opt 5 9.590 ns 0.0476 ns 0.0397 ns
Main 8 10.979 ns 0.0118 ns 0.0099 ns
Opt 8 7.262 ns 0.0813 ns 0.0721 ns
Main 16 17.104 ns 0.0292 ns 0.0228 ns
Opt 16 8.030 ns 0.0201 ns 0.0188 ns
Main 32 26.957 ns 0.1203 ns 0.0939 ns
Opt 32 11.416 ns 0.0169 ns 0.0141 ns
Main 64 57.944 ns 0.3560 ns 0.3330 ns
Opt 64 17.249 ns 0.0897 ns 0.0839 ns

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions