1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2018 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
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
#define SHOW_TIMING 0
#include "config.h"
#include <cstdio>
#include <ctype.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#if SHOW_TIMING
#include <Carbon/Carbon.h>
#include "client_msgs.h"
#endif
#include "error_numbers.h"
#include "procinfo.h"
#include "mac_branding.h"
using std::vector;
// build table of all processes in system
//
int procinfo_setup(PROC_MAP& pm) {
int pid = getpid();
FILE* fd;
PROCINFO p;
int c, real_mem, virtual_mem, hours;
char* lf;
static long iBrandID = -1;
// 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;
}
#if SHOW_TIMING
UnsignedWide start, end, elapsed;
start = UpTime();
#endif
// Some values of possible interest available from 'ps' command:
// %cpu percentage cpu usage (alias pcpu)
// %mem percentage memory usage (alias pmem)
// command command (executable name)
// 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
// pri scheduling priority
// 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.
// 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.
fd = popen("env -i ps -axcopid,ppid,rss,vsz,pagein,time,command", "r");
if (!fd) return ERR_FOPEN;
// Skip over the header line
do {
c = fgetc(fd);
if (c == EOF) {
pclose(fd);
return ERR_GETS;
}
} while (c != '\n');
while (1) {
p.clear();
c = fscanf(fd, "%d%d%d%d%lu%d:%lf ",
&p.id,
&p.parentid,
&real_mem,
&virtual_mem,
&p.page_fault_count,
&hours,
&p.user_time
);
if (c < 7) break;
if (fgets(p.command, sizeof(p.command) , fd) == NULL) break;
lf = strchr(p.command, '\n');
if (lf) *lf = '\0'; // Strip trailing linefeed
p.working_set_size = (double)real_mem * 1024.;
p.swap_size = (double)virtual_mem * 1024.;
p.user_time += 60. * (float)hours;
p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc"));
// 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;
// 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;
if (!strcasestr(p.command, brandName[iBrandID])) {
p.is_boinc_app = true;
}
pm.insert(std::pair<int, PROCINFO>(p.id, p));
}
pclose(fd);
#if SHOW_TIMING
end = UpTime();
elapsed = AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(end, start));
msg_printf(NULL, MSG_INFO, "elapsed time = %llu, m_swap = %lf\n", elapsed, gstate.host_info.m_swap);
#endif
find_children(pm);
return 0;
}
|