diff --git a/client/app.cpp b/client/app.cpp index db9bcecc74..8bda083a1a 100644 --- a/client/app.cpp +++ b/client/app.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2008 University of California +// Copyright (C) 2022 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -486,51 +486,55 @@ void ACTIVE_TASK_SET::get_memory_usage() { } } -#if defined(__linux__) || defined(_WIN32) +#if defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // compute non_boinc_cpu_usage - // Improved version for systems where we can get total CPU (Win, Linux) + // Improved version for systems where we can get total CPU (Win, Linux, Mac) // 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) { - //procinfo_show(pm); - msg_printf(NULL, MSG_INFO, - "[mem_usage] All others: WS %.2fMB, swap %.2fMB, user %.3fs, kernel %.3fs", - pi.working_set_size/MEGA, pi.swap_size/MEGA, - pi.user_time, pi.kernel_time - ); - } - double new_cpu_time = pi.user_time + pi.kernel_time; - if (!first) { - non_boinc_cpu_usage = (new_cpu_time - last_cpu_time)/(diff*gstate.host_info.p_ncpus); - // 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; + double total_cpu_time_now = total_cpu_time(); + if (total_cpu_time_now != 0.0) { // total_cpu_time() returns 0.0 on error + double nbrc = total_cpu_time_now - 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 #endif + { + // compute non_boinc_cpu_usage the old way + // + // 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) { + //procinfo_show(pm); + msg_printf(NULL, MSG_INFO, + "[mem_usage] All others: WS %.2fMB, swap %.2fMB, user %.3fs, kernel %.3fs", + pi.working_set_size/MEGA, pi.swap_size/MEGA, + pi.user_time, pi.kernel_time + ); + } + double new_cpu_time = pi.user_time + pi.kernel_time; + if (!first) { + non_boinc_cpu_usage = (new_cpu_time - last_cpu_time)/(diff*gstate.host_info.p_ncpus); + // 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; + } if (!first) { if (log_flags.mem_usage_debug) { @@ -542,7 +546,7 @@ void ACTIVE_TASK_SET::get_memory_usage() { first = false; } -#endif +#endif // ! defined (SIM) // There's a new trickle file. // Move it from slot dir to project dir diff --git a/lib/procinfo_mac.cpp b/lib/procinfo_mac.cpp index 4438de3d28..620645f123 100644 --- a/lib/procinfo_mac.cpp +++ b/lib/procinfo_mac.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2020 University of California +// Copyright (C) 2022 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -26,6 +26,8 @@ #include #include #include +#include +#include #if SHOW_TIMING #include @@ -167,3 +169,44 @@ int procinfo_setup(PROC_MAP& pm) { setlocale(LC_ALL, old_locale.c_str()); return 0; } + +// get total user-mode CPU time +// +// From usr/include/mach/processor_info.h: +// struct processor_cpu_load_info { /* number of ticks while running... */ +// unsigned int cpu_ticks[CPU_STATE_MAX]; /* ... in the given mode */ +// }; +// +double total_cpu_time() { + static bool first = true; + natural_t processorCount = 0; + processor_cpu_load_info_t cpuLoad; + mach_msg_type_number_t processorMsgCount; + static double scale; + uint64_t totalUserTime = 0; + + if (first) { + first = false; + long hz = sysconf(_SC_CLK_TCK); + scale = 1./hz; + } + + kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &processorCount, (processor_info_array_t *)&cpuLoad, &processorMsgCount); + + if (err != KERN_SUCCESS) { + return 0.0; + } + + for (natural_t i = 0; i < processorCount; i++) { + // Calc user and nice CPU usage, with guards against 32-bit overflow + // (values are natural_t) + uint64_t user = 0, nice = 0; + + user = cpuLoad[i].cpu_ticks[CPU_STATE_USER]; + nice = cpuLoad[i].cpu_ticks[CPU_STATE_NICE]; + + totalUserTime = totalUserTime + user + nice; + } + + return totalUserTime * scale; +} diff --git a/lib/procinfo_unix.cpp b/lib/procinfo_unix.cpp index 611e2af55f..1509062611 100644 --- a/lib/procinfo_unix.cpp +++ b/lib/procinfo_unix.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2008 University of California +// Copyright (C) 2022 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License