Adding LZC impls to benchmarks

This commit is contained in:
Lee Campbell 2017-07-17 12:40:22 +08:00
Родитель a8c2a7ec24
Коммит b14a3689d9
5 изменённых файлов: 166 добавлений и 10 удалений

Просмотреть файл

@ -6,12 +6,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.6" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.8" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net47'">
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows">
<Version>0.10.6</Version>
<Version>0.10.8</Version>
</PackageReference>
</ItemGroup>

Просмотреть файл

@ -0,0 +1,73 @@
using System;
namespace HdrHistogram.Benchmarking.LeadingZeroCount
{
/// <summary>
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
/// This variation perfoms very well. Similar profile to the "Current Impl".
/// Faster on LegacyJIT/CLR, but much slower on RyuJIT (CLR & Core)
/// </summary>
public static class BBarry32BitIfShiftLookupWith64BitShiftBranch
{
private static readonly int[] Lookup;
static BBarry32BitIfShiftLookupWith64BitShiftBranch()
{
Lookup = new int[256];
for (int i = 1; i < 256; ++i)
{
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
}
}
public static int GetLeadingZeroCount(long value)
{
//TODO: Test this with just < instead of <=? i.e. const of int.Max+1;
if (value <= int.MaxValue)
return 63 - Log2((int)value);
if (value <= uint.MaxValue)
return 62 - Log2((int)(value >> 1));
return 31 - Log2((int)(value >> 32));
}
private static int Log2(int i)
{
if (i >= 0x1000000) { return Lookup[i >> 24] + 24; }
if (i >= 0x10000) { return Lookup[i >> 16] + 16; }
if (i >= 0x100) { return Lookup[i >> 8] + 8; }
return Lookup[i];
}
}
/// <summary>
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
/// This variation perfoms very well. Similar profile to the "Current Impl".
/// Faster on LegacyJIT/CLR, but much slower on RyuJIT (CLR & Core)
/// </summary>
public static class BBarry32BitIfShiftLookupWith64BitShiftBranch_2
{
private static readonly int[] Lookup;
private const long IntOverflow = int.MaxValue + 1L;
static BBarry32BitIfShiftLookupWith64BitShiftBranch_2()
{
Lookup = new int[256];
for (int i = 1; i < 256; ++i)
{
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
}
}
public static int GetLeadingZeroCount(long value)
{
if (value < IntOverflow)
return 63 - Log2((uint)value);
return 32 - Log2((uint)(value >> 31));
}
private static int Log2(uint i)
{
if (i >= 0x1000000) { return Lookup[i >> 24] + 24; }
if (i >= 0x10000) { return Lookup[i >> 16] + 16; }
if (i >= 0x100) { return Lookup[i >> 8] + 8; }
return Lookup[i];
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System;
namespace HdrHistogram.Benchmarking.LeadingZeroCount
{
/// <summary>
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
/// This variation inlines all the shifts.
/// It performs on par on LegacyJIT/CLR but significantly slower on RyuJIT.
/// I assume it is because 7 branches vs the 4 above.
/// </summary>
internal static class BBarryIfShiftLookup
{
private static readonly int[] Lookup;
static BBarryIfShiftLookup()
{
Lookup = new int[256];
for (int i = 1; i < 256; ++i)
{
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
}
}
public static int GetLeadingZeroCount(long value)
{
if (value >= 0x100000000000000) { return 7 - Lookup[value >> 56]; }
if (value >= 0x1000000000000) { return 15 - Lookup[value >> 48]; }
if (value >= 0x10000000000) { return 23 - Lookup[value >> 40]; }
if (value >= 0x100000000) { return 31 - Lookup[value >> 32]; }
if (value >= 0x1000000) { return 39 - Lookup[value >> 24]; }
if (value >= 0x10000) { return 47 - Lookup[value >> 16]; }
if (value >= 0x100) { return 55 - Lookup[value >> 8]; }
return 63 - Lookup[value];
}
}
}

Просмотреть файл

@ -27,10 +27,23 @@ namespace HdrHistogram.Benchmarking.LeadingZeroCount
/// </remarks>
public abstract class LeadingZeroCountBenchmarkBase
{
private readonly int _maxBit;
private readonly long[] _testValues;
protected LeadingZeroCountBenchmarkBase(int maxBit)
{
_maxBit = maxBit;
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
var expectedData = GenerateTestData(maxBit);
_testValues = expectedData.Select(d => d.Value).ToArray();
}
[BenchmarkDotNet.Attributes.GlobalSetup]
public void OneOffValidationOfImplementations()
{
var expectedData = GenerateTestData(_maxBit);
var functions = new Dictionary<string, Func<long, int>>
{
{"CurrentImpl", Bitwise.NumberOfLeadingZeros},
@ -41,13 +54,11 @@ namespace HdrHistogram.Benchmarking.LeadingZeroCount
{"DeBruijn64BitsBitScanner", LeadingZeroCount.DeBruijn64BitsBitScanner.GetLeadingZeroCount},
{"DeBruijnMultiplication", LeadingZeroCount.DeBruijnMultiplication.GetLeadingZeroCount},
{"DeBruijn128Bits", LeadingZeroCount.DeBruijn128Bits.GetLeadingZeroCount},
{"BBarry32BitIfShiftLookupWith64BitShiftBranch", LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch.GetLeadingZeroCount},
{"BBarry32BitIfShiftLookupWith64BitShiftBranch_2", LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch_2.GetLeadingZeroCount},
{"BBarryIfShiftLookup", LeadingZeroCount.BBarryIfShiftLookup.GetLeadingZeroCount},
};
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
var expectedData = GenerateTestData(maxBit);
ValidateImplementations(expectedData, functions);
_testValues = expectedData.Select(d => d.Value).ToArray();
}
private static CalculationExpectation[] GenerateTestData(int maxBit)
@ -157,7 +168,7 @@ namespace HdrHistogram.Benchmarking.LeadingZeroCount
}
return sum;
}
[Benchmark]
public int StringManipulation()
{
@ -168,7 +179,37 @@ namespace HdrHistogram.Benchmarking.LeadingZeroCount
}
return sum;
}
[Benchmark]
public int BBarry_imp1()
{
var sum = 0;
for (int i = 0; i < _testValues.Length; i++)
{
sum += LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch.GetLeadingZeroCount(_testValues[i]);
}
return sum;
}
[Benchmark]
public int BBarry_imp3()
{
var sum = 0;
for (int i = 0; i < _testValues.Length; i++)
{
sum += LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch_2.GetLeadingZeroCount(_testValues[i]);
}
return sum;
}
[Benchmark]
public int BBarry_imp2()
{
var sum = 0;
for (int i = 0; i < _testValues.Length; i++)
{
sum += LeadingZeroCount.BBarryIfShiftLookup.GetLeadingZeroCount(_testValues[i]);
}
return sum;
}
private class CalculationExpectation
{
public long Value { get; }

Просмотреть файл

@ -7,9 +7,15 @@ if [%1]==[] (
)
dotnet restore -v=q
IF %ERRORLEVEL% NEQ 0 GOTO EOF
dotnet build -v=q -c=Release /p:Version=%SemVer%
IF %ERRORLEVEL% NEQ 0 GOTO EOF
dotnet test .\HdrHistogram.UnitTests\HdrHistogram.UnitTests.csproj -v=q --no-build -c=Release
IF %ERRORLEVEL% NEQ 0 GOTO EOF
dotnet pack .\HdrHistogram\HdrHistogram.csproj --no-build --include-symbols -c=Release /p:Version=%SemVer%
dotnet pack .\HdrHistogram\HdrHistogram.csproj --no-build --include-symbols -c=Release /p:Version=%SemVer%
IF %ERRORLEVEL% NEQ 0 GOTO EOF
.\HdrHistogram.Benchmarking\bin\Release\net47\HdrHistogram.Benchmarking.exe *