Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

speed up Uint160.CompareTo and Uint256.CompareTo function #552

Merged
merged 21 commits into from
Mar 16, 2019
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 19 additions & 26 deletions neo.UnitTests/UT_UIntBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
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;
using System.Diagnostics;

namespace Neo.UnitTests
{
[TestClass]
public class UT_UIntBenchmarks
{
int MAX_TESTS = 1000000; // 1 million
private const int MAX_TESTS = 1000;

byte[][] base_32_1;
byte[][] base_32_2;
Expand All @@ -35,7 +28,7 @@ public void TestSetup()
base_20_1 = new byte[MAX_TESTS][];
base_20_2 = new byte[MAX_TESTS][];

for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
base_32_1[i] = RandomBytes(32);
base_20_1[i] = RandomBytes(20);
Expand All @@ -61,9 +54,9 @@ private byte[] RandomBytes(int count)
return randomBytes;
}

public delegate Object BenchmarkMethod();
public delegate object BenchmarkMethod();

public (TimeSpan, Object) Benchmark(BenchmarkMethod method)
public (TimeSpan, object) Benchmark(BenchmarkMethod method)
{
Stopwatch sw0 = new Stopwatch();
sw0.Start();
Expand All @@ -89,7 +82,7 @@ public void Benchmark_CompareTo_UInt256()
UInt256[] uut_32_1 = new UInt256[MAX_TESTS];
UInt256[] uut_32_2 = new UInt256[MAX_TESTS];

for(var i=0; i<MAX_TESTS; i++)
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]);
Expand All @@ -98,7 +91,7 @@ public void Benchmark_CompareTo_UInt256()
var checksum0 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += uut_32_1[i].CompareTo(uut_32_2[i]);
}
Expand All @@ -109,7 +102,7 @@ public void Benchmark_CompareTo_UInt256()
var checksum1 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code1_UInt256CompareTo(base_32_1[i], base_32_2[i]);
}
Expand All @@ -120,7 +113,7 @@ public void Benchmark_CompareTo_UInt256()
var checksum2 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code2_UInt256CompareTo(base_32_1[i], base_32_2[i]);
}
Expand All @@ -131,7 +124,7 @@ public void Benchmark_CompareTo_UInt256()
var checksum3 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code3_UInt256CompareTo(base_32_1[i], base_32_2[i]);
}
Expand All @@ -151,7 +144,7 @@ public void Benchmark_CompareTo_UInt160()
UInt160[] uut_20_1 = new UInt160[MAX_TESTS];
UInt160[] uut_20_2 = new UInt160[MAX_TESTS];

