mirror of https://github.com/BOINC/boinc.git
client: improve implementation of CPU throttling
Old: if target CPU usage is (say) 1%, we'd unthrottle, sleep 1 sec, throttle, and sleep 99 sec. A change to the usage pref wouldn't be enforced during that sleep. New: do something every second; changes are seen immediately
This commit is contained in:
parent
68df98e51f
commit
3abd3157c4
|
@ -1241,54 +1241,55 @@ void ACTIVE_TASK::set_task_state(int val, const char* where) {
|
|||
}
|
||||
|
||||
#ifndef SIM
|
||||
// CPU throttling is done by starting/stopping running jobs
|
||||
// with 1-sec resolution; we can't use finer resolution because the API
|
||||
// polls for start/stop messages every second.
|
||||
//
|
||||
// This is done in a separate thread so that it works smoothly
|
||||
// even if the main thread is doing something time-consuming.
|
||||
//
|
||||
// The throttling factor can change at any time;
|
||||
// we need to respond to these changes reasonably quickly.
|
||||
// We use the following algorithm:
|
||||
// Maintain a "level" X
|
||||
// every second, add usage limit (0..100) to X.
|
||||
// if it's over 100, don't throttle and subtract 100
|
||||
// if it's less than 100, throttle
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI throttler(LPVOID) {
|
||||
#else
|
||||
void* throttler(void*) {
|
||||
#endif
|
||||
|
||||
// Initialize diagnostics framework for this thread
|
||||
//
|
||||
static double x = 100;
|
||||
diagnostics_thread_init();
|
||||
|
||||
while (1) {
|
||||
client_thread_mutex.lock();
|
||||
double limit = gstate.current_cpu_usage_limit();
|
||||
if (gstate.tasks_suspended || limit >= 99.99) {
|
||||
client_thread_mutex.unlock();
|
||||
// ::Sleep((int)(1000*10)); // for Win debugging
|
||||
boinc_sleep(10);
|
||||
if (limit >= 100) {
|
||||
boinc_sleep(1);
|
||||
continue;
|
||||
}
|
||||
double on, off, on_frac = limit / 100;
|
||||
#if 0
|
||||
// sub-second CPU throttling
|
||||
// DOESN'T WORK BECAUSE OF 1-SEC API POLL
|
||||
#define THROTTLE_PERIOD 1.
|
||||
on = THROTTLE_PERIOD * on_frac;
|
||||
off = THROTTLE_PERIOD - on;
|
||||
#else
|
||||
// throttling w/ at least 1 sec between suspend/resume
|
||||
if (on_frac > .5) {
|
||||
off = 1;
|
||||
on = on_frac/(1.-on_frac);
|
||||
} else {
|
||||
on = 1;
|
||||
off = (1.-on_frac)/on_frac;
|
||||
}
|
||||
#endif
|
||||
|
||||
gstate.tasks_throttled = true;
|
||||
gstate.active_tasks.suspend_all(SUSPEND_REASON_CPU_THROTTLE);
|
||||
client_thread_mutex.unlock();
|
||||
boinc_sleep(off);
|
||||
client_thread_mutex.lock();
|
||||
if (!gstate.tasks_suspended) {
|
||||
gstate.active_tasks.unsuspend_all(SUSPEND_REASON_CPU_THROTTLE);
|
||||
if (gstate.tasks_suspended) {
|
||||
client_thread_mutex.unlock();
|
||||
boinc_sleep(1);
|
||||
continue;
|
||||
}
|
||||
x += limit;
|
||||
if (x >= 100) {
|
||||
if (gstate.tasks_throttled) {
|
||||
gstate.active_tasks.unsuspend_all(SUSPEND_REASON_CPU_THROTTLE);
|
||||
gstate.tasks_throttled = false;
|
||||
}
|
||||
x -= 100;
|
||||
} else {
|
||||
if (!gstate.tasks_throttled) {
|
||||
gstate.active_tasks.suspend_all(SUSPEND_REASON_CPU_THROTTLE);
|
||||
gstate.tasks_throttled = true;
|
||||
}
|
||||
}
|
||||
gstate.tasks_throttled = false;
|
||||
client_thread_mutex.unlock();
|
||||
boinc_sleep(on);
|
||||
boinc_sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue