From be63e83d79e7e00e6b8ca889a70e6a19886aa1d8 Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Wed, 19 Aug 2026 22:46:53 +0000 Subject: 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) --- src/main.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'src/main.cpp') 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() return (int)(nCores - 1); } +// Hash threads one participant session runs. +// +// Explicit /hashthreads=N is honored exactly, including 1 -- a miner who says +// one means one. Automatic leaves a core to the node, the Stratum I/O loop and +// everything else the process still has to do, for the same reason +// MinerThreadCount() does. +// +// Lives here, next to that function, because the two are easy to confuse and +// StartMinerThreads() needs to be able to tell them apart: only ONE session +// runs in participant mode, and this is what sizes it. +int ParticipantHashThreadCount() +{ + if (nHashThreads > 0) + return nHashThreads; + int nWorkers = (int)AvailableCoreCount(); + if (nWorkers < 2) + nWorkers = 2; + return nWorkers - 1; +} + bool AddKey(const CKey& key) { if (IsWalletEncrypted()) @@ -3828,13 +3848,11 @@ connected: // shared dataset), then run the I/O loop below: receive pool messages, // publish jobs to the threads, submit the shares they find. // ------------------------------------------------------------------ - int nWorkers = nHashThreads > 0 ? nHashThreads - : (int)AvailableCoreCount(); - if (nHashThreads <= 0) { - if (nWorkers < 2) nWorkers = 2; - nWorkers -= 1; // leave one core for node + I/O threads - } - // explicit /hashthreads=N is honored exactly (including 1) + // One count, decided in one place (main.cpp:MinerThreadCount's neighbour), + // so that what StartMinerThreads() reports at startup and what actually + // hashes here can never drift apart. Explicit /hashthreads=N is honored + // exactly, including 1; automatic leaves one core for node + I/O threads. + int nWorkers = ParticipantHashThreadCount(); ParticipantJobShared jobShared; std::vector shareHits; std::mutex shareHitsMtx; -- cgit v1.2.3