Skip to content

Commit b14a368

Browse files
committed
Adding LZC impls to benchmarks
1 parent a8c2a7e commit b14a368

5 files changed

Lines changed: 166 additions & 10 deletions

File tree

HdrHistogram.Benchmarking/HdrHistogram.Benchmarking.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="BenchmarkDotNet" Version="0.10.6" />
9+
<PackageReference Include="BenchmarkDotNet" Version="0.10.8" />
1010
</ItemGroup>
1111

1212
<ItemGroup Condition="'$(TargetFramework)' == 'net47'">
1313
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows">
14-
<Version>0.10.6</Version>
14+
<Version>0.10.8</Version>
1515
</PackageReference>
1616
</ItemGroup>
1717

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
3+
namespace HdrHistogram.Benchmarking.LeadingZeroCount
4+
{
5+
/// <summary>
6+
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
7+
/// This variation perfoms very well. Similar profile to the "Current Impl".
8+
/// Faster on LegacyJIT/CLR, but much slower on RyuJIT (CLR & Core)
9+
/// </summary>
10+
public static class BBarry32BitIfShiftLookupWith64BitShiftBranch
11+
{
12+
private static readonly int[] Lookup;
13+
14+
static BBarry32BitIfShiftLookupWith64BitShiftBranch()
15+
{
16+
Lookup = new int[256];
17+
for (int i = 1; i < 256; ++i)
18+
{
19+
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
20+
}
21+
}
22+
public static int GetLeadingZeroCount(long value)
23+
{
24+
//TODO: Test this with just < instead of <=? i.e. const of int.Max+1;
25+
if (value <= int.MaxValue)
26+
return 63 - Log2((int)value);
27+
if (value <= uint.MaxValue)
28+
return 62 - Log2((int)(value >> 1));
29+
return 31 - Log2((int)(value >> 32));
30+
}
31+
32+
private static int Log2(int i)
33+
{
34+
if (i >= 0x1000000) { return Lookup[i >> 24] + 24; }
35+
if (i >= 0x10000) { return Lookup[i >> 16] + 16; }
36+
if (i >= 0x100) { return Lookup[i >> 8] + 8; }
37+
return Lookup[i];
38+
}
39+
}
40+
41+
/// <summary>
42+
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
43+
/// This variation perfoms very well. Similar profile to the "Current Impl".
44+
/// Faster on LegacyJIT/CLR, but much slower on RyuJIT (CLR & Core)
45+
/// </summary>
46+
public static class BBarry32BitIfShiftLookupWith64BitShiftBranch_2
47+
{
48+
private static readonly int[] Lookup;
49+
private const long IntOverflow = int.MaxValue + 1L;
50+
static BBarry32BitIfShiftLookupWith64BitShiftBranch_2()
51+
{
52+
Lookup = new int[256];
53+
for (int i = 1; i < 256; ++i)
54+
{
55+
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
56+
}
57+
}
58+
public static int GetLeadingZeroCount(long value)
59+
{
60+
if (value < IntOverflow)
61+
return 63 - Log2((uint)value);
62+
return 32 - Log2((uint)(value >> 31));
63+
}
64+
65+
private static int Log2(uint i)
66+
{
67+
if (i >= 0x1000000) { return Lookup[i >> 24] + 24; }
68+
if (i >= 0x10000) { return Lookup[i >> 16] + 16; }
69+
if (i >= 0x100) { return Lookup[i >> 8] + 8; }
70+
return Lookup[i];
71+
}
72+
}
73+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
3+
namespace HdrHistogram.Benchmarking.LeadingZeroCount
4+
{
5+
/// <summary>
6+
/// Contributed from @BBarry at https://github.com/HdrHistogram/HdrHistogram.NET/issues/42
7+
/// This variation inlines all the shifts.
8+
/// It performs on par on LegacyJIT/CLR but significantly slower on RyuJIT.
9+
/// I assume it is because 7 branches vs the 4 above.
10+
/// </summary>
11+
internal static class BBarryIfShiftLookup
12+
{
13+
private static readonly int[] Lookup;
14+
15+
static BBarryIfShiftLookup()
16+
{
17+
Lookup = new int[256];
18+
for (int i = 1; i < 256; ++i)
19+
{
20+
Lookup[i] = (int)(Math.Log(i) / Math.Log(2));
21+
}
22+
}
23+
24+
public static int GetLeadingZeroCount(long value)
25+
{
26+
if (value >= 0x100000000000000) { return 7 - Lookup[value >> 56]; }
27+
if (value >= 0x1000000000000) { return 15 - Lookup[value >> 48]; }
28+
if (value >= 0x10000000000) { return 23 - Lookup[value >> 40]; }
29+
if (value >= 0x100000000) { return 31 - Lookup[value >> 32]; }
30+
if (value >= 0x1000000) { return 39 - Lookup[value >> 24]; }
31+
if (value >= 0x10000) { return 47 - Lookup[value >> 16]; }
32+
if (value >= 0x100) { return 55 - Lookup[value >> 8]; }
33+
return 63 - Lookup[value];
34+
}
35+
}
36+
}

HdrHistogram.Benchmarking/LeadingZeroCount/LeadingZeroCountBenchmarkBase.cs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,23 @@ namespace HdrHistogram.Benchmarking.LeadingZeroCount
2727
/// </remarks>
2828
public abstract class LeadingZeroCountBenchmarkBase
2929
{
30+
private readonly int _maxBit;
3031
private readonly long[] _testValues;
3132

3233
protected LeadingZeroCountBenchmarkBase(int maxBit)
3334
{
35+
_maxBit = maxBit;
36+
37+
38+
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
39+
var expectedData = GenerateTestData(maxBit);
40+
_testValues = expectedData.Select(d => d.Value).ToArray();
41+
}
42+
43+
[BenchmarkDotNet.Attributes.GlobalSetup]
44+
public void OneOffValidationOfImplementations()
45+
{
46+
var expectedData = GenerateTestData(_maxBit);
3447
var functions = new Dictionary<string, Func<long, int>>
3548
{
3649
{"CurrentImpl", Bitwise.NumberOfLeadingZeros},
@@ -41,13 +54,11 @@ protected LeadingZeroCountBenchmarkBase(int maxBit)
4154
{"DeBruijn64BitsBitScanner", LeadingZeroCount.DeBruijn64BitsBitScanner.GetLeadingZeroCount},
4255
{"DeBruijnMultiplication", LeadingZeroCount.DeBruijnMultiplication.GetLeadingZeroCount},
4356
{"DeBruijn128Bits", LeadingZeroCount.DeBruijn128Bits.GetLeadingZeroCount},
57+
{"BBarry32BitIfShiftLookupWith64BitShiftBranch", LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch.GetLeadingZeroCount},
58+
{"BBarry32BitIfShiftLookupWith64BitShiftBranch_2", LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch_2.GetLeadingZeroCount},
59+
{"BBarryIfShiftLookup", LeadingZeroCount.BBarryIfShiftLookup.GetLeadingZeroCount},
4460
};
45-
46-
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
47-
var expectedData = GenerateTestData(maxBit);
4861
ValidateImplementations(expectedData, functions);
49-
50-
_testValues = expectedData.Select(d => d.Value).ToArray();
5162
}
5263

5364
private static CalculationExpectation[] GenerateTestData(int maxBit)
@@ -157,7 +168,7 @@ public int Debruijn128Bit()
157168
}
158169
return sum;
159170
}
160-
171+
161172
[Benchmark]
162173
public int StringManipulation()
163174
{
@@ -168,7 +179,37 @@ public int StringManipulation()
168179
}
169180
return sum;
170181
}
171-
182+
[Benchmark]
183+
public int BBarry_imp1()
184+
{
185+
var sum = 0;
186+
for (int i = 0; i < _testValues.Length; i++)
187+
{
188+
sum += LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch.GetLeadingZeroCount(_testValues[i]);
189+
}
190+
return sum;
191+
}
192+
[Benchmark]
193+
public int BBarry_imp3()
194+
{
195+
var sum = 0;
196+
for (int i = 0; i < _testValues.Length; i++)
197+
{
198+
sum += LeadingZeroCount.BBarry32BitIfShiftLookupWith64BitShiftBranch_2.GetLeadingZeroCount(_testValues[i]);
199+
}
200+
return sum;
201+
}
202+
[Benchmark]
203+
public int BBarry_imp2()
204+
{
205+
var sum = 0;
206+
for (int i = 0; i < _testValues.Length; i++)
207+
{
208+
sum += LeadingZeroCount.BBarryIfShiftLookup.GetLeadingZeroCount(_testValues[i]);
209+
}
210+
return sum;
211+
}
212+
172213
private class CalculationExpectation
173214
{
174215
public long Value { get; }

build.cmd

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ if [%1]==[] (
77
)
88

99
dotnet restore -v=q
10+
IF %ERRORLEVEL% NEQ 0 GOTO EOF
1011

1112
dotnet build -v=q -c=Release /p:Version=%SemVer%
13+
IF %ERRORLEVEL% NEQ 0 GOTO EOF
1214

1315
dotnet test .\HdrHistogram.UnitTests\HdrHistogram.UnitTests.csproj -v=q --no-build -c=Release
16+
IF %ERRORLEVEL% NEQ 0 GOTO EOF
1417

15-
dotnet pack .\HdrHistogram\HdrHistogram.csproj --no-build --include-symbols -c=Release /p:Version=%SemVer%
18+
dotnet pack .\HdrHistogram\HdrHistogram.csproj --no-build --include-symbols -c=Release /p:Version=%SemVer%
19+
IF %ERRORLEVEL% NEQ 0 GOTO EOF
20+
21+
.\HdrHistogram.Benchmarking\bin\Release\net47\HdrHistogram.Benchmarking.exe *

0 commit comments

Comments
 (0)