From 6cb3e3b8a5c0e9d755cf731d1c259aae5f3f4d33 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Tue, 9 Aug 2022 02:22:53 -0700 Subject: [PATCH 1/4] Mac: compute non-BOINC CPU usage in a more accurate way --- client/app.cpp | 2 +- lib/procinfo_mac.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/client/app.cpp b/client/app.cpp index db9bcecc74..bcb86a9cb7 100644 --- a/client/app.cpp +++ b/client/app.cpp @@ -486,7 +486,7 @@ 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) // diff --git a/lib/procinfo_mac.cpp b/lib/procinfo_mac.cpp index 4438de3d28..8bdb405955 100644 --- a/lib/procinfo_mac.cpp +++ b/lib/procinfo_mac.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #if SHOW_TIMING #include @@ -167,3 +169,42 @@ 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 natural_t processorCount = 0; + processor_cpu_load_info_t cpuLoad; + mach_msg_type_number_t processorMsgCount; + static double scale; + uint64_t totalUserTime = 0; + + if (processorCount == 0) { + 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; +} From 7b49e10737122da3becda4483cc68df01b4b9b08 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 10 Aug 2022 00:20:00 -0700 Subject: [PATCH 2/4] Mac: make initialization logic easier to understand --- lib/procinfo_mac.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/procinfo_mac.cpp b/lib/procinfo_mac.cpp index 8bdb405955..5e5688913e 100644 --- a/lib/procinfo_mac.cpp +++ b/lib/procinfo_mac.cpp @@ -178,13 +178,15 @@ int procinfo_setup(PROC_MAP& pm) { // }; // double total_cpu_time() { - static natural_t processorCount = 0; + 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 (processorCount == 0) { + if (!first) { + first = false; long hz = sysconf(_SC_CLK_TCK); scale = 1./hz; } From 63f3acc114794945a94106219e177c4a1aecf6f8 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 10 Aug 2022 00:33:53 -0700 Subject: [PATCH 3/4] If new total_cpu_time() method has error, revert to the old method --- client/app.cpp | 86 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/client/app.cpp b/client/app.cpp index bcb86a9cb7..72feb725c9 100644 --- a/client/app.cpp +++ b/client/app.cpp @@ -488,49 +488,53 @@ void ACTIVE_TASK_SET::get_memory_usage() { #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 From 31352444d2c68075c74d094ee4d86360d13d87a3 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 10 Aug 2022 03:28:44 -0700 Subject: [PATCH 4/4] Fix typos, update copyright dates --- client/app.cpp | 2 +- lib/procinfo_mac.cpp | 4 ++-- lib/procinfo_unix.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/app.cpp b/client/app.cpp index 72feb725c9..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 diff --git a/lib/procinfo_mac.cpp b/lib/procinfo_mac.cpp index 5e5688913e..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 @@ -185,7 +185,7 @@ double total_cpu_time() { static double scale; uint64_t totalUserTime = 0; - if (!first) { + if (first) { first = false; long hz = sysconf(_SC_CLK_TCK); scale = 1./hz; 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