Skip to content

Instantly share code, notes, and snippets.

@GrabYourPitchforks
Created January 31, 2018 16:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GrabYourPitchforks/990cf1e73c438c4c727d7beda8e484ec to your computer and use it in GitHub Desktop.
Save GrabYourPitchforks/990cf1e73c438c4c727d7beda8e484ec to your computer and use it in GitHub Desktop.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
byte[] rand = GetRandom();
char hi = default, lo = default;
var sw = new Stopwatch();
while (true)
{
sw.Restart();
for (int j = 0; j < 500_000; j++)
{
for (int i = 0; i < rand.Length; i++)
{
BinaryToHex2(rand[i], out hi, out lo);
}
}
Console.WriteLine(sw.ElapsedMilliseconds);
GC.KeepAlive(hi);
GC.KeepAlive(lo);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static byte[] GetRandom()
{
var rbg = new Random(0x1234);
byte[] retVal = new byte[1024];
rbg.NextBytes(retVal);
return retVal;
}
// 'valueIfTrue' and 'valueIfFalse' really should be compile-time constants for maximum throughput.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ConditionalSelect(bool condition, int valueIfTrue, int valueIfFalse)
{
// From https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf
// Example 3.2. We're taking advantage of the fact that bools are passed by value as 32-bit integers,
// so we'll blit it directly into a 1 or a 0 without a jump.
// Codegen will emit a movzx, but on Ivy Bridge (and later) the CPU itself elides the instruction.
return ((-Unsafe.As<bool, int>(ref condition)) & (valueIfTrue - valueIfFalse)) + valueIfFalse;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ToInt(bool b)
{
return Unsafe.As<bool, int>(ref b);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ToUInt(bool b)
{
return Unsafe.As<bool, uint>(ref b);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BinaryToHex1(byte b, out char hi, out char lo)
{
hi = (char)((b >> 4) + ((b < (10 << 4)) ? '0' : ('A' - 10)));
b &= 0xF;
lo = (char)(b + ((b < 10) ? '0' : ('A' - 10)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BinaryToHex2(byte b, out char hi, out char lo)
{
uint bVal = b; // MOVZX (elided)
bVal = (bVal >> 4) | (bVal << 28); // ROR
uint firstNibbleMultiplier = ToUInt((byte)bVal >= 10); // CMP and SETGE
hi = (char)((firstNibbleMultiplier * 8 + bVal + '0') - firstNibbleMultiplier); // LEA, SUB, MOVZX
bVal >>= 28; // SHR
uint secondNibbleMultiplier = ToUInt((byte)bVal >= 10); // CMP and SETGE
lo = (char)((secondNibbleMultiplier * 8 + bVal + '0') - secondNibbleMultiplier); // LEA, SUB, MOVZX
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment