Skip to content

Commit

Permalink
Merge pull request #4859 from BOINC/dpa_cpu_usage2
Browse files Browse the repository at this point in the history
fix non-BOINC CPU usage limit on Win and Linux
  • Loading branch information
davidpanderson authored Aug 2, 2022
2 parents 40548c5 + 46d489c commit a036709
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 6 deletions.
30 changes: 27 additions & 3 deletions client/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ void ACTIVE_TASK_SET::get_memory_usage() {
unsigned int i;
int retval;
static bool first = true;
static double last_cpu_time;
double diff=0;
bool using_vbox = false;

if (!first) {
diff = gstate.now - last_mem_time;
Expand Down Expand Up @@ -412,6 +412,7 @@ void ACTIVE_TASK_SET::get_memory_usage() {
}
procinfo_app(pi, v, pm, atp->app_version->graphics_exec_file);
if (atp->app_version->is_vm_app) {
using_vbox = true;
// the memory of virtual machine apps is not reported correctly,
// at least on Windows. Use the VM size instead.
//
Expand Down Expand Up @@ -485,13 +486,32 @@ void ACTIVE_TASK_SET::get_memory_usage() {
}
}

// get info on non-BOINC processes.
#if defined(__linux__) || defined(_WIN32)
// compute non_boinc_cpu_usage
// Improved version for systems where we can get total CPU (Win, Linux)
//
static double last_nbrc=0;
double nbrc = total_cpu_time() - boinc_related_cpu_time(pm, using_vbox);
double delta_nbrc = nbrc - last_nbrc;
if (delta_nbrc < 0) delta_nbrc = 0;
last_nbrc = nbrc;
if (!first) {
non_boinc_cpu_usage = delta_nbrc/(diff*gstate.host_info.p_ncpus);
//printf("non_boinc_cpu_usage %f\n", non_boinc_cpu_usage);
}
#else
// compute non_boinc_cpu_usage
//
// NOTE: this is flawed because it doesn't count short-lived processes
// correctly. Linux and Win use a better approach (see above).
//
// mem usage info is not useful because most OSs don't
// move idle processes out of RAM, so physical memory is always full.
// Also (at least on Win) page faults are used for various things,
// not all of them generate disk I/O,
// so they're not useful for detecting paging/thrashing.
//
static double last_cpu_time;
PROCINFO pi;
procinfo_non_boinc(pi, pm);
if (log_flags.mem_usage_debug) {
Expand All @@ -508,13 +528,17 @@ void ACTIVE_TASK_SET::get_memory_usage() {
// processes might have exited in the last 10 sec,
// causing this to be negative.
if (non_boinc_cpu_usage < 0) non_boinc_cpu_usage = 0;
}
last_cpu_time = new_cpu_time;
#endif

if (!first) {
if (log_flags.mem_usage_debug) {
msg_printf(NULL, MSG_INFO,
"[mem_usage] non-BOINC CPU usage: %.2f%%", non_boinc_cpu_usage*100
);
}
}
last_cpu_time = new_cpu_time;
first = false;
}

Expand Down
16 changes: 14 additions & 2 deletions client/cs_prefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ void CLIENT_STATE::get_disk_shares() {
// and if it's zero set gpu_suspend_reason
//
int CLIENT_STATE::check_suspend_processing() {
static double last_cpu_usage_suspend=0;

if (benchmarks_running) {
return SUSPEND_REASON_BENCHMARKS;
}
Expand Down Expand Up @@ -247,8 +249,18 @@ int CLIENT_STATE::check_suspend_processing() {
if (now - exclusive_app_running < MEMORY_USAGE_PERIOD + EXCLUSIVE_APP_WAIT) {
return SUSPEND_REASON_EXCLUSIVE_APP_RUNNING;
}
if (global_prefs.suspend_cpu_usage && non_boinc_cpu_usage*100 > global_prefs.suspend_cpu_usage) {
return SUSPEND_REASON_CPU_USAGE;

// if we suspended because of CPU usage,
// don't unsuspend for at least 2*MEMORY_USAGE_PERIOD
//
if (global_prefs.suspend_cpu_usage) {
if (now < last_cpu_usage_suspend+2*MEMORY_USAGE_PERIOD) {
return SUSPEND_REASON_CPU_USAGE;
}
if (non_boinc_cpu_usage*100 > global_prefs.suspend_cpu_usage) {
last_cpu_usage_suspend = now;
return SUSPEND_REASON_CPU_USAGE;
}
}
}

Expand Down
26 changes: 25 additions & 1 deletion lib/procinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,34 @@ void procinfo_non_boinc(PROCINFO& procinfo, PROC_MAP& pm) {
procinfo.working_set_size += p.working_set_size;
}
#if 0
fprintf(stderr, "total non-boinc: %f %f\n", procinfo.user_time, procinfo.kernel_time);
fprintf(stderr,
"total non-boinc: %f %f\n", procinfo.user_time, procinfo.kernel_time
);
#endif
}

// get CPU time of BOINC-related processes, low-priority processes,
// and (if we're using Vbox) the Vbox daemon.
//
double boinc_related_cpu_time(PROC_MAP& pm, bool using_vbox) {
double sum = 0;
PROC_MAP::iterator i;
for (i=pm.begin(); i!=pm.end(); ++i) {
PROCINFO& p = i->second;
#ifdef _WIN32
if (p.id == 0) continue; // idle process
#endif
if (
p.is_boinc_app
|| p.is_low_priority
|| (using_vbox && strstr(p.command, "VBoxSVC"))
) {
sum += p.user_time;
}
}
return sum;
}

double process_tree_cpu_time(int pid) {
PROC_MAP pm;
PROCINFO procinfo;
Expand Down
6 changes: 6 additions & 0 deletions lib/procinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,10 @@ extern void procinfo_non_boinc(PROCINFO&, PROC_MAP&);
extern double process_tree_cpu_time(int pid);
// get the CPU time of the given process and its descendants

extern double total_cpu_time();
// total user-mode CPU time, as reported by OS

extern double boinc_related_cpu_time(PROC_MAP&, bool using_vbox);
// total CPU of current BOINC processes, low-priority processes,
// and (if using vbox) the Vbox daemon
#endif
32 changes: 32 additions & 0 deletions lib/procinfo_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,35 @@ int procinfo_setup(PROC_MAP& pm) {
find_children(pm);
return 0;
}

// get total user-mode CPU time
// see https://www.baeldung.com/linux/get-cpu-usage
//
double total_cpu_time() {
char buf[1024];
static FILE *f=NULL;
static double scale;
if (!f) {
f = fopen("/proc/stat", "r");
if (!f) {
fprintf(stderr, "can't open /proc/stat\n");
return 0;
}
long hz = sysconf(_SC_CLK_TCK);
scale = 1./hz;
} else {
fflush(f);
rewind(f);
}
if (!fgets(buf, 256, f)) {
fprintf(stderr, "can't read /proc/stat\n");
return 0;
}
double user, nice;
int n = sscanf(buf, "cpu %lf %lf", &user, &nice);
if (n != 2) {
fprintf(stderr, "can't parse /proc/stat: %s\n", buf);
return 0;
}
return (user+nice)*scale;
}
12 changes: 12 additions & 0 deletions lib/procinfo_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,15 @@ int procinfo_setup(PROC_MAP& pm) {
}
return 0;
}

// get total CPU time
// see https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getsystemtimes
//
double total_cpu_time() {
FILETIME i, s, u;
GetSystemTimes(&i, &s, &u);
ULARGE_INTEGER x;
x.LowPart = u.dwLowDateTime;
x.HighPart = u.dwHighDateTime;
return (double)x.QuadPart/1e7;
}

0 comments on commit a036709

Please sign in to comment.