diff options
Diffstat (limited to 'src/pmdas/process')
-rw-r--r-- | src/pmdas/process/GNUmakefile | 65 | ||||
-rwxr-xr-x | src/pmdas/process/Install | 28 | ||||
-rw-r--r-- | src/pmdas/process/README | 74 | ||||
-rwxr-xr-x | src/pmdas/process/Remove | 41 | ||||
-rw-r--r-- | src/pmdas/process/help | 38 | ||||
-rw-r--r-- | src/pmdas/process/pmns | 26 | ||||
-rw-r--r-- | src/pmdas/process/process.c | 413 | ||||
-rw-r--r-- | src/pmdas/process/process.conf | 11 | ||||
-rw-r--r-- | src/pmdas/process/root | 16 |
9 files changed, 712 insertions, 0 deletions
diff --git a/src/pmdas/process/GNUmakefile b/src/pmdas/process/GNUmakefile new file mode 100644 index 0000000..b04c78f --- /dev/null +++ b/src/pmdas/process/GNUmakefile @@ -0,0 +1,65 @@ +# +# Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) +# for the portions of the code supporting the initial agent functionality. +# All rights reserved. +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General Public License +# for more details. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + + +IAM = process +DOMAIN = PROCESS +TARGETS = $(IAM) +CFILES = process.c +SCRIPTS = Install Remove +DFILES = README +LSRCFILES= $(SCRIPTS) pmns help root $(DFILES) process.conf + +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +PMCHART = $(PCP_VAR_DIR)/config/pmchart + +LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so $(TARGETS) \ + help.dir help.pag +LLDLIBS = $(PCP_PMDALIB) + +default: build-me + +include $(BUILDRULES) + +# This PMDA is only valid on platforms with a procfs +# It is also superceded by the cgroup functionality on Linux +# thus has not been built for some time, for reference only. +#build-me: $(TARGETS) +#install install_pcp : default +# $(INSTALL) -m 755 -d $(PMDADIR) +# $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) +# $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) +# $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) +# $(INSTALL) -m 644 process.conf $(PMDADIR)/process.conf +#else +build-me: +install: +#endif + +$(IAM): $(OBJECTS) + +default_pcp : default + +install_pcp : install + +process.o: domain.h + +domain.h: ../../pmns/stdpmid + $(DOMAIN_MAKERULE) diff --git a/src/pmdas/process/Install b/src/pmdas/process/Install new file mode 100755 index 0000000..7bc54b9 --- /dev/null +++ b/src/pmdas/process/Install @@ -0,0 +1,28 @@ +#! /bin/sh +# +# Copyright (c) 2001 Alan Bailey. All Rights Reserved. +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General Public License +# for more details. +# +# Install the process PMDA and/or PMNS +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=process +pmda_interface=2 +forced_restart=true + +pmdaSetup +pmdaInstall +exit 0 diff --git a/src/pmdas/process/README b/src/pmdas/process/README new file mode 100644 index 0000000..78579e8 --- /dev/null +++ b/src/pmdas/process/README @@ -0,0 +1,74 @@ +# +# Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) +# for the portions of the code supporting the initial agent functionality. +# All rights reserved. +# +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# + +Process PMDA +============ + +This PMDA monitors root processes to see if they are still running. +The processes that are monitored are stored in a config file, +and the PMDA returns the number of root processes with that name +running. In this way, you can check to see if the number of processes +is in a range, is 1, is 0, or some other combination. + +This source code was contributed by Alan Bailey (abailey@ncsa.uiuc.edu) +to the PCP open source project. + +Metrics +======= + +The file ./help contains descriptions for all of the metrics exported +by this PMDA. + +Once the PMDA has been installed, the following command will list all +the available metrics and their explanatory "help" text: + + $ pminfo -fT process + +Installation +============ + + + # cd $PCP_PMDAS_DIR/process + + + Check that there is no clash in the Performance Metrics Domain + defined in ./domain.h and the other PMDAs currently in use + ($PCP_PMCDCONF_PATH). If there is, edit ./domain.h + to choose another domain number. + + + Then simply use + + # ./Install + + and choose both the "collector" and "monitor" installation + configuration options -- everything else is automated. + + + Alternatively, to install just the Performance Metrics Name Space + for the process metrics on the local system, but not the process + PMDA (presumably because the local system is running PCP 1.x and + you wish to connect to a remote system where PCP 2.0 and the process + PMDA is running), make sure the Performance Metrics Domain defined + in ./domain.h matches the domain chosen for the process PMDA on the + remote system (check the second field in the corresponding line of the + $PCP_PMCDCONF_PATH file on the remote system), then + + # ./Install -N + +De-installation +=============== + + + Simply use + + # cd $PCP_PMDAS_DIR/process + # ./Remove + +Troubleshooting +=============== + + + After installing or restarting the agent, the PMCD log file + ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file + ($PCP_LOG_DIR/pmcd/process.log) should be checked for any warnings or + errors. diff --git a/src/pmdas/process/Remove b/src/pmdas/process/Remove new file mode 100755 index 0000000..b90a863 --- /dev/null +++ b/src/pmdas/process/Remove @@ -0,0 +1,41 @@ +#! /bin/sh +# +# Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) +# for the portions of the code supporting the initial agent functionality. +# All rights reserved. +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Remove the process PMDA +# + +# source the PCP configuration environment variables +. $PCP_DIR/etc/pcp.env + +# Get the common procedures and variable assignments +# +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +# The name of the PMDA +# +iam=process + +# Do it +# +pmdaSetup +pmdaRemove + +exit 0 diff --git a/src/pmdas/process/help b/src/pmdas/process/help new file mode 100644 index 0000000..acf2a37 --- /dev/null +++ b/src/pmdas/process/help @@ -0,0 +1,38 @@ +# +# Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) +# for the portions of the code supporting the initial agent functionality. +# All rights reserved. +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program 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 General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# process PMDA help file in the ASCII format +# +# lines beginning with a # are ignored +# lines beginning @ introduce a new entry of the form +# @ metric_name oneline-text +# help test goes +# here over multiple lines +# ... +# +# the metric_name is decoded against the default PMNS -- as a special case, +# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an +# instance domain identification, and the text describes the instance domain +# +# blank lines before the @ line are ignored +# + +@ process.running Tool for tracking running root processes +This tracks the number of running root processes for processes you define diff --git a/src/pmdas/process/pmns b/src/pmdas/process/pmns new file mode 100644 index 0000000..8df2327 --- /dev/null +++ b/src/pmdas/process/pmns @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) + * for the portions of the code supporting the initial agent functionality. + * All rights reserved. + * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Metrics for process PMDA + */ + +process { + running PROCESS:0:0 +} diff --git a/src/pmdas/process/process.c b/src/pmdas/process/process.c new file mode 100644 index 0000000..00f9d80 --- /dev/null +++ b/src/pmdas/process/process.c @@ -0,0 +1,413 @@ +/* + * The process PMDA + * + * This code monitors root processes to see if they are still + * running. The processes that are monitored are stored in a config file, + * and the PMDA returns the number of root processes with that name + * running. In this way, you can check to see if the number of processes + * is in a range, is 1, is 0, or some other combination. + * + * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) + * for the portions of the code supporting the initial agent functionality. + * All rights reserved. + * + * Copyright (c) 2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License + * for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "domain.h" +#include <ctype.h> +#include <dirent.h> +#include <sys/stat.h> + +/* + * Process PMDA + * + * Metrics + * process.running + * The number of root processes running for each name + * The process names are stored in + * PCP_VAR_DIR/pmdas/process/process.conf + */ + +static pmdaInstid *processes; + +static pmdaIndom indomtab[] = { +#define PROC_INDOM 0 + { PROC_INDOM, 0, NULL } +}; + +static pmdaMetric metrictab[] = { +/* process.running */ + { NULL, + { PMDA_PMID(0,0), PM_TYPE_DOUBLE, PROC_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0) }, }, +}; + +/* Variables needed for this file */ +static int *num_procs; +static struct stat file_change; +static int npidlist; +static int maxpidlist; +static int *pidlist; +static int isDSO = 1; +static char mypath[MAXPATHLEN]; + +/* Routines in this file */ +static void process_clear_config_info(void); +static void process_grab_config_info(void); +static void process_config_file_check(void); +static int process_refresh_pidlist(void); + +static void +process_config_file_check(void) +{ + struct stat statbuf; + static int last_error; + int sep = __pmPathSeparator(); + + snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "process.conf", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + if (stat(mypath, &statbuf) == -1) { + if (oserror() != last_error) { + last_error = oserror(); + __pmNotifyErr(LOG_WARNING, "stat failed on %s: %s\n", + mypath, pmErrStr(-oserror())); + } + } else { + last_error = 0; +#if defined(HAVE_ST_MTIME_WITH_E) + if (memcmp(&statbuf.st_mtime, &file_change.st_mtime, sizeof(statbuf.st_mtime)) != 0) +#elif defined(HAVE_ST_MTIME_WITH_SPEC) + if (memcmp(&statbuf.st_mtimespec, &file_change.st_mtimespec, sizeof(statbuf.st_mtimespec)) != 0) +#else + if (memcmp(&statbuf.st_mtim, &file_change.st_mtim, sizeof(statbuf.st_mtim)) != 0) +#endif + { + process_clear_config_info(); + process_grab_config_info(); + file_change = statbuf; + } + } +} + +/* + * This function is called when the config file needs to be read in + * again, so we can define new instances and such. This frees the + * previous memory, if any (on startup, there won't be any), and sets + * the two variables to NULL for fun. + */ +static void +process_clear_config_info(void) +{ + int i; + + /* Free the memory holding the process name */ + for (i = 0; i < indomtab[PROC_INDOM].it_numinst; i++) + free(processes[i].i_name); + + /* Free the processes structure */ + if (processes) + free(processes); + + /* Free the process counter structure */ + if (num_procs) + free(num_procs); + num_procs = NULL; + + indomtab[PROC_INDOM].it_set = processes = NULL; + indomtab[PROC_INDOM].it_numinst = 0; +} + +/* + * This routine opens the config file and stores the information in the + * processes structure. The processes structure must be reallocated as + * necessary, and also the num_procs structure needs to be reallocated + * as we define new processes. When all of that is done, we fill in the + * values in the indomtab structure, those being the number of instances + * and the pointer to the processes structure. + * + * A lot of this code was taken from the simple.c code, but in this + * case, I changed a lot of it to fit my purposes... + */ +static void +process_grab_config_info(void) +{ + FILE *fp; + char process_name[1024]; + char *q; + size_t size; + int process_number = 0; + int sep = __pmPathSeparator(); + + snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "process.conf", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + if ((fp = fopen(mypath, "r")) == NULL) { + __pmNotifyErr(LOG_ERR, "fopen on %s failed: %s\n", + mypath, pmErrStr(-oserror())); + if (processes != NULL) { + free(processes); + processes = NULL; + process_number = 0; + } + goto done; + } + + while (fgets(process_name, sizeof(process_name), fp) != NULL) { + if (process_name[0] == '#') + continue; + /* Remove the newline */ + if ((q = strchr(process_name, '\n')) != NULL) { + *q = '\0'; + } else { + /* This means the line was too long */ + __pmNotifyErr(LOG_WARNING, "line %d in config file too long\n", + process_number + 1); + } + size = (process_number + 1) * sizeof(pmdaInstid); + if ((processes = realloc(processes, size)) == NULL) + __pmNoMem("process", size, PM_FATAL_ERR); + processes[process_number].i_name = malloc(strlen(process_name) + 1); + strcpy(processes[process_number].i_name, process_name); + processes[process_number].i_inst = process_number; + process_number++; + } + fclose(fp); + +done: + if (processes == NULL) + __pmNotifyErr(LOG_WARNING, "\"process\" instance domain is empty"); + + indomtab[PROC_INDOM].it_set = processes; + indomtab[PROC_INDOM].it_numinst = process_number; + + num_procs = realloc(num_procs, (process_number)*sizeof(int)); +} + +/* + * This code refreshes the count of all the processes that we want to + * monitor. It does this by calling process_refresh_pidlist, which just + * grabs a list of all the running processes (as PIDs). We then loop + * through each of these processes, and check to see if it is a root + * process. If so, we then open up the /proc/<PID>/status file, + * and see what the process name is. If it is one of our special + * processes that we want to track, then we up the count for that + * process in num_procs. Then we're done. + */ +static void +process_refresh_pid_checks(void) +{ + int proc; + char proc_path[30]; + char cmd_line[200]; + FILE *fd; + int proc_name; + int item; + struct stat statbuf; + + process_refresh_pidlist(); + + /* Clear the variables */ + for (item = 0; item < indomtab[PROC_INDOM].it_numinst; item++) + num_procs[item] = 0; + + for (proc = 0; proc < npidlist; proc++) { + sprintf(proc_path, "/proc/%d/status", pidlist[proc]); + if (stat(proc_path, &statbuf) == -1) { + /* We can't stat it, let's assume the process isn't running anymore */ + continue; + } else { + /* This checks to make sure the process is a root process */ + if (statbuf.st_uid != 0) { + continue; + } + } + + if ((fd = fopen(proc_path, "r")) != NULL) { + /* + * matching process by name is platform specific ... this code + * works for Linux when /proc/<pid>/status is ascii and the + * first line is of the form: + * Name: <cmdname> + */ + if (fgets(cmd_line, sizeof(cmd_line), fd) == NULL) { + /* + * not expected, but not a disaster ... we'll just not try + * to match this one + */ + fclose(fd); + continue; + } + fclose(fd); + + for (proc_name = 0; proc_name < indomtab[PROC_INDOM].it_numinst; proc_name++) { + if (strstr(cmd_line, (processes[proc_name]).i_name)) { + (num_procs[proc_name])++; + } + } + } + } +} + +/* + * Read in the list of all processes running. + */ +int +process_refresh_pidlist() +{ + DIR *dirp = opendir("/proc"); + struct dirent *dp; + + if (dirp == NULL) + return -oserror(); + + npidlist = 0; + while ((dp = readdir(dirp)) != (struct dirent *)NULL) { + if (isdigit((int)dp->d_name[0])) { + if (npidlist >= maxpidlist) { + maxpidlist += 16; + pidlist = (int *)realloc(pidlist, maxpidlist * sizeof(int)); + } + pidlist[npidlist++] = atoi(dp->d_name); + } + } + closedir(dirp); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "process_refresh_pidlist: found %d PIDs:", npidlist); + if (npidlist > 0) { + fprintf(stderr, " %d", pidlist[0]); + if (npidlist > 1) { + fprintf(stderr, " %d", pidlist[1]); + if (npidlist == 3) + fprintf(stderr, " %d", pidlist[2]); + else if (npidlist == 4) + fprintf(stderr, " %d %d", pidlist[2], pidlist[3]); + else if (npidlist > 4) + fprintf(stderr, " ... %d %d", pidlist[npidlist-2], + pidlist[npidlist-1]); + } + } + fprintf(stderr, "\n"); + } +#endif + + return npidlist; +} + +static int +process_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) +{ + /* + * This is the wrapper over the pmdaFetch routine, to handle the problem + * of varying instance domains. All this does is check to see if the + * config file has been updated, and update the instance domain if so, + * and refresh the pid count for the processes. + */ + process_config_file_check(); + process_refresh_pid_checks(); + return pmdaFetch(numpmid, pmidlist, resp, pmda); +} + + +/* + * callback provided to pmdaFetch + */ +static int +process_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) +{ + __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); + + if (idp->cluster != 0) + return PM_ERR_PMID; + if (idp->item != 0) + return PM_ERR_PMID; + + /* We have the values stored, simply grab it and return it. */ + atom->d = num_procs[inst]; + return 0; +} + +/* + * Initialise the agent (both daemon and DSO). + */ +void +process_init(pmdaInterface *dp) +{ + if (isDSO) { + int sep = __pmPathSeparator(); + snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDSO(dp, PMDA_INTERFACE_2, "process DSO", mypath); + } + + if (dp->status != 0) + return; + + dp->version.two.fetch = process_fetch; + + /* Let's grab the info right away just to make sure it's there. */ + process_grab_config_info(); + + pmdaSetFetchCallBack(dp, process_fetchCallBack); + + pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), + metrictab, sizeof(metrictab)/sizeof(metrictab[0])); +} + +pmLongOptions longopts[] = { + PMDA_OPTIONS_HEADER("Options"), + PMOPT_DEBUG, + PMDAOPT_DOMAIN, + PMDAOPT_LOGFILE, + PMOPT_HELP, + PMDA_OPTIONS_END +}; + +pmdaOptions opts = { + .short_options = "D:d:l:?", + .long_options = longopts, +}; + +/* + * Set up the agent if running as a daemon. + */ +int +main(int argc, char **argv) +{ + int sep = __pmPathSeparator(); + pmdaInterface desc; + + isDSO = 0; + __pmSetProgname(argv[0]); + + snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, PROCESS, + "process.log", mypath); + + pmdaGetOptions(argc, argv, &opts, &desc); + if (opts.errors) { + pmdaUsageMessage(&opts); + exit(1); + } + + pmdaOpenLog(&desc); + process_init(&desc); + pmdaConnect(&desc); + pmdaMain(&desc); + exit(0); +} diff --git a/src/pmdas/process/process.conf b/src/pmdas/process/process.conf new file mode 100644 index 0000000..a02879d --- /dev/null +++ b/src/pmdas/process/process.conf @@ -0,0 +1,11 @@ +# Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) +# for the portions of the code supporting the initial agent functionality. +# All rights reserved. +# Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. +# +sshd +crond +inetd +nfsd +afsd +test diff --git a/src/pmdas/process/root b/src/pmdas/process/root new file mode 100644 index 0000000..f2fba58 --- /dev/null +++ b/src/pmdas/process/root @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) + * for the portions of the code supporting the initial agent functionality. + * All rights reserved. + * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * fake "root" for validating the local PMNS subtree + */ +#include <stdpmid> + +root { process } + +#include "pmns" + |