Skip to content

Commit c0c5815

Browse files
authored
Merge pull request #4875 from BOINC/mac_get_total_cpu_usage
Mac: compute non-BOINC CPU usage in a more accurate way
2 parents a597329 + 3135244 commit c0c5815

File tree

3 files changed

+92
-45
lines changed

3 files changed

+92
-45
lines changed

client/app.cpp

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of BOINC.
22
// http://boinc.berkeley.edu
3-
// Copyright (C) 2008 University of California
3+
// Copyright (C) 2022 University of California
44
//
55
// BOINC is free software; you can redistribute it and/or modify it
66
// under the terms of the GNU Lesser General Public License
@@ -486,51 +486,55 @@ void ACTIVE_TASK_SET::get_memory_usage() {
486486
}
487487
}
488488

489-
#if defined(__linux__) || defined(_WIN32)
489+
#if defined(__linux__) || defined(_WIN32) || defined(__APPLE__)
490490
// compute non_boinc_cpu_usage
491-
// Improved version for systems where we can get total CPU (Win, Linux)
491+
// Improved version for systems where we can get total CPU (Win, Linux, Mac)
492492
//
493493
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-
//
508-
// mem usage info is not useful because most OSs don't
509-
// move idle processes out of RAM, so physical memory is always full.
510-
// Also (at least on Win) page faults are used for various things,
511-
// not all of them generate disk I/O,
512-
// so they're not useful for detecting paging/thrashing.
513-
//
514-
static double last_cpu_time;
515-
PROCINFO pi;
516-
procinfo_non_boinc(pi, pm);
517-
if (log_flags.mem_usage_debug) {
518-
//procinfo_show(pm);
519-
msg_printf(NULL, MSG_INFO,
520-
"[mem_usage] All others: WS %.2fMB, swap %.2fMB, user %.3fs, kernel %.3fs",
521-
pi.working_set_size/MEGA, pi.swap_size/MEGA,
522-
pi.user_time, pi.kernel_time
523-
);
524-
}
525-
double new_cpu_time = pi.user_time + pi.kernel_time;
526-
if (!first) {
527-
non_boinc_cpu_usage = (new_cpu_time - last_cpu_time)/(diff*gstate.host_info.p_ncpus);
528-
// processes might have exited in the last 10 sec,
529-
// causing this to be negative.
530-
if (non_boinc_cpu_usage < 0) non_boinc_cpu_usage = 0;
531-
}
532-
last_cpu_time = new_cpu_time;
494+
double total_cpu_time_now = total_cpu_time();
495+
if (total_cpu_time_now != 0.0) { // total_cpu_time() returns 0.0 on error
496+
double nbrc = total_cpu_time_now - boinc_related_cpu_time(pm, using_vbox);
497+
double delta_nbrc = nbrc - last_nbrc;
498+
if (delta_nbrc < 0) delta_nbrc = 0;
499+
last_nbrc = nbrc;
500+
if (!first) {
501+
non_boinc_cpu_usage = delta_nbrc/(diff*gstate.host_info.p_ncpus);
502+
//printf("non_boinc_cpu_usage %f\n", non_boinc_cpu_usage);
503+
}
504+
} else
533505
#endif
506+
{
507+
// compute non_boinc_cpu_usage the old way
508+
//
509+
// NOTE: this is flawed because it doesn't count short-lived processes
510+
// correctly. Linux and Win use a better approach (see above).
511+
//
512+
// mem usage info is not useful because most OSs don't
513+
// move idle processes out of RAM, so physical memory is always full.
514+
// Also (at least on Win) page faults are used for various things,
515+
// not all of them generate disk I/O,
516+
// so they're not useful for detecting paging/thrashing.
517+
//
518+
static double last_cpu_time;
519+
PROCINFO pi;
520+
procinfo_non_boinc(pi, pm);
521+
if (log_flags.mem_usage_debug) {
522+
//procinfo_show(pm);
523+
msg_printf(NULL, MSG_INFO,
524+
"[mem_usage] All others: WS %.2fMB, swap %.2fMB, user %.3fs, kernel %.3fs",
525+
pi.working_set_size/MEGA, pi.swap_size/MEGA,
526+
pi.user_time, pi.kernel_time
527+
);
528+
}
529+
double new_cpu_time = pi.user_time + pi.kernel_time;
530+
if (!first) {
531+
non_boinc_cpu_usage = (new_cpu_time - last_cpu_time)/(diff*gstate.host_info.p_ncpus);
532+
// processes might have exited in the last 10 sec,
533+
// causing this to be negative.
534+
if (non_boinc_cpu_usage < 0) non_boinc_cpu_usage = 0;
535+
}
536+
last_cpu_time = new_cpu_time;
537+
}
534538

535539
if (!first) {
536540
if (log_flags.mem_usage_debug) {
@@ -542,7 +546,7 @@ void ACTIVE_TASK_SET::get_memory_usage() {
542546
first = false;
543547
}
544548

545-
#endif
549+
#endif // ! defined (SIM)
546550

547551
// There's a new trickle file.
548552
// Move it from slot dir to project dir

lib/procinfo_mac.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of BOINC.
22
// http://boinc.berkeley.edu
3-
// Copyright (C) 2020 University of California
3+
// Copyright (C) 2022 University of California
44
//
55
// BOINC is free software; you can redistribute it and/or modify it
66
// under the terms of the GNU Lesser General Public License
@@ -26,6 +26,8 @@
2626
#include <unistd.h>
2727
#include <string>
2828
#include <locale.h>
29+
#include <sys/sysctl.h>
30+
#include <mach/mach.h>
2931

3032
#if SHOW_TIMING
3133
#include <Carbon/Carbon.h>
@@ -167,3 +169,44 @@ int procinfo_setup(PROC_MAP& pm) {
167169
setlocale(LC_ALL, old_locale.c_str());
168170
return 0;
169171
}
172+
173+
// get total user-mode CPU time
174+
//
175+
// From usr/include/mach/processor_info.h:
176+
// struct processor_cpu_load_info { /* number of ticks while running... */
177+
// unsigned int cpu_ticks[CPU_STATE_MAX]; /* ... in the given mode */
178+
// };
179+
//
180+
double total_cpu_time() {
181+
static bool first = true;
182+
natural_t processorCount = 0;
183+
processor_cpu_load_info_t cpuLoad;
184+
mach_msg_type_number_t processorMsgCount;
185+
static double scale;
186+
uint64_t totalUserTime = 0;
187+
188+
if (first) {
189+
first = false;
190+
long hz = sysconf(_SC_CLK_TCK);
191+
scale = 1./hz;
192+
}
193+
194+
kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &processorCount, (processor_info_array_t *)&cpuLoad, &processorMsgCount);
195+
196+
if (err != KERN_SUCCESS) {
197+
return 0.0;
198+
}
199+
200+
for (natural_t i = 0; i < processorCount; i++) {
201+
// Calc user and nice CPU usage, with guards against 32-bit overflow
202+
// (values are natural_t)
203+
uint64_t user = 0, nice = 0;
204+
205+
user = cpuLoad[i].cpu_ticks[CPU_STATE_USER];
206+
nice = cpuLoad[i].cpu_ticks[CPU_STATE_NICE];
207+
208+
totalUserTime = totalUserTime + user + nice;
209+
}
210+
211+
return totalUserTime * scale;
212+
}

lib/procinfo_unix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of BOINC.
22
// http://boinc.berkeley.edu
3-
// Copyright (C) 2008 University of California
3+
// Copyright (C) 2022 University of California
44
//
55
// BOINC is free software; you can redistribute it and/or modify it
66
// under the terms of the GNU Lesser General Public License

0 commit comments

Comments
 (0)