perf(mining): one save, at most one restart per thread-count gesture
Every thread-count change on the Mining tab saved settings.json and, with a miner running, stopped and restarted it: xmrig re-inits its RandomX dataset and reconnects to the pool, seconds of lost hashing each time. A drag across the grid did this once per tile crossed (up to ~24), with a "Starting pool miner" toast each; every -/+ click or Enter did it again. The tab now hands each pick to the App, which puts the newest in settings at once and applies it when the input settles: on drag release, or 0.5 s after the last click, even if the Mining tab was left in the meantime. The header, RAM estimate and tile fill still follow the drag live. - Pool: the restart is decided on the mining-control thread, after every earlier start or stop has run. It never starts a miner the user stopped, is a no-op when xmrig already runs at that count, and is no longer silently skipped when the pick lands in another restart's stop window (which left xmrig on the old count). - Solo: one setgenerate per gesture. A pick made while one is in flight now waits for it instead of being dropped (another stale count). - Clicking the tile that is already selected does nothing; it used to save settings and restart the miner. - With idle thread scaling on, the grid no longer snaps back to the old count while a pick is on its way to the miner. A pool auto-balance restart keeps a count still queued. - Idle thread scaling changes the pool count through the same retarget. Its correction after a start compares with the count last requested, not the xmrig API's lagging report, so it comes about 1 s in instead of after the first API report (3-5 s). - A retarget whose pool config no longer validates shows the same error and stops the miner, as the old stop-then-start did. - While a benchmark runs a pick is saved, but the miner change is dropped: the benchmark owns the count until it ends. A crash within 0.5 s of a pick, or mid-drag, loses that pick; every clean exit saves it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+36
-1
@@ -3369,6 +3369,28 @@ void App::startPoolMining(int threads)
|
||||
if (state_.mining.generate) stopMining();
|
||||
// (the "stop the already-running miner first" step is done inside the control job below, in FIFO order)
|
||||
|
||||
postPoolMinerJob(threads, /*retargetOnly=*/false);
|
||||
}
|
||||
|
||||
// Change the thread count of the pool miner that is running, or queued to start (Mining tab picks, idle
|
||||
// thread scaling). Never starts a miner: the job decides on the mining-control thread (postPoolMinerJob).
|
||||
// Nothing is posted when there is no miner, or when the newest start/retarget already asks for `threads`.
|
||||
void App::retargetPoolMining(int threads)
|
||||
{
|
||||
if (!supportsPoolMining() || !xmrig_manager_) return;
|
||||
threads = std::clamp(threads, 1, std::max(1, (int)std::thread::hardware_concurrency()));
|
||||
const int target = pool_threads_target_.load(std::memory_order_relaxed);
|
||||
if (target <= 0 && !xmrig_manager_->isRunning()) return; // no miner, none queued
|
||||
if (target == threads) return; // the newest queued job already does this
|
||||
postPoolMinerJob(threads, /*retargetOnly=*/true);
|
||||
}
|
||||
|
||||
// Builds the xmrig config from settings + wallet state on this (main) thread and posts the blocking
|
||||
// stop(if running)+start to the mining-control thread. retargetOnly (a thread-count change): the job does
|
||||
// nothing unless a miner is running when it runs, at another count; a config that no longer validates
|
||||
// stops the miner, as the old stop-then-start did.
|
||||
void App::postPoolMinerJob(int threads, bool retargetOnly)
|
||||
{
|
||||
daemon::XmrigManager::Config cfg;
|
||||
cfg.pool_url = settings_->getPoolUrl();
|
||||
cfg.worker_name = settings_->getPoolWorker();
|
||||
@@ -3381,6 +3403,7 @@ void App::startPoolMining(int threads)
|
||||
ui::Notifications::instance().error(util::isTransparentAddress(cfg.worker_name)
|
||||
? TR("mining_payout_needs_shielded")
|
||||
: "Pool payout address is not a valid DragonX address — mining not started.");
|
||||
if (retargetOnly) stopPoolMining(); // never keep mining on a config that no longer validates
|
||||
return;
|
||||
}
|
||||
// The algo follows the pool: official pools use their own algo (pool.dragonx.cc
|
||||
@@ -3411,6 +3434,7 @@ void App::startPoolMining(int threads)
|
||||
if (cfg.wallet_address.empty()) {
|
||||
DEBUG_LOGF("[ERROR] Pool mining: No wallet address available\n");
|
||||
ui::Notifications::instance().error("No wallet address available — generate a Z address in the Receive tab");
|
||||
if (retargetOnly) stopPoolMining();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3418,10 +3442,20 @@ void App::startPoolMining(int threads)
|
||||
// never blocks on stop()'s SIGTERM->SIGKILL->join; marshal the spawn result back to the UI. (M-03/L-06/
|
||||
// L-08/L-09/L-13). cfg was fully built above on this (main) thread.
|
||||
daemon::XmrigManager::Config cfgCopy = cfg;
|
||||
postMiningControl([this, cfgCopy]() {
|
||||
const int target = cfg.threads;
|
||||
pool_threads_target_.store(target, std::memory_order_relaxed);
|
||||
postMiningControl([this, cfgCopy, target, retargetOnly]() {
|
||||
// A retarget is decided HERE, after every earlier start/stop ran: nothing happens unless a miner is
|
||||
// running now and at another count. So it never starts a miner the user stopped, and a restart's
|
||||
// stop window (isRunning() false on the UI thread) can't hide the running one.
|
||||
if (retargetOnly) {
|
||||
if (!xmrig_manager_->isRunning()) { clearPoolThreadsTarget(target); return; }
|
||||
if (xmrig_manager_->getRequestedThreads() == target) return;
|
||||
}
|
||||
if (xmrig_manager_->isRunning()) xmrig_manager_->stop(3000);
|
||||
const bool ok = xmrig_manager_->start(cfgCopy);
|
||||
const std::string err = ok ? std::string() : xmrig_manager_->getLastError();
|
||||
if (!ok) clearPoolThreadsTarget(target);
|
||||
if (!worker_) return;
|
||||
worker_->post([this, ok, err]() -> rpc::RPCWorker::MainCb {
|
||||
return [this, ok, err]() {
|
||||
@@ -3450,6 +3484,7 @@ void App::startPoolMining(int threads)
|
||||
void App::stopPoolMining()
|
||||
{
|
||||
if (!xmrig_manager_) return;
|
||||
pool_threads_target_.store(0, std::memory_order_relaxed); // no start/retarget is current any more
|
||||
// Off the render thread — stop()'s SIGTERM->SIGKILL->join can block up to ~3s. (M-03/L-06/L-08/L-09)
|
||||
postMiningControl([this]() {
|
||||
if (xmrig_manager_->isRunning()) xmrig_manager_->stop(3000);
|
||||
|
||||
Reference in New Issue
Block a user