for(var i=0; i<MAX_TESTS; i++)
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]);
Expand All @@ -160,7 +153,7 @@ public void Benchmark_CompareTo_UInt160()
var checksum0 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += uut_20_1[i].CompareTo(uut_20_2[i]);
}
Expand All @@ -171,7 +164,7 @@ public void Benchmark_CompareTo_UInt160()
var checksum1 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code1_UInt160CompareTo(base_20_1[i], base_20_2[i]);
}
Expand All @@ -182,7 +175,7 @@ public void Benchmark_CompareTo_UInt160()
var checksum2 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code2_UInt160CompareTo(base_20_1[i], base_20_2[i]);
}
Expand All @@ -193,7 +186,7 @@ public void Benchmark_CompareTo_UInt160()
var checksum3 = Benchmark(() =>
{
var checksum = 0;
for(var i=0; i<MAX_TESTS; i++)
for (var i = 0; i < MAX_TESTS; i++)
{
checksum += code3_UInt160CompareTo(base_20_1[i], base_20_2[i]);
}
Expand All @@ -209,7 +202,7 @@ public void Benchmark_CompareTo_UInt160()
[TestMethod]
public void Benchmark_UInt_IsCorrect_Self_CompareTo()
{
for(var i=0; i<MAX_TESTS; i++)
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);
Expand Down Expand Up @@ -240,7 +233,7 @@ private unsafe int code2_UInt256CompareTo(byte[] b1, byte[] b2)
{
uint* lpx = (uint*)px;
uint* lpy = (uint*)py;
for (int i = 256/32-1; i >= 0; i--)
for (int i = 256 / 32 - 1; i >= 0; i--)
{
if (lpx[i] > lpy[i])
return 1;
Expand All @@ -257,7 +250,7 @@ private unsafe int code3_UInt256CompareTo(byte[] b1, byte[] b2)
{
ulong* lpx = (ulong*)px;
ulong* lpy = (ulong*)py;
for (int i = 256/64-1; i >= 0; i--)
for (int i = 256 / 64 - 1; i >= 0; i--)
{
if (lpx[i] > lpy[i])
return 1;
Expand Down Expand Up @@ -287,7 +280,7 @@ private unsafe int code2_UInt160CompareTo(byte[] b1, byte[] b2)
{
uint* lpx = (uint*)px;
uint* lpy = (uint*)py;
for (int i = 160/32-1; i >= 0; i--)
for (int i = 160 / 32 - 1; i >= 0; i--)
{
if (lpx[i] > lpy[i])
return 1;
Expand Down
35 changes: 25 additions & 10 deletions neo/UInt160.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,41 @@ public UInt160(byte[] value)
/// Method CompareTo returns 1 if this UInt160 is bigger than other UInt160; -1 if it's smaller; 0 if it's equals
/// Example: assume this is 01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4, this.CompareTo(02ff00ff00ff00ff00ff00ff00ff00ff00ff00a3) returns 1
/// </summary>
public int CompareTo(UInt160 other)
public unsafe int CompareTo(UInt160 other)
{
byte[] x = ToArray();
byte[] y = other.ToArray();
for (int i = x.Length - 1; i >= 0; i--)
fixed (byte* px = ToArray(), py = other.ToArray())
{
if (x[i] > y[i])
return 1;
if (x[i] < y[i])
return -1;
uint* lpx = (uint*)px;
uint* lpy = (uint*)py;
//160 bit / 32 bit step -1
for (int i = (160 / 32 - 1); i >= 0; i--)
Copy link
Contributor

@jsolman jsolman Feb 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we were going to unroll to use 1 uint comparison and 2 ulong comparisons instead of 5 uint comparisons?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes,can do more test to find a fast way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we resolve this, @jsolman? Maybe we could add this change in another PR after another tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be switched later

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dismissed the review; this comment can be left open though while the PR can still be approved.

{
if (lpx[i] > lpy[i])
lightszero marked this conversation as resolved.
Show resolved Hide resolved
return 1;
if (lpx[i] < lpy[i])
return -1;
}
}
return 0;
}

/// <summary>
/// Method Equals returns true if objects are equal, false otherwise
/// </summary>
bool IEquatable<UInt160>.Equals(UInt160 other)
public unsafe bool Equals(UInt160 other)
{
return Equals(other);
fixed (byte* px = ToArray(), py = other.ToArray())
{
uint* lpx = (uint*)px;
uint* lpy = (uint*)py;
//160 bit / 32 bit(uint step) -1
for (int i = (160 / 32 - 1); i >= 0; i--)
{
if (lpx[i] != lpy[i])
return false;
}
}
return true;
}

/// <summary>
Expand Down
35 changes: 25 additions & 10 deletions neo/UInt256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,41 @@ public UInt256(byte[] value)
/// Method CompareTo returns 1 if this UInt256 is bigger than other UInt256; -1 if it's smaller; 0 if it's equals
/// Example: assume this is 01ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a4, this.CompareTo(02ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a3) returns 1
/// </summary>
public int CompareTo(UInt256 other)
public unsafe int CompareTo(UInt256 other)
{
byte[] x = ToArray();
byte[] y = other.ToArray();
for (int i = x.Length - 1; i >= 0; i--)
fixed (byte* px = ToArray(), py = other.ToArray())
{
if (x[i] > y[i])
return 1;
if (x[i] < y[i])
return -1;
ulong* lpx = (ulong*)px;
ulong* lpy = (ulong*)py;
//256bit / 64bit(ulong step) -1
for (int i = (256 / 64 - 1); i >= 0; i--)
{
lightszero marked this conversation as resolved.
Show resolved Hide resolved
if (lpx[i] > lpy[i])
return 1;
if (lpx[i] < lpy[i])
return -1;
}
}
return 0;
}

/// <summary>
/// Method Equals returns true if objects are equal, false otherwise
/// </summary>
bool IEquatable<UInt256>.Equals(UInt256 other)
public unsafe bool Equals(UInt256 other)
{
return Equals(other);
fixed (byte* px = ToArray(), py = other.ToArray())
{
ulong* lpx = (ulong*)px;
ulong* lpy = (ulong*)py;
//256bit / 64bit(ulong step) -1
for (int i = (256 / 64 - 1); i >= 0; i--)
jsolman marked this conversation as resolved.
Show resolved Hide resolved
{
if (lpx[i] != lpy[i])
return false;
}
}
return true;
}

/// <summary>
Expand Down