2008-08-06 18:36:30 +00:00
|
|
|
// This file is part of BOINC.
|
2006-09-19 10:40:24 +00:00
|
|
|
// http://boinc.berkeley.edu
|
2022-08-10 10:28:44 +00:00
|
|
|
// Copyright (C) 2022 University of California
|
2006-09-19 10:40:24 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
|
|
// under the terms of the GNU Lesser General Public License
|
|
|
|
// as published by the Free Software Foundation,
|
|
|
|
// either version 3 of the License, or (at your option) any later version.
|
2006-09-19 10:40:24 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is distributed in the hope that it will be useful,
|
2006-09-19 10:40:24 +00:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
2006-09-19 10:40:24 +00:00
|
|
|
|
2006-09-28 01:30:58 +00:00
|
|
|
#define SHOW_TIMING 0
|
|
|
|
|
2006-09-19 10:40:24 +00:00
|
|
|
#include "config.h"
|
2009-02-26 00:23:23 +00:00
|
|
|
#include <cstdio>
|
2006-09-19 10:40:24 +00:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
2015-01-12 05:26:10 +00:00
|
|
|
#include <unistd.h>
|
2020-08-21 12:21:14 +00:00
|
|
|
#include <string>
|
|
|
|
#include <locale.h>
|
2022-08-09 09:22:53 +00:00
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <mach/mach.h>
|
2006-09-28 01:30:58 +00:00
|
|
|
|
|
|
|
#if SHOW_TIMING
|
|
|
|
#include <Carbon/Carbon.h>
|
2010-06-16 02:10:23 +00:00
|
|
|
#include "client_msgs.h"
|
2006-09-28 01:30:58 +00:00
|
|
|
#endif
|
2006-09-19 10:40:24 +00:00
|
|
|
|
2012-07-18 08:49:27 +00:00
|
|
|
#include "error_numbers.h"
|
2012-08-11 05:47:18 +00:00
|
|
|
#include "procinfo.h"
|
|
|
|
|
2018-07-11 10:59:34 +00:00
|
|
|
#include "mac_branding.h"
|
2010-04-13 08:52:50 +00:00
|
|
|
|
2018-07-11 10:59:34 +00:00
|
|
|
using std::vector;
|
2006-09-25 10:49:39 +00:00
|
|
|
|
2007-02-20 01:39:26 +00:00
|
|
|
// build table of all processes in system
|
|
|
|
//
|
2011-09-02 17:45:29 +00:00
|
|
|
int procinfo_setup(PROC_MAP& pm) {
|
2010-02-15 01:00:32 +00:00
|
|
|
int pid = getpid();
|
2007-02-20 01:39:26 +00:00
|
|
|
FILE* fd;
|
2006-09-19 10:40:24 +00:00
|
|
|
PROCINFO p;
|
2007-02-20 01:39:26 +00:00
|
|
|
int c, real_mem, virtual_mem, hours;
|
2009-06-12 00:42:09 +00:00
|
|
|
char* lf;
|
2010-04-13 08:52:50 +00:00
|
|
|
static long iBrandID = -1;
|
2020-08-21 12:21:14 +00:00
|
|
|
std::string old_locale;
|
2014-07-08 07:16:12 +00:00
|
|
|
|
2018-07-11 10:59:34 +00:00
|
|
|
// For branded installs, the Mac installer put a branding file in our data directory
|
|
|
|
FILE *f = fopen("/Library/Application Support/BOINC Data/Branding", "r");
|
|
|
|
if (f) {
|
|
|
|
fscanf(f, "BrandId=%ld\n", &iBrandID);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
if ((iBrandID < 0) || (iBrandID > (NUMBRANDS-1))) {
|
|
|
|
iBrandID = 0;
|
2010-04-13 08:52:50 +00:00
|
|
|
}
|
2007-02-20 01:39:26 +00:00
|
|
|
|
2006-09-28 01:30:58 +00:00
|
|
|
#if SHOW_TIMING
|
|
|
|
UnsignedWide start, end, elapsed;
|
2006-09-19 10:40:24 +00:00
|
|
|
|
2006-09-28 01:30:58 +00:00
|
|
|
start = UpTime();
|
|
|
|
#endif
|
|
|
|
|
2007-02-20 01:39:26 +00:00
|
|
|
// Some values of possible interest available from 'ps' command:
|
|
|
|
// %cpu percentage cpu usage (alias pcpu)
|
|
|
|
// %mem percentage memory usage (alias pmem)
|
2009-04-09 10:41:11 +00:00
|
|
|
// command command (executable name)
|
2007-02-20 01:39:26 +00:00
|
|
|
// majflt total page faults
|
|
|
|
// minflt total page reclaims
|
|
|
|
// nswap total swaps in/out
|
|
|
|
// pagein pageins (same as majflt)
|
|
|
|
// pid process ID
|
|
|
|
// ppid parent process ID
|
|
|
|
// poip pageouts in progress
|
2010-09-30 06:45:45 +00:00
|
|
|
// pri scheduling priority
|
2007-02-20 01:39:26 +00:00
|
|
|
// rss resident set size in Kbytes
|
|
|
|
// time accumulated cpu time, user + system
|
|
|
|
// vsz virtual size in Kbytes
|
|
|
|
//
|
|
|
|
// Unfortunately, the selectors majflt, minflt, pagein do not work on OS X,
|
|
|
|
// and ps does not return kernel time separately from user time.
|
|
|
|
//
|
|
|
|
// Earlier versions of procinf_mac.C launched a small helper application
|
|
|
|
// AppStats using a bi-directional pipe. AppStats used mach ports to get
|
|
|
|
// all the information, including page fault counts, kernel and user times.
|
|
|
|
// In order to use mach ports, AppStats must run setuid root.
|
|
|
|
//
|
|
|
|
// But these three items are not actually used (page fault counts aren't
|
|
|
|
// available from Windows either) so we have reverted to using the ps
|
|
|
|
// utility, even though it takes more cpu time than AppStats did.
|
|
|
|
// This eliminates the need to install our own application which runs setuid
|
|
|
|
// root; this was perceived by some users as a security risk.
|
|
|
|
|
2014-07-08 07:16:12 +00:00
|
|
|
// Under OS 10.8.x (only) ps writes a spurious warning to stderr if called
|
|
|
|
// from a process that has the DYLD_LIBRARY_PATH environment variable set.
|
|
|
|
// "env -i command" prevents the command from inheriting the caller's
|
|
|
|
// environment, which avoids the spurious warning.
|
2014-11-15 10:54:56 +00:00
|
|
|
fd = popen("env -i ps -axcopid,ppid,rss,vsz,pagein,time,command", "r");
|
2010-08-31 10:35:42 +00:00
|
|
|
if (!fd) return ERR_FOPEN;
|
2007-02-20 01:39:26 +00:00
|
|
|
|
|
|
|
// Skip over the header line
|
|
|
|
do {
|
|
|
|
c = fgetc(fd);
|
|
|
|
if (c == EOF) {
|
|
|
|
pclose(fd);
|
2010-08-31 10:35:42 +00:00
|
|
|
return ERR_GETS;
|
2006-09-28 08:13:53 +00:00
|
|
|
}
|
2007-02-20 01:39:26 +00:00
|
|
|
} while (c != '\n');
|
2006-09-28 01:30:58 +00:00
|
|
|
|
2021-10-01 07:36:00 +00:00
|
|
|
// Ensure %lf works correctly if called from non-English Manager
|
2020-08-21 12:21:14 +00:00
|
|
|
old_locale = setlocale(LC_ALL, NULL);
|
|
|
|
setlocale(LC_ALL, "C");
|
|
|
|
|
2006-09-28 08:13:53 +00:00
|
|
|
while (1) {
|
2011-10-19 07:49:23 +00:00
|
|
|
p.clear();
|
2014-11-15 10:54:56 +00:00
|
|
|
c = fscanf(fd, "%d%d%d%d%lu%d:%lf ",
|
2011-02-22 23:11:34 +00:00
|
|
|
&p.id,
|
|
|
|
&p.parentid,
|
|
|
|
&real_mem,
|
|
|
|
&virtual_mem,
|
|
|
|
&p.page_fault_count,
|
|
|
|
&hours,
|
|
|
|
&p.user_time
|
|
|
|
);
|
2007-02-20 01:39:26 +00:00
|
|
|
if (c < 7) break;
|
2009-04-10 01:09:58 +00:00
|
|
|
if (fgets(p.command, sizeof(p.command) , fd) == NULL) break;
|
2009-06-12 00:42:09 +00:00
|
|
|
lf = strchr(p.command, '\n');
|
|
|
|
if (lf) *lf = '\0'; // Strip trailing linefeed
|
2007-02-20 01:39:26 +00:00
|
|
|
p.working_set_size = (double)real_mem * 1024.;
|
|
|
|
p.swap_size = (double)virtual_mem * 1024.;
|
|
|
|
p.user_time += 60. * (float)hours;
|
2010-02-16 01:00:35 +00:00
|
|
|
p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc"));
|
2014-10-21 10:00:09 +00:00
|
|
|
// Ideally, we should count ScreenSaverEngine.app as a BOINC process
|
|
|
|
// only if BOINC is set as the screensaver. We could set a flag in
|
|
|
|
// the client when the get_screensaver_tasks rpc is called, but that
|
|
|
|
// would not be 100% reliable for several reasons.
|
|
|
|
if (strcasestr(p.command, "screensaverengine")) p.is_boinc_app = true;
|
2014-11-15 10:54:56 +00:00
|
|
|
|
|
|
|
// We do not mark Mac processes as low priority because some processes
|
|
|
|
// (e.g., Finder) change priority frequently, which would cause
|
|
|
|
// procinfo_non_boinc() and ACTIVE_TASK_SET::get_memory_usage() to get
|
|
|
|
// incorrect results for the % CPU used.
|
|
|
|
p.is_low_priority = false;
|
2010-04-13 08:52:50 +00:00
|
|
|
|
2019-11-08 09:10:30 +00:00
|
|
|
if (strcasestr(p.command, brandName[iBrandID])) {
|
2018-07-11 10:59:34 +00:00
|
|
|
p.is_boinc_app = true;
|
2010-04-13 08:52:50 +00:00
|
|
|
}
|
2018-07-11 10:59:34 +00:00
|
|
|
|
2011-09-02 17:45:29 +00:00
|
|
|
pm.insert(std::pair<int, PROCINFO>(p.id, p));
|
2006-09-19 10:40:24 +00:00
|
|
|
}
|
2007-02-20 01:39:26 +00:00
|
|
|
|
|
|
|
pclose(fd);
|
2006-09-28 08:13:53 +00:00
|
|
|
|
2006-09-28 01:30:58 +00:00
|
|
|
#if SHOW_TIMING
|
|
|
|
end = UpTime();
|
|
|
|
elapsed = AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(end, start));
|
2007-02-20 01:39:26 +00:00
|
|
|
msg_printf(NULL, MSG_INFO, "elapsed time = %llu, m_swap = %lf\n", elapsed, gstate.host_info.m_swap);
|
2006-09-28 01:30:58 +00:00
|
|
|
#endif
|
2006-09-25 10:49:39 +00:00
|
|
|
|
2011-09-02 17:45:29 +00:00
|
|
|
find_children(pm);
|
2020-08-21 12:21:14 +00:00
|
|
|
|
|
|
|
setlocale(LC_ALL, old_locale.c_str());
|
2006-09-25 10:49:39 +00:00
|
|
|
return 0;
|
2006-09-19 10:40:24 +00:00
|
|
|
}
|
2022-08-09 09:22:53 +00:00
|
|
|
|
|
|
|
// 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() {
|
2022-08-10 07:20:00 +00:00
|
|
|
static bool first = true;
|
|
|
|
natural_t processorCount = 0;
|
2022-08-09 09:22:53 +00:00
|
|
|
processor_cpu_load_info_t cpuLoad;
|
|
|
|
mach_msg_type_number_t processorMsgCount;
|
|
|
|
static double scale;
|
|
|
|
uint64_t totalUserTime = 0;
|
|
|
|
|
2022-08-10 10:28:44 +00:00
|
|
|
if (first) {
|
2022-08-10 07:20:00 +00:00
|
|
|
first = false;
|
2022-08-09 09:22:53 +00:00
|
|
|
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;
|
|
|
|
}
|