Skip to content

Commit

Permalink
Use BCL provided BitOperations class to accelerate bit-twiddling hacks (
Browse files Browse the repository at this point in the history
#35)

* Use BCL provided BitOperations class to accelerate bit-twiddling

* Use BitOperations.RotateRight in ByteArrayComparer

* Remove more duplicate and unused bit-twiddling logic from Garnet.client.Utility

* Use BitOperations.RoundUpToPow2 in ScratchBufferManager

* Use BitOperations.LeadingZeroCount in HyperLogLog

* Use BitOperations.LeadingZeroCount in HdrHistogram

---------

Co-authored-by: Badrish Chandramouli <badrishc@microsoft.com>
Co-authored-by: vazois <96085550+vazois@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 19, 2024
1 parent 3dee117 commit 9386480
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 326 deletions.
141 changes: 0 additions & 141 deletions libs/client/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,147 +188,6 @@ public static unsafe void Copy(byte* src, byte* dest, int numBytes)
}
}

/// <summary>
/// Get 64-bit hash code for a long value
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long GetHashCode(long input)
{
long local_rand = input;
long local_rand_hash = 8;

local_rand_hash = 40343 * local_rand_hash + ((local_rand) & 0xFFFF);
local_rand_hash = 40343 * local_rand_hash + ((local_rand >> 16) & 0xFFFF);
local_rand_hash = 40343 * local_rand_hash + ((local_rand >> 32) & 0xFFFF);
local_rand_hash = 40343 * local_rand_hash + (local_rand >> 48);
local_rand_hash = 40343 * local_rand_hash;

return (long)Rotr64((ulong)local_rand_hash, 45);
}

/// <summary>
/// Get 64-bit hash code for a byte array
/// </summary>
/// <param name="pbString"></param>
/// <param name="len"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe long HashBytes(byte* pbString, int len)
{
const long magicno = 40343;
char* pwString = (char*)pbString;
int cbBuf = len / 2;
ulong hashState = (ulong)len;

for (int i = 0; i < cbBuf; i++, pwString++)
hashState = magicno * hashState + *pwString;

if ((len & 1) > 0)
{
byte* pC = (byte*)pwString;
hashState = magicno * hashState + *pC;
}

return (long)Rotr64(magicno * hashState, 4);
}

/// <summary>
/// Compute XOR of all provided bytes
/// </summary>
/// <param name="src"></param>
/// <param name="length"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ulong XorBytes(byte* src, int length)
{
ulong result = 0;
byte* curr = src;
byte* end = src + length;
while (curr + 4 * sizeof(ulong) <= end)
{
result ^= *(ulong*)curr;
result ^= *(1 + (ulong*)curr);
result ^= *(2 + (ulong*)curr);
result ^= *(3 + (ulong*)curr);
curr += 4 * sizeof(ulong);
}
while (curr + sizeof(ulong) <= end)
{
result ^= *(ulong*)curr;
curr += sizeof(ulong);
}
while (curr + 1 <= end)
{
result ^= *curr;
curr++;
}

return result;
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong Rotr64(ulong x, int n)
{
return (((x) >> n) | ((x) << (64 - n)));
}

/// <summary>
/// Is power of 2
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPowerOfTwo(long x)
{
return (x > 0) && ((x & (x - 1)) == 0);
}

internal static readonly int[] MultiplyDeBruijnBitPosition2 = new int[32]
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

/// <summary>
/// Get log base 2
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetLogBase2(int x)
{
return MultiplyDeBruijnBitPosition2[(uint)(x * 0x077CB531U) >> 27];
}

/// <summary>
/// Get log base 2
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int GetLogBase2(ulong value)
{
int i;
for (i = -1; value != 0; i++)
value >>= 1;

return (i == -1) ? 0 : i;
}

/// <summary>
/// Check if power of two
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Is32Bit(long x)
{
return ((ulong)x < 4294967295ul);
}


/// <summary>
/// A 32-bit murmur3 implementation.
/// </summary>
Expand Down
10 changes: 3 additions & 7 deletions libs/common/HashUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System.Numerics;
using System.Runtime.CompilerServices;

namespace Garnet.common
Expand All @@ -10,14 +11,9 @@ namespace Garnet.common
/// </summary>
public static class HashUtils
{
/// <summary>
/// rotate shift left
/// </summary>
/// <param name="v"></param>
/// <param name="r"></param>
/// <returns></returns>
/// <inheritdoc cref="BitOperations.RotateLeft(ulong, int)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static unsafe ulong Rotl64(ulong v, int r) => ((ulong)(v << r)) | ((ulong)(v >> (64 - r)));
static unsafe ulong Rotl64(ulong v, int r) => BitOperations.RotateLeft(v, r);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static unsafe ulong fmix64(ulong k)
Expand Down
15 changes: 2 additions & 13 deletions libs/server/ArgSlice/ScratchBufferManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using Garnet.common;
Expand Down Expand Up @@ -203,7 +204,7 @@ void ExpandScratchBufferIfNeeded(int newLength)
void ExpandScratchBuffer(int newLength)
{
if (newLength < 64) newLength = 64;
else newLength = (int)NextPowerOf2(newLength);
else newLength = (int)BitOperations.RoundUpToPowerOf2((uint)newLength + 1);

var _scratchBuffer = GC.AllocateArray<byte>(newLength, true);
var _scratchBufferHead = (byte*)Unsafe.AsPointer(ref _scratchBuffer[0]);
Expand All @@ -213,18 +214,6 @@ void ExpandScratchBuffer(int newLength)
scratchBufferHead = _scratchBufferHead;
}

static long NextPowerOf2(long v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
return v + 1;
}

/// <summary>
/// Returns a new <see cref="ArgSlice"/>
/// with the <paramref name="length"/> bytes of the buffer;
Expand Down
8 changes: 2 additions & 6 deletions libs/server/Resp/ByteArrayComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Numerics;

namespace Garnet.server
{
Expand Down Expand Up @@ -49,12 +50,7 @@ static unsafe long HashBytes(byte* pbString, int len)
hashState = magicno * hashState + *pC;
}

return (long)Rotr64(magicno * hashState, 4);
}

static ulong Rotr64(ulong x, int n)
{
return (((x) >> n) | ((x) << (64 - n)));
return (long)BitOperations.RotateRight(magicno * hashState, 4);
}
}
}
37 changes: 2 additions & 35 deletions libs/server/Resp/HyperLogLog/HyperLogLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
#endif
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using Garnet.common;

Expand Down Expand Up @@ -142,43 +143,9 @@ public HyperLogLog(byte pbit)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte clz(long hv)
{
#if NET5_0_OR_GREATER
ulong bits = (ulong)hv;
byte lz = (byte)(System.Runtime.Intrinsics.X86.Lzcnt.X64.LeadingZeroCount(bits));
byte lz = (byte)(BitOperations.LeadingZeroCount(bits));
return lz >= qbit ? (byte)(qbit + 1) : (byte)(lz + 1);
#else
ulong bits = (ulong)((ulong)hv >> pbit);
byte pc = popc(bsmr(bits));
return (byte)(qbit - pc + 1);
#endif
}

//bit smearing
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong bsmr(ulong x)
{
ulong y = x;
y |= y >> 1;
y |= y >> 2;
y |= y >> 4;
y |= y >> 8;
y |= y >> 16;
y |= y >> 32;
return y;
}

//count bit set
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte popc(ulong x)
{
ulong y = x;
y = (y & 0x5555555555555555) + ((y >> 1) & 0x5555555555555555);
y = (y & 0x3333333333333333) + ((y >> 2) & 0x3333333333333333);
y = (y & 0x0F0F0F0F0F0F0F0F) + ((y >> 4) & 0x0F0F0F0F0F0F0F0F);
y = (y & 0x007F007F007F007F) + ((y >> 8) & 0x007F007F007F007F);
y = (y & 0x0000007F0000007F) + ((y >> 16) & 0x0000007F0000007F);
y = (y & 0x000000000000007F) + ((y >> 32) & 0x000000000000007F);
return (byte)(y & 0x7F);
}

/// <summary>
Expand Down
53 changes: 10 additions & 43 deletions libs/storage/Tsavorite/cs/src/core/Utilities/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Diagnostics;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -152,7 +153,6 @@ internal static string PrettySize(long value)
/// <param name="value">Value to be aligned</param>
/// <param name="alignment">Align to this</param>
/// <returns>Aligned value</returns>

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundUp(int value, int alignment) => (value + (alignment - 1)) & ~(alignment - 1);

Expand Down Expand Up @@ -300,54 +300,21 @@ public static unsafe ulong XorBytes(byte* src, int length)
return result;
}


/// <inheritdoc cref="BitOperations.RotateRight(ulong, int)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong Rotr64(ulong x, int n)
{
return (((x) >> n) | ((x) << (64 - n)));
}
internal static ulong Rotr64(ulong x, int n) => BitOperations.RotateRight(x, n);

/// <summary>
/// Is power of 2
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
/// <inheritdoc cref="BitOperations.IsPow2(ulong)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPowerOfTwo(long x)
{
return (x > 0) && ((x & (x - 1)) == 0);
}
public static bool IsPowerOfTwo(long x) => BitOperations.IsPow2(x);

internal static readonly int[] MultiplyDeBruijnBitPosition2 = new int[32]
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

/// <summary>
/// Get log base 2
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
/// <inheritdoc cref="BitOperations.Log2(uint)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetLogBase2(int x)
{
return MultiplyDeBruijnBitPosition2[(uint)(x * 0x077CB531U) >> 27];
}
public static int GetLogBase2(int x) => BitOperations.Log2((uint)x);

/// <summary>
/// Get log base 2
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int GetLogBase2(ulong value)
{
int i;
for (i = -1; value != 0; i++)
value >>= 1;

return (i == -1) ? 0 : i;
}
/// <inheritdoc cref="BitOperations.Log2(ulong)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetLogBase2(ulong value) => BitOperations.Log2(value);

/// <summary>
/// Check if power of two
Expand Down
Loading

0 comments on commit 9386480

Please sign in to comment.