Speed up randomx hashing by ~60X per core
These code changes move various randomx setup code out of the inner mining loop, which significantly increases hashrate. Currently seeing ~60 hashes/second/core on a Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz. This code may have memory leaks, it does not destroy the randomx VM since it was causing coredumps. It also seems to use more memory, I am only able to mine on 2 cores with 16GB of RAM. Using more cores runs out of memory.
This commit is contained in:
108
src/miner.cpp
108
src/miner.cpp
@@ -1131,6 +1131,55 @@ void static RandomXMiner()
|
|||||||
{
|
{
|
||||||
Mining_height = pindexPrev->GetHeight()+1;
|
Mining_height = pindexPrev->GetHeight()+1;
|
||||||
Mining_start = (uint32_t)time(NULL);
|
Mining_start = (uint32_t)time(NULL);
|
||||||
|
}
|
||||||
|
char randomxHash[RANDOMX_HASH_SIZE];
|
||||||
|
rxdebug("%s: created randomxHash of size %d\n", RANDOMX_HASH_SIZE);
|
||||||
|
char randomxKey[82]; // randomx spec says keysize of >60 bytes is implementation-specific
|
||||||
|
// initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy
|
||||||
|
// since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long
|
||||||
|
snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT);
|
||||||
|
|
||||||
|
// With the defaults of 1024 and 64
|
||||||
|
// the key block will change every ~21.3 hours with a 75s block time
|
||||||
|
// and every ~17 hours with the default 60s block time for HSCs
|
||||||
|
int randomxInterval = GetArg("-ac_randomx_interval",1024);
|
||||||
|
// This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs
|
||||||
|
int randomxBlockLag = GetArg("-ac_randomx_lag", 64);
|
||||||
|
|
||||||
|
// fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag);
|
||||||
|
rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height);
|
||||||
|
// Use the initial key at the start of the chain, until the first key block
|
||||||
|
if( (Mining_height) < randomxInterval + randomxBlockLag) {
|
||||||
|
randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey);
|
||||||
|
rxdebug("%s: initialized cache with initial key\n");
|
||||||
|
} else {
|
||||||
|
rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval);
|
||||||
|
// At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing
|
||||||
|
int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval;
|
||||||
|
uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash();
|
||||||
|
|
||||||
|
randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey);
|
||||||
|
rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto datasetItemCount = randomx_dataset_item_count();
|
||||||
|
rxdebug("%s: dataset items=%lu\n", datasetItemCount);
|
||||||
|
//TODO: this is hardcoded to use 2 threads instead of the number of mining threads
|
||||||
|
//std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2);
|
||||||
|
//std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2);
|
||||||
|
//t1.join();
|
||||||
|
//t2.join();
|
||||||
|
|
||||||
|
randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount);
|
||||||
|
rxdebug("%s: dataset initialized\n");
|
||||||
|
// randomx_release_cache(randomxCache);
|
||||||
|
// rxdebug("%s: cache released\n");
|
||||||
|
|
||||||
|
randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset);
|
||||||
|
if(myVM == NULL) {
|
||||||
|
LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
//fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start);
|
//fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start);
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
@@ -1185,6 +1234,7 @@ void static RandomXMiner()
|
|||||||
} else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
} else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",SMART_CHAIN_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rxdebug("%s: incrementing extra nonce\n");
|
||||||
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
||||||
// fprintf(stderr,"RandomXMiner: %u transactions in block\n",(int32_t)pblock->vtx.size());
|
// fprintf(stderr,"RandomXMiner: %u transactions in block\n",(int32_t)pblock->vtx.size());
|
||||||
LogPrintf("Running HushRandomXMiner with %u transactions in block (%u bytes)\n",pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
|
LogPrintf("Running HushRandomXMiner with %u transactions in block (%u bytes)\n",pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
|
||||||
@@ -1213,13 +1263,6 @@ void static RandomXMiner()
|
|||||||
arith_uint256 hashTarget;
|
arith_uint256 hashTarget;
|
||||||
hashTarget = HASHTarget;
|
hashTarget = HASHTarget;
|
||||||
|
|
||||||
char randomxHash[RANDOMX_HASH_SIZE];
|
|
||||||
//fprintf(stderr,"RandomXMiner: created randomxHash of size %d\n", RANDOMX_HASH_SIZE);
|
|
||||||
char randomxKey[82]; // randomx spec says keysize of >60 bytes is implementation-specific
|
|
||||||
// initial randomx key is unique to every Hush Smart Chain, and has at least 9 bytes (2^9=128 bits) of entropy
|
|
||||||
// since magic is 4 bytes, rpc port is 4 bytes and smart chain symbol must be at least 1 character long
|
|
||||||
snprintf(randomxKey, 81, "%08x%s%08x", ASSETCHAINS_MAGIC, SMART_CHAIN_SYMBOL, ASSETCHAINS_RPCPORT);
|
|
||||||
|
|
||||||
CDataStream randomxInput(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream randomxInput(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
// Use the current block as randomx input
|
// Use the current block as randomx input
|
||||||
randomxInput << pblocktemplate->block;
|
randomxInput << pblocktemplate->block;
|
||||||
@@ -1228,50 +1271,7 @@ void static RandomXMiner()
|
|||||||
// fprintf(stderr,"RandomXMiner: created randomxKey=%s , randomxInput.size=%lu\n", randomxKey, randomxInput.size() ); //randomxInput);
|
// fprintf(stderr,"RandomXMiner: created randomxKey=%s , randomxInput.size=%lu\n", randomxKey, randomxInput.size() ); //randomxInput);
|
||||||
rxdebug("%s: randomxKey=%s randomxInput=%s\n", randomxKey, HexStr(randomxInput).c_str());
|
rxdebug("%s: randomxKey=%s randomxInput=%s\n", randomxKey, HexStr(randomxInput).c_str());
|
||||||
|
|
||||||
// With the defaults of 1024 and 64
|
rxdebug("%s: calculating randomx hash\n");
|
||||||
// the key block will change every ~21.3 hours with a 75s block time
|
|
||||||
// and every ~17 hours with the default 60s block time for HSCs
|
|
||||||
int randomxInterval = GetArg("-ac_randomx_interval",1024);
|
|
||||||
// This lag is 80 mins for 75s blocktime and 64 mins for 60s (default) blocktime for HSCs
|
|
||||||
int randomxBlockLag = GetArg("-ac_randomx_lag", 64);
|
|
||||||
|
|
||||||
// fprintf(stderr,"RandomXMiner: using initial key with interval=%d and lag=%d\n", randomxInterval, randomxBlockLag);
|
|
||||||
rxdebug("%s: using initial key, interval=%d, lag=%d, Mining_height=%u\n", randomxInterval, randomxBlockLag, Mining_height);
|
|
||||||
// Use the initial key at the start of the chain, until the first key block
|
|
||||||
if( (Mining_height) < randomxInterval + randomxBlockLag) {
|
|
||||||
randomx_init_cache(randomxCache, &randomxKey, sizeof randomxKey);
|
|
||||||
rxdebug("%s: initialized cache with initial key\n");
|
|
||||||
} else {
|
|
||||||
rxdebug("%s: calculating keyHeight with randomxInterval=%d\n", randomxInterval);
|
|
||||||
// At heights between intervals, we use the same block key and wait randomxBlockLag blocks until changing
|
|
||||||
int keyHeight = ((Mining_height - randomxBlockLag) / randomxInterval) * randomxInterval;
|
|
||||||
uint256 randomxBlockKey = chainActive[keyHeight]->GetBlockHash();
|
|
||||||
|
|
||||||
randomx_init_cache(randomxCache, &randomxBlockKey, sizeof randomxBlockKey);
|
|
||||||
rxdebug("%s: initialized cache with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: this is hardcoded to use 2 threads instead of the number of mining threads
|
|
||||||
//std::thread t1(&randomx_init_dataset, randomxDataset, randomxCache, 0, datasetItemCount / 2);
|
|
||||||
//std::thread t2(&randomx_init_dataset, randomxDataset, randomxCache, datasetItemCount / 2, datasetItemCount - datasetItemCount / 2);
|
|
||||||
//t1.join();
|
|
||||||
//t2.join();
|
|
||||||
auto datasetItemCount = randomx_dataset_item_count();
|
|
||||||
rxdebug("%s: dataset items=%lu\n", datasetItemCount);
|
|
||||||
|
|
||||||
randomx_init_dataset(randomxDataset, randomxCache, 0, datasetItemCount);
|
|
||||||
rxdebug("%s: dataset initialized\n");
|
|
||||||
// randomx_release_cache(randomxCache);
|
|
||||||
// rxdebug("%s: cache released\n");
|
|
||||||
|
|
||||||
randomx_vm *myVM = randomx_create_vm(flags, nullptr, randomxDataset);
|
|
||||||
if(myVM == NULL) {
|
|
||||||
LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
randomx_calculate_hash(myVM, &randomxInput, sizeof randomxInput, randomxHash);
|
randomx_calculate_hash(myVM, &randomxInput, sizeof randomxInput, randomxHash);
|
||||||
rxdebug("%s: calculated randomx hash\n");
|
rxdebug("%s: calculated randomx hash\n");
|
||||||
|
|
||||||
@@ -1283,11 +1283,11 @@ void static RandomXMiner()
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
randomx_destroy_vm(myVM);
|
|
||||||
rxdebug("%s: destroyed VM\n");
|
//randomx_destroy_vm(myVM);
|
||||||
|
//rxdebug("%s: destroyed VM\n");
|
||||||
|
|
||||||
// Use randomx hash to build a valid block
|
// Use randomx hash to build a valid block
|
||||||
|
|
||||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
|
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
|
||||||
|
|||||||
Reference in New Issue
Block a user