Skip to content

Commit a036709

Browse files
Merge pull request #4859 from BOINC/dpa_cpu_usage2
fix non-BOINC CPU usage limit on Win and Linux
2 parents 40548c5 + 46d489c commit a036709

File tree

6 files changed

+116
-6
lines changed

6 files changed

+116
-6
lines changed

client/app.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,8 @@ void ACTIVE_TASK_SET::get_memory_usage() {
359359
unsigned int i;
360360
int retval;
361361
static bool first = true;
362-
static double last_cpu_time;
363362
double diff=0;
363+
bool using_vbox = false;
364364

365365
if (!first) {
366366
diff = gstate.now - last_mem_time;
@@ -412,6 +412,7 @@ void ACTIVE_TASK_SET::get_memory_usage() {
412412
}
413413
procinfo_app(pi, v, pm, atp->app_version->graphics_exec_file);
414414
if (atp->app_version->is_vm_app) {
415+
using_vbox = true;
415416
// the memory of virtual machine apps is not reported correctly,
416417
// at least on Windows. Use the VM size instead.
417418
//
@@ -485,13 +486,32 @@ void ACTIVE_TASK_SET::get_memory_usage() {
485486
}
486487
}
487488

488-
// get info on non-BOINC processes.
489+
#if defined(__linux__) || defined(_WIN32)
490+
// compute non_boinc_cpu_usage
491+
// Improved version for systems where we can get total CPU (Win, Linux)
492+
//
493+
static double last_nbrc=0;
494+
double nbrc = total_cpu_time() - boinc_related_cpu_time(pm, using_vbox);
495+
double delta_nbrc = nbrc - last_nbrc;
496+
if (delta_nbrc < 0) delta_nbrc = 0;
497+
last_nbrc = nbrc;
498+
if (!first) {
499+
non_boinc_cpu_usage = delta_nbrc/(diff*gstate.host_info.p_ncpus);
500+
//printf("non_boinc_cpu_usage %f\n", non_boinc_cpu_usage);
501+
}
502+
#else
503+
// compute non_boinc_cpu_usage
504+
//
505+
// NOTE: this is flawed because it doesn't count short-lived processes
506+
// correctly. Linux and Win use a better approach (see above).
507+
//
489508
// mem usage info is not useful because most OSs don't
490509
// move idle processes out of RAM, so physical memory is always full.
491510
// Also (at least on Win) page faults are used for various things,
492511
// not all of them generate disk I/O,
493512
// so they're not useful for detecting paging/thrashing.
494513
//
514+
static double last_cpu_time;
495515
PROCINFO pi;
496516
procinfo_non_boinc(pi, pm);
497517
if (log_flags.mem_usage_debug) {
@@ -508,13 +528,17 @@ void ACTIVE_TASK_SET::get_memory_usage() {
508528
// processes might have exited in the last 10 sec,
509529
// causing this to be negative.
510530
if (non_boinc_cpu_usage < 0) non_boinc_cpu_usage = 0;
531+
}
532+
last_cpu_time = new_cpu_time;
533+
#endif
534+
535+
if (!first) {
511536
if (log_flags.mem_usage_debug) {
512537
msg_printf(NULL, MSG_INFO,
513538
"[mem_usage] non-BOINC CPU usage: %.2f%%", non_boinc_cpu_usage*100
514539
);
515540
}
516541
}
517-
last_cpu_time = new_cpu_time;
518542
first = false;
519543
}
520544

client/cs_prefs.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ void CLIENT_STATE::get_disk_shares() {
203203
// and if it's zero set gpu_suspend_reason
204204
//
205205
int CLIENT_STATE::check_suspend_processing() {
206+
static double last_cpu_usage_suspend=0;
207+
206208
if (benchmarks_running) {
207209
return SUSPEND_REASON_BENCHMARKS;
208210
}
@@ -247,8 +249,18 @@ int CLIENT_STATE::check_suspend_processing() {
247249
if (now - exclusive_app_running < MEMORY_USAGE_PERIOD + EXCLUSIVE_APP_WAIT) {
248250
return SUSPEND_REASON_EXCLUSIVE_APP_RUNNING;
249251
}
250-
if (global_prefs.suspend_cpu_usage && non_boinc_cpu_usage*100 > global_prefs.suspend_cpu_usage) {
251-
return SUSPEND_REASON_CPU_USAGE;
252+
253+
// if we suspended because of CPU usage,
254+
// don't unsuspend for at least 2*MEMORY_USAGE_PERIOD
255+
//
256+
if (global_prefs.suspend_cpu_usage) {
257+
if (now < last_cpu_usage_suspend+2*MEMORY_USAGE_PERIOD) {
258+
return SUSPEND_REASON_CPU_USAGE;
259+
}
260+
if (non_boinc_cpu_usage*100 > global_prefs.suspend_cpu_usage) {
261+
last_cpu_usage_suspend = now;
262+
return SUSPEND_REASON_CPU_USAGE;
263+
}
252264
}
253265
}
254266

lib/procinfo.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,34 @@ void procinfo_non_boinc(PROCINFO& procinfo, PROC_MAP& pm) {
135135
procinfo.working_set_size += p.working_set_size;
136136
}
137137
#if 0
138-
fprintf(stderr, "total non-boinc: %f %f\n", procinfo.user_time, procinfo.kernel_time);
138+
fprintf(stderr,
139+
"total non-boinc: %f %f\n", procinfo.user_time, procinfo.kernel_time
140+
);
139141
#endif
140142
}
141143

144+
// get CPU time of BOINC-related processes, low-priority processes,
145+
// and (if we're using Vbox) the Vbox daemon.
146+
//
147+
double boinc_related_cpu_time(PROC_MAP& pm, bool using_vbox) {
148+
double sum = 0;
149+
PROC_MAP::iterator i;
150+
for (i=pm.begin(); i!=pm.end(); ++i) {
151+
PROCINFO& p = i->second;
152+
#ifdef _WIN32
153+
if (p.id == 0) continue; // idle process
154+
#endif
155+
if (
156+
p.is_boinc_app
157+
|| p.is_low_priority
158+
|| (using_vbox && strstr(p.command, "VBoxSVC"))
159+
) {
160+
sum += p.user_time;
161+
}
162+
}
163+
return sum;
164+
}
165+
142166
double process_tree_cpu_time(int pid) {
143167
PROC_MAP pm;
144168
PROCINFO procinfo;

lib/procinfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,10 @@ extern void procinfo_non_boinc(PROCINFO&, PROC_MAP&);
8282
extern double process_tree_cpu_time(int pid);
8383
// get the CPU time of the given process and its descendants
8484

85+
extern double total_cpu_time();
86+
// total user-mode CPU time, as reported by OS
87+
88+
extern double boinc_related_cpu_time(PROC_MAP&, bool using_vbox);
89+
// total CPU of current BOINC processes, low-priority processes,
90+
// and (if using vbox) the Vbox daemon
8591
#endif

lib/procinfo_unix.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,35 @@ int procinfo_setup(PROC_MAP& pm) {
263263
find_children(pm);
264264
return 0;
265265
}
266+
267+
// get total user-mode CPU time
268+
// see https://www.baeldung.com/linux/get-cpu-usage
269+
//
270+
double total_cpu_time() {
271+
char buf[1024];
272+
static FILE *f=NULL;
273+
static double scale;
274+
if (!f) {
275+
f = fopen("/proc/stat", "r");
276+
if (!f) {
277+
fprintf(stderr, "can't open /proc/stat\n");
278+
return 0;
279+
}
280+
long hz = sysconf(_SC_CLK_TCK);
281+
scale = 1./hz;
282+
} else {
283+
fflush(f);
284+
rewind(f);
285+
}
286+
if (!fgets(buf, 256, f)) {
287+
fprintf(stderr, "can't read /proc/stat\n");
288+
return 0;
289+
}
290+
double user, nice;
291+
int n = sscanf(buf, "cpu %lf %lf", &user, &nice);
292+
if (n != 2) {
293+
fprintf(stderr, "can't parse /proc/stat: %s\n", buf);
294+
return 0;
295+
}
296+
return (user+nice)*scale;
297+
}

lib/procinfo_win.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,15 @@ int procinfo_setup(PROC_MAP& pm) {
149149
}
150150
return 0;
151151
}
152+
153+
// get total CPU time
154+
// see https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getsystemtimes
155+
//
156+
double total_cpu_time() {
157+
FILETIME i, s, u;
158+
GetSystemTimes(&i, &s, &u);
159+
ULARGE_INTEGER x;
160+
x.LowPart = u.dwLowDateTime;
161+
x.HighPart = u.dwHighDateTime;
162+
return (double)x.QuadPart/1e7;
163+
}

0 commit comments

Comments
 (0)