Skip to content

Commit

Permalink
Optimize Activity Ids (#46890)
Browse files Browse the repository at this point in the history
* Optimize Activity Ids

* Generate long random numbers and make the generator object a threadstatic

* Addnew line at the end of the file

* Update the Random number generator

* Fix Full Framework failure

* Address the feedback regarding ranomizing Guid bits

* address more Feedback

* Address more feedback
  • Loading branch information
tarekgh authored Jan 21, 2021
1 parent 1f493b3 commit 035821a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\DynamicallyAccessedMemberTypes.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.1'">
<Compile Include="$(CommonPath)System\HexConverter.cs"
Link="Common\System\HexConverter.cs" />
<Compile Include="$(CommonPath)System\HexConverter.cs" Link="Common\System\HexConverter.cs" />
<Compile Include="System\Diagnostics\Activity.cs" />
<Compile Include="System\Diagnostics\ActivityTagsCollection.cs" />
<Compile Include="System\Diagnostics\ActivityContext.cs" />
Expand All @@ -45,6 +44,7 @@
<Compile Include="System\Diagnostics\ActivityListener.cs" />
<Compile Include="System\Diagnostics\ActivitySource.cs" />
<Compile Include="System\Diagnostics\DiagnosticSourceActivity.cs" />
<Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
<None Include="ActivityUserGuide.md" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == '$(NetCoreAppCurrent)'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1763,15 +1763,20 @@ public void CopyTo(Span<byte> destination)
}

/// <summary>
/// Sets the bytes in 'outBytes' to be random values. outBytes.Length must be less than or equal to 16
/// Sets the bytes in 'outBytes' to be random values. outBytes.Length must be either 8 or 16 bytes.
/// </summary>
/// <param name="outBytes"></param>
internal static unsafe void SetToRandomBytes(Span<byte> outBytes)
{
Debug.Assert(outBytes.Length <= sizeof(Guid)); // Guid is 16 bytes, and so is TraceId
Guid guid = Guid.NewGuid();
ReadOnlySpan<byte> guidBytes = new ReadOnlySpan<byte>(&guid, sizeof(Guid));
guidBytes.Slice(0, outBytes.Length).CopyTo(outBytes);
Debug.Assert(outBytes.Length == 16 || outBytes.Length == 8);
RandomNumberGenerator r = RandomNumberGenerator.Current;

Unsafe.WriteUnaligned(ref outBytes[0], r.Next());

if (outBytes.Length == 16)
{
Unsafe.WriteUnaligned(ref outBytes[8], r.Next());
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Diagnostics
{
/// <summary>
/// RandomNumberGenerator implementation is the 64-bit random number generator based on the Xoshiro256StarStar algorithm (known as shift-register generators).
/// </summary>
internal class RandomNumberGenerator
{
[ThreadStatic] private static RandomNumberGenerator? t_random;

private ulong _s0, _s1, _s2, _s3;

public static RandomNumberGenerator Current
{
get
{
if (t_random == null)
{
t_random = new RandomNumberGenerator();
}
return t_random;
}
}

#if ALLOW_PARTIALLY_TRUSTED_CALLERS
[System.Security.SecuritySafeCriticalAttribute]
#endif
public unsafe RandomNumberGenerator()
{
do
{
Guid g1 = Guid.NewGuid();
Guid g2 = Guid.NewGuid();
ulong* g1p = (ulong*)&g1;
ulong* g2p = (ulong*)&g2;
_s0 = *g1p;
_s1 = *(g1p + 1);
_s2 = *g2p;
_s3 = *(g2p + 1);

// Guid uses the 4 most significant bits of the first long as the version which would be fixed and not randomized.
// and uses 2 other bits in the second long for variants which would be fixed and not randomized too.
// let's overwrite the fixed bits in each long part by the other long.
_s0 = (_s0 & 0x0FFFFFFFFFFFFFFF) | (_s1 & 0xF000000000000000);
_s2 = (_s2 & 0x0FFFFFFFFFFFFFFF) | (_s3 & 0xF000000000000000);
_s1 = (_s1 & 0xFFFFFFFFFFFFFF3F) | (_s0 & 0x00000000000000C0);
_s3 = (_s3 & 0xFFFFFFFFFFFFFF3F) | (_s2 & 0x00000000000000C0);
}
while ((_s0 | _s1 | _s2 | _s3) == 0);
}

private ulong Rol64(ulong x, int k) => (x << k) | (x >> (64 - k));

public long Next()
{
ulong result = Rol64(_s1 * 5, 7) * 9;
ulong t = _s1 << 17;

_s2 ^= _s0;
_s3 ^= _s1;
_s1 ^= _s2;
_s0 ^= _s3;

_s2 ^= t;
_s3 = Rol64(_s3, 45);

return (long)result;
}
}
}

0 comments on commit 035821a

Please sign in to comment.