Further Equihash optimisation: partial parallelisation

Run the initial XorTable fillup in 'Equihash::computeAllHashes' in
parallel, using a parallel stream, to get an easy speed up. (The solver
spends about half its time computing BLAKE2b hashes before iteratively
building tables of partial collisions using 'Equihash::findCollisions'.)

As part of this, replace the use of 'java.nio.ByteBuffer' array wrapping
in 'Utilities::(bytesToIntsBE|intsToBytesBE)' with manual for-loops, as
profiling reveals an unexpected bottleneck in the former when used in a
multithreaded setting. (Lock contention somewhere in unsafe code?)
This commit is contained in:
Steven Barclay 2021-11-23 08:54:55 +00:00 committed by Christoph Atteneder
parent 0a603167f1
commit 998a0e0aaf
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B
2 changed files with 16 additions and 11 deletions

View file

@ -42,6 +42,7 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.PrimitiveIterator;
import java.util.stream.IntStream;
import lombok.ToString;
@ -244,15 +245,11 @@ public class Equihash {
}
private XorTable computeAllHashes() {
var tableValues = ImmutableIntArray.builder((k + 2) * N);
for (int i = 0; i < N; i++) {
var tableValues = IntStream.range(0, N).flatMap(i -> {
int[] hash = hashInputs(i);
for (int j = 0; j <= k; j++) {
tableValues.add(hash[j] & (N / 2 - 1));
}
tableValues.add(i);
}
return new XorTable(k + 1, 1, tableValues.build());
return IntStream.range(0, k + 2).map(j -> j <= k ? hash[j] & (N / 2 - 1) : i);
});
return new XorTable(k + 1, 1, ImmutableIntArray.copyOf(tableValues.parallel()));
}
private boolean testDifficultyCondition(int[] inputs) {

View file

@ -20,6 +20,7 @@ package bisq.common.util;
import org.bitcoinj.core.Utils;
import com.google.common.base.Splitter;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
@ -42,7 +43,6 @@ import java.text.DecimalFormat;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.file.Paths;
import java.io.File;
@ -536,13 +536,21 @@ public class Utilities {
public static byte[] intsToBytesBE(int[] ints) {
byte[] bytes = new byte[ints.length * 4];
ByteBuffer.wrap(bytes).asIntBuffer().put(ints);
int i = 0;
for (int v : ints) {
bytes[i++] = (byte) (v >> 24);
bytes[i++] = (byte) (v >> 16);
bytes[i++] = (byte) (v >> 8);
bytes[i++] = (byte) v;
}
return bytes;
}
public static int[] bytesToIntsBE(byte[] bytes) {
int[] ints = new int[bytes.length / 4];
ByteBuffer.wrap(bytes).asIntBuffer().get(ints);
for (int i = 0, j = 0; i < bytes.length / 4; i++) {
ints[i] = Ints.fromBytes(bytes[j++], bytes[j++], bytes[j++], bytes[j++]);
}
return ints;
}