fixed windows dataset not being shared across threads

This commit is contained in:
dan_s
2026-02-21 17:46:23 -06:00
parent 8a0eb77692
commit 59be9a4cc0
3 changed files with 28 additions and 662 deletions

View File

@@ -1180,7 +1180,9 @@ struct RandomXDatasetManager {
// Creates a per-thread VM using the shared dataset.
// Caller must hold a shared lock on datasetMtx.
// The VM itself is small (~2MB scratchpad) - the 2GB dataset is shared via pointer.
// The VM itself is small (~2MB scratchpad + ~84KB JIT code) the ~2GB dataset is shared via pointer.
// VMs should be created ONCE per thread and reused across blocks to avoid
// heap fragmentation on Windows (repeated 2MB alloc/free causes address-space bloat).
randomx_vm *CreateVM() {
static std::atomic<int> vmCount{0};
LogProcessMemory("before CreateVM");
@@ -1188,8 +1190,9 @@ struct RandomXDatasetManager {
if (vm != nullptr) {
int id = ++vmCount;
uint8_t *datasetMemory = (uint8_t*)randomx_get_dataset_memory(dataset);
LogPrintf("RandomXDatasetManager: VM #%d created - VM at %p, shared dataset memory at %p\n",
LogPrintf("RandomXDatasetManager: VM #%d created VM at %p, shared dataset at %p\n",
id, (void*)vm, (void*)datasetMemory);
LogPrintf(" Per-thread overhead: ~2MB scratchpad + ~84KB JIT (dataset NOT copied)\n");
LogProcessMemory("after CreateVM");
}
return vm;
@@ -1343,14 +1346,24 @@ void static RandomXMiner()
rxdebug("%s: updated shared dataset with keyHeight=%d, randomxBlockKey=%s\n", keyHeight, randomxBlockKey.ToString().c_str());
}
// Create a per-thread VM that uses the shared dataset (read-only, thread-safe)
// Create a per-thread VM once and reuse across blocks.
// The VM just stores a pointer to the shared dataset — the pointer
// remains valid across key changes since UpdateKey rebuilds the dataset
// contents in-place without reallocating. Reusing the VM avoids
// repeated 2MB scratchpad + 84KB JIT alloc/free churn that causes
// Windows heap fragmentation and apparent memory growth per thread.
if (myVM == nullptr) {
// First iteration: acquire shared lock briefly to create VM
boost::shared_lock<boost::shared_mutex> initLock(g_rxDatasetManager->datasetMtx);
myVM = g_rxDatasetManager->CreateVM();
if (myVM == nullptr) {
LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n");
return;
}
}
// Acquire shared lock to prevent dataset rebuild while we're hashing
boost::shared_lock<boost::shared_mutex> datasetLock(g_rxDatasetManager->datasetMtx);
myVM = g_rxDatasetManager->CreateVM();
if(myVM == NULL) {
LogPrintf("RandomXMiner: Cannot create RandomX VM, aborting!\n");
return;
}
//fprintf(stderr,"RandomXMiner: Mining_start=%u\n", Mining_start);
#ifdef ENABLE_WALLET
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, pindexPrev->GetHeight()+1, gpucount, 0);
@@ -1576,17 +1589,8 @@ void static RandomXMiner()
pblock->nBits = savebits;
}
rxdebug("%s: going to destroy rx VM\n");
if (myVM != nullptr) {
randomx_destroy_vm(myVM);
myVM = nullptr;
LogPrintf("RandomXMiner: destroyed VM after inner loop\n");
fprintf(stderr, "RandomXMiner: destroyed VM after inner loop\n");
} else {
LogPrintf("RandomXMiner: WARNING myVM already null after inner loop, skipping destroy (would double-free)\n");
fprintf(stderr, "RandomXMiner: WARNING myVM already null after inner loop, skipping destroy (would double-free)\n");
}
// Release shared lock so UpdateKey can acquire exclusive lock for dataset rebuild
// VM is kept alive — its dataset pointer remains valid across rebuilds
datasetLock.unlock();
}