Skip to content

Commit 8914ca5

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 1e03461 commit 8914ca5

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

src/miner.cpp

+30-8
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,7 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
869869
enablewallet = !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
870870
#endif
871871

872+
bool fBlockFoundAlready = false;
872873
while (!ShutdownRequested() && (GenerateActive() || (fProofOfStake && enablewallet)))
873874
{
874875
boost::this_thread::interruption_point();
@@ -984,6 +985,12 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
984985
}
985986

986987
int nTries = 0;
988+
// As SHA runs much faster than the other algorithms, run more of them in this section
989+
// to avoid lock contention from creating block templates. Use a separate counter
990+
// nMidLoopCount to keep track of this, so that we can check every nInnerLoopCount hashes
991+
// if the block is done.
992+
int nMidTries = 0;
993+
static const int nMidLoopCount = 0x1000;
987994
if (pblock->IsProgPow() && pblock->nTime >= Params().PowUpdateTimestamp()) {
988995
uint256 mix_hash;
989996
while (nTries < nInnerLoopCount &&
@@ -996,12 +1003,24 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
9961003
pblock->mixHash = mix_hash;
9971004
} else if (pblock->IsSha256D() && pblock->nTime >= Params().PowUpdateTimestamp()) {
9981005
uint256 midStateHash = pblock->GetSha256dMidstate();
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;
1006+
bool success = false;
1007+
while (nMidTries < nMidLoopCount) {
1008+
while (nTries < nInnerLoopCount &&
1009+
!(success = CheckProofOfWork(pblock->GetSha256D(midStateHash), pblock->nBits,
1010+
Params().GetConsensus(), CBlockHeader::SHA256D_BLOCK))) {
1011+
boost::this_thread::interruption_point();
1012+
++nTries;
1013+
++pblock->nNonce64;
1014+
}
1015+
if (success) {
1016+
break;
1017+
}
1018+
++nMidTries;
1019+
nTries = 0;
1020+
if (pblock->nHeight <= chainActive.Height()) {
1021+
fBlockFoundAlready = true;
1022+
break;
1023+
}
10051024
}
10061025
} else if (pblock->nTime < Params().PowUpdateTimestamp()) {
10071026
while (nTries < nInnerLoopCount &&
@@ -1018,14 +1037,17 @@ void BitcoinMiner(std::shared_ptr<CReserveScript> coinbaseScript, bool fProofOfS
10181037
double nHashSpeed = 0;
10191038
{
10201039
LOCK(cs_nonce);
1021-
nHashes += nTries;
1040+
nHashes += nTries + (nMidTries * nInnerLoopCount);
10221041
nTimeDuration = GetTime() - nTimeStart;
10231042
if (!nTimeDuration) nTimeDuration = 1;
10241043
nHashSpeed = arith_uint256(nHashes/1000/nTimeDuration).getdouble();
10251044
}
10261045

10271046
LogPrint(BCLog::MINING, "%s: PoW Hashspeed %d kh/s\n", __func__, nHashSpeed);
1028-
if (nTries == nInnerLoopCount) {
1047+
// ProgPow/X16RT only use nTries
1048+
// SHA uses nMidTries/fBlockFoundAlready (and nTries can never be nInnerLoopCount here)
1049+
if (nTries == nInnerLoopCount || nMidTries == nMidLoopCount || fBlockFoundAlready) {
1050+
fBlockFoundAlready = false;
10291051
continue;
10301052
}
10311053
}

0 commit comments

Comments
 (0)