mirror of
https://codeberg.org/wownero/RandomWOW
synced 2026-03-05 14:17:33 -05:00
@@ -70,10 +70,6 @@ void generateNative(uint32_t nonce) {
|
||||
fillAes1Rx4<softAes>((void*)hash, randomx::ScratchpadSize, scratchpad);
|
||||
alignas(16) randomx::Program prog;
|
||||
fillAes1Rx4<softAes>((void*)hash, sizeof(prog), &prog);
|
||||
for (int i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
|
||||
prog(i).dst %= 8;
|
||||
prog(i).src %= 8;
|
||||
}
|
||||
std::cout << prog << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ int main(int argc, char** argv) {
|
||||
readIntOption("--seed", argc, argv, seed, 0);
|
||||
readIntOption("--executionPorts", argc, argv, executionPorts, 4);
|
||||
readIntOption("--memoryPorts", argc, argv, memoryPorts, 2);
|
||||
readIntOption("--pipeline", argc, argv, pipeline, 3 + speculate);
|
||||
readIntOption("--pipeline", argc, argv, pipeline, 3);
|
||||
randomx::Program p, original;
|
||||
double totalCycles = 0.0;
|
||||
double jumpCount = 0;
|
||||
@@ -113,7 +113,6 @@ int executeInOrder(randomx::Program& p, randomx::Program& original, bool print,
|
||||
int flt_reg_ready[randomx::RegistersCount] = { 0 };
|
||||
//each workgroup takes 1 or 2 cycles (2 cycles if any instruction has a memory operand)
|
||||
while (index < RANDOMX_PROGRAM_SIZE) {
|
||||
int memoryReads = 0;
|
||||
int memoryAccesses = 0;
|
||||
bool hasRound = false;
|
||||
int workers = 0;
|
||||
@@ -128,7 +127,10 @@ int executeInOrder(randomx::Program& p, randomx::Program& original, bool print,
|
||||
if (has(instr, MASK_SRC, SRC_INT) && int_reg_ready[instr.src] > cycle)
|
||||
break;
|
||||
|
||||
if (has(instr, MASK_SRC, SRC_MEM) && int_reg_ready[instr.src] > cycle)
|
||||
if (has(instr, MASK_SRC, SRC_MEM) && int_reg_ready[instr.src] > cycle - 1)
|
||||
break;
|
||||
|
||||
if (has(instr, MASK_DST, DST_MEM) && int_reg_ready[instr.dst] > cycle - 1)
|
||||
break;
|
||||
|
||||
if (has(instr, MASK_DST, DST_FLT) && flt_reg_ready[instr.dst] > cycle)
|
||||
@@ -160,20 +162,12 @@ int executeInOrder(randomx::Program& p, randomx::Program& original, bool print,
|
||||
if (has(instr, MASK_EXT, OP_CFROUND))
|
||||
hasRound = true;
|
||||
|
||||
if (has(instr, MASK_SRC, SRC_MEM)) {
|
||||
memoryReads++;
|
||||
if (has(instr, MASK_SRC, SRC_MEM) || has(instr, MASK_DST, DST_MEM)) {
|
||||
memoryAccesses++;
|
||||
if (print)
|
||||
std::cout << std::setw(2) << (cycle + 2) << ": " << origi;
|
||||
}
|
||||
else {
|
||||
if (print)
|
||||
std::cout << std::setw(2) << (cycle + 1) << ": " << origi;
|
||||
}
|
||||
|
||||
if (has(instr, MASK_DST, DST_MEM)) {
|
||||
memoryAccesses++;
|
||||
}
|
||||
if (print)
|
||||
std::cout << std::setw(2) << (cycle + 1) << ": " << origi;
|
||||
|
||||
//non-speculative execution must stall after branch
|
||||
if (!speculate && has(instr, MASK_EXT, OP_BRANCH)) {
|
||||
@@ -183,8 +177,6 @@ int executeInOrder(randomx::Program& p, randomx::Program& original, bool print,
|
||||
}
|
||||
//std::cout << " workers: " << workers << std::endl;
|
||||
cycle++;
|
||||
if (memoryReads)
|
||||
cycle++;
|
||||
}
|
||||
if (speculate) {
|
||||
//account for mispredicted branches
|
||||
@@ -201,8 +193,8 @@ int executeInOrder(randomx::Program& p, randomx::Program& original, bool print,
|
||||
|
||||
int executeOutOfOrder(randomx::Program& p, randomx::Program& original, bool print, int executionPorts, int memoryPorts, bool speculate, int pipeline) {
|
||||
int index = 0;
|
||||
int busyExecutionPorts[RANDOMX_PROGRAM_SIZE] = { 0 };
|
||||
int busyMemoryPorts[RANDOMX_PROGRAM_SIZE] = { 0 };
|
||||
int busyExecutionPorts[2 * RANDOMX_PROGRAM_SIZE] = { 0 };
|
||||
int busyMemoryPorts[2 * RANDOMX_PROGRAM_SIZE] = { 0 };
|
||||
int int_reg_ready[randomx::RegistersCount] = { 0 };
|
||||
int flt_reg_ready[randomx::RegistersCount] = { 0 };
|
||||
int fprcReady = 0;
|
||||
@@ -219,14 +211,15 @@ int executeOutOfOrder(randomx::Program& p, randomx::Program& original, bool prin
|
||||
//check dependencies
|
||||
if (has(instr, MASK_SRC, SRC_INT)) {
|
||||
retireCycle = std::max(retireCycle, int_reg_ready[instr.src]);
|
||||
int_reg_ready[instr.src] = retireCycle;
|
||||
}
|
||||
|
||||
if (has(instr, MASK_SRC, SRC_MEM)) {
|
||||
retireCycle = std::max(retireCycle, int_reg_ready[instr.src]);
|
||||
retireCycle = std::max(retireCycle, int_reg_ready[instr.src] + 1);
|
||||
//find free memory port
|
||||
do {
|
||||
while (busyMemoryPorts[retireCycle - 1] >= memoryPorts) {
|
||||
retireCycle++;
|
||||
} while (busyMemoryPorts[retireCycle - 1] >= memoryPorts);
|
||||
}
|
||||
busyMemoryPorts[retireCycle - 1]++;
|
||||
}
|
||||
|
||||
@@ -244,11 +237,13 @@ int executeOutOfOrder(randomx::Program& p, randomx::Program& original, bool prin
|
||||
|
||||
//execute
|
||||
if (has(instr, MASK_DST, DST_MEM)) {
|
||||
retireCycle = std::max(retireCycle, int_reg_ready[instr.dst] + 1);
|
||||
//find free memory port
|
||||
do {
|
||||
while (busyMemoryPorts[retireCycle - 1] >= memoryPorts) {
|
||||
retireCycle++;
|
||||
} while (busyMemoryPorts[retireCycle - 1] >= memoryPorts);
|
||||
}
|
||||
busyMemoryPorts[retireCycle - 1]++;
|
||||
retireCycle++;
|
||||
}
|
||||
|
||||
if (has(instr, MASK_DST, DST_FLT)) {
|
||||
@@ -625,7 +620,6 @@ int analyze(randomx::Program& p) {
|
||||
CASE_REP(ISTORE) {
|
||||
instr.dst = instr.dst % randomx::RegistersCount;
|
||||
instr.src = instr.src % randomx::RegistersCount;
|
||||
instr.opcode |= SRC_INT;
|
||||
instr.opcode |= DST_MEM;
|
||||
if (instr.getModCond() < randomx::StoreL3Condition)
|
||||
instr.imm32 = (instr.getModMem() ? randomx::ScratchpadL1Mask : randomx::ScratchpadL2Mask);
|
||||
|
||||
172
src/tests/runtime-distr.cpp
Normal file
172
src/tests/runtime-distr.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#include <thread>
|
||||
#include "utility.hpp"
|
||||
#include "stopwatch.hpp"
|
||||
#include "../dataset.hpp"
|
||||
#include "../vm_compiled.hpp"
|
||||
#include "../blake2/blake2.h"
|
||||
|
||||
struct Outlier {
|
||||
Outlier(int idx, double rtime) : index(idx), runtime(rtime) {}
|
||||
int index;
|
||||
double runtime;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
constexpr int distributionSize = 100;
|
||||
int distribution[distributionSize + 1] = { 0 };
|
||||
Stopwatch sw;
|
||||
alignas(16) uint64_t hash[8];
|
||||
|
||||
uint64_t checksum = 0;
|
||||
double totalRuntime = 0;
|
||||
double maxRuntime = 0;
|
||||
std::vector<Outlier> outliers;
|
||||
outliers.reserve(25);
|
||||
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
|
||||
|
||||
bool softAes, largePages, jit, verify;
|
||||
int totalCount, initThreadCount;
|
||||
double binSize, offset;
|
||||
int32_t seed;
|
||||
|
||||
readOption("--verify", argc, argv, verify);
|
||||
readOption("--jit", argc, argv, jit);
|
||||
readOption("--softAes", argc, argv, softAes);
|
||||
readIntOption("--nonces", argc, argv, totalCount, 10000);
|
||||
readIntOption("--init", argc, argv, initThreadCount, 1);
|
||||
readFloatOption("--binSize", argc, argv, binSize, 1e-3);
|
||||
readFloatOption("--offset", argc, argv, offset, 0);
|
||||
readIntOption("--seed", argc, argv, seed, 0);
|
||||
readOption("--largePages", argc, argv, largePages);
|
||||
|
||||
if (!verify) {
|
||||
flags = (randomx_flags)(flags | RANDOMX_FLAG_FULL_MEM);
|
||||
std::cout << "Measure program runtime" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "Measure verification time" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << " - histogram offset: " << offset << std::endl;
|
||||
std::cout << " - histogram bin size: " << binSize << std::endl;
|
||||
|
||||
if (jit) {
|
||||
flags = (randomx_flags)(flags | RANDOMX_FLAG_JIT);
|
||||
std::cout << " - JIT compiled mode" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << " - interpreted mode" << std::endl;
|
||||
}
|
||||
|
||||
if (softAes) {
|
||||
std::cout << " - software AES mode" << std::endl;
|
||||
}
|
||||
else {
|
||||
flags = (randomx_flags)(flags | RANDOMX_FLAG_HARD_AES);
|
||||
std::cout << " - hardware AES mode" << std::endl;
|
||||
}
|
||||
|
||||
if (largePages) {
|
||||
flags = (randomx_flags)(flags | RANDOMX_FLAG_LARGE_PAGES);
|
||||
std::cout << " - large pages mode" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << " - small pages mode" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Initializing..." << std::endl;
|
||||
|
||||
randomx_cache *cache = randomx_alloc_cache(flags);
|
||||
randomx_dataset *dataset = nullptr;
|
||||
if (cache == nullptr) {
|
||||
std::cout << "Cache allocation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
randomx_init_cache(cache, &seed, sizeof seed);
|
||||
|
||||
if (!verify) {
|
||||
blake2b(&hash, sizeof hash, &seed, sizeof seed, nullptr, 0);
|
||||
|
||||
dataset = randomx_alloc_dataset(flags);
|
||||
if (dataset == nullptr) {
|
||||
std::cout << "Dataset allocation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
uint32_t datasetItemCount = randomx_dataset_item_count();
|
||||
if (initThreadCount > 1) {
|
||||
auto perThread = datasetItemCount / initThreadCount;
|
||||
auto remainder = datasetItemCount % initThreadCount;
|
||||
uint32_t startItem = 0;
|
||||
for (int i = 0; i < initThreadCount; ++i) {
|
||||
auto count = perThread + (i == initThreadCount - 1 ? remainder : 0);
|
||||
threads.push_back(std::thread(&randomx_init_dataset, dataset, cache, startItem, count));
|
||||
startItem += count;
|
||||
}
|
||||
for (unsigned i = 0; i < threads.size(); ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
else {
|
||||
randomx_init_dataset(dataset, cache, 0, datasetItemCount);
|
||||
}
|
||||
randomx_release_cache(cache);
|
||||
cache = nullptr;
|
||||
}
|
||||
|
||||
std::cout << "Running " << totalCount << " programs..." << std::endl;
|
||||
|
||||
randomx_vm* vm = randomx_create_vm(flags, cache, dataset);
|
||||
|
||||
if (!verify) {
|
||||
vm->initScratchpad(&hash);
|
||||
vm->resetRoundingMode();
|
||||
}
|
||||
|
||||
for (int i = 0; i < totalCount; ++i) {
|
||||
sw.restart();
|
||||
if (verify)
|
||||
randomx_calculate_hash(vm, &i, sizeof i, &hash);
|
||||
else
|
||||
vm->run(&hash);
|
||||
double elapsed = sw.getElapsed();
|
||||
//std::cout << "Elapsed: " << elapsed << std::endl;
|
||||
totalRuntime += elapsed;
|
||||
if (elapsed > maxRuntime)
|
||||
maxRuntime = elapsed;
|
||||
int bin = (elapsed - offset) / binSize;
|
||||
bool outlier = false;
|
||||
if (bin < 0) {
|
||||
bin = 0;
|
||||
outlier = true;
|
||||
}
|
||||
if (bin > distributionSize) {
|
||||
bin = distributionSize;
|
||||
outlier = true;
|
||||
}
|
||||
if (outlier && outliers.size() < outliers.capacity())
|
||||
outliers.push_back(Outlier(i, elapsed));
|
||||
distribution[bin]++;
|
||||
if(!verify)
|
||||
blake2b(hash, sizeof(hash), vm->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0);
|
||||
checksum ^= hash[0];
|
||||
}
|
||||
|
||||
for (int i = 0; i < distributionSize + 1; ++i) {
|
||||
std::cout << i << " " << distribution[i] << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Average runtime: " << totalRuntime / totalCount << std::endl;
|
||||
std::cout << "Maximum runtime: " << maxRuntime << std::endl;
|
||||
std::cout << "Checksum: " << checksum << std::endl;
|
||||
|
||||
std::cout << "Outliers: " << std::endl;
|
||||
|
||||
for (Outlier& ol : outliers) {
|
||||
std::cout << " " << ol.index << ": " << ol.runtime << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -66,6 +66,15 @@ inline void readIntOption(const char* option, int argc, char** argv, int& out, i
|
||||
out = defaultValue;
|
||||
}
|
||||
|
||||
inline void readFloatOption(const char* option, int argc, char** argv, double& out, double defaultValue) {
|
||||
for (int i = 0; i < argc - 1; ++i) {
|
||||
if (strcmp(argv[i], option) == 0 && (out = atof(argv[i + 1])) > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
out = defaultValue;
|
||||
}
|
||||
|
||||
inline void readInt(int argc, char** argv, int& out, int defaultValue) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (*argv[i] != '-' && (out = atoi(argv[i])) > 0) {
|
||||
|
||||
Reference in New Issue
Block a user