-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Optimize Random{NumberGenerator}.GetItems for power-of-two choices #92229
Conversation
When possible, make a single call to get the required randomness rather than one per element.
Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones Issue DetailsWhen possible, make a single call to get the required randomness rather than one per element. Closes #92130 using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Security.Cryptography;
BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);
[HideColumns("Error", "StdDev", "Median", "RatioSD")]
public class Tests
{
private const int Length = 11;
private static readonly string s_charChoices = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
private static ReadOnlySpan<int> s_intChoices => [42, 43, 44, 45, 46, 47, 48, 49];
private static int[] s_dest = new int[Length];
[Benchmark]
public string RngGetString() => RandomNumberGenerator.GetString(s_charChoices, Length);
[Benchmark]
public void RandGetItems() => Random.Shared.GetItems(s_intChoices, s_dest);
}
|
Use separate scratch buffer instead of destination buffer. Upside, we don't need to be concerned about temporarily corrupt Ts, and it can work for managed Ts. Downside, it requires separate scratch space, which means an ArrayPool rental for larger sizes.
...aries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...aries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...aries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...aries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
...aries/System.Security.Cryptography/src/System/Security/Cryptography/RandomNumberGenerator.cs
Outdated
Show resolved
Hide resolved
Loop over a stackalloc'd buffer rather than using ArrayPool
784de41
to
72269f1
Compare
A few remarks if you do not mind.
|
This sounds very niche, and the savings is effectively an array access per element. I don't think it's worth special-casing without seeing more examples of where it would be really meaningful.
It's an implementation detail. We avoid documenting such optimization implementations, as we reserve the right to change them at any point. |
A) Generate random booleans |
I don't follow. Are you proposing a new API? Or are you proposing that the implementation special-case |
@stephentoub Consider also duplicating the test here with one that passes a power-of-two sized values span. That way we get distribution tests across both implementations which now exist in this method. runtime/src/libraries/System.Security.Cryptography/tests/RandomNumberGeneratorTests.cs Lines 669 to 675 in 0ad4e69
|
The current I am using something like that, it is essentially the same spirit as you do here with the new
|
That's a new API. Feel free to open a separate proposal for one. That won't be done as part of an optimization PR. |
This would be a new API proposal. We can discuss the merits and usefulness of the proposal there to keep this PR focused on the perf of existing APIs. |
@bartonjs, per your feedback on my recent PR, I've marked this as a breaking change to be documented. |
Opened #108018 to revert the breaking change aspect. |
When possible, make a single call to get the required randomness rather than one per element.
Closes #92130