Skip to content

Commit 2270c94

Browse files
committed
[Mining] Reduce lock contention with SHA256D
Increases the number of hashes a SHA256D miner thread attempts per created block template, and adds a separate counter to allow an early continuation when the chain tip changes. The SHA256D algorithm is fast enough that the main miner loop runs multiple times per second with the previous loop count. In each loop, a thread generates a new block template, which requires grabbing cs_main a couple times. I found this to be a significant source of contention, often causing both SHA mining and wallet syncing to stop. In contrast, a RandomX miner thread runs its main loop on the order of minutes, with a lower loop count, and checks on every hash attempt whether the tip has changed, resulting in approximately one block template created per block. I chose nMidLoopCount to approximately match the RandomX timing, while nInnerLoopCount is still fast enough to be used as an intermittent sub-second check of the chain height.
1 parent 1e2b060 commit 2270c94

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

src/miner.cpp

+28-8
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,13 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
973973
IncrementExtraNonce(pblock, chainActive.Height(), nExtraNonce);
974974

975975
int nTries = 0;
976+
bool success = false;
977+
// As SHA runs much faster than the other algorithms, run more of them in this section
978+
// to avoid lock contention from creating block templates. Use a separate counter
979+
// nMidLoopCount to keep track of this, so that we can check every nInnerLoopCount hashes
980+
// if the block is done.
981+
int nMidTries = 0;
982+
static const int nMidLoopCount = 0x1000;
976983
if (pblock->IsProgPow() && pblock->nTime >= Params().PowUpdateTimestamp()) {
977984
uint256 mix_hash;
978985
while (nTries < nInnerLoopCount &&
@@ -983,14 +990,25 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
983990
++pblock->nNonce64;
984991
}
985992
pblock->mixHash = mix_hash;
993+
success = nTries != nInnerLoopCount;
986994
} else if (pblock->IsSha256D() && pblock->nTime >= Params().PowUpdateTimestamp()) {
987995
uint256 midStateHash = pblock->GetSha256dMidstate();
988-
while (nTries < nInnerLoopCount &&
989-
!CheckProofOfWork(pblock->GetSha256D(midStateHash), pblock->nBits,
990-
Params().GetConsensus(), CBlockHeader::SHA256D_BLOCK)) {
991-
boost::this_thread::interruption_point();
992-
++nTries;
993-
++pblock->nNonce64;
996+
// Exit loop when nMidLoopCount loops are done, or when a new block is found.
997+
// Either way, success will be false.
998+
while (nMidTries < nMidLoopCount && chainActive.Height() < pblock->nHeight) {
999+
while (nTries < nInnerLoopCount &&
1000+
!CheckProofOfWork(pblock->GetSha256D(midStateHash), pblock->nBits,
1001+
Params().GetConsensus(), CBlockHeader::SHA256D_BLOCK)) {
1002+
boost::this_thread::interruption_point();
1003+
++nTries;
1004+
++pblock->nNonce64;
1005+
}
1006+
if (nTries != nInnerLoopCount) {
1007+
success = true;
1008+
break;
1009+
}
1010+
++nMidTries;
1011+
nTries = 0;
9941012
}
9951013
} else if (pblock->nTime < Params().PowUpdateTimestamp()) {
9961014
while (nTries < nInnerLoopCount &&
@@ -999,6 +1017,7 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
9991017
++nTries;
10001018
++pblock->nNonce;
10011019
}
1020+
success = nTries != nInnerLoopCount;
10021021
} else {
10031022
LogPrintf("%s: Unknown hashing algorithm found!\n", __func__);
10041023
return;
@@ -1007,14 +1026,14 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
10071026
double nHashSpeed = 0;
10081027
{
10091028
LOCK(cs_nonce);
1010-
nHashes += nTries;
1029+
nHashes += nTries + (nMidTries * nInnerLoopCount);
10111030
nTimeDuration = GetTime() - nTimeStart;
10121031
if (!nTimeDuration) nTimeDuration = 1;
10131032
nHashSpeed = arith_uint256(nHashes/1000/nTimeDuration).getdouble();
10141033
}
10151034

10161035
LogPrint(BCLog::MINING, "%s: PoW Hashspeed %d kh/s\n", __func__, nHashSpeed);
1017-
if (nTries == nInnerLoopCount) {
1036+
if (!success) {
10181037
continue;
10191038
}
10201039
}
@@ -1024,6 +1043,7 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
10241043
LogPrint(BCLog::MINING, "%s: Failed to process new block\n", __func__);
10251044
continue;
10261045
}
1046+
LogPrint(BCLog::MINING, "%s: Found block\n", __func__);
10271047

10281048
if (!fProofOfStake)
10291049
coinbaseScript->KeepScript();

0 commit comments

Comments
 (0)