Created
August 10, 2022 19:52
-
-
Save mbcrawfo/1fae97185df320e7b48a8c56eb82a1fe to your computer and use it in GitHub Desktop.
MulAdd Benchmarks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.CompilerServices; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
BenchmarkRunner.Run<Benchmark>(); | |
public class Benchmark | |
{ | |
private readonly Random _random = new(314159265); | |
[Benchmark] | |
public uint ManualInlining() | |
{ | |
var c0 = 0u; | |
var c1 = 0u; | |
var c2 = 0u; | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
return c2 + c0; | |
} | |
[Benchmark] | |
public uint ManualInliningWithFastBool() | |
{ | |
var c0 = 0u; | |
var c1 = 0u; | |
var c2 = 0u; | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
{ | |
var t = (ulong)((uint)_random.Next() * (uint)_random.Next()); | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
return c2 + c0; | |
} | |
[Benchmark] | |
public uint NormalMethod() | |
{ | |
var c0 = 0u; | |
var c1 = 0u; | |
var c2 = 0u; | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
return c2 + c0; | |
} | |
[Benchmark] | |
public uint AggressiveInlining() | |
{ | |
var c0 = 0u; | |
var c1 = 0u; | |
var c2 = 0u; | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_Inlined((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
return c2 + c0; | |
} | |
[Benchmark] | |
public uint AggressiveInliningWithFastBool() | |
{ | |
var c0 = 0u; | |
var c1 = 0u; | |
var c2 = 0u; | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
MulAdd_InlinedWithFastBool((uint)_random.Next(), (uint)_random.Next(), ref c0, ref c1, ref c2); | |
return c2 + c0; | |
} | |
private static void MulAdd(uint a, uint b, ref uint c0, ref uint c1, ref uint c2) | |
{ | |
var t = (ulong)a * b; | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static void MulAdd_Inlined(uint a, uint b, ref uint c0, ref uint c1, ref uint c2) | |
{ | |
var t = (ulong)a * b; | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += c0 < tl ? 1U : 0; | |
c1 += th; | |
c2 += c1 < th ? 1U : 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static void MulAdd_InlinedWithFastBool(uint a, uint b, ref uint c0, ref uint c1, ref uint c2) | |
{ | |
var t = (ulong)a * b; | |
var th = (uint)(t >> 32); | |
var tl = (uint)t; | |
c0 += tl; | |
th += BoolToUnsigned(c0 < tl); | |
c1 += th; | |
c2 += BoolToUnsigned(c1 < th); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private static uint BoolToUnsigned(bool b) => Unsafe.As<bool, uint>(ref b); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment