mirror of
https://github.com/wownero/RandomX.git
synced 2026-10-17 15:31:50 +02:00
RandomX-TOR-v1 benchmark
This commit is contained in:
+15
-7
@@ -34,6 +34,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "vm_compiled_light.hpp"
|
||||
#include "blake2/blake2.h"
|
||||
#include "cpu.hpp"
|
||||
#include "blake2/endian.h"
|
||||
#include "intrin_portable.h"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
@@ -345,10 +347,9 @@ extern "C" {
|
||||
delete machine;
|
||||
}
|
||||
|
||||
void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output) {
|
||||
uint64_t randomx_calculate_numeric(randomx_vm *machine, const void *input, size_t inputSize) {
|
||||
assert(machine != nullptr);
|
||||
assert(inputSize == 0 || input != nullptr);
|
||||
assert(output != nullptr);
|
||||
alignas(16) uint64_t tempHash[8];
|
||||
int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0);
|
||||
assert(blakeResult == 0);
|
||||
@@ -360,7 +361,9 @@ extern "C" {
|
||||
assert(blakeResult == 0);
|
||||
}
|
||||
machine->run(&tempHash);
|
||||
machine->getFinalResult(output, RANDOMX_HASH_SIZE);
|
||||
uint8_t resultBytes[RANDOMX_HASH_SIZE];
|
||||
machine->getFinalResult(resultBytes, RANDOMX_HASH_SIZE);
|
||||
return load64(resultBytes);
|
||||
}
|
||||
|
||||
void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize) {
|
||||
@@ -368,7 +371,7 @@ extern "C" {
|
||||
machine->initScratchpad(machine->tempHash);
|
||||
}
|
||||
|
||||
void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output) {
|
||||
uint64_t randomx_calculate_numeric_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize) {
|
||||
machine->resetRoundingMode();
|
||||
for (uint32_t chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain) {
|
||||
machine->run(machine->tempHash);
|
||||
@@ -378,16 +381,21 @@ extern "C" {
|
||||
|
||||
// Finish current hash and fill the scratchpad for the next hash at the same time
|
||||
blake2b(machine->tempHash, sizeof(machine->tempHash), nextInput, nextInputSize, nullptr, 0);
|
||||
machine->hashAndFill(output, RANDOMX_HASH_SIZE, machine->tempHash);
|
||||
uint8_t resultBytes[RANDOMX_HASH_SIZE];
|
||||
machine->hashAndFill(resultBytes, RANDOMX_HASH_SIZE, machine->tempHash);
|
||||
return load64(resultBytes);
|
||||
}
|
||||
|
||||
void randomx_calculate_hash_last(randomx_vm* machine, void* output) {
|
||||
uint64_t randomx_calculate_numeric_last(randomx_vm* machine) {
|
||||
machine->resetRoundingMode();
|
||||
for (int chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain) {
|
||||
machine->run(machine->tempHash);
|
||||
blake2b(machine->tempHash, sizeof(machine->tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0);
|
||||
}
|
||||
machine->run(machine->tempHash);
|
||||
machine->getFinalResult(output, RANDOMX_HASH_SIZE);
|
||||
uint8_t resultBytes[RANDOMX_HASH_SIZE];
|
||||
machine->getFinalResult(resultBytes, RANDOMX_HASH_SIZE);
|
||||
return load64(resultBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-13
@@ -32,7 +32,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RANDOMX_HASH_SIZE 32
|
||||
#define RANDOMX_HASH_SIZE 8
|
||||
#define RANDOMX_DATASET_ITEM_SIZE 64
|
||||
|
||||
#ifndef RANDOMX_EXPORT
|
||||
@@ -229,34 +229,36 @@ RANDOMX_EXPORT void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset
|
||||
RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine);
|
||||
|
||||
/**
|
||||
* Calculates a RandomX hash value.
|
||||
* Calculates a RandomX hash value and interprets the result as a little-endian 64-bit usigned integer.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
|
||||
* @param input is a pointer to memory to be hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes to be hashed.
|
||||
* @param output is a pointer to memory where the hash will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*
|
||||
* @return 64-bit numeric hash value
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output);
|
||||
RANDOMX_EXPORT uint64_t randomx_calculate_numeric(randomx_vm *machine, const void *input, size_t inputSize);
|
||||
|
||||
/**
|
||||
* Set of functions used to calculate multiple RandomX hashes more efficiently.
|
||||
* randomx_calculate_hash_first will begin a hash calculation.
|
||||
* randomx_calculate_hash_next will output the hash value of the previous input
|
||||
* and begin the calculation of the next hash.
|
||||
* randomx_calculate_hash_last will output the hash value of the previous input.
|
||||
* Hashes are returned as 64-bit unsigned integers.
|
||||
*
|
||||
* randomx_calculate_hash_first will begin a hash calculation.
|
||||
* randomx_calculate_numeric_next will output the hash value of the previous input
|
||||
* and begin the calculation of the next hash.
|
||||
* randomx_calculate_numeric_last will output the hash value of the previous input.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
|
||||
* @param input is a pointer to memory to be hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes to be hashed.
|
||||
* @param nextInput is a pointer to memory to be hashed for the next hash. Must not be NULL.
|
||||
* @param nextInputSize is the number of bytes to be hashed for the next hash.
|
||||
* @param output is a pointer to memory where the hash will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*
|
||||
* @return 64-bit numeric hash value (when applicable).
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize);
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output);
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_last(randomx_vm* machine, void* output);
|
||||
RANDOMX_EXPORT uint64_t randomx_calculate_numeric_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize);
|
||||
RANDOMX_EXPORT uint64_t randomx_calculate_numeric_last(randomx_vm* machine);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
+62
-39
@@ -40,32 +40,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../dataset.hpp"
|
||||
#include "../blake2/endian.h"
|
||||
#include "../common.hpp"
|
||||
#include "../intrin_portable.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <VersionHelpers.h>
|
||||
#endif
|
||||
#include "affinity.hpp"
|
||||
|
||||
const uint8_t blockTemplate_[] = {
|
||||
0x07, 0x07, 0xf7, 0xa4, 0xf0, 0xd6, 0x05, 0xb3, 0x03, 0x26, 0x08, 0x16, 0xba, 0x3f, 0x10, 0x90, 0x2e, 0x1a, 0x14,
|
||||
0x5a, 0xc5, 0xfa, 0xd3, 0xaa, 0x3a, 0xf6, 0xea, 0x44, 0xc1, 0x18, 0x69, 0xdc, 0x4f, 0x85, 0x3f, 0x00, 0x2b, 0x2e,
|
||||
0xea, 0x00, 0x00, 0x00, 0x00, 0x77, 0xb2, 0x06, 0xa0, 0x2c, 0xa5, 0xb1, 0xd4, 0xce, 0x6b, 0xbf, 0xdf, 0x0a, 0xca,
|
||||
0xc3, 0x8b, 0xde, 0xd3, 0x4d, 0x2d, 0xcd, 0xee, 0xf9, 0x5c, 0xd2, 0x0c, 0xef, 0xc1, 0x2f, 0x61, 0xd5, 0x61, 0x09
|
||||
};
|
||||
const uint8_t nonceTemplate[] = { 0x8b, 0xc3, 0xde, 0xd3, 0x4d, 0x2d, 0xcd, 0xee, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x5c, 0xd2, 0x0c };
|
||||
|
||||
class AtomicHash {
|
||||
public:
|
||||
AtomicHash() {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
hash[i].store(0);
|
||||
hash.store(0);
|
||||
}
|
||||
void xorWith(uint64_t update[4]) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
hash[i].fetch_xor(update[i]);
|
||||
void xorWith(uint64_t update) {
|
||||
hash.fetch_xor(update);
|
||||
}
|
||||
void print(std::ostream& os) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
print(hash[i], os);
|
||||
print(hash, os);
|
||||
os << std::endl;
|
||||
}
|
||||
private:
|
||||
@@ -73,14 +66,14 @@ private:
|
||||
auto h = hash.load();
|
||||
outputHex(std::cout, (char*)&h, sizeof(h));
|
||||
}
|
||||
std::atomic<uint64_t> hash[4];
|
||||
std::atomic<uint64_t> hash;
|
||||
};
|
||||
|
||||
void printUsage(const char* executable) {
|
||||
std::cout << "Usage: " << executable << " [OPTIONS]" << std::endl;
|
||||
std::cout << "Supported options:" << std::endl;
|
||||
std::cout << " --help shows this message" << std::endl;
|
||||
std::cout << " --mine mining mode: 2080 MiB" << std::endl;
|
||||
std::cout << " --mine mining mode: 1040 MiB" << std::endl;
|
||||
std::cout << " --verify verification mode: 256 MiB" << std::endl;
|
||||
std::cout << " --jit JIT compiled mode (default: interpreter)" << std::endl;
|
||||
std::cout << " --secure W^X policy for JIT pages (default: off)" << std::endl;
|
||||
@@ -109,30 +102,46 @@ struct DatasetAllocException : public MemoryException {
|
||||
}
|
||||
};
|
||||
|
||||
void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread, int cpuid=-1) {
|
||||
struct HashResult {
|
||||
uint64_t result = UINT64_MAX;
|
||||
uint32_t nonce;
|
||||
};
|
||||
|
||||
void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread, int cpuid, HashResult& bestResult) {
|
||||
if (cpuid >= 0) {
|
||||
int rc = set_thread_affinity(cpuid);
|
||||
if (rc) {
|
||||
std::cerr << "Failed to set thread affinity for thread " << thread << " (error=" << rc << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
uint64_t hash[RANDOMX_HASH_SIZE / sizeof(uint64_t)];
|
||||
uint8_t blockTemplate[sizeof(blockTemplate_)];
|
||||
memcpy(blockTemplate, blockTemplate_, sizeof(blockTemplate));
|
||||
void* noncePtr = blockTemplate + 39;
|
||||
auto nonce = atomicNonce.fetch_add(1);
|
||||
|
||||
uint8_t fullNonce[sizeof(nonceTemplate)];
|
||||
memcpy(fullNonce, nonceTemplate, sizeof(nonceTemplate));
|
||||
void* noncePtr = fullNonce + 8;
|
||||
uint32_t nonce = atomicNonce.fetch_add(1);
|
||||
uint32_t prevNonce;
|
||||
|
||||
store32(noncePtr, nonce);
|
||||
randomx_calculate_hash_first(vm, blockTemplate, sizeof(blockTemplate));
|
||||
randomx_calculate_hash_first(vm, fullNonce, sizeof(fullNonce));
|
||||
|
||||
while (nonce < noncesCount) {
|
||||
prevNonce = nonce;
|
||||
nonce = atomicNonce.fetch_add(1);
|
||||
store32(noncePtr, nonce);
|
||||
randomx_calculate_hash_next(vm, blockTemplate, sizeof(blockTemplate), &hash);
|
||||
result.xorWith(hash);
|
||||
auto hash = randomx_calculate_numeric_next(vm, fullNonce, sizeof(fullNonce));
|
||||
//result.xorWith(hash);
|
||||
if (hash < bestResult.result) {
|
||||
bestResult.result = hash;
|
||||
bestResult.nonce = prevNonce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int validateResult(randomx_vm* vm, uint64_t effort, void* nonce) {
|
||||
uint64_t result = randomx_calculate_numeric(vm, nonce, sizeof(nonceTemplate));
|
||||
return mulh(effort, result) == 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool softAes, miningMode, verificationMode, help, largePages, jit, secure, ssse3, avx2, autoFlags;
|
||||
int noncesCount, threadCount, initThreadCount;
|
||||
@@ -161,7 +170,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
store32(&seed, seedValue);
|
||||
|
||||
std::cout << "RandomX benchmark v1.1.7" << std::endl;
|
||||
std::cout << "RandomX-TOR-v1 benchmark" << std::endl;
|
||||
|
||||
if (help) {
|
||||
printUsage(argv[0]);
|
||||
@@ -181,6 +190,7 @@ int main(int argc, char** argv) {
|
||||
randomx_dataset* dataset;
|
||||
randomx_cache* cache;
|
||||
randomx_flags flags;
|
||||
std::vector<HashResult> results;
|
||||
|
||||
if (autoFlags) {
|
||||
initThreadCount = std::thread::hardware_concurrency();
|
||||
@@ -228,7 +238,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (flags & RANDOMX_FLAG_FULL_MEM) {
|
||||
std::cout << " - full memory mode (2080 MiB)" << std::endl;
|
||||
std::cout << " - full memory mode (1040 MiB)" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << " - light memory mode (256 MiB)" << std::endl;
|
||||
@@ -325,6 +335,7 @@ int main(int argc, char** argv) {
|
||||
throw std::runtime_error("Cannot create VM");
|
||||
}
|
||||
vms.push_back(vm);
|
||||
results.push_back(HashResult());
|
||||
}
|
||||
std::cout << "Running benchmark (" << noncesCount << " nonces) ..." << std::endl;
|
||||
sw.restart();
|
||||
@@ -333,33 +344,45 @@ int main(int argc, char** argv) {
|
||||
int cpuid = -1;
|
||||
if (threadAffinity)
|
||||
cpuid = cpuid_from_mask(threadAffinity, i);
|
||||
threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i, cpuid));
|
||||
threads.push_back(std::thread(&mine, vms[i], std::ref(atomicNonce), std::ref(result), noncesCount, i, cpuid, std::ref(results[i])));
|
||||
}
|
||||
for (unsigned i = 0; i < threads.size(); ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
else {
|
||||
mine(vms[0], std::ref(atomicNonce), std::ref(result), noncesCount, 0);
|
||||
mine(vms[0], std::ref(atomicNonce), std::ref(result), noncesCount, 0, -1, std::ref(results[0]));
|
||||
}
|
||||
|
||||
double elapsed = sw.getElapsed();
|
||||
std::cout << "Performance: " << noncesCount / elapsed << " hashes per second" << std::endl;
|
||||
HashResult bestResult;
|
||||
for (auto& result : results) {
|
||||
if (result.result < bestResult.result) {
|
||||
bestResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
auto effort = UINT64_MAX / bestResult.result;
|
||||
std::cout << "Best result: " << std::endl;
|
||||
uint8_t nonce[sizeof(nonceTemplate)];
|
||||
memcpy(nonce, nonceTemplate, sizeof(nonceTemplate));
|
||||
store32(nonce + 8, bestResult.nonce);
|
||||
std::cout << " Nonce: ";
|
||||
outputHex(std::cout, (const char*)nonce, sizeof(nonce));
|
||||
std::cout << std::endl;
|
||||
std::cout << " Result: ";
|
||||
outputHex(std::cout, (char*)&bestResult.result, sizeof(bestResult.result));
|
||||
std::cout << std::endl;
|
||||
std::cout << " Effort: " << effort << std::endl;
|
||||
std::cout << " Valid: " << validateResult(vms[0], effort, nonce) << std::endl;
|
||||
|
||||
for (unsigned i = 0; i < vms.size(); ++i)
|
||||
randomx_destroy_vm(vms[i]);
|
||||
if (miningMode)
|
||||
randomx_release_dataset(dataset);
|
||||
else
|
||||
randomx_release_cache(cache);
|
||||
std::cout << "Calculated result: ";
|
||||
result.print(std::cout);
|
||||
if (noncesCount == 1000 && seedValue == 0)
|
||||
std::cout << "Reference result: 10b649a3f15c7c7f88277812f2e74b337a0f20ce909af09199cccb960771cfa1" << std::endl;
|
||||
if (!miningMode) {
|
||||
std::cout << "Performance: " << 1000 * elapsed / noncesCount << " ms per hash" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "Performance: " << noncesCount / elapsed << " hashes per second" << std::endl;
|
||||
}
|
||||
}
|
||||
catch (MemoryException& e) {
|
||||
std::cout << "ERROR: " << e.what() << std::endl;
|
||||
@@ -370,7 +393,7 @@ int main(int argc, char** argv) {
|
||||
std::cout << "Additionally, you have to run the benchmark from elevated command prompt." << std::endl;
|
||||
}
|
||||
#else
|
||||
std::cout << "To use large pages, please run: sudo sysctl -w vm.nr_hugepages=1250" << std::endl;
|
||||
std::cout << "To use large pages, please run: sudo sysctl -w vm.nr_hugepages=750" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user