-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Guid.CreateVersion7() could be faster #106377
Comments
macOS, M2 Pro (ARM64), .NET 9 Preview 7:
|
Windows, Intel Core i9-12900H (x64) .NET 9 Preview 7:
Here my "faster" version is actually slower, so I can see how the existing decision would have been made to use |
I don't think changing CreateVersion7 here is appropriate. The only extra overhead using NewGuid has is setting (and requesting from the rng) a few extra bytes that CreateVersion7 will then overwrite, but otherwise it needs cryptographically-secure random bytes, and it gets them from a native method. If you're really seeing RandomNumberGenerator.Fill being 3x faster than NewGuid on macOS, then I suspect that means the CryptoNative_GetRandomBytes function is ~3x faster than the SystemNative_GetCryptographicallySecureRandomBytes function on macOS, and that's the gap we should be looking to address. |
We should be calling
|
Thanks. If they're already calling the same function, then @yaakov-h more analysis will be needed to understand the cited differences before a PR would be accepted. What does "my version depends on being smart with RandomNumberGenerator.Fill" mean? |
yes and no, because that comes back to:
In the version marked Span<byte> value = _interior; // InlineArray(16) struct
RandomNumberGenerator.Fill(value.Slice(6)); Generating fewer random bytes helps speed things up a little bit. |
But generating 6 fewer random bytes when it's already generating over a hundred should not make a 3x difference. Can you expand on that? |
A hundred? A GUID is only 16 bytes. Calling When Somre more of the performance difference may be lost due to additional things in the runtime like checking for a negative DateTimeOffset, I would have to check that. |
Tagging subscribers to this area: @dotnet/area-system-runtime |
Sorry, that was supposed to be ten; typing late at night. I'd expect generating ~35% fewer bytes would make it ~35% faster, but your numbers are showing ~2x as much gain. That's what's I'm not clear about. |
I'm not entirely sure either. Looking over the differences as well as the iteration history and Mastodon conversation history of making the other version faster:
|
It doesn't seem like I even need most of the little optimisations in the other implementation. Just skipping the parts of v4 generation that get replaced by the v7 generation is enough to achieve the speedup. PR in #106525 with benchmarks. |
Description
I got nerd-sniped on Mastodon a while back into build a highly performant UUIDv7 implementation for .NET.
I haven't published it as a library yet or anything like that.
I just saw that .NET 9 Preview 7 adds
Guid.CreateVersion7()
which does the same thing, but when I benchmarked it the runtime version came out as almost 3x as slow as my version.The problem is my version depends on being smart with
RandomNumberGenerator.Fill
, and based on this comment it seems that random number generation is not available in this part of the runtime and what is available is slowerHowever I think there may be an oversight here.
RandomNumberGenerator.Fill
is significantly faster on macOS, but about 20% slower on Windows. I suspect this is due to the split betweenCoCreateGuid()
on Windows vsInterop.GetCryptographicallySecureRandomBytes()
on Unix.I'll post additional benchmarks below.
Would you be open to me doing platform-specific implementations to speed up
Guid.CreateVersion7()
(and if I can get benchmarks to back it up, maybeGuid.NewGuid()
too?) on non-Windows platforms?The text was updated successfully, but these errors were encountered: