forked from neo-project/neo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Benchmark structure for UInt classes (neo-project#553)
* basic benchmark structure for UInt classes * commented code2 from lights for now * updated tests. all seem correct now * Switch to using a benchmark method taking a method delegate to benchmark. * Make pass. * 1 million iterations. * Switch to ulong for the 4th option, and it is still the same speed. * fix test data for 50% equal data * make test pass * neo.UnitTests/UT_UIntBenchmarks.cs * neo.UnitTests/UT_UIntBenchmarks.cs * Base 20 - UInt160 tests * neo.UnitTests/UT_UIntBenchmarks.cs * inlined 160 * complete tests with UInt256 and UInt160 * neo.UnitTests/UT_UIntBenchmarks.cs * Lights division calculation
- Loading branch information
1 parent
66bd45b
commit 3240cb4
Showing
2 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,333 @@ | ||
using FluentAssertions; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Neo.Cryptography.ECC; | ||
using Neo.IO; | ||
using Neo.Ledger; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Text; | ||
using System.Diagnostics; | ||
using System; | ||
//using System.Runtime.CompilerServices.Unsafe; | ||
|
||
namespace Neo.UnitTests | ||
{ | ||
[TestClass] | ||
public class UT_UIntBenchmarks | ||
{ | ||
int MAX_TESTS = 1000000; // 1 million | ||
|
||
byte[][] base_32_1; | ||
byte[][] base_32_2; | ||
byte[][] base_20_1; | ||
byte[][] base_20_2; | ||
|
||
private Random random; | ||
|
||
[TestInitialize] | ||
public void TestSetup() | ||
{ | ||
int SEED = 123456789; | ||
random = new Random(SEED); | ||
|
||
base_32_1 = new byte[MAX_TESTS][]; | ||
base_32_2 = new byte[MAX_TESTS][]; | ||
base_20_1 = new byte[MAX_TESTS][]; | ||
base_20_2 = new byte[MAX_TESTS][]; | ||
|
||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
base_32_1[i] = RandomBytes(32); | ||
base_20_1[i] = RandomBytes(20); | ||
if (i % 2 == 0) | ||
{ | ||
base_32_2[i] = RandomBytes(32); | ||
base_20_2[i] = RandomBytes(20); | ||
} | ||
else | ||
{ | ||
base_32_2[i] = new byte[32]; | ||
Buffer.BlockCopy(base_32_1[i], 0, base_32_2[i], 0, 32); | ||
base_20_2[i] = new byte[20]; | ||
Buffer.BlockCopy(base_20_1[i], 0, base_20_2[i], 0, 20); | ||
} | ||
} | ||
} | ||
|
||
private byte[] RandomBytes(int count) | ||
{ | ||
byte[] randomBytes = new byte[count]; | ||
random.NextBytes(randomBytes); | ||
return randomBytes; | ||
} | ||
|
||
public delegate Object BenchmarkMethod(); | ||
|
||
public (TimeSpan, Object) Benchmark(BenchmarkMethod method) | ||
{ | ||
Stopwatch sw0 = new Stopwatch(); | ||
sw0.Start(); | ||
var result = method(); | ||
sw0.Stop(); | ||
TimeSpan elapsed = sw0.Elapsed; | ||
Console.WriteLine($"Elapsed={elapsed} Sum={result}"); | ||
return (elapsed, result); | ||
} | ||
|
||
/* Could do this also so just pass the method to benchmark, but overhead of delegate call might affect benchmark | ||
public delegate int ComparisonMethod(byte[] b1, byte[] b2); | ||
public int BechmarkComparisonMethod(ComparisonMethod compareMethod) | ||
{ | ||
} | ||
*/ | ||
|
||
[TestMethod] | ||
public void Benchmark_CompareTo_UInt256() | ||
{ | ||
// testing "official UInt256 version" | ||
UInt256[] uut_32_1 = new UInt256[MAX_TESTS]; | ||
UInt256[] uut_32_2 = new UInt256[MAX_TESTS]; | ||
|
||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
uut_32_1[i] = new UInt256(base_32_1[i]); | ||
uut_32_2[i] = new UInt256(base_32_2[i]); | ||
} | ||
|
||
var checksum0 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += uut_32_1[i].CompareTo(uut_32_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum1 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code1_UInt256CompareTo(base_32_1[i], base_32_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum2 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code2_UInt256CompareTo(base_32_1[i], base_32_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum3 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code3_UInt256CompareTo(base_32_1[i], base_32_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
checksum0.Should().Be(checksum1); | ||
checksum0.Should().Be(checksum2); | ||
checksum0.Should().Be(checksum3); | ||
} | ||
|
||
[TestMethod] | ||
public void Benchmark_CompareTo_UInt160() | ||
{ | ||
// testing "official UInt160 version" | ||
UInt160[] uut_20_1 = new UInt160[MAX_TESTS]; | ||
UInt160[] uut_20_2 = new UInt160[MAX_TESTS]; | ||
|
||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
uut_20_1[i] = new UInt160(base_20_1[i]); | ||
uut_20_2[i] = new UInt160(base_20_2[i]); | ||
} | ||
|
||
var checksum0 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += uut_20_1[i].CompareTo(uut_20_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum1 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code1_UInt160CompareTo(base_20_1[i], base_20_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum2 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code2_UInt160CompareTo(base_20_1[i], base_20_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
var checksum3 = Benchmark(() => | ||
{ | ||
var checksum = 0; | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
checksum += code3_UInt160CompareTo(base_20_1[i], base_20_2[i]); | ||
} | ||
|
||
return checksum; | ||
}).Item2; | ||
|
||
checksum0.Should().Be(checksum1); | ||
checksum0.Should().Be(checksum2); | ||
checksum0.Should().Be(checksum3); | ||
} | ||
|
||
[TestMethod] | ||
public void Benchmark_UInt_IsCorrect_Self_CompareTo() | ||
{ | ||
for(var i=0; i<MAX_TESTS; i++) | ||
{ | ||
code1_UInt160CompareTo(base_20_1[i], base_20_1[i]).Should().Be(0); | ||
code2_UInt160CompareTo(base_20_1[i], base_20_1[i]).Should().Be(0); | ||
code3_UInt160CompareTo(base_20_1[i], base_20_1[i]).Should().Be(0); | ||
code1_UInt256CompareTo(base_32_1[i], base_32_1[i]).Should().Be(0); | ||
code2_UInt256CompareTo(base_32_1[i], base_32_1[i]).Should().Be(0); | ||
code3_UInt256CompareTo(base_32_1[i], base_32_1[i]).Should().Be(0); | ||
} | ||
} | ||
|
||
private int code1_UInt256CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
byte[] x = b1; | ||
byte[] y = b2; | ||
for (int i = x.Length - 1; i >= 0; i--) | ||
{ | ||
if (x[i] > y[i]) | ||
return 1; | ||
if (x[i] < y[i]) | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
private unsafe int code2_UInt256CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
fixed (byte* px = b1, py = b2) | ||
{ | ||
uint* lpx = (uint*)px; | ||
uint* lpy = (uint*)py; | ||
for (int i = 256/32-1; i >= 0; i--) | ||
{ | ||
if (lpx[i] > lpy[i]) | ||
return 1; | ||
if (lpx[i] < lpy[i]) | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
private unsafe int code3_UInt256CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
fixed (byte* px = b1, py = b2) | ||
{ | ||
ulong* lpx = (ulong*)px; | ||
ulong* lpy = (ulong*)py; | ||
for (int i = 256/64-1; i >= 0; i--) | ||
{ | ||
if (lpx[i] > lpy[i]) | ||
return 1; | ||
if (lpx[i] < lpy[i]) | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
} | ||
private int code1_UInt160CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
byte[] x = b1; | ||
byte[] y = b2; | ||
for (int i = x.Length - 1; i >= 0; i--) | ||
{ | ||
if (x[i] > y[i]) | ||
return 1; | ||
if (x[i] < y[i]) | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
private unsafe int code2_UInt160CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
fixed (byte* px = b1, py = b2) | ||
{ | ||
uint* lpx = (uint*)px; | ||
uint* lpy = (uint*)py; | ||
for (int i = 160/32-1; i >= 0; i--) | ||
{ | ||
if (lpx[i] > lpy[i]) | ||
return 1; | ||
if (lpx[i] < lpy[i]) | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
private unsafe int code3_UInt160CompareTo(byte[] b1, byte[] b2) | ||
{ | ||
// LSB -----------------> MSB | ||
// -------------------------- | ||
// | 8B | 8B | 4B | | ||
// -------------------------- | ||
// 0l 1l 4i | ||
// -------------------------- | ||
fixed (byte* px = b1, py = b2) | ||
{ | ||
uint* ipx = (uint*)px; | ||
uint* ipy = (uint*)py; | ||
if (ipx[4] > ipy[4]) | ||
return 1; | ||
if (ipx[4] < ipy[4]) | ||
return -1; | ||
|
||
ulong* lpx = (ulong*)px; | ||
ulong* lpy = (ulong*)py; | ||
if (lpx[1] > lpy[1]) | ||
return 1; | ||
if (lpx[1] < lpy[1]) | ||
return -1; | ||
if (lpx[0] > lpy[0]) | ||
return 1; | ||
if (lpx[0] < lpy[0]) | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
} | ||
} |
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