upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 22:46:53 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 22:48:27 +0000
commitbe63e83d79e7e00e6b8ca889a70e6a19886aa1d8 (patch)
treedddbb629a288d4fdf8f4f145454ff70517b5a852 /src
parentad41b7a151f2f4b7f483dfc8c6eae74d8292f97a (diff)
mine: one pool session in participant mode, not one per core
StartMinerThreads() sizes its pool with MinerThreadCount(), which is right for solo mining -- each thread hashes a template of its own -- and wrong for participant mode, where every thread entering BitcoinMiner() is a whole miner: its own Stratum session, its own payout address off the rotation, its own pool of /hashthreads workers. The two counts multiplied instead of dividing. Measured on the pool box with /hashthreads=2: a container with no cpuset logged "Mining with 11 thread(s) of 12 core(s)" -- 11 sessions, 22 hash threads on 12 cores, 1058% CPU, load 22.68 -- while the same binary under --cpuset-cpus 10,11 logged one session and 199%. The second miner (8 cores, /hashthreads=1) ran 7 sessions and went 74C to 89C. No code differed between those runs. Only the cpuset did, which means the cpuset was holding the thread count down by accident and every deployment without one was oversubscribed. Participant mode now starts exactly one session, so /hashthreads means what it says instead of being multiplied by the core count. The worker count moves to ParticipantHashThreadCount(), next to MinerThreadCount() where the two are easy to confuse, so what is printed at startup and what actually hashes cannot drift apart -- and it IS printed now. It was only ever visible under -debug, which is how eleven sessions ran unnoticed. Same host, same cpuset (0-3), same arguments, measured as a delta over 20 s more than four minutes after start: before 399% CPU, 6-7 threads hot, 3 sessions after 201% CPU, exactly 2 threads at 99.9%, 1 session Solo mining is untouched: /gen without /participant still starts MinerThreadCount() threads. (cherry picked from commit 45bc9ed5bc132712092f3e7902fef746c6cae898)
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp32
-rw-r--r--src/main.h3
-rw-r--r--src/net.cpp37
3 files changed, 61 insertions, 11 deletions
diff --git a/src/main.cpp b/src/main.cpp
index efff96c..77aba89 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -170,6 +170,26 @@ int MinerThreadCount()
170 return (int)(nCores - 1); 170 return (int)(nCores - 1);
171} 171}
172 172
173// Hash threads one participant session runs.
174//
175// Explicit /hashthreads=N is honored exactly, including 1 -- a miner who says
176// one means one. Automatic leaves a core to the node, the Stratum I/O loop and
177// everything else the process still has to do, for the same reason
178// MinerThreadCount() does.
179//
180// Lives here, next to that function, because the two are easy to confuse and
181// StartMinerThreads() needs to be able to tell them apart: only ONE session
182// runs in participant mode, and this is what sizes it.
183int ParticipantHashThreadCount()
184{
185 if (nHashThreads > 0)
186 return nHashThreads;
187 int nWorkers = (int)AvailableCoreCount();
188 if (nWorkers < 2)
189 nWorkers = 2;
190 return nWorkers - 1;
191}
192
173bool AddKey(const CKey& key) 193bool AddKey(const CKey& key)
174{ 194{
175 if (IsWalletEncrypted()) 195 if (IsWalletEncrypted())
@@ -3828,13 +3848,11 @@ connected:
3828 // shared dataset), then run the I/O loop below: receive pool messages, 3848 // shared dataset), then run the I/O loop below: receive pool messages,
3829 // publish jobs to the threads, submit the shares they find. 3849 // publish jobs to the threads, submit the shares they find.
3830 // ------------------------------------------------------------------ 3850 // ------------------------------------------------------------------
3831 int nWorkers = nHashThreads > 0 ? nHashThreads 3851 // One count, decided in one place (main.cpp:MinerThreadCount's neighbour),
3832 : (int)AvailableCoreCount(); 3852 // so that what StartMinerThreads() reports at startup and what actually
3833 if (nHashThreads <= 0) { 3853 // hashes here can never drift apart. Explicit /hashthreads=N is honored
3834 if (nWorkers < 2) nWorkers = 2; 3854 // exactly, including 1; automatic leaves one core for node + I/O threads.
3835 nWorkers -= 1; // leave one core for node + I/O threads 3855 int nWorkers = ParticipantHashThreadCount();
3836 }
3837 // explicit /hashthreads=N is honored exactly (including 1)
3838 ParticipantJobShared jobShared; 3856 ParticipantJobShared jobShared;
3839 std::vector<ParticipantShareHit> shareHits; 3857 std::vector<ParticipantShareHit> shareHits;
3840 std::mutex shareHitsMtx; 3858 std::mutex shareHitsMtx;
diff --git a/src/main.h b/src/main.h
index f5409e9..27f89ac 100644
--- a/src/main.h
+++ b/src/main.h
@@ -103,6 +103,9 @@ extern bool fSoloMineTest; // /solomine: mine without requiring a peer (local te
103extern int nMinerThreads; 103extern int nMinerThreads;
104// Resolves the automatic case into a real count. 104// Resolves the automatic case into a real count.
105int MinerThreadCount(); 105int MinerThreadCount();
106// Hash threads one participant session runs; resolves /hashthreads. Not the
107// same number as MinerThreadCount(), and only ONE session ever runs.
108int ParticipantHashThreadCount();
106extern bool gPoolServerRunning; // GUI/startup state 109extern bool gPoolServerRunning; // GUI/startup state
107extern volatile bool gPoolRunning; // runtime pool server loop flag (rpc.cpp) 110extern volatile bool gPoolRunning; // runtime pool server loop flag (rpc.cpp)
108 111
diff --git a/src/net.cpp b/src/net.cpp
index e08f6f7..34c608c 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1801,7 +1801,21 @@ void ThreadBitcoinMiner(void* parg)
1801// Start the miners. Returns how many actually got off the ground. 1801// Start the miners. Returns how many actually got off the ground.
1802int StartMinerThreads() 1802int StartMinerThreads()
1803{ 1803{
1804 int nThreads = MinerThreadCount(); 1804 // MinerThreadCount() sizes the SOLO miner, where each thread hashes a
1805 // template of its own and more threads is simply more hashrate.
1806 //
1807 // Participant mode is not that shape. Every thread that enters
1808 // BitcoinMiner() takes the MINE_PARTICIPANT branch, and that branch is a
1809 // whole miner: its own Stratum session to the pool, its own payout address
1810 // from the rotation, and its own pool of /hashthreads worker threads. So
1811 // the two counts multiply instead of dividing, and the machine ends up
1812 // running MinerThreadCount() x nHashThreads hashing threads plus one pool
1813 // connection each. On a 12-core host with /hashthreads=2 that is 11
1814 // sessions and 22 hash threads -- roughly 2x the cores, which is not more
1815 // work done, only more contention -- and with /hashthreads unset it is 11
1816 // sessions of 11 workers. One session is the entirety of participant mode;
1817 // /hashthreads is what sizes it, and it can then mean what it says.
1818 int nThreads = (nMineMode == MINE_PARTICIPANT) ? 1 : MinerThreadCount();
1805 int nStarted = 0; 1819 int nStarted = 0;
1806 for (int i = 0; i < nThreads; i++) 1820 for (int i = 0; i < nThreads; i++)
1807 { 1821 {
@@ -1813,9 +1827,24 @@ int StartMinerThreads()
1813 // The dataset is one allocation shared by all of them; only the 2 MB 1827 // The dataset is one allocation shared by all of them; only the 2 MB
1814 // scratchpads multiply. Printed because "why is it using 2 GB" is the first 1828 // scratchpads multiply. Printed because "why is it using 2 GB" is the first
1815 // question anyone asks. 1829 // question anyone asks.
1816 printf("Mining with %d thread(s) of %u core(s) -- about %d MB " 1830 //
1817 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n", 1831 // Participant mode reports the workers that session will run, not the one
1818 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted); 1832 // thread that runs it: the hash thread count is the number an operator
1833 // watches, and it is the number that was wrong here. It is otherwise only
1834 // logged under -debug, which is how 11 sessions ran unnoticed.
1835 if (nMineMode == MINE_PARTICIPANT)
1836 {
1837 int nWorkers = ParticipantHashThreadCount();
1838 printf("Mining for the pool with %d hash thread(s) of %u core(s) -- about %d MB "
1839 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1840 nWorkers, AvailableCoreCount(), 2080 + 2 * nWorkers);
1841 }
1842 else
1843 {
1844 printf("Mining with %d thread(s) of %u core(s) -- about %d MB "
1845 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1846 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted);
1847 }
1819 return nStarted; 1848 return nStarted;
1820} 1849}
1821 1850