-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Speed up Guid.NewGuid() on Linux #123540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Speed up Guid.NewGuid() on Linux #123540
Conversation
… to offset generation costs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR optimizes Guid.NewGuid() on Unix, primarily targeting Linux, by reducing syscall overhead and reusing entropy to significantly improve performance while maintaining cryptographic-strength randomness.
Changes:
- Teach the native random infrastructure to use
getrandom()(when available) instead of/dev/urandom, reducing per-call overhead for cryptographically secure random bytes. - Add CMake configuration and header wiring to detect and expose the availability of
getrandom. - Reimplement
Guid.NewGuid()on Unix to use a per-thread cache of GUIDs filled in batches via a single secure-random call, including logic to correctly set RFC 4122 version and variant bits for each cached GUID.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/native/minipal/random.c |
Adds a HAVE_GETRANDOM-guarded implementation of minipal_get_cryptographically_secure_random_bytes using the getrandom() syscall, looping until the requested buffer is fully populated and handling EINTR, to provide a faster secure RNG backend than /dev/urandom. |
src/native/minipal/minipalconfig.h.in |
Introduces the HAVE_GETRANDOM configuration macro so native code can be conditionally compiled against getrandom() support. |
src/native/minipal/configure.cmake |
Extends the CMake configuration to probe for getrandom in sys/random.h, defining HAVE_GETRANDOM when present so the new native path in random.c is enabled on supported Unix platforms. |
src/libraries/System.Private.CoreLib/src/System/Guid.Unix.cs |
Replaces the per-call secure RNG usage with a [ThreadStatic] cache of 64 GUIDs, filled via a single Interop.GetCryptographicallySecureRandomBytes call and post-processed to set version/variant bits, and updates NewGuid() to draw from this cache (with a WASI-specific non-cached fallback). |
|
Managed side cache of secure RNG doesn't sound secure. If NewGuid becomes a bottleneck there are other strategies to make it fast |
|
@dotnet-policy-service agree |
|
@reedz can you please update your PR's description with performance numbers now that the batching has been removed? |
|
@EgorBot -arm -x64 using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
[MemoryDiagnoser]
public class Bench
{
[Benchmark]
public Guid New() => Guid.NewGuid();
} |
Fixes #13628.
Fixes #107989.
This PR implements two optimizations:
getrandom()syscall (if available) instead of reading from/dev/urandomis ~14% quicker >getrandom()call as performed inRandom.SharedBenchmark dot net benchmark is showing the following changes: