Configurable parameters separated into configuration.h

This commit is contained in:
tevador 2019-03-08 15:34:34 +01:00
parent 096a7c0d7b
commit e65d9da66c
16 changed files with 182 additions and 170 deletions

View File

@ -47,7 +47,7 @@ namespace RandomX {
void AssemblyGeneratorX86::generateProgram(Program& prog) { void AssemblyGeneratorX86::generateProgram(Program& prog) {
asmCode.str(std::string()); //clear asmCode.str(std::string()); //clear
for (unsigned i = 0; i < ProgramLength; ++i) { for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
Instruction& instr = prog(i); Instruction& instr = prog(i);
instr.src %= RegistersCount; instr.src %= RegistersCount;
instr.dst %= RegistersCount; instr.dst %= RegistersCount;
@ -491,7 +491,6 @@ namespace RandomX {
INST_HANDLE(ISMULH_R) INST_HANDLE(ISMULH_R)
INST_HANDLE(ISMULH_M) INST_HANDLE(ISMULH_M)
INST_HANDLE(IMUL_RCP) INST_HANDLE(IMUL_RCP)
INST_HANDLE(ISDIV_C)
INST_HANDLE(INEG_R) INST_HANDLE(INEG_R)
INST_HANDLE(IXOR_R) INST_HANDLE(IXOR_R)
INST_HANDLE(IXOR_M) INST_HANDLE(IXOR_M)
@ -511,8 +510,6 @@ namespace RandomX {
//Floating point group E //Floating point group E
INST_HANDLE(FMUL_R) INST_HANDLE(FMUL_R)
INST_HANDLE(FMUL_M)
INST_HANDLE(FDIV_R)
INST_HANDLE(FDIV_M) INST_HANDLE(FDIV_M)
INST_HANDLE(FSQRT_R) INST_HANDLE(FSQRT_R)
@ -520,9 +517,7 @@ namespace RandomX {
INST_HANDLE(COND_R) INST_HANDLE(COND_R)
INST_HANDLE(COND_M) INST_HANDLE(COND_M)
INST_HANDLE(CFROUND) INST_HANDLE(CFROUND)
INST_HANDLE(ISTORE) INST_HANDLE(ISTORE)
INST_HANDLE(FSTORE)
INST_HANDLE(NOP) INST_HANDLE(NOP)
}; };

View File

@ -24,7 +24,7 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
namespace RandomX { namespace RandomX {
static_assert(ArgonMemorySize % (ArgonLanes * ARGON2_SYNC_POINTS) == 0, "ArgonMemorySize - invalid value"); static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value");
void Cache::argonFill(const void* seed, size_t seedSize) { void Cache::argonFill(const void* seed, size_t seedSize) {
uint32_t memory_blocks, segment_length; uint32_t memory_blocks, segment_length;
@ -35,15 +35,15 @@ namespace RandomX {
context.outlen = 0; context.outlen = 0;
context.pwd = CONST_CAST(uint8_t *)seed; context.pwd = CONST_CAST(uint8_t *)seed;
context.pwdlen = (uint32_t)seedSize; context.pwdlen = (uint32_t)seedSize;
context.salt = CONST_CAST(uint8_t *)ArgonSalt; context.salt = CONST_CAST(uint8_t *)RANDOMX_ARGON_SALT;
context.saltlen = (uint32_t)ArgonSaltSize; context.saltlen = (uint32_t)ArgonSaltSize;
context.secret = NULL; context.secret = NULL;
context.secretlen = 0; context.secretlen = 0;
context.ad = NULL; context.ad = NULL;
context.adlen = 0; context.adlen = 0;
context.t_cost = ArgonIterations; context.t_cost = RANDOMX_ARGON_ITERATIONS;
context.m_cost = ArgonMemorySize; context.m_cost = RANDOMX_ARGON_MEMORY;
context.lanes = ArgonLanes; context.lanes = RANDOMX_ARGON_LANES;
context.threads = 1; context.threads = 1;
context.allocate_cbk = NULL; context.allocate_cbk = NULL;
context.free_cbk = NULL; context.free_cbk = NULL;

View File

@ -23,6 +23,9 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
namespace RandomX { namespace RandomX {
static_assert(sizeof(MemoryRegisters) == 2 * sizeof(addr_t) + sizeof(uintptr_t), "Invalid alignment of struct RandomX::MemoryRegisters");
static_assert(sizeof(RegisterFile) == 256, "Invalid alignment of struct RandomX::RegisterFile");
CompiledVirtualMachine::CompiledVirtualMachine() { CompiledVirtualMachine::CompiledVirtualMachine() {
totalSize = 0; totalSize = 0;
} }
@ -39,7 +42,7 @@ namespace RandomX {
void CompiledVirtualMachine::execute() { void CompiledVirtualMachine::execute() {
//executeProgram(reg, mem, scratchpad, InstructionCount); //executeProgram(reg, mem, scratchpad, InstructionCount);
//totalSize += compiler.getCodeSize(); //totalSize += compiler.getCodeSize();
compiler.getProgramFunc()(reg, mem, scratchpad, InstructionCount); compiler.getProgramFunc()(reg, mem, scratchpad, RANDOMX_PROGRAM_ITERATIONS);
#ifdef TRACEVM #ifdef TRACEVM
for (int32_t i = InstructionCount - 1; i >= 0; --i) { for (int32_t i = InstructionCount - 1; i >= 0; --i) {
std::cout << std::hex << tracepad[i].u64 << std::endl; std::cout << std::hex << tracepad[i].u64 << std::endl;

View File

@ -26,6 +26,10 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
namespace RandomX { namespace RandomX {
extern "C" {
void executeProgram(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t);
}
class CompiledVirtualMachine : public VirtualMachine { class CompiledVirtualMachine : public VirtualMachine {
public: public:
void* operator new(size_t size) { void* operator new(size_t size) {

View File

@ -346,12 +346,10 @@ namespace RandomX {
INST_NAME(ISMULH_R) INST_NAME(ISMULH_R)
INST_NAME(ISMULH_M) INST_NAME(ISMULH_M)
INST_NAME(IMUL_RCP) INST_NAME(IMUL_RCP)
INST_NAME(ISDIV_C)
INST_NAME(INEG_R) INST_NAME(INEG_R)
INST_NAME(IXOR_R) INST_NAME(IXOR_R)
INST_NAME(IXOR_M) INST_NAME(IXOR_M)
INST_NAME(IROR_R) INST_NAME(IROR_R)
INST_NAME(IROL_R)
INST_NAME(ISWAP_R) INST_NAME(ISWAP_R)
//Common floating point //Common floating point
@ -366,8 +364,6 @@ namespace RandomX {
//Floating point group E //Floating point group E
INST_NAME(FMUL_R) INST_NAME(FMUL_R)
INST_NAME(FMUL_M)
INST_NAME(FDIV_R)
INST_NAME(FDIV_M) INST_NAME(FDIV_M)
INST_NAME(FSQRT_R) INST_NAME(FSQRT_R)
@ -377,7 +373,6 @@ namespace RandomX {
INST_NAME(CFROUND) INST_NAME(CFROUND)
INST_NAME(ISTORE) INST_NAME(ISTORE)
INST_NAME(FSTORE)
INST_NAME(NOP) INST_NAME(NOP)
}; };
@ -397,7 +392,6 @@ namespace RandomX {
INST_HANDLE(ISMULH_R) INST_HANDLE(ISMULH_R)
INST_HANDLE(ISMULH_M) INST_HANDLE(ISMULH_M)
INST_HANDLE(IMUL_RCP) INST_HANDLE(IMUL_RCP)
INST_HANDLE(ISDIV_C)
INST_HANDLE(INEG_R) INST_HANDLE(INEG_R)
INST_HANDLE(IXOR_R) INST_HANDLE(IXOR_R)
INST_HANDLE(IXOR_M) INST_HANDLE(IXOR_M)
@ -417,8 +411,6 @@ namespace RandomX {
//Floating point group E //Floating point group E
INST_HANDLE(FMUL_R) INST_HANDLE(FMUL_R)
INST_HANDLE(FMUL_M)
INST_HANDLE(FDIV_R)
INST_HANDLE(FDIV_M) INST_HANDLE(FDIV_M)
INST_HANDLE(FSQRT_R) INST_HANDLE(FSQRT_R)
@ -428,7 +420,6 @@ namespace RandomX {
INST_HANDLE(CFROUND) INST_HANDLE(CFROUND)
INST_HANDLE(ISTORE) INST_HANDLE(ISTORE)
INST_HANDLE(FSTORE)
INST_HANDLE(NOP) INST_HANDLE(NOP)
}; };

View File

@ -68,7 +68,7 @@ namespace RandomX {
void InterpretedVirtualMachine::initialize() { void InterpretedVirtualMachine::initialize() {
VirtualMachine::initialize(); VirtualMachine::initialize();
for (unsigned i = 0; i < ProgramLength; ++i) { for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
program(i).src %= RegistersCount; program(i).src %= RegistersCount;
program(i).dst %= RegistersCount; program(i).dst %= RegistersCount;
} }
@ -81,7 +81,7 @@ namespace RandomX {
} }
template<> template<>
void InterpretedVirtualMachine::executeBytecode<ProgramLength>(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) { void InterpretedVirtualMachine::executeBytecode<RANDOMX_PROGRAM_SIZE>(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
} }
static void print(int_reg_t r) { static void print(int_reg_t r) {
@ -299,7 +299,7 @@ namespace RandomX {
printState(r, f, e, a); printState(r, f, e, a);
} }
for(unsigned iter = 0; iter < InstructionCount; ++iter) { for(unsigned ic = 0; ic < RANDOMX_PROGRAM_ITERATIONS; ++ic) {
//std::cout << "Iteration " << iter << std::endl; //std::cout << "Iteration " << iter << std::endl;
uint64_t spMix = r[readReg0] ^ r[readReg1]; uint64_t spMix = r[readReg0] ^ r[readReg1];
spAddr0 ^= spMix; spAddr0 ^= spMix;
@ -326,7 +326,7 @@ namespace RandomX {
e[3] = ieee_set_exponent<-240>(load_cvt_i32x2(scratchpad + spAddr1 + 56)); e[3] = ieee_set_exponent<-240>(load_cvt_i32x2(scratchpad + spAddr1 + 56));
if (trace) { if (trace) {
std::cout << "iteration " << std::dec << iter << std::endl; std::cout << "iteration " << std::dec << ic << std::endl;
std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl; std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl;
std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl; std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl;
printState(r, f, e, a); printState(r, f, e, a);
@ -357,7 +357,7 @@ namespace RandomX {
} }
if (trace) { if (trace) {
std::cout << "iteration " << std::dec << iter << std::endl; std::cout << "iteration " << std::dec << ic << std::endl;
std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl; std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl;
std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl; std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl;
printState(r, f, e, a); printState(r, f, e, a);
@ -421,7 +421,7 @@ namespace RandomX {
#include "instructionWeights.hpp" #include "instructionWeights.hpp"
void InterpretedVirtualMachine::precompileProgram(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) { void InterpretedVirtualMachine::precompileProgram(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
for (unsigned i = 0; i < ProgramLength; ++i) { for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
auto& instr = program(i); auto& instr = program(i);
auto& ibc = byteCode[i]; auto& ibc = byteCode[i];
switch (instr.opcode) { switch (instr.opcode) {
@ -593,10 +593,6 @@ namespace RandomX {
} }
} break; } break;
CASE_REP(ISDIV_C) {
ibc.type = InstructionType::NOP;
} break;
CASE_REP(INEG_R) { CASE_REP(INEG_R) {
auto dst = instr.dst % RegistersCount; auto dst = instr.dst % RegistersCount;
ibc.type = InstructionType::INEG_R; ibc.type = InstructionType::INEG_R;
@ -731,12 +727,6 @@ namespace RandomX {
ibc.fsrc = &a[src]; ibc.fsrc = &a[src];
} break; } break;
CASE_REP(FMUL_M) {
} break;
CASE_REP(FDIV_R) {
} break;
CASE_REP(FDIV_M) { CASE_REP(FDIV_M) {
auto dst = instr.dst % 4; auto dst = instr.dst % 4;
auto src = instr.src % 8; auto src = instr.src % 8;
@ -789,9 +779,6 @@ namespace RandomX {
ibc.memMask = ((instr.mod % 4) ? ScratchpadL1Mask : ScratchpadL2Mask); ibc.memMask = ((instr.mod % 4) ? ScratchpadL1Mask : ScratchpadL2Mask);
} break; } break;
CASE_REP(FSTORE) {
} break;
CASE_REP(NOP) { CASE_REP(NOP) {
ibc.type = InstructionType::NOP; ibc.type = InstructionType::NOP;
} break; } break;

View File

@ -79,7 +79,7 @@ namespace RandomX {
static InstructionHandler engine[256]; static InstructionHandler engine[256];
DatasetReadFunc readDataset; DatasetReadFunc readDataset;
bool softAes, asyncWorker; bool softAes, asyncWorker;
InstructionByteCode byteCode[ProgramLength]; InstructionByteCode byteCode[RANDOMX_PROGRAM_SIZE];
#ifdef STATS #ifdef STATS
int count_ADD_64 = 0; int count_ADD_64 = 0;

View File

@ -195,7 +195,7 @@ namespace RandomX {
emitByte(0xc0 + readReg1); emitByte(0xc0 + readReg1);
memcpy(code + codePos, codeLoopLoad, loopLoadSize); memcpy(code + codePos, codeLoopLoad, loopLoadSize);
codePos += loopLoadSize; codePos += loopLoadSize;
for (unsigned i = 0; i < ProgramLength; ++i) { for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
Instruction& instr = prog(i); Instruction& instr = prog(i);
instr.src %= RegistersCount; instr.src %= RegistersCount;
instr.dst %= RegistersCount; instr.dst %= RegistersCount;
@ -658,7 +658,6 @@ namespace RandomX {
INST_HANDLE(ISMULH_R) INST_HANDLE(ISMULH_R)
INST_HANDLE(ISMULH_M) INST_HANDLE(ISMULH_M)
INST_HANDLE(IMUL_RCP) INST_HANDLE(IMUL_RCP)
INST_HANDLE(ISDIV_C)
INST_HANDLE(INEG_R) INST_HANDLE(INEG_R)
INST_HANDLE(IXOR_R) INST_HANDLE(IXOR_R)
INST_HANDLE(IXOR_M) INST_HANDLE(IXOR_M)
@ -672,15 +671,12 @@ namespace RandomX {
INST_HANDLE(FSUB_M) INST_HANDLE(FSUB_M)
INST_HANDLE(FSCAL_R) INST_HANDLE(FSCAL_R)
INST_HANDLE(FMUL_R) INST_HANDLE(FMUL_R)
INST_HANDLE(FMUL_M)
INST_HANDLE(FDIV_R)
INST_HANDLE(FDIV_M) INST_HANDLE(FDIV_M)
INST_HANDLE(FSQRT_R) INST_HANDLE(FSQRT_R)
INST_HANDLE(COND_R) INST_HANDLE(COND_R)
INST_HANDLE(COND_M) INST_HANDLE(COND_M)
INST_HANDLE(CFROUND) INST_HANDLE(CFROUND)
INST_HANDLE(ISTORE) INST_HANDLE(ISTORE)
INST_HANDLE(FSTORE)
INST_HANDLE(NOP) INST_HANDLE(NOP)
}; };

View File

@ -22,7 +22,7 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
namespace RandomX { namespace RandomX {
void Program::print(std::ostream& os) const { void Program::print(std::ostream& os) const {
for (int i = 0; i < RandomX::ProgramLength; ++i) { for (int i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
auto instr = programBuffer[i]; auto instr = programBuffer[i];
os << instr; os << instr;
} }

View File

@ -41,7 +41,7 @@ namespace RandomX {
private: private:
void print(std::ostream&) const; void print(std::ostream&) const;
uint64_t entropyBuffer[16]; uint64_t entropyBuffer[16];
Instruction programBuffer[ProgramLength]; Instruction programBuffer[RANDOMX_PROGRAM_SIZE];
}; };
static_assert(sizeof(Program) % 64 == 0, "Invalid size of class Program"); static_assert(sizeof(Program) % 64 == 0, "Invalid size of class Program");

View File

@ -22,30 +22,43 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include "blake2/endian.h" #include "blake2/endian.h"
#include "configuration.h"
namespace RandomX { namespace RandomX {
static_assert((RANDOMX_ARGON_MEMORY & (RANDOMX_ARGON_MEMORY - 1)) == 0, "RANDOMX_ARGON_MEMORY must be a power of 2.");
static_assert((RANDOMX_DATASET_SIZE & (RANDOMX_DATASET_SIZE - 1)) == 0, "RANDOMX_DATASET_SIZE must be a power of 2.");
static_assert(RANDOMX_DATASET_SIZE <= 4294967296ULL, "RANDOMX_DATASET_SIZE must not exceed 4294967296.");
static_assert(RANDOMX_DS_GROWTH_RATE % 64 == 0, "RANDOMX_DS_GROWTH_RATE must be divisible by 64.");
static_assert(RANDOMX_PROGRAM_SIZE > 0, "RANDOMX_PROGRAM_SIZE must be greater than 0");
static_assert(RANDOMX_PROGRAM_ITERATIONS > 0, "RANDOMX_PROGRAM_ITERATIONS must be greater than 0");
static_assert(RANDOMX_PROGRAM_COUNT > 0, "RANDOMX_PROGRAM_COUNT must be greater than 0");
static_assert((RANDOMX_SCRATCHPAD_L3 & (RANDOMX_SCRATCHPAD_L3 - 1)) == 0, "RANDOMX_SCRATCHPAD_L3 must be a power of 2.");
static_assert(RANDOMX_SCRATCHPAD_L3 >= RANDOMX_SCRATCHPAD_L2, "RANDOMX_SCRATCHPAD_L3 must be greater than or equal to RANDOMX_SCRATCHPAD_L2.");
static_assert((RANDOMX_SCRATCHPAD_L2 & (RANDOMX_SCRATCHPAD_L2 - 1)) == 0, "RANDOMX_SCRATCHPAD_L2 must be a power of 2.");
static_assert(RANDOMX_SCRATCHPAD_L2 >= RANDOMX_SCRATCHPAD_L1, "RANDOMX_SCRATCHPAD_L2 must be greater than or equal to RANDOMX_SCRATCHPAD_L1.");
static_assert((RANDOMX_SCRATCHPAD_L1 & (RANDOMX_SCRATCHPAD_L1 - 1)) == 0, "RANDOMX_SCRATCHPAD_L1 must be a power of 2.");
static_assert(RANDOMX_CACHE_ACCESSES > 1, "RANDOMX_CACHE_ACCESSES must be greater than 1");
constexpr int wtSum = RANDOMX_FREQ_IADD_R + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_IADD_RC + RANDOMX_FREQ_ISUB_R + \
RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_9C + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + \
RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M + RANDOMX_FREQ_IMUL_RCP + \
RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_ISWAP_R + \
RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + \
RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R + RANDOMX_FREQ_COND_R + \
RANDOMX_FREQ_COND_M + RANDOMX_FREQ_CFROUND + RANDOMX_FREQ_ISTORE + RANDOMX_FREQ_NOP;
static_assert(wtSum == 256, "Sum of instruction frequencies must be 256.");
using addr_t = uint32_t; using addr_t = uint32_t;
constexpr int SeedSize = 32; constexpr int SeedSize = 32;
constexpr int ResultSize = 64; constexpr int ResultSize = 64;
constexpr int ArgonSaltSize = sizeof(RANDOMX_ARGON_SALT) - 1;
constexpr int ArgonIterations = 3;
constexpr uint32_t ArgonMemorySize = 262144; //KiB
constexpr int ArgonLanes = 1;
const char ArgonSalt[] = "Monero\x1A$";
constexpr int ArgonSaltSize = sizeof(ArgonSalt) - 1;
constexpr int CacheLineSize = 64; constexpr int CacheLineSize = 64;
constexpr uint32_t CacheLineAlignMask = (RANDOMX_DATASET_SIZE - 1) & ~(CacheLineSize - 1);
constexpr uint64_t DatasetSize = 4ULL * 1024 * 1024 * 1024; //4 GiB constexpr uint32_t CacheSize = RANDOMX_ARGON_MEMORY * 1024;
constexpr uint32_t CacheLineAlignMask = (DatasetSize - 1) & ~(CacheLineSize - 1);
constexpr uint32_t CacheSize = ArgonMemorySize * 1024;
constexpr int CacheBlockCount = CacheSize / CacheLineSize; constexpr int CacheBlockCount = CacheSize / CacheLineSize;
constexpr int DatasetExpansionRatio = DatasetSize / CacheSize;
constexpr int DatasetBlockCount = DatasetExpansionRatio * CacheBlockCount;
constexpr int DatasetIterations = DatasetExpansionRatio;
#ifdef TRACE #ifdef TRACE
constexpr bool trace = true; constexpr bool trace = true;
@ -70,29 +83,19 @@ namespace RandomX {
double hi; double hi;
}; };
constexpr int ProgramLength = 256; constexpr uint32_t ScratchpadL1 = RANDOMX_SCRATCHPAD_L1 / sizeof(int_reg_t);
constexpr uint32_t InstructionCount = 2048; constexpr uint32_t ScratchpadL2 = RANDOMX_SCRATCHPAD_L2 / sizeof(int_reg_t);
constexpr int ChainLength = 8; constexpr uint32_t ScratchpadL3 = RANDOMX_SCRATCHPAD_L3 / sizeof(int_reg_t);
constexpr uint32_t ScratchpadSize = 2 * 1024 * 1024;
constexpr uint32_t ScratchpadLength = ScratchpadSize / sizeof(int_reg_t);
constexpr uint32_t ScratchpadL1 = ScratchpadSize / 128 / sizeof(int_reg_t);
constexpr uint32_t ScratchpadL2 = ScratchpadSize / 8 / sizeof(int_reg_t);
constexpr uint32_t ScratchpadL3 = ScratchpadSize / sizeof(int_reg_t);
constexpr int ScratchpadL1Mask = (ScratchpadL1 - 1) * 8; constexpr int ScratchpadL1Mask = (ScratchpadL1 - 1) * 8;
constexpr int ScratchpadL2Mask = (ScratchpadL2 - 1) * 8; constexpr int ScratchpadL2Mask = (ScratchpadL2 - 1) * 8;
constexpr int ScratchpadL1Mask16 = (ScratchpadL1 / 2 - 1) * 16; constexpr int ScratchpadL1Mask16 = (ScratchpadL1 / 2 - 1) * 16;
constexpr int ScratchpadL2Mask16 = (ScratchpadL2 / 2 - 1) * 16; constexpr int ScratchpadL2Mask16 = (ScratchpadL2 / 2 - 1) * 16;
constexpr int ScratchpadL3Mask = (ScratchpadLength - 1) * 8; constexpr int ScratchpadL3Mask = (ScratchpadL3 - 1) * 8;
constexpr int ScratchpadL3Mask64 = (ScratchpadLength / 8 - 1) * 64; constexpr int ScratchpadL3Mask64 = (ScratchpadL3 / 8 - 1) * 64;
constexpr uint32_t TransformationCount = 90;
constexpr int RegistersCount = 8; constexpr int RegistersCount = 8;
class Cache; class Cache;
inline int wrapInstr(int i) {
return i % RandomX::ProgramLength;
}
class ILightClientAsyncWorker { class ILightClientAsyncWorker {
public: public:
virtual ~ILightClientAsyncWorker() {} virtual ~ILightClientAsyncWorker() {}
@ -120,8 +123,6 @@ namespace RandomX {
dataset_t ds; dataset_t ds;
}; };
static_assert(sizeof(MemoryRegisters) == 2 * sizeof(addr_t) + sizeof(uintptr_t), "Invalid alignment of struct RandomX::MemoryRegisters");
struct RegisterFile { struct RegisterFile {
int_reg_t r[RegistersCount]; int_reg_t r[RegistersCount];
fpu_reg_t f[RegistersCount / 2]; fpu_reg_t f[RegistersCount / 2];
@ -129,15 +130,9 @@ namespace RandomX {
fpu_reg_t a[RegistersCount / 2]; fpu_reg_t a[RegistersCount / 2];
}; };
static_assert(sizeof(RegisterFile) == 256, "Invalid alignment of struct RandomX::RegisterFile");
typedef void(*DatasetReadFunc)(addr_t, MemoryRegisters&, int_reg_t(&reg)[RegistersCount]); typedef void(*DatasetReadFunc)(addr_t, MemoryRegisters&, int_reg_t(&reg)[RegistersCount]);
typedef void(*ProgramFunc)(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t); typedef void(*ProgramFunc)(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t);
extern "C" {
void executeProgram(RegisterFile&, MemoryRegisters&, uint8_t* /* scratchpad */, uint64_t);
}
} }
std::ostream& operator<<(std::ostream& os, const RandomX::RegisterFile& rf); std::ostream& operator<<(std::ostream& os, const RandomX::RegisterFile& rf);

101
src/configuration.h Normal file
View File

@ -0,0 +1,101 @@
/*
Copyright (c) 2019 tevador
This file is part of RandomX.
RandomX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
RandomX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
*/
#pragma once
//Cache size in KiB. Must be a power of 2.
#define RANDOMX_ARGON_MEMORY (256 * 1024)
//Number of Argon2d iterations for Cache initialization
#define RANDOMX_ARGON_ITERATIONS 3
//Number of parallel lanes for Cache initialization
#define RANDOMX_ARGON_LANES 1
//Argon2d salt
#define RANDOMX_ARGON_SALT "RandomX\x03"
//Number of random Cache accesses per Dataset block. Minimum is 2.
#define RANDOMX_CACHE_ACCESSES 16
//Dataset size in bytes. Must be a power of 2.
#define RANDOMX_DATASET_SIZE (4ULL * 1024 * 1024 * 1024)
//Dataset growth per epoch in bytes. Must be divisible by 64.
#define RANDOMX_DS_GROWTH_RATE (2 * 1024 * 1024)
//Number of instructions in a RandomX program
#define RANDOMX_PROGRAM_SIZE 256
//Number of iterations during VM execution
#define RANDOMX_PROGRAM_ITERATIONS 2048
//Number of chained VM executions per hash
#define RANDOMX_PROGRAM_COUNT 8
//Scratchpad L3 size in bytes. Must be a power of 2.
#define RANDOMX_SCRATCHPAD_L3 (2 * 1024 * 1024)
//Scratchpad L2 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L3.
#define RANDOMX_SCRATCHPAD_L2 (256 * 1024)
//Scratchpad L1 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L2.
#define RANDOMX_SCRATCHPAD_L1 (16 * 1024)
/*
Instruction frequencies (per 256 opcodes)
Total sum of frequencies must be 256
*/
#define RANDOMX_FREQ_IADD_R 12
#define RANDOMX_FREQ_IADD_M 7
#define RANDOMX_FREQ_IADD_RC 16
#define RANDOMX_FREQ_ISUB_R 12
#define RANDOMX_FREQ_ISUB_M 7
#define RANDOMX_FREQ_IMUL_9C 9
#define RANDOMX_FREQ_IMUL_R 16
#define RANDOMX_FREQ_IMUL_M 4
#define RANDOMX_FREQ_IMULH_R 4
#define RANDOMX_FREQ_IMULH_M 1
#define RANDOMX_FREQ_ISMULH_R 4
#define RANDOMX_FREQ_ISMULH_M 1
#define RANDOMX_FREQ_IMUL_RCP 8
#define RANDOMX_FREQ_INEG_R 2
#define RANDOMX_FREQ_IXOR_R 16
#define RANDOMX_FREQ_IXOR_M 4
#define RANDOMX_FREQ_IROR_R 10
#define RANDOMX_FREQ_IROL_R 0
#define RANDOMX_FREQ_ISWAP_R 4
#define RANDOMX_FREQ_FSWAP_R 8
#define RANDOMX_FREQ_FADD_R 20
#define RANDOMX_FREQ_FADD_M 5
#define RANDOMX_FREQ_FSUB_R 20
#define RANDOMX_FREQ_FSUB_M 5
#define RANDOMX_FREQ_FSCAL_R 6
#define RANDOMX_FREQ_FMUL_R 20
#define RANDOMX_FREQ_FDIV_M 4
#define RANDOMX_FREQ_FSQRT_R 6
#define RANDOMX_FREQ_COND_R 7
#define RANDOMX_FREQ_COND_M 1
#define RANDOMX_FREQ_CFROUND 1
#define RANDOMX_FREQ_ISTORE 16
#define RANDOMX_FREQ_NOP 0

View File

@ -47,7 +47,7 @@ namespace RandomX {
constexpr uint32_t mask = (CacheSize - 1) & CacheLineAlignMask; constexpr uint32_t mask = (CacheSize - 1) & CacheLineAlignMask;
for (auto i = 0; i < DatasetIterations; ++i) { for (auto i = 0; i < RANDOMX_CACHE_ACCESSES; ++i) {
const uint8_t* mixBlock = cache + (c0 & mask); const uint8_t* mixBlock = cache + (c0 & mask);
PREFETCHNTA(mixBlock); PREFETCHNTA(mixBlock);
c0 = squareHash(c0); c0 = squareHash(c0);
@ -103,14 +103,14 @@ namespace RandomX {
aw->prepareBlock(memory.ma); aw->prepareBlock(memory.ma);
} }
void datasetAlloc(dataset_t& ds, bool largePages) { void datasetAlloc(dataset_t& ds, uint64_t size, bool largePages) {
if (sizeof(size_t) <= 4) if (sizeof(size_t) <= 4)
throw std::runtime_error("Platform doesn't support enough memory for the dataset"); throw std::runtime_error("Platform doesn't support enough memory for the dataset");
if (largePages) { if (largePages) {
ds.dataset = (uint8_t*)allocLargePagesMemory(DatasetSize); ds.dataset = (uint8_t*)allocLargePagesMemory(size);
} }
else { else {
ds.dataset = (uint8_t*)_mm_malloc(DatasetSize, 64); ds.dataset = (uint8_t*)_mm_malloc(size, 64);
if (ds.dataset == nullptr) { if (ds.dataset == nullptr) {
throw std::runtime_error("Dataset memory allocation failed. >4 GiB of free virtual memory is needed."); throw std::runtime_error("Dataset memory allocation failed. >4 GiB of free virtual memory is needed.");
} }

View File

@ -30,7 +30,7 @@ namespace RandomX {
void initBlock(const uint8_t* cache, uint8_t* block, uint32_t blockNumber); void initBlock(const uint8_t* cache, uint8_t* block, uint32_t blockNumber);
void datasetAlloc(dataset_t& ds, bool largePages); void datasetAlloc(dataset_t& ds, uint64_t size, bool largePages);
void datasetInit(Cache* cache, dataset_t ds, uint32_t startBlock, uint32_t blockCount); void datasetInit(Cache* cache, dataset_t ds, uint32_t startBlock, uint32_t blockCount);

View File

@ -19,67 +19,6 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
#pragma once #pragma once
//Integer
#define WT_IADD_R 12
#define WT_IADD_M 7
#define WT_IADD_RC 16
#define WT_ISUB_R 12
#define WT_ISUB_M 7
#define WT_IMUL_9C 9
#define WT_IMUL_R 16
#define WT_IMUL_M 4
#define WT_IMULH_R 4
#define WT_IMULH_M 1
#define WT_ISMULH_R 4
#define WT_ISMULH_M 1
#define WT_IMUL_RCP 8
#define WT_ISDIV_C 0
#define WT_INEG_R 2
#define WT_IXOR_R 16
#define WT_IXOR_M 4
#define WT_IROR_R 10
#define WT_IROL_R 0
#define WT_ISWAP_R 4
//Common floating point
#define WT_FSWAP_R 8
//Floating point group F
#define WT_FADD_R 20
#define WT_FADD_M 5
#define WT_FSUB_R 20
#define WT_FSUB_M 5
#define WT_FSCAL_R 6
//Floating point group E
#define WT_FMUL_R 20
#define WT_FMUL_M 0
#define WT_FDIV_R 0
#define WT_FDIV_M 4
#define WT_FSQRT_R 6
//Control
#define WT_COND_R 7
#define WT_COND_M 1
#define WT_CFROUND 1
//Store
#define WT_ISTORE 16
#define WT_FSTORE 0
#define WT_NOP 0
constexpr int wtSum = WT_IADD_R + WT_IADD_M + WT_IADD_RC + WT_ISUB_R + \
WT_ISUB_M + WT_IMUL_9C + WT_IMUL_R + WT_IMUL_M + WT_IMULH_R + \
WT_IMULH_M + WT_ISMULH_R + WT_ISMULH_M + WT_IMUL_RCP + WT_ISDIV_C + \
WT_INEG_R + WT_IXOR_R + WT_IXOR_M + WT_IROR_R + WT_IROL_R + \
WT_ISWAP_R + WT_FSWAP_R + WT_FADD_R + WT_FADD_M + WT_FSUB_R + WT_FSUB_M + \
WT_FSCAL_R + WT_FMUL_R + WT_FMUL_M + WT_FDIV_R + WT_FDIV_M + \
WT_FSQRT_R + WT_COND_R + WT_COND_M + WT_CFROUND + WT_ISTORE + WT_FSTORE + WT_NOP;
static_assert(wtSum == 256,
"Sum of instruction weights must be 256");
#define REP0(x) #define REP0(x)
#define REP1(x) x, #define REP1(x) x,
#define REP2(x) REP1(x) x, #define REP2(x) REP1(x) x,
@ -121,7 +60,7 @@ static_assert(wtSum == 256,
#define REPNX(x,N) REP##N(x) #define REPNX(x,N) REP##N(x)
#define REPN(x,N) REPNX(x,N) #define REPN(x,N) REPNX(x,N)
#define NUM(x) x #define NUM(x) x
#define WT(x) NUM(WT_##x) #define WT(x) NUM(RANDOMX_FREQ_##x)
#define REPCASE0(x) #define REPCASE0(x)
#define REPCASE1(x) case __COUNTER__: #define REPCASE1(x) case __COUNTER__:

View File

@ -132,8 +132,8 @@ void generateAsm(uint32_t nonce) {
memcpy(blockTemplate, blockTemplate__, sizeof(blockTemplate)); memcpy(blockTemplate, blockTemplate__, sizeof(blockTemplate));
store32(blockTemplate + 39, nonce); store32(blockTemplate + 39, nonce);
blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0); blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0);
uint8_t scratchpad[RandomX::ScratchpadSize]; uint8_t scratchpad[RANDOMX_SCRATCHPAD_L3];
fillAes1Rx4<softAes>((void*)hash, RandomX::ScratchpadSize, scratchpad); fillAes1Rx4<softAes>((void*)hash, RANDOMX_SCRATCHPAD_L3, scratchpad);
RandomX::AssemblyGeneratorX86 asmX86; RandomX::AssemblyGeneratorX86 asmX86;
RandomX::Program p; RandomX::Program p;
fillAes1Rx4<softAes>(hash, sizeof(p), &p); fillAes1Rx4<softAes>(hash, sizeof(p), &p);
@ -148,11 +148,11 @@ void generateNative(uint32_t nonce) {
memcpy(blockTemplate, blockTemplate__, sizeof(blockTemplate)); memcpy(blockTemplate, blockTemplate__, sizeof(blockTemplate));
store32(blockTemplate + 39, nonce); store32(blockTemplate + 39, nonce);
blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0); blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0);
uint8_t scratchpad[RandomX::ScratchpadSize]; uint8_t scratchpad[RANDOMX_SCRATCHPAD_L3];
fillAes1Rx4<softAes>((void*)hash, RandomX::ScratchpadSize, scratchpad); fillAes1Rx4<softAes>((void*)hash, RANDOMX_SCRATCHPAD_L3, scratchpad);
alignas(16) RandomX::Program prog; alignas(16) RandomX::Program prog;
fillAes1Rx4<softAes>((void*)hash, sizeof(prog), &prog); fillAes1Rx4<softAes>((void*)hash, sizeof(prog), &prog);
for (int i = 0; i < RandomX::ProgramLength; ++i) { for (int i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
prog(i).dst %= 8; prog(i).dst %= 8;
prog(i).src %= 8; prog(i).src %= 8;
} }
@ -171,11 +171,11 @@ void mine(RandomX::VirtualMachine* vm, std::atomic<uint32_t>& atomicNonce, Atomi
//std::cout << "Thread " << thread << " nonce " << nonce << std::endl; //std::cout << "Thread " << thread << " nonce " << nonce << std::endl;
store32(noncePtr, nonce); store32(noncePtr, nonce);
blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0); blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0);
fillAes1Rx4<softAes>((void*)hash, RandomX::ScratchpadSize, scratchpad); fillAes1Rx4<softAes>((void*)hash, RANDOMX_SCRATCHPAD_L3, scratchpad);
vm->resetRoundingMode(); vm->resetRoundingMode();
vm->setScratchpad(scratchpad); vm->setScratchpad(scratchpad);
//dump((char*)scratchpad, RandomX::ScratchpadSize, "spad-before.txt"); //dump((char*)scratchpad, RandomX::ScratchpadSize, "spad-before.txt");
for (int chain = 0; chain < RandomX::ChainLength - 1; ++chain) { for (int chain = 0; chain < RANDOMX_PROGRAM_COUNT - 1; ++chain) {
fillAes1Rx4<softAes>((void*)hash, sizeof(RandomX::Program), vm->getProgramBuffer()); fillAes1Rx4<softAes>((void*)hash, sizeof(RandomX::Program), vm->getProgramBuffer());
vm->initialize(); vm->initialize();
vm->execute(); vm->execute();
@ -190,7 +190,7 @@ void mine(RandomX::VirtualMachine* vm, std::atomic<uint32_t>& atomicNonce, Atomi
std::cout << std::hex << std::setw(16) << std::setfill('0') << res << std::endl; std::cout << std::hex << std::setw(16) << std::setfill('0') << res << std::endl;
} }
}*/ }*/
vm->getResult<softAes>(scratchpad, RandomX::ScratchpadSize, hash); vm->getResult<softAes>(scratchpad, RANDOMX_SCRATCHPAD_L3, hash);
result.xorWith(hash); result.xorWith(hash);
if (RandomX::trace) { if (RandomX::trace) {
std::cout << "Nonce: " << nonce << " "; std::cout << "Nonce: " << nonce << " ";
@ -267,10 +267,11 @@ int main(int argc, char** argv) {
} }
else { else {
RandomX::Cache* cache = dataset.cache; RandomX::Cache* cache = dataset.cache;
RandomX::datasetAlloc(dataset, largePages); RandomX::datasetAlloc(dataset, RANDOMX_DATASET_SIZE, largePages);
const uint64_t datasetBlockCount = RANDOMX_DATASET_SIZE / RandomX::CacheLineSize;
if (initThreadCount > 1) { if (initThreadCount > 1) {
auto perThread = RandomX::DatasetBlockCount / initThreadCount; auto perThread = datasetBlockCount / initThreadCount;
auto remainder = RandomX::DatasetBlockCount % initThreadCount; auto remainder = datasetBlockCount % initThreadCount;
for (int i = 0; i < initThreadCount; ++i) { for (int i = 0; i < initThreadCount; ++i) {
auto count = perThread + (i == initThreadCount - 1 ? remainder : 0); auto count = perThread + (i == initThreadCount - 1 ? remainder : 0);
threads.push_back(std::thread(&RandomX::datasetInit, cache, dataset, i * perThread, count)); threads.push_back(std::thread(&RandomX::datasetInit, cache, dataset, i * perThread, count));
@ -280,7 +281,7 @@ int main(int argc, char** argv) {
} }
} }
else { else {
RandomX::datasetInit(cache, dataset, 0, RandomX::DatasetBlockCount); RandomX::datasetInit(cache, dataset, 0, datasetBlockCount);
} }
RandomX::Cache::dealloc(cache, largePages); RandomX::Cache::dealloc(cache, largePages);
threads.clear(); threads.clear();
@ -300,19 +301,19 @@ int main(int argc, char** argv) {
} }
uint8_t* scratchpadMem; uint8_t* scratchpadMem;
if (largePages) { if (largePages) {
scratchpadMem = (uint8_t*)allocLargePagesMemory(threadCount * RandomX::ScratchpadSize); scratchpadMem = (uint8_t*)allocLargePagesMemory(threadCount * RANDOMX_SCRATCHPAD_L3);
} }
else { else {
scratchpadMem = (uint8_t*)_mm_malloc(threadCount * RandomX::ScratchpadSize, RandomX::CacheLineSize); scratchpadMem = (uint8_t*)_mm_malloc(threadCount * RANDOMX_SCRATCHPAD_L3, RandomX::CacheLineSize);
} }
std::cout << "Running benchmark (" << programCount << " nonces) ..." << std::endl; std::cout << "Running benchmark (" << programCount << " nonces) ..." << std::endl;
sw.restart(); sw.restart();
if (threadCount > 1) { if (threadCount > 1) {
for (unsigned i = 0; i < vms.size(); ++i) { for (unsigned i = 0; i < vms.size(); ++i) {
if (softAes) if (softAes)
threads.push_back(std::thread(&mine<true>, vms[i], std::ref(atomicNonce), std::ref(result), programCount, i, scratchpadMem + RandomX::ScratchpadSize * i)); threads.push_back(std::thread(&mine<true>, vms[i], std::ref(atomicNonce), std::ref(result), programCount, i, scratchpadMem + RANDOMX_SCRATCHPAD_L3 * i));
else else
threads.push_back(std::thread(&mine<false>, vms[i], std::ref(atomicNonce), std::ref(result), programCount, i, scratchpadMem + RandomX::ScratchpadSize * i)); threads.push_back(std::thread(&mine<false>, vms[i], std::ref(atomicNonce), std::ref(result), programCount, i, scratchpadMem + RANDOMX_SCRATCHPAD_L3 * i));
} }
for (unsigned i = 0; i < threads.size(); ++i) { for (unsigned i = 0; i < threads.size(); ++i) {
threads[i].join(); threads[i].join();
@ -330,7 +331,7 @@ int main(int argc, char** argv) {
std::cout << "Calculated result: "; std::cout << "Calculated result: ";
result.print(std::cout); result.print(std::cout);
if(programCount == 1000) if(programCount == 1000)
std::cout << "Reference result: e1b4144293ff9ab5aa4c98f2389bb18950d8c3fd874891ac64628e028a286006" << std::endl; std::cout << "Reference result: 128599cc10f9f6251e7917fa1d09ab2116ab4081bf1357149bd4054275dd8ee9" << std::endl;
if (!miningMode) { if (!miningMode) {
std::cout << "Performance: " << 1000 * elapsed / programCount << " ms per hash" << std::endl; std::cout << "Performance: " << 1000 * elapsed / programCount << " ms per hash" << std::endl;
} }