From 6b26086f7c064603c9bda1b11bef75dbbeb13b1d Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Thu, 28 Sep 2006 01:30:58 +0000 Subject: [PATCH] *** empty log message *** svn path=/trunk/boinc/; revision=11207 --- checkin_notes | 13 +++++ client/app_control.C | 2 + client/app_stats_mac.C | 44 +++++++++++++-- lib/procinfo_mac.C | 124 ++++++++++++++++++++++++++++++++++------- 4 files changed, 159 insertions(+), 24 deletions(-) diff --git a/checkin_notes b/checkin_notes index b8949560fe..4d0d5e9397 100755 --- a/checkin_notes +++ b/checkin_notes @@ -10507,3 +10507,16 @@ Kevin 27 Sept 2006 clientgui/ sg_BoincSimpleGUI.cpp sg_ProgressBar.cpp/h + +Charlie 27 Sept 2006 + - Mac: Use full-duplex pipes s AppStats helper application can stay open + for better efficiency. + - Mac: Update host_info.m_swap on each PROCINFO update. + - Comment out bogus memory usage exceeded message if mem_usage_debug log + flag is set. + + client/ + app_control.C + app_stats_mac.C + lib/ + procinfo_mac.C diff --git a/client/app_control.C b/client/app_control.C index 7cf6087942..8e2ea29de3 100644 --- a/client/app_control.C +++ b/client/app_control.C @@ -469,6 +469,7 @@ bool ACTIVE_TASK::check_max_disk_exceeded() { bool ACTIVE_TASK::check_max_mem_exceeded() { if (max_mem_usage != 0 && procinfo.working_set_size > max_mem_usage) { +#if 0 if (log_flags.mem_usage_debug) { msg_printf( result->project, MSG_INFO, @@ -477,6 +478,7 @@ bool ACTIVE_TASK::check_max_mem_exceeded() { ); } //abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum memory usage exceeded"); +#endif } return false; } diff --git a/client/app_stats_mac.C b/client/app_stats_mac.C index f91536fde2..ad16f46b81 100644 --- a/client/app_stats_mac.C +++ b/client/app_stats_mac.C @@ -81,12 +81,14 @@ using std::vector; +static int get_boinc_proc_info(int my_pid, int boinc_pid); static int build_proc_list (vector& pi, int boinc_pid); static void output_child_totals(PROCINFO& pinfo); static boolean_t appstats_task_update(task_t a_task, vector& piv); static void find_all_descendants(vector& piv, int pid, int rlvl); static void add_child_totals(PROCINFO& pi, vector& piv, int pid, int rlvl); //static void add_others(PROCINFO&, std::vector&); +static void sig_pipe(int signo); #ifdef _DEBUG static void print_procinfo(PROCINFO& pinfo); @@ -102,9 +104,7 @@ static void vm_size_render(unsigned long long a_size); int main(int argc, char** argv) { int boinc_pid, my_pid; int retval; - vector piv; - PROCINFO child_total; - unsigned int i; + char buf[256]; if (geteuid() != 0) // This must be run setuid root return EACCES; @@ -114,7 +114,35 @@ int main(int argc, char** argv) { if (argc == 2) boinc_pid = atoi(argv[1]); // Pass in any desired valid pid for testing + + if (signal(SIGPIPE, sig_pipe) == SIG_ERR) { + fprintf(stderr, "signal error"); + return 0; + } + setbuf(stdin, 0); + setbuf(stdout, 0); + + while (1) { + if (fgets(buf, sizeof(buf), stdin) == NULL) + return 0; + + if (feof(stdin)) + return 0; + + retval = get_boinc_proc_info(my_pid, boinc_pid); + } + + return 0; +} + +static int get_boinc_proc_info(int my_pid, int boinc_pid) { + int retval; + vector piv; + PROCINFO child_total; + unsigned int i; + + retval = build_proc_list(piv, boinc_pid); if (retval) return retval; @@ -140,14 +168,14 @@ int main(int argc, char** argv) { } } + memset(&child_total, 0, sizeof(child_total)); #if 0 #ifdef _DEBUG printf("\n\nSumming info for all other processes\n"); #endif - memset(&child_total, 0, sizeof(child_total)); add_others(child_total, piv); - output_child_totals(child_total); #endif + output_child_totals(child_total); // zero pid signals end of data return 0; } @@ -157,6 +185,7 @@ static void output_child_totals(PROCINFO& pinfo) { printf("%d %d %.0lf %.0lf %lu %lf %lf\n", pinfo.id, pinfo.parentid, pinfo.working_set_size, pinfo.swap_size, pinfo.page_fault_count, pinfo.user_time, pinfo.kernel_time); +// fflush(stdout); } static int build_proc_list (vector& pi, int boinc_pid) { @@ -564,6 +593,11 @@ static void add_others(PROCINFO& pi, vector& piv) { } #endif +static void sig_pipe(int signo) +{ + exit(1); +} + #ifdef _DEBUG static void print_procinfo(PROCINFO& pinfo) { unsigned long long rsize, vsize; diff --git a/lib/procinfo_mac.C b/lib/procinfo_mac.C index 5fc89c1657..4dc7823710 100644 --- a/lib/procinfo_mac.C +++ b/lib/procinfo_mac.C @@ -20,12 +20,22 @@ // procinfo_mac.C // +#define SHOW_TIMING 0 + #include "config.h" #include #include +#include #include #include +#include +#include +#include + +#if SHOW_TIMING +#include +#endif #include "procinfo.h" #include "client_msgs.h" @@ -57,25 +67,54 @@ using std::vector; // This code doesn't use PROCINFO.is_boinc_app, but we set it to be consistent // with the code for other platforms. +static int bidirectional_popen(char *path, int *fd); int procinfo_setup(vector& pi) { char appstats_path[100]; - FILE* fd; + static int fd[2] = {0, 0}; PROCINFO p; - int c; - unsigned int i; - double m_swap; + int c, result, retry = 0; + char buf[256]; + struct statfs fs_info; +#if SHOW_TIMING + UnsignedWide start, end, elapsed; - sprintf(appstats_path, "%s/%s", SWITCHER_DIR, APP_STATS_FILE_NAME); - fd = popen(appstats_path, "r"); - if (!fd) return 0; + start = UpTime(); +#endif + + if (fd[0] == 0) { + // Launch AppStats helper application with a bidirectional pipe +RELAUNCH: + sprintf(appstats_path, "%s/%s", SWITCHER_DIR, APP_STATS_FILE_NAME); + result = bidirectional_popen(appstats_path, fd); +#if SHOW_TIMING + msg_printf(NULL, MSG_ERROR, "bidirectional_popen returned %d\n", result); +#endif + if (result) return 0; + retry = 0; // Reset retry counter on success + } while (1) { + c = write(fd[0], "\n", 1); // Request a set of process info from AppStats helper application + if (c < 0) // AppStats application quit + if (++retry == 1) + goto RELAUNCH; + memset(&p, 0, sizeof(p)); - c = fscanf(fd, "%d %d %lf %lf %lu %lf %lf\n", + for (unsigned int i=0; i& pi) { p.page_fault_count, p.user_time, p.kernel_time ); } + + statfs(".", &fs_info); + gstate.host_info.m_swap = (double)fs_info.f_bsize * (double)fs_info.f_bfree; } - pclose(fd); - - // The sysctl(vm.vmmeter) function doesn't work on OS X, so hostinfo_unix.C - // function HOST_INFO::get_host_info() can't get the total swap space. - // It is easily calculated here, so fill in the value of host_info.m_swap. - m_swap = 0; - for (i=0; i& piv) { } } +#if 0 + // the following is not useful because most OSs don't + // move idle processes out of RAM, so physical memory is always full + // void procinfo_other(PROCINFO& pi, vector& piv) { // AppStat returned total for all other processes as a single PROCINFO // struct with id field set to zero. memset(&pi, 0, sizeof(pi)); procinfo_app(pi, piv); } +#endif + +static int bidirectional_popen(char *path, int *fd) { + pid_t pid; + char *appname; + + appname = strrchr(path, '/'); + if (! appname) + appname = path; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { /* only need a single stream pipe */ + msg_printf(NULL, MSG_ERROR, "%s: pipe error %d: %s\n", appname, errno, strerror(errno)); + return ERR_SOCKET; + } + + if ( (pid = fork()) < 0) { + close(fd[0]); + close(fd[1]); + msg_printf(NULL, MSG_ERROR, "%s: fork error\n", appname); + return ERR_FORK; + } + else if (pid > 0) { /* parent */ + close(fd[1]); + } else { /* child */ + close(fd[0]); + if (fd[1] != STDIN_FILENO) { + if (dup2(fd[1], STDIN_FILENO) != STDIN_FILENO) { + fprintf(stderr, "dup2 error to stdin"); + exit (1); + } + } + if (fd[1] != STDOUT_FILENO) { + if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { + fprintf(stderr, "dup2 error to stdout"); + exit (1); + } + } + if (execl(path, appname, NULL) < 0) { + printf("-1\n"); + fprintf(stderr, "execl error"); + } + } + + return 0; +}