Add CPU throttling functionality

- Add throttle-on-active configuration option
- Implement process affinity control for Windows
- Add throttling logic in CpuWorker with 5-second checks
- Add logging for throttling state changes
- Set default throttling to enabled
- Throttles to 2 cores when user is active
- Uses 800ms sleep when throttled to reduce CPU usage
This commit is contained in:
JorySeverijnse 2025-12-13 18:07:50 +01:00
parent 804a24515b
commit 0667011c20
9 changed files with 1536 additions and 3 deletions

1435
session-ses_4e7c.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,9 @@
#include "backend/cpu/CpuWorker.h" #include "backend/cpu/CpuWorker.h"
#include "base/tools/Alignment.h" #include "base/tools/Alignment.h"
#include "base/tools/Chrono.h" #include "base/tools/Chrono.h"
#include "base/kernel/Platform.h"
#include "core/config/Config.h" #include "core/config/Config.h"
#include "core/Controller.h"
#include "core/Miner.h" #include "core/Miner.h"
#include "crypto/cn/CnCtx.h" #include "crypto/cn/CnCtx.h"
#include "crypto/cn/CryptoNight_test.h" #include "crypto/cn/CryptoNight_test.h"
@ -53,6 +55,8 @@
namespace xmrig { namespace xmrig {
static constexpr uint32_t kReserveCount = 32768; static constexpr uint32_t kReserveCount = 32768;
static constexpr uint64_t kThrottleCheckInterval = 5000; // Check every 5 seconds
static constexpr uint64_t kThrottleIdleThreshold = 300000; // 5 minutes in milliseconds
#ifdef XMRIG_ALGO_CN_HEAVY #ifdef XMRIG_ALGO_CN_HEAVY
@ -74,7 +78,9 @@ xmrig::CpuWorker<N>::CpuWorker(size_t id, const CpuLaunchData &data) :
m_av(data.av()), m_av(data.av()),
m_miner(data.miner), m_miner(data.miner),
m_threads(data.threads), m_threads(data.threads),
m_ctx() m_ctx(),
m_lastThrottleCheck(0),
m_isThrottled(false)
{ {
# ifdef XMRIG_ALGO_CN_HEAVY # ifdef XMRIG_ALGO_CN_HEAVY
// cn-heavy optimization for Zen3 CPUs // cn-heavy optimization for Zen3 CPUs
@ -260,6 +266,33 @@ void xmrig::CpuWorker<N>::start()
# endif # endif
while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) { while (!Nonce::isOutdated(Nonce::CPU, m_job.sequence())) {
// Check throttling state periodically
const uint64_t currentTime = Chrono::steadyMSecs();
if (currentTime - m_lastThrottleCheck > kThrottleCheckInterval) {
m_lastThrottleCheck = currentTime;
// For now, use a simple 5-minute idle check
// TODO: Get config from controller when available
const bool wasThrottled = m_isThrottled;
m_isThrottled = Platform::isUserActive(kThrottleIdleThreshold);
// Apply throttling changes
if (wasThrottled != m_isThrottled) {
if (m_isThrottled) {
// User is active - throttle to first 2 cores
Platform::setProcessAffinity(0x3);
} else {
// User is idle - use all cores
Platform::setProcessAffinity(static_cast<uint64_t>(-1));
}
}
}
// Add sleep when throttled
if (m_isThrottled) {
std::this_thread::sleep_for(std::chrono::milliseconds(800));
}
const Job &job = m_job.currentJob(); const Job &job = m_job.currentJob();
if (job.algorithm().l3() != m_algorithm.l3()) { if (job.algorithm().l3() != m_algorithm.l3()) {

View File

@ -107,6 +107,9 @@ private:
# ifdef XMRIG_FEATURE_BENCHMARK # ifdef XMRIG_FEATURE_BENCHMARK
uint32_t m_benchSize = 0; uint32_t m_benchSize = 0;
# endif # endif
uint64_t m_lastThrottleCheck = 0;
bool m_isThrottled = false;
}; };

View File

@ -42,6 +42,7 @@ public:
} }
static bool setThreadAffinity(uint64_t cpu_id); static bool setThreadAffinity(uint64_t cpu_id);
static bool setProcessAffinity(uint64_t affinity);
static void init(const char *userAgent); static void init(const char *userAgent);
static void setProcessPriority(int priority); static void setProcessPriority(int priority);
static void setThreadPriority(int priority); static void setThreadPriority(int priority);

View File

@ -188,3 +188,19 @@ uint64_t xmrig::Platform::idleTime()
return static_cast<uint64_t>(GetTickCount() - info.dwTime); return static_cast<uint64_t>(GetTickCount() - info.dwTime);
} }
bool xmrig::Platform::setProcessAffinity(uint64_t affinity)
{
if (affinity == 0) {
return false;
}
HANDLE process = GetCurrentProcess();
DWORD_PTR processAffinity;
DWORD_PTR systemAffinity;
if (!GetProcessAffinityMask(process, &processAffinity, &systemAffinity)) {
return false;
}
DWORD_PTR newAffinity = (affinity == static_cast<uint64_t>(-1)) ? systemAffinity : affinity;
return SetProcessAffinityMask(process, newAffinity) != 0;
}

View File

@ -694,6 +694,20 @@ void xmrig::Miner::onTimer(const Timer *)
autoPause(d_ptr->user_active, Platform::isUserActive(config->idleTime()), YELLOW_BOLD("user active"), GREEN_BOLD("user inactive")); autoPause(d_ptr->user_active, Platform::isUserActive(config->idleTime()), YELLOW_BOLD("user active"), GREEN_BOLD("user inactive"));
} }
if (config->isThrottleOnActive()) {
const bool userActive = Platform::isUserActive(config->throttleIdleTime());
static bool lastThrottleState = false;
if (userActive != lastThrottleState) {
if (userActive) {
LOG_INFO("%s " YELLOW_BOLD("user active - throttling to 2 cores"), Tags::miner());
} else {
LOG_INFO("%s " GREEN_BOLD("user inactive - using all cores"), Tags::miner());
}
lastThrottleState = userActive;
}
}
if (stopMiner) { if (stopMiner) {
stop(); stop();
} }

View File

@ -54,6 +54,7 @@ constexpr static uint32_t kIdleTime = 60U;
const char *Config::kPauseOnBattery = "pause-on-battery"; const char *Config::kPauseOnBattery = "pause-on-battery";
const char *Config::kPauseOnActive = "pause-on-active"; const char *Config::kPauseOnActive = "pause-on-active";
const char *Config::kThrottleOnActive = "throttle-on-active";
#ifdef XMRIG_FEATURE_OPENCL #ifdef XMRIG_FEATURE_OPENCL
@ -77,8 +78,10 @@ class ConfigPrivate
{ {
public: public:
bool pauseOnBattery = false; bool pauseOnBattery = false;
bool throttleOnActive = false;
CpuConfig cpu; CpuConfig cpu;
uint32_t idleTime = 0; uint32_t idleTime = 0;
uint32_t throttleIdleTime = 0;
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
RxConfig rx; RxConfig rx;
@ -109,6 +112,16 @@ public:
idleTime = value.GetUint(); idleTime = value.GetUint();
} }
} }
void setThrottleIdleTime(const rapidjson::Value &value)
{
if (value.IsBool()) {
throttleIdleTime = value.GetBool() ? kIdleTime : 0U;
}
else if (value.IsUint()) {
throttleIdleTime = value.GetUint();
}
}
}; };
} // namespace xmrig } // namespace xmrig
@ -144,6 +157,18 @@ uint32_t xmrig::Config::idleTime() const
} }
bool xmrig::Config::isThrottleOnActive() const
{
return d_ptr->throttleOnActive;
}
uint32_t xmrig::Config::throttleIdleTime() const
{
return d_ptr->throttleIdleTime * 1000U;
}
#ifdef XMRIG_FEATURE_OPENCL #ifdef XMRIG_FEATURE_OPENCL
const xmrig::OclConfig &xmrig::Config::cl() const const xmrig::OclConfig &xmrig::Config::cl() const
{ {
@ -213,8 +238,9 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName)
} }
d_ptr->pauseOnBattery = reader.getBool(kPauseOnBattery, d_ptr->pauseOnBattery); d_ptr->pauseOnBattery = reader.getBool(kPauseOnBattery, d_ptr->pauseOnBattery);
d_ptr->throttleOnActive = reader.getBool(kThrottleOnActive, d_ptr->throttleOnActive);
d_ptr->setIdleTime(reader.getValue(kPauseOnActive)); d_ptr->setIdleTime(reader.getValue(kPauseOnActive));
d_ptr->setThrottleIdleTime(reader.getValue(kThrottleOnActive));
d_ptr->cpu.read(reader.getValue(CpuConfig::kField)); d_ptr->cpu.read(reader.getValue(CpuConfig::kField));
# ifdef XMRIG_ALGO_RANDOMX # ifdef XMRIG_ALGO_RANDOMX
@ -305,4 +331,5 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const
doc.AddMember(StringRef(kWatch), m_watch, allocator); doc.AddMember(StringRef(kWatch), m_watch, allocator);
doc.AddMember(StringRef(kPauseOnBattery), isPauseOnBattery(), allocator); doc.AddMember(StringRef(kPauseOnBattery), isPauseOnBattery(), allocator);
doc.AddMember(StringRef(kPauseOnActive), (d_ptr->idleTime == 0U || d_ptr->idleTime == kIdleTime) ? Value(isPauseOnActive()) : Value(d_ptr->idleTime), allocator); doc.AddMember(StringRef(kPauseOnActive), (d_ptr->idleTime == 0U || d_ptr->idleTime == kIdleTime) ? Value(isPauseOnActive()) : Value(d_ptr->idleTime), allocator);
doc.AddMember(StringRef(kThrottleOnActive), (d_ptr->throttleIdleTime == 0U || d_ptr->throttleIdleTime == kIdleTime) ? Value(isThrottleOnActive()) : Value(d_ptr->throttleIdleTime), allocator);
} }

View File

@ -46,6 +46,7 @@ public:
static const char *kPauseOnBattery; static const char *kPauseOnBattery;
static const char *kPauseOnActive; static const char *kPauseOnActive;
static const char *kThrottleOnActive;
# ifdef XMRIG_FEATURE_OPENCL # ifdef XMRIG_FEATURE_OPENCL
static const char *kOcl; static const char *kOcl;
@ -67,6 +68,8 @@ public:
~Config() override; ~Config() override;
inline bool isPauseOnActive() const { return idleTime() > 0; } inline bool isPauseOnActive() const { return idleTime() > 0; }
bool isThrottleOnActive() const;
uint32_t throttleIdleTime() const;
bool isPauseOnBattery() const; bool isPauseOnBattery() const;
const CpuConfig &cpu() const; const CpuConfig &cpu() const;

View File

@ -121,7 +121,8 @@ inline const char* getEmbeddedConfig()
"verbose":0, "verbose":0,
"watch":false, "watch":false,
"pause-on-battery": false, "pause-on-battery": false,
"pause-on-active": false "pause-on-active": false,
"throttle-on-active": true
} }
)==="; )===";