Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 599902 Details for
Bug 840905
pmcd /proc information disclosure
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
patch to split off a new "proc" agent from the "linux" agent
pcp-split_linux_proc_pmda.patch (text/plain), 402.76 KB, created by
Mark Goodwin
on 2012-07-24 04:01:07 UTC
(
hide
)
Description:
patch to split off a new "proc" agent from the "linux" agent
Filename:
MIME Type:
Creator:
Mark Goodwin
Created:
2012-07-24 04:01:07 UTC
Size:
402.76 KB
patch
obsolete
>commit d9c696f1e999ef22828d7b1485634b0998573d9f >Author: Mark Goodwin <mgoodwin@redhat.com> >Date: Tue Jul 24 12:55:02 2012 +1000 > > Continuing the linux / proc PMDA split. > > - fix the proc instance domain table initialization - it's sparse > and preserves Linux indom numbers (for archive migration). > > - move cgroup pmns root to CGROUP_ROOT ("proc.cgroup") and fix > a segfault in proc_dynamic_pmns(). "cgroup" can't be a top level > leaf node in the pmns file (would need other code changes to support > this, which we may want to consider). > > - add linux_proc into the build (platform conditional) but not > enabled by default. > > - trim code copied from ../linux/filesys.[ch] and #if 0 blocks. > > - fix a bug in proc_fetchCallBack - wrong variable was being > returned for proc.cgroup.subsys.hierarchy > > modified: src/pmdas/GNUmakefile > modified: src/pmdas/linux_proc/GNUmakefile > modified: src/pmdas/linux_proc/cgroups.c > modified: src/pmdas/linux_proc/cgroups.h > modified: src/pmdas/linux_proc/clusters.h > modified: src/pmdas/linux_proc/filesys.c > modified: src/pmdas/linux_proc/filesys.h > modified: src/pmdas/linux_proc/indom.h > modified: src/pmdas/linux_proc/pmda.c > modified: src/pmdas/linux_proc/pmns > >diff --git a/src/pmdas/GNUmakefile b/src/pmdas/GNUmakefile >index c537b70..9a53064 100644 >--- a/src/pmdas/GNUmakefile >+++ b/src/pmdas/GNUmakefile >@@ -24,7 +24,7 @@ SUBDIRS = pmcd linux solaris aix darwin windows etw \ > dbping memcache systemtap mysql vmware kvm \ > bonding lustrecomm mmv netfilter zimbra \ > named news pdns samba dtsrun postfix gpsd \ >- rsyslog elasticsearch postgresql snmp >+ rsyslog elasticsearch postgresql snmp linux_proc > > LDIRT = pmcd.conf > >diff --git a/src/pmdas/linux_proc/GNUmakefile b/src/pmdas/linux_proc/GNUmakefile >index 5d97007..9927ae7 100644 >--- a/src/pmdas/linux_proc/GNUmakefile >+++ b/src/pmdas/linux_proc/GNUmakefile >@@ -25,7 +25,8 @@ PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) > CFILES = pmda.c cgroups.c dynamic.c filesys.c proc_pid.c proc_runq.c \ > ksym.c getinfo.c > >-HFILES = cgroups.h clusters.h dynamic.h proc_pid.h >+HFILES = cgroups.h clusters.h dynamic.h proc_pid.h indom.h getinfo.h \ >+ proc_runq.h ksym.h filesys.h > > LSRCFILES = Install Remove help pmns root > LDIRT = help.dir help.pag domain.h >diff --git a/src/pmdas/linux_proc/cgroups.c b/src/pmdas/linux_proc/cgroups.c >index 8805e1e..f37a662 100644 >--- a/src/pmdas/linux_proc/cgroups.c >+++ b/src/pmdas/linux_proc/cgroups.c >@@ -177,8 +177,8 @@ process_prepare(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, > qsort(list->pids, list->count, sizeof(int), compare_pid); > > pmid = cgroup_pmid_build(domain, subsys->process_cluster, group, 0); >- snprintf(taskpath, sizeof(taskpath), "cgroup.groups.%s%s.tasks.pid", >- subsys->name, name); >+ snprintf(taskpath, sizeof(taskpath), "%s.groups.%s%s.tasks.pid", >+ CGROUP_ROOT, subsys->name, name); > __pmAddPMNSNode(pmns, pmid, taskpath); > #endif > return 0; >@@ -191,8 +191,8 @@ update_pmns(__pmnsTree *pmns, cgroup_subsys_t *subsys, const char *name, > char entry[MAXPATHLEN]; > pmID pmid; > >- snprintf(entry, sizeof(entry), "cgroup.groups.%s%s.%s", >- subsys->name, name, metrics->suffix); >+ snprintf(entry, sizeof(entry), "%s.groups.%s%s.%s", >+ CGROUP_ROOT, subsys->name, name, metrics->suffix); > pmid = cgroup_pmid_build(domain, subsys->cluster, group, metrics->item); > __pmAddPMNSNode(pmns, pmid, entry); > } >@@ -550,10 +550,10 @@ cgroup_regulars(__pmnsTree *pmns, int domain) > int cluster; > char *name; > } regulars[] = { >- { 0, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.hierarchy" }, >- { 1, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.count" }, >- { 0, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.subsys" }, >- { 1, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.count" }, >+ { 0, CLUSTER_CGROUP_SUBSYS, CGROUP_ROOT ".subsys.hierarchy" }, >+ { 1, CLUSTER_CGROUP_SUBSYS, CGROUP_ROOT ".subsys.count" }, >+ { 0, CLUSTER_CGROUP_MOUNTS, CGROUP_ROOT ".mounts.subsys" }, >+ { 1, CLUSTER_CGROUP_MOUNTS, CGROUP_ROOT ".mounts.count" }, > }; > > for (i = 0; i < 4; i++) { >@@ -754,7 +754,7 @@ cgroup_init(void) > CLUSTER_NET_CLS_GROUPS, CLUSTER_NET_CLS_PROCS, > }; > >- proc_dynamic_pmns("cgroup", set, sizeof(set)/sizeof(int), >+ proc_dynamic_pmns(CGROUP_ROOT, set, sizeof(set)/sizeof(int), > refresh_cgroups, cgroup_text, > refresh_metrictable, size_metrictable); > } >diff --git a/src/pmdas/linux_proc/cgroups.h b/src/pmdas/linux_proc/cgroups.h >index d3b01f6..04ec721 100644 >--- a/src/pmdas/linux_proc/cgroups.h >+++ b/src/pmdas/linux_proc/cgroups.h >@@ -19,6 +19,8 @@ > * is the 3rd cgroup we've seen). > */ > >+#define CGROUP_ROOT "proc.cgroup" /* cgroup root pmns node */ >+ > static inline pmID > cgroup_pmid_build(unsigned int domain, unsigned int cluster, > unsigned int gid, unsigned int metric) >diff --git a/src/pmdas/linux_proc/clusters.h b/src/pmdas/linux_proc/clusters.h >index 96e3933..2719c89 100644 >--- a/src/pmdas/linux_proc/clusters.h >+++ b/src/pmdas/linux_proc/clusters.h >@@ -43,43 +43,4 @@ > #define MIN_CLUSTER 8 /* first cluster number we use here */ > #define NUM_CLUSTERS 52 /* one more than highest cluster number we use here */ > >-#if 0 >-enum { >- CLUSTER_STAT = 0, /* 0 /proc/stat */ >- CLUSTER_MEMINFO, /* 1 /proc/meminfo */ >- CLUSTER_LOADAVG, /* 2 /proc/loadavg */ >- CLUSTER_NET_DEV, /* 3 /proc/net/dev */ >- CLUSTER_INTERRUPTS, /* 4 /proc/interrupts */ >- CLUSTER_FILESYS, /* 5 /proc/mounts + statfs */ >- CLUSTER_SWAPDEV, /* 6 /proc/swaps */ >- CLUSTER_NET_NFS, /* 7 /proc/net/rpc/nfs + /proc/net/rpc/nfsd */ >- CLUSTER_PARTITIONS, /* 10 /proc/partitions */ >- CLUSTER_NET_SOCKSTAT, /* 11 /proc/net/sockstat */ >- CLUSTER_KERNEL_UNAME, /* 12 uname() system call */ >- CLUSTER_NET_SNMP, /* 14 /proc/net/snmp */ >- CLUSTER_SCSI, /* 15 /proc/scsi/scsi */ >- CLUSTER_XFS, /* 16 /proc/fs/xfs/stat */ >- CLUSTER_XFSBUF, /* 17 (deprecated /proc/fs/pagebuf/stat) */ >- CLUSTER_CPUINFO, /* 18 /proc/cpuinfo */ >- CLUSTER_NET_TCP, /* 19 /proc/net/tcp */ >- CLUSTER_SLAB, /* 20 /proc/slabinfo */ >- CLUSTER_SEM_LIMITS, /* 21 semctl(IPC_INFO) system call */ >- CLUSTER_MSG_LIMITS, /* 22 msgctl(IPC_INFO) system call */ >- CLUSTER_SHM_LIMITS, /* 23 shmctl(IPC_INFO) system call */ >- CLUSTER_NUSERS, /* 25 number of users */ >- CLUSTER_UPTIME, /* 26 /proc/uptime */ >- CLUSTER_VFS, /* 27 /proc/sys/fs */ >- CLUSTER_VMSTAT, /* 28 /proc/vmstat */ >- CLUSTER_IB, /* deprecated: do not re-use 29 infiniband */ >- CLUSTER_QUOTA, /* 30 quotactl() */ >- CLUSTER_NET_INET, /* 33 /proc/net/dev and ioctl(SIOCGIFCONF) */ >- CLUSTER_TMPFS, /* 34 /proc/mounts + statfs (tmpfs only) */ >- CLUSTER_SYSFS_KERNEL, /* 35 /sys/kernel metrics */ >- CLUSTER_NUMA_MEMINFO, /* 36 /sys/devices/system/node* NUMA memory */ >- CLUSTER_INTERRUPT_LINES,/* 49 /proc/interrupts percpu interrupts */ >- CLUSTER_INTERRUPT_OTHER,/* 50 /proc/interrupts percpu interrupts */ >- >-}; >-#endif >- > #endif /* _CLUSTERS_H */ >diff --git a/src/pmdas/linux_proc/filesys.c b/src/pmdas/linux_proc/filesys.c >index 4db2a10..4e03d4b 100644 >--- a/src/pmdas/linux_proc/filesys.c >+++ b/src/pmdas/linux_proc/filesys.c >@@ -1,7 +1,6 @@ > /* >- * Linux Filesystem Cluster >- * > * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Copyright (c) 2012 Red Hat, 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 >@@ -36,86 +35,3 @@ scan_filesys_options(const char *options, const char *option) > return NULL; > } > >-int >-refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, >- pmInDom tmpfs_indom) >-{ >- char buf[MAXPATHLEN]; >- char realdevice[MAXPATHLEN]; >- filesys_t *fs; >- pmInDom indom; >- FILE *fp; >- char *path, *device, *type, *options; >- int sts; >- >- pmdaCacheOp(quota_indom, PMDA_CACHE_INACTIVE); >- pmdaCacheOp(tmpfs_indom, PMDA_CACHE_INACTIVE); >- pmdaCacheOp(filesys_indom, PMDA_CACHE_INACTIVE); >- >- if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) >- return -oserror(); >- >- while (fgets(buf, sizeof(buf), fp) != NULL) { >- if ((device = strtok(buf, " ")) == 0) >- continue; >- >- path = strtok(NULL, " "); >- type = strtok(NULL, " "); >- options = strtok(NULL, " "); >- if (strcmp(type, "proc") == 0 || >- strcmp(type, "nfs") == 0 || >- strcmp(type, "devfs") == 0 || >- strcmp(type, "devpts") == 0 || >- strcmp(type, "cgroup") == 0 || >- strncmp(type, "auto", 4) == 0) >- continue; >- >- indom = filesys_indom; >- if (strcmp(type, "tmpfs") == 0) { >- indom = tmpfs_indom; >- device = path; >- } >- else if (strncmp(device, "/dev", 4) != 0) >- continue; >- if (realpath(device, realdevice) != NULL) >- device = realdevice; >- >- sts = pmdaCacheLookupName(indom, device, NULL, (void **)&fs); >- if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/mounts? */ >- continue; >- if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old mount */ >- pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); >- if (strcmp(path, fs->path) != 0) { /* old device, new path */ >- free(fs->path); >- fs->path = strdup(path); >- } >- if (strcmp(options, fs->options) != 0) { /* old device, new opts */ >- free(fs->options); >- fs->options = strdup(options); >- } >- } >- else { /* new mount */ >- if ((fs = malloc(sizeof(filesys_t))) == NULL) >- continue; >- fs->device = strdup(device); >- fs->path = strdup(path); >- fs->options = strdup(options); >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_LIBPMDA) { >- fprintf(stderr, "refresh_filesys: add \"%s\" \"%s\"\n", >- fs->path, device); >- } >-#endif >- pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); >- } >- fs->flags = 0; >- } >- >- /* >- * success >- * Note: we do not call statfs() here since only some instances >- * may be requested (rather, we do it in linux_fetch, see pmda.c). >- */ >- fclose(fp); >- return 0; >-} >diff --git a/src/pmdas/linux_proc/filesys.h b/src/pmdas/linux_proc/filesys.h >index 668794c..65e35ba 100644 >--- a/src/pmdas/linux_proc/filesys.h >+++ b/src/pmdas/linux_proc/filesys.h >@@ -30,5 +30,4 @@ typedef struct filesys { > struct statfs stats; > } filesys_t; > >-extern int refresh_filesys(pmInDom, pmInDom, pmInDom); > extern char *scan_filesys_options(const char *, const char *); >diff --git a/src/pmdas/linux_proc/indom.h b/src/pmdas/linux_proc/indom.h >index 0bb7a63..3111104 100644 >--- a/src/pmdas/linux_proc/indom.h >+++ b/src/pmdas/linux_proc/indom.h >@@ -1,6 +1,7 @@ > /* > * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. > * Copyright (c) 2010 Aconex. All Rights Reserved. >+ * Copyright (c) 2012 Red Hat, 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 >@@ -19,39 +20,16 @@ > /* > * indom cluster numbers ... to manage the indom migration after the > * linux -> linux + proc PMDAs split, these need to match the enum >- * assigned values for *_INDOM from the linux PMDA. >+ * assigned values for *_INDOM from the linux PMDA. Consequently, >+ * the proc indom table is sparse. > */ >- > #define CPU_INDOM 0 /* 0 - percpu */ > #define PROC_INDOM 9 /* - processes */ > #define CGROUP_SUBSYS_INDOM 20 /* - control group subsystems */ > #define CGROUP_MOUNTS_INDOM 21 /* - control group mounts */ > >-#define MIN_INDOM 0 /* first cluster number we use here */ >-#define NUM_INDOMS 22 /* one more than highest cluster number we use here */ >- >-#if 0 >-enum { >- DISK_INDOM, /* 1 - disks */ >- LOADAVG_INDOM, /* 2 - 1, 5, 15 minute load averages */ >- NET_DEV_INDOM, /* 3 - network interfaces */ >- PROC_INTERRUPTS_INDOM, /* 4 - interrupt lines */ >- FILESYS_INDOM, /* 5 - mounted bdev filesystems */ >- SWAPDEV_INDOM, /* 6 - swap devices */ >- NFS_INDOM, /* 7 - nfs operations */ >- NFS3_INDOM, /* 8 - nfs v3 operations */ >- PARTITIONS_INDOM, /* 10 - disk partitions */ >- SCSI_INDOM, /* 11 - scsi devices */ >- SLAB_INDOM, /* 12 - kernel slabs */ >- IB_INDOM, /* 13 - deprecated: do not re-use */ >- NFS4_CLI_INDOM, /* 14 - nfs v4 client operations */ >- NFS4_SVR_INDOM, /* 15 - nfs n4 server operations */ >- QUOTA_PRJ_INDOM, /* 16 - project quota */ >- NET_INET_INDOM, /* 17 - inet addresses */ >- TMPFS_INDOM, /* 18 - tmpfs mounts */ >- NODE_INDOM, /* 19 - NUMA nodes */ >-}; >-#endif >+#define MIN_INDOM 0 /* first indom number we use here */ >+#define NUM_INDOMS 22 /* one more than highest indom number we use here */ > > #define INDOM(x) (indomtab[x].it_indom) > extern pmdaIndom indomtab[]; >diff --git a/src/pmdas/linux_proc/pmda.c b/src/pmdas/linux_proc/pmda.c >index 947020e..d906884 100644 >--- a/src/pmdas/linux_proc/pmda.c >+++ b/src/pmdas/linux_proc/pmda.c >@@ -4,6 +4,7 @@ > * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. > * Portions Copyright (c) 2002 International Business Machines Corp. > * Portions Copyright (c) 2007-2011 Aconex. All Rights Reserved. >+ * Portions Copyright (c) 2012 Red Hat, 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 >@@ -51,18 +52,15 @@ static int _isDSO = 1; /* =0 I am a daemon */ > /* globals */ > size_t _pm_system_pagesize; /* for hinv.pagesize and used elsewhere */ > >-pmdaIndom indomtab[] = { >- { CPU_INDOM, 0, NULL }, >- { PROC_INDOM, 0, NULL }, >- { CGROUP_SUBSYS_INDOM, 0, NULL }, >- { CGROUP_MOUNTS_INDOM, 0, NULL }, >-}; >- >+/* >+ * The proc instance domain table is direct lookup and sparse. >+ * It is initialized in proc_init(), see below. >+ */ >+pmdaIndom indomtab[NUM_INDOMS]; > > /* > * all metrics supported in this PMDA - one table entry for each > */ >- > pmdaMetric proc_metrictab[] = { > > /* >@@ -828,7 +826,6 @@ static int > proc_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) > { > __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); >- int i; > int sts; > char *f; > unsigned long ul; >@@ -1257,7 +1254,7 @@ proc_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) > return sts; > if (sts != PMDA_CACHE_ACTIVE) > return PM_ERR_INST; >- atom->ul = i; >+ atom->ul = *ip; > break; > > case 1: /* cgroup.subsys.count */ >@@ -1405,6 +1402,15 @@ proc_init(pmdaInterface *dp) > dp->version.four.children = proc_children; > pmdaSetFetchCallBack(dp, proc_fetchCallBack); > >+ /* >+ * Initialize the instance domain table. >+ */ >+ memset(indomtab, 0, sizeof(indomtab)); >+ indomtab[CPU_INDOM].it_indom = CPU_INDOM; >+ indomtab[PROC_INDOM].it_indom = PROC_INDOM; >+ indomtab[CGROUP_SUBSYS_INDOM].it_indom = CGROUP_SUBSYS_INDOM; >+ indomtab[CGROUP_MOUNTS_INDOM].it_indom = CGROUP_MOUNTS_INDOM; >+ > proc_pid.indom = &indomtab[PROC_INDOM]; > > /* >diff --git a/src/pmdas/linux_proc/pmns b/src/pmdas/linux_proc/pmns >index 7dab4e6..2e1ea2b 100644 >--- a/src/pmdas/linux_proc/pmns >+++ b/src/pmdas/linux_proc/pmns >@@ -24,7 +24,6 @@ > * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > */ > >- > proc { > nprocs PROC:8:99 > psinfo >@@ -34,7 +33,7 @@ proc { > io > schedstat > fd >- cgroup PROC:*:* >+ cgroup PROC:*:* /* dynamic */ > } > > proc.psinfo { > >commit 228d75bc7131251977df5ab33551e666920cfca9 >Merge: 6524103 f153788 >Author: Mark Goodwin <mgoodwin@redhat.com> >Date: Mon Jul 23 11:15:09 2012 +1000 > > Merge branch 'proc_pmda' of git://oss.sgi.com/kenj/pcp into proc_pmda > > >commit f15378821b2d53ad00a8083653ea3ab4f8e63070 >Author: Ken McDonell <kenj@internode.on.net> >Date: Sun Jul 22 20:18:44 2012 +1000 > > proc PMDA - more bits 'n pieces > > Install and Remove scripts. > >diff --git a/src/pmdas/linux_proc/.gitignore b/src/pmdas/linux_proc/.gitignore >new file mode 100644 >index 0000000..2a72b78 >--- /dev/null >+++ b/src/pmdas/linux_proc/.gitignore >@@ -0,0 +1,5 @@ >+domain.h >+pmdaproc >+pmda_proc.so >+help.dir >+help.pag >diff --git a/src/pmdas/linux_proc/GNUmakefile b/src/pmdas/linux_proc/GNUmakefile >index 11682d7..5d97007 100644 >--- a/src/pmdas/linux_proc/GNUmakefile >+++ b/src/pmdas/linux_proc/GNUmakefile >@@ -21,14 +21,13 @@ DOMAIN = PROC > CMDTARGET = pmdaproc > LIBTARGET = pmda_proc.so > PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) >-CONF_LINE = "proc 60 dso proc $(PMDADIR)/$(LIBTARGET)" > > CFILES = pmda.c cgroups.c dynamic.c filesys.c proc_pid.c proc_runq.c \ > ksym.c getinfo.c > > HFILES = cgroups.h clusters.h dynamic.h proc_pid.h > >-LSRCFILES = help pmns root >+LSRCFILES = Install Remove help pmns root > LDIRT = help.dir help.pag domain.h > > LLDLIBS = -lpcp_pmda -lpcp >@@ -43,12 +42,10 @@ include $(BUILDRULES) > > ifeq "$(TARGET_OS)" "linux" > build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag >- @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ >- echo $(CONF_LINE) >> ../pmcd.conf ; \ >- fi > > install: default > $(INSTALL) -m 755 -d $(PMDADIR) >+ $(INSTALL) -m 755 Install Remove $(PMDADIR) > $(INSTALL) -m 644 domain.h pmns root help help.dir help.pag $(PMDADIR) > $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) > else >diff --git a/src/pmdas/linux_proc/Install b/src/pmdas/linux_proc/Install >new file mode 100644 >index 0000000..39b95f7 >--- /dev/null >+++ b/src/pmdas/linux_proc/Install >@@ -0,0 +1,31 @@ >+#! /bin/sh >+# >+# Copyright (c) 2012 Ken McDonell. 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 >+# >+# Install the Linux proc PMDA >+# >+ >+. $PCP_DIR/etc/pcp.env >+. $PCP_SHARE_DIR/lib/pmdaproc.sh >+ >+iam=proc >+pmda_interface=4 >+dso_opt=true >+ >+pmdaSetup >+pmdaInstall >+exit 0 >diff --git a/src/pmdas/linux_proc/Remove b/src/pmdas/linux_proc/Remove >new file mode 100644 >index 0000000..5ebddb8 >--- /dev/null >+++ b/src/pmdas/linux_proc/Remove >@@ -0,0 +1,29 @@ >+#! /bin/sh >+# >+# Copyright (c) 2012 Ken McDonell. 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 Linux proc PMDA >+# >+ >+. $PCP_DIR/etc/pcp.env >+. $PCP_SHARE_DIR/lib/pmdaproc.sh >+ >+iam=proc >+ >+pmdaSetup >+pmdaRemove >+exit 0 > >commit b28bb3bd72ef9d6bd538d991efec34f65374b7df >Author: Ken McDonell <kenj@internode.on.net> >Date: Sun Jul 22 20:03:14 2012 +1000 > > proc PMDA - missed file from last commit > >diff --git a/src/pmdas/linux_proc/indom.h b/src/pmdas/linux_proc/indom.h >new file mode 100644 >index 0000000..0bb7a63 >--- /dev/null >+++ b/src/pmdas/linux_proc/indom.h >@@ -0,0 +1,59 @@ >+/* >+ * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Copyright (c) 2010 Aconex. 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. >+ */ >+ >+#ifndef _INDOM_H >+#define _INDOM_H >+ >+/* >+ * indom cluster numbers ... to manage the indom migration after the >+ * linux -> linux + proc PMDAs split, these need to match the enum >+ * assigned values for *_INDOM from the linux PMDA. >+ */ >+ >+#define CPU_INDOM 0 /* 0 - percpu */ >+#define PROC_INDOM 9 /* - processes */ >+#define CGROUP_SUBSYS_INDOM 20 /* - control group subsystems */ >+#define CGROUP_MOUNTS_INDOM 21 /* - control group mounts */ >+ >+#define MIN_INDOM 0 /* first cluster number we use here */ >+#define NUM_INDOMS 22 /* one more than highest cluster number we use here */ >+ >+#if 0 >+enum { >+ DISK_INDOM, /* 1 - disks */ >+ LOADAVG_INDOM, /* 2 - 1, 5, 15 minute load averages */ >+ NET_DEV_INDOM, /* 3 - network interfaces */ >+ PROC_INTERRUPTS_INDOM, /* 4 - interrupt lines */ >+ FILESYS_INDOM, /* 5 - mounted bdev filesystems */ >+ SWAPDEV_INDOM, /* 6 - swap devices */ >+ NFS_INDOM, /* 7 - nfs operations */ >+ NFS3_INDOM, /* 8 - nfs v3 operations */ >+ PARTITIONS_INDOM, /* 10 - disk partitions */ >+ SCSI_INDOM, /* 11 - scsi devices */ >+ SLAB_INDOM, /* 12 - kernel slabs */ >+ IB_INDOM, /* 13 - deprecated: do not re-use */ >+ NFS4_CLI_INDOM, /* 14 - nfs v4 client operations */ >+ NFS4_SVR_INDOM, /* 15 - nfs n4 server operations */ >+ QUOTA_PRJ_INDOM, /* 16 - project quota */ >+ NET_INET_INDOM, /* 17 - inet addresses */ >+ TMPFS_INDOM, /* 18 - tmpfs mounts */ >+ NODE_INDOM, /* 19 - NUMA nodes */ >+}; >+#endif >+ >+#define INDOM(x) (indomtab[x].it_indom) >+extern pmdaIndom indomtab[]; >+ >+#endif /* _INDOM_H */ > >commit 372b1b0d34ae2a0e1df5b6f4a6d2b1a54c90bef3 >Author: Ken McDonell <kenj@internode.on.net> >Date: Sun Jul 22 19:56:36 2012 +1000 > > Linux proc pmda - initial checkpoint > > This commit delivers the first cut of the proc PMDA ... the code > has been lifted out of the linux PMDA and compiles and links without > error ... but there has been no testing and no Install and Remove > scripts yet. > >diff --git a/src/pmdas/linux_proc/GNUmakefile b/src/pmdas/linux_proc/GNUmakefile >new file mode 100644 >index 0000000..11682d7 >--- /dev/null >+++ b/src/pmdas/linux_proc/GNUmakefile >@@ -0,0 +1,69 @@ >+# >+# Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. >+# Copyright (c) 2007-2010 Aconex. 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 = proc >+DOMAIN = PROC >+CMDTARGET = pmdaproc >+LIBTARGET = pmda_proc.so >+PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) >+CONF_LINE = "proc 60 dso proc $(PMDADIR)/$(LIBTARGET)" >+ >+CFILES = pmda.c cgroups.c dynamic.c filesys.c proc_pid.c proc_runq.c \ >+ ksym.c getinfo.c >+ >+HFILES = cgroups.h clusters.h dynamic.h proc_pid.h >+ >+LSRCFILES = help pmns root >+LDIRT = help.dir help.pag domain.h >+ >+LLDLIBS = -lpcp_pmda -lpcp >+ >+# Uncomment these flags for profiling >+# LCFLAGS = -pg >+# LLDFLAGS = -pg >+ >+default: build-me >+ >+include $(BUILDRULES) >+ >+ifeq "$(TARGET_OS)" "linux" >+build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag >+ @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ >+ echo $(CONF_LINE) >> ../pmcd.conf ; \ >+ fi >+ >+install: default >+ $(INSTALL) -m 755 -d $(PMDADIR) >+ $(INSTALL) -m 644 domain.h pmns root help help.dir help.pag $(PMDADIR) >+ $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) >+else >+build-me: >+install: >+endif >+ >+help.dir help.pag : help >+ $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root -v 2 -o help < help >+ >+default_pcp : default >+ >+install_pcp : install >+ >+domain.h: ../../pmns/stdpmid >+ $(DOMAIN_MAKERULE) >+ >+cgroups.o dynamic.o pmda.o: clusters.h >diff --git a/src/pmdas/linux_proc/cgroups.c b/src/pmdas/linux_proc/cgroups.c >new file mode 100644 >index 0000000..8805e1e >--- /dev/null >+++ b/src/pmdas/linux_proc/cgroups.c >@@ -0,0 +1,760 @@ >+/* >+ * Copyright (c) 2010 Aconex. 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 "cgroups.h" >+#include "../linux/filesys.h" >+#include "dynamic.h" >+#include "clusters.h" >+#include "proc_pid.h" >+#include <sys/stat.h> >+#ifdef HAVE_STRINGS_H >+#include <strings.h> >+#endif >+#include <ctype.h> >+ >+/* Add namespace entries and prepare values for one cgroupfs directory entry */ >+struct cgroup_subsys; >+typedef int (*cgroup_prepare_t)(__pmnsTree *, const char *, >+ struct cgroup_subsys *, const char *, int, int, int); >+static int prepare_ull(__pmnsTree *, const char *, >+ struct cgroup_subsys *, const char *, int, int, int); >+static int prepare_string(__pmnsTree *, const char *, >+ struct cgroup_subsys *, const char *, int, int, int); >+static int prepare_named_ull(__pmnsTree *, const char *, >+ struct cgroup_subsys *, const char *, int, int, int); >+ >+/* >+ * Critical data structures for cgroup subsystem in pmdalinux... >+ * Initial comment for each struct talks about lifecycle of that >+ * data, in terms of what pmdalinux must do with it (esp. memory >+ * allocation related). >+ */ >+ >+typedef struct { /* contents depends on individual kernel cgroups */ >+ int item; /* PMID == domain:cluster:[id:item] */ >+ int dynamic; /* do we need an extra free (string) */ >+ cgroup_prepare_t prepare; /* setup metric name(s) and value(s) */ >+ char *suffix; /* cpus/mems/rss/... */ >+} cgroup_metrics_t; >+ >+typedef struct { /* some metrics are multi-valued, but most have only one */ >+ int item; /* PMID == domain:cluster:[id:item] */ >+ int atom_count; >+ pmAtomValue *atoms; >+} cgroup_values_t; >+ >+typedef struct { /* contains data for each group users have created, if any */ >+ int id; /* PMID == domain:cluster:[id:item] */ >+ int refreshed; /* boolean: are values all uptodate */ >+ proc_pid_list_t process_list; >+ cgroup_values_t *metric_values; >+} cgroup_group_t; >+ >+typedef struct cgroup_subsys { /* contents covers the known kernel cgroups */ >+ const char *name; /* cpuset/memory/... */ >+ int cluster; /* PMID == domain:cluster:[id:item] */ >+ int process_cluster;/* cluster ID for process metrics */ >+ int group_count; /* number of groups (dynamic) */ >+ int metric_count; /* number of metrics (fixed) */ >+ cgroup_group_t *groups; /* array of groups (dynamic) */ >+ cgroup_metrics_t *metrics; /* array of metrics (fixed) */ >+} cgroup_subsys_t; >+ >+static cgroup_metrics_t cpusched_metrics[] = { >+ { .item = 0, .suffix = "shares", .prepare = prepare_ull }, >+}; >+ >+static cgroup_metrics_t cpuacct_metrics[] = { >+ { .item = 0, .suffix = "stat.user", .prepare = prepare_named_ull }, >+ { .item = 1, .suffix = "stat.system", .prepare = prepare_named_ull }, >+ { .item = 2, .suffix = "usage", .prepare = prepare_ull }, >+ { .item = 3, .suffix = "usage_percpu", .prepare = prepare_ull }, >+}; >+ >+static cgroup_metrics_t cpuset_metrics[] = { >+ { .item = 0, .suffix = "cpus", .prepare = prepare_string, .dynamic = 1 }, >+ { .item = 1, .suffix = "mems", .prepare = prepare_string, .dynamic = 1 }, >+}; >+ >+static cgroup_metrics_t memory_metrics[] = { >+ { .item = 0, .suffix = "stat.cache", .prepare = prepare_named_ull }, >+ { .item = 1, .suffix = "stat.rss", .prepare = prepare_named_ull }, >+ { .item = 2, .suffix = "stat.pgin", .prepare = prepare_named_ull }, >+ { .item = 3, .suffix = "stat.pgout", .prepare = prepare_named_ull }, >+ { .item = 4, .suffix = "stat.swap", .prepare = prepare_named_ull }, >+ { .item = 5, .suffix = "stat.active_anon", .prepare = prepare_named_ull }, >+ { .item = 6, .suffix = "stat.inactive_anon", .prepare = prepare_named_ull }, >+ { .item = 7, .suffix = "stat.active_file", .prepare = prepare_named_ull }, >+ { .item = 8, .suffix = "stat.inactive_file", .prepare = prepare_named_ull }, >+ { .item = 9, .suffix = "stat.unevictable", .prepare = prepare_named_ull }, >+}; >+ >+static cgroup_metrics_t netclass_metrics[] = { >+ { .item = 0, .suffix = "classid", .prepare = prepare_ull }, >+}; >+ >+static cgroup_subsys_t controllers[] = { >+ { .name = "cpu", >+ .cluster = CLUSTER_CPUSCHED_GROUPS, >+ .process_cluster = CLUSTER_CPUSCHED_PROCS, >+ .metrics = cpusched_metrics, >+ .metric_count = sizeof(cpusched_metrics) / sizeof(cpusched_metrics[0]), >+ }, >+ { .name = "cpuset", >+ .cluster = CLUSTER_CPUSET_GROUPS, >+ .process_cluster = CLUSTER_CPUSET_PROCS, >+ .metrics = cpuset_metrics, >+ .metric_count = sizeof(cpuset_metrics) / sizeof(cpuset_metrics[0]), >+ }, >+ { .name = "cpuacct", >+ .cluster = CLUSTER_CPUACCT_GROUPS, >+ .process_cluster = CLUSTER_CPUACCT_PROCS, >+ .metrics = cpuacct_metrics, >+ .metric_count = sizeof(cpuacct_metrics) / sizeof(cpuacct_metrics[0]), >+ }, >+ { .name = "memory", >+ .cluster = CLUSTER_MEMORY_GROUPS, >+ .process_cluster = CLUSTER_MEMORY_PROCS, >+ .metrics = memory_metrics, >+ .metric_count = sizeof(memory_metrics) / sizeof(memory_metrics[0]), >+ }, >+ { .name = "net_cls", >+ .cluster = CLUSTER_NET_CLS_GROUPS, >+ .process_cluster = CLUSTER_NET_CLS_PROCS, >+ .metrics = netclass_metrics, >+ .metric_count = sizeof(netclass_metrics) / sizeof(netclass_metrics[0]), >+ }, >+}; >+ >+static int >+read_values(char *buffer, int size, const char *path, const char *subsys, >+ const char *metric) >+{ >+ int fd, count; >+ >+ snprintf(buffer, size, "%s/%s.%s", path, subsys, metric); >+ if ((fd = open(buffer, O_RDONLY)) < 0) >+ return -oserror(); >+ count = read(fd, buffer, size); >+ close(fd); >+ if (count < 0) >+ return -oserror(); >+ buffer[count-1] = '\0'; >+ return 0; >+} >+ >+static int >+process_prepare(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >+ const char *name, int group, int domain) >+{ >+#if 0 /* not yet implemented */ >+ FILE *fp; >+ pmID pmid; >+ char process[64]; >+ char taskpath[MAXPATHLEN]; >+ proc_pid_list_t *list = &subsys->groups[group].process_list; >+ >+ snprintf(taskpath, sizeof(taskpath), "%s/tasks", path); >+ if ((fp = fopen(taskpath, "r")) == NULL) >+ return -oserror(); >+ while (fgets(process, sizeof(process), fp) != NULL) >+ pidlist_append(list, process); >+ fclose(fp); >+ qsort(list->pids, list->count, sizeof(int), compare_pid); >+ >+ pmid = cgroup_pmid_build(domain, subsys->process_cluster, group, 0); >+ snprintf(taskpath, sizeof(taskpath), "cgroup.groups.%s%s.tasks.pid", >+ subsys->name, name); >+ __pmAddPMNSNode(pmns, pmid, taskpath); >+#endif >+ return 0; >+} >+ >+static void >+update_pmns(__pmnsTree *pmns, cgroup_subsys_t *subsys, const char *name, >+ cgroup_metrics_t *metrics, int group, int domain) >+{ >+ char entry[MAXPATHLEN]; >+ pmID pmid; >+ >+ snprintf(entry, sizeof(entry), "cgroup.groups.%s%s.%s", >+ subsys->name, name, metrics->suffix); >+ pmid = cgroup_pmid_build(domain, subsys->cluster, group, metrics->item); >+ __pmAddPMNSNode(pmns, pmid, entry); >+} >+ >+static int >+prepare_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >+ const char *name, int metric, int group, int domain) >+{ >+ int count = 0; >+ unsigned long long value; >+ char buffer[MAXPATHLEN]; >+ char *endp, *p = &buffer[0]; >+ cgroup_group_t *groups = &subsys->groups[group]; >+ cgroup_metrics_t *metrics = &subsys->metrics[metric]; >+ pmAtomValue *atoms = groups->metric_values[metric].atoms; >+ >+ if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) >+ return -oserror(); >+ >+ while (p && *p) { >+ value = strtoull(p, &endp, 0); >+ if ((atoms = realloc(atoms, (count + 1) * sizeof(pmAtomValue))) == NULL) >+ return -oserror(); >+ atoms[count++].ull = value; >+ if (endp == '\0' || endp == p) >+ break; >+ p = endp; >+ while (p && isspace(*p)) >+ p++; >+ } >+ >+ groups->metric_values[metric].item = metric; >+ groups->metric_values[metric].atoms = atoms; >+ groups->metric_values[metric].atom_count = count; >+ update_pmns(pmns, subsys, name, metrics, group, domain); >+ return 0; >+} >+ >+static int >+prepare_named_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >+ const char *name, int metric, int group, int domain) >+{ >+ int i, count; >+ unsigned long long value; >+ char filename[64], buffer[MAXPATHLEN]; >+ char *offset, *p = &buffer[0]; >+ cgroup_group_t *groups = &subsys->groups[group]; >+ cgroup_metrics_t *metrics = &subsys->metrics[metric]; >+ >+ if (groups->refreshed) >+ return 0; >+ >+ /* metric => e.g. stat.user and stat.system - split it up first */ >+ offset = index(metrics->suffix, '.'); >+ if (!offset) >+ return PM_ERR_CONV; >+ count = (offset - metrics->suffix); >+ strncpy(filename, metrics->suffix, count); >+ filename[count] = '\0'; >+ >+ if (read_values(p, sizeof(buffer), path, subsys->name, filename) < 0) >+ return -oserror(); >+ >+ /* buffer contains <name <value> pairs */ >+ while (p && *p) { >+ char *endp, *field, *offset; >+ >+ if ((field = index(p, ' ')) == NULL) >+ return PM_ERR_CONV; >+ offset = field + 1; >+ *field = '\0'; >+ field = p; /* field now points to <name> */ >+ p = offset; >+ value = strtoull(p, &endp, 0); >+ p = endp; >+ while (p && isspace(*p)) >+ p++; >+ >+ for (i = 0; i < subsys->metric_count; i++) { >+ pmAtomValue *atoms = groups->metric_values[i].atoms; >+ metrics = &subsys->metrics[i]; >+ >+ if (strcmp(field, metrics->suffix + count + 1) != 0) >+ continue; >+ if ((atoms = calloc(1, sizeof(pmAtomValue))) == NULL) >+ return -oserror(); >+ atoms[0].ull = value; >+ >+ groups->metric_values[i].item = i; >+ groups->metric_values[i].atoms = atoms; >+ groups->metric_values[i].atom_count = 1; >+ update_pmns(pmns, subsys, name, metrics, group, domain); >+ break; >+ } >+ } >+ groups->refreshed = 1; >+ return 0; >+} >+ >+static int >+prepare_string(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >+ const char *name, int metric, int group, int domain) >+{ >+ char buffer[MAXPATHLEN]; >+ cgroup_group_t *groups = &subsys->groups[group]; >+ cgroup_metrics_t *metrics = &subsys->metrics[metric]; >+ pmAtomValue *atoms = groups->metric_values[metric].atoms; >+ char *p = &buffer[0]; >+ >+ if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) >+ return -oserror(); >+ >+ if ((atoms = malloc(sizeof(pmAtomValue))) == NULL) >+ return -oserror(); >+ if ((atoms[0].cp = strdup(buffer)) == NULL) { >+ free(atoms); >+ return -oserror(); >+ } >+ groups->metric_values[metric].item = metric; >+ groups->metric_values[metric].atoms = atoms; >+ groups->metric_values[metric].atom_count = 1; >+ update_pmns(pmns, subsys, name, metrics, group, domain); >+ return 0; >+} >+ >+static void >+translate(char *dest, const char *src, size_t size) >+{ >+ char *p; >+ >+ if (*src != '\0') /* non-root */ >+ *dest = '.'; >+ strncpy(dest, src, size); >+ for (p = dest; *p; p++) { >+ if (*p == '/') >+ *p = '.'; >+ } >+} >+ >+static int >+namespace(__pmnsTree *pmns, cgroup_subsys_t *subsys, >+ const char *cgrouppath, const char *cgroupname, int domain) >+{ >+ int i, id, sts; >+ cgroup_values_t *cvp; >+ char group[128]; >+ >+ translate(&group[0], cgroupname, sizeof(group)); >+ >+ /* allocate space for this group */ >+ sts = (subsys->group_count + 1) * sizeof(cgroup_group_t); >+ subsys->groups = (cgroup_group_t *)realloc(subsys->groups, sts); >+ if (subsys->groups == NULL) >+ return -oserror(); >+ /* allocate space for all values up-front */ >+ sts = subsys->metric_count * sizeof(cgroup_values_t); >+ if ((cvp = (cgroup_values_t *)calloc(1, sts)) == NULL) >+ return -oserror(); >+ id = subsys->group_count++; >+ memset(&subsys->groups[id], 0, sizeof(cgroup_group_t)); >+ subsys->groups[id].id = id; >+ subsys->groups[id].metric_values = cvp; >+ >+ for (i = 0; i < subsys->metric_count; i++) { >+ cgroup_metrics_t *metrics = &subsys->metrics[i]; >+ metrics->prepare(pmns, cgrouppath, subsys, group, i, id, domain); >+ } >+ process_prepare(pmns, cgrouppath, subsys, group, id, domain); >+ return 1; >+} >+ >+int >+refresh_cgroup_subsys(pmInDom indom) >+{ >+ char buf[4096]; >+ char name[MAXPATHLEN]; >+ int numcgroups, enabled, sts; >+ long *data; >+ long hierarchy; >+ FILE *fp; >+ >+ if ((fp = fopen("/proc/cgroups", "r")) == NULL) >+ return 1; >+ >+ while (fgets(buf, sizeof(buf), fp) != NULL) { >+ /* skip lines starting with hash (header) */ >+ if (buf[0] == '#') >+ continue; >+ if (sscanf(buf, "%s %lu %u %u", &name[0], >+ &hierarchy, &numcgroups, &enabled) != 4) >+ continue; >+ sts = pmdaCacheLookupName(indom, name, NULL, (void **)&data); >+ if (sts == PMDA_CACHE_ACTIVE) { >+ if (*data != hierarchy) { >+ /* >+ * odd ... instance name repeated but different >+ * hierarchy ... we cannot support more than one hierachy >+ * yet >+ */ >+ fprintf(stderr, "refresh_cgroup_subsys: \"%s\": entries for hierachy %ld ignored (hierarchy %ld seen first)\n", name, hierarchy, *data); >+ } >+ continue; >+ } >+ else if (sts != PMDA_CACHE_INACTIVE) { >+ if ((data = (long *)malloc(sizeof(long))) == NULL) { >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_LIBPMDA) >+ fprintf(stderr, "refresh_cgroup_subsys: \"%s\": malloc failed\n", name); >+#endif >+ continue; >+ } >+ *data = hierarchy; >+ } >+ pmdaCacheStore(indom, PMDA_CACHE_ADD, name, (void *)data); >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_LIBPMDA) >+ fprintf(stderr, "refresh_cgroup_subsys: add \"%s\" [hierarchy %ld]\n", name, hierarchy); >+#endif >+ } >+ fclose(fp); >+ return 0; >+} >+ >+/* >+ * Parse a (comma-separated) mount option string to find one of the known >+ * cgroup subsystems, and return a pointer to it or "?" if none found. >+ */ >+char * >+cgroup_find_subsys(pmInDom indom, const char *options) >+{ >+ static char dunno[] = "?"; >+ static char opts[128]; >+ char buffer[128]; >+ char *s, *out = NULL; >+ >+ memset(opts, 0, sizeof(opts)); >+ strncpy(buffer, options, sizeof(buffer)); >+ >+ s = strtok(buffer, ","); >+ while (s) { >+ if (pmdaCacheLookupName(indom, s, NULL, NULL) == PMDA_CACHE_ACTIVE) { >+ if (out) { /* append option */ >+ strcat(out, ","); >+ strcat(out, s); >+ out += strlen(s) + 1; /* +1 => cater for comma */ >+ } else { /* first option */ >+ strcat(opts, s); >+ out = opts + strlen(s); >+ } >+ } >+ s = strtok(NULL, ","); >+ } >+ if (out) >+ return opts; >+ return dunno; >+} >+ >+/* Ensure cgroup name can be used as a PCP namespace entry, ignore it if not */ >+static int >+valid_pmns_name(char *name) >+{ >+ if (!isalpha(name[0])) >+ return 0; >+ for (; *name != '\0'; name++) >+ if (!isalnum(*name) && *name != '_') >+ return 0; >+ return 1; >+} >+ >+static int >+cgroup_namespace(__pmnsTree *pmns, const char *options, >+ const char *cgrouppath, const char *cgroupname, int domain) >+{ >+ int i, sts = 0; >+ >+ /* use options to tell which cgroup controller(s) are active here */ >+ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >+ int lsts; >+ cgroup_subsys_t *subsys = &controllers[i]; >+ if (scan_filesys_options(options, subsys->name) == NULL) >+ continue; >+ lsts = namespace(pmns, subsys, cgrouppath, cgroupname, domain); >+ if (lsts > 0) >+ sts = 1; >+ } >+ return sts; >+} >+ >+static int >+cgroup_scan(const char *mnt, const char *path, const char *options, >+ int domain, __pmnsTree *pmns, int root) >+{ >+ int sts, length; >+ DIR *dirp; >+ struct stat sbuf; >+ struct dirent *dp; >+ char *cgroupname; >+ char cgrouppath[MAXPATHLEN]; >+ >+ if (root) >+ strncpy(cgrouppath, mnt, sizeof(cgrouppath)); >+ else >+ snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", mnt, path); >+ >+ if ((dirp = opendir(cgrouppath)) == NULL) >+ return -oserror(); >+ >+ length = strlen(cgrouppath); >+ cgroupname = &cgrouppath[length]; >+ >+ sts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); >+ >+ /* >+ * readdir - descend into directories to find all cgroups, then >+ * populate namespace with <controller>[.<groupname>].<metrics> >+ */ >+ while ((dp = readdir(dirp)) != NULL) { >+ int lsts; >+ if (!valid_pmns_name(dp->d_name)) >+ continue; >+ if (path[0] == '\0') >+ snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", >+ mnt, dp->d_name); >+ else >+ snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s/%s", >+ mnt, path, dp->d_name); >+ cgroupname = &cgrouppath[length]; >+ if (stat(cgrouppath, &sbuf) < 0) >+ continue; >+ if (!(S_ISDIR(sbuf.st_mode))) >+ continue; >+ >+ lsts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); >+ if (lsts > 0) >+ sts = 1; >+ >+ /* >+ * also scan for any child cgroups, but cgroup_scan() may return >+ * an error >+ */ >+ lsts = cgroup_scan(mnt, cgrouppath, options, domain, pmns, 0); >+ if (lsts > 0) >+ sts = 1; >+ } >+ closedir(dirp); >+ return sts; >+} >+ >+static void >+cgroup_regulars(__pmnsTree *pmns, int domain) >+{ >+ int i; >+ static struct { >+ int item; >+ int cluster; >+ char *name; >+ } regulars[] = { >+ { 0, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.hierarchy" }, >+ { 1, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.count" }, >+ { 0, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.subsys" }, >+ { 1, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.count" }, >+ }; >+ >+ for (i = 0; i < 4; i++) { >+ pmID pmid = pmid_build(domain, regulars[i].cluster, regulars[i].item); >+ __pmAddPMNSNode(pmns, pmid, regulars[i].name); >+ } >+} >+ >+int >+refresh_cgroup_groups(pmdaExt *pmda, pmInDom mounts, __pmnsTree **pmns) >+{ >+ int i, j, k, a; >+ int sts, mtab = 0, domain = pmda->e_domain; >+ filesys_t *fs; >+ __pmnsTree *tree = pmns ? *pmns : NULL; >+ >+ if (tree) >+ __pmFreePMNS(tree); >+ >+ if ((sts = __pmNewPMNS(&tree)) < 0) { >+ __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n", >+ pmProgname, pmErrStr(sts)); >+ if (pmns) >+ *pmns = NULL; >+ return 0; >+ } >+ >+ cgroup_regulars(tree, domain); >+ >+ /* reset our view of subsystems and groups */ >+ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >+ cgroup_subsys_t *subsys = &controllers[i]; >+ for (j = 0; j < subsys->group_count; j++) { >+ cgroup_group_t *group = &subsys->groups[j]; >+ for (k = 0; k < subsys->metric_count; k++) { >+ pmAtomValue *atoms = group->metric_values[k].atoms; >+ if (subsys->metrics[k].dynamic) >+ for (a = 0; a < group->metric_values[k].atom_count; a++) >+ free(atoms[a].cp); >+ free(atoms); >+ } >+ free(group->metric_values); >+ if (group->process_list.size) >+ free(group->process_list.pids); >+ memset(group, 0, sizeof(cgroup_group_t)); >+ } >+ controllers[i].group_count = 0; >+ } >+ >+ pmdaCacheOp(mounts, PMDA_CACHE_WALK_REWIND); >+ while ((sts = pmdaCacheOp(mounts, PMDA_CACHE_WALK_NEXT)) != -1) { >+ int lsts; >+ if (!pmdaCacheLookup(mounts, sts, NULL, (void **)&fs)) >+ continue; >+ /* walk this cgroup mount finding groups (subdirs) */ >+ lsts = cgroup_scan(fs->path, "", fs->options, domain, tree, 1); >+ if (lsts > 0) >+ mtab = 1; >+ } >+ >+ if (pmns) >+ *pmns = tree; >+ else >+ __pmFreePMNS(tree); >+ >+ return mtab; >+} >+ >+int >+cgroup_group_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) >+{ >+ int i, j, k, gid; >+ >+ gid = cgroup_pmid_group(item); >+ item = cgroup_pmid_metric(item); >+ >+ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >+ cgroup_subsys_t *subsys = &controllers[i]; >+ >+ if (subsys->cluster != cluster) >+ continue; >+ for (j = 0; j < subsys->group_count; j++) { >+ cgroup_group_t *group = &subsys->groups[j]; >+ >+ if (group->id != gid) >+ continue; >+ for (k = 0; k < subsys->metric_count; k++) { >+ cgroup_values_t *cvp = &group->metric_values[k]; >+ >+ if (cvp->item != item) >+ continue; >+ if (cvp->atom_count <= 0) >+ return PM_ERR_VALUE; >+ if (inst == PM_IN_NULL) >+ inst = 0; >+ else if (inst >= cvp->atom_count) >+ return PM_ERR_INST; >+ *atom = cvp->atoms[inst]; >+ return 1; >+ } >+ } >+ } >+ return PM_ERR_PMID; >+} >+ >+int >+cgroup_procs_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) >+{ >+ int i, j, gid; >+ >+ gid = cgroup_pmid_group(item); >+ item = cgroup_pmid_metric(item); >+ >+ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >+ cgroup_subsys_t *subsys = &controllers[i]; >+ if (subsys->process_cluster != cluster) >+ continue; >+ >+ for (j = 0; j < subsys->group_count; j++) { >+ cgroup_group_t *group = &subsys->groups[j]; >+ >+ if (group->id != gid) >+ continue; >+ >+ /* TODO: return values for process metrics */ >+ return PM_ERR_NYI; >+ } >+ } >+ return PM_ERR_PMID; >+} >+ >+/* >+ * Needs to answer the question: how much extra space needs to be allocated >+ * in the metric table for (dynamic) cgroup metrics"? We have static entries >+ * for group ID zero - if we have any non-zero group IDs, we need entries to >+ * cover those. Return value is the number of additional entries needed. >+ */ >+static void >+size_metrictable(int *total, int *trees) >+{ >+ int i, j, maxid = 0, count = 0; >+ >+ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >+ cgroup_subsys_t *subsys = &controllers[i]; >+ for (j = 0; j < subsys->group_count; j++) { >+ cgroup_group_t *group = &subsys->groups[j]; >+ if (group->id > maxid) >+ maxid = group->id; >+ } >+ count += subsys->metric_count + 0; /* +1 for task.pid */ >+ } >+ >+ *total = count; >+ *trees = maxid; >+ >+ if (pmDebug & DBG_TRACE_LIBPMDA) >+ fprintf(stderr, "cgroups size_metrictable: %d total x %d trees\n", >+ *total, *trees); >+} >+ >+/* >+ * Create new metric table entry for a group based on an existing one. >+ */ >+static void >+refresh_metrictable(pmdaMetric *source, pmdaMetric *dest, int id) >+{ >+ int domain = pmid_domain(source->m_desc.pmid); >+ int cluster = pmid_cluster(source->m_desc.pmid); >+ int item = pmid_item(source->m_desc.pmid); >+ >+ memcpy(dest, source, sizeof(pmdaMetric)); >+ dest->m_desc.pmid = cgroup_pmid_build(domain, cluster, id, item); >+ >+ if (pmDebug & DBG_TRACE_LIBPMDA) >+ fprintf(stderr, "cgroup refresh_metrictable: (%p -> %p) " >+ "metric ID dup: %d.%d.%d.%d -> %d.%d.%d.%d\n", >+ source, dest, domain, cluster, >+ cgroup_pmid_group(source->m_desc.pmid), >+ cgroup_pmid_metric(source->m_desc.pmid), >+ pmid_domain(dest->m_desc.pmid), pmid_cluster(dest->m_desc.pmid), >+ cgroup_pmid_group(dest->m_desc.pmid), >+ cgroup_pmid_metric(dest->m_desc.pmid)); >+} >+ >+static int >+cgroup_text(pmdaExt *pmda, pmID pmid, int type, char **buf) >+{ >+ return PM_ERR_TEXT; >+} >+ >+void >+cgroup_init(void) >+{ >+ int set[] = { CLUSTER_CPUSET_GROUPS, CLUSTER_CPUSET_PROCS, >+ CLUSTER_CPUACCT_GROUPS, CLUSTER_CPUACCT_PROCS, >+ CLUSTER_CPUSCHED_GROUPS, CLUSTER_CPUSCHED_PROCS, >+ CLUSTER_MEMORY_GROUPS, CLUSTER_MEMORY_PROCS, >+ CLUSTER_NET_CLS_GROUPS, CLUSTER_NET_CLS_PROCS, >+ }; >+ >+ proc_dynamic_pmns("cgroup", set, sizeof(set)/sizeof(int), >+ refresh_cgroups, cgroup_text, >+ refresh_metrictable, size_metrictable); >+} >diff --git a/src/pmdas/linux_proc/cgroups.h b/src/pmdas/linux_proc/cgroups.h >new file mode 100644 >index 0000000..d3b01f6 >--- /dev/null >+++ b/src/pmdas/linux_proc/cgroups.h >@@ -0,0 +1,49 @@ >+/* >+ * Copyright (c) 2010 Aconex. 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. >+ */ >+ >+/* >+ * Note: cgroup metrics have an "extra" component - the final item part >+ * of the PMID (10 bits) is split into two (5 bits each) - top contains >+ * the metric ID (item), bottom holds the cgroup ID (index - e.g. this >+ * is the 3rd cgroup we've seen). >+ */ >+ >+static inline pmID >+cgroup_pmid_build(unsigned int domain, unsigned int cluster, >+ unsigned int gid, unsigned int metric) >+{ >+ return pmid_build(domain, cluster, (gid << 5) | metric); >+} >+ >+static inline unsigned int >+cgroup_pmid_group(pmID id) >+{ >+ return pmid_item(id) >> 5; >+} >+ >+static inline unsigned int >+cgroup_pmid_metric(pmID id) >+{ >+ return pmid_item(id) & ((1 << 5) - 1); >+} >+ >+extern void cgroup_init(); >+extern char *cgroup_find_subsys(pmInDom, const char *); >+ >+extern int refresh_cgroups(pmdaExt *, __pmnsTree **); >+extern int refresh_cgroup_subsys(pmInDom); >+extern int refresh_cgroup_groups(pmdaExt *, pmInDom, __pmnsTree **); >+ >+extern int cgroup_group_fetch(int, int, unsigned int, pmAtomValue *); >+extern int cgroup_procs_fetch(int, int, unsigned int, pmAtomValue *); >diff --git a/src/pmdas/linux_proc/clusters.h b/src/pmdas/linux_proc/clusters.h >new file mode 100644 >index 0000000..96e3933 >--- /dev/null >+++ b/src/pmdas/linux_proc/clusters.h >@@ -0,0 +1,85 @@ >+/* >+ * Copyright (c) 2005,2007-2008 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. >+ */ >+ >+#ifndef _CLUSTERS_H >+#define _CLUSTERS_H >+ >+/* >+ * fetch cluster numbers ... to manage the PMID migration after the >+ * linux -> linux + proc PMDAs split, these need to match the enum >+ * assigned values for CLUSTER_* from the linux PMDA. >+ */ >+#define CLUSTER_PID_STAT 8 /* /proc/<pid>/stat */ >+#define CLUSTER_PID_STATM 9 /* /proc/<pid>/statm + /proc/<pid>/maps */ >+#define CLUSTER_PROC_RUNQ 13 /* number of processes in various states */ >+#define CLUSTER_PID_STATUS 24 /* /proc/<pid>/status */ >+#define CLUSTER_PID_SCHEDSTAT 31 /* /proc/<pid>/schedstat */ >+#define CLUSTER_PID_IO 32 /* /proc/<pid>/io */ >+#define CLUSTER_CGROUP_SUBSYS 37 /* /proc/cgroups control group subsystems */ >+#define CLUSTER_CGROUP_MOUNTS 38 /* /proc/mounts active control groups */ >+#define CLUSTER_CPUSET_GROUPS 39 /* cpuset control groups */ >+#define CLUSTER_CPUSET_PROCS 40 /* cpuset control group processes */ >+#define CLUSTER_CPUACCT_GROUPS 41 /* cpu accounting control groups */ >+#define CLUSTER_CPUACCT_PROCS 42 /* cpu accounting group processes */ >+#define CLUSTER_CPUSCHED_GROUPS 43 /* scheduler control groups */ >+#define CLUSTER_CPUSCHED_PROCS 44 /* scheduler group processes */ >+#define CLUSTER_MEMORY_GROUPS 45 /* memory control groups */ >+#define CLUSTER_MEMORY_PROCS 46 /* memory group processes */ >+#define CLUSTER_NET_CLS_GROUPS 47 /* network classification control groups */ >+#define CLUSTER_NET_CLS_PROCS 48 /* network classification group processes */ >+#define CLUSTER_PID_FD 51 /* /proc/<pid>/fd */ >+ >+#define MIN_CLUSTER 8 /* first cluster number we use here */ >+#define NUM_CLUSTERS 52 /* one more than highest cluster number we use here */ >+ >+#if 0 >+enum { >+ CLUSTER_STAT = 0, /* 0 /proc/stat */ >+ CLUSTER_MEMINFO, /* 1 /proc/meminfo */ >+ CLUSTER_LOADAVG, /* 2 /proc/loadavg */ >+ CLUSTER_NET_DEV, /* 3 /proc/net/dev */ >+ CLUSTER_INTERRUPTS, /* 4 /proc/interrupts */ >+ CLUSTER_FILESYS, /* 5 /proc/mounts + statfs */ >+ CLUSTER_SWAPDEV, /* 6 /proc/swaps */ >+ CLUSTER_NET_NFS, /* 7 /proc/net/rpc/nfs + /proc/net/rpc/nfsd */ >+ CLUSTER_PARTITIONS, /* 10 /proc/partitions */ >+ CLUSTER_NET_SOCKSTAT, /* 11 /proc/net/sockstat */ >+ CLUSTER_KERNEL_UNAME, /* 12 uname() system call */ >+ CLUSTER_NET_SNMP, /* 14 /proc/net/snmp */ >+ CLUSTER_SCSI, /* 15 /proc/scsi/scsi */ >+ CLUSTER_XFS, /* 16 /proc/fs/xfs/stat */ >+ CLUSTER_XFSBUF, /* 17 (deprecated /proc/fs/pagebuf/stat) */ >+ CLUSTER_CPUINFO, /* 18 /proc/cpuinfo */ >+ CLUSTER_NET_TCP, /* 19 /proc/net/tcp */ >+ CLUSTER_SLAB, /* 20 /proc/slabinfo */ >+ CLUSTER_SEM_LIMITS, /* 21 semctl(IPC_INFO) system call */ >+ CLUSTER_MSG_LIMITS, /* 22 msgctl(IPC_INFO) system call */ >+ CLUSTER_SHM_LIMITS, /* 23 shmctl(IPC_INFO) system call */ >+ CLUSTER_NUSERS, /* 25 number of users */ >+ CLUSTER_UPTIME, /* 26 /proc/uptime */ >+ CLUSTER_VFS, /* 27 /proc/sys/fs */ >+ CLUSTER_VMSTAT, /* 28 /proc/vmstat */ >+ CLUSTER_IB, /* deprecated: do not re-use 29 infiniband */ >+ CLUSTER_QUOTA, /* 30 quotactl() */ >+ CLUSTER_NET_INET, /* 33 /proc/net/dev and ioctl(SIOCGIFCONF) */ >+ CLUSTER_TMPFS, /* 34 /proc/mounts + statfs (tmpfs only) */ >+ CLUSTER_SYSFS_KERNEL, /* 35 /sys/kernel metrics */ >+ CLUSTER_NUMA_MEMINFO, /* 36 /sys/devices/system/node* NUMA memory */ >+ CLUSTER_INTERRUPT_LINES,/* 49 /proc/interrupts percpu interrupts */ >+ CLUSTER_INTERRUPT_OTHER,/* 50 /proc/interrupts percpu interrupts */ >+ >+}; >+#endif >+ >+#endif /* _CLUSTERS_H */ >diff --git a/src/pmdas/linux_proc/dynamic.c b/src/pmdas/linux_proc/dynamic.c >new file mode 100644 >index 0000000..cb69deb >--- /dev/null >+++ b/src/pmdas/linux_proc/dynamic.c >@@ -0,0 +1,176 @@ >+/* >+ * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >+ * >+ * Copyright (c) 2010 Aconex. 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 "indom.h" >+#include "dynamic.h" >+#include "clusters.h" >+ >+static struct dynamic { >+ const char *prefix; >+ int prefixlen; >+ int mtabcount; /* internal use only */ >+ int extratrees; /* internal use only */ >+ int nclusters; >+ int clusters[NUM_CLUSTERS]; >+ pmnsUpdate pmnsupdate; >+ textUpdate textupdate; >+ mtabUpdate mtabupdate; >+ mtabCounts mtabcounts; >+ __pmnsTree *pmns; >+} *dynamic; >+ >+static int dynamic_count; >+ >+void >+proc_dynamic_pmns(const char *prefix, int *clusters, int nclusters, >+ pmnsUpdate pmnsupdate, textUpdate textupdate, >+ mtabUpdate mtabupdate, mtabCounts mtabcounts) >+{ >+ int size = (dynamic_count+1) * sizeof(struct dynamic); >+ >+ if ((dynamic = (struct dynamic *)realloc(dynamic, size)) == NULL) { >+ __pmNotifyErr(LOG_ERR, "out-of-memory registering dynamic metrics"); >+ return; >+ } >+ dynamic[dynamic_count].prefix = prefix; >+ dynamic[dynamic_count].prefixlen = strlen(prefix); >+ dynamic[dynamic_count].nclusters = nclusters; >+ memcpy(dynamic[dynamic_count].clusters, clusters, nclusters * sizeof(int)); >+ dynamic[dynamic_count].pmnsupdate = pmnsupdate; >+ dynamic[dynamic_count].textupdate = textupdate; >+ dynamic[dynamic_count].mtabupdate = mtabupdate; >+ dynamic[dynamic_count].mtabcounts = mtabcounts; >+ dynamic[dynamic_count].pmns = NULL; >+ dynamic_count++; >+} >+ >+__pmnsTree * >+proc_dynamic_lookup_name(pmdaExt *pmda, const char *name) >+{ >+ int i; >+ >+ for (i = 0; i < dynamic_count; i++) { >+ if (strncmp(name, dynamic[i].prefix, dynamic[i].prefixlen) == 0) { >+ if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >+ proc_dynamic_metrictable(pmda); >+ return dynamic[i].pmns; >+ } >+ } >+ return NULL; >+} >+ >+__pmnsTree * >+proc_dynamic_lookup_pmid(pmdaExt *pmda, pmID pmid) >+{ >+ int i, j; >+ int cluster = pmid_cluster(pmid); >+ >+ for (i = 0; i < dynamic_count; i++) { >+ for (j = 0; j < dynamic[i].nclusters; j++) { >+ if (cluster == dynamic[i].clusters[j]) { >+ if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >+ proc_dynamic_metrictable(pmda); >+ return dynamic[i].pmns; >+ } >+ } >+ } >+ return NULL; >+} >+ >+int >+proc_dynamic_lookup_text(pmID pmid, int type, char **buf, pmdaExt *pmda) >+{ >+ int i, j; >+ int cluster = pmid_cluster(pmid); >+ >+ for (i = 0; i < dynamic_count; i++) { >+ for (j = 0; j < dynamic[i].nclusters; j++) >+ if (cluster == dynamic[i].clusters[j]) >+ return dynamic[i].textupdate(pmda, pmid, type, buf); >+ } >+ return -ENOENT; >+} >+ >+/* >+ * Call the update function for each new metric we're adding. >+ * We pass in the original metric, and the new (uninit'd) slot >+ * which needs to be filled in. All a bit obscure, really. >+ */ >+static pmdaMetric * >+proc_dynamic_mtab(struct dynamic *dynamic, pmdaMetric *offset) >+{ >+ int m, metric_count = proc_metrictable_size(); >+ int tree_count = dynamic->extratrees; >+ >+ for (m = 0; m < metric_count; m++) { >+ int c, id, cluster = pmid_cluster(proc_metrictab[m].m_desc.pmid); >+ for (c = 0; c < dynamic->nclusters; c++) >+ if (dynamic->clusters[c] == cluster) >+ break; >+ if (c < dynamic->nclusters) >+ for (id = 0; id < tree_count; id++) >+ dynamic->mtabupdate(&proc_metrictab[m], offset++, id+1); >+ } >+ return offset; >+} >+ >+/* >+ * Iterate through the dynamic table working out how many additional metric >+ * table entries are needed. Then allocate a new metric table, if needed, >+ * and run through the dynamic table once again to fill in the additional >+ * entries. Finally, we update the metric table pointer to be the pmdaExt >+ * for libpcp_pmda routines subsequent use. >+ */ >+void >+proc_dynamic_metrictable(pmdaExt *pmda) >+{ >+ int i, trees, total, resize = 0; >+ pmdaMetric *mtab, *offset; >+ >+ for (i = 0; i < dynamic_count; i++) >+ dynamic[i].mtabcount = dynamic[i].extratrees = 0; >+ >+ for (i = 0; i < dynamic_count; i++) { >+ dynamic[i].mtabcounts(&total, &trees); >+ dynamic[i].mtabcount += total; >+ dynamic[i].extratrees += trees; >+ resize += (total * trees); >+ } >+ >+ if (resize == 0) { >+ /* Fits into the default metric table - reset it to original values */ >+fallback: >+ if (pmda->e_metrics != proc_metrictab) >+ free(pmda->e_metrics); >+ pmda->e_metrics = proc_metrictab; >+ pmda->e_nmetrics = proc_metrictable_size(); >+ } else { >+ resize += proc_metrictable_size(); >+ if ((mtab = calloc(resize, sizeof(pmdaMetric))) == NULL) >+ goto fallback; >+ memcpy(mtab, proc_metrictab, proc_metrictable_size() * sizeof(pmdaMetric)); >+ offset = mtab + proc_metrictable_size(); >+ for (i = 0; i < dynamic_count; i++) >+ offset = proc_dynamic_mtab(&dynamic[i], offset); >+ if (pmda->e_metrics != proc_metrictab) >+ free(pmda->e_metrics); >+ pmda->e_metrics = mtab; >+ pmda->e_nmetrics = resize; >+ } >+} >diff --git a/src/pmdas/linux_proc/dynamic.h b/src/pmdas/linux_proc/dynamic.h >new file mode 100644 >index 0000000..8819f4e >--- /dev/null >+++ b/src/pmdas/linux_proc/dynamic.h >@@ -0,0 +1,31 @@ >+/* >+ * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >+ * >+ * Copyright (c) 2010 Aconex. 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. >+ */ >+ >+/* function to refresh a specific subtree */ >+typedef int (*pmnsUpdate)(pmdaExt *, __pmnsTree **); >+typedef int (*textUpdate)(pmdaExt *, pmID, int, char **); >+typedef void (*mtabUpdate)(pmdaMetric *, pmdaMetric *, int); >+typedef void (*mtabCounts)(int *, int *); >+ >+extern pmdaMetric proc_metrictab[]; /* default metric table */ >+extern int proc_metrictable_size(); >+ >+extern void proc_dynamic_pmns(const char *, int *, int, >+ pmnsUpdate, textUpdate, mtabUpdate, mtabCounts); >+extern __pmnsTree *proc_dynamic_lookup_name(pmdaExt *, const char *); >+extern __pmnsTree *proc_dynamic_lookup_pmid(pmdaExt *, pmID); >+extern int proc_dynamic_lookup_text(pmID, int, char **, pmdaExt *); >+extern void proc_dynamic_metrictable(pmdaExt *); >diff --git a/src/pmdas/linux_proc/filesys.c b/src/pmdas/linux_proc/filesys.c >new file mode 100644 >index 0000000..4db2a10 >--- /dev/null >+++ b/src/pmdas/linux_proc/filesys.c >@@ -0,0 +1,121 @@ >+/* >+ * Linux Filesystem Cluster >+ * >+ * Copyright (c) 2000,2004,2007-2008 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 "filesys.h" >+ >+char * >+scan_filesys_options(const char *options, const char *option) >+{ >+ static char buffer[128]; >+ char *s; >+ >+ strncpy(buffer, options, sizeof(buffer)); >+ >+ s = strtok(buffer, ","); >+ while (s) { >+ if (strcmp(s, option) == 0) >+ return s; >+ s = strtok(NULL, ","); >+ } >+ return NULL; >+} >+ >+int >+refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, >+ pmInDom tmpfs_indom) >+{ >+ char buf[MAXPATHLEN]; >+ char realdevice[MAXPATHLEN]; >+ filesys_t *fs; >+ pmInDom indom; >+ FILE *fp; >+ char *path, *device, *type, *options; >+ int sts; >+ >+ pmdaCacheOp(quota_indom, PMDA_CACHE_INACTIVE); >+ pmdaCacheOp(tmpfs_indom, PMDA_CACHE_INACTIVE); >+ pmdaCacheOp(filesys_indom, PMDA_CACHE_INACTIVE); >+ >+ if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) >+ return -oserror(); >+ >+ while (fgets(buf, sizeof(buf), fp) != NULL) { >+ if ((device = strtok(buf, " ")) == 0) >+ continue; >+ >+ path = strtok(NULL, " "); >+ type = strtok(NULL, " "); >+ options = strtok(NULL, " "); >+ if (strcmp(type, "proc") == 0 || >+ strcmp(type, "nfs") == 0 || >+ strcmp(type, "devfs") == 0 || >+ strcmp(type, "devpts") == 0 || >+ strcmp(type, "cgroup") == 0 || >+ strncmp(type, "auto", 4) == 0) >+ continue; >+ >+ indom = filesys_indom; >+ if (strcmp(type, "tmpfs") == 0) { >+ indom = tmpfs_indom; >+ device = path; >+ } >+ else if (strncmp(device, "/dev", 4) != 0) >+ continue; >+ if (realpath(device, realdevice) != NULL) >+ device = realdevice; >+ >+ sts = pmdaCacheLookupName(indom, device, NULL, (void **)&fs); >+ if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/mounts? */ >+ continue; >+ if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old mount */ >+ pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); >+ if (strcmp(path, fs->path) != 0) { /* old device, new path */ >+ free(fs->path); >+ fs->path = strdup(path); >+ } >+ if (strcmp(options, fs->options) != 0) { /* old device, new opts */ >+ free(fs->options); >+ fs->options = strdup(options); >+ } >+ } >+ else { /* new mount */ >+ if ((fs = malloc(sizeof(filesys_t))) == NULL) >+ continue; >+ fs->device = strdup(device); >+ fs->path = strdup(path); >+ fs->options = strdup(options); >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_LIBPMDA) { >+ fprintf(stderr, "refresh_filesys: add \"%s\" \"%s\"\n", >+ fs->path, device); >+ } >+#endif >+ pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); >+ } >+ fs->flags = 0; >+ } >+ >+ /* >+ * success >+ * Note: we do not call statfs() here since only some instances >+ * may be requested (rather, we do it in linux_fetch, see pmda.c). >+ */ >+ fclose(fp); >+ return 0; >+} >diff --git a/src/pmdas/linux_proc/filesys.h b/src/pmdas/linux_proc/filesys.h >new file mode 100644 >index 0000000..668794c >--- /dev/null >+++ b/src/pmdas/linux_proc/filesys.h >@@ -0,0 +1,34 @@ >+/* >+ * Linux Filesystem Cluster >+ * >+ * Copyright (c) 2000,2004,2007 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 <sys/vfs.h> >+ >+/* Values for flags in filesys_t */ >+#define FSF_FETCHED (1U << 0) >+#define FSF_QUOT_PROJ_ACC (1U << 1) >+#define FSF_QUOT_PROJ_ENF (1U << 2) >+ >+typedef struct filesys { >+ int id; >+ unsigned int flags; >+ char *device; >+ char *path; >+ char *options; >+ struct statfs stats; >+} filesys_t; >+ >+extern int refresh_filesys(pmInDom, pmInDom, pmInDom); >+extern char *scan_filesys_options(const char *, const char *); >diff --git a/src/pmdas/linux_proc/getinfo.c b/src/pmdas/linux_proc/getinfo.c >new file mode 100644 >index 0000000..7bc0a80 >--- /dev/null >+++ b/src/pmdas/linux_proc/getinfo.c >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (c) 2010 Aconex. All Rights Reserved. >+ * Copyright (c) 2000,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 <sys/stat.h> >+#include <sys/dir.h> >+#include <ctype.h> >+#include <fcntl.h> >+#include "pmapi.h" >+ >+char * >+get_ttyname_info(int pid, dev_t dev, char *ttyname) >+{ >+ DIR *dir; >+ struct dirent *dp; >+ struct stat sbuf; >+ int found=0; >+ char procpath[MAXPATHLEN]; >+ char ttypath[MAXPATHLEN]; >+ >+ sprintf(procpath, "/proc/%d/fd", pid); >+ if ((dir = opendir(procpath)) != NULL) { >+ while ((dp = readdir(dir)) != NULL) { >+ if (!isdigit(dp->d_name[0])) >+ continue; >+ sprintf(procpath, "/proc/%d/fd/%s", pid, dp->d_name); >+ if (realpath(procpath, ttypath) == NULL || stat(ttypath, &sbuf) < 0) >+ continue; >+ if (S_ISCHR(sbuf.st_mode) && dev == sbuf.st_rdev) { >+ found=1; >+ break; >+ } >+ } >+ closedir(dir); >+ } >+ >+ if (!found) >+ strcpy(ttyname, "?"); >+ else >+ /* skip the "/dev/" prefix */ >+ strcpy(ttyname, &ttypath[5]); >+ >+ return ttyname; >+} >diff --git a/src/pmdas/linux_proc/getinfo.h b/src/pmdas/linux_proc/getinfo.h >new file mode 100644 >index 0000000..9006c00 >--- /dev/null >+++ b/src/pmdas/linux_proc/getinfo.h >@@ -0,0 +1,16 @@ >+/* >+ * Copyright (c) 2010 Aconex. 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. >+ */ >+ >+extern char *get_ttyname_info(int, dev_t, char *); >+ >diff --git a/src/pmdas/linux_proc/help b/src/pmdas/linux_proc/help >new file mode 100644 >index 0000000..8426f9a >--- /dev/null >+++ b/src/pmdas/linux_proc/help >@@ -0,0 +1,181 @@ >+# >+# Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. >+# Portions Copyright (c) International Business Machines Corp., 2002 >+# Portions Copyright (c) 2007-2009 Aconex. 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. >+# >+# Linux proc 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 >+# >+ >+@ proc.nprocs instantaneous number of processes >+@ proc.psinfo.pid process identifier >+@ proc.psinfo.psargs full command string >+@ proc.psinfo.cmd command name >+@ proc.psinfo.sname process state identifier (see ps(1)). See also proc.runq metrics. >+@ proc.psinfo.ppid parent process identifier >+@ proc.psinfo.pgrp process group identifier >+@ proc.psinfo.session process session identifier >+@ proc.psinfo.tty controlling tty device number (zero if none) >+@ proc.psinfo.tty_pgrp controlling tty process group identifier >+@ proc.psinfo.flags process state flags, as a bitmap >+@ proc.psinfo.minflt count of minor page faults (i.e. reclaims) >+@ proc.psinfo.cmin_flt count of minor page faults (i.e. reclaims) of all exited children >+@ proc.psinfo.maj_flt count of page faults other than reclaims >+@ proc.psinfo.cmaj_flt count of page faults other than reclaims of all exited children >+@ proc.psinfo.utime time (in ms) spent executing user code since process started >+@ proc.psinfo.stime time (in ms) spent executing system code (calls) since process started >+@ proc.psinfo.cutime time (in ms) spent executing user code of all exited children >+@ proc.psinfo.cstime time (in ms) spent executing system code of all exited children >+@ proc.psinfo.priority priority value >+@ proc.psinfo.nice process nice value (negative nice values are lower priority) >+@ proc.psinfo.it_real_value current interval timer value (zero if none) >+@ proc.psinfo.start_time start time of the process relative to system boot time in seconds >+@ proc.psinfo.vsize virtual size of the process in Kbytes >+@ proc.psinfo.rss resident set size (i.e. physical memory) of the process >+@ proc.psinfo.rss_rlim limit on resident set size of process >+@ proc.psinfo.start_code address of the start of the code segment for the process >+@ proc.psinfo.end_code address of the end of the code segment for the process >+@ proc.psinfo.start_stack address of the stack segment for the process >+@ proc.psinfo.esp the value in the esp field of struct task_struct for the process >+@ proc.psinfo.eip the value in the eip field of struct task_struct for the process >+@ proc.psinfo.signal the value in the signal field of struct task_struct for the process >+@ proc.psinfo.blocked the value in the blocked field of struct task_struct for the process >+@ proc.psinfo.sigignore the value in the sigignore field of struct task_struct for the process >+@ proc.psinfo.sigcatch the value in the sigcatch field of struct task_struct for the process >+@ proc.psinfo.wchan wait channel, kernel address this process is blocked or sleeping on >+@ proc.psinfo.nswap count of page swap operations >+@ proc.psinfo.cnswap count of page swap operations of all exited children >+@ proc.psinfo.exit_signal the value in the exit_signal field of struct task_struct for the process >+@ proc.psinfo.ttyname name of controlling tty device, or "?" if none. See also proc.psinfo.tty. >+@ proc.psinfo.processor last CPU the process was running on >+@ proc.psinfo.wchan_s name of an event for which the process is sleeping (if blank, the process is running). >+This field needs access to a namelist file for proper >+address-to-symbol name translation. If no namelist file >+is available, the address is printed instead. The namelist >+file must match the current Linux kernel exactly. >+The search path for the namelist file is as follows: >+ /boot/System.map-`uname -r` >+ /boot/System.map >+ /lib/modules/`uname -r`/System.map >+ /usr/src/linux/System.map >+ /System.map >+@ proc.psinfo.signal_s pending signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.blocked_s blocked signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.sigignore_s ignored signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.sigcatch_s caught signals mask in string form (from /proc/<pid>/status) >+@ proc.memory.size instantaneous virtual size of process, excluding page table and task structure. >+@ proc.memory.rss instantaneous resident size of process, excluding page table and task structure. >+@ proc.memory.share instantaneous amount of memory shared by this process with other processes >+@ proc.memory.textrss instantaneous resident size of process code segment in Kbytes >+@ proc.memory.librss instantaneous resident size of library code mapped by the process, in Kbytes >+@ proc.memory.datrss instantaneous resident size of process data segment, in Kbytes >+@ proc.memory.dirty instantaneous amount of memory that has been modified by the process, in Kbytes >+@ proc.memory.maps table of memory mapped by process in string form from /proc/<pid>/maps >+@ proc.memory.vmsize total virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmlock locked virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmrss resident virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmdata virtual memory used for data (from /proc/<pid>/status) >+@ proc.memory.vmstack virtual memory used for stack (from /proc/<pid>/status) >+@ proc.memory.vmexe virtual memory used for non-library executable code (from /proc/<pid>/status) >+@ proc.memory.vmlib virtual memory used for libraries (from /proc/<pid>/status) >+@ proc.id.uid real user ID from /proc/<pid>/status >+@ proc.id.euid effective user ID from /proc/<pid>/status >+@ proc.id.suid saved user ID from /proc/<pid>/status >+@ proc.id.fsuid filesystem user ID from /proc/<pid>/status >+@ proc.id.gid real group ID from /proc/<pid>/status >+@ proc.id.egid effective group ID from /proc/<pid>/status >+@ proc.id.sgid saved group ID from /proc/<pid>/status >+@ proc.id.fsgid filesystem group ID from /proc/<pid>/status >+@ proc.id.uid_nm real user name based on real user ID from /proc/<pid>/status >+@ proc.id.euid_nm effective user name based on effective user ID from /proc/<pid>/status >+@ proc.id.suid_nm saved user name based on saved user ID from /proc/<pid>/status >+@ proc.id.fsuid_nm filesystem user name based on filesystem user ID from /proc/<pid>/status >+@ proc.id.gid_nm real group name based on real group ID from /proc/<pid>/status >+@ proc.id.egid_nm effective group name based on effective group ID from /proc/<pid>/status >+@ proc.id.sgid_nm saved group name based on saved group ID from /proc/<pid>/status >+@ proc.id.fsgid_nm filesystem group name based on filesystem group ID from /proc/<pid>/status >+ >+@ proc.runq.runnable number of runnable (on run queue) processes >+Instantaneous number of runnable (on run queue) processes, state 'R' in ps >+@ proc.runq.blocked number of processes in uninterruptible sleep >+Instantaneous number of processes in uninterruptible sleep, state 'D' in ps >+@ proc.runq.sleeping number of processes sleeping >+Instantaneous number of processes sleeping, state 'S' in ps >+@ proc.runq.stopped number of traced, stopped or suspended processes >+Instantaneous number of traced, stopped or suspended processes, state >+'T' in ps >+@ proc.runq.swapped number of processes that are swapped >+Instantaneous number of processes (excluding kernel threads) that are >+swapped, state 'SW' in ps >+@ proc.runq.defunct number of defunct/zombie processes >+Instantaneous number of defunct/zombie processes, state 'Z' in ps >+@ proc.runq.unknown number of processes is an unknown state >+Instantaneous number of processes is an unknown state, including all >+kernel threads >+@ proc.runq.kernel number of kernel threads >+Instantaneous number of processes with virtual size of zero (kernel threads) >+ >+@ proc.io.rchar >+Extended accounting information - count of the number of bytes that >+have passed over the read(2), readv(2) and sendfile(2) syscalls by >+each process. >+ >+@ proc.io.wchar >+Extended accounting information - count of the number of bytes that >+have passed over the write(2), writev(2) and sendfile(2) syscalls by >+each process. >+ >+@ proc.io.syscr >+Extended accounting information - count of number of calls to the >+read(2), readv(2) and sendfile(2) syscalls by each process. >+ >+@ proc.io.syscw >+Extended accounting information - count of number of calls to the >+write(2), writev(2) and sendfile(2) syscalls by each process. >+ >+@ proc.io.read_bytes >+Number of bytes physically read on by devices on behalf of this process. >+@ proc.io.write_bytes >+Number of bytes physically written to devices on behalf of this process. >+This must be reduced by any truncated I/O (proc.io.cancelled_write_bytes). >+@ proc.io.cancelled_write_bytes >+Number of bytes cancelled via truncate by this process. Actual physical >+writes for an individual process can be calculated as: >+ proc.io.write_bytes - proc.io.cancelled_write_bytes. >+ >+@ proc.schedstat.cpu_time >+Length of time in nanoseconds that a process has been running, including >+scheduling time. >+@ proc.schedstat.run_delay >+Length of time in nanoseconds that a process spent waiting to be scheduled >+to run in the run queue. >+@ proc.schedstat.pcount >+Number of times a process has been scheduled to run on a CPU (this is >+incremented when a task actually reaches a CPU to run on, not simply >+when it is added to the run queue). >+ >+@ proc.fd.count >+Number of file descriptors this process has open. >+ >diff --git a/src/pmdas/linux_proc/ksym.c b/src/pmdas/linux_proc/ksym.c >new file mode 100644 >index 0000000..3061912 >--- /dev/null >+++ b/src/pmdas/linux_proc/ksym.c >@@ -0,0 +1,551 @@ >+/* >+ * Copyright (c) International Business Machines Corp., 2002 >+ * Copyright (c) 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. >+ */ >+ >+/* >+ * This code originally contributed by Mike Mason <mmlnx@us.ibm.com> >+ * with hints from the procps and ksymoops projects. >+ */ >+ >+#include <ctype.h> >+#include <limits.h> >+#include <sys/time.h> >+#include <sys/utsname.h> >+#include "pmapi.h" >+#include "impl.h" >+#include "ksym.h" >+ >+static struct ksym *ksym_a; >+static size_t ksym_a_sz; >+ >+static int >+find_index(__psint_t addr, int lo, int hi) >+{ >+ int mid; >+ >+ if (lo > hi) { >+ return -1; >+ } >+ >+ mid = lo + ((hi - lo) / 2); >+ if (addr == ksym_a[mid].addr || >+ (addr > ksym_a[mid].addr && addr < ksym_a[mid+1].addr)) { >+ return mid; >+ } >+ >+ if (addr > ksym_a[mid].addr) >+ return find_index(addr, mid+1, hi); >+ else >+ return find_index(addr, lo, mid-1); >+} >+ >+static char * >+find_name_by_addr(__psint_t addr) >+{ >+ int ix = -1; >+ >+ if (ksym_a) >+ ix = find_index(addr, 0, ksym_a_sz - 1); >+ if (ix < 0) >+ return NULL; >+ >+ return ksym_a[ix].name; >+} >+ >+static int >+find_dup_name(int maxix, __psint_t addr, char *name) >+{ >+ int i, res; >+ >+ for (i = 0; i < maxix; i++) { >+ if (ksym_a[i].name) { >+ res = strcmp(ksym_a[i].name, name); >+ if (res > 0) >+ break; >+ if (res == 0) { >+ if (addr == ksym_a[i].addr) >+ return KSYM_FOUND; >+ else >+ return KSYM_FOUND_MISMATCH; >+ } >+ } >+ } >+ >+ return KSYM_NOT_FOUND; >+} >+ >+/* Brute force linear search to determine if the kernel version >+ in System.map matches the running kernel version and returns >+ a tri-state result as follows: >+ >+ 0 no match >+ 1 _end not found but version matched >+ 2 _end found and matched >+ */ >+static int >+validate_sysmap(FILE *fp, char *version, __psint_t end_addr) >+{ >+ __psint_t addr; >+ char type; >+ int ret = 0; >+ char kname[128]; >+ >+ while (fscanf(fp, "%p %c %s", (void **)&addr, &type, kname) != EOF) { >+ if (end_addr && strcmp(kname, "_end") == 0) { >+ ret = (end_addr == addr) ? 2 : 0; >+ break; /* no need to look any further */ >+ } >+ if (strcmp(kname, version) == 0) >+ ret = 1; >+ } >+ >+ return ret; >+} >+ >+char * >+wchan(__psint_t addr) >+{ >+ static char zero; >+ char *p = NULL; >+ >+ if (addr == 0) /* 0 address means not in kernel space */ >+ p = &zero; >+ else if ((p = find_name_by_addr(addr))) { >+ /* strip off "sys_" or leading "_"s if necessary */ >+ if (strncmp(p, "sys_", 4) == 0) >+ p += 4; >+ while (*p == '_' && *p) >+ ++p; >+ } >+ >+ return p; >+} >+ >+static int >+ksym_compare_addr(const void *e1, const void *e2) >+{ >+ struct ksym *ks1 = (struct ksym *) e1; >+ struct ksym *ks2 = (struct ksym *) e2; >+ >+ if (ks1->addr < ks2->addr) >+ return -1; >+ if (ks1->addr > ks2->addr) >+ return 1; >+ return 0; >+} >+ >+static int >+ksym_compare_name(const void *e1, const void *e2) >+{ >+ struct ksym *ks1 = (struct ksym *) e1; >+ struct ksym *ks2 = (struct ksym *) e2; >+ >+ return(strcmp(ks1->name, ks2->name)); >+} >+ >+static int >+read_ksyms(__psint_t *end_addr) >+{ >+ char inbuf[256]; >+ char *ip; >+ char *sp; >+ char *tp; >+ char *p; >+ int ix = 0; >+ int l = 0; >+ int len; >+ int err; >+ FILE *fp; >+ char *ksyms_path = "/proc/ksyms"; >+ >+ *end_addr = 0; >+ if ((fp = fopen(ksyms_path, "r")) == NULL) >+ return -oserror(); >+ >+ while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { >+ l++; >+ >+ /* >+ * /proc/ksyms lines look like this on ia32 ... >+ * >+ * c8804060 __insmod_rtc_S.text_L4576 [rtc] >+ * c010a320 disable_irq_nosync >+ * >+ * else on ia64 ... >+ * >+ * a0000000003e0d28 debug [arsess] >+ * e002100000891140 disable_irq_nosync >+ */ >+ >+ if (strstr(inbuf, "\n") == NULL) { >+ fprintf(stderr, "read_ksyms: truncated /proc/ksyms line [%d]: %s\n", l-1, inbuf); >+ continue; >+ } >+ >+ /* Increase array size, if necessary */ >+ if (ksym_a_sz < ix+1) { >+ if (ksym_a_sz > 0) >+ ksym_a_sz += INCR_KSIZE; >+ else >+ ksym_a_sz = INIT_KSIZE; >+ ksym_a = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); >+ if (ksym_a == NULL) { >+ err = -oserror(); >+ fclose(fp); >+ return err; >+ } >+ } >+ >+ ip = inbuf; >+ /* parse over address */ >+ while (isxdigit((int)*ip)) ip++; >+ >+ if (!isspace((int)*ip) || ip-inbuf < 4) { >+ /* bad format line */ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "read_ksyms: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >+ } >+#endif >+ continue; >+ } >+ >+ sscanf(inbuf, "%p", (void **)&ksym_a[ix].addr); >+ >+ while (isblank((int)*ip)) ip++; >+ >+ /* next should be the symbol name */ >+ sp = ip++; >+ while (!isblank((int)*ip) &&*ip != '\n') ip++; >+ >+ /* strip off GPLONLY_ prefix, if found */ >+ if (strncmp(sp, "GPLONLY_", 8) == 0) >+ sp += 8; >+ >+ /* >+ * strip off symbol version suffix, if found ... looking for >+ * trailing pattern of the form _R.*[0-9a-fA-F]{8,} >+ * - find rightmost _R, if any >+ */ >+ tp = sp; >+ while ((p = strstr(tp, "_R")) != NULL) tp = p+2; >+ if (tp > sp) { >+ /* >+ * found _R, need the last 8 digits to be hex >+ */ >+ if (ip - tp + 1 >= 8) { >+ for (p = &ip[-8]; p < ip; p++) { >+ if (!isxdigit(*p)) { >+ tp = sp; >+ break; >+ } >+ } >+ } >+ else { >+ /* not enough characters for [0-9a-fA-f]{8,} at the end */ >+ tp = sp; >+ } >+ } >+ if (tp > sp) >+ /* need to strip the trailing _R.*[0-9a-fA-f]{8,} */ >+ len = tp - sp - 2; >+ else >+ len = ip - sp + 1; >+ >+ ksym_a[ix].name = strndup(sp, len); >+ if (ksym_a[ix].name == NULL) { >+ err = -oserror(); >+ fclose(fp); >+ return err; >+ } >+ ksym_a[ix].name[len-1] = '\0'; >+ >+ if (*end_addr == 0 && strcmp(ksym_a[ix].name, "_end") == 0) >+ *end_addr = ksym_a[ix].addr; >+ >+ if (*ip == '\n') >+ /* nothing after the symbol name, so no module name */ >+ goto next; >+ >+ while (isblank((int)*ip)) ip++; >+ >+ /* next expect module name */ >+ if (*ip != '[') { >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "read_ksyms: bad start module name %c[%d] != [ line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >+ } >+#endif >+ free(ksym_a[ix].name); >+ continue; >+ } >+ >+ sp = ++ip; >+ while (!isblank((int)*ip) && *ip != ']') ip++; >+ >+ if (*ip != ']') { >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "read_ksyms: bad end module name %c[%d] != ] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >+ } >+#endif >+ free(ksym_a[ix].name); >+ continue; >+ } >+ >+ ksym_a[ix].module = strndup(sp, ip - sp + 1); >+ if (ksym_a[ix].module == NULL) { >+ err = -oserror(); >+ fclose(fp); >+ free(ksym_a[ix].name); >+ return err; >+ } >+ ksym_a[ix].module[ip - sp] = '\0'; >+ >+next: >+ ix++; >+ } >+ >+ /* release unused ksym array entries */ >+ if (ix) { >+ ksym_a = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); >+ if (ksym_a == NULL) >+ return -oserror(); >+ } >+ >+ ksym_a_sz = ix; >+ >+ qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_name); >+ >+ fclose(fp); >+ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "symbols from ksyms ...\n"); >+ for (ix = 0; ix < ksym_a_sz; ix++) { >+ fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); >+ if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); >+ fprintf(stderr, "\n"); >+ } >+ } >+#endif >+ >+ return ksym_a_sz; >+} >+ >+static int >+read_sysmap(const char *release, __psint_t end_addr) >+{ >+ char inbuf[256], path[MAXPATHLEN], **fmt; >+ __psint_t addr; >+ int ix, res, i, e; >+ int l = 0; >+ char *ip; >+ char *sp; >+ int major, minor, patch; >+ FILE *fp; >+ char *bestpath = NULL; >+ int ksym_mismatch_count; >+ char *sysmap_paths[] = { /* Paths to check for System.map file */ >+ "/boot/System.map-%s", >+ "/boot/System.map", >+ "/lib/modules/%s/System.map", >+ "/usr/src/linux/System.map", >+ "/System.map", >+ NULL >+ }; >+ >+ /* Create version symbol name to look for in System.map */ >+ if (sscanf(release, "%d.%d.%d", &major, &minor, &patch) < 3 ) >+ return -1; >+ sprintf(inbuf, "Version_%u", KERNEL_VERSION(major, minor, patch)); >+ >+ /* >+ * Walk through System.map path list looking for one that matches >+ * either _end from /proc/ksyms or the uts version. >+ */ >+ for (fmt = sysmap_paths; *fmt; fmt++) { >+ snprintf(path, MAXPATHLEN, *fmt, release); >+ if ((fp = fopen(path, "r"))) { >+ if ((e = validate_sysmap(fp, inbuf, end_addr)) != 0) { >+ if (e == 2) { >+ /* matched _end, so this is the right System.map */ >+ if (bestpath) >+ free(bestpath); >+ bestpath = strdup(path); >+ } >+ else >+ if (e == 1 && !bestpath) >+ bestpath = strdup(path); >+ } >+ fclose(fp); >+ if (e == 2) { >+ /* _end matched => don't look any further */ >+ break; >+ } >+ } >+ } >+ >+ if (bestpath) >+ fprintf(stderr, "NOTICE: using \"%s\" for kernel symbols map.\n", bestpath); >+ else { >+ /* Didn't find a valid System.map */ >+ fprintf(stderr, "Warning: Valid System.map file not found!\n"); >+ fprintf(stderr, "Warning: proc.psinfo.wchan_s symbol names cannot be derived!\n"); >+ fprintf(stderr, "Warning: Addresses will be returned for proc.psinfo.wchan_s instead!\n"); >+ /* Free symbol array */ >+ for (i = 0; i < ksym_a_sz; i++) { >+ if (ksym_a[i].name) >+ free(ksym_a[i].name); >+ if (ksym_a[i].module) >+ free(ksym_a[i].module); >+ } >+ free(ksym_a); >+ ksym_a = NULL; >+ ksym_a_sz = 0; >+ return -1; >+ } >+ >+ /* scan the System map */ >+ if ((fp = fopen(bestpath, "r")) == NULL) >+ return -oserror(); >+ >+ ix = ksym_a_sz; >+ >+ /* Read each line in System.map */ >+ ksym_mismatch_count = 0; >+ while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { >+ i++; >+ >+ /* >+ * System.map lines look like this on ia32 ... >+ * >+ * c010a320 T disable_irq_nosync >+ * >+ * else on ia64 ... >+ * >+ * e002000000014c80 T disable_irq_nosync >+ */ >+ >+ if (strstr(inbuf, "\n") == NULL) { >+ fprintf(stderr, "read_sysmap: truncated System.map line [%d]: %s\n", l-1, inbuf); >+ continue; >+ } >+ >+ /* Increase array size, if necessary */ >+ if (ksym_a_sz < ix+1) { >+ ksym_a_sz += INCR_KSIZE; >+ ksym_a = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); >+ if (ksym_a == NULL) >+ goto fail; >+ } >+ >+ ip = inbuf; >+ /* parse over address */ >+ while (isxdigit((int)*ip)) ip++; >+ >+ if (!isspace((int)*ip) || ip-inbuf < 4) { >+ /* bad format line */ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "read_sysmap: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >+ } >+#endif >+ continue; >+ } >+ >+ sscanf(inbuf, "%p", (void **)&addr); >+ >+ while (isblank((int)*ip)) ip++; >+ >+ /* Only interested in symbol types that map to code addresses, >+ * so: t, T, W or A >+ */ >+ if (*ip != 't' && *ip != 'T' && *ip != 'W' && *ip != 'A') >+ continue; >+ >+ ip++; >+ while (isblank((int)*ip)) ip++; >+ >+ /* next should be the symbol name */ >+ sp = ip++; >+ while (!isblank((int)*ip) && *ip != '\n') ip++; >+ *ip = '\0'; >+ >+ /* Determine if symbol is already in ksym array. >+ If so, make sure the addresses match. */ >+ res = find_dup_name(ix - 1, addr, sp); >+ if (res == KSYM_NOT_FOUND) { /* add it */ >+ ksym_a[ix].name = strdup(sp); >+ if (ksym_a[ix].name == NULL) >+ goto fail; >+ ksym_a[ix].addr = addr; >+ ix++; >+ } >+ else if (res == KSYM_FOUND_MISMATCH) { >+ if (ksym_mismatch_count++ < KSYM_MISMATCH_MAX_ALLOWED) { >+ /* >+ * ia64 function pointer descriptors make this validation >+ * next to useless. So only report the first >+ * KSYM_MISMATCH_MAX_ALLOWED mismatches found. >+ */ >+ fprintf(stderr, "Warning: mismatch for \"%s\" between System.map" >+ " and /proc/ksyms.\n", sp); >+ } >+ } >+ } >+ >+ if (ksym_mismatch_count > KSYM_MISMATCH_MAX_ALLOWED) { >+ fprintf(stderr, "Warning: only reported first %d out of %d mismatches " >+ "between System.map and /proc/ksyms.\n", >+ KSYM_MISMATCH_MAX_ALLOWED, ksym_mismatch_count); >+ } >+ >+ /* release unused ksym array entries */ >+ ksym_a = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); >+ if (ksym_a == NULL) >+ goto fail; >+ >+ ksym_a_sz = ix; >+ >+ qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_addr); >+ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_APPL2) { >+ fprintf(stderr, "symbols from ksyms + sysmap ...\n"); >+ for (ix = 0; ix < ksym_a_sz; ix++) { >+ fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); >+ if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); >+ fprintf(stderr, "\n"); >+ } >+ } >+#endif >+ >+ return ksym_a_sz; >+ >+fail: >+ e = -oserror(); >+ if (fp) >+ fclose(fp); >+ return e; >+} >+ >+void >+read_ksym_sources(const char *release) >+{ >+ __psint_t end_addr; >+ >+ if (read_ksyms(&end_addr) > 0) /* read /proc/ksyms first */ >+ read_sysmap(release, end_addr); /* then System.map */ >+} >diff --git a/src/pmdas/linux_proc/ksym.h b/src/pmdas/linux_proc/ksym.h >new file mode 100644 >index 0000000..f328ca4 >--- /dev/null >+++ b/src/pmdas/linux_proc/ksym.h >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (c) International Business Machines Corp., 2002 >+ * >+ * 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 >+ */ >+ >+/* >+ * This code contributed by Mike Mason (mmlnx@us.ibm.com) >+ */ >+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) >+ >+#define INIT_KSIZE 8192 >+#define INCR_KSIZE 2048 >+ >+#define KSYM_FOUND_MISMATCH -1 >+#define KSYM_NOT_FOUND 0 >+#define KSYM_FOUND 1 >+ >+#define KSYM_MISMATCH_MAX_ALLOWED 10 >+ >+struct ksym { >+ __psint_t addr; >+ char *name; >+ char *module; >+}; >+ >+extern char *wchan(__psint_t); >+extern void read_ksym_sources(const char *); >+ >diff --git a/src/pmdas/linux_proc/pmda.c b/src/pmdas/linux_proc/pmda.c >new file mode 100644 >index 0000000..947020e >--- /dev/null >+++ b/src/pmdas/linux_proc/pmda.c >@@ -0,0 +1,1467 @@ >+/* >+ * proc PMDA >+ * >+ * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Portions Copyright (c) 2002 International Business Machines Corp. >+ * Portions Copyright (c) 2007-2011 Aconex. 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 "dynamic.h" >+ >+#include <ctype.h> >+#include <sys/vfs.h> >+#include <sys/stat.h> >+#include <sys/times.h> >+#include <sys/utsname.h> >+#include <utmp.h> >+#include <pwd.h> >+#include <grp.h> >+ >+#include "../linux/convert.h" >+#include "../linux/filesys.h" >+#include "clusters.h" >+#include "indom.h" >+ >+#include "getinfo.h" >+#include "proc_pid.h" >+#include "proc_runq.h" >+#include "ksym.h" >+#include "cgroups.h" >+ >+static proc_pid_t proc_pid; >+static struct utsname kernel_uname; >+static proc_runq_t proc_runq; >+ >+static int _isDSO = 1; /* =0 I am a daemon */ >+ >+/* globals */ >+size_t _pm_system_pagesize; /* for hinv.pagesize and used elsewhere */ >+ >+pmdaIndom indomtab[] = { >+ { CPU_INDOM, 0, NULL }, >+ { PROC_INDOM, 0, NULL }, >+ { CGROUP_SUBSYS_INDOM, 0, NULL }, >+ { CGROUP_MOUNTS_INDOM, 0, NULL }, >+}; >+ >+ >+/* >+ * all metrics supported in this PMDA - one table entry for each >+ */ >+ >+pmdaMetric proc_metrictab[] = { >+ >+/* >+ * proc/<pid>/stat cluster >+ */ >+ >+/* proc.nprocs */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.pid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.cmd */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,1), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sname */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,2), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.ppid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.pgrp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.session */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.tty */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.tty_pgrp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.flags */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,8), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.minflt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,9), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cmin_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,10), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.maj_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,11), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cmaj_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,12), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.utime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,13), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.stime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,14), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.cutime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,15), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.cstime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,16), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.priority */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,17), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.nice */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,18), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+#if 0 >+/* invalid field */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,19), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#endif >+ >+/* proc.psinfo.it_real_value */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.start_time */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) } }, >+ >+/* proc.psinfo.vsize */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.rss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.rss_rlim */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.start_code */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.end_code */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.start_stack */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,27), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.esp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,28), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.eip */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,29), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.signal */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,30), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.blocked */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,31), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sigignore */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,32), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sigcatch */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,33), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.wchan */ >+#if defined(HAVE_64BIT_PTR) >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U64, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#elif defined(HAVE_32BIT_PTR) >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#else >+ error! unsupported pointer size >+#endif >+ >+/* proc.psinfo.nswap */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,35), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cnswap */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,36), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.exit_signal */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,37), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.processor -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,38), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.ttyname */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,39), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.wchan_s -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,40), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.psargs -- modified by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,41), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* >+ * proc/<pid>/status cluster >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ >+/* proc.id.uid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.euid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.suid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsuid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.gid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.egid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.sgid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsgid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.uid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,8), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.euid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,9), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.suid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,10), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsuid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,11), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.gid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,12), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.egid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,13), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.sgid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,14), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsgid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,15), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.signal_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,16), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.blocked_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,17), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.sigignore_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,18), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.sigcatch_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,19), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.memory.vmsize */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmlock */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmdata */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmstack */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmexe */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmlib */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* >+ * proc/<pid>/statm cluster >+ */ >+ >+/* proc.memory.size */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.rss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.share */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.textrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.librss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.datrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.dirty */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.maps -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,7), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* >+ * proc/<pid>/schedstat cluster >+ */ >+ >+/* proc.schedstat.cpu_time */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >+/* proc.schedstat.run_delay */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >+/* proc.schedstat.pcount */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,2), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+ >+/* >+ * proc/<pid>/io cluster >+ */ >+/* proc.io.rchar */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.wchar */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.syscr */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,2), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.syscw */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,3), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.read_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,4), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+/* proc.io.write_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,5), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+/* proc.io.cancelled_write_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,6), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* >+ * proc.runq cluster >+ */ >+ >+/* proc.runq.runnable */ >+ { &proc_runq.runnable, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.blocked */ >+ { &proc_runq.blocked, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.sleeping */ >+ { &proc_runq.sleeping, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.stopped */ >+ { &proc_runq.stopped, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.swapped */ >+ { &proc_runq.swapped, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.defunct */ >+ { &proc_runq.defunct, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.unknown */ >+ { &proc_runq.unknown, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.kernel */ >+ { &proc_runq.kernel, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+ >+ >+/* >+ * control groups cluster >+ */ >+ /* cgroups.subsys.hierarchy */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,0), PM_TYPE_U32, >+ CGROUP_SUBSYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroups.subsys.count */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,1), PM_TYPE_U32, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >+ >+ /* cgroups.mounts.subsys */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,0), PM_TYPE_STRING, >+ CGROUP_MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroups.mounts.count */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,1), PM_TYPE_U32, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >+ >+#if 0 /* not yet implemented */ >+ /* cgroup.groups.cpuset.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpuset.[<group>.]cpus */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,0), PM_TYPE_STRING, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroup.groups.cpuset.[<group>.]mems */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,1), PM_TYPE_STRING, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+#if 0 /* not yet implemented */ >+ /* cgroup.groups.cpuacct.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpuacct.[<group>.]stat.user */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]stat.system */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,1), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]usage */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,2), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]usage_percpu */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,3), PM_TYPE_U64, >+ CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.cpusched.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpusched.[<group>.]shares */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.memory.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.memory.[<group>.]stat.cache */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.rss */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,1), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.pgin */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,2), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.pgout */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,3), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.swap */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,4), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.active_anon */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,5), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.inactive_anon */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,6), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.active_file */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,7), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.inactive_file */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,8), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.unevictable */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,9), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.netclass.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_NET_CLS_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.netclass.[<group>.]classid */ >+ { NULL, {PMDA_PMID(CLUSTER_NET_CLS_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+/* >+ * proc/<pid>/fd cluster >+ */ >+ >+ /* proc.fd.count */ >+ { NULL, {PMDA_PMID(CLUSTER_PID_FD,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+}; >+ >+int >+refresh_cgroups(pmdaExt *pmda, __pmnsTree **tree) >+{ >+ int changed; >+ time_t rightnow; >+ static time_t previoustime; >+ static __pmnsTree *previoustree; >+ >+ if (tree) { >+ if ((rightnow = time(NULL)) == previoustime) { >+ *tree = previoustree; >+ return 0; >+ } >+ } >+ >+ refresh_cgroup_subsys(INDOM(CGROUP_SUBSYS_INDOM)); >+ changed = refresh_cgroup_groups(pmda, INDOM(CGROUP_MOUNTS_INDOM), tree); >+ >+ if (tree) { >+ previoustime = rightnow; >+ previoustree = *tree; >+ } >+ return changed; >+} >+ >+static void >+proc_refresh(pmdaExt *pmda, int *need_refresh) >+{ >+ int need_refresh_mtab = 0; >+ >+ if (need_refresh[CLUSTER_CGROUP_SUBSYS] || >+ need_refresh[CLUSTER_CGROUP_MOUNTS] || >+ need_refresh[CLUSTER_CPUSET_PROCS] || >+ need_refresh[CLUSTER_CPUSET_GROUPS] || >+ need_refresh[CLUSTER_CPUACCT_PROCS] || >+ need_refresh[CLUSTER_CPUACCT_GROUPS] || >+ need_refresh[CLUSTER_CPUSCHED_PROCS] || >+ need_refresh[CLUSTER_CPUSCHED_GROUPS] || >+ need_refresh[CLUSTER_MEMORY_PROCS] || >+ need_refresh[CLUSTER_MEMORY_GROUPS] || >+ need_refresh[CLUSTER_NET_CLS_PROCS] || >+ need_refresh[CLUSTER_NET_CLS_GROUPS]) { >+ need_refresh_mtab |= refresh_cgroups(pmda, NULL); >+ } >+ >+ if (need_refresh[CLUSTER_PID_STAT] || need_refresh[CLUSTER_PID_STATM] || >+ need_refresh[CLUSTER_PID_STATUS] || need_refresh[CLUSTER_PID_IO] || >+ need_refresh[CLUSTER_PID_SCHEDSTAT] || need_refresh[CLUSTER_PID_FD]) >+ refresh_proc_pid(&proc_pid); >+ >+ if (need_refresh[CLUSTER_PROC_RUNQ]) >+ refresh_proc_runq(&proc_runq); >+ >+ if (need_refresh_mtab) >+ proc_dynamic_metrictable(pmda); >+} >+ >+static int >+proc_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) >+{ >+ __pmInDom_int *indomp = (__pmInDom_int *)&indom; >+ int need_refresh[NUM_CLUSTERS]; >+ char newname[11]; /* see Note below */ >+ >+ memset(need_refresh, 0, sizeof(need_refresh)); >+ switch (indomp->serial) { >+ case CPU_INDOM: >+ // TODO - need to pull back CPU_INDOM setup from proc_stat.c >+ // in linux PMDA to populate the indom for >+ // cgroup.groups.cpuacct.[<group>.]usage_percpu >+ // probably gut refresh_proc_stat() to make refresh_cpu_indom() >+ need_refresh[CLUSTER_CPUACCT_GROUPS]++; >+ break; >+ case PROC_INDOM: >+ need_refresh[CLUSTER_PID_STAT]++; >+ need_refresh[CLUSTER_PID_STATM]++; >+ need_refresh[CLUSTER_PID_STATUS]++; >+ need_refresh[CLUSTER_PID_SCHEDSTAT]++; >+ need_refresh[CLUSTER_PID_IO]++; >+ need_refresh[CLUSTER_PID_FD]++; >+ break; >+ case CGROUP_SUBSYS_INDOM: >+ need_refresh[CLUSTER_CGROUP_SUBSYS]++; >+ break; >+ case CGROUP_MOUNTS_INDOM: >+ need_refresh[CLUSTER_CGROUP_MOUNTS]++; >+ break; >+ /* no default label : pmdaInstance will pick up errors */ >+ } >+ >+ if (indomp->serial == PROC_INDOM && inst == PM_IN_NULL && name != NULL) { >+ /* >+ * For the proc indom, if the name is a pid (as a string), and it >+ * contains only digits (i.e. it's not a full instance name) then >+ * reformat it to be exactly six digits, with leading zeros. >+ * >+ * Note that although format %06d is used here and in proc_pid.c, >+ * the pid could be longer than this (in which case there >+ * are no leading zeroes. The size of newname[] is chosen >+ * to comfortably accommodate a 32-bit pid (Linux maximum), >+ * or max value of 4294967295 (10 digits) >+ */ >+ char *p; >+ for (p = name; *p != '\0'; p++) { >+ if (!isdigit(*p)) >+ break; >+ } >+ if (*p == '\0') { >+ snprintf(newname, sizeof(newname), "%06d", atoi(name)); >+ name = newname; >+ } >+ } >+ >+ proc_refresh(pmda, need_refresh); >+ return pmdaInstance(indom, inst, name, result, pmda); >+} >+ >+/* >+ * callback provided to pmdaFetch >+ */ >+ >+static int >+proc_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) >+{ >+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); >+ int i; >+ int sts; >+ char *f; >+ unsigned long ul; >+ int *ip; >+ proc_pid_entry_t *entry; >+ struct filesys *fs; >+ static int hz = -1; >+ >+ if (mdesc->m_user != NULL) { >+ /* >+ * The metric value is extracted directly via the address specified >+ * in metrictab. Note: not all metrics support this - those that >+ * don't have NULL for the m_user field in their respective >+ * metrictab slot. >+ */ >+ >+ switch (mdesc->m_desc.type) { >+ case PM_TYPE_32: >+ atom->l = *(__int32_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_U32: >+ atom->ul = *(__uint32_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_64: >+ atom->ll = *(__int64_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_U64: >+ atom->ull = *(__uint64_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_FLOAT: >+ atom->f = *(float *)mdesc->m_user; >+ break; >+ case PM_TYPE_DOUBLE: >+ atom->d = *(double *)mdesc->m_user; >+ break; >+ case PM_TYPE_STRING: >+ atom->cp = (char *)mdesc->m_user; >+ break; >+ default: >+ return 0; >+ } >+ } >+ else >+ switch (idp->cluster) { >+ >+ case CLUSTER_PID_STAT: >+ if (idp->item == 99) /* proc.nprocs */ >+ atom->ul = proc_pid.indom->it_numinst; >+ else { >+ static char ttyname[MAXPATHLEN]; >+ >+ if ((entry = fetch_proc_pid_stat(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ >+ case PROC_PID_STAT_PID: >+ atom->ul = entry->id; >+ break; >+ >+ case PROC_PID_STAT_TTYNAME: >+ if ((f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_TTY)) == NULL) >+ atom->cp = "?"; >+ else { >+ dev_t dev = (dev_t)atoi(f); >+ atom->cp = get_ttyname_info(inst, dev, ttyname); >+ } >+ break; >+ >+ case PROC_PID_STAT_CMD: >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = f + 1; >+ atom->cp[strlen(atom->cp)-1] = '\0'; >+ break; >+ >+ case PROC_PID_STAT_PSARGS: >+ atom->cp = entry->name + 7; >+ break; >+ >+ case PROC_PID_STAT_STATE: >+ /* >+ * string >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = f; >+ break; >+ >+ case PROC_PID_STAT_VSIZE: >+ case PROC_PID_STAT_RSS_RLIM: >+ /* >+ * bytes converted to kbytes >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul /= 1024; >+ break; >+ >+ case PROC_PID_STAT_RSS: >+ /* >+ * pages converted to kbytes >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul *= _pm_system_pagesize / 1024; >+ break; >+ >+ case PROC_PID_STAT_UTIME: >+ case PROC_PID_STAT_STIME: >+ case PROC_PID_STAT_CUTIME: >+ case PROC_PID_STAT_CSTIME: >+ /* >+ * unsigned jiffies converted to unsigned milliseconds >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ >+ sscanf(f, "%lu", &ul); >+ if (hz == -1) { >+ // TODO one trip initialization, same way >+ // proc_stat.hz is set in the linux PMDA >+ ; >+ } >+ _pm_assign_ulong(atom, 1000 * (double)ul / hz); >+ break; >+ >+ case PROC_PID_STAT_PRIORITY: >+ case PROC_PID_STAT_NICE: >+ /* >+ * signed decimal int >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%d", &atom->l); >+ break; >+ >+ case PROC_PID_STAT_WCHAN: >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+#endif >+ break; >+ >+ case PROC_PID_STAT_WCHAN_SYMBOL: >+ if (entry->wchan_buf) /* 2.6 kernel, /proc/<pid>/wchan */ >+ atom->cp = entry->wchan_buf; >+ else { /* old school (2.4 kernels, at least) */ >+ char *wc; >+ /* >+ * Convert address to symbol name if requested >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_WCHAN); >+ if (f == NULL) >+ return PM_ERR_INST; >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+ if ((wc = wchan(atom->ull))) >+ atom->cp = wc; >+ else >+ atom->cp = atom->ull ? f : ""; >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+ if ((wc = wchan((__psint_t)atom->ul))) >+ atom->cp = wc; >+ else >+ atom->cp = atom->ul ? f : ""; >+#endif >+ } >+ break; >+ >+ default: >+ /* >+ * unsigned decimal int >+ */ >+ if (idp->item >= 0 && idp->item < NR_PROC_PID_STAT) { >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ } >+ else >+ return PM_ERR_PMID; >+ break; >+ } >+ } >+ break; >+ >+ case CLUSTER_PID_STATM: >+ if (idp->item == PROC_PID_STATM_MAPS) { /* proc.memory.maps */ >+ if ((entry = fetch_proc_pid_maps(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = entry->maps_buf; >+ } else { >+ if ((entry = fetch_proc_pid_statm(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ if (idp->item >= 0 && idp->item <= PROC_PID_STATM_DIRTY) { >+ /* unsigned int */ >+ if ((f = _pm_getfield(entry->statm_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul *= _pm_system_pagesize / 1024; >+ } >+ else >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ case CLUSTER_PID_SCHEDSTAT: >+ if ((entry = fetch_proc_pid_schedstat(inst, &proc_pid)) == NULL) >+ return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; >+ >+ if (idp->item >= 0 && idp->item < NR_PROC_PID_SCHED) { >+ if ((f = _pm_getfield(entry->schedstat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ if (idp->item == PROC_PID_SCHED_PCOUNT && >+ mdesc->m_desc.type == PM_TYPE_U32) >+ sscanf(f, "%u", &atom->ul); >+ else >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+#endif >+ } >+ else >+ return PM_ERR_PMID; >+ break; >+ >+ case CLUSTER_PID_IO: >+ if ((entry = fetch_proc_pid_io(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ case PROC_PID_IO_RCHAR: >+ if ((f = _pm_getfield(entry->io_lines.rchar, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_WCHAR: >+ if ((f = _pm_getfield(entry->io_lines.wchar, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_SYSCR: >+ if ((f = _pm_getfield(entry->io_lines.syscr, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_SYSCW: >+ if ((f = _pm_getfield(entry->io_lines.syscw, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_READ_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.readb, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_WRITE_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.writeb, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_CANCELLED_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.cancel, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_PID_STATUS: >+ if ((entry = fetch_proc_pid_status(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ case PROC_PID_STATUS_UID: >+ case PROC_PID_STATUS_EUID: >+ case PROC_PID_STATUS_SUID: >+ case PROC_PID_STATUS_FSUID: >+ case PROC_PID_STATUS_UID_NM: >+ case PROC_PID_STATUS_EUID_NM: >+ case PROC_PID_STATUS_SUID_NM: >+ case PROC_PID_STATUS_FSUID_NM: >+ { >+ struct passwd *pwe; >+ >+ if ((f = _pm_getfield(entry->status_lines.uid, (idp->item % 4) + 1)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ if (idp->item > PROC_PID_STATUS_FSUID) { >+ if ((pwe = getpwuid((uid_t)atom->ul)) != NULL) >+ atom->cp = pwe->pw_name; >+ else >+ atom->cp = "UNKNOWN"; >+ } >+ } >+ break; >+ >+ case PROC_PID_STATUS_GID: >+ case PROC_PID_STATUS_EGID: >+ case PROC_PID_STATUS_SGID: >+ case PROC_PID_STATUS_FSGID: >+ case PROC_PID_STATUS_GID_NM: >+ case PROC_PID_STATUS_EGID_NM: >+ case PROC_PID_STATUS_SGID_NM: >+ case PROC_PID_STATUS_FSGID_NM: >+ { >+ struct group *gre; >+ >+ if ((f = _pm_getfield(entry->status_lines.gid, (idp->item % 4) + 1)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ if (idp->item > PROC_PID_STATUS_FSGID) { >+ if ((gre = getgrgid((gid_t)atom->ul)) != NULL) { >+ atom->cp = gre->gr_name; >+ } else { >+ atom->cp = "UNKNOWN"; >+ } >+ } >+ } >+ break; >+ >+ case PROC_PID_STATUS_SIGNAL: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigpnd, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_BLOCKED: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigblk, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_SIGCATCH: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigcgt, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_SIGIGNORE: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigign, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_VMSIZE: >+ if ((f = _pm_getfield(entry->status_lines.vmsize, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMLOCK: >+ if ((f = _pm_getfield(entry->status_lines.vmlck, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMRSS: >+ if ((f = _pm_getfield(entry->status_lines.vmrss, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMDATA: >+ if ((f = _pm_getfield(entry->status_lines.vmdata, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMSTACK: >+ if ((f = _pm_getfield(entry->status_lines.vmstk, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMEXE: >+ if ((f = _pm_getfield(entry->status_lines.vmexe, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMLIB: >+ if ((f = _pm_getfield(entry->status_lines.vmlib, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ case CLUSTER_CGROUP_SUBSYS: >+ switch (idp->item) { >+ case 0: /* cgroup.subsys.hierarchy */ >+ sts = pmdaCacheLookup(INDOM(CGROUP_SUBSYS_INDOM), inst, NULL, (void **)&ip); >+ if (sts < 0) >+ return sts; >+ if (sts != PMDA_CACHE_ACTIVE) >+ return PM_ERR_INST; >+ atom->ul = i; >+ break; >+ >+ case 1: /* cgroup.subsys.count */ >+ atom->ul = pmdaCacheOp(INDOM(CGROUP_SUBSYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >+ break; >+ } >+ break; >+ >+ case CLUSTER_CGROUP_MOUNTS: >+ switch (idp->item) { >+ case 0: /* cgroup.mounts.subsys */ >+ sts = pmdaCacheLookup(INDOM(CGROUP_MOUNTS_INDOM), inst, NULL, (void **)&fs); >+ if (sts < 0) >+ return sts; >+ if (sts != PMDA_CACHE_ACTIVE) >+ return PM_ERR_INST; >+ atom->cp = cgroup_find_subsys(INDOM(CGROUP_SUBSYS_INDOM), fs->options); >+ break; >+ >+ case 1: /* cgroup.mounts.count */ >+ atom->ul = pmdaCacheOp(INDOM(CGROUP_MOUNTS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >+ break; >+ } >+ break; >+ >+ case CLUSTER_CPUSET_GROUPS: >+ case CLUSTER_CPUACCT_GROUPS: >+ case CLUSTER_CPUSCHED_GROUPS: >+ case CLUSTER_MEMORY_GROUPS: >+ case CLUSTER_NET_CLS_GROUPS: >+ return cgroup_group_fetch(idp->cluster, idp->item, inst, atom); >+ >+ case CLUSTER_CPUSET_PROCS: >+ case CLUSTER_CPUACCT_PROCS: >+ case CLUSTER_CPUSCHED_PROCS: >+ case CLUSTER_MEMORY_PROCS: >+ case CLUSTER_NET_CLS_PROCS: >+ return cgroup_procs_fetch(idp->cluster, idp->item, inst, atom); >+ >+ case CLUSTER_PID_FD: >+ if ((entry = fetch_proc_pid_fd(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ if (idp->item != PROC_PID_FD_COUNT) >+ return PM_ERR_INST; >+ >+ atom->ul = entry->fd_count; >+ break; >+ >+ default: /* unknown cluster */ >+ return PM_ERR_PMID; >+ } >+ >+ return 1; >+} >+ >+ >+static int >+proc_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) >+{ >+ int i; >+ int need_refresh[NUM_CLUSTERS]; >+ >+ memset(need_refresh, 0, sizeof(need_refresh)); >+ for (i=0; i < numpmid; i++) { >+ __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); >+ if (idp->cluster >= 0 && idp->cluster < NUM_CLUSTERS) { >+ need_refresh[idp->cluster]++; >+ } >+ >+ } >+ >+ proc_refresh(pmda, need_refresh); >+ return pmdaFetch(numpmid, pmidlist, resp, pmda); >+} >+ >+static int >+proc_store(pmResult *result, pmdaExt *pmda) >+{ >+ return PM_ERR_PERMISSION; >+} >+ >+static int >+proc_text(int ident, int type, char **buf, pmdaExt *pmda) >+{ >+ if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { >+ int sts = proc_dynamic_lookup_text(ident, type, buf, pmda); >+ if (sts != -ENOENT) >+ return sts; >+ } >+ return pmdaText(ident, type, buf, pmda); >+} >+ >+static int >+proc_pmid(const char *name, pmID *pmid, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >+ return pmdaTreePMID(tree, name, pmid); >+} >+ >+static int >+proc_name(pmID pmid, char ***nameset, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_pmid(pmda, pmid); >+ return pmdaTreeName(tree, pmid, nameset); >+} >+ >+static int >+proc_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >+ return pmdaTreeChildren(tree, name, flag, kids, sts); >+} >+ >+int >+proc_metrictable_size(void) >+{ >+ return sizeof(proc_metrictab)/sizeof(proc_metrictab[0]); >+} >+ >+/* >+ * Initialise the agent (both daemon and DSO). >+ */ >+ >+void >+proc_init(pmdaInterface *dp) >+{ >+ _pm_system_pagesize = getpagesize(); >+ if (_isDSO) { >+ char helppath[MAXPATHLEN]; >+ int sep = __pmPathSeparator(); >+ snprintf(helppath, sizeof(helppath), "%s%c" "proc" "%c" "help", >+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >+ pmdaDSO(dp, PMDA_INTERFACE_4, "proc DSO", helppath); >+ } >+ >+ if (dp->status != 0) >+ return; >+ >+ dp->version.four.instance = proc_instance; >+ dp->version.four.store = proc_store; >+ dp->version.four.fetch = proc_fetch; >+ dp->version.four.text = proc_text; >+ dp->version.four.pmid = proc_pmid; >+ dp->version.four.name = proc_name; >+ dp->version.four.children = proc_children; >+ pmdaSetFetchCallBack(dp, proc_fetchCallBack); >+ >+ proc_pid.indom = &indomtab[PROC_INDOM]; >+ >+ /* >+ * Read System.map and /proc/ksyms. Used to translate wait channel >+ * addresses to symbol names. >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ read_ksym_sources(kernel_uname.release); >+ >+ cgroup_init(); >+ >+ pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), proc_metrictab, >+ sizeof(proc_metrictab)/sizeof(proc_metrictab[0])); >+} >+ >+ >+static void >+usage(void) >+{ >+ fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); >+ fputs("Options:\n" >+ " -d domain use domain (numeric) for metrics domain of PMDA\n" >+ " -l logfile write log into logfile rather than using default log name\n", >+ stderr); >+ exit(1); >+} >+ >+/* >+ * Set up the agent if running as a daemon. >+ */ >+ >+int >+main(int argc, char **argv) >+{ >+ int sep = __pmPathSeparator(); >+ int err = 0; >+ int c; >+ pmdaInterface dispatch; >+ char helppath[MAXPATHLEN]; >+ >+ _isDSO = 0; >+ __pmSetProgname(argv[0]); >+ >+ snprintf(helppath, sizeof(helppath), "%s%c" "proc" "%c" "help", >+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >+ pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, PROC, "proc.log", helppath); >+ >+ if ((c = pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err)) != EOF) >+ err++; >+ >+ if (err) >+ usage(); >+ >+ pmdaOpenLog(&dispatch); >+ proc_init(&dispatch); >+ pmdaConnect(&dispatch); >+ pmdaMain(&dispatch); >+ >+ exit(0); >+} >diff --git a/src/pmdas/linux_proc/pmns b/src/pmdas/linux_proc/pmns >new file mode 100644 >index 0000000..7dab4e6 >--- /dev/null >+++ b/src/pmdas/linux_proc/pmns >@@ -0,0 +1,155 @@ >+/* >+ * Metrics for the Linux proc PMDA >+ * >+ * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Portions Copyright (c) International Business Machines Corp., 2002 >+ * Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. >+ * >+ * Note: >+ * names and pmids migrated from the Linux PMDA, with the domain >+ * number changed from LINUX (60) to PROC (3) >+ * >+ * 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 >+ */ >+ >+ >+proc { >+ nprocs PROC:8:99 >+ psinfo >+ memory >+ runq >+ id >+ io >+ schedstat >+ fd >+ cgroup PROC:*:* >+} >+ >+proc.psinfo { >+ pid PROC:8:0 >+ cmd PROC:8:1 >+ sname PROC:8:2 >+ ppid PROC:8:3 >+ pgrp PROC:8:4 >+ session PROC:8:5 >+ tty PROC:8:6 >+ tty_pgrp PROC:8:7 >+ flags PROC:8:8 >+ minflt PROC:8:9 >+ cmin_flt PROC:8:10 >+ maj_flt PROC:8:11 >+ cmaj_flt PROC:8:12 >+ utime PROC:8:13 >+ stime PROC:8:14 >+ cutime PROC:8:15 >+ cstime PROC:8:16 >+ priority PROC:8:17 >+ nice PROC:8:18 >+ /* not valid in 2.2.1 PROC:8:19 */ >+ it_real_value PROC:8:20 >+ start_time PROC:8:21 >+ vsize PROC:8:22 >+ rss PROC:8:23 >+ rss_rlim PROC:8:24 >+ start_code PROC:8:25 >+ end_code PROC:8:26 >+ start_stack PROC:8:27 >+ esp PROC:8:28 >+ eip PROC:8:29 >+ signal PROC:8:30 >+ blocked PROC:8:31 >+ sigignore PROC:8:32 >+ sigcatch PROC:8:33 >+ wchan PROC:8:34 >+ nswap PROC:8:35 >+ cnswap PROC:8:36 >+ exit_signal PROC:8:37 >+ processor PROC:8:38 >+ ttyname PROC:8:39 >+ wchan_s PROC:8:40 >+ psargs PROC:8:41 >+ signal_s PROC:24:16 >+ blocked_s PROC:24:17 >+ sigignore_s PROC:24:18 >+ sigcatch_s PROC:24:19 >+} >+ >+proc.id { >+ uid PROC:24:0 >+ euid PROC:24:1 >+ suid PROC:24:2 >+ fsuid PROC:24:3 >+ gid PROC:24:4 >+ egid PROC:24:5 >+ sgid PROC:24:6 >+ fsgid PROC:24:7 >+ uid_nm PROC:24:8 >+ euid_nm PROC:24:9 >+ suid_nm PROC:24:10 >+ fsuid_nm PROC:24:11 >+ gid_nm PROC:24:12 >+ egid_nm PROC:24:13 >+ sgid_nm PROC:24:14 >+ fsgid_nm PROC:24:15 >+} >+ >+proc.memory { >+ size PROC:9:0 >+ rss PROC:9:1 >+ share PROC:9:2 >+ textrss PROC:9:3 >+ librss PROC:9:4 >+ datrss PROC:9:5 >+ dirty PROC:9:6 >+ maps PROC:9:7 >+ vmsize PROC:24:20 >+ vmlock PROC:24:21 >+ vmrss PROC:24:22 >+ vmdata PROC:24:23 >+ vmstack PROC:24:24 >+ vmexe PROC:24:25 >+ vmlib PROC:24:26 >+} >+ >+proc.runq { >+ runnable PROC:13:0 >+ blocked PROC:13:1 >+ sleeping PROC:13:2 >+ stopped PROC:13:3 >+ swapped PROC:13:4 >+ defunct PROC:13:5 >+ unknown PROC:13:6 >+ kernel PROC:13:7 >+} >+ >+proc.io { >+ rchar PROC:32:0 >+ wchar PROC:32:1 >+ syscr PROC:32:2 >+ syscw PROC:32:3 >+ read_bytes PROC:32:4 >+ write_bytes PROC:32:5 >+ cancelled_write_bytes PROC:32:6 >+} >+ >+proc.schedstat { >+ cpu_time PROC:31:0 >+ run_delay PROC:31:1 >+ pcount PROC:31:2 >+} >+ >+proc.fd { >+ count PROC:51:0 >+} >diff --git a/src/pmdas/linux_proc/proc_pid.c b/src/pmdas/linux_proc/proc_pid.c >new file mode 100644 >index 0000000..ea98642 >--- /dev/null >+++ b/src/pmdas/linux_proc/proc_pid.c >@@ -0,0 +1,723 @@ >+/* >+ * Linux proc/<pid>/{stat,statm,status,maps} Clusters >+ * >+ * Copyright (c) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved. >+ * Copyright (c) 2010 Aconex. 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 <ctype.h> >+#include <dirent.h> >+#include <sys/stat.h> >+#include "proc_pid.h" >+ >+static proc_pid_list_t allpids; >+ >+int >+compare_pid(const void *pa, const void *pb) >+{ >+ int a = *(int *)pa; >+ int b = *(int *)pb; >+ return a - b; >+} >+ >+void >+pidlist_append(proc_pid_list_t *list, const char *pidname) >+{ >+ if (list->count >= list->size) { >+ list->size += 64; >+ if (!(list->pids = (int *)realloc(list->pids, list->size * sizeof(int)))) { >+ perror("pidlist_append: out of memory"); >+ exit(1); /* no recovery from this */ >+ } >+ } >+ list->pids[list->count++] = atoi(pidname); >+} >+ >+static int >+refresh_pidlist() >+{ >+ DIR *dirp, *taskdirp; >+ struct dirent *dp, *tdp; >+ char taskpath[1024]; >+ >+ if ((dirp = opendir("/proc")) == NULL) >+ return -oserror(); >+ >+ allpids.count = 0; >+ while ((dp = readdir(dirp)) != NULL) { >+ if (isdigit(dp->d_name[0])) { >+ pidlist_append(&allpids, dp->d_name); >+ /* readdir on /proc ignores threads */ >+ sprintf(taskpath, "/proc/%s/task", dp->d_name); >+ if ((taskdirp = opendir(taskpath)) != NULL) { >+ while ((tdp = readdir(taskdirp)) != NULL) { >+ if (!isdigit(tdp->d_name[0]) || strcmp(dp->d_name, tdp->d_name) == 0) >+ continue; >+ pidlist_append(&allpids, tdp->d_name); >+ } >+ closedir(taskdirp); >+ } >+ } >+ } >+ closedir(dirp); >+ >+ qsort(allpids.pids, allpids.count, sizeof(int), compare_pid); >+ return allpids.count; >+} >+ >+int >+refresh_proc_pidlist(proc_pid_t *proc_pid, proc_pid_list_t *pidlist) >+{ >+ int i; >+ int fd; >+ char *p; >+ char buf[1024]; >+ __pmHashNode *node, *next, *prev; >+ proc_pid_entry_t *ep; >+ pmdaIndom *indomp = proc_pid->indom; >+ >+ if (indomp->it_numinst < pidlist->count) >+ indomp->it_set = (pmdaInstid *)realloc(indomp->it_set, >+ pidlist->count * sizeof(pmdaInstid)); >+ indomp->it_numinst = pidlist->count; >+ >+ /* >+ * invalidate all entries so we can harvest pids that have exited >+ */ >+ for (i=0; i < proc_pid->pidhash.hsize; i++) { >+ for (node=proc_pid->pidhash.hash[i]; node != NULL; node = node->next) { >+ ep = (proc_pid_entry_t *)node->data; >+ ep->valid = 0; >+ ep->stat_fetched = 0; >+ ep->statm_fetched = 0; >+ ep->status_fetched = 0; >+ ep->schedstat_fetched = 0; >+ ep->maps_fetched = 0; >+ ep->io_fetched = 0; >+ ep->wchan_fetched = 0; >+ ep->fd_fetched = 0; >+ } >+ } >+ >+ /* >+ * walk pidlist and add new pids to the hash table, >+ * marking entries valid as we go ... >+ */ >+ for (i=0; i < pidlist->count; i++) { >+ node = __pmHashSearch(pidlist->pids[i], &proc_pid->pidhash); >+ if (node == NULL) { >+ int k = 0; >+ >+ ep = (proc_pid_entry_t *)malloc(sizeof(proc_pid_entry_t)); >+ memset(ep, 0, sizeof(proc_pid_entry_t)); >+ >+ ep->id = pidlist->pids[i]; >+ >+ sprintf(buf, "/proc/%d/cmdline", pidlist->pids[i]); >+ if ((fd = open(buf, O_RDONLY)) >= 0) { >+ sprintf(buf, "%06d ", pidlist->pids[i]); >+ if ((k = read(fd, buf+7, sizeof(buf)-8)) > 0) { >+ p = buf + k +7; >+ *p-- = '\0'; >+ /* Skip trailing nils, i.e. don't replace them */ >+ while (buf+7 < p) { >+ if (*p-- != '\0') { >+ break; >+ } >+ } >+ /* Remove NULL terminators from cmdline string array */ >+ /* Suggested by Mike Mason <mmlnx@us.ibm.com> */ >+ while (buf+7 < p) { >+ if (*p == '\0') *p = ' '; >+ p--; >+ } >+ } >+ close(fd); >+ } >+ >+ if (k == 0) { >+ /* >+ * If a process is swapped out, /proc/<pid>/cmdline >+ * returns an empty string so we have to get it >+ * from /proc/<pid>/status or /proc/<pid>/stat >+ */ >+ sprintf(buf, "/proc/%d/status", pidlist->pids[i]); >+ if ((fd = open(buf, O_RDONLY)) >= 0) { >+ /* We engage in a bit of a hanky-panky here: >+ * the string should look like "123456 (name)", >+ * we get it from /proc/XX/status as "Name: name\n...", >+ * to fit the 6 digits of PID and opening parenthesis, >+ * save 2 bytes at the start of the buffer. >+ * And don't forget to leave 2 bytes for the trailing >+ * parenthesis and the nil. Here is >+ * an example of what we're trying to achieve: >+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ >+ * | | | N| a| m| e| :|\t| i| n| i| t|\n| S|... >+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ >+ * | 0| 0| 0| 0| 0| 1| | (| i| n| i| t| )|\0|... >+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ >+ if ((k = read(fd, buf+2, sizeof(buf)-4)) > 0) { >+ int bc; >+ >+ if ((p = strchr(buf+2, '\n')) == NULL) >+ p = buf+k; >+ p[0] = ')'; >+ p[1] = '\0'; >+ bc = sprintf(buf, "%06d ", pidlist->pids[i]); >+ buf[bc] = '('; >+ } >+ close(fd); >+ } >+ } >+ >+ if (k <= 0) { >+ /* hmm .. must be exiting */ >+ sprintf(buf, "%06d <exiting>", pidlist->pids[i]); >+ } >+ >+ ep->name = strdup(buf); >+ >+ __pmHashAdd(pidlist->pids[i], (void *)ep, &proc_pid->pidhash); >+ // fprintf(stderr, "## ADDED \"%s\" to hash table\n", buf); >+ } >+ else >+ ep = (proc_pid_entry_t *)node->data; >+ >+ /* mark pid as still existing */ >+ ep->valid = 1; >+ >+ /* refresh the indom pointer */ >+ indomp->it_set[i].i_inst = ep->id; >+ indomp->it_set[i].i_name = ep->name; >+ } >+ >+ /* >+ * harvest exited pids from the pid hash table >+ */ >+ for (i=0; i < proc_pid->pidhash.hsize; i++) { >+ for (prev=NULL, node=proc_pid->pidhash.hash[i]; node != NULL;) { >+ next = node->next; >+ ep = (proc_pid_entry_t *)node->data; >+ // fprintf(stderr, "CHECKING key=%d node=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p ep=" PRINTF_P_PFX "%p valid=%d\n", >+ // ep->id, node, prev, node->next, ep, ep->valid); >+ if (ep->valid == 0) { >+ // fprintf(stderr, "DELETED key=%d name=\"%s\"\n", ep->id, ep->name); >+ if (ep->name != NULL) >+ free(ep->name); >+ if (ep->stat_buf != NULL) >+ free(ep->stat_buf); >+ if (ep->status_buf != NULL) >+ free(ep->status_buf); >+ if (ep->statm_buf != NULL) >+ free(ep->statm_buf); >+ if (ep->maps_buf != NULL) >+ free(ep->maps_buf); >+ if (ep->schedstat_buf != NULL) >+ free(ep->schedstat_buf); >+ if (ep->io_buf != NULL) >+ free(ep->io_buf); >+ if (ep->wchan_buf != NULL) >+ free(ep->wchan_buf); >+ >+ if (prev == NULL) >+ proc_pid->pidhash.hash[i] = node->next; >+ else >+ prev->next = node->next; >+ free(ep); >+ free(node); >+ } >+ else { >+ prev = node; >+ } >+ if ((node = next) == NULL) >+ break; >+ } >+ } >+ >+ return pidlist->count; >+} >+ >+int >+refresh_proc_pid(proc_pid_t *proc_pid) >+{ >+ if (refresh_pidlist() <= 0) >+ return -oserror(); >+ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_LIBPMDA) >+ fprintf(stderr, "refresh_proc_pid: found %d pids\n", allpids.count); >+#endif >+ >+ return refresh_proc_pidlist(proc_pid, &allpids); >+} >+ >+ >+/* >+ * fetch a proc/<pid>/stat entry for pid >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_stat(int id, proc_pid_t *proc_pid) >+{ >+ int fd; >+ int sts = 0; >+ int n; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ char buf[1024]; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->stat_fetched == 0) { >+ sprintf(buf, "/proc/%d/stat", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else >+ if ((n = read(fd, buf, sizeof(buf))) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ /* eh? */ >+ sts = -1; >+ else { >+ if (ep->stat_buflen <= n) { >+ ep->stat_buflen = n; >+ ep->stat_buf = (char *)realloc(ep->stat_buf, n); >+ } >+ memcpy(ep->stat_buf, buf, n); >+ ep->stat_buf[n-1] = '\0'; >+ sts = 0; >+ } >+ } >+ if (fd >= 0) >+ close(fd); >+ ep->stat_fetched = 1; >+ } >+ >+ if (ep->wchan_fetched == 0) { >+ sprintf(buf, "/proc/%d/wchan", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = 0; /* ignore failure here, backwards compat */ >+ else >+ if ((n = read(fd, buf, sizeof(buf)-1)) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ /* eh? */ >+ sts = -1; >+ else { >+ n++; /* no terminating null (from kernel) */ >+ if (ep->wchan_buflen <= n) { >+ ep->wchan_buflen = n; >+ ep->wchan_buf = (char *)realloc(ep->wchan_buf, n); >+ } >+ memcpy(ep->wchan_buf, buf, n); >+ ep->wchan_buf[n-1] = '\0'; >+ sts = 0; >+ } >+ } >+ if (fd >= 0) >+ close(fd); >+ ep->wchan_fetched = 1; >+ } >+ >+ if (sts < 0) >+ return NULL; >+ return ep; >+} >+ >+/* >+ * fetch a proc/<pid>/status entry for pid >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_status(int id, proc_pid_t *proc_pid) >+{ >+ int sts = 0; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->status_fetched == 0) { >+ int fd; >+ int n; >+ char buf[1024]; >+ char *curline; >+ >+ sprintf(buf, "/proc/%d/status", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else if ((n = read(fd, buf, sizeof(buf))) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ sts = -1; >+ else { >+ if (ep->status_buflen < n) { >+ ep->status_buflen = n; >+ ep->status_buf = (char *)realloc(ep->status_buf, n); >+ } >+ >+ if (ep->status_buf == NULL) >+ sts = -1; >+ else { >+ memcpy(ep->status_buf, buf, n); >+ ep->status_buf[n-1] = '\0'; >+ } >+ } >+ } >+ >+ if (sts == 0) { >+ /* assign pointers to individual lines in buffer */ >+ curline = ep->status_buf; >+ >+ while (strncmp(curline, "Uid:", 4)) { >+ curline = index(curline, '\n') + 1; >+ } >+ >+ /* user & group IDs */ >+ ep->status_lines.uid = strsep(&curline, "\n"); >+ ep->status_lines.gid = strsep(&curline, "\n"); >+ >+ while (curline) { >+ if (strncmp(curline, "VmSize:", 7) == 0) { >+ /* memory info - these lines don't exist for kernel threads */ >+ ep->status_lines.vmsize = strsep(&curline, "\n"); >+ ep->status_lines.vmlck = strsep(&curline, "\n"); >+ ep->status_lines.vmrss = strsep(&curline, "\n"); >+ ep->status_lines.vmdata = strsep(&curline, "\n"); >+ ep->status_lines.vmstk = strsep(&curline, "\n"); >+ ep->status_lines.vmexe = strsep(&curline, "\n"); >+ ep->status_lines.vmlib = strsep(&curline, "\n"); >+ } else >+ if (strncmp(curline, "SigPnd:", 7) == 0) { >+ /* signal masks */ >+ ep->status_lines.sigpnd = strsep(&curline, "\n"); >+ ep->status_lines.sigblk = strsep(&curline, "\n"); >+ ep->status_lines.sigign = strsep(&curline, "\n"); >+ ep->status_lines.sigcgt = strsep(&curline, "\n"); >+ break; /* we're done */ >+ } else { >+ curline = index(curline, '\n') + 1; >+ } >+ } >+ >+ } >+ if (fd >= 0) >+ close(fd); >+ } >+ >+ ep->status_fetched = 1; >+ >+ return (sts < 0) ? NULL : ep; >+} >+ >+/* >+ * fetch a proc/<pid>/statm entry for pid >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_statm(int id, proc_pid_t *proc_pid) >+{ >+ int fd; >+ int sts = 0; >+ int n; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ char buf[1024]; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->statm_fetched == 0) { >+ sprintf(buf, "/proc/%d/statm", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else >+ if ((n = read(fd, buf, sizeof(buf))) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ /* eh? */ >+ sts = -1; >+ else { >+ if (ep->statm_buflen <= n) { >+ ep->statm_buflen = n; >+ ep->statm_buf = (char *)realloc(ep->statm_buf, n); >+ } >+ memcpy(ep->statm_buf, buf, n); >+ ep->statm_buf[n-1] = '\0'; >+ } >+ } >+ >+ if (fd >= 0) >+ close(fd); >+ ep->statm_fetched = 1; >+ } >+ >+ if (sts < 0) >+ return NULL; >+ return ep; >+} >+ >+ >+/* >+ * fetch a proc/<pid>/maps entry for pid >+ * WARNING: This can be very large! Only ask for it if you really need it. >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_maps(int id, proc_pid_t *proc_pid) >+{ >+ int fd; >+ int sts = 0; >+ int n; >+ int len = 0; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ char buf[1024]; >+ char *maps_bufptr = NULL; >+ >+ if (node == NULL) >+ return NULL; >+ >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->maps_fetched == 0) { >+ sprintf(buf, "/proc/%d/maps", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else { >+ while ((n = read(fd, buf, sizeof(buf))) > 0) { >+ len += n; >+ if (ep->maps_buflen <= len) { >+ ep->maps_buflen = len + 1; >+ ep->maps_buf = (char *)realloc(ep->maps_buf, ep->maps_buflen); >+ } >+ maps_bufptr = ep->maps_buf + len - n; >+ memcpy(maps_bufptr, buf, n); >+ } >+ ep->maps_fetched = 1; >+ /* If there are no maps, make maps_buf point to a zero length string. */ >+ if (ep->maps_buflen == 0) { >+ ep->maps_buf = (char *)malloc(1); >+ ep->maps_buflen = 1; >+ } >+ ep->maps_buf[ep->maps_buflen - 1] = '\0'; >+ close(fd); >+ } >+ } >+ >+ if (sts < 0) >+ return NULL; >+ return ep; >+} >+ >+/* >+ * fetch a proc/<pid>/schedstat entry for pid >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_schedstat(int id, proc_pid_t *proc_pid) >+{ >+ int fd; >+ int sts = 0; >+ int n; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ char buf[1024]; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->schedstat_fetched == 0) { >+ sprintf(buf, "/proc/%d/schedstat", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else >+ if ((n = read(fd, buf, sizeof(buf))) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ /* eh? */ >+ sts = -1; >+ else { >+ if (ep->schedstat_buflen <= n) { >+ ep->schedstat_buflen = n; >+ ep->schedstat_buf = (char *)realloc(ep->schedstat_buf, n); >+ } >+ memcpy(ep->schedstat_buf, buf, n); >+ ep->schedstat_buf[n-1] = '\0'; >+ } >+ } >+ if (fd >= 0) { >+ close(fd); >+ ep->schedstat_fetched = 1; >+ } >+ } >+ >+ if (sts < 0) >+ return NULL; >+ return ep; >+} >+ >+/* >+ * fetch a proc/<pid>/io entry for pid >+ * >+ * Depends on kernel built with CONFIG_TASK_IO_ACCOUNTING=y >+ * which means the following must also be set: >+ * CONFIG_TASKSTATS=y >+ * CONFIG_TASK_DELAY_ACCT=y >+ * CONFIG_TASK_XACCT=y >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_io(int id, proc_pid_t *proc_pid) >+{ >+ int sts = 0; >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->io_fetched == 0) { >+ int fd; >+ int n; >+ char buf[1024]; >+ char *curline; >+ >+ sprintf(buf, "/proc/%d/io", ep->id); >+ if ((fd = open(buf, O_RDONLY)) < 0) >+ sts = -oserror(); >+ else if ((n = read(fd, buf, sizeof(buf))) < 0) >+ sts = -oserror(); >+ else { >+ if (n == 0) >+ sts = -1; >+ else { >+ if (ep->io_buflen < n) { >+ ep->io_buflen = n; >+ ep->io_buf = (char *)realloc(ep->io_buf, n); >+ } >+ >+ if (ep->io_buf == NULL) >+ sts = -1; >+ else { >+ memcpy(ep->io_buf, buf, n); >+ ep->io_buf[n-1] = '\0'; >+ } >+ } >+ } >+ >+ if (sts == 0) { >+ /* assign pointers to individual lines in buffer */ >+ curline = ep->io_buf; >+ ep->io_lines.rchar = strsep(&curline, "\n"); >+ ep->io_lines.wchar = strsep(&curline, "\n"); >+ ep->io_lines.syscr = strsep(&curline, "\n"); >+ ep->io_lines.syscw = strsep(&curline, "\n"); >+ ep->io_lines.readb = strsep(&curline, "\n"); >+ ep->io_lines.writeb = strsep(&curline, "\n"); >+ ep->io_lines.cancel = strsep(&curline, "\n"); >+ ep->io_fetched = 1; >+ } >+ if (fd >= 0) >+ close(fd); >+ } >+ >+ return (sts < 0) ? NULL : ep; >+} >+ >+/* >+ * fetch a proc/<pid>/fd entry for pid >+ */ >+proc_pid_entry_t * >+fetch_proc_pid_fd(int id, proc_pid_t *proc_pid) >+{ >+ __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >+ proc_pid_entry_t *ep; >+ >+ if (node == NULL) >+ return NULL; >+ ep = (proc_pid_entry_t *)node->data; >+ >+ if (ep->fd_fetched == 0) { >+ char buf[PATH_MAX]; >+ uint32_t de_count = 0; >+ DIR *dir; >+ >+ sprintf(buf, "/proc/%d/fd", ep->id); >+ dir = opendir(buf); >+ if (dir == NULL) { >+ __pmNotifyErr(LOG_ERR, "failed to open pid fd path %s\n", >+ buf); >+ return NULL; >+ } >+ while (readdir(dir) != NULL) { >+ de_count++; >+ } >+ closedir(dir); >+ ep->fd_count = de_count - 2; /* subtract cwd and parent entries */ >+ } >+ ep->fd_fetched = 1; >+ >+ return ep; >+} >+ >+/* >+ * Extract the ith (space separated) field from a char buffer. >+ * The first field starts at zero. >+ * BEWARE: return copy is in a static buffer. >+ */ >+char * >+_pm_getfield(char *buf, int field) >+{ >+ static int retbuflen = 0; >+ static char *retbuf = NULL; >+ char *p; >+ int i; >+ >+ if (buf == NULL) >+ return NULL; >+ >+ for (p=buf, i=0; i < field; i++) { >+ /* skip to the next space */ >+ for (; *p && !isspace(*p); p++) {;} >+ >+ /* skip to the next word */ >+ for (; *p && isspace(*p); p++) {;} >+ } >+ >+ /* return a null terminated copy of the field */ >+ for (i=0; ; i++) { >+ if (isspace(p[i]) || p[i] == '\0' || p[i] == '\n') >+ break; >+ } >+ >+ if (i >= retbuflen) { >+ retbuflen = i+4; >+ retbuf = (char *)realloc(retbuf, retbuflen); >+ } >+ memcpy(retbuf, p, i); >+ retbuf[i] = '\0'; >+ >+ return retbuf; >+} >diff --git a/src/pmdas/linux_proc/proc_pid.h b/src/pmdas/linux_proc/proc_pid.h >new file mode 100644 >index 0000000..53ff1a3 >--- /dev/null >+++ b/src/pmdas/linux_proc/proc_pid.h >@@ -0,0 +1,269 @@ >+/* >+ * Linux /proc/<pid>/{stat,statm} Clusters >+ * >+ * Copyright (c) 2000,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 >+ */ >+ >+#ifndef _PROC_PID_H >+#define _PROC_PID_H >+ >+/* >+ * /proc/<pid>/stat metrics >+ */ >+#define PROC_PID_STAT_PID 0 >+#define PROC_PID_STAT_CMD 1 >+#define PROC_PID_STAT_STATE 2 >+#define PROC_PID_STAT_PPID 3 >+#define PROC_PID_STAT_PGRP 4 >+#define PROC_PID_STAT_SESSION 5 >+#define PROC_PID_STAT_TTY 6 >+#define PROC_PID_STAT_TTY_PGRP 7 >+#define PROC_PID_STAT_FLAGS 8 >+#define PROC_PID_STAT_MINFLT 9 >+#define PROC_PID_STAT_CMIN_FLT 10 >+#define PROC_PID_STAT_MAJ_FLT 11 >+#define PROC_PID_STAT_CMAJ_FLT 12 >+#define PROC_PID_STAT_UTIME 13 >+#define PROC_PID_STAT_STIME 14 >+#define PROC_PID_STAT_CUTIME 15 >+#define PROC_PID_STAT_CSTIME 16 >+#define PROC_PID_STAT_PRIORITY 17 >+#define PROC_PID_STAT_NICE 18 >+#define PROC_PID_STAT_REMOVED 19 >+#define PROC_PID_STAT_IT_REAL_VALUE 20 >+#define PROC_PID_STAT_START_TIME 21 >+#define PROC_PID_STAT_VSIZE 22 >+#define PROC_PID_STAT_RSS 23 >+#define PROC_PID_STAT_RSS_RLIM 24 >+#define PROC_PID_STAT_START_CODE 25 >+#define PROC_PID_STAT_END_CODE 26 >+#define PROC_PID_STAT_START_STACK 27 >+#define PROC_PID_STAT_ESP 28 >+#define PROC_PID_STAT_EIP 29 >+#define PROC_PID_STAT_SIGNAL 30 >+#define PROC_PID_STAT_BLOCKED 31 >+#define PROC_PID_STAT_SIGIGNORE 32 >+#define PROC_PID_STAT_SIGCATCH 33 >+#define PROC_PID_STAT_WCHAN 34 >+#define PROC_PID_STAT_NSWAP 35 >+#define PROC_PID_STAT_CNSWAP 36 >+#define PROC_PID_STAT_EXIT_SIGNAL 37 >+#define PROC_PID_STAT_PROCESSOR 38 >+#define PROC_PID_STAT_TTYNAME 39 >+#define PROC_PID_STAT_WCHAN_SYMBOL 40 >+#define PROC_PID_STAT_PSARGS 41 >+ >+/* number of fields in proc_pid_stat_entry_t */ >+#define NR_PROC_PID_STAT 42 >+ >+/* >+ * metrics in /proc/<pid>/status >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+#define PROC_PID_STATUS_UID 0 >+#define PROC_PID_STATUS_EUID 1 >+#define PROC_PID_STATUS_SUID 2 >+#define PROC_PID_STATUS_FSUID 3 >+#define PROC_PID_STATUS_GID 4 >+#define PROC_PID_STATUS_EGID 5 >+#define PROC_PID_STATUS_SGID 6 >+#define PROC_PID_STATUS_FSGID 7 >+#define PROC_PID_STATUS_UID_NM 8 >+#define PROC_PID_STATUS_EUID_NM 9 >+#define PROC_PID_STATUS_SUID_NM 10 >+#define PROC_PID_STATUS_FSUID_NM 11 >+#define PROC_PID_STATUS_GID_NM 12 >+#define PROC_PID_STATUS_EGID_NM 13 >+#define PROC_PID_STATUS_SGID_NM 14 >+#define PROC_PID_STATUS_FSGID_NM 15 >+#define PROC_PID_STATUS_SIGNAL 16 >+#define PROC_PID_STATUS_BLOCKED 17 >+#define PROC_PID_STATUS_SIGIGNORE 18 >+#define PROC_PID_STATUS_SIGCATCH 19 >+#define PROC_PID_STATUS_VMSIZE 20 >+#define PROC_PID_STATUS_VMLOCK 21 >+#define PROC_PID_STATUS_VMRSS 22 >+#define PROC_PID_STATUS_VMDATA 23 >+#define PROC_PID_STATUS_VMSTACK 24 >+#define PROC_PID_STATUS_VMEXE 25 >+#define PROC_PID_STATUS_VMLIB 26 >+ >+/* number of metrics from /proc/<pid>/status */ >+#define NR_PROC_PID_STATUS 27 >+ >+/* >+ * metrics in /proc/<pid>/statm & /proc/<pid>/maps >+ */ >+#define PROC_PID_STATM_SIZE 0 >+#define PROC_PID_STATM_RSS 1 >+#define PROC_PID_STATM_SHARE 2 >+#define PROC_PID_STATM_TEXTRS 3 >+#define PROC_PID_STATM_LIBRS 4 >+#define PROC_PID_STATM_DATRS 5 >+#define PROC_PID_STATM_DIRTY 6 >+#define PROC_PID_STATM_MAPS 7 >+ >+/* number of fields in proc_pid_statm_entry_t */ >+#define NR_PROC_PID_STATM 8 >+ >+/* >+ * metrics in /proc/<pid>/schedstat >+ */ >+#define PROC_PID_SCHED_CPUTIME 0 >+#define PROC_PID_SCHED_RUNDELAY 1 >+#define PROC_PID_SCHED_PCOUNT 2 >+#define NR_PROC_PID_SCHED 3 >+ >+/* >+ * metrics in /proc/<pid>/io >+ */ >+#define PROC_PID_IO_RCHAR 0 >+#define PROC_PID_IO_WCHAR 1 >+#define PROC_PID_IO_SYSCR 2 >+#define PROC_PID_IO_SYSCW 3 >+#define PROC_PID_IO_READ_BYTES 4 >+#define PROC_PID_IO_WRITE_BYTES 5 >+#define PROC_PID_IO_CANCELLED_BYTES 6 >+ >+/* >+ * metrics in /proc/<pid>/fd >+ */ >+#define PROC_PID_FD_COUNT 0 >+ >+typedef struct { /* /proc/<pid>/status */ >+ char *uid; >+ char *gid; >+ char *sigpnd; >+ char *sigblk; >+ char *sigign; >+ char *sigcgt; >+ char *vmsize; >+ char *vmlck; >+ char *vmrss; >+ char *vmdata; >+ char *vmstk; >+ char *vmexe; >+ char *vmlib; >+} status_lines_t; >+ >+typedef struct { /* /proc/<pid>/io */ >+ char *rchar; >+ char *wchar; >+ char *syscr; >+ char *syscw; >+ char *readb; >+ char *writeb; >+ char *cancel; >+} io_lines_t; >+ >+typedef struct { >+ int id; /* pid, hash key and internal instance id */ >+ int valid; /* flag (zero if process has exited) */ >+ char *name; /* external instance name (<pid> cmdline) */ >+ >+ /* /proc/<pid>/stat cluster */ >+ int stat_fetched; >+ int stat_buflen; >+ char *stat_buf; >+ >+ /* /proc/<pid>/statm and /proc/<pid>/maps cluster */ >+ int statm_fetched; >+ int statm_buflen; >+ char *statm_buf; >+ int maps_fetched; >+ int maps_buflen; >+ char *maps_buf; >+ >+ /* /proc/<pid>/status cluster */ >+ int status_fetched; >+ int status_buflen; >+ char *status_buf; >+ status_lines_t status_lines; >+ >+ /* /proc/<pid>/schedstat cluster */ >+ int schedstat_fetched; >+ int schedstat_buflen; >+ char *schedstat_buf; >+ >+ /* /proc/<pid>/io cluster */ >+ int io_fetched; >+ int io_buflen; >+ char *io_buf; >+ io_lines_t io_lines; >+ >+ /* /proc/<pid>/wchan cluster */ >+ int wchan_fetched; >+ int wchan_buflen; >+ char *wchan_buf; >+ >+ /* /proc/<pid>/fd cluster */ >+ int fd_fetched; >+ int fd_buflen; >+ char *fd_buf; >+ uint32_t fd_count; >+} proc_pid_entry_t; >+ >+typedef struct { >+ __pmHashCtl pidhash; /* hash table for current pids */ >+ pmdaIndom *indom; /* instance domain table */ >+} proc_pid_t; >+ >+typedef struct { >+ int count; /* number of processes in the list */ >+ int size; /* size of the buffer (pids) allocated */ >+ int *pids; /* array of process identifiers */ >+} proc_pid_list_t; >+ >+/* refresh the proc indom, reset all "fetched" flags */ >+extern int refresh_proc_pid(proc_pid_t *); >+ >+/* add a process onto a process list */ >+extern void pidlist_append(proc_pid_list_t *, const char *); >+ >+/* comparator routine for sorting a process list */ >+extern int compare_pid(const void *, const void *); >+ >+/* refresh a proc indom (subset), reset all "fetched" flags */ >+extern int refresh_proc_pidlist(proc_pid_t *proc_pid, proc_pid_list_t *); >+ >+/* fetch a proc/<pid>/stat entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_stat(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/statm entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_statm(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/status entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_status(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/maps entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_maps(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/schedstat entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_schedstat(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/io entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_io(int, proc_pid_t *); >+ >+/* fetch a proc/<pid>/fd entry for pid */ >+extern proc_pid_entry_t *fetch_proc_pid_fd(int, proc_pid_t *); >+ >+extern int _pm_pid_io_fields; /* count of fields in proc/<pid>/io */ >+ >+/* extract the ith space separated field from a buffer */ >+extern char *_pm_getfield(char *, int); >+ >+#endif /* _PROC_PID_H */ >diff --git a/src/pmdas/linux_proc/proc_runq.c b/src/pmdas/linux_proc/proc_runq.c >new file mode 100644 >index 0000000..c5d5930 >--- /dev/null >+++ b/src/pmdas/linux_proc/proc_runq.c >@@ -0,0 +1,123 @@ >+/* >+ * Linux /proc/runq metrics cluster >+ * >+ * Copyright (c) 2000,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 <ctype.h> >+#include <dirent.h> >+#include <sys/stat.h> >+#include "proc_pid.h" >+#include "proc_runq.h" >+ >+int >+refresh_proc_runq(proc_runq_t *proc_runq) >+{ >+ int sz; >+ int fd; >+ char *p; >+ int sname; >+ DIR *dir; >+ struct dirent *d; >+ char fullpath[MAXPATHLEN]; >+ char buf[4096]; >+ >+ memset(proc_runq, 0, sizeof(proc_runq_t)); >+ if ((dir = opendir("/proc")) == NULL) >+ return -oserror(); >+ >+ while((d = readdir(dir)) != NULL) { >+ if (!isdigit(d->d_name[0])) >+ continue; >+ sprintf(fullpath, "/proc/%s/stat", d->d_name); >+ if ((fd = open(fullpath, O_RDONLY)) < 0) >+ continue; >+ sz = read(fd, buf, sizeof(buf)); >+ close(fd); >+ buf[sizeof(buf)-1] = '\0'; >+ >+ /* >+ * defunct (state name is 'Z') >+ */ >+ if (sz <= 0 || (p = _pm_getfield(buf, PROC_PID_STAT_STATE)) == NULL) { >+ proc_runq->unknown++; >+ continue; >+ } >+ if ((sname = *p) == 'Z') { >+ proc_runq->defunct++; >+ continue; >+ } >+ >+ /* >+ * kernel process (not defunct and virtual size is zero) >+ */ >+ if ((p = _pm_getfield(buf, PROC_PID_STAT_VSIZE)) == NULL) { >+ proc_runq->unknown++; >+ continue; >+ } >+ if (strcmp(p, "0") == 0) { >+ proc_runq->kernel++; >+ continue; >+ } >+ >+ /* >+ * swapped (resident set size is zero) >+ */ >+ if ((p = _pm_getfield(buf, PROC_PID_STAT_RSS)) == NULL) { >+ proc_runq->unknown++; >+ continue; >+ } >+ if (strcmp(p, "0") == 0) { >+ proc_runq->swapped++; >+ continue; >+ } >+ >+ /* >+ * All other states >+ */ >+ switch (sname) { >+ case 'R': >+ proc_runq->runnable++; >+ break; >+ case 'S': >+ proc_runq->sleeping++; >+ break; >+ case 'T': >+ proc_runq->stopped++; >+ break; >+ case 'D': >+ proc_runq->blocked++; >+ break; >+ case 'Z': >+ break; /* already counted above */ >+ default: >+ fprintf(stderr, "UNKNOWN %c : %s\n", sname, buf); >+ proc_runq->unknown++; >+ break; >+ } >+ } >+ closedir(dir); >+ >+#if PCP_DEBUG >+ if (pmDebug & DBG_TRACE_LIBPMDA) { >+ fprintf(stderr, "refresh_runq: runnable=%d sleeping=%d stopped=%d blocked=%d unknown=%d\n", >+ proc_runq->runnable, proc_runq->sleeping, proc_runq->stopped, >+ proc_runq->blocked, proc_runq->unknown); >+ } >+#endif >+ >+ return 0; >+} >diff --git a/src/pmdas/linux_proc/proc_runq.h b/src/pmdas/linux_proc/proc_runq.h >new file mode 100644 >index 0000000..9739208 >--- /dev/null >+++ b/src/pmdas/linux_proc/proc_runq.h >@@ -0,0 +1,35 @@ >+/* >+ * Copyright (c) 2000,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 >+ */ >+ >+#ifndef _PROC_RUNQ_H >+#define _PROC_RUNQ_H >+ >+typedef struct { >+ int runnable; >+ int blocked; >+ int sleeping; >+ int stopped; >+ int swapped; >+ int kernel; >+ int defunct; >+ int unknown; >+} proc_runq_t; >+ >+extern int refresh_proc_runq(proc_runq_t *); >+ >+#endif /* _PROC_RUNQ_H */ >diff --git a/src/pmdas/linux_proc/root b/src/pmdas/linux_proc/root >new file mode 100644 >index 0000000..834246f >--- /dev/null >+++ b/src/pmdas/linux_proc/root >@@ -0,0 +1,10 @@ >+/* >+ * fake "root" for validating the local PMNS subtree >+ */ >+ >+#include <stdpmid> >+ >+root { proc } >+ >+#include "pmns" >+ >diff --git a/src/pmdas/proc/GNUmakefile b/src/pmdas/proc/GNUmakefile >deleted file mode 100644 >index b5dbb7e..0000000 >--- a/src/pmdas/proc/GNUmakefile >+++ /dev/null >@@ -1,85 +0,0 @@ >-# >-# Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. >-# Copyright (c) 2007-2010 Aconex. 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 = linux >-DOMAIN = LINUX >-CMDTARGET = pmdalinux >-LIBTARGET = pmda_linux.so >-PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) >-CONF_LINE = "linux 60 dso linux_init $(PMDADIR)/$(LIBTARGET)" >- >-CFILES = pmda.c proc_stat.c proc_meminfo.c proc_loadavg.c \ >- proc_net_dev.c interrupts.c filesys.c \ >- swapdev.c proc_net_rpc.c proc_partitions.c \ >- getinfo.c proc_net_sockstat.c proc_runq.c \ >- proc_net_snmp.c proc_scsi.c proc_fs_xfs.c \ >- proc_cpuinfo.c proc_net_tcp.c \ >- proc_slabinfo.c sem_limits.c msg_limits.c shm_limits.c \ >- proc_uptime.c ksym.c proc_sys_fs.c proc_vmstat.c \ >- sysfs_kernel.c linux_table.c numa_meminfo.c \ >- dynamic.c cgroups.c >- >-HFILES = proc_stat.h proc_meminfo.h proc_loadavg.h \ >- proc_net_dev.h interrupts.h filesys.h swapdev.h \ >- proc_net_rpc.h proc_pid.h proc_partitions.h getinfo.h \ >- proc_net_sockstat.h proc_runq.h proc_net_snmp.h \ >- proc_scsi.h proc_fs_xfs.h \ >- proc_cpuinfo.h proc_net_tcp.h proc_slabinfo.h \ >- sem_limits.h msg_limits.h shm_limits.h proc_uptime.h \ >- ksym.h proc_sys_fs.h proc_vmstat.h clusters.h indom.h \ >- convert.h sysfs_kernel.h linux_table.h numa_meminfo.h \ >- dynamic.h cgroups.h >- >-LSRCFILES = help root_linux >-LDIRT = help.dir help.pag domain.h >- >-LLDLIBS = -lpcp_pmda -lpcp >- >-# Uncomment these flags for profiling >-# LCFLAGS = -pg >-# LLDFLAGS = -pg >- >-default: build-me >- >-include $(BUILDRULES) >- >-ifeq "$(TARGET_OS)" "linux" >-build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag >- @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ >- echo $(CONF_LINE) >> ../pmcd.conf ; \ >- fi >- >-install: default >- $(INSTALL) -m 755 -d $(PMDADIR) >- $(INSTALL) -m 644 domain.h help help.dir help.pag $(PMDADIR) >- $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) >- $(INSTALL) -m 644 root_linux $(PCP_VAR_DIR)/pmns/root_linux >-else >-build-me: >-install: >-endif >- >-help.dir help.pag : help >- $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_linux -v 2 -o help < help >- >-default_pcp : default >- >-install_pcp : install >- >-domain.h: ../../pmns/stdpmid >- $(DOMAIN_MAKERULE) >diff --git a/src/pmdas/proc/TODO b/src/pmdas/proc/TODO >deleted file mode 100644 >index 70064a9..0000000 >--- a/src/pmdas/proc/TODO >+++ /dev/null >@@ -1,18 +0,0 @@ >-Start with PROC_INDOM >- >- >-[ ] proc_pid.indom >- >-[y] CLUSTER_PID_STAT fetch_proc_pid_stat() >-[y] CLUSTER_PID_STATM fetch_proc_pid_maps() fetch_proc_pid_statm() >-[y] CLUSTER_PID_STATUS fetch_proc_pid_status() >-[y] CLUSTER_PID_SCHEDSTAT fetch_proc_pid_schedstat() >-[y] CLUSTER_PID_IO fetch_proc_pid_io() >-[y] CLUSTER_PID_FD fetch_proc_pid_fd() >-[ ] CLUSTER_PROC_RUNQ refresh_proc_runq() >- >-[ ] proc.nprocs >- >-[y] refresh_proc_pid() >- >-[ ] cgroups? >diff --git a/src/pmdas/proc/cgroups.c b/src/pmdas/proc/cgroups.c >deleted file mode 100644 >index 1620ad3..0000000 >--- a/src/pmdas/proc/cgroups.c >+++ /dev/null >@@ -1,760 +0,0 @@ >-/* >- * Copyright (c) 2010 Aconex. 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 "cgroups.h" >-#include "filesys.h" >-#include "dynamic.h" >-#include "clusters.h" >-#include "proc_pid.h" >-#include <sys/stat.h> >-#ifdef HAVE_STRINGS_H >-#include <strings.h> >-#endif >-#include <ctype.h> >- >-/* Add namespace entries and prepare values for one cgroupfs directory entry */ >-struct cgroup_subsys; >-typedef int (*cgroup_prepare_t)(__pmnsTree *, const char *, >- struct cgroup_subsys *, const char *, int, int, int); >-static int prepare_ull(__pmnsTree *, const char *, >- struct cgroup_subsys *, const char *, int, int, int); >-static int prepare_string(__pmnsTree *, const char *, >- struct cgroup_subsys *, const char *, int, int, int); >-static int prepare_named_ull(__pmnsTree *, const char *, >- struct cgroup_subsys *, const char *, int, int, int); >- >-/* >- * Critical data structures for cgroup subsystem in pmdalinux... >- * Initial comment for each struct talks about lifecycle of that >- * data, in terms of what pmdalinux must do with it (esp. memory >- * allocation related). >- */ >- >-typedef struct { /* contents depends on individual kernel cgroups */ >- int item; /* PMID == domain:cluster:[id:item] */ >- int dynamic; /* do we need an extra free (string) */ >- cgroup_prepare_t prepare; /* setup metric name(s) and value(s) */ >- char *suffix; /* cpus/mems/rss/... */ >-} cgroup_metrics_t; >- >-typedef struct { /* some metrics are multi-valued, but most have only one */ >- int item; /* PMID == domain:cluster:[id:item] */ >- int atom_count; >- pmAtomValue *atoms; >-} cgroup_values_t; >- >-typedef struct { /* contains data for each group users have created, if any */ >- int id; /* PMID == domain:cluster:[id:item] */ >- int refreshed; /* boolean: are values all uptodate */ >- proc_pid_list_t process_list; >- cgroup_values_t *metric_values; >-} cgroup_group_t; >- >-typedef struct cgroup_subsys { /* contents covers the known kernel cgroups */ >- const char *name; /* cpuset/memory/... */ >- int cluster; /* PMID == domain:cluster:[id:item] */ >- int process_cluster;/* cluster ID for process metrics */ >- int group_count; /* number of groups (dynamic) */ >- int metric_count; /* number of metrics (fixed) */ >- cgroup_group_t *groups; /* array of groups (dynamic) */ >- cgroup_metrics_t *metrics; /* array of metrics (fixed) */ >-} cgroup_subsys_t; >- >-static cgroup_metrics_t cpusched_metrics[] = { >- { .item = 0, .suffix = "shares", .prepare = prepare_ull }, >-}; >- >-static cgroup_metrics_t cpuacct_metrics[] = { >- { .item = 0, .suffix = "stat.user", .prepare = prepare_named_ull }, >- { .item = 1, .suffix = "stat.system", .prepare = prepare_named_ull }, >- { .item = 2, .suffix = "usage", .prepare = prepare_ull }, >- { .item = 3, .suffix = "usage_percpu", .prepare = prepare_ull }, >-}; >- >-static cgroup_metrics_t cpuset_metrics[] = { >- { .item = 0, .suffix = "cpus", .prepare = prepare_string, .dynamic = 1 }, >- { .item = 1, .suffix = "mems", .prepare = prepare_string, .dynamic = 1 }, >-}; >- >-static cgroup_metrics_t memory_metrics[] = { >- { .item = 0, .suffix = "stat.cache", .prepare = prepare_named_ull }, >- { .item = 1, .suffix = "stat.rss", .prepare = prepare_named_ull }, >- { .item = 2, .suffix = "stat.pgin", .prepare = prepare_named_ull }, >- { .item = 3, .suffix = "stat.pgout", .prepare = prepare_named_ull }, >- { .item = 4, .suffix = "stat.swap", .prepare = prepare_named_ull }, >- { .item = 5, .suffix = "stat.active_anon", .prepare = prepare_named_ull }, >- { .item = 6, .suffix = "stat.inactive_anon", .prepare = prepare_named_ull }, >- { .item = 7, .suffix = "stat.active_file", .prepare = prepare_named_ull }, >- { .item = 8, .suffix = "stat.inactive_file", .prepare = prepare_named_ull }, >- { .item = 9, .suffix = "stat.unevictable", .prepare = prepare_named_ull }, >-}; >- >-static cgroup_metrics_t netclass_metrics[] = { >- { .item = 0, .suffix = "classid", .prepare = prepare_ull }, >-}; >- >-static cgroup_subsys_t controllers[] = { >- { .name = "cpu", >- .cluster = CLUSTER_CPUSCHED_GROUPS, >- .process_cluster = CLUSTER_CPUSCHED_PROCS, >- .metrics = cpusched_metrics, >- .metric_count = sizeof(cpusched_metrics) / sizeof(cpusched_metrics[0]), >- }, >- { .name = "cpuset", >- .cluster = CLUSTER_CPUSET_GROUPS, >- .process_cluster = CLUSTER_CPUSET_PROCS, >- .metrics = cpuset_metrics, >- .metric_count = sizeof(cpuset_metrics) / sizeof(cpuset_metrics[0]), >- }, >- { .name = "cpuacct", >- .cluster = CLUSTER_CPUACCT_GROUPS, >- .process_cluster = CLUSTER_CPUACCT_PROCS, >- .metrics = cpuacct_metrics, >- .metric_count = sizeof(cpuacct_metrics) / sizeof(cpuacct_metrics[0]), >- }, >- { .name = "memory", >- .cluster = CLUSTER_MEMORY_GROUPS, >- .process_cluster = CLUSTER_MEMORY_PROCS, >- .metrics = memory_metrics, >- .metric_count = sizeof(memory_metrics) / sizeof(memory_metrics[0]), >- }, >- { .name = "net_cls", >- .cluster = CLUSTER_NET_CLS_GROUPS, >- .process_cluster = CLUSTER_NET_CLS_PROCS, >- .metrics = netclass_metrics, >- .metric_count = sizeof(netclass_metrics) / sizeof(netclass_metrics[0]), >- }, >-}; >- >-static int >-read_values(char *buffer, int size, const char *path, const char *subsys, >- const char *metric) >-{ >- int fd, count; >- >- snprintf(buffer, size, "%s/%s.%s", path, subsys, metric); >- if ((fd = open(buffer, O_RDONLY)) < 0) >- return -oserror(); >- count = read(fd, buffer, size); >- close(fd); >- if (count < 0) >- return -oserror(); >- buffer[count-1] = '\0'; >- return 0; >-} >- >-static int >-process_prepare(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >- const char *name, int group, int domain) >-{ >-#if 0 /* not yet implemented */ >- FILE *fp; >- pmID pmid; >- char process[64]; >- char taskpath[MAXPATHLEN]; >- proc_pid_list_t *list = &subsys->groups[group].process_list; >- >- snprintf(taskpath, sizeof(taskpath), "%s/tasks", path); >- if ((fp = fopen(taskpath, "r")) == NULL) >- return -oserror(); >- while (fgets(process, sizeof(process), fp) != NULL) >- pidlist_append(list, process); >- fclose(fp); >- qsort(list->pids, list->count, sizeof(int), compare_pid); >- >- pmid = cgroup_pmid_build(domain, subsys->process_cluster, group, 0); >- snprintf(taskpath, sizeof(taskpath), "cgroup.groups.%s%s.tasks.pid", >- subsys->name, name); >- __pmAddPMNSNode(pmns, pmid, taskpath); >-#endif >- return 0; >-} >- >-static void >-update_pmns(__pmnsTree *pmns, cgroup_subsys_t *subsys, const char *name, >- cgroup_metrics_t *metrics, int group, int domain) >-{ >- char entry[MAXPATHLEN]; >- pmID pmid; >- >- snprintf(entry, sizeof(entry), "cgroup.groups.%s%s.%s", >- subsys->name, name, metrics->suffix); >- pmid = cgroup_pmid_build(domain, subsys->cluster, group, metrics->item); >- __pmAddPMNSNode(pmns, pmid, entry); >-} >- >-static int >-prepare_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >- const char *name, int metric, int group, int domain) >-{ >- int count = 0; >- unsigned long long value; >- char buffer[MAXPATHLEN]; >- char *endp, *p = &buffer[0]; >- cgroup_group_t *groups = &subsys->groups[group]; >- cgroup_metrics_t *metrics = &subsys->metrics[metric]; >- pmAtomValue *atoms = groups->metric_values[metric].atoms; >- >- if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) >- return -oserror(); >- >- while (p && *p) { >- value = strtoull(p, &endp, 0); >- if ((atoms = realloc(atoms, (count + 1) * sizeof(pmAtomValue))) == NULL) >- return -oserror(); >- atoms[count++].ull = value; >- if (endp == '\0' || endp == p) >- break; >- p = endp; >- while (p && isspace(*p)) >- p++; >- } >- >- groups->metric_values[metric].item = metric; >- groups->metric_values[metric].atoms = atoms; >- groups->metric_values[metric].atom_count = count; >- update_pmns(pmns, subsys, name, metrics, group, domain); >- return 0; >-} >- >-static int >-prepare_named_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >- const char *name, int metric, int group, int domain) >-{ >- int i, count; >- unsigned long long value; >- char filename[64], buffer[MAXPATHLEN]; >- char *offset, *p = &buffer[0]; >- cgroup_group_t *groups = &subsys->groups[group]; >- cgroup_metrics_t *metrics = &subsys->metrics[metric]; >- >- if (groups->refreshed) >- return 0; >- >- /* metric => e.g. stat.user and stat.system - split it up first */ >- offset = index(metrics->suffix, '.'); >- if (!offset) >- return PM_ERR_CONV; >- count = (offset - metrics->suffix); >- strncpy(filename, metrics->suffix, count); >- filename[count] = '\0'; >- >- if (read_values(p, sizeof(buffer), path, subsys->name, filename) < 0) >- return -oserror(); >- >- /* buffer contains <name <value> pairs */ >- while (p && *p) { >- char *endp, *field, *offset; >- >- if ((field = index(p, ' ')) == NULL) >- return PM_ERR_CONV; >- offset = field + 1; >- *field = '\0'; >- field = p; /* field now points to <name> */ >- p = offset; >- value = strtoull(p, &endp, 0); >- p = endp; >- while (p && isspace(*p)) >- p++; >- >- for (i = 0; i < subsys->metric_count; i++) { >- pmAtomValue *atoms = groups->metric_values[i].atoms; >- metrics = &subsys->metrics[i]; >- >- if (strcmp(field, metrics->suffix + count + 1) != 0) >- continue; >- if ((atoms = calloc(1, sizeof(pmAtomValue))) == NULL) >- return -oserror(); >- atoms[0].ull = value; >- >- groups->metric_values[i].item = i; >- groups->metric_values[i].atoms = atoms; >- groups->metric_values[i].atom_count = 1; >- update_pmns(pmns, subsys, name, metrics, group, domain); >- break; >- } >- } >- groups->refreshed = 1; >- return 0; >-} >- >-static int >-prepare_string(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, >- const char *name, int metric, int group, int domain) >-{ >- char buffer[MAXPATHLEN]; >- cgroup_group_t *groups = &subsys->groups[group]; >- cgroup_metrics_t *metrics = &subsys->metrics[metric]; >- pmAtomValue *atoms = groups->metric_values[metric].atoms; >- char *p = &buffer[0]; >- >- if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) >- return -oserror(); >- >- if ((atoms = malloc(sizeof(pmAtomValue))) == NULL) >- return -oserror(); >- if ((atoms[0].cp = strdup(buffer)) == NULL) { >- free(atoms); >- return -oserror(); >- } >- groups->metric_values[metric].item = metric; >- groups->metric_values[metric].atoms = atoms; >- groups->metric_values[metric].atom_count = 1; >- update_pmns(pmns, subsys, name, metrics, group, domain); >- return 0; >-} >- >-static void >-translate(char *dest, const char *src, size_t size) >-{ >- char *p; >- >- if (*src != '\0') /* non-root */ >- *dest = '.'; >- strncpy(dest, src, size); >- for (p = dest; *p; p++) { >- if (*p == '/') >- *p = '.'; >- } >-} >- >-static int >-namespace(__pmnsTree *pmns, cgroup_subsys_t *subsys, >- const char *cgrouppath, const char *cgroupname, int domain) >-{ >- int i, id, sts; >- cgroup_values_t *cvp; >- char group[128]; >- >- translate(&group[0], cgroupname, sizeof(group)); >- >- /* allocate space for this group */ >- sts = (subsys->group_count + 1) * sizeof(cgroup_group_t); >- subsys->groups = (cgroup_group_t *)realloc(subsys->groups, sts); >- if (subsys->groups == NULL) >- return -oserror(); >- /* allocate space for all values up-front */ >- sts = subsys->metric_count * sizeof(cgroup_values_t); >- if ((cvp = (cgroup_values_t *)calloc(1, sts)) == NULL) >- return -oserror(); >- id = subsys->group_count++; >- memset(&subsys->groups[id], 0, sizeof(cgroup_group_t)); >- subsys->groups[id].id = id; >- subsys->groups[id].metric_values = cvp; >- >- for (i = 0; i < subsys->metric_count; i++) { >- cgroup_metrics_t *metrics = &subsys->metrics[i]; >- metrics->prepare(pmns, cgrouppath, subsys, group, i, id, domain); >- } >- process_prepare(pmns, cgrouppath, subsys, group, id, domain); >- return 1; >-} >- >-int >-refresh_cgroup_subsys(pmInDom indom) >-{ >- char buf[4096]; >- char name[MAXPATHLEN]; >- int numcgroups, enabled, sts; >- long *data; >- long hierarchy; >- FILE *fp; >- >- if ((fp = fopen("/proc/cgroups", "r")) == NULL) >- return 1; >- >- while (fgets(buf, sizeof(buf), fp) != NULL) { >- /* skip lines starting with hash (header) */ >- if (buf[0] == '#') >- continue; >- if (sscanf(buf, "%s %lu %u %u", &name[0], >- &hierarchy, &numcgroups, &enabled) != 4) >- continue; >- sts = pmdaCacheLookupName(indom, name, NULL, (void **)&data); >- if (sts == PMDA_CACHE_ACTIVE) { >- if (*data != hierarchy) { >- /* >- * odd ... instance name repeated but different >- * hierarchy ... we cannot support more than one hierachy >- * yet >- */ >- fprintf(stderr, "refresh_cgroup_subsys: \"%s\": entries for hierachy %ld ignored (hierarchy %ld seen first)\n", name, hierarchy, *data); >- } >- continue; >- } >- else if (sts != PMDA_CACHE_INACTIVE) { >- if ((data = (long *)malloc(sizeof(long))) == NULL) { >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_LIBPMDA) >- fprintf(stderr, "refresh_cgroup_subsys: \"%s\": malloc failed\n", name); >-#endif >- continue; >- } >- *data = hierarchy; >- } >- pmdaCacheStore(indom, PMDA_CACHE_ADD, name, (void *)data); >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_LIBPMDA) >- fprintf(stderr, "refresh_cgroup_subsys: add \"%s\" [hierarchy %ld]\n", name, hierarchy); >-#endif >- } >- fclose(fp); >- return 0; >-} >- >-/* >- * Parse a (comma-separated) mount option string to find one of the known >- * cgroup subsystems, and return a pointer to it or "?" if none found. >- */ >-char * >-cgroup_find_subsys(pmInDom indom, const char *options) >-{ >- static char dunno[] = "?"; >- static char opts[128]; >- char buffer[128]; >- char *s, *out = NULL; >- >- memset(opts, 0, sizeof(opts)); >- strncpy(buffer, options, sizeof(buffer)); >- >- s = strtok(buffer, ","); >- while (s) { >- if (pmdaCacheLookupName(indom, s, NULL, NULL) == PMDA_CACHE_ACTIVE) { >- if (out) { /* append option */ >- strcat(out, ","); >- strcat(out, s); >- out += strlen(s) + 1; /* +1 => cater for comma */ >- } else { /* first option */ >- strcat(opts, s); >- out = opts + strlen(s); >- } >- } >- s = strtok(NULL, ","); >- } >- if (out) >- return opts; >- return dunno; >-} >- >-/* Ensure cgroup name can be used as a PCP namespace entry, ignore it if not */ >-static int >-valid_pmns_name(char *name) >-{ >- if (!isalpha(name[0])) >- return 0; >- for (; *name != '\0'; name++) >- if (!isalnum(*name) && *name != '_') >- return 0; >- return 1; >-} >- >-static int >-cgroup_namespace(__pmnsTree *pmns, const char *options, >- const char *cgrouppath, const char *cgroupname, int domain) >-{ >- int i, sts = 0; >- >- /* use options to tell which cgroup controller(s) are active here */ >- for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >- int lsts; >- cgroup_subsys_t *subsys = &controllers[i]; >- if (scan_filesys_options(options, subsys->name) == NULL) >- continue; >- lsts = namespace(pmns, subsys, cgrouppath, cgroupname, domain); >- if (lsts > 0) >- sts = 1; >- } >- return sts; >-} >- >-static int >-cgroup_scan(const char *mnt, const char *path, const char *options, >- int domain, __pmnsTree *pmns, int root) >-{ >- int sts, length; >- DIR *dirp; >- struct stat sbuf; >- struct dirent *dp; >- char *cgroupname; >- char cgrouppath[MAXPATHLEN]; >- >- if (root) >- strncpy(cgrouppath, mnt, sizeof(cgrouppath)); >- else >- snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", mnt, path); >- >- if ((dirp = opendir(cgrouppath)) == NULL) >- return -oserror(); >- >- length = strlen(cgrouppath); >- cgroupname = &cgrouppath[length]; >- >- sts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); >- >- /* >- * readdir - descend into directories to find all cgroups, then >- * populate namespace with <controller>[.<groupname>].<metrics> >- */ >- while ((dp = readdir(dirp)) != NULL) { >- int lsts; >- if (!valid_pmns_name(dp->d_name)) >- continue; >- if (path[0] == '\0') >- snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", >- mnt, dp->d_name); >- else >- snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s/%s", >- mnt, path, dp->d_name); >- cgroupname = &cgrouppath[length]; >- if (stat(cgrouppath, &sbuf) < 0) >- continue; >- if (!(S_ISDIR(sbuf.st_mode))) >- continue; >- >- lsts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); >- if (lsts > 0) >- sts = 1; >- >- /* >- * also scan for any child cgroups, but cgroup_scan() may return >- * an error >- */ >- lsts = cgroup_scan(mnt, cgrouppath, options, domain, pmns, 0); >- if (lsts > 0) >- sts = 1; >- } >- closedir(dirp); >- return sts; >-} >- >-static void >-cgroup_regulars(__pmnsTree *pmns, int domain) >-{ >- int i; >- static struct { >- int item; >- int cluster; >- char *name; >- } regulars[] = { >- { 0, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.hierarchy" }, >- { 1, CLUSTER_CGROUP_SUBSYS, "cgroup.subsys.count" }, >- { 0, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.subsys" }, >- { 1, CLUSTER_CGROUP_MOUNTS, "cgroup.mounts.count" }, >- }; >- >- for (i = 0; i < 4; i++) { >- pmID pmid = pmid_build(domain, regulars[i].cluster, regulars[i].item); >- __pmAddPMNSNode(pmns, pmid, regulars[i].name); >- } >-} >- >-int >-refresh_cgroup_groups(pmdaExt *pmda, pmInDom mounts, __pmnsTree **pmns) >-{ >- int i, j, k, a; >- int sts, mtab = 0, domain = pmda->e_domain; >- filesys_t *fs; >- __pmnsTree *tree = pmns ? *pmns : NULL; >- >- if (tree) >- __pmFreePMNS(tree); >- >- if ((sts = __pmNewPMNS(&tree)) < 0) { >- __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n", >- pmProgname, pmErrStr(sts)); >- if (pmns) >- *pmns = NULL; >- return 0; >- } >- >- cgroup_regulars(tree, domain); >- >- /* reset our view of subsystems and groups */ >- for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >- cgroup_subsys_t *subsys = &controllers[i]; >- for (j = 0; j < subsys->group_count; j++) { >- cgroup_group_t *group = &subsys->groups[j]; >- for (k = 0; k < subsys->metric_count; k++) { >- pmAtomValue *atoms = group->metric_values[k].atoms; >- if (subsys->metrics[k].dynamic) >- for (a = 0; a < group->metric_values[k].atom_count; a++) >- free(atoms[a].cp); >- free(atoms); >- } >- free(group->metric_values); >- if (group->process_list.size) >- free(group->process_list.pids); >- memset(group, 0, sizeof(cgroup_group_t)); >- } >- controllers[i].group_count = 0; >- } >- >- pmdaCacheOp(mounts, PMDA_CACHE_WALK_REWIND); >- while ((sts = pmdaCacheOp(mounts, PMDA_CACHE_WALK_NEXT)) != -1) { >- int lsts; >- if (!pmdaCacheLookup(mounts, sts, NULL, (void **)&fs)) >- continue; >- /* walk this cgroup mount finding groups (subdirs) */ >- lsts = cgroup_scan(fs->path, "", fs->options, domain, tree, 1); >- if (lsts > 0) >- mtab = 1; >- } >- >- if (pmns) >- *pmns = tree; >- else >- __pmFreePMNS(tree); >- >- return mtab; >-} >- >-int >-cgroup_group_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) >-{ >- int i, j, k, gid; >- >- gid = cgroup_pmid_group(item); >- item = cgroup_pmid_metric(item); >- >- for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >- cgroup_subsys_t *subsys = &controllers[i]; >- >- if (subsys->cluster != cluster) >- continue; >- for (j = 0; j < subsys->group_count; j++) { >- cgroup_group_t *group = &subsys->groups[j]; >- >- if (group->id != gid) >- continue; >- for (k = 0; k < subsys->metric_count; k++) { >- cgroup_values_t *cvp = &group->metric_values[k]; >- >- if (cvp->item != item) >- continue; >- if (cvp->atom_count <= 0) >- return PM_ERR_VALUE; >- if (inst == PM_IN_NULL) >- inst = 0; >- else if (inst >= cvp->atom_count) >- return PM_ERR_INST; >- *atom = cvp->atoms[inst]; >- return 1; >- } >- } >- } >- return PM_ERR_PMID; >-} >- >-int >-cgroup_procs_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) >-{ >- int i, j, gid; >- >- gid = cgroup_pmid_group(item); >- item = cgroup_pmid_metric(item); >- >- for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >- cgroup_subsys_t *subsys = &controllers[i]; >- if (subsys->process_cluster != cluster) >- continue; >- >- for (j = 0; j < subsys->group_count; j++) { >- cgroup_group_t *group = &subsys->groups[j]; >- >- if (group->id != gid) >- continue; >- >- /* TODO: return values for process metrics */ >- return PM_ERR_NYI; >- } >- } >- return PM_ERR_PMID; >-} >- >-/* >- * Needs to answer the question: how much extra space needs to be allocated >- * in the metric table for (dynamic) cgroup metrics"? We have static entries >- * for group ID zero - if we have any non-zero group IDs, we need entries to >- * cover those. Return value is the number of additional entries needed. >- */ >-static void >-size_metrictable(int *total, int *trees) >-{ >- int i, j, maxid = 0, count = 0; >- >- for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { >- cgroup_subsys_t *subsys = &controllers[i]; >- for (j = 0; j < subsys->group_count; j++) { >- cgroup_group_t *group = &subsys->groups[j]; >- if (group->id > maxid) >- maxid = group->id; >- } >- count += subsys->metric_count + 0; /* +1 for task.pid */ >- } >- >- *total = count; >- *trees = maxid; >- >- if (pmDebug & DBG_TRACE_LIBPMDA) >- fprintf(stderr, "cgroups size_metrictable: %d total x %d trees\n", >- *total, *trees); >-} >- >-/* >- * Create new metric table entry for a group based on an existing one. >- */ >-static void >-refresh_metrictable(pmdaMetric *source, pmdaMetric *dest, int id) >-{ >- int domain = pmid_domain(source->m_desc.pmid); >- int cluster = pmid_cluster(source->m_desc.pmid); >- int item = pmid_item(source->m_desc.pmid); >- >- memcpy(dest, source, sizeof(pmdaMetric)); >- dest->m_desc.pmid = cgroup_pmid_build(domain, cluster, id, item); >- >- if (pmDebug & DBG_TRACE_LIBPMDA) >- fprintf(stderr, "cgroup refresh_metrictable: (%p -> %p) " >- "metric ID dup: %d.%d.%d.%d -> %d.%d.%d.%d\n", >- source, dest, domain, cluster, >- cgroup_pmid_group(source->m_desc.pmid), >- cgroup_pmid_metric(source->m_desc.pmid), >- pmid_domain(dest->m_desc.pmid), pmid_cluster(dest->m_desc.pmid), >- cgroup_pmid_group(dest->m_desc.pmid), >- cgroup_pmid_metric(dest->m_desc.pmid)); >-} >- >-static int >-cgroup_text(pmdaExt *pmda, pmID pmid, int type, char **buf) >-{ >- return PM_ERR_TEXT; >-} >- >-void >-cgroup_init(void) >-{ >- int set[] = { CLUSTER_CPUSET_GROUPS, CLUSTER_CPUSET_PROCS, >- CLUSTER_CPUACCT_GROUPS, CLUSTER_CPUACCT_PROCS, >- CLUSTER_CPUSCHED_GROUPS, CLUSTER_CPUSCHED_PROCS, >- CLUSTER_MEMORY_GROUPS, CLUSTER_MEMORY_PROCS, >- CLUSTER_NET_CLS_GROUPS, CLUSTER_NET_CLS_PROCS, >- }; >- >- linux_dynamic_pmns("cgroup", set, sizeof(set)/sizeof(int), >- refresh_cgroups, cgroup_text, >- refresh_metrictable, size_metrictable); >-} >diff --git a/src/pmdas/proc/cgroups.h b/src/pmdas/proc/cgroups.h >deleted file mode 100644 >index d3b01f6..0000000 >--- a/src/pmdas/proc/cgroups.h >+++ /dev/null >@@ -1,49 +0,0 @@ >-/* >- * Copyright (c) 2010 Aconex. 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. >- */ >- >-/* >- * Note: cgroup metrics have an "extra" component - the final item part >- * of the PMID (10 bits) is split into two (5 bits each) - top contains >- * the metric ID (item), bottom holds the cgroup ID (index - e.g. this >- * is the 3rd cgroup we've seen). >- */ >- >-static inline pmID >-cgroup_pmid_build(unsigned int domain, unsigned int cluster, >- unsigned int gid, unsigned int metric) >-{ >- return pmid_build(domain, cluster, (gid << 5) | metric); >-} >- >-static inline unsigned int >-cgroup_pmid_group(pmID id) >-{ >- return pmid_item(id) >> 5; >-} >- >-static inline unsigned int >-cgroup_pmid_metric(pmID id) >-{ >- return pmid_item(id) & ((1 << 5) - 1); >-} >- >-extern void cgroup_init(); >-extern char *cgroup_find_subsys(pmInDom, const char *); >- >-extern int refresh_cgroups(pmdaExt *, __pmnsTree **); >-extern int refresh_cgroup_subsys(pmInDom); >-extern int refresh_cgroup_groups(pmdaExt *, pmInDom, __pmnsTree **); >- >-extern int cgroup_group_fetch(int, int, unsigned int, pmAtomValue *); >-extern int cgroup_procs_fetch(int, int, unsigned int, pmAtomValue *); >diff --git a/src/pmdas/proc/dynamic.c b/src/pmdas/proc/dynamic.c >deleted file mode 100644 >index cb69deb..0000000 >--- a/src/pmdas/proc/dynamic.c >+++ /dev/null >@@ -1,176 +0,0 @@ >-/* >- * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >- * >- * Copyright (c) 2010 Aconex. 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 "indom.h" >-#include "dynamic.h" >-#include "clusters.h" >- >-static struct dynamic { >- const char *prefix; >- int prefixlen; >- int mtabcount; /* internal use only */ >- int extratrees; /* internal use only */ >- int nclusters; >- int clusters[NUM_CLUSTERS]; >- pmnsUpdate pmnsupdate; >- textUpdate textupdate; >- mtabUpdate mtabupdate; >- mtabCounts mtabcounts; >- __pmnsTree *pmns; >-} *dynamic; >- >-static int dynamic_count; >- >-void >-proc_dynamic_pmns(const char *prefix, int *clusters, int nclusters, >- pmnsUpdate pmnsupdate, textUpdate textupdate, >- mtabUpdate mtabupdate, mtabCounts mtabcounts) >-{ >- int size = (dynamic_count+1) * sizeof(struct dynamic); >- >- if ((dynamic = (struct dynamic *)realloc(dynamic, size)) == NULL) { >- __pmNotifyErr(LOG_ERR, "out-of-memory registering dynamic metrics"); >- return; >- } >- dynamic[dynamic_count].prefix = prefix; >- dynamic[dynamic_count].prefixlen = strlen(prefix); >- dynamic[dynamic_count].nclusters = nclusters; >- memcpy(dynamic[dynamic_count].clusters, clusters, nclusters * sizeof(int)); >- dynamic[dynamic_count].pmnsupdate = pmnsupdate; >- dynamic[dynamic_count].textupdate = textupdate; >- dynamic[dynamic_count].mtabupdate = mtabupdate; >- dynamic[dynamic_count].mtabcounts = mtabcounts; >- dynamic[dynamic_count].pmns = NULL; >- dynamic_count++; >-} >- >-__pmnsTree * >-proc_dynamic_lookup_name(pmdaExt *pmda, const char *name) >-{ >- int i; >- >- for (i = 0; i < dynamic_count; i++) { >- if (strncmp(name, dynamic[i].prefix, dynamic[i].prefixlen) == 0) { >- if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >- proc_dynamic_metrictable(pmda); >- return dynamic[i].pmns; >- } >- } >- return NULL; >-} >- >-__pmnsTree * >-proc_dynamic_lookup_pmid(pmdaExt *pmda, pmID pmid) >-{ >- int i, j; >- int cluster = pmid_cluster(pmid); >- >- for (i = 0; i < dynamic_count; i++) { >- for (j = 0; j < dynamic[i].nclusters; j++) { >- if (cluster == dynamic[i].clusters[j]) { >- if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >- proc_dynamic_metrictable(pmda); >- return dynamic[i].pmns; >- } >- } >- } >- return NULL; >-} >- >-int >-proc_dynamic_lookup_text(pmID pmid, int type, char **buf, pmdaExt *pmda) >-{ >- int i, j; >- int cluster = pmid_cluster(pmid); >- >- for (i = 0; i < dynamic_count; i++) { >- for (j = 0; j < dynamic[i].nclusters; j++) >- if (cluster == dynamic[i].clusters[j]) >- return dynamic[i].textupdate(pmda, pmid, type, buf); >- } >- return -ENOENT; >-} >- >-/* >- * Call the update function for each new metric we're adding. >- * We pass in the original metric, and the new (uninit'd) slot >- * which needs to be filled in. All a bit obscure, really. >- */ >-static pmdaMetric * >-proc_dynamic_mtab(struct dynamic *dynamic, pmdaMetric *offset) >-{ >- int m, metric_count = proc_metrictable_size(); >- int tree_count = dynamic->extratrees; >- >- for (m = 0; m < metric_count; m++) { >- int c, id, cluster = pmid_cluster(proc_metrictab[m].m_desc.pmid); >- for (c = 0; c < dynamic->nclusters; c++) >- if (dynamic->clusters[c] == cluster) >- break; >- if (c < dynamic->nclusters) >- for (id = 0; id < tree_count; id++) >- dynamic->mtabupdate(&proc_metrictab[m], offset++, id+1); >- } >- return offset; >-} >- >-/* >- * Iterate through the dynamic table working out how many additional metric >- * table entries are needed. Then allocate a new metric table, if needed, >- * and run through the dynamic table once again to fill in the additional >- * entries. Finally, we update the metric table pointer to be the pmdaExt >- * for libpcp_pmda routines subsequent use. >- */ >-void >-proc_dynamic_metrictable(pmdaExt *pmda) >-{ >- int i, trees, total, resize = 0; >- pmdaMetric *mtab, *offset; >- >- for (i = 0; i < dynamic_count; i++) >- dynamic[i].mtabcount = dynamic[i].extratrees = 0; >- >- for (i = 0; i < dynamic_count; i++) { >- dynamic[i].mtabcounts(&total, &trees); >- dynamic[i].mtabcount += total; >- dynamic[i].extratrees += trees; >- resize += (total * trees); >- } >- >- if (resize == 0) { >- /* Fits into the default metric table - reset it to original values */ >-fallback: >- if (pmda->e_metrics != proc_metrictab) >- free(pmda->e_metrics); >- pmda->e_metrics = proc_metrictab; >- pmda->e_nmetrics = proc_metrictable_size(); >- } else { >- resize += proc_metrictable_size(); >- if ((mtab = calloc(resize, sizeof(pmdaMetric))) == NULL) >- goto fallback; >- memcpy(mtab, proc_metrictab, proc_metrictable_size() * sizeof(pmdaMetric)); >- offset = mtab + proc_metrictable_size(); >- for (i = 0; i < dynamic_count; i++) >- offset = proc_dynamic_mtab(&dynamic[i], offset); >- if (pmda->e_metrics != proc_metrictab) >- free(pmda->e_metrics); >- pmda->e_metrics = mtab; >- pmda->e_nmetrics = resize; >- } >-} >diff --git a/src/pmdas/proc/dynamic.h b/src/pmdas/proc/dynamic.h >deleted file mode 100644 >index 8819f4e..0000000 >--- a/src/pmdas/proc/dynamic.h >+++ /dev/null >@@ -1,31 +0,0 @@ >-/* >- * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >- * >- * Copyright (c) 2010 Aconex. 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. >- */ >- >-/* function to refresh a specific subtree */ >-typedef int (*pmnsUpdate)(pmdaExt *, __pmnsTree **); >-typedef int (*textUpdate)(pmdaExt *, pmID, int, char **); >-typedef void (*mtabUpdate)(pmdaMetric *, pmdaMetric *, int); >-typedef void (*mtabCounts)(int *, int *); >- >-extern pmdaMetric proc_metrictab[]; /* default metric table */ >-extern int proc_metrictable_size(); >- >-extern void proc_dynamic_pmns(const char *, int *, int, >- pmnsUpdate, textUpdate, mtabUpdate, mtabCounts); >-extern __pmnsTree *proc_dynamic_lookup_name(pmdaExt *, const char *); >-extern __pmnsTree *proc_dynamic_lookup_pmid(pmdaExt *, pmID); >-extern int proc_dynamic_lookup_text(pmID, int, char **, pmdaExt *); >-extern void proc_dynamic_metrictable(pmdaExt *); >diff --git a/src/pmdas/proc/help b/src/pmdas/proc/help >deleted file mode 100644 >index 8426f9a..0000000 >--- a/src/pmdas/proc/help >+++ /dev/null >@@ -1,181 +0,0 @@ >-# >-# Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. >-# Portions Copyright (c) International Business Machines Corp., 2002 >-# Portions Copyright (c) 2007-2009 Aconex. 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. >-# >-# Linux proc 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 >-# >- >-@ proc.nprocs instantaneous number of processes >-@ proc.psinfo.pid process identifier >-@ proc.psinfo.psargs full command string >-@ proc.psinfo.cmd command name >-@ proc.psinfo.sname process state identifier (see ps(1)). See also proc.runq metrics. >-@ proc.psinfo.ppid parent process identifier >-@ proc.psinfo.pgrp process group identifier >-@ proc.psinfo.session process session identifier >-@ proc.psinfo.tty controlling tty device number (zero if none) >-@ proc.psinfo.tty_pgrp controlling tty process group identifier >-@ proc.psinfo.flags process state flags, as a bitmap >-@ proc.psinfo.minflt count of minor page faults (i.e. reclaims) >-@ proc.psinfo.cmin_flt count of minor page faults (i.e. reclaims) of all exited children >-@ proc.psinfo.maj_flt count of page faults other than reclaims >-@ proc.psinfo.cmaj_flt count of page faults other than reclaims of all exited children >-@ proc.psinfo.utime time (in ms) spent executing user code since process started >-@ proc.psinfo.stime time (in ms) spent executing system code (calls) since process started >-@ proc.psinfo.cutime time (in ms) spent executing user code of all exited children >-@ proc.psinfo.cstime time (in ms) spent executing system code of all exited children >-@ proc.psinfo.priority priority value >-@ proc.psinfo.nice process nice value (negative nice values are lower priority) >-@ proc.psinfo.it_real_value current interval timer value (zero if none) >-@ proc.psinfo.start_time start time of the process relative to system boot time in seconds >-@ proc.psinfo.vsize virtual size of the process in Kbytes >-@ proc.psinfo.rss resident set size (i.e. physical memory) of the process >-@ proc.psinfo.rss_rlim limit on resident set size of process >-@ proc.psinfo.start_code address of the start of the code segment for the process >-@ proc.psinfo.end_code address of the end of the code segment for the process >-@ proc.psinfo.start_stack address of the stack segment for the process >-@ proc.psinfo.esp the value in the esp field of struct task_struct for the process >-@ proc.psinfo.eip the value in the eip field of struct task_struct for the process >-@ proc.psinfo.signal the value in the signal field of struct task_struct for the process >-@ proc.psinfo.blocked the value in the blocked field of struct task_struct for the process >-@ proc.psinfo.sigignore the value in the sigignore field of struct task_struct for the process >-@ proc.psinfo.sigcatch the value in the sigcatch field of struct task_struct for the process >-@ proc.psinfo.wchan wait channel, kernel address this process is blocked or sleeping on >-@ proc.psinfo.nswap count of page swap operations >-@ proc.psinfo.cnswap count of page swap operations of all exited children >-@ proc.psinfo.exit_signal the value in the exit_signal field of struct task_struct for the process >-@ proc.psinfo.ttyname name of controlling tty device, or "?" if none. See also proc.psinfo.tty. >-@ proc.psinfo.processor last CPU the process was running on >-@ proc.psinfo.wchan_s name of an event for which the process is sleeping (if blank, the process is running). >-This field needs access to a namelist file for proper >-address-to-symbol name translation. If no namelist file >-is available, the address is printed instead. The namelist >-file must match the current Linux kernel exactly. >-The search path for the namelist file is as follows: >- /boot/System.map-`uname -r` >- /boot/System.map >- /lib/modules/`uname -r`/System.map >- /usr/src/linux/System.map >- /System.map >-@ proc.psinfo.signal_s pending signals mask in string form (from /proc/<pid>/status) >-@ proc.psinfo.blocked_s blocked signals mask in string form (from /proc/<pid>/status) >-@ proc.psinfo.sigignore_s ignored signals mask in string form (from /proc/<pid>/status) >-@ proc.psinfo.sigcatch_s caught signals mask in string form (from /proc/<pid>/status) >-@ proc.memory.size instantaneous virtual size of process, excluding page table and task structure. >-@ proc.memory.rss instantaneous resident size of process, excluding page table and task structure. >-@ proc.memory.share instantaneous amount of memory shared by this process with other processes >-@ proc.memory.textrss instantaneous resident size of process code segment in Kbytes >-@ proc.memory.librss instantaneous resident size of library code mapped by the process, in Kbytes >-@ proc.memory.datrss instantaneous resident size of process data segment, in Kbytes >-@ proc.memory.dirty instantaneous amount of memory that has been modified by the process, in Kbytes >-@ proc.memory.maps table of memory mapped by process in string form from /proc/<pid>/maps >-@ proc.memory.vmsize total virtual memory (from /proc/<pid>/status) >-@ proc.memory.vmlock locked virtual memory (from /proc/<pid>/status) >-@ proc.memory.vmrss resident virtual memory (from /proc/<pid>/status) >-@ proc.memory.vmdata virtual memory used for data (from /proc/<pid>/status) >-@ proc.memory.vmstack virtual memory used for stack (from /proc/<pid>/status) >-@ proc.memory.vmexe virtual memory used for non-library executable code (from /proc/<pid>/status) >-@ proc.memory.vmlib virtual memory used for libraries (from /proc/<pid>/status) >-@ proc.id.uid real user ID from /proc/<pid>/status >-@ proc.id.euid effective user ID from /proc/<pid>/status >-@ proc.id.suid saved user ID from /proc/<pid>/status >-@ proc.id.fsuid filesystem user ID from /proc/<pid>/status >-@ proc.id.gid real group ID from /proc/<pid>/status >-@ proc.id.egid effective group ID from /proc/<pid>/status >-@ proc.id.sgid saved group ID from /proc/<pid>/status >-@ proc.id.fsgid filesystem group ID from /proc/<pid>/status >-@ proc.id.uid_nm real user name based on real user ID from /proc/<pid>/status >-@ proc.id.euid_nm effective user name based on effective user ID from /proc/<pid>/status >-@ proc.id.suid_nm saved user name based on saved user ID from /proc/<pid>/status >-@ proc.id.fsuid_nm filesystem user name based on filesystem user ID from /proc/<pid>/status >-@ proc.id.gid_nm real group name based on real group ID from /proc/<pid>/status >-@ proc.id.egid_nm effective group name based on effective group ID from /proc/<pid>/status >-@ proc.id.sgid_nm saved group name based on saved group ID from /proc/<pid>/status >-@ proc.id.fsgid_nm filesystem group name based on filesystem group ID from /proc/<pid>/status >- >-@ proc.runq.runnable number of runnable (on run queue) processes >-Instantaneous number of runnable (on run queue) processes, state 'R' in ps >-@ proc.runq.blocked number of processes in uninterruptible sleep >-Instantaneous number of processes in uninterruptible sleep, state 'D' in ps >-@ proc.runq.sleeping number of processes sleeping >-Instantaneous number of processes sleeping, state 'S' in ps >-@ proc.runq.stopped number of traced, stopped or suspended processes >-Instantaneous number of traced, stopped or suspended processes, state >-'T' in ps >-@ proc.runq.swapped number of processes that are swapped >-Instantaneous number of processes (excluding kernel threads) that are >-swapped, state 'SW' in ps >-@ proc.runq.defunct number of defunct/zombie processes >-Instantaneous number of defunct/zombie processes, state 'Z' in ps >-@ proc.runq.unknown number of processes is an unknown state >-Instantaneous number of processes is an unknown state, including all >-kernel threads >-@ proc.runq.kernel number of kernel threads >-Instantaneous number of processes with virtual size of zero (kernel threads) >- >-@ proc.io.rchar >-Extended accounting information - count of the number of bytes that >-have passed over the read(2), readv(2) and sendfile(2) syscalls by >-each process. >- >-@ proc.io.wchar >-Extended accounting information - count of the number of bytes that >-have passed over the write(2), writev(2) and sendfile(2) syscalls by >-each process. >- >-@ proc.io.syscr >-Extended accounting information - count of number of calls to the >-read(2), readv(2) and sendfile(2) syscalls by each process. >- >-@ proc.io.syscw >-Extended accounting information - count of number of calls to the >-write(2), writev(2) and sendfile(2) syscalls by each process. >- >-@ proc.io.read_bytes >-Number of bytes physically read on by devices on behalf of this process. >-@ proc.io.write_bytes >-Number of bytes physically written to devices on behalf of this process. >-This must be reduced by any truncated I/O (proc.io.cancelled_write_bytes). >-@ proc.io.cancelled_write_bytes >-Number of bytes cancelled via truncate by this process. Actual physical >-writes for an individual process can be calculated as: >- proc.io.write_bytes - proc.io.cancelled_write_bytes. >- >-@ proc.schedstat.cpu_time >-Length of time in nanoseconds that a process has been running, including >-scheduling time. >-@ proc.schedstat.run_delay >-Length of time in nanoseconds that a process spent waiting to be scheduled >-to run in the run queue. >-@ proc.schedstat.pcount >-Number of times a process has been scheduled to run on a CPU (this is >-incremented when a task actually reaches a CPU to run on, not simply >-when it is added to the run queue). >- >-@ proc.fd.count >-Number of file descriptors this process has open. >- >diff --git a/src/pmdas/proc/pmda.c b/src/pmdas/proc/pmda.c >deleted file mode 100644 >index bf680c8..0000000 >--- a/src/pmdas/proc/pmda.c >+++ /dev/null >@@ -1,1674 +0,0 @@ >-/* >- * proc PMDA >- * >- * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >- * Portions Copyright (c) 2002 International Business Machines Corp. >- * Portions Copyright (c) 2007-2011 Aconex. 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 "dynamic.h" >- >-#include <ctype.h> >-#include <sys/vfs.h> >-#include <sys/stat.h> >-#include <sys/times.h> >-#include <sys/utsname.h> >-#include <utmp.h> >-#include <pwd.h> >-#include <grp.h> >- >-#include "../linux/convert.h" >-#include "clusters.h" >-#include "indom.h" >- >-#include "proc_stat.h" >-#include "getinfo.h" >-#include "proc_pid.h" >-#include "proc_partitions.h" >-#include "proc_runq.h" >-#include "proc_uptime.h" >-#include "ksym.h" >-#include "proc_sys_fs.h" >-#include "proc_vmstat.h" >-#include "sysfs_kernel.h" >-#include "linux_table.h" >-#include "cgroups.h" >- >-static proc_stat_t proc_stat; >-static proc_pid_t proc_pid; >-static struct utsname kernel_uname; >-static char uname_string[sizeof(kernel_uname)]; >-static proc_runq_t proc_runq; >-static proc_uptime_t proc_uptime; >-static proc_sys_fs_t proc_sys_fs; >-static proc_vmstat_t proc_vmstat; >-static sysfs_kernel_t sysfs_kernel; >- >-static int _isDSO = 1; /* =0 I am a daemon */ >- >-/* globals */ >-size_t _pm_system_pagesize; /* for hinv.pagesize and used elsewhere */ >-int _pm_have_proc_vmstat; /* if /proc/vmstat is available */ >- >-pmdaIndom indomtab[] = { >- { PROC_INDOM, 0, NULL }, >- { CGROUP_SUBSYS_INDOM, 0, NULL }, >- { CGROUP_MOUNTS_INDOM, 0, NULL }, >-}; >- >- >-/* >- * all metrics supported in this PMDA - one table entry for each >- */ >- >-pmdaMetric linux_metrictab[] = { >- >-/* >- * proc/<pid>/stat cluster >- */ >- >-/* proc.nprocs */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.pid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.cmd */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,1), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.sname */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,2), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.ppid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.pgrp */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.session */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.tty */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.tty_pgrp */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.flags */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,8), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.minflt */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,9), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.cmin_flt */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,10), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.maj_flt */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,11), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.cmaj_flt */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,12), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.utime */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,13), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >- >-/* proc.psinfo.stime */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,14), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >- >-/* proc.psinfo.cutime */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,15), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >- >-/* proc.psinfo.cstime */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,16), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >- >-/* proc.psinfo.priority */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,17), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.nice */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,18), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-#if 0 >-/* invalid field */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,19), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >-#endif >- >-/* proc.psinfo.it_real_value */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.start_time */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) } }, >- >-/* proc.psinfo.vsize */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.psinfo.rss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.psinfo.rss_rlim */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.psinfo.start_code */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.end_code */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.start_stack */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,27), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.esp */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,28), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.eip */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,29), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.signal */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,30), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.blocked */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,31), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.sigignore */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,32), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.sigcatch */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,33), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.wchan */ >-#if defined(HAVE_64BIT_PTR) >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U64, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >-#elif defined(HAVE_32BIT_PTR) >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >-#else >- error! unsupported pointer size >-#endif >- >-/* proc.psinfo.nswap */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,35), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.cnswap */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,36), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.psinfo.exit_signal */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,37), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.processor -- added by Mike Mason <mmlnx@us.ibm.com> */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,38), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.ttyname */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,39), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0) } }, >- >-/* proc.psinfo.wchan_s -- added by Mike Mason <mmlnx@us.ibm.com> */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,40), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.psargs -- modified by Mike Mason <mmlnx@us.ibm.com> */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STAT,41), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* >- * proc/<pid>/status cluster >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- >-/* proc.id.uid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.euid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.suid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.fsuid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.gid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.egid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.sgid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.fsgid */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.uid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,8), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.euid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,9), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.suid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,10), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.fsuid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,11), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.gid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,12), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.egid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,13), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.sgid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,14), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.id.fsgid_nm */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,15), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.signal_s */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,16), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.blocked_s */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,17), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.sigignore_s */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,18), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.psinfo.sigcatch_s */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,19), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* proc.memory.vmsize */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmlock */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmrss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmdata */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmstack */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmexe */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* proc.memory.vmlib */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATUS,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* >- * proc/<pid>/statm cluster >- */ >- >-/* proc.memory.size */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.rss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.share */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.textrss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.librss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.datrss */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.dirty */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >- >-/* proc.memory.maps -- added by Mike Mason <mmlnx@us.ibm.com> */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_STATM,7), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,0,0,0,0)}}, >- >-/* >- * proc/<pid>/schedstat cluster >- */ >- >-/* proc.schedstat.cpu_time */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >-/* proc.schedstat.run_delay */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >-/* proc.schedstat.pcount */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,2), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >- >-/* >- * proc/<pid>/io cluster >- */ >-/* proc.io.rchar */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >-/* proc.io.wchar */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >-/* proc.io.syscr */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,2), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >-/* proc.io.syscw */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,3), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >-/* proc.io.read_bytes */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,4), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >-/* proc.io.write_bytes */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,5), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >-/* proc.io.cancelled_write_bytes */ >- { NULL, >- { PMDA_PMID(CLUSTER_PID_IO,6), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >- PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >- >-/* >- * proc.runq cluster >- */ >- >-/* proc.runq.runnable */ >- { &proc_runq.runnable, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.blocked */ >- { &proc_runq.blocked, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.sleeping */ >- { &proc_runq.sleeping, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.stopped */ >- { &proc_runq.stopped, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.swapped */ >- { &proc_runq.swapped, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.defunct */ >- { &proc_runq.defunct, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.unknown */ >- { &proc_runq.unknown, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >-/* proc.runq.kernel */ >- { &proc_runq.kernel, >- { PMDA_PMID(CLUSTER_PROC_RUNQ, 7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >- >- >- >-/* >- * control groups cluster >- */ >- /* cgroups.subsys.hierarchy */ >- { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,0), PM_TYPE_U32, >- CGROUP_SUBSYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >- >- /* cgroups.subsys.count */ >- { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,1), PM_TYPE_U32, >- PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >- >- /* cgroups.mounts.subsys */ >- { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,0), PM_TYPE_STRING, >- CGROUP_MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >- >- /* cgroups.mounts.count */ >- { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,1), PM_TYPE_U32, >- PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >- >-#if 0 /* not yet implemented */ >- /* cgroup.groups.cpuset.[<group>.]tasks.pid */ >- { NULL, {PMDA_PMID(CLUSTER_CPUSET_PROCS,0), PM_TYPE_U32, >- PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >-#endif >- >- /* cgroup.groups.cpuset.[<group>.]cpus */ >- { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,0), PM_TYPE_STRING, >- PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >- >- /* cgroup.groups.cpuset.[<group>.]mems */ >- { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,1), PM_TYPE_STRING, >- PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >- >-#if 0 /* not yet implemented */ >- /* cgroup.groups.cpuacct.[<group>.]tasks.pid */ >- { NULL, {PMDA_PMID(CLUSTER_CPUACCT_PROCS,0), PM_TYPE_U32, >- PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >-#endif >- >- /* cgroup.groups.cpuacct.[<group>.]stat.user */ >- { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,0), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >- >- /* cgroup.groups.cpuacct.[<group>.]stat.system */ >- { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,1), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >- >- /* cgroup.groups.cpuacct.[<group>.]usage */ >- { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,2), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >- >- /* cgroup.groups.cpuacct.[<group>.]usage_percpu */ >- { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,3), PM_TYPE_U64, >- CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >- >-#if 0 >- /* cgroup.groups.cpusched.[<group>.]tasks.pid */ >- { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_PROCS,0), PM_TYPE_U32, >- PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >-#endif >- >- /* cgroup.groups.cpusched.[<group>.]shares */ >- { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_GROUPS,0), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >- >-#if 0 >- /* cgroup.groups.memory.[<group>.]tasks.pid */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_PROCS,0), PM_TYPE_U32, >- PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >-#endif >- >- /* cgroup.groups.memory.[<group>.]stat.cache */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,0), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.rss */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,1), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.pgin */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,2), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.pgout */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,3), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.swap */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,4), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.active_anon */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,5), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.inactive_anon */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,6), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.active_file */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,7), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.inactive_file */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,8), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >- /* cgroup.groups.memory.[<group>.]stat.unevictable */ >- { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,9), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >-#if 0 >- /* cgroup.groups.netclass.[<group>.]tasks.pid */ >- { NULL, {PMDA_PMID(CLUSTER_NET_CLS_PROCS,0), PM_TYPE_U32, >- PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >-#endif >- >- /* cgroup.groups.netclass.[<group>.]classid */ >- { NULL, {PMDA_PMID(CLUSTER_NET_CLS_GROUPS,0), PM_TYPE_U64, >- PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >- >-/* >- * proc/<pid>/fd cluster >- */ >- >- /* proc.fd.count */ >- { NULL, {PMDA_PMID(CLUSTER_PID_FD,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >- PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >-}; >- >-int >-refresh_cgroups(pmdaExt *pmda, __pmnsTree **tree) >-{ >- int changed; >- time_t rightnow; >- static time_t previoustime; >- static __pmnsTree *previoustree; >- >- if (tree) { >- if ((rightnow = time(NULL)) == previoustime) { >- *tree = previoustree; >- return 0; >- } >- } >- >- refresh_cgroup_subsys(INDOM(CGROUP_SUBSYS_INDOM)); >- changed = refresh_cgroup_groups(pmda, INDOM(CGROUP_MOUNTS_INDOM), tree); >- >- if (tree) { >- previoustime = rightnow; >- previoustree = *tree; >- } >- return changed; >-} >- >-static void >-linux_refresh(pmdaExt *pmda, int *need_refresh) >-{ >- int need_refresh_mtab = 0; >- >- if (need_refresh[CLUSTER_CGROUP_SUBSYS] || >- need_refresh[CLUSTER_CGROUP_MOUNTS] || >- need_refresh[CLUSTER_CPUSET_PROCS] || >- need_refresh[CLUSTER_CPUSET_GROUPS] || >- need_refresh[CLUSTER_CPUACCT_PROCS] || >- need_refresh[CLUSTER_CPUACCT_GROUPS] || >- need_refresh[CLUSTER_CPUSCHED_PROCS] || >- need_refresh[CLUSTER_CPUSCHED_GROUPS] || >- need_refresh[CLUSTER_MEMORY_PROCS] || >- need_refresh[CLUSTER_MEMORY_GROUPS] || >- need_refresh[CLUSTER_NET_CLS_PROCS] || >- need_refresh[CLUSTER_NET_CLS_GROUPS]) { >- need_refresh_mtab |= refresh_cgroups(pmda, NULL); >- } >- >- if (need_refresh[CLUSTER_PID_STAT] || need_refresh[CLUSTER_PID_STATM] || >- need_refresh[CLUSTER_PID_STATUS] || need_refresh[CLUSTER_PID_IO] || >- need_refresh[CLUSTER_PID_SCHEDSTAT] || need_refresh[CLUSTER_PID_FD]) >- refresh_proc_pid(&proc_pid); >- >- if (need_refresh[CLUSTER_KERNEL_UNAME]) >- uname(&kernel_uname); >- >- if (need_refresh[CLUSTER_PROC_RUNQ]) >- refresh_proc_runq(&proc_runq); >- >- if (need_refresh[CLUSTER_SCSI]) >- refresh_proc_scsi(&proc_scsi); >- >- if (need_refresh[CLUSTER_SEM_LIMITS]) >- refresh_sem_limits(&sem_limits); >- >- if (need_refresh[CLUSTER_MSG_LIMITS]) >- refresh_msg_limits(&msg_limits); >- >- if (need_refresh[CLUSTER_SHM_LIMITS]) >- refresh_shm_limits(&shm_limits); >- >- if (need_refresh[CLUSTER_UPTIME]) >- refresh_proc_uptime(&proc_uptime); >- >- if (need_refresh[CLUSTER_VFS]) >- refresh_proc_sys_fs(&proc_sys_fs); >- >- if (need_refresh[CLUSTER_VMSTAT]) >- refresh_proc_vmstat(&proc_vmstat); >- >- if (need_refresh[CLUSTER_SYSFS_KERNEL]) >- refresh_sysfs_kernel(&sysfs_kernel); >- >- if (need_refresh_mtab) >- proc_dynamic_metrictable(pmda); >-} >- >-static int >-linux_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) >-{ >- __pmInDom_int *indomp = (__pmInDom_int *)&indom; >- int need_refresh[NUM_CLUSTERS]; >- char newname[11]; /* see Note below */ >- >- memset(need_refresh, 0, sizeof(need_refresh)); >- switch (indomp->serial) { >- case PROC_INDOM: >- need_refresh[CLUSTER_PID_STAT]++; >- need_refresh[CLUSTER_PID_STATM]++; >- need_refresh[CLUSTER_PID_STATUS]++; >- need_refresh[CLUSTER_PID_SCHEDSTAT]++; >- need_refresh[CLUSTER_PID_IO]++; >- need_refresh[CLUSTER_PID_FD]++; >- break; >- case CGROUP_SUBSYS_INDOM: >- need_refresh[CLUSTER_CGROUP_SUBSYS]++; >- break; >- case CGROUP_MOUNTS_INDOM: >- need_refresh[CLUSTER_CGROUP_MOUNTS]++; >- break; >- /* no default label : pmdaInstance will pick up errors */ >- } >- >- if (indomp->serial == PROC_INDOM && inst == PM_IN_NULL && name != NULL) { >- /* >- * For the proc indom, if the name is a pid (as a string), and it >- * contains only digits (i.e. it's not a full instance name) then >- * reformat it to be exactly six digits, with leading zeros. >- * >- * Note that although format %06d is used here and in proc_pid.c, >- * the pid could be longer than this (in which case there >- * are no leading zeroes. The size of newname[] is chosen >- * to comfortably accommodate a 32-bit pid (Linux maximum), >- * or max value of 4294967295 (10 digits) >- */ >- char *p; >- for (p = name; *p != '\0'; p++) { >- if (!isdigit(*p)) >- break; >- } >- if (*p == '\0') { >- snprintf(newname, sizeof(newname), "%06d", atoi(name)); >- name = newname; >- } >- } >- >- linux_refresh(pmda, need_refresh); >- return pmdaInstance(indom, inst, name, result, pmda); >-} >- >-/* >- * callback provided to pmdaFetch >- */ >- >-static int >-linux_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) >-{ >- __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); >- int i; >- int sts; >- char *f; >- long sl; >- unsigned long ul; >- int *ip; >- proc_pid_entry_t *entry; >- >- if (mdesc->m_user != NULL) { >- /* >- * The metric value is extracted directly via the address specified >- * in metrictab. Note: not all metrics support this - those that >- * don't have NULL for the m_user field in their respective >- * metrictab slot. >- */ >- if (idp->cluster == CLUSTER_VMSTAT) { >- if (!_pm_have_proc_vmstat || *(__uint64_t *)mdesc->m_user == (__uint64_t)-1) >- return 0; /* no value available on this kernel */ >- } >- if (idp->cluster == CLUSTER_SYSFS_KERNEL) { >- /* no values available for udev metrics */ >- if (idp->item == 0 && !sysfs_kernel.valid_uevent_seqnum) { >- return 0; >- } >- } >- >- switch (mdesc->m_desc.type) { >- case PM_TYPE_32: >- atom->l = *(__int32_t *)mdesc->m_user; >- break; >- case PM_TYPE_U32: >- atom->ul = *(__uint32_t *)mdesc->m_user; >- break; >- case PM_TYPE_64: >- atom->ll = *(__int64_t *)mdesc->m_user; >- break; >- case PM_TYPE_U64: >- atom->ull = *(__uint64_t *)mdesc->m_user; >- break; >- case PM_TYPE_FLOAT: >- atom->f = *(float *)mdesc->m_user; >- break; >- case PM_TYPE_DOUBLE: >- atom->d = *(double *)mdesc->m_user; >- break; >- case PM_TYPE_STRING: >- atom->cp = (char *)mdesc->m_user; >- break; >- default: >- return 0; >- } >- } >- else >- switch (idp->cluster) { >- >- case CLUSTER_UPTIME: /* uptime */ >- switch (idp->item) { >- case 0: >- /* >- * kernel.all.uptime (in seconds) >- * contributed by "gilly" <gilly@exanet.com> >- * modified by Mike Mason" <mmlnx@us.ibm.com> >- */ >- atom->ul = proc_uptime.uptime; >- break; >- case 1: >- /* >- * kernel.all.idletime (in seconds) >- * contributed by "Mike Mason" <mmlnx@us.ibm.com> >- */ >- atom->ul = proc_uptime.idletime; >- break; >- default: >- return PM_ERR_PMID; >- } >- break; >- >- case CLUSTER_PID_STAT: >- if (idp->item == 99) /* proc.nprocs */ >- atom->ul = proc_pid.indom->it_numinst; >- else { >- static char ttyname[MAXPATHLEN]; >- >- if ((entry = fetch_proc_pid_stat(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- >- switch (idp->item) { >- >- >- case PROC_PID_STAT_PID: >- atom->ul = entry->id; >- break; >- >- case PROC_PID_STAT_TTYNAME: >- if ((f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_TTY)) == NULL) >- atom->cp = "?"; >- else { >- dev_t dev = (dev_t)atoi(f); >- atom->cp = get_ttyname_info(inst, dev, ttyname); >- } >- break; >- >- case PROC_PID_STAT_CMD: >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- atom->cp = f + 1; >- atom->cp[strlen(atom->cp)-1] = '\0'; >- break; >- >- case PROC_PID_STAT_PSARGS: >- atom->cp = entry->name + 7; >- break; >- >- case PROC_PID_STAT_STATE: >- /* >- * string >- */ >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- atom->cp = f; >- break; >- >- case PROC_PID_STAT_VSIZE: >- case PROC_PID_STAT_RSS_RLIM: >- /* >- * bytes converted to kbytes >- */ >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- atom->ul /= 1024; >- break; >- >- case PROC_PID_STAT_RSS: >- /* >- * pages converted to kbytes >- */ >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- atom->ul *= _pm_system_pagesize / 1024; >- break; >- >- case PROC_PID_STAT_UTIME: >- case PROC_PID_STAT_STIME: >- case PROC_PID_STAT_CUTIME: >- case PROC_PID_STAT_CSTIME: >- /* >- * unsigned jiffies converted to unsigned milliseconds >- */ >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- >- sscanf(f, "%lu", &ul); >- _pm_assign_ulong(atom, 1000 * (double)ul / proc_stat.hz); >- break; >- >- case PROC_PID_STAT_PRIORITY: >- case PROC_PID_STAT_NICE: >- /* >- * signed decimal int >- */ >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%d", &atom->l); >- break; >- >- case PROC_PID_STAT_WCHAN: >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >-#if defined(HAVE_64BIT_PTR) >- sscanf(f, "%lu", &atom->ull); /* 64bit address */ >-#else >- sscanf(f, "%u", &atom->ul); /* 32bit address */ >-#endif >- break; >- >- case PROC_PID_STAT_WCHAN_SYMBOL: >- if (entry->wchan_buf) /* 2.6 kernel, /proc/<pid>/wchan */ >- atom->cp = entry->wchan_buf; >- else { /* old school (2.4 kernels, at least) */ >- char *wc; >- /* >- * Convert address to symbol name if requested >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >- f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_WCHAN); >- if (f == NULL) >- return PM_ERR_INST; >-#if defined(HAVE_64BIT_PTR) >- sscanf(f, "%lu", &atom->ull); /* 64bit address */ >- if ((wc = wchan(atom->ull))) >- atom->cp = wc; >- else >- atom->cp = atom->ull ? f : ""; >-#else >- sscanf(f, "%u", &atom->ul); /* 32bit address */ >- if ((wc = wchan((__psint_t)atom->ul))) >- atom->cp = wc; >- else >- atom->cp = atom->ul ? f : ""; >-#endif >- } >- break; >- >- default: >- /* >- * unsigned decimal int >- */ >- if (idp->item >= 0 && idp->item < NR_PROC_PID_STAT) { >- if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- } >- else >- return PM_ERR_PMID; >- break; >- } >- } >- break; >- >- case CLUSTER_PID_STATM: >- if (idp->item == PROC_PID_STATM_MAPS) { /* proc.memory.maps */ >- if ((entry = fetch_proc_pid_maps(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- atom->cp = entry->maps_buf; >- } else { >- if ((entry = fetch_proc_pid_statm(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- >- if (idp->item >= 0 && idp->item <= PROC_PID_STATM_DIRTY) { >- /* unsigned int */ >- if ((f = _pm_getfield(entry->statm_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- atom->ul *= _pm_system_pagesize / 1024; >- } >- else >- return PM_ERR_PMID; >- } >- break; >- >- case CLUSTER_PID_SCHEDSTAT: >- if ((entry = fetch_proc_pid_schedstat(inst, &proc_pid)) == NULL) >- return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; >- >- if (idp->item >= 0 && idp->item < NR_PROC_PID_SCHED) { >- if ((f = _pm_getfield(entry->schedstat_buf, idp->item)) == NULL) >- return PM_ERR_INST; >- if (idp->item == PROC_PID_SCHED_PCOUNT && >- mdesc->m_desc.type == PM_TYPE_U32) >- sscanf(f, "%u", &atom->ul); >- else >-#if defined(HAVE_64BIT_PTR) >- sscanf(f, "%lu", &atom->ull); /* 64bit address */ >-#else >- sscanf(f, "%u", &atom->ul); /* 32bit address */ >-#endif >- } >- else >- return PM_ERR_PMID; >- break; >- >- case CLUSTER_PID_IO: >- if ((entry = fetch_proc_pid_io(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- >- switch (idp->item) { >- >- case PROC_PID_IO_RCHAR: >- if ((f = _pm_getfield(entry->io_lines.rchar, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_WCHAR: >- if ((f = _pm_getfield(entry->io_lines.wchar, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_SYSCR: >- if ((f = _pm_getfield(entry->io_lines.syscr, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_SYSCW: >- if ((f = _pm_getfield(entry->io_lines.syscw, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_READ_BYTES: >- if ((f = _pm_getfield(entry->io_lines.readb, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_WRITE_BYTES: >- if ((f = _pm_getfield(entry->io_lines.writeb, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- case PROC_PID_IO_CANCELLED_BYTES: >- if ((f = _pm_getfield(entry->io_lines.cancel, 1)) == NULL) >- atom->ull = 0; >- else >- sscanf(f, "%llu", (unsigned long long *)&atom->ull); >- break; >- >- default: >- return PM_ERR_PMID; >- } >- break; >- >- /* >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- case CLUSTER_PID_STATUS: >- if ((entry = fetch_proc_pid_status(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- >- switch (idp->item) { >- >- case PROC_PID_STATUS_UID: >- case PROC_PID_STATUS_EUID: >- case PROC_PID_STATUS_SUID: >- case PROC_PID_STATUS_FSUID: >- case PROC_PID_STATUS_UID_NM: >- case PROC_PID_STATUS_EUID_NM: >- case PROC_PID_STATUS_SUID_NM: >- case PROC_PID_STATUS_FSUID_NM: >- { >- struct passwd *pwe; >- >- if ((f = _pm_getfield(entry->status_lines.uid, (idp->item % 4) + 1)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- if (idp->item > PROC_PID_STATUS_FSUID) { >- if ((pwe = getpwuid((uid_t)atom->ul)) != NULL) >- atom->cp = pwe->pw_name; >- else >- atom->cp = "UNKNOWN"; >- } >- } >- break; >- >- case PROC_PID_STATUS_GID: >- case PROC_PID_STATUS_EGID: >- case PROC_PID_STATUS_SGID: >- case PROC_PID_STATUS_FSGID: >- case PROC_PID_STATUS_GID_NM: >- case PROC_PID_STATUS_EGID_NM: >- case PROC_PID_STATUS_SGID_NM: >- case PROC_PID_STATUS_FSGID_NM: >- { >- struct group *gre; >- >- if ((f = _pm_getfield(entry->status_lines.gid, (idp->item % 4) + 1)) == NULL) >- return PM_ERR_INST; >- sscanf(f, "%u", &atom->ul); >- if (idp->item > PROC_PID_STATUS_FSGID) { >- if ((gre = getgrgid((gid_t)atom->ul)) != NULL) { >- atom->cp = gre->gr_name; >- } else { >- atom->cp = "UNKNOWN"; >- } >- } >- } >- break; >- >- case PROC_PID_STATUS_SIGNAL: >- if ((atom->cp = _pm_getfield(entry->status_lines.sigpnd, 1)) == NULL) >- return PM_ERR_INST; >- break; >- >- case PROC_PID_STATUS_BLOCKED: >- if ((atom->cp = _pm_getfield(entry->status_lines.sigblk, 1)) == NULL) >- return PM_ERR_INST; >- break; >- >- case PROC_PID_STATUS_SIGCATCH: >- if ((atom->cp = _pm_getfield(entry->status_lines.sigcgt, 1)) == NULL) >- return PM_ERR_INST; >- break; >- >- case PROC_PID_STATUS_SIGIGNORE: >- if ((atom->cp = _pm_getfield(entry->status_lines.sigign, 1)) == NULL) >- return PM_ERR_INST; >- break; >- >- case PROC_PID_STATUS_VMSIZE: >- if ((f = _pm_getfield(entry->status_lines.vmsize, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMLOCK: >- if ((f = _pm_getfield(entry->status_lines.vmlck, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMRSS: >- if ((f = _pm_getfield(entry->status_lines.vmrss, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMDATA: >- if ((f = _pm_getfield(entry->status_lines.vmdata, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMSTACK: >- if ((f = _pm_getfield(entry->status_lines.vmstk, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMEXE: >- if ((f = _pm_getfield(entry->status_lines.vmexe, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- case PROC_PID_STATUS_VMLIB: >- if ((f = _pm_getfield(entry->status_lines.vmlib, 1)) == NULL) >- atom->ul = 0; >- else >- sscanf(f, "%u", &atom->ul); >- break; >- >- default: >- return PM_ERR_PMID; >- } >- break; >- >- /* >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- case CLUSTER_SEM_LIMITS: >- switch (idp->item) { >- case 0: /* ipc.sem.max_semmap */ >- atom->ul = sem_limits.semmap; >- break; >- case 1: /* ipc.sem.max_semid */ >- atom->ul = sem_limits.semmni; >- break; >- case 2: /* ipc.sem.max_sem */ >- atom->ul = sem_limits.semmns; >- break; >- case 3: /* ipc.sem.num_undo */ >- atom->ul = sem_limits.semmnu; >- break; >- case 4: /* ipc.sem.max_perid */ >- atom->ul = sem_limits.semmsl; >- break; >- case 5: /* ipc.sem.max_ops */ >- atom->ul = sem_limits.semopm; >- break; >- case 6: /* ipc.sem.max_undoent */ >- atom->ul = sem_limits.semume; >- break; >- case 7: /* ipc.sem.sz_semundo */ >- atom->ul = sem_limits.semusz; >- break; >- case 8: /* ipc.sem.max_semval */ >- atom->ul = sem_limits.semvmx; >- break; >- case 9: /* ipc.sem.max_exit */ >- atom->ul = sem_limits.semaem; >- break; >- default: >- return PM_ERR_PMID; >- } >- break; >- >- /* >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- case CLUSTER_MSG_LIMITS: >- switch (idp->item) { >- case 0: /* ipc.msg.sz_pool */ >- atom->ul = msg_limits.msgpool; >- break; >- case 1: /* ipc.msg.mapent */ >- atom->ul = msg_limits.msgmap; >- break; >- case 2: /* ipc.msg.max_msgsz */ >- atom->ul = msg_limits.msgmax; >- break; >- case 3: /* ipc.msg.max_defmsgq */ >- atom->ul = msg_limits.msgmnb; >- break; >- case 4: /* ipc.msg.max_msgqid */ >- atom->ul = msg_limits.msgmni; >- break; >- case 5: /* ipc.msg.sz_msgseg */ >- atom->ul = msg_limits.msgssz; >- break; >- case 6: /* ipc.msg.num_smsghdr */ >- atom->ul = msg_limits.msgtql; >- break; >- case 7: /* ipc.msg.max_seg */ >- atom->ul = (unsigned long) msg_limits.msgseg; >- break; >- default: >- return PM_ERR_PMID; >- } >- break; >- >- /* >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- case CLUSTER_SHM_LIMITS: >- switch (idp->item) { >- case 0: /* ipc.shm.max_segsz */ >- atom->ul = shm_limits.shmmax; >- break; >- case 1: /* ipc.shm.min_segsz */ >- atom->ul = shm_limits.shmmin; >- break; >- case 2: /* ipc.shm.max_seg */ >- atom->ul = shm_limits.shmmni; >- break; >- case 3: /* ipc.shm.max_segproc */ >- atom->ul = shm_limits.shmseg; >- break; >- case 4: /* ipc.shm.max_shmsys */ >- atom->ul = shm_limits.shmall; >- break; >- default: >- return PM_ERR_PMID; >- } >- break; >- >- /* >- * Cluster added by Mike Mason <mmlnx@us.ibm.com> >- */ >- case CLUSTER_NUSERS: >- { >- /* count the number of users */ >- struct utmp *ut; >- atom->ul = 0; >- setutent(); >- while ((ut = getutent())) { >- if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) >- atom->ul++; >- } >- endutent(); >- } >- break; >- >- >- case CLUSTER_CGROUP_SUBSYS: >- switch (idp->item) { >- case 0: /* cgroup.subsys.hierarchy */ >- sts = pmdaCacheLookup(INDOM(CGROUP_SUBSYS_INDOM), inst, NULL, (void **)&ip); >- if (sts < 0) >- return sts; >- if (sts != PMDA_CACHE_ACTIVE) >- return PM_ERR_INST; >- atom->ul = i; >- break; >- >- case 1: /* cgroup.subsys.count */ >- atom->ul = pmdaCacheOp(INDOM(CGROUP_SUBSYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >- break; >- } >- break; >- >- case CLUSTER_CGROUP_MOUNTS: >- switch (idp->item) { >- case 0: /* cgroup.mounts.subsys */ >- sts = pmdaCacheLookup(INDOM(CGROUP_MOUNTS_INDOM), inst, NULL, (void **)&fs); >- if (sts < 0) >- return sts; >- if (sts != PMDA_CACHE_ACTIVE) >- return PM_ERR_INST; >- atom->cp = cgroup_find_subsys(INDOM(CGROUP_SUBSYS_INDOM), fs->options); >- break; >- >- case 1: /* cgroup.mounts.count */ >- atom->ul = pmdaCacheOp(INDOM(CGROUP_MOUNTS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >- break; >- } >- break; >- >- case CLUSTER_CPUSET_GROUPS: >- case CLUSTER_CPUACCT_GROUPS: >- case CLUSTER_CPUSCHED_GROUPS: >- case CLUSTER_MEMORY_GROUPS: >- case CLUSTER_NET_CLS_GROUPS: >- return cgroup_group_fetch(idp->cluster, idp->item, inst, atom); >- >- case CLUSTER_CPUSET_PROCS: >- case CLUSTER_CPUACCT_PROCS: >- case CLUSTER_CPUSCHED_PROCS: >- case CLUSTER_MEMORY_PROCS: >- case CLUSTER_NET_CLS_PROCS: >- return cgroup_procs_fetch(idp->cluster, idp->item, inst, atom); >- >- case CLUSTER_PID_FD: >- if ((entry = fetch_proc_pid_fd(inst, &proc_pid)) == NULL) >- return PM_ERR_INST; >- if (idp->item != PROC_PID_FD_COUNT) >- return PM_ERR_INST; >- >- atom->ul = entry->fd_count; >- break; >- >- default: /* unknown cluster */ >- return PM_ERR_PMID; >- } >- >- return 1; >-} >- >- >-static int >-linux_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) >-{ >- int i; >- int need_refresh[NUM_CLUSTERS]; >- >- memset(need_refresh, 0, sizeof(need_refresh)); >- for (i=0; i < numpmid; i++) { >- __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); >- if (idp->cluster >= 0 && idp->cluster < NUM_CLUSTERS) { >- need_refresh[idp->cluster]++; >- >- if (idp->cluster == CLUSTER_STAT && >- need_refresh[CLUSTER_PARTITIONS] == 0 && >- is_partitions_metric(pmidlist[i])) >- need_refresh[CLUSTER_PARTITIONS]++; >- >- if (idp->cluster == CLUSTER_CPUACCT_GROUPS) >- need_refresh[CLUSTER_STAT]++; >- } >- >- } >- >- linux_refresh(pmda, need_refresh); >- return pmdaFetch(numpmid, pmidlist, resp, pmda); >-} >- >-static int >-procfs_zero(const char *filename, pmValueSet *vsp) >-{ >- FILE *fp; >- int value; >- int sts = 0; >- >- value = vsp->vlist[0].value.lval; >- if (value < 0) >- return PM_ERR_SIGN; >- >- fp = fopen(filename, "w"); >- if (!fp) { >- sts = -oserror(); >- } else { >- fprintf(fp, "%d\n", value); >- fclose(fp); >- } >- return sts; >-} >- >-static int >-linux_store(pmResult *result, pmdaExt *pmda) >-{ >- return PM_ERR_PERMISSION; >-} >- >-static int >-linux_text(int ident, int type, char **buf, pmdaExt *pmda) >-{ >- if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { >- int sts = proc_dynamic_lookup_text(ident, type, buf, pmda); >- if (sts != -ENOENT) >- return sts; >- } >- return pmdaText(ident, type, buf, pmda); >-} >- >-static int >-linux_pmid(const char *name, pmID *pmid, pmdaExt *pmda) >-{ >- __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >- return pmdaTreePMID(tree, name, pmid); >-} >- >-static int >-linux_name(pmID pmid, char ***nameset, pmdaExt *pmda) >-{ >- __pmnsTree *tree = proc_dynamic_lookup_pmid(pmda, pmid); >- return pmdaTreeName(tree, pmid, nameset); >-} >- >-static int >-linux_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) >-{ >- __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >- return pmdaTreeChildren(tree, name, flag, kids, sts); >-} >- >-int >-linux_metrictable_size(void) >-{ >- return sizeof(linux_metrictab)/sizeof(linux_metrictab[0]); >-} >- >-/* >- * Initialise the agent (both daemon and DSO). >- */ >- >-void >-linux_init(pmdaInterface *dp) >-{ >- int i, major, minor; >- __pmID_int *idp; >- >- _pm_system_pagesize = getpagesize(); >- if (_isDSO) { >- char helppath[MAXPATHLEN]; >- int sep = __pmPathSeparator(); >- snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", >- pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >- pmdaDSO(dp, PMDA_INTERFACE_4, "linux DSO", helppath); >- } >- >- if (dp->status != 0) >- return; >- >- dp->version.four.instance = linux_instance; >- dp->version.four.store = linux_store; >- dp->version.four.fetch = linux_fetch; >- dp->version.four.text = linux_text; >- dp->version.four.pmid = linux_pmid; >- dp->version.four.name = linux_name; >- dp->version.four.children = linux_children; >- pmdaSetFetchCallBack(dp, linux_fetchCallBack); >- >- proc_pid.indom = &indomtab[PROC_INDOM]; >- >- /* >- * Read System.map and /proc/ksyms. Used to translate wait channel >- * addresses to symbol names. >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >- read_ksym_sources(kernel_uname.release); >- >- cgroup_init(); >- >- pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), linux_metrictab, >- sizeof(linux_metrictab)/sizeof(linux_metrictab[0])); >-} >- >- >-static void >-usage(void) >-{ >- fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); >- fputs("Options:\n" >- " -d domain use domain (numeric) for metrics domain of PMDA\n" >- " -l logfile write log into logfile rather than using default log name\n", >- stderr); >- exit(1); >-} >- >-/* >- * Set up the agent if running as a daemon. >- */ >- >-int >-main(int argc, char **argv) >-{ >- int sep = __pmPathSeparator(); >- int err = 0; >- int c; >- pmdaInterface dispatch; >- char helppath[MAXPATHLEN]; >- >- _isDSO = 0; >- __pmSetProgname(argv[0]); >- >- snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", >- pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >- pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, LINUX, "linux.log", helppath); >- >- if ((c = pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err)) != EOF) >- err++; >- >- if (err) >- usage(); >- >- pmdaOpenLog(&dispatch); >- linux_init(&dispatch); >- pmdaConnect(&dispatch); >- pmdaMain(&dispatch); >- >- exit(0); >-} >diff --git a/src/pmdas/proc/pmns b/src/pmdas/proc/pmns >deleted file mode 100644 >index d93678b..0000000 >--- a/src/pmdas/proc/pmns >+++ /dev/null >@@ -1,155 +0,0 @@ >-/* >- * Metrics for the Linux proc PMDA >- * >- * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >- * Portions Copyright (c) International Business Machines Corp., 2002 >- * Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. >- * >- * Note: >- * names and pmids migrated from the Linux PMDA, with the domain >- * number changed from LINUX (60) to PROC (3) >- * >- * 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 >- */ >- >-cgroup PROC:*:* >- >-proc { >- nprocs 60:8:99 >- psinfo >- memory >- runq >- id >- io >- schedstat >- fd >-} >- >-proc.psinfo { >- pid PROC:8:0 >- cmd PROC:8:1 >- sname PROC:8:2 >- ppid PROC:8:3 >- pgrp PROC:8:4 >- session PROC:8:5 >- tty PROC:8:6 >- tty_pgrp PROC:8:7 >- flags PROC:8:8 >- minflt PROC:8:9 >- cmin_flt PROC:8:10 >- maj_flt PROC:8:11 >- cmaj_flt PROC:8:12 >- utime PROC:8:13 >- stime PROC:8:14 >- cutime PROC:8:15 >- cstime PROC:8:16 >- priority PROC:8:17 >- nice PROC:8:18 >- /* not valid in 2.2.1 PROC:8:19 */ >- it_real_value PROC:8:20 >- start_time PROC:8:21 >- vsize PROC:8:22 >- rss PROC:8:23 >- rss_rlim PROC:8:24 >- start_code PROC:8:25 >- end_code PROC:8:26 >- start_stack PROC:8:27 >- esp PROC:8:28 >- eip PROC:8:29 >- signal PROC:8:30 >- blocked PROC:8:31 >- sigignore PROC:8:32 >- sigcatch PROC:8:33 >- wchan PROC:8:34 >- nswap PROC:8:35 >- cnswap PROC:8:36 >- exit_signal PROC:8:37 >- processor PROC:8:38 >- ttyname PROC:8:39 >- wchan_s PROC:8:40 >- psargs PROC:8:41 >- signal_s PROC:24:16 >- blocked_s PROC:24:17 >- sigignore_s PROC:24:18 >- sigcatch_s PROC:24:19 >-} >- >-proc.id { >- uid PROC:24:0 >- euid PROC:24:1 >- suid PROC:24:2 >- fsuid PROC:24:3 >- gid PROC:24:4 >- egid PROC:24:5 >- sgid PROC:24:6 >- fsgid PROC:24:7 >- uid_nm PROC:24:8 >- euid_nm PROC:24:9 >- suid_nm PROC:24:10 >- fsuid_nm PROC:24:11 >- gid_nm PROC:24:12 >- egid_nm PROC:24:13 >- sgid_nm PROC:24:14 >- fsgid_nm PROC:24:15 >-} >- >-proc.memory { >- size PROC:9:0 >- rss PROC:9:1 >- share PROC:9:2 >- textrss PROC:9:3 >- librss PROC:9:4 >- datrss PROC:9:5 >- dirty PROC:9:6 >- maps PROC:9:7 >- vmsize PROC:24:20 >- vmlock PROC:24:21 >- vmrss PROC:24:22 >- vmdata PROC:24:23 >- vmstack PROC:24:24 >- vmexe PROC:24:25 >- vmlib PROC:24:26 >-} >- >-proc.runq { >- runnable PROC:13:0 >- blocked PROC:13:1 >- sleeping PROC:13:2 >- stopped PROC:13:3 >- swapped PROC:13:4 >- defunct PROC:13:5 >- unknown PROC:13:6 >- kernel PROC:13:7 >-} >- >-proc.io { >- rchar PROC:32:0 >- wchar PROC:32:1 >- syscr PROC:32:2 >- syscw PROC:32:3 >- read_bytes PROC:32:4 >- write_bytes PROC:32:5 >- cancelled_write_bytes PROC:32:6 >-} >- >-proc.schedstat { >- cpu_time PROC:31:0 >- run_delay PROC:31:1 >- pcount PROC:31:2 >-} >- >-proc.fd { >- count PROC:51:0 >-} >diff --git a/src/pmdas/proc/proc_pid.c b/src/pmdas/proc/proc_pid.c >deleted file mode 100644 >index ea98642..0000000 >--- a/src/pmdas/proc/proc_pid.c >+++ /dev/null >@@ -1,723 +0,0 @@ >-/* >- * Linux proc/<pid>/{stat,statm,status,maps} Clusters >- * >- * Copyright (c) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved. >- * Copyright (c) 2010 Aconex. 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 <ctype.h> >-#include <dirent.h> >-#include <sys/stat.h> >-#include "proc_pid.h" >- >-static proc_pid_list_t allpids; >- >-int >-compare_pid(const void *pa, const void *pb) >-{ >- int a = *(int *)pa; >- int b = *(int *)pb; >- return a - b; >-} >- >-void >-pidlist_append(proc_pid_list_t *list, const char *pidname) >-{ >- if (list->count >= list->size) { >- list->size += 64; >- if (!(list->pids = (int *)realloc(list->pids, list->size * sizeof(int)))) { >- perror("pidlist_append: out of memory"); >- exit(1); /* no recovery from this */ >- } >- } >- list->pids[list->count++] = atoi(pidname); >-} >- >-static int >-refresh_pidlist() >-{ >- DIR *dirp, *taskdirp; >- struct dirent *dp, *tdp; >- char taskpath[1024]; >- >- if ((dirp = opendir("/proc")) == NULL) >- return -oserror(); >- >- allpids.count = 0; >- while ((dp = readdir(dirp)) != NULL) { >- if (isdigit(dp->d_name[0])) { >- pidlist_append(&allpids, dp->d_name); >- /* readdir on /proc ignores threads */ >- sprintf(taskpath, "/proc/%s/task", dp->d_name); >- if ((taskdirp = opendir(taskpath)) != NULL) { >- while ((tdp = readdir(taskdirp)) != NULL) { >- if (!isdigit(tdp->d_name[0]) || strcmp(dp->d_name, tdp->d_name) == 0) >- continue; >- pidlist_append(&allpids, tdp->d_name); >- } >- closedir(taskdirp); >- } >- } >- } >- closedir(dirp); >- >- qsort(allpids.pids, allpids.count, sizeof(int), compare_pid); >- return allpids.count; >-} >- >-int >-refresh_proc_pidlist(proc_pid_t *proc_pid, proc_pid_list_t *pidlist) >-{ >- int i; >- int fd; >- char *p; >- char buf[1024]; >- __pmHashNode *node, *next, *prev; >- proc_pid_entry_t *ep; >- pmdaIndom *indomp = proc_pid->indom; >- >- if (indomp->it_numinst < pidlist->count) >- indomp->it_set = (pmdaInstid *)realloc(indomp->it_set, >- pidlist->count * sizeof(pmdaInstid)); >- indomp->it_numinst = pidlist->count; >- >- /* >- * invalidate all entries so we can harvest pids that have exited >- */ >- for (i=0; i < proc_pid->pidhash.hsize; i++) { >- for (node=proc_pid->pidhash.hash[i]; node != NULL; node = node->next) { >- ep = (proc_pid_entry_t *)node->data; >- ep->valid = 0; >- ep->stat_fetched = 0; >- ep->statm_fetched = 0; >- ep->status_fetched = 0; >- ep->schedstat_fetched = 0; >- ep->maps_fetched = 0; >- ep->io_fetched = 0; >- ep->wchan_fetched = 0; >- ep->fd_fetched = 0; >- } >- } >- >- /* >- * walk pidlist and add new pids to the hash table, >- * marking entries valid as we go ... >- */ >- for (i=0; i < pidlist->count; i++) { >- node = __pmHashSearch(pidlist->pids[i], &proc_pid->pidhash); >- if (node == NULL) { >- int k = 0; >- >- ep = (proc_pid_entry_t *)malloc(sizeof(proc_pid_entry_t)); >- memset(ep, 0, sizeof(proc_pid_entry_t)); >- >- ep->id = pidlist->pids[i]; >- >- sprintf(buf, "/proc/%d/cmdline", pidlist->pids[i]); >- if ((fd = open(buf, O_RDONLY)) >= 0) { >- sprintf(buf, "%06d ", pidlist->pids[i]); >- if ((k = read(fd, buf+7, sizeof(buf)-8)) > 0) { >- p = buf + k +7; >- *p-- = '\0'; >- /* Skip trailing nils, i.e. don't replace them */ >- while (buf+7 < p) { >- if (*p-- != '\0') { >- break; >- } >- } >- /* Remove NULL terminators from cmdline string array */ >- /* Suggested by Mike Mason <mmlnx@us.ibm.com> */ >- while (buf+7 < p) { >- if (*p == '\0') *p = ' '; >- p--; >- } >- } >- close(fd); >- } >- >- if (k == 0) { >- /* >- * If a process is swapped out, /proc/<pid>/cmdline >- * returns an empty string so we have to get it >- * from /proc/<pid>/status or /proc/<pid>/stat >- */ >- sprintf(buf, "/proc/%d/status", pidlist->pids[i]); >- if ((fd = open(buf, O_RDONLY)) >= 0) { >- /* We engage in a bit of a hanky-panky here: >- * the string should look like "123456 (name)", >- * we get it from /proc/XX/status as "Name: name\n...", >- * to fit the 6 digits of PID and opening parenthesis, >- * save 2 bytes at the start of the buffer. >- * And don't forget to leave 2 bytes for the trailing >- * parenthesis and the nil. Here is >- * an example of what we're trying to achieve: >- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ >- * | | | N| a| m| e| :|\t| i| n| i| t|\n| S|... >- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ >- * | 0| 0| 0| 0| 0| 1| | (| i| n| i| t| )|\0|... >- * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ >- if ((k = read(fd, buf+2, sizeof(buf)-4)) > 0) { >- int bc; >- >- if ((p = strchr(buf+2, '\n')) == NULL) >- p = buf+k; >- p[0] = ')'; >- p[1] = '\0'; >- bc = sprintf(buf, "%06d ", pidlist->pids[i]); >- buf[bc] = '('; >- } >- close(fd); >- } >- } >- >- if (k <= 0) { >- /* hmm .. must be exiting */ >- sprintf(buf, "%06d <exiting>", pidlist->pids[i]); >- } >- >- ep->name = strdup(buf); >- >- __pmHashAdd(pidlist->pids[i], (void *)ep, &proc_pid->pidhash); >- // fprintf(stderr, "## ADDED \"%s\" to hash table\n", buf); >- } >- else >- ep = (proc_pid_entry_t *)node->data; >- >- /* mark pid as still existing */ >- ep->valid = 1; >- >- /* refresh the indom pointer */ >- indomp->it_set[i].i_inst = ep->id; >- indomp->it_set[i].i_name = ep->name; >- } >- >- /* >- * harvest exited pids from the pid hash table >- */ >- for (i=0; i < proc_pid->pidhash.hsize; i++) { >- for (prev=NULL, node=proc_pid->pidhash.hash[i]; node != NULL;) { >- next = node->next; >- ep = (proc_pid_entry_t *)node->data; >- // fprintf(stderr, "CHECKING key=%d node=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p ep=" PRINTF_P_PFX "%p valid=%d\n", >- // ep->id, node, prev, node->next, ep, ep->valid); >- if (ep->valid == 0) { >- // fprintf(stderr, "DELETED key=%d name=\"%s\"\n", ep->id, ep->name); >- if (ep->name != NULL) >- free(ep->name); >- if (ep->stat_buf != NULL) >- free(ep->stat_buf); >- if (ep->status_buf != NULL) >- free(ep->status_buf); >- if (ep->statm_buf != NULL) >- free(ep->statm_buf); >- if (ep->maps_buf != NULL) >- free(ep->maps_buf); >- if (ep->schedstat_buf != NULL) >- free(ep->schedstat_buf); >- if (ep->io_buf != NULL) >- free(ep->io_buf); >- if (ep->wchan_buf != NULL) >- free(ep->wchan_buf); >- >- if (prev == NULL) >- proc_pid->pidhash.hash[i] = node->next; >- else >- prev->next = node->next; >- free(ep); >- free(node); >- } >- else { >- prev = node; >- } >- if ((node = next) == NULL) >- break; >- } >- } >- >- return pidlist->count; >-} >- >-int >-refresh_proc_pid(proc_pid_t *proc_pid) >-{ >- if (refresh_pidlist() <= 0) >- return -oserror(); >- >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_LIBPMDA) >- fprintf(stderr, "refresh_proc_pid: found %d pids\n", allpids.count); >-#endif >- >- return refresh_proc_pidlist(proc_pid, &allpids); >-} >- >- >-/* >- * fetch a proc/<pid>/stat entry for pid >- */ >-proc_pid_entry_t * >-fetch_proc_pid_stat(int id, proc_pid_t *proc_pid) >-{ >- int fd; >- int sts = 0; >- int n; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- char buf[1024]; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->stat_fetched == 0) { >- sprintf(buf, "/proc/%d/stat", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else >- if ((n = read(fd, buf, sizeof(buf))) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- /* eh? */ >- sts = -1; >- else { >- if (ep->stat_buflen <= n) { >- ep->stat_buflen = n; >- ep->stat_buf = (char *)realloc(ep->stat_buf, n); >- } >- memcpy(ep->stat_buf, buf, n); >- ep->stat_buf[n-1] = '\0'; >- sts = 0; >- } >- } >- if (fd >= 0) >- close(fd); >- ep->stat_fetched = 1; >- } >- >- if (ep->wchan_fetched == 0) { >- sprintf(buf, "/proc/%d/wchan", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = 0; /* ignore failure here, backwards compat */ >- else >- if ((n = read(fd, buf, sizeof(buf)-1)) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- /* eh? */ >- sts = -1; >- else { >- n++; /* no terminating null (from kernel) */ >- if (ep->wchan_buflen <= n) { >- ep->wchan_buflen = n; >- ep->wchan_buf = (char *)realloc(ep->wchan_buf, n); >- } >- memcpy(ep->wchan_buf, buf, n); >- ep->wchan_buf[n-1] = '\0'; >- sts = 0; >- } >- } >- if (fd >= 0) >- close(fd); >- ep->wchan_fetched = 1; >- } >- >- if (sts < 0) >- return NULL; >- return ep; >-} >- >-/* >- * fetch a proc/<pid>/status entry for pid >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >-proc_pid_entry_t * >-fetch_proc_pid_status(int id, proc_pid_t *proc_pid) >-{ >- int sts = 0; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->status_fetched == 0) { >- int fd; >- int n; >- char buf[1024]; >- char *curline; >- >- sprintf(buf, "/proc/%d/status", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else if ((n = read(fd, buf, sizeof(buf))) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- sts = -1; >- else { >- if (ep->status_buflen < n) { >- ep->status_buflen = n; >- ep->status_buf = (char *)realloc(ep->status_buf, n); >- } >- >- if (ep->status_buf == NULL) >- sts = -1; >- else { >- memcpy(ep->status_buf, buf, n); >- ep->status_buf[n-1] = '\0'; >- } >- } >- } >- >- if (sts == 0) { >- /* assign pointers to individual lines in buffer */ >- curline = ep->status_buf; >- >- while (strncmp(curline, "Uid:", 4)) { >- curline = index(curline, '\n') + 1; >- } >- >- /* user & group IDs */ >- ep->status_lines.uid = strsep(&curline, "\n"); >- ep->status_lines.gid = strsep(&curline, "\n"); >- >- while (curline) { >- if (strncmp(curline, "VmSize:", 7) == 0) { >- /* memory info - these lines don't exist for kernel threads */ >- ep->status_lines.vmsize = strsep(&curline, "\n"); >- ep->status_lines.vmlck = strsep(&curline, "\n"); >- ep->status_lines.vmrss = strsep(&curline, "\n"); >- ep->status_lines.vmdata = strsep(&curline, "\n"); >- ep->status_lines.vmstk = strsep(&curline, "\n"); >- ep->status_lines.vmexe = strsep(&curline, "\n"); >- ep->status_lines.vmlib = strsep(&curline, "\n"); >- } else >- if (strncmp(curline, "SigPnd:", 7) == 0) { >- /* signal masks */ >- ep->status_lines.sigpnd = strsep(&curline, "\n"); >- ep->status_lines.sigblk = strsep(&curline, "\n"); >- ep->status_lines.sigign = strsep(&curline, "\n"); >- ep->status_lines.sigcgt = strsep(&curline, "\n"); >- break; /* we're done */ >- } else { >- curline = index(curline, '\n') + 1; >- } >- } >- >- } >- if (fd >= 0) >- close(fd); >- } >- >- ep->status_fetched = 1; >- >- return (sts < 0) ? NULL : ep; >-} >- >-/* >- * fetch a proc/<pid>/statm entry for pid >- */ >-proc_pid_entry_t * >-fetch_proc_pid_statm(int id, proc_pid_t *proc_pid) >-{ >- int fd; >- int sts = 0; >- int n; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- char buf[1024]; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->statm_fetched == 0) { >- sprintf(buf, "/proc/%d/statm", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else >- if ((n = read(fd, buf, sizeof(buf))) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- /* eh? */ >- sts = -1; >- else { >- if (ep->statm_buflen <= n) { >- ep->statm_buflen = n; >- ep->statm_buf = (char *)realloc(ep->statm_buf, n); >- } >- memcpy(ep->statm_buf, buf, n); >- ep->statm_buf[n-1] = '\0'; >- } >- } >- >- if (fd >= 0) >- close(fd); >- ep->statm_fetched = 1; >- } >- >- if (sts < 0) >- return NULL; >- return ep; >-} >- >- >-/* >- * fetch a proc/<pid>/maps entry for pid >- * WARNING: This can be very large! Only ask for it if you really need it. >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >-proc_pid_entry_t * >-fetch_proc_pid_maps(int id, proc_pid_t *proc_pid) >-{ >- int fd; >- int sts = 0; >- int n; >- int len = 0; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- char buf[1024]; >- char *maps_bufptr = NULL; >- >- if (node == NULL) >- return NULL; >- >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->maps_fetched == 0) { >- sprintf(buf, "/proc/%d/maps", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else { >- while ((n = read(fd, buf, sizeof(buf))) > 0) { >- len += n; >- if (ep->maps_buflen <= len) { >- ep->maps_buflen = len + 1; >- ep->maps_buf = (char *)realloc(ep->maps_buf, ep->maps_buflen); >- } >- maps_bufptr = ep->maps_buf + len - n; >- memcpy(maps_bufptr, buf, n); >- } >- ep->maps_fetched = 1; >- /* If there are no maps, make maps_buf point to a zero length string. */ >- if (ep->maps_buflen == 0) { >- ep->maps_buf = (char *)malloc(1); >- ep->maps_buflen = 1; >- } >- ep->maps_buf[ep->maps_buflen - 1] = '\0'; >- close(fd); >- } >- } >- >- if (sts < 0) >- return NULL; >- return ep; >-} >- >-/* >- * fetch a proc/<pid>/schedstat entry for pid >- */ >-proc_pid_entry_t * >-fetch_proc_pid_schedstat(int id, proc_pid_t *proc_pid) >-{ >- int fd; >- int sts = 0; >- int n; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- char buf[1024]; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->schedstat_fetched == 0) { >- sprintf(buf, "/proc/%d/schedstat", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else >- if ((n = read(fd, buf, sizeof(buf))) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- /* eh? */ >- sts = -1; >- else { >- if (ep->schedstat_buflen <= n) { >- ep->schedstat_buflen = n; >- ep->schedstat_buf = (char *)realloc(ep->schedstat_buf, n); >- } >- memcpy(ep->schedstat_buf, buf, n); >- ep->schedstat_buf[n-1] = '\0'; >- } >- } >- if (fd >= 0) { >- close(fd); >- ep->schedstat_fetched = 1; >- } >- } >- >- if (sts < 0) >- return NULL; >- return ep; >-} >- >-/* >- * fetch a proc/<pid>/io entry for pid >- * >- * Depends on kernel built with CONFIG_TASK_IO_ACCOUNTING=y >- * which means the following must also be set: >- * CONFIG_TASKSTATS=y >- * CONFIG_TASK_DELAY_ACCT=y >- * CONFIG_TASK_XACCT=y >- */ >-proc_pid_entry_t * >-fetch_proc_pid_io(int id, proc_pid_t *proc_pid) >-{ >- int sts = 0; >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->io_fetched == 0) { >- int fd; >- int n; >- char buf[1024]; >- char *curline; >- >- sprintf(buf, "/proc/%d/io", ep->id); >- if ((fd = open(buf, O_RDONLY)) < 0) >- sts = -oserror(); >- else if ((n = read(fd, buf, sizeof(buf))) < 0) >- sts = -oserror(); >- else { >- if (n == 0) >- sts = -1; >- else { >- if (ep->io_buflen < n) { >- ep->io_buflen = n; >- ep->io_buf = (char *)realloc(ep->io_buf, n); >- } >- >- if (ep->io_buf == NULL) >- sts = -1; >- else { >- memcpy(ep->io_buf, buf, n); >- ep->io_buf[n-1] = '\0'; >- } >- } >- } >- >- if (sts == 0) { >- /* assign pointers to individual lines in buffer */ >- curline = ep->io_buf; >- ep->io_lines.rchar = strsep(&curline, "\n"); >- ep->io_lines.wchar = strsep(&curline, "\n"); >- ep->io_lines.syscr = strsep(&curline, "\n"); >- ep->io_lines.syscw = strsep(&curline, "\n"); >- ep->io_lines.readb = strsep(&curline, "\n"); >- ep->io_lines.writeb = strsep(&curline, "\n"); >- ep->io_lines.cancel = strsep(&curline, "\n"); >- ep->io_fetched = 1; >- } >- if (fd >= 0) >- close(fd); >- } >- >- return (sts < 0) ? NULL : ep; >-} >- >-/* >- * fetch a proc/<pid>/fd entry for pid >- */ >-proc_pid_entry_t * >-fetch_proc_pid_fd(int id, proc_pid_t *proc_pid) >-{ >- __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); >- proc_pid_entry_t *ep; >- >- if (node == NULL) >- return NULL; >- ep = (proc_pid_entry_t *)node->data; >- >- if (ep->fd_fetched == 0) { >- char buf[PATH_MAX]; >- uint32_t de_count = 0; >- DIR *dir; >- >- sprintf(buf, "/proc/%d/fd", ep->id); >- dir = opendir(buf); >- if (dir == NULL) { >- __pmNotifyErr(LOG_ERR, "failed to open pid fd path %s\n", >- buf); >- return NULL; >- } >- while (readdir(dir) != NULL) { >- de_count++; >- } >- closedir(dir); >- ep->fd_count = de_count - 2; /* subtract cwd and parent entries */ >- } >- ep->fd_fetched = 1; >- >- return ep; >-} >- >-/* >- * Extract the ith (space separated) field from a char buffer. >- * The first field starts at zero. >- * BEWARE: return copy is in a static buffer. >- */ >-char * >-_pm_getfield(char *buf, int field) >-{ >- static int retbuflen = 0; >- static char *retbuf = NULL; >- char *p; >- int i; >- >- if (buf == NULL) >- return NULL; >- >- for (p=buf, i=0; i < field; i++) { >- /* skip to the next space */ >- for (; *p && !isspace(*p); p++) {;} >- >- /* skip to the next word */ >- for (; *p && isspace(*p); p++) {;} >- } >- >- /* return a null terminated copy of the field */ >- for (i=0; ; i++) { >- if (isspace(p[i]) || p[i] == '\0' || p[i] == '\n') >- break; >- } >- >- if (i >= retbuflen) { >- retbuflen = i+4; >- retbuf = (char *)realloc(retbuf, retbuflen); >- } >- memcpy(retbuf, p, i); >- retbuf[i] = '\0'; >- >- return retbuf; >-} >diff --git a/src/pmdas/proc/proc_pid.h b/src/pmdas/proc/proc_pid.h >deleted file mode 100644 >index 53ff1a3..0000000 >--- a/src/pmdas/proc/proc_pid.h >+++ /dev/null >@@ -1,269 +0,0 @@ >-/* >- * Linux /proc/<pid>/{stat,statm} Clusters >- * >- * Copyright (c) 2000,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 >- */ >- >-#ifndef _PROC_PID_H >-#define _PROC_PID_H >- >-/* >- * /proc/<pid>/stat metrics >- */ >-#define PROC_PID_STAT_PID 0 >-#define PROC_PID_STAT_CMD 1 >-#define PROC_PID_STAT_STATE 2 >-#define PROC_PID_STAT_PPID 3 >-#define PROC_PID_STAT_PGRP 4 >-#define PROC_PID_STAT_SESSION 5 >-#define PROC_PID_STAT_TTY 6 >-#define PROC_PID_STAT_TTY_PGRP 7 >-#define PROC_PID_STAT_FLAGS 8 >-#define PROC_PID_STAT_MINFLT 9 >-#define PROC_PID_STAT_CMIN_FLT 10 >-#define PROC_PID_STAT_MAJ_FLT 11 >-#define PROC_PID_STAT_CMAJ_FLT 12 >-#define PROC_PID_STAT_UTIME 13 >-#define PROC_PID_STAT_STIME 14 >-#define PROC_PID_STAT_CUTIME 15 >-#define PROC_PID_STAT_CSTIME 16 >-#define PROC_PID_STAT_PRIORITY 17 >-#define PROC_PID_STAT_NICE 18 >-#define PROC_PID_STAT_REMOVED 19 >-#define PROC_PID_STAT_IT_REAL_VALUE 20 >-#define PROC_PID_STAT_START_TIME 21 >-#define PROC_PID_STAT_VSIZE 22 >-#define PROC_PID_STAT_RSS 23 >-#define PROC_PID_STAT_RSS_RLIM 24 >-#define PROC_PID_STAT_START_CODE 25 >-#define PROC_PID_STAT_END_CODE 26 >-#define PROC_PID_STAT_START_STACK 27 >-#define PROC_PID_STAT_ESP 28 >-#define PROC_PID_STAT_EIP 29 >-#define PROC_PID_STAT_SIGNAL 30 >-#define PROC_PID_STAT_BLOCKED 31 >-#define PROC_PID_STAT_SIGIGNORE 32 >-#define PROC_PID_STAT_SIGCATCH 33 >-#define PROC_PID_STAT_WCHAN 34 >-#define PROC_PID_STAT_NSWAP 35 >-#define PROC_PID_STAT_CNSWAP 36 >-#define PROC_PID_STAT_EXIT_SIGNAL 37 >-#define PROC_PID_STAT_PROCESSOR 38 >-#define PROC_PID_STAT_TTYNAME 39 >-#define PROC_PID_STAT_WCHAN_SYMBOL 40 >-#define PROC_PID_STAT_PSARGS 41 >- >-/* number of fields in proc_pid_stat_entry_t */ >-#define NR_PROC_PID_STAT 42 >- >-/* >- * metrics in /proc/<pid>/status >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >-#define PROC_PID_STATUS_UID 0 >-#define PROC_PID_STATUS_EUID 1 >-#define PROC_PID_STATUS_SUID 2 >-#define PROC_PID_STATUS_FSUID 3 >-#define PROC_PID_STATUS_GID 4 >-#define PROC_PID_STATUS_EGID 5 >-#define PROC_PID_STATUS_SGID 6 >-#define PROC_PID_STATUS_FSGID 7 >-#define PROC_PID_STATUS_UID_NM 8 >-#define PROC_PID_STATUS_EUID_NM 9 >-#define PROC_PID_STATUS_SUID_NM 10 >-#define PROC_PID_STATUS_FSUID_NM 11 >-#define PROC_PID_STATUS_GID_NM 12 >-#define PROC_PID_STATUS_EGID_NM 13 >-#define PROC_PID_STATUS_SGID_NM 14 >-#define PROC_PID_STATUS_FSGID_NM 15 >-#define PROC_PID_STATUS_SIGNAL 16 >-#define PROC_PID_STATUS_BLOCKED 17 >-#define PROC_PID_STATUS_SIGIGNORE 18 >-#define PROC_PID_STATUS_SIGCATCH 19 >-#define PROC_PID_STATUS_VMSIZE 20 >-#define PROC_PID_STATUS_VMLOCK 21 >-#define PROC_PID_STATUS_VMRSS 22 >-#define PROC_PID_STATUS_VMDATA 23 >-#define PROC_PID_STATUS_VMSTACK 24 >-#define PROC_PID_STATUS_VMEXE 25 >-#define PROC_PID_STATUS_VMLIB 26 >- >-/* number of metrics from /proc/<pid>/status */ >-#define NR_PROC_PID_STATUS 27 >- >-/* >- * metrics in /proc/<pid>/statm & /proc/<pid>/maps >- */ >-#define PROC_PID_STATM_SIZE 0 >-#define PROC_PID_STATM_RSS 1 >-#define PROC_PID_STATM_SHARE 2 >-#define PROC_PID_STATM_TEXTRS 3 >-#define PROC_PID_STATM_LIBRS 4 >-#define PROC_PID_STATM_DATRS 5 >-#define PROC_PID_STATM_DIRTY 6 >-#define PROC_PID_STATM_MAPS 7 >- >-/* number of fields in proc_pid_statm_entry_t */ >-#define NR_PROC_PID_STATM 8 >- >-/* >- * metrics in /proc/<pid>/schedstat >- */ >-#define PROC_PID_SCHED_CPUTIME 0 >-#define PROC_PID_SCHED_RUNDELAY 1 >-#define PROC_PID_SCHED_PCOUNT 2 >-#define NR_PROC_PID_SCHED 3 >- >-/* >- * metrics in /proc/<pid>/io >- */ >-#define PROC_PID_IO_RCHAR 0 >-#define PROC_PID_IO_WCHAR 1 >-#define PROC_PID_IO_SYSCR 2 >-#define PROC_PID_IO_SYSCW 3 >-#define PROC_PID_IO_READ_BYTES 4 >-#define PROC_PID_IO_WRITE_BYTES 5 >-#define PROC_PID_IO_CANCELLED_BYTES 6 >- >-/* >- * metrics in /proc/<pid>/fd >- */ >-#define PROC_PID_FD_COUNT 0 >- >-typedef struct { /* /proc/<pid>/status */ >- char *uid; >- char *gid; >- char *sigpnd; >- char *sigblk; >- char *sigign; >- char *sigcgt; >- char *vmsize; >- char *vmlck; >- char *vmrss; >- char *vmdata; >- char *vmstk; >- char *vmexe; >- char *vmlib; >-} status_lines_t; >- >-typedef struct { /* /proc/<pid>/io */ >- char *rchar; >- char *wchar; >- char *syscr; >- char *syscw; >- char *readb; >- char *writeb; >- char *cancel; >-} io_lines_t; >- >-typedef struct { >- int id; /* pid, hash key and internal instance id */ >- int valid; /* flag (zero if process has exited) */ >- char *name; /* external instance name (<pid> cmdline) */ >- >- /* /proc/<pid>/stat cluster */ >- int stat_fetched; >- int stat_buflen; >- char *stat_buf; >- >- /* /proc/<pid>/statm and /proc/<pid>/maps cluster */ >- int statm_fetched; >- int statm_buflen; >- char *statm_buf; >- int maps_fetched; >- int maps_buflen; >- char *maps_buf; >- >- /* /proc/<pid>/status cluster */ >- int status_fetched; >- int status_buflen; >- char *status_buf; >- status_lines_t status_lines; >- >- /* /proc/<pid>/schedstat cluster */ >- int schedstat_fetched; >- int schedstat_buflen; >- char *schedstat_buf; >- >- /* /proc/<pid>/io cluster */ >- int io_fetched; >- int io_buflen; >- char *io_buf; >- io_lines_t io_lines; >- >- /* /proc/<pid>/wchan cluster */ >- int wchan_fetched; >- int wchan_buflen; >- char *wchan_buf; >- >- /* /proc/<pid>/fd cluster */ >- int fd_fetched; >- int fd_buflen; >- char *fd_buf; >- uint32_t fd_count; >-} proc_pid_entry_t; >- >-typedef struct { >- __pmHashCtl pidhash; /* hash table for current pids */ >- pmdaIndom *indom; /* instance domain table */ >-} proc_pid_t; >- >-typedef struct { >- int count; /* number of processes in the list */ >- int size; /* size of the buffer (pids) allocated */ >- int *pids; /* array of process identifiers */ >-} proc_pid_list_t; >- >-/* refresh the proc indom, reset all "fetched" flags */ >-extern int refresh_proc_pid(proc_pid_t *); >- >-/* add a process onto a process list */ >-extern void pidlist_append(proc_pid_list_t *, const char *); >- >-/* comparator routine for sorting a process list */ >-extern int compare_pid(const void *, const void *); >- >-/* refresh a proc indom (subset), reset all "fetched" flags */ >-extern int refresh_proc_pidlist(proc_pid_t *proc_pid, proc_pid_list_t *); >- >-/* fetch a proc/<pid>/stat entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_stat(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/statm entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_statm(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/status entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_status(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/maps entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_maps(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/schedstat entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_schedstat(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/io entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_io(int, proc_pid_t *); >- >-/* fetch a proc/<pid>/fd entry for pid */ >-extern proc_pid_entry_t *fetch_proc_pid_fd(int, proc_pid_t *); >- >-extern int _pm_pid_io_fields; /* count of fields in proc/<pid>/io */ >- >-/* extract the ith space separated field from a buffer */ >-extern char *_pm_getfield(char *, int); >- >-#endif /* _PROC_PID_H */ >diff --git a/src/pmdas/proc/proc_runq.c b/src/pmdas/proc/proc_runq.c >deleted file mode 100644 >index c5d5930..0000000 >--- a/src/pmdas/proc/proc_runq.c >+++ /dev/null >@@ -1,123 +0,0 @@ >-/* >- * Linux /proc/runq metrics cluster >- * >- * Copyright (c) 2000,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 <ctype.h> >-#include <dirent.h> >-#include <sys/stat.h> >-#include "proc_pid.h" >-#include "proc_runq.h" >- >-int >-refresh_proc_runq(proc_runq_t *proc_runq) >-{ >- int sz; >- int fd; >- char *p; >- int sname; >- DIR *dir; >- struct dirent *d; >- char fullpath[MAXPATHLEN]; >- char buf[4096]; >- >- memset(proc_runq, 0, sizeof(proc_runq_t)); >- if ((dir = opendir("/proc")) == NULL) >- return -oserror(); >- >- while((d = readdir(dir)) != NULL) { >- if (!isdigit(d->d_name[0])) >- continue; >- sprintf(fullpath, "/proc/%s/stat", d->d_name); >- if ((fd = open(fullpath, O_RDONLY)) < 0) >- continue; >- sz = read(fd, buf, sizeof(buf)); >- close(fd); >- buf[sizeof(buf)-1] = '\0'; >- >- /* >- * defunct (state name is 'Z') >- */ >- if (sz <= 0 || (p = _pm_getfield(buf, PROC_PID_STAT_STATE)) == NULL) { >- proc_runq->unknown++; >- continue; >- } >- if ((sname = *p) == 'Z') { >- proc_runq->defunct++; >- continue; >- } >- >- /* >- * kernel process (not defunct and virtual size is zero) >- */ >- if ((p = _pm_getfield(buf, PROC_PID_STAT_VSIZE)) == NULL) { >- proc_runq->unknown++; >- continue; >- } >- if (strcmp(p, "0") == 0) { >- proc_runq->kernel++; >- continue; >- } >- >- /* >- * swapped (resident set size is zero) >- */ >- if ((p = _pm_getfield(buf, PROC_PID_STAT_RSS)) == NULL) { >- proc_runq->unknown++; >- continue; >- } >- if (strcmp(p, "0") == 0) { >- proc_runq->swapped++; >- continue; >- } >- >- /* >- * All other states >- */ >- switch (sname) { >- case 'R': >- proc_runq->runnable++; >- break; >- case 'S': >- proc_runq->sleeping++; >- break; >- case 'T': >- proc_runq->stopped++; >- break; >- case 'D': >- proc_runq->blocked++; >- break; >- case 'Z': >- break; /* already counted above */ >- default: >- fprintf(stderr, "UNKNOWN %c : %s\n", sname, buf); >- proc_runq->unknown++; >- break; >- } >- } >- closedir(dir); >- >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_LIBPMDA) { >- fprintf(stderr, "refresh_runq: runnable=%d sleeping=%d stopped=%d blocked=%d unknown=%d\n", >- proc_runq->runnable, proc_runq->sleeping, proc_runq->stopped, >- proc_runq->blocked, proc_runq->unknown); >- } >-#endif >- >- return 0; >-} >diff --git a/src/pmdas/proc/proc_runq.h b/src/pmdas/proc/proc_runq.h >deleted file mode 100644 >index 9739208..0000000 >--- a/src/pmdas/proc/proc_runq.h >+++ /dev/null >@@ -1,35 +0,0 @@ >-/* >- * Copyright (c) 2000,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 >- */ >- >-#ifndef _PROC_RUNQ_H >-#define _PROC_RUNQ_H >- >-typedef struct { >- int runnable; >- int blocked; >- int sleeping; >- int stopped; >- int swapped; >- int kernel; >- int defunct; >- int unknown; >-} proc_runq_t; >- >-extern int refresh_proc_runq(proc_runq_t *); >- >-#endif /* _PROC_RUNQ_H */ >diff --git a/src/pmdas/proc/root b/src/pmdas/proc/root >deleted file mode 100644 >index 834246f..0000000 >--- a/src/pmdas/proc/root >+++ /dev/null >@@ -1,10 +0,0 @@ >-/* >- * fake "root" for validating the local PMNS subtree >- */ >- >-#include <stdpmid> >- >-root { proc } >- >-#include "pmns" >- > >commit 8ff4984fee93bab09ea5c68b7ee18d1ab715bea1 >Author: Ken McDonell <kenj@internode.on.net> >Date: Sun Jul 22 19:52:34 2012 +1000 > > linux PMDA - remove all proc metrics > > All the proc metrics have been moved to the proc PMDA. > >diff --git a/src/pmdas/linux/GNUmakefile b/src/pmdas/linux/GNUmakefile >index 43c4f2d..0ff1ec6 100644 >--- a/src/pmdas/linux/GNUmakefile >+++ b/src/pmdas/linux/GNUmakefile >@@ -30,7 +30,7 @@ CFILES = pmda.c proc_stat.c proc_meminfo.c proc_loadavg.c \ > proc_net_snmp.c proc_scsi.c proc_fs_xfs.c \ > proc_cpuinfo.c proc_net_tcp.c \ > proc_slabinfo.c sem_limits.c msg_limits.c shm_limits.c \ >- proc_uptime.c ksym.c proc_sys_fs.c proc_vmstat.c \ >+ proc_uptime.c proc_sys_fs.c proc_vmstat.c \ > sysfs_kernel.c linux_table.c numa_meminfo.c \ > dynamic.c > >@@ -41,7 +41,7 @@ HFILES = proc_stat.h proc_meminfo.h proc_loadavg.h \ > proc_scsi.h proc_fs_xfs.h \ > proc_cpuinfo.h proc_net_tcp.h proc_slabinfo.h \ > sem_limits.h msg_limits.h shm_limits.h proc_uptime.h \ >- ksym.h proc_sys_fs.h proc_vmstat.h clusters.h indom.h \ >+ proc_sys_fs.h proc_vmstat.h clusters.h indom.h \ > convert.h sysfs_kernel.h linux_table.h numa_meminfo.h \ > dynamic.h > >@@ -83,3 +83,35 @@ install_pcp : install > > domain.h: ../../pmns/stdpmid > $(DOMAIN_MAKERULE) >+ >+dynamic.o interrupts.o pmda.o proc_partitions.o: clusters.h >+pmda.o proc_partitions.o: convert.h >+pmda.o: domain.h >+dynamic.o interrupts.o pmda.o: dynamic.h >+filesys.o interrupts.o pmda.o: filesys.h >+pmda.o: getinfo.h >+dynamic.o numa_meminfo.o pmda.o proc_cpuinfo.o proc_partitions.o proc_stat.o: indom.h >+interrupts.o pmda.o: interrupts.h >+linux_table.o numa_meminfo.o pmda.o: linux_table.h >+msg_limits.o pmda.o: msg_limits.h >+numa_meminfo.o pmda.o: numa_meminfo.h >+pmda.o proc_cpuinfo.o proc_stat.o: proc_cpuinfo.h >+pmda.o proc_fs_xfs.o: proc_fs_xfs.h >+pmda.o proc_loadavg.o: proc_loadavg.h >+pmda.o proc_meminfo.o: proc_meminfo.h >+pmda.o proc_net_dev.o: proc_net_dev.h >+pmda.o proc_net_rpc.o: proc_net_rpc.h >+pmda.o proc_net_snmp.o: proc_net_snmp.h >+pmda.o proc_net_sockstat.o: proc_net_sockstat.h >+pmda.o proc_net_tcp.o: proc_net_tcp.h >+pmda.o proc_partitions.o: proc_partitions.h >+pmda.o proc_scsi.o: proc_scsi.h >+pmda.o proc_slabinfo.o: proc_slabinfo.h >+pmda.o proc_stat.o: proc_stat.h >+pmda.o proc_sys_fs.o: proc_sys_fs.h >+pmda.o proc_uptime.o: proc_uptime.h >+pmda.o proc_vmstat.o: proc_vmstat.h >+pmda.o sem_limits.o: sem_limits.h >+pmda.o shm_limits.o: shm_limits.h >+pmda.o swapdev.o: swapdev.h >+pmda.o sysfs_kernel.o: sysfs_kernel.h >diff --git a/src/pmdas/linux/clusters.h b/src/pmdas/linux/clusters.h >index be845bf..d259f58 100644 >--- a/src/pmdas/linux/clusters.h >+++ b/src/pmdas/linux/clusters.h >@@ -27,12 +27,12 @@ enum { > CLUSTER_FILESYS, /* 5 /proc/mounts + statfs */ > CLUSTER_SWAPDEV, /* 6 /proc/swaps */ > CLUSTER_NET_NFS, /* 7 /proc/net/rpc/nfs + /proc/net/rpc/nfsd */ >- CLUSTER_PID_STAT, /* 8 /proc/<pid>/stat */ >- CLUSTER_PID_STATM, /* 9 /proc/<pid>/statm + /proc/<pid>/maps */ >+ PROC_PID_STAT, /* 8 /proc/<pid>/stat -> proc PMDA */ >+ PROC_PID_STATM, /* 9 /proc/<pid>/statm + /proc/<pid>/maps -> proc PMDA */ > CLUSTER_PARTITIONS, /* 10 /proc/partitions */ > CLUSTER_NET_SOCKSTAT, /* 11 /proc/net/sockstat */ > CLUSTER_KERNEL_UNAME, /* 12 uname() system call */ >- CLUSTER_PROC_RUNQ, /* 13 number of processes in various states */ >+ PROC_PROC_RUNQ, /* 13 number of processes in various states -> proc PMDA */ > CLUSTER_NET_SNMP, /* 14 /proc/net/snmp */ > CLUSTER_SCSI, /* 15 /proc/scsi/scsi */ > CLUSTER_XFS, /* 16 /proc/fs/xfs/stat */ >@@ -43,34 +43,34 @@ enum { > CLUSTER_SEM_LIMITS, /* 21 semctl(IPC_INFO) system call */ > CLUSTER_MSG_LIMITS, /* 22 msgctl(IPC_INFO) system call */ > CLUSTER_SHM_LIMITS, /* 23 shmctl(IPC_INFO) system call */ >- CLUSTER_PID_STATUS, /* 24 /proc/<pid>/status */ >+ PROC_PID_STATUS, /* 24 /proc/<pid>/status -> proc PMDA */ > CLUSTER_NUSERS, /* 25 number of users */ > CLUSTER_UPTIME, /* 26 /proc/uptime */ > CLUSTER_VFS, /* 27 /proc/sys/fs */ > CLUSTER_VMSTAT, /* 28 /proc/vmstat */ > CLUSTER_IB, /* deprecated: do not re-use 29 infiniband */ > CLUSTER_QUOTA, /* 30 quotactl() */ >- CLUSTER_PID_SCHEDSTAT, /* 31 /proc/<pid>/schedstat */ >- CLUSTER_PID_IO, /* 32 /proc/<pid>/io */ >+ PROC_PID_SCHEDSTAT, /* 31 /proc/<pid>/schedstat -> proc PMDA */ >+ PROC_PID_IO, /* 32 /proc/<pid>/io -> proc PMDA */ > CLUSTER_NET_INET, /* 33 /proc/net/dev and ioctl(SIOCGIFCONF) */ > CLUSTER_TMPFS, /* 34 /proc/mounts + statfs (tmpfs only) */ > CLUSTER_SYSFS_KERNEL, /* 35 /sys/kernel metrics */ > CLUSTER_NUMA_MEMINFO, /* 36 /sys/devices/system/node* NUMA memory */ >- CLUSTER_CGROUP_SUBSYS, /* 37 /proc/cgroups control group subsystems */ >- CLUSTER_CGROUP_MOUNTS, /* 38 /proc/mounts active control groups */ >- CLUSTER_CPUSET_GROUPS, /* 39 cpuset control groups */ >- CLUSTER_CPUSET_PROCS, /* 40 cpuset control group processes */ >- CLUSTER_CPUACCT_GROUPS, /* 41 cpu accounting control groups */ >- CLUSTER_CPUACCT_PROCS, /* 42 cpu accounting group processes */ >- CLUSTER_CPUSCHED_GROUPS,/* 43 scheduler control groups */ >- CLUSTER_CPUSCHED_PROCS, /* 44 scheduler group processes */ >- CLUSTER_MEMORY_GROUPS, /* 45 memory control groups */ >- CLUSTER_MEMORY_PROCS, /* 46 memory group processes */ >- CLUSTER_NET_CLS_GROUPS, /* 47 network classification control groups */ >- CLUSTER_NET_CLS_PROCS, /* 48 network classification group processes */ >+ PROC_CGROUP_SUBSYS, /* 37 /proc/cgroups control group subsystems -> proc PMDA */ >+ PROC_CGROUP_MOUNTS, /* 38 /proc/mounts active control groups -> proc PMDA */ >+ PROC_CPUSET_GROUPS, /* 39 cpuset control groups -> proc PMDA */ >+ PROC_CPUSET_PROCS, /* 40 cpuset control group processes -> proc PMDA */ >+ PROC_CPUACCT_GROUPS, /* 41 cpu accounting control groups -> proc PMDA */ >+ PROC_CPUACCT_PROCS, /* 42 cpu accounting group processes -> proc PMDA */ >+ PROC_CPUSCHED_GROUPS, /* 43 scheduler control groups -> proc PMDA */ >+ PROC_CPUSCHED_PROCS, /* 44 scheduler group processes -> proc PMDA */ >+ PROC_MEMORY_GROUPS, /* 45 memory control groups -> proc PMDA */ >+ PROC_MEMORY_PROCS, /* 46 memory group processes -> proc PMDA */ >+ PROC_NET_CLS_GROUPS, /* 47 network classification control groups -> proc PMDA */ >+ PROC_NET_CLS_PROCS, /* 48 network classification group processes -> proc PMDA */ > CLUSTER_INTERRUPT_LINES,/* 49 /proc/interrupts percpu interrupts */ > CLUSTER_INTERRUPT_OTHER,/* 50 /proc/interrupts percpu interrupts */ >- CLUSTER_PID_FD, /* 51 /proc/<pid>/fd */ >+ PROC_PID_FD, /* 51 /proc/<pid>/fd -> proc PMDA */ > > NUM_CLUSTERS /* one more than highest numbered cluster */ > }; >diff --git a/src/pmdas/linux/filesys.c b/src/pmdas/linux/filesys.c >index 15a4383..08bb99d 100644 >--- a/src/pmdas/linux/filesys.c >+++ b/src/pmdas/linux/filesys.c >@@ -115,7 +115,7 @@ scan_filesys_options(const char *options, const char *option) > > int > refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, >- pmInDom tmpfs_indom, pmInDom cgroups_indom) >+ pmInDom tmpfs_indom) > { > char buf[MAXPATHLEN]; > char realdevice[MAXPATHLEN]; >@@ -128,7 +128,6 @@ refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, > pmdaCacheOp(quota_indom, PMDA_CACHE_INACTIVE); > pmdaCacheOp(tmpfs_indom, PMDA_CACHE_INACTIVE); > pmdaCacheOp(filesys_indom, PMDA_CACHE_INACTIVE); >- pmdaCacheOp(cgroups_indom, PMDA_CACHE_INACTIVE); > > if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) > return -oserror(); >@@ -144,6 +143,7 @@ refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, > strcmp(type, "nfs") == 0 || > strcmp(type, "devfs") == 0 || > strcmp(type, "devpts") == 0 || >+ strcmp(type, "cgroup") == 0 || > strncmp(type, "auto", 4) == 0) > continue; > >@@ -152,10 +152,6 @@ refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom, > indom = tmpfs_indom; > device = path; > } >- else if (strcmp(type, "cgroup") == 0) { >- indom = cgroups_indom; >- device = path; >- } > else if (strncmp(device, "/dev", 4) != 0) > continue; > if (realpath(device, realdevice) != NULL) >diff --git a/src/pmdas/linux/filesys.h b/src/pmdas/linux/filesys.h >index 9379d58..a461b9d 100644 >--- a/src/pmdas/linux/filesys.h >+++ b/src/pmdas/linux/filesys.h >@@ -103,5 +103,5 @@ typedef struct filesys { > struct statfs stats; > } filesys_t; > >-extern int refresh_filesys(pmInDom, pmInDom, pmInDom, pmInDom); >+extern int refresh_filesys(pmInDom, pmInDom, pmInDom); > extern char *scan_filesys_options(const char *, const char *); >diff --git a/src/pmdas/linux/getinfo.c b/src/pmdas/linux/getinfo.c >index 9bbf1dd..c5f9f33 100644 >--- a/src/pmdas/linux/getinfo.c >+++ b/src/pmdas/linux/getinfo.c >@@ -20,41 +20,6 @@ > #include "pmapi.h" > > char * >-get_ttyname_info(int pid, dev_t dev, char *ttyname) >-{ >- DIR *dir; >- struct dirent *dp; >- struct stat sbuf; >- int found=0; >- char procpath[MAXPATHLEN]; >- char ttypath[MAXPATHLEN]; >- >- sprintf(procpath, "/proc/%d/fd", pid); >- if ((dir = opendir(procpath)) != NULL) { >- while ((dp = readdir(dir)) != NULL) { >- if (!isdigit(dp->d_name[0])) >- continue; >- sprintf(procpath, "/proc/%d/fd/%s", pid, dp->d_name); >- if (realpath(procpath, ttypath) == NULL || stat(ttypath, &sbuf) < 0) >- continue; >- if (S_ISCHR(sbuf.st_mode) && dev == sbuf.st_rdev) { >- found=1; >- break; >- } >- } >- closedir(dir); >- } >- >- if (!found) >- strcpy(ttyname, "?"); >- else >- /* skip the "/dev/" prefix */ >- strcpy(ttyname, &ttypath[5]); >- >- return ttyname; >-} >- >-char * > get_distro_info(void) > { > /* >diff --git a/src/pmdas/linux/getinfo.h b/src/pmdas/linux/getinfo.h >index 51f1627..0bf170d 100644 >--- a/src/pmdas/linux/getinfo.h >+++ b/src/pmdas/linux/getinfo.h >@@ -12,6 +12,5 @@ > * for more details. > */ > >-extern char *get_ttyname_info(int, dev_t, char *); > extern char *get_distro_info(void); > >diff --git a/src/pmdas/linux/indom.h b/src/pmdas/linux/indom.h >index 95d06f5..b79b047 100644 >--- a/src/pmdas/linux/indom.h >+++ b/src/pmdas/linux/indom.h >@@ -21,12 +21,12 @@ enum { > DISK_INDOM, /* 1 - disks */ > LOADAVG_INDOM, /* 2 - 1, 5, 15 minute load averages */ > NET_DEV_INDOM, /* 3 - network interfaces */ >- PROC_INTERRUPTS_INDOM, /* 4 - interrupt lines */ >+ PROC_INTERRUPTS_INDOM, /* 4 - interrupt lines -> proc PMDA */ > FILESYS_INDOM, /* 5 - mounted bdev filesystems */ > SWAPDEV_INDOM, /* 6 - swap devices */ > NFS_INDOM, /* 7 - nfs operations */ > NFS3_INDOM, /* 8 - nfs v3 operations */ >- PROC_INDOM, /* 9 - processes */ >+ PROC_PROC_INDOM, /* 9 - processes */ > PARTITIONS_INDOM, /* 10 - disk partitions */ > SCSI_INDOM, /* 11 - scsi devices */ > SLAB_INDOM, /* 12 - kernel slabs */ >@@ -37,8 +37,8 @@ enum { > NET_INET_INDOM, /* 17 - inet addresses */ > TMPFS_INDOM, /* 18 - tmpfs mounts */ > NODE_INDOM, /* 19 - NUMA nodes */ >- CGROUP_SUBSYS_INDOM, /* 20 - control group subsystems */ >- CGROUP_MOUNTS_INDOM, /* 21 - control group mounts */ >+ PROC_CGROUP_SUBSYS_INDOM, /* 20 - control group subsystems -> proc PMDA */ >+ PROC_CGROUP_MOUNTS_INDOM, /* 21 - control group mounts -> proc PMDA */ > > NUM_INDOMS /* one more than highest numbered cluster */ > }; >diff --git a/src/pmdas/linux/ksym.c b/src/pmdas/linux/ksym.c >deleted file mode 100644 >index 3061912..0000000 >--- a/src/pmdas/linux/ksym.c >+++ /dev/null >@@ -1,551 +0,0 @@ >-/* >- * Copyright (c) International Business Machines Corp., 2002 >- * Copyright (c) 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. >- */ >- >-/* >- * This code originally contributed by Mike Mason <mmlnx@us.ibm.com> >- * with hints from the procps and ksymoops projects. >- */ >- >-#include <ctype.h> >-#include <limits.h> >-#include <sys/time.h> >-#include <sys/utsname.h> >-#include "pmapi.h" >-#include "impl.h" >-#include "ksym.h" >- >-static struct ksym *ksym_a; >-static size_t ksym_a_sz; >- >-static int >-find_index(__psint_t addr, int lo, int hi) >-{ >- int mid; >- >- if (lo > hi) { >- return -1; >- } >- >- mid = lo + ((hi - lo) / 2); >- if (addr == ksym_a[mid].addr || >- (addr > ksym_a[mid].addr && addr < ksym_a[mid+1].addr)) { >- return mid; >- } >- >- if (addr > ksym_a[mid].addr) >- return find_index(addr, mid+1, hi); >- else >- return find_index(addr, lo, mid-1); >-} >- >-static char * >-find_name_by_addr(__psint_t addr) >-{ >- int ix = -1; >- >- if (ksym_a) >- ix = find_index(addr, 0, ksym_a_sz - 1); >- if (ix < 0) >- return NULL; >- >- return ksym_a[ix].name; >-} >- >-static int >-find_dup_name(int maxix, __psint_t addr, char *name) >-{ >- int i, res; >- >- for (i = 0; i < maxix; i++) { >- if (ksym_a[i].name) { >- res = strcmp(ksym_a[i].name, name); >- if (res > 0) >- break; >- if (res == 0) { >- if (addr == ksym_a[i].addr) >- return KSYM_FOUND; >- else >- return KSYM_FOUND_MISMATCH; >- } >- } >- } >- >- return KSYM_NOT_FOUND; >-} >- >-/* Brute force linear search to determine if the kernel version >- in System.map matches the running kernel version and returns >- a tri-state result as follows: >- >- 0 no match >- 1 _end not found but version matched >- 2 _end found and matched >- */ >-static int >-validate_sysmap(FILE *fp, char *version, __psint_t end_addr) >-{ >- __psint_t addr; >- char type; >- int ret = 0; >- char kname[128]; >- >- while (fscanf(fp, "%p %c %s", (void **)&addr, &type, kname) != EOF) { >- if (end_addr && strcmp(kname, "_end") == 0) { >- ret = (end_addr == addr) ? 2 : 0; >- break; /* no need to look any further */ >- } >- if (strcmp(kname, version) == 0) >- ret = 1; >- } >- >- return ret; >-} >- >-char * >-wchan(__psint_t addr) >-{ >- static char zero; >- char *p = NULL; >- >- if (addr == 0) /* 0 address means not in kernel space */ >- p = &zero; >- else if ((p = find_name_by_addr(addr))) { >- /* strip off "sys_" or leading "_"s if necessary */ >- if (strncmp(p, "sys_", 4) == 0) >- p += 4; >- while (*p == '_' && *p) >- ++p; >- } >- >- return p; >-} >- >-static int >-ksym_compare_addr(const void *e1, const void *e2) >-{ >- struct ksym *ks1 = (struct ksym *) e1; >- struct ksym *ks2 = (struct ksym *) e2; >- >- if (ks1->addr < ks2->addr) >- return -1; >- if (ks1->addr > ks2->addr) >- return 1; >- return 0; >-} >- >-static int >-ksym_compare_name(const void *e1, const void *e2) >-{ >- struct ksym *ks1 = (struct ksym *) e1; >- struct ksym *ks2 = (struct ksym *) e2; >- >- return(strcmp(ks1->name, ks2->name)); >-} >- >-static int >-read_ksyms(__psint_t *end_addr) >-{ >- char inbuf[256]; >- char *ip; >- char *sp; >- char *tp; >- char *p; >- int ix = 0; >- int l = 0; >- int len; >- int err; >- FILE *fp; >- char *ksyms_path = "/proc/ksyms"; >- >- *end_addr = 0; >- if ((fp = fopen(ksyms_path, "r")) == NULL) >- return -oserror(); >- >- while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { >- l++; >- >- /* >- * /proc/ksyms lines look like this on ia32 ... >- * >- * c8804060 __insmod_rtc_S.text_L4576 [rtc] >- * c010a320 disable_irq_nosync >- * >- * else on ia64 ... >- * >- * a0000000003e0d28 debug [arsess] >- * e002100000891140 disable_irq_nosync >- */ >- >- if (strstr(inbuf, "\n") == NULL) { >- fprintf(stderr, "read_ksyms: truncated /proc/ksyms line [%d]: %s\n", l-1, inbuf); >- continue; >- } >- >- /* Increase array size, if necessary */ >- if (ksym_a_sz < ix+1) { >- if (ksym_a_sz > 0) >- ksym_a_sz += INCR_KSIZE; >- else >- ksym_a_sz = INIT_KSIZE; >- ksym_a = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); >- if (ksym_a == NULL) { >- err = -oserror(); >- fclose(fp); >- return err; >- } >- } >- >- ip = inbuf; >- /* parse over address */ >- while (isxdigit((int)*ip)) ip++; >- >- if (!isspace((int)*ip) || ip-inbuf < 4) { >- /* bad format line */ >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "read_ksyms: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >- } >-#endif >- continue; >- } >- >- sscanf(inbuf, "%p", (void **)&ksym_a[ix].addr); >- >- while (isblank((int)*ip)) ip++; >- >- /* next should be the symbol name */ >- sp = ip++; >- while (!isblank((int)*ip) &&*ip != '\n') ip++; >- >- /* strip off GPLONLY_ prefix, if found */ >- if (strncmp(sp, "GPLONLY_", 8) == 0) >- sp += 8; >- >- /* >- * strip off symbol version suffix, if found ... looking for >- * trailing pattern of the form _R.*[0-9a-fA-F]{8,} >- * - find rightmost _R, if any >- */ >- tp = sp; >- while ((p = strstr(tp, "_R")) != NULL) tp = p+2; >- if (tp > sp) { >- /* >- * found _R, need the last 8 digits to be hex >- */ >- if (ip - tp + 1 >= 8) { >- for (p = &ip[-8]; p < ip; p++) { >- if (!isxdigit(*p)) { >- tp = sp; >- break; >- } >- } >- } >- else { >- /* not enough characters for [0-9a-fA-f]{8,} at the end */ >- tp = sp; >- } >- } >- if (tp > sp) >- /* need to strip the trailing _R.*[0-9a-fA-f]{8,} */ >- len = tp - sp - 2; >- else >- len = ip - sp + 1; >- >- ksym_a[ix].name = strndup(sp, len); >- if (ksym_a[ix].name == NULL) { >- err = -oserror(); >- fclose(fp); >- return err; >- } >- ksym_a[ix].name[len-1] = '\0'; >- >- if (*end_addr == 0 && strcmp(ksym_a[ix].name, "_end") == 0) >- *end_addr = ksym_a[ix].addr; >- >- if (*ip == '\n') >- /* nothing after the symbol name, so no module name */ >- goto next; >- >- while (isblank((int)*ip)) ip++; >- >- /* next expect module name */ >- if (*ip != '[') { >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "read_ksyms: bad start module name %c[%d] != [ line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >- } >-#endif >- free(ksym_a[ix].name); >- continue; >- } >- >- sp = ++ip; >- while (!isblank((int)*ip) && *ip != ']') ip++; >- >- if (*ip != ']') { >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "read_ksyms: bad end module name %c[%d] != ] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >- } >-#endif >- free(ksym_a[ix].name); >- continue; >- } >- >- ksym_a[ix].module = strndup(sp, ip - sp + 1); >- if (ksym_a[ix].module == NULL) { >- err = -oserror(); >- fclose(fp); >- free(ksym_a[ix].name); >- return err; >- } >- ksym_a[ix].module[ip - sp] = '\0'; >- >-next: >- ix++; >- } >- >- /* release unused ksym array entries */ >- if (ix) { >- ksym_a = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); >- if (ksym_a == NULL) >- return -oserror(); >- } >- >- ksym_a_sz = ix; >- >- qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_name); >- >- fclose(fp); >- >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "symbols from ksyms ...\n"); >- for (ix = 0; ix < ksym_a_sz; ix++) { >- fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); >- if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); >- fprintf(stderr, "\n"); >- } >- } >-#endif >- >- return ksym_a_sz; >-} >- >-static int >-read_sysmap(const char *release, __psint_t end_addr) >-{ >- char inbuf[256], path[MAXPATHLEN], **fmt; >- __psint_t addr; >- int ix, res, i, e; >- int l = 0; >- char *ip; >- char *sp; >- int major, minor, patch; >- FILE *fp; >- char *bestpath = NULL; >- int ksym_mismatch_count; >- char *sysmap_paths[] = { /* Paths to check for System.map file */ >- "/boot/System.map-%s", >- "/boot/System.map", >- "/lib/modules/%s/System.map", >- "/usr/src/linux/System.map", >- "/System.map", >- NULL >- }; >- >- /* Create version symbol name to look for in System.map */ >- if (sscanf(release, "%d.%d.%d", &major, &minor, &patch) < 3 ) >- return -1; >- sprintf(inbuf, "Version_%u", KERNEL_VERSION(major, minor, patch)); >- >- /* >- * Walk through System.map path list looking for one that matches >- * either _end from /proc/ksyms or the uts version. >- */ >- for (fmt = sysmap_paths; *fmt; fmt++) { >- snprintf(path, MAXPATHLEN, *fmt, release); >- if ((fp = fopen(path, "r"))) { >- if ((e = validate_sysmap(fp, inbuf, end_addr)) != 0) { >- if (e == 2) { >- /* matched _end, so this is the right System.map */ >- if (bestpath) >- free(bestpath); >- bestpath = strdup(path); >- } >- else >- if (e == 1 && !bestpath) >- bestpath = strdup(path); >- } >- fclose(fp); >- if (e == 2) { >- /* _end matched => don't look any further */ >- break; >- } >- } >- } >- >- if (bestpath) >- fprintf(stderr, "NOTICE: using \"%s\" for kernel symbols map.\n", bestpath); >- else { >- /* Didn't find a valid System.map */ >- fprintf(stderr, "Warning: Valid System.map file not found!\n"); >- fprintf(stderr, "Warning: proc.psinfo.wchan_s symbol names cannot be derived!\n"); >- fprintf(stderr, "Warning: Addresses will be returned for proc.psinfo.wchan_s instead!\n"); >- /* Free symbol array */ >- for (i = 0; i < ksym_a_sz; i++) { >- if (ksym_a[i].name) >- free(ksym_a[i].name); >- if (ksym_a[i].module) >- free(ksym_a[i].module); >- } >- free(ksym_a); >- ksym_a = NULL; >- ksym_a_sz = 0; >- return -1; >- } >- >- /* scan the System map */ >- if ((fp = fopen(bestpath, "r")) == NULL) >- return -oserror(); >- >- ix = ksym_a_sz; >- >- /* Read each line in System.map */ >- ksym_mismatch_count = 0; >- while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { >- i++; >- >- /* >- * System.map lines look like this on ia32 ... >- * >- * c010a320 T disable_irq_nosync >- * >- * else on ia64 ... >- * >- * e002000000014c80 T disable_irq_nosync >- */ >- >- if (strstr(inbuf, "\n") == NULL) { >- fprintf(stderr, "read_sysmap: truncated System.map line [%d]: %s\n", l-1, inbuf); >- continue; >- } >- >- /* Increase array size, if necessary */ >- if (ksym_a_sz < ix+1) { >- ksym_a_sz += INCR_KSIZE; >- ksym_a = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); >- if (ksym_a == NULL) >- goto fail; >- } >- >- ip = inbuf; >- /* parse over address */ >- while (isxdigit((int)*ip)) ip++; >- >- if (!isspace((int)*ip) || ip-inbuf < 4) { >- /* bad format line */ >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "read_sysmap: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); >- } >-#endif >- continue; >- } >- >- sscanf(inbuf, "%p", (void **)&addr); >- >- while (isblank((int)*ip)) ip++; >- >- /* Only interested in symbol types that map to code addresses, >- * so: t, T, W or A >- */ >- if (*ip != 't' && *ip != 'T' && *ip != 'W' && *ip != 'A') >- continue; >- >- ip++; >- while (isblank((int)*ip)) ip++; >- >- /* next should be the symbol name */ >- sp = ip++; >- while (!isblank((int)*ip) && *ip != '\n') ip++; >- *ip = '\0'; >- >- /* Determine if symbol is already in ksym array. >- If so, make sure the addresses match. */ >- res = find_dup_name(ix - 1, addr, sp); >- if (res == KSYM_NOT_FOUND) { /* add it */ >- ksym_a[ix].name = strdup(sp); >- if (ksym_a[ix].name == NULL) >- goto fail; >- ksym_a[ix].addr = addr; >- ix++; >- } >- else if (res == KSYM_FOUND_MISMATCH) { >- if (ksym_mismatch_count++ < KSYM_MISMATCH_MAX_ALLOWED) { >- /* >- * ia64 function pointer descriptors make this validation >- * next to useless. So only report the first >- * KSYM_MISMATCH_MAX_ALLOWED mismatches found. >- */ >- fprintf(stderr, "Warning: mismatch for \"%s\" between System.map" >- " and /proc/ksyms.\n", sp); >- } >- } >- } >- >- if (ksym_mismatch_count > KSYM_MISMATCH_MAX_ALLOWED) { >- fprintf(stderr, "Warning: only reported first %d out of %d mismatches " >- "between System.map and /proc/ksyms.\n", >- KSYM_MISMATCH_MAX_ALLOWED, ksym_mismatch_count); >- } >- >- /* release unused ksym array entries */ >- ksym_a = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); >- if (ksym_a == NULL) >- goto fail; >- >- ksym_a_sz = ix; >- >- qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_addr); >- >-#if PCP_DEBUG >- if (pmDebug & DBG_TRACE_APPL2) { >- fprintf(stderr, "symbols from ksyms + sysmap ...\n"); >- for (ix = 0; ix < ksym_a_sz; ix++) { >- fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); >- if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); >- fprintf(stderr, "\n"); >- } >- } >-#endif >- >- return ksym_a_sz; >- >-fail: >- e = -oserror(); >- if (fp) >- fclose(fp); >- return e; >-} >- >-void >-read_ksym_sources(const char *release) >-{ >- __psint_t end_addr; >- >- if (read_ksyms(&end_addr) > 0) /* read /proc/ksyms first */ >- read_sysmap(release, end_addr); /* then System.map */ >-} >diff --git a/src/pmdas/linux/ksym.h b/src/pmdas/linux/ksym.h >deleted file mode 100644 >index f328ca4..0000000 >--- a/src/pmdas/linux/ksym.h >+++ /dev/null >@@ -1,41 +0,0 @@ >-/* >- * Copyright (c) International Business Machines Corp., 2002 >- * >- * 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 >- */ >- >-/* >- * This code contributed by Mike Mason (mmlnx@us.ibm.com) >- */ >-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) >- >-#define INIT_KSIZE 8192 >-#define INCR_KSIZE 2048 >- >-#define KSYM_FOUND_MISMATCH -1 >-#define KSYM_NOT_FOUND 0 >-#define KSYM_FOUND 1 >- >-#define KSYM_MISMATCH_MAX_ALLOWED 10 >- >-struct ksym { >- __psint_t addr; >- char *name; >- char *module; >-}; >- >-extern char *wchan(__psint_t); >-extern void read_ksym_sources(const char *); >- >diff --git a/src/pmdas/linux/pmda.c b/src/pmdas/linux/pmda.c >index dbc2ac7..462d0ef 100644 >--- a/src/pmdas/linux/pmda.c >+++ b/src/pmdas/linux/pmda.c >@@ -55,7 +55,6 @@ > #include "sem_limits.h" > #include "msg_limits.h" > #include "shm_limits.h" >-#include "ksym.h" > #include "proc_sys_fs.h" > #include "proc_vmstat.h" > #include "sysfs_kernel.h" >@@ -247,7 +246,7 @@ pmdaIndom indomtab[] = { > { SWAPDEV_INDOM, 0, NULL }, > { NFS_INDOM, NR_RPC_COUNTERS, nfs_indom_id }, > { NFS3_INDOM, NR_RPC3_COUNTERS, nfs3_indom_id }, >- { PROC_INDOM, 0, NULL }, /* migrated to the proc PMDA */ >+ { PROC_PROC_INDOM, 0, NULL }, /* migrated to the proc PMDA */ > { PARTITIONS_INDOM, 0, NULL }, /* cached */ > { SCSI_INDOM, 0, NULL }, > { SLAB_INDOM, 0, NULL }, >@@ -258,8 +257,6 @@ pmdaIndom indomtab[] = { > { NET_INET_INDOM, 0, NULL }, > { TMPFS_INDOM, 0, NULL }, > { NODE_INDOM, 0, NULL }, >- { CGROUP_SUBSYS_INDOM, 0, NULL }, >- { CGROUP_MOUNTS_INDOM, 0, NULL }, > }; > > >@@ -3798,24 +3795,10 @@ linux_refresh(pmdaExt *pmda, int *need_refresh) > if (need_refresh[CLUSTER_NET_INET]) > refresh_net_dev_inet(INDOM(NET_INET_INDOM)); > >- if (need_refresh[CLUSTER_CGROUP_SUBSYS] || >- need_refresh[CLUSTER_CGROUP_MOUNTS] || >- need_refresh[CLUSTER_CPUSET_PROCS] || >- need_refresh[CLUSTER_CPUSET_GROUPS] || >- need_refresh[CLUSTER_CPUACCT_PROCS] || >- need_refresh[CLUSTER_CPUACCT_GROUPS] || >- need_refresh[CLUSTER_CPUSCHED_PROCS] || >- need_refresh[CLUSTER_CPUSCHED_GROUPS] || >- need_refresh[CLUSTER_MEMORY_PROCS] || >- need_refresh[CLUSTER_MEMORY_GROUPS] || >- need_refresh[CLUSTER_NET_CLS_PROCS] || >- need_refresh[CLUSTER_NET_CLS_GROUPS]) { >- } >- else > if (need_refresh[CLUSTER_FILESYS] || > need_refresh[CLUSTER_QUOTA] || need_refresh[CLUSTER_TMPFS]) > refresh_filesys(INDOM(FILESYS_INDOM), INDOM(QUOTA_PRJ_INDOM), >- INDOM(TMPFS_INDOM), INDOM(CGROUP_MOUNTS_INDOM)); >+ INDOM(TMPFS_INDOM)); > > if (need_refresh[CLUSTER_INTERRUPTS] || > need_refresh[CLUSTER_INTERRUPT_LINES] || >@@ -3922,12 +3905,6 @@ linux_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaE > case SLAB_INDOM: > need_refresh[CLUSTER_SLAB]++; > break; >- case CGROUP_SUBSYS_INDOM: >- need_refresh[CLUSTER_CGROUP_SUBSYS]++; >- break; >- case CGROUP_MOUNTS_INDOM: >- need_refresh[CLUSTER_CGROUP_MOUNTS]++; >- break; > /* no default label : pmdaInstance will pick up errors */ > } > >@@ -5436,6 +5413,22 @@ linux_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) > } > return sts; > >+ case CLUSTER_INTERRUPTS: >+ switch (idp->item) { >+ case 3: /* kernel.all.interrupts.error */ >+ atom->ul = irq_err_count; >+ break; >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ case CLUSTER_INTERRUPT_LINES: >+ case CLUSTER_INTERRUPT_OTHER: >+ if (inst >= indomtab[CPU_INDOM].it_numinst) >+ return PM_ERR_INST; >+ return interrupts_fetch(idp->cluster, idp->item, inst, atom); >+ > default: /* unknown cluster */ > return PM_ERR_PMID; > } >@@ -5462,7 +5455,6 @@ linux_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) > need_refresh[CLUSTER_PARTITIONS]++; > > if (idp->cluster == CLUSTER_CPUINFO || >- idp->cluster == CLUSTER_CPUACCT_GROUPS || > idp->cluster == CLUSTER_INTERRUPT_LINES || > idp->cluster == CLUSTER_INTERRUPT_OTHER || > idp->cluster == CLUSTER_INTERRUPTS) >@@ -5675,13 +5667,6 @@ linux_init(pmdaInterface *dp) > idp->cluster, idp->item); > } > >- /* >- * Read System.map and /proc/ksyms. Used to translate wait channel >- * addresses to symbol names. >- * Added by Mike Mason <mmlnx@us.ibm.com> >- */ >- read_ksym_sources(kernel_uname.release); >- > interrupts_init(); > > pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), linux_metrictab, > >commit 279950ec0f5bb70967b2d5260ac7f075b8187ca1 >Author: Ken McDonell <kenj@internode.on.net> >Date: Sun Jul 22 18:29:40 2012 +1000 > > Rebuild (pmns) - changes for linux-proc PMDA split > > Need to be selective about the top-level proc and cgroup metrics. > If we're on Linux and the proc PMDA is not there, need to cull these > ones ... this is needed for the migration/upgrade after the split > when the linux PMDA will be installed by default, but the proc PMDA > will not. > If the proc PMDA is installed in pmcd's config file, don't do the > culling. > >diff --git a/src/pmns/Rebuild b/src/pmns/Rebuild >index bbc008a..046cd80 100755 >--- a/src/pmns/Rebuild >+++ b/src/pmns/Rebuild >@@ -110,7 +110,27 @@ _upgrade_root() > > # If there are deprecated top-level names (below "root") that are > # no longer in a root_* file, add them here ... >- EXCLUDE="pagebuf origin" >+ EXCLUDE="pagebuf origin proc cgroup" >+ if [ "$PCP_PLATFORM" = linux ] >+ then >+ # If we're on Linux and the proc PMDA is _not_ included in >+ # the pmcd configuration file, add the top-level metrics >+ # that migrated from the linux PMDA to the proc PMDA >+ # >+ if [ -f $PCP_PMCDCONF_PATH ] >+ then >+ if grep '^proc[ ]' $PCP_PMCDCONF_PATH >/dev/null >+ then >+ # proc PMDA is installed >+ # >+ : >+ else >+ EXCLUDE="$EXCLUDE proc cgroup" >+ fi >+ else >+ EXCLUDE="$EXCLUDE proc cgroup" >+ fi >+ fi > > # now gather top-level names from root_* files > # > >commit c20319d064af66dc5902661a3f05dccb24d7d177 >Author: Ken McDonell <kenj@internode.on.net> >Date: Thu Jul 19 11:30:32 2012 +1000 > > proc PMDA - preliminary checkin > > This is not working ... just want to save state so far. > >diff --git a/src/pmdas/proc/GNUmakefile b/src/pmdas/proc/GNUmakefile >new file mode 100644 >index 0000000..b5dbb7e >--- /dev/null >+++ b/src/pmdas/proc/GNUmakefile >@@ -0,0 +1,85 @@ >+# >+# Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. >+# Copyright (c) 2007-2010 Aconex. 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 = linux >+DOMAIN = LINUX >+CMDTARGET = pmdalinux >+LIBTARGET = pmda_linux.so >+PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) >+CONF_LINE = "linux 60 dso linux_init $(PMDADIR)/$(LIBTARGET)" >+ >+CFILES = pmda.c proc_stat.c proc_meminfo.c proc_loadavg.c \ >+ proc_net_dev.c interrupts.c filesys.c \ >+ swapdev.c proc_net_rpc.c proc_partitions.c \ >+ getinfo.c proc_net_sockstat.c proc_runq.c \ >+ proc_net_snmp.c proc_scsi.c proc_fs_xfs.c \ >+ proc_cpuinfo.c proc_net_tcp.c \ >+ proc_slabinfo.c sem_limits.c msg_limits.c shm_limits.c \ >+ proc_uptime.c ksym.c proc_sys_fs.c proc_vmstat.c \ >+ sysfs_kernel.c linux_table.c numa_meminfo.c \ >+ dynamic.c cgroups.c >+ >+HFILES = proc_stat.h proc_meminfo.h proc_loadavg.h \ >+ proc_net_dev.h interrupts.h filesys.h swapdev.h \ >+ proc_net_rpc.h proc_pid.h proc_partitions.h getinfo.h \ >+ proc_net_sockstat.h proc_runq.h proc_net_snmp.h \ >+ proc_scsi.h proc_fs_xfs.h \ >+ proc_cpuinfo.h proc_net_tcp.h proc_slabinfo.h \ >+ sem_limits.h msg_limits.h shm_limits.h proc_uptime.h \ >+ ksym.h proc_sys_fs.h proc_vmstat.h clusters.h indom.h \ >+ convert.h sysfs_kernel.h linux_table.h numa_meminfo.h \ >+ dynamic.h cgroups.h >+ >+LSRCFILES = help root_linux >+LDIRT = help.dir help.pag domain.h >+ >+LLDLIBS = -lpcp_pmda -lpcp >+ >+# Uncomment these flags for profiling >+# LCFLAGS = -pg >+# LLDFLAGS = -pg >+ >+default: build-me >+ >+include $(BUILDRULES) >+ >+ifeq "$(TARGET_OS)" "linux" >+build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag >+ @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ >+ echo $(CONF_LINE) >> ../pmcd.conf ; \ >+ fi >+ >+install: default >+ $(INSTALL) -m 755 -d $(PMDADIR) >+ $(INSTALL) -m 644 domain.h help help.dir help.pag $(PMDADIR) >+ $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) >+ $(INSTALL) -m 644 root_linux $(PCP_VAR_DIR)/pmns/root_linux >+else >+build-me: >+install: >+endif >+ >+help.dir help.pag : help >+ $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_linux -v 2 -o help < help >+ >+default_pcp : default >+ >+install_pcp : install >+ >+domain.h: ../../pmns/stdpmid >+ $(DOMAIN_MAKERULE) >diff --git a/src/pmdas/proc/TODO b/src/pmdas/proc/TODO >new file mode 100644 >index 0000000..70064a9 >--- /dev/null >+++ b/src/pmdas/proc/TODO >@@ -0,0 +1,18 @@ >+Start with PROC_INDOM >+ >+ >+[ ] proc_pid.indom >+ >+[y] CLUSTER_PID_STAT fetch_proc_pid_stat() >+[y] CLUSTER_PID_STATM fetch_proc_pid_maps() fetch_proc_pid_statm() >+[y] CLUSTER_PID_STATUS fetch_proc_pid_status() >+[y] CLUSTER_PID_SCHEDSTAT fetch_proc_pid_schedstat() >+[y] CLUSTER_PID_IO fetch_proc_pid_io() >+[y] CLUSTER_PID_FD fetch_proc_pid_fd() >+[ ] CLUSTER_PROC_RUNQ refresh_proc_runq() >+ >+[ ] proc.nprocs >+ >+[y] refresh_proc_pid() >+ >+[ ] cgroups? >diff --git a/src/pmdas/proc/dynamic.c b/src/pmdas/proc/dynamic.c >new file mode 100644 >index 0000000..cb69deb >--- /dev/null >+++ b/src/pmdas/proc/dynamic.c >@@ -0,0 +1,176 @@ >+/* >+ * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >+ * >+ * Copyright (c) 2010 Aconex. 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 "indom.h" >+#include "dynamic.h" >+#include "clusters.h" >+ >+static struct dynamic { >+ const char *prefix; >+ int prefixlen; >+ int mtabcount; /* internal use only */ >+ int extratrees; /* internal use only */ >+ int nclusters; >+ int clusters[NUM_CLUSTERS]; >+ pmnsUpdate pmnsupdate; >+ textUpdate textupdate; >+ mtabUpdate mtabupdate; >+ mtabCounts mtabcounts; >+ __pmnsTree *pmns; >+} *dynamic; >+ >+static int dynamic_count; >+ >+void >+proc_dynamic_pmns(const char *prefix, int *clusters, int nclusters, >+ pmnsUpdate pmnsupdate, textUpdate textupdate, >+ mtabUpdate mtabupdate, mtabCounts mtabcounts) >+{ >+ int size = (dynamic_count+1) * sizeof(struct dynamic); >+ >+ if ((dynamic = (struct dynamic *)realloc(dynamic, size)) == NULL) { >+ __pmNotifyErr(LOG_ERR, "out-of-memory registering dynamic metrics"); >+ return; >+ } >+ dynamic[dynamic_count].prefix = prefix; >+ dynamic[dynamic_count].prefixlen = strlen(prefix); >+ dynamic[dynamic_count].nclusters = nclusters; >+ memcpy(dynamic[dynamic_count].clusters, clusters, nclusters * sizeof(int)); >+ dynamic[dynamic_count].pmnsupdate = pmnsupdate; >+ dynamic[dynamic_count].textupdate = textupdate; >+ dynamic[dynamic_count].mtabupdate = mtabupdate; >+ dynamic[dynamic_count].mtabcounts = mtabcounts; >+ dynamic[dynamic_count].pmns = NULL; >+ dynamic_count++; >+} >+ >+__pmnsTree * >+proc_dynamic_lookup_name(pmdaExt *pmda, const char *name) >+{ >+ int i; >+ >+ for (i = 0; i < dynamic_count; i++) { >+ if (strncmp(name, dynamic[i].prefix, dynamic[i].prefixlen) == 0) { >+ if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >+ proc_dynamic_metrictable(pmda); >+ return dynamic[i].pmns; >+ } >+ } >+ return NULL; >+} >+ >+__pmnsTree * >+proc_dynamic_lookup_pmid(pmdaExt *pmda, pmID pmid) >+{ >+ int i, j; >+ int cluster = pmid_cluster(pmid); >+ >+ for (i = 0; i < dynamic_count; i++) { >+ for (j = 0; j < dynamic[i].nclusters; j++) { >+ if (cluster == dynamic[i].clusters[j]) { >+ if (dynamic[i].pmnsupdate(pmda, &dynamic[i].pmns)) >+ proc_dynamic_metrictable(pmda); >+ return dynamic[i].pmns; >+ } >+ } >+ } >+ return NULL; >+} >+ >+int >+proc_dynamic_lookup_text(pmID pmid, int type, char **buf, pmdaExt *pmda) >+{ >+ int i, j; >+ int cluster = pmid_cluster(pmid); >+ >+ for (i = 0; i < dynamic_count; i++) { >+ for (j = 0; j < dynamic[i].nclusters; j++) >+ if (cluster == dynamic[i].clusters[j]) >+ return dynamic[i].textupdate(pmda, pmid, type, buf); >+ } >+ return -ENOENT; >+} >+ >+/* >+ * Call the update function for each new metric we're adding. >+ * We pass in the original metric, and the new (uninit'd) slot >+ * which needs to be filled in. All a bit obscure, really. >+ */ >+static pmdaMetric * >+proc_dynamic_mtab(struct dynamic *dynamic, pmdaMetric *offset) >+{ >+ int m, metric_count = proc_metrictable_size(); >+ int tree_count = dynamic->extratrees; >+ >+ for (m = 0; m < metric_count; m++) { >+ int c, id, cluster = pmid_cluster(proc_metrictab[m].m_desc.pmid); >+ for (c = 0; c < dynamic->nclusters; c++) >+ if (dynamic->clusters[c] == cluster) >+ break; >+ if (c < dynamic->nclusters) >+ for (id = 0; id < tree_count; id++) >+ dynamic->mtabupdate(&proc_metrictab[m], offset++, id+1); >+ } >+ return offset; >+} >+ >+/* >+ * Iterate through the dynamic table working out how many additional metric >+ * table entries are needed. Then allocate a new metric table, if needed, >+ * and run through the dynamic table once again to fill in the additional >+ * entries. Finally, we update the metric table pointer to be the pmdaExt >+ * for libpcp_pmda routines subsequent use. >+ */ >+void >+proc_dynamic_metrictable(pmdaExt *pmda) >+{ >+ int i, trees, total, resize = 0; >+ pmdaMetric *mtab, *offset; >+ >+ for (i = 0; i < dynamic_count; i++) >+ dynamic[i].mtabcount = dynamic[i].extratrees = 0; >+ >+ for (i = 0; i < dynamic_count; i++) { >+ dynamic[i].mtabcounts(&total, &trees); >+ dynamic[i].mtabcount += total; >+ dynamic[i].extratrees += trees; >+ resize += (total * trees); >+ } >+ >+ if (resize == 0) { >+ /* Fits into the default metric table - reset it to original values */ >+fallback: >+ if (pmda->e_metrics != proc_metrictab) >+ free(pmda->e_metrics); >+ pmda->e_metrics = proc_metrictab; >+ pmda->e_nmetrics = proc_metrictable_size(); >+ } else { >+ resize += proc_metrictable_size(); >+ if ((mtab = calloc(resize, sizeof(pmdaMetric))) == NULL) >+ goto fallback; >+ memcpy(mtab, proc_metrictab, proc_metrictable_size() * sizeof(pmdaMetric)); >+ offset = mtab + proc_metrictable_size(); >+ for (i = 0; i < dynamic_count; i++) >+ offset = proc_dynamic_mtab(&dynamic[i], offset); >+ if (pmda->e_metrics != proc_metrictab) >+ free(pmda->e_metrics); >+ pmda->e_metrics = mtab; >+ pmda->e_nmetrics = resize; >+ } >+} >diff --git a/src/pmdas/proc/dynamic.h b/src/pmdas/proc/dynamic.h >new file mode 100644 >index 0000000..8819f4e >--- /dev/null >+++ b/src/pmdas/proc/dynamic.h >@@ -0,0 +1,31 @@ >+/* >+ * Dynamic namespace metrics for the proc PMDA -- pinched from the Linux PMDA >+ * >+ * Copyright (c) 2010 Aconex. 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. >+ */ >+ >+/* function to refresh a specific subtree */ >+typedef int (*pmnsUpdate)(pmdaExt *, __pmnsTree **); >+typedef int (*textUpdate)(pmdaExt *, pmID, int, char **); >+typedef void (*mtabUpdate)(pmdaMetric *, pmdaMetric *, int); >+typedef void (*mtabCounts)(int *, int *); >+ >+extern pmdaMetric proc_metrictab[]; /* default metric table */ >+extern int proc_metrictable_size(); >+ >+extern void proc_dynamic_pmns(const char *, int *, int, >+ pmnsUpdate, textUpdate, mtabUpdate, mtabCounts); >+extern __pmnsTree *proc_dynamic_lookup_name(pmdaExt *, const char *); >+extern __pmnsTree *proc_dynamic_lookup_pmid(pmdaExt *, pmID); >+extern int proc_dynamic_lookup_text(pmID, int, char **, pmdaExt *); >+extern void proc_dynamic_metrictable(pmdaExt *); >diff --git a/src/pmdas/proc/help b/src/pmdas/proc/help >new file mode 100644 >index 0000000..8426f9a >--- /dev/null >+++ b/src/pmdas/proc/help >@@ -0,0 +1,181 @@ >+# >+# Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. >+# Portions Copyright (c) International Business Machines Corp., 2002 >+# Portions Copyright (c) 2007-2009 Aconex. 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. >+# >+# Linux proc 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 >+# >+ >+@ proc.nprocs instantaneous number of processes >+@ proc.psinfo.pid process identifier >+@ proc.psinfo.psargs full command string >+@ proc.psinfo.cmd command name >+@ proc.psinfo.sname process state identifier (see ps(1)). See also proc.runq metrics. >+@ proc.psinfo.ppid parent process identifier >+@ proc.psinfo.pgrp process group identifier >+@ proc.psinfo.session process session identifier >+@ proc.psinfo.tty controlling tty device number (zero if none) >+@ proc.psinfo.tty_pgrp controlling tty process group identifier >+@ proc.psinfo.flags process state flags, as a bitmap >+@ proc.psinfo.minflt count of minor page faults (i.e. reclaims) >+@ proc.psinfo.cmin_flt count of minor page faults (i.e. reclaims) of all exited children >+@ proc.psinfo.maj_flt count of page faults other than reclaims >+@ proc.psinfo.cmaj_flt count of page faults other than reclaims of all exited children >+@ proc.psinfo.utime time (in ms) spent executing user code since process started >+@ proc.psinfo.stime time (in ms) spent executing system code (calls) since process started >+@ proc.psinfo.cutime time (in ms) spent executing user code of all exited children >+@ proc.psinfo.cstime time (in ms) spent executing system code of all exited children >+@ proc.psinfo.priority priority value >+@ proc.psinfo.nice process nice value (negative nice values are lower priority) >+@ proc.psinfo.it_real_value current interval timer value (zero if none) >+@ proc.psinfo.start_time start time of the process relative to system boot time in seconds >+@ proc.psinfo.vsize virtual size of the process in Kbytes >+@ proc.psinfo.rss resident set size (i.e. physical memory) of the process >+@ proc.psinfo.rss_rlim limit on resident set size of process >+@ proc.psinfo.start_code address of the start of the code segment for the process >+@ proc.psinfo.end_code address of the end of the code segment for the process >+@ proc.psinfo.start_stack address of the stack segment for the process >+@ proc.psinfo.esp the value in the esp field of struct task_struct for the process >+@ proc.psinfo.eip the value in the eip field of struct task_struct for the process >+@ proc.psinfo.signal the value in the signal field of struct task_struct for the process >+@ proc.psinfo.blocked the value in the blocked field of struct task_struct for the process >+@ proc.psinfo.sigignore the value in the sigignore field of struct task_struct for the process >+@ proc.psinfo.sigcatch the value in the sigcatch field of struct task_struct for the process >+@ proc.psinfo.wchan wait channel, kernel address this process is blocked or sleeping on >+@ proc.psinfo.nswap count of page swap operations >+@ proc.psinfo.cnswap count of page swap operations of all exited children >+@ proc.psinfo.exit_signal the value in the exit_signal field of struct task_struct for the process >+@ proc.psinfo.ttyname name of controlling tty device, or "?" if none. See also proc.psinfo.tty. >+@ proc.psinfo.processor last CPU the process was running on >+@ proc.psinfo.wchan_s name of an event for which the process is sleeping (if blank, the process is running). >+This field needs access to a namelist file for proper >+address-to-symbol name translation. If no namelist file >+is available, the address is printed instead. The namelist >+file must match the current Linux kernel exactly. >+The search path for the namelist file is as follows: >+ /boot/System.map-`uname -r` >+ /boot/System.map >+ /lib/modules/`uname -r`/System.map >+ /usr/src/linux/System.map >+ /System.map >+@ proc.psinfo.signal_s pending signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.blocked_s blocked signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.sigignore_s ignored signals mask in string form (from /proc/<pid>/status) >+@ proc.psinfo.sigcatch_s caught signals mask in string form (from /proc/<pid>/status) >+@ proc.memory.size instantaneous virtual size of process, excluding page table and task structure. >+@ proc.memory.rss instantaneous resident size of process, excluding page table and task structure. >+@ proc.memory.share instantaneous amount of memory shared by this process with other processes >+@ proc.memory.textrss instantaneous resident size of process code segment in Kbytes >+@ proc.memory.librss instantaneous resident size of library code mapped by the process, in Kbytes >+@ proc.memory.datrss instantaneous resident size of process data segment, in Kbytes >+@ proc.memory.dirty instantaneous amount of memory that has been modified by the process, in Kbytes >+@ proc.memory.maps table of memory mapped by process in string form from /proc/<pid>/maps >+@ proc.memory.vmsize total virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmlock locked virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmrss resident virtual memory (from /proc/<pid>/status) >+@ proc.memory.vmdata virtual memory used for data (from /proc/<pid>/status) >+@ proc.memory.vmstack virtual memory used for stack (from /proc/<pid>/status) >+@ proc.memory.vmexe virtual memory used for non-library executable code (from /proc/<pid>/status) >+@ proc.memory.vmlib virtual memory used for libraries (from /proc/<pid>/status) >+@ proc.id.uid real user ID from /proc/<pid>/status >+@ proc.id.euid effective user ID from /proc/<pid>/status >+@ proc.id.suid saved user ID from /proc/<pid>/status >+@ proc.id.fsuid filesystem user ID from /proc/<pid>/status >+@ proc.id.gid real group ID from /proc/<pid>/status >+@ proc.id.egid effective group ID from /proc/<pid>/status >+@ proc.id.sgid saved group ID from /proc/<pid>/status >+@ proc.id.fsgid filesystem group ID from /proc/<pid>/status >+@ proc.id.uid_nm real user name based on real user ID from /proc/<pid>/status >+@ proc.id.euid_nm effective user name based on effective user ID from /proc/<pid>/status >+@ proc.id.suid_nm saved user name based on saved user ID from /proc/<pid>/status >+@ proc.id.fsuid_nm filesystem user name based on filesystem user ID from /proc/<pid>/status >+@ proc.id.gid_nm real group name based on real group ID from /proc/<pid>/status >+@ proc.id.egid_nm effective group name based on effective group ID from /proc/<pid>/status >+@ proc.id.sgid_nm saved group name based on saved group ID from /proc/<pid>/status >+@ proc.id.fsgid_nm filesystem group name based on filesystem group ID from /proc/<pid>/status >+ >+@ proc.runq.runnable number of runnable (on run queue) processes >+Instantaneous number of runnable (on run queue) processes, state 'R' in ps >+@ proc.runq.blocked number of processes in uninterruptible sleep >+Instantaneous number of processes in uninterruptible sleep, state 'D' in ps >+@ proc.runq.sleeping number of processes sleeping >+Instantaneous number of processes sleeping, state 'S' in ps >+@ proc.runq.stopped number of traced, stopped or suspended processes >+Instantaneous number of traced, stopped or suspended processes, state >+'T' in ps >+@ proc.runq.swapped number of processes that are swapped >+Instantaneous number of processes (excluding kernel threads) that are >+swapped, state 'SW' in ps >+@ proc.runq.defunct number of defunct/zombie processes >+Instantaneous number of defunct/zombie processes, state 'Z' in ps >+@ proc.runq.unknown number of processes is an unknown state >+Instantaneous number of processes is an unknown state, including all >+kernel threads >+@ proc.runq.kernel number of kernel threads >+Instantaneous number of processes with virtual size of zero (kernel threads) >+ >+@ proc.io.rchar >+Extended accounting information - count of the number of bytes that >+have passed over the read(2), readv(2) and sendfile(2) syscalls by >+each process. >+ >+@ proc.io.wchar >+Extended accounting information - count of the number of bytes that >+have passed over the write(2), writev(2) and sendfile(2) syscalls by >+each process. >+ >+@ proc.io.syscr >+Extended accounting information - count of number of calls to the >+read(2), readv(2) and sendfile(2) syscalls by each process. >+ >+@ proc.io.syscw >+Extended accounting information - count of number of calls to the >+write(2), writev(2) and sendfile(2) syscalls by each process. >+ >+@ proc.io.read_bytes >+Number of bytes physically read on by devices on behalf of this process. >+@ proc.io.write_bytes >+Number of bytes physically written to devices on behalf of this process. >+This must be reduced by any truncated I/O (proc.io.cancelled_write_bytes). >+@ proc.io.cancelled_write_bytes >+Number of bytes cancelled via truncate by this process. Actual physical >+writes for an individual process can be calculated as: >+ proc.io.write_bytes - proc.io.cancelled_write_bytes. >+ >+@ proc.schedstat.cpu_time >+Length of time in nanoseconds that a process has been running, including >+scheduling time. >+@ proc.schedstat.run_delay >+Length of time in nanoseconds that a process spent waiting to be scheduled >+to run in the run queue. >+@ proc.schedstat.pcount >+Number of times a process has been scheduled to run on a CPU (this is >+incremented when a task actually reaches a CPU to run on, not simply >+when it is added to the run queue). >+ >+@ proc.fd.count >+Number of file descriptors this process has open. >+ >diff --git a/src/pmdas/proc/pmda.c b/src/pmdas/proc/pmda.c >new file mode 100644 >index 0000000..bf680c8 >--- /dev/null >+++ b/src/pmdas/proc/pmda.c >@@ -0,0 +1,1674 @@ >+/* >+ * proc PMDA >+ * >+ * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Portions Copyright (c) 2002 International Business Machines Corp. >+ * Portions Copyright (c) 2007-2011 Aconex. 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 "dynamic.h" >+ >+#include <ctype.h> >+#include <sys/vfs.h> >+#include <sys/stat.h> >+#include <sys/times.h> >+#include <sys/utsname.h> >+#include <utmp.h> >+#include <pwd.h> >+#include <grp.h> >+ >+#include "../linux/convert.h" >+#include "clusters.h" >+#include "indom.h" >+ >+#include "proc_stat.h" >+#include "getinfo.h" >+#include "proc_pid.h" >+#include "proc_partitions.h" >+#include "proc_runq.h" >+#include "proc_uptime.h" >+#include "ksym.h" >+#include "proc_sys_fs.h" >+#include "proc_vmstat.h" >+#include "sysfs_kernel.h" >+#include "linux_table.h" >+#include "cgroups.h" >+ >+static proc_stat_t proc_stat; >+static proc_pid_t proc_pid; >+static struct utsname kernel_uname; >+static char uname_string[sizeof(kernel_uname)]; >+static proc_runq_t proc_runq; >+static proc_uptime_t proc_uptime; >+static proc_sys_fs_t proc_sys_fs; >+static proc_vmstat_t proc_vmstat; >+static sysfs_kernel_t sysfs_kernel; >+ >+static int _isDSO = 1; /* =0 I am a daemon */ >+ >+/* globals */ >+size_t _pm_system_pagesize; /* for hinv.pagesize and used elsewhere */ >+int _pm_have_proc_vmstat; /* if /proc/vmstat is available */ >+ >+pmdaIndom indomtab[] = { >+ { PROC_INDOM, 0, NULL }, >+ { CGROUP_SUBSYS_INDOM, 0, NULL }, >+ { CGROUP_MOUNTS_INDOM, 0, NULL }, >+}; >+ >+ >+/* >+ * all metrics supported in this PMDA - one table entry for each >+ */ >+ >+pmdaMetric linux_metrictab[] = { >+ >+/* >+ * proc/<pid>/stat cluster >+ */ >+ >+/* proc.nprocs */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.pid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.cmd */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,1), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sname */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,2), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.ppid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.pgrp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.session */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.tty */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.tty_pgrp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.flags */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,8), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.minflt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,9), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cmin_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,10), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.maj_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,11), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cmaj_flt */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,12), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.utime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,13), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.stime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,14), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.cutime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,15), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.cstime */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,16), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, >+ >+/* proc.psinfo.priority */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,17), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.nice */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,18), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+#if 0 >+/* invalid field */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,19), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#endif >+ >+/* proc.psinfo.it_real_value */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.start_time */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) } }, >+ >+/* proc.psinfo.vsize */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.rss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.rss_rlim */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.psinfo.start_code */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.end_code */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.start_stack */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,27), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.esp */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,28), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.eip */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,29), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.signal */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,30), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.blocked */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,31), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sigignore */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,32), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.sigcatch */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,33), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.wchan */ >+#if defined(HAVE_64BIT_PTR) >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U64, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#elif defined(HAVE_32BIT_PTR) >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+#else >+ error! unsupported pointer size >+#endif >+ >+/* proc.psinfo.nswap */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,35), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.cnswap */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,36), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.psinfo.exit_signal */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,37), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.processor -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,38), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.ttyname */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,39), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0) } }, >+ >+/* proc.psinfo.wchan_s -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,40), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.psargs -- modified by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STAT,41), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* >+ * proc/<pid>/status cluster >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ >+/* proc.id.uid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.euid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.suid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsuid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.gid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.egid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.sgid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsgid */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.uid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,8), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.euid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,9), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.suid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,10), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsuid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,11), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.gid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,12), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.egid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,13), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.sgid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,14), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.id.fsgid_nm */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,15), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.signal_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,16), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.blocked_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,17), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.sigignore_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,18), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.psinfo.sigcatch_s */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,19), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* proc.memory.vmsize */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmlock */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmdata */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmstack */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmexe */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* proc.memory.vmlib */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATUS,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* >+ * proc/<pid>/statm cluster >+ */ >+ >+/* proc.memory.size */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.rss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.share */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.textrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.librss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.datrss */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.dirty */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, >+ >+/* proc.memory.maps -- added by Mike Mason <mmlnx@us.ibm.com> */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_STATM,7), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,0,0,0,0)}}, >+ >+/* >+ * proc/<pid>/schedstat cluster >+ */ >+ >+/* proc.schedstat.cpu_time */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >+/* proc.schedstat.run_delay */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, >+/* proc.schedstat.pcount */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,2), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+ >+/* >+ * proc/<pid>/io cluster >+ */ >+/* proc.io.rchar */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.wchar */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.syscr */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,2), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.syscw */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,3), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, >+/* proc.io.read_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,4), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+/* proc.io.write_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,5), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+/* proc.io.cancelled_write_bytes */ >+ { NULL, >+ { PMDA_PMID(CLUSTER_PID_IO,6), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, >+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, >+ >+/* >+ * proc.runq cluster >+ */ >+ >+/* proc.runq.runnable */ >+ { &proc_runq.runnable, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.blocked */ >+ { &proc_runq.blocked, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.sleeping */ >+ { &proc_runq.sleeping, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.stopped */ >+ { &proc_runq.stopped, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.swapped */ >+ { &proc_runq.swapped, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.defunct */ >+ { &proc_runq.defunct, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.unknown */ >+ { &proc_runq.unknown, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+/* proc.runq.kernel */ >+ { &proc_runq.kernel, >+ { PMDA_PMID(CLUSTER_PROC_RUNQ, 7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+ >+ >+ >+/* >+ * control groups cluster >+ */ >+ /* cgroups.subsys.hierarchy */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,0), PM_TYPE_U32, >+ CGROUP_SUBSYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroups.subsys.count */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,1), PM_TYPE_U32, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >+ >+ /* cgroups.mounts.subsys */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,0), PM_TYPE_STRING, >+ CGROUP_MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroups.mounts.count */ >+ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,1), PM_TYPE_U32, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, >+ >+#if 0 /* not yet implemented */ >+ /* cgroup.groups.cpuset.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpuset.[<group>.]cpus */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,0), PM_TYPE_STRING, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+ /* cgroup.groups.cpuset.[<group>.]mems */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,1), PM_TYPE_STRING, >+ PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+#if 0 /* not yet implemented */ >+ /* cgroup.groups.cpuacct.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpuacct.[<group>.]stat.user */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]stat.system */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,1), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]usage */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,2), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >+ >+ /* cgroup.groups.cpuacct.[<group>.]usage_percpu */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,3), PM_TYPE_U64, >+ CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.cpusched.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.cpusched.[<group>.]shares */ >+ { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.memory.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.memory.[<group>.]stat.cache */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.rss */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,1), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.pgin */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,2), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.pgout */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,3), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.swap */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,4), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.active_anon */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,5), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.inactive_anon */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,6), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.active_file */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,7), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.inactive_file */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,8), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+ /* cgroup.groups.memory.[<group>.]stat.unevictable */ >+ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,9), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+#if 0 >+ /* cgroup.groups.netclass.[<group>.]tasks.pid */ >+ { NULL, {PMDA_PMID(CLUSTER_NET_CLS_PROCS,0), PM_TYPE_U32, >+ PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, >+#endif >+ >+ /* cgroup.groups.netclass.[<group>.]classid */ >+ { NULL, {PMDA_PMID(CLUSTER_NET_CLS_GROUPS,0), PM_TYPE_U64, >+ PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, >+ >+/* >+ * proc/<pid>/fd cluster >+ */ >+ >+ /* proc.fd.count */ >+ { NULL, {PMDA_PMID(CLUSTER_PID_FD,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, >+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, >+}; >+ >+int >+refresh_cgroups(pmdaExt *pmda, __pmnsTree **tree) >+{ >+ int changed; >+ time_t rightnow; >+ static time_t previoustime; >+ static __pmnsTree *previoustree; >+ >+ if (tree) { >+ if ((rightnow = time(NULL)) == previoustime) { >+ *tree = previoustree; >+ return 0; >+ } >+ } >+ >+ refresh_cgroup_subsys(INDOM(CGROUP_SUBSYS_INDOM)); >+ changed = refresh_cgroup_groups(pmda, INDOM(CGROUP_MOUNTS_INDOM), tree); >+ >+ if (tree) { >+ previoustime = rightnow; >+ previoustree = *tree; >+ } >+ return changed; >+} >+ >+static void >+linux_refresh(pmdaExt *pmda, int *need_refresh) >+{ >+ int need_refresh_mtab = 0; >+ >+ if (need_refresh[CLUSTER_CGROUP_SUBSYS] || >+ need_refresh[CLUSTER_CGROUP_MOUNTS] || >+ need_refresh[CLUSTER_CPUSET_PROCS] || >+ need_refresh[CLUSTER_CPUSET_GROUPS] || >+ need_refresh[CLUSTER_CPUACCT_PROCS] || >+ need_refresh[CLUSTER_CPUACCT_GROUPS] || >+ need_refresh[CLUSTER_CPUSCHED_PROCS] || >+ need_refresh[CLUSTER_CPUSCHED_GROUPS] || >+ need_refresh[CLUSTER_MEMORY_PROCS] || >+ need_refresh[CLUSTER_MEMORY_GROUPS] || >+ need_refresh[CLUSTER_NET_CLS_PROCS] || >+ need_refresh[CLUSTER_NET_CLS_GROUPS]) { >+ need_refresh_mtab |= refresh_cgroups(pmda, NULL); >+ } >+ >+ if (need_refresh[CLUSTER_PID_STAT] || need_refresh[CLUSTER_PID_STATM] || >+ need_refresh[CLUSTER_PID_STATUS] || need_refresh[CLUSTER_PID_IO] || >+ need_refresh[CLUSTER_PID_SCHEDSTAT] || need_refresh[CLUSTER_PID_FD]) >+ refresh_proc_pid(&proc_pid); >+ >+ if (need_refresh[CLUSTER_KERNEL_UNAME]) >+ uname(&kernel_uname); >+ >+ if (need_refresh[CLUSTER_PROC_RUNQ]) >+ refresh_proc_runq(&proc_runq); >+ >+ if (need_refresh[CLUSTER_SCSI]) >+ refresh_proc_scsi(&proc_scsi); >+ >+ if (need_refresh[CLUSTER_SEM_LIMITS]) >+ refresh_sem_limits(&sem_limits); >+ >+ if (need_refresh[CLUSTER_MSG_LIMITS]) >+ refresh_msg_limits(&msg_limits); >+ >+ if (need_refresh[CLUSTER_SHM_LIMITS]) >+ refresh_shm_limits(&shm_limits); >+ >+ if (need_refresh[CLUSTER_UPTIME]) >+ refresh_proc_uptime(&proc_uptime); >+ >+ if (need_refresh[CLUSTER_VFS]) >+ refresh_proc_sys_fs(&proc_sys_fs); >+ >+ if (need_refresh[CLUSTER_VMSTAT]) >+ refresh_proc_vmstat(&proc_vmstat); >+ >+ if (need_refresh[CLUSTER_SYSFS_KERNEL]) >+ refresh_sysfs_kernel(&sysfs_kernel); >+ >+ if (need_refresh_mtab) >+ proc_dynamic_metrictable(pmda); >+} >+ >+static int >+linux_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) >+{ >+ __pmInDom_int *indomp = (__pmInDom_int *)&indom; >+ int need_refresh[NUM_CLUSTERS]; >+ char newname[11]; /* see Note below */ >+ >+ memset(need_refresh, 0, sizeof(need_refresh)); >+ switch (indomp->serial) { >+ case PROC_INDOM: >+ need_refresh[CLUSTER_PID_STAT]++; >+ need_refresh[CLUSTER_PID_STATM]++; >+ need_refresh[CLUSTER_PID_STATUS]++; >+ need_refresh[CLUSTER_PID_SCHEDSTAT]++; >+ need_refresh[CLUSTER_PID_IO]++; >+ need_refresh[CLUSTER_PID_FD]++; >+ break; >+ case CGROUP_SUBSYS_INDOM: >+ need_refresh[CLUSTER_CGROUP_SUBSYS]++; >+ break; >+ case CGROUP_MOUNTS_INDOM: >+ need_refresh[CLUSTER_CGROUP_MOUNTS]++; >+ break; >+ /* no default label : pmdaInstance will pick up errors */ >+ } >+ >+ if (indomp->serial == PROC_INDOM && inst == PM_IN_NULL && name != NULL) { >+ /* >+ * For the proc indom, if the name is a pid (as a string), and it >+ * contains only digits (i.e. it's not a full instance name) then >+ * reformat it to be exactly six digits, with leading zeros. >+ * >+ * Note that although format %06d is used here and in proc_pid.c, >+ * the pid could be longer than this (in which case there >+ * are no leading zeroes. The size of newname[] is chosen >+ * to comfortably accommodate a 32-bit pid (Linux maximum), >+ * or max value of 4294967295 (10 digits) >+ */ >+ char *p; >+ for (p = name; *p != '\0'; p++) { >+ if (!isdigit(*p)) >+ break; >+ } >+ if (*p == '\0') { >+ snprintf(newname, sizeof(newname), "%06d", atoi(name)); >+ name = newname; >+ } >+ } >+ >+ linux_refresh(pmda, need_refresh); >+ return pmdaInstance(indom, inst, name, result, pmda); >+} >+ >+/* >+ * callback provided to pmdaFetch >+ */ >+ >+static int >+linux_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) >+{ >+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); >+ int i; >+ int sts; >+ char *f; >+ long sl; >+ unsigned long ul; >+ int *ip; >+ proc_pid_entry_t *entry; >+ >+ if (mdesc->m_user != NULL) { >+ /* >+ * The metric value is extracted directly via the address specified >+ * in metrictab. Note: not all metrics support this - those that >+ * don't have NULL for the m_user field in their respective >+ * metrictab slot. >+ */ >+ if (idp->cluster == CLUSTER_VMSTAT) { >+ if (!_pm_have_proc_vmstat || *(__uint64_t *)mdesc->m_user == (__uint64_t)-1) >+ return 0; /* no value available on this kernel */ >+ } >+ if (idp->cluster == CLUSTER_SYSFS_KERNEL) { >+ /* no values available for udev metrics */ >+ if (idp->item == 0 && !sysfs_kernel.valid_uevent_seqnum) { >+ return 0; >+ } >+ } >+ >+ switch (mdesc->m_desc.type) { >+ case PM_TYPE_32: >+ atom->l = *(__int32_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_U32: >+ atom->ul = *(__uint32_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_64: >+ atom->ll = *(__int64_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_U64: >+ atom->ull = *(__uint64_t *)mdesc->m_user; >+ break; >+ case PM_TYPE_FLOAT: >+ atom->f = *(float *)mdesc->m_user; >+ break; >+ case PM_TYPE_DOUBLE: >+ atom->d = *(double *)mdesc->m_user; >+ break; >+ case PM_TYPE_STRING: >+ atom->cp = (char *)mdesc->m_user; >+ break; >+ default: >+ return 0; >+ } >+ } >+ else >+ switch (idp->cluster) { >+ >+ case CLUSTER_UPTIME: /* uptime */ >+ switch (idp->item) { >+ case 0: >+ /* >+ * kernel.all.uptime (in seconds) >+ * contributed by "gilly" <gilly@exanet.com> >+ * modified by Mike Mason" <mmlnx@us.ibm.com> >+ */ >+ atom->ul = proc_uptime.uptime; >+ break; >+ case 1: >+ /* >+ * kernel.all.idletime (in seconds) >+ * contributed by "Mike Mason" <mmlnx@us.ibm.com> >+ */ >+ atom->ul = proc_uptime.idletime; >+ break; >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ case CLUSTER_PID_STAT: >+ if (idp->item == 99) /* proc.nprocs */ >+ atom->ul = proc_pid.indom->it_numinst; >+ else { >+ static char ttyname[MAXPATHLEN]; >+ >+ if ((entry = fetch_proc_pid_stat(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ >+ case PROC_PID_STAT_PID: >+ atom->ul = entry->id; >+ break; >+ >+ case PROC_PID_STAT_TTYNAME: >+ if ((f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_TTY)) == NULL) >+ atom->cp = "?"; >+ else { >+ dev_t dev = (dev_t)atoi(f); >+ atom->cp = get_ttyname_info(inst, dev, ttyname); >+ } >+ break; >+ >+ case PROC_PID_STAT_CMD: >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = f + 1; >+ atom->cp[strlen(atom->cp)-1] = '\0'; >+ break; >+ >+ case PROC_PID_STAT_PSARGS: >+ atom->cp = entry->name + 7; >+ break; >+ >+ case PROC_PID_STAT_STATE: >+ /* >+ * string >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = f; >+ break; >+ >+ case PROC_PID_STAT_VSIZE: >+ case PROC_PID_STAT_RSS_RLIM: >+ /* >+ * bytes converted to kbytes >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul /= 1024; >+ break; >+ >+ case PROC_PID_STAT_RSS: >+ /* >+ * pages converted to kbytes >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul *= _pm_system_pagesize / 1024; >+ break; >+ >+ case PROC_PID_STAT_UTIME: >+ case PROC_PID_STAT_STIME: >+ case PROC_PID_STAT_CUTIME: >+ case PROC_PID_STAT_CSTIME: >+ /* >+ * unsigned jiffies converted to unsigned milliseconds >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ >+ sscanf(f, "%lu", &ul); >+ _pm_assign_ulong(atom, 1000 * (double)ul / proc_stat.hz); >+ break; >+ >+ case PROC_PID_STAT_PRIORITY: >+ case PROC_PID_STAT_NICE: >+ /* >+ * signed decimal int >+ */ >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%d", &atom->l); >+ break; >+ >+ case PROC_PID_STAT_WCHAN: >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+#endif >+ break; >+ >+ case PROC_PID_STAT_WCHAN_SYMBOL: >+ if (entry->wchan_buf) /* 2.6 kernel, /proc/<pid>/wchan */ >+ atom->cp = entry->wchan_buf; >+ else { /* old school (2.4 kernels, at least) */ >+ char *wc; >+ /* >+ * Convert address to symbol name if requested >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_WCHAN); >+ if (f == NULL) >+ return PM_ERR_INST; >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+ if ((wc = wchan(atom->ull))) >+ atom->cp = wc; >+ else >+ atom->cp = atom->ull ? f : ""; >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+ if ((wc = wchan((__psint_t)atom->ul))) >+ atom->cp = wc; >+ else >+ atom->cp = atom->ul ? f : ""; >+#endif >+ } >+ break; >+ >+ default: >+ /* >+ * unsigned decimal int >+ */ >+ if (idp->item >= 0 && idp->item < NR_PROC_PID_STAT) { >+ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ } >+ else >+ return PM_ERR_PMID; >+ break; >+ } >+ } >+ break; >+ >+ case CLUSTER_PID_STATM: >+ if (idp->item == PROC_PID_STATM_MAPS) { /* proc.memory.maps */ >+ if ((entry = fetch_proc_pid_maps(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ atom->cp = entry->maps_buf; >+ } else { >+ if ((entry = fetch_proc_pid_statm(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ if (idp->item >= 0 && idp->item <= PROC_PID_STATM_DIRTY) { >+ /* unsigned int */ >+ if ((f = _pm_getfield(entry->statm_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ atom->ul *= _pm_system_pagesize / 1024; >+ } >+ else >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ case CLUSTER_PID_SCHEDSTAT: >+ if ((entry = fetch_proc_pid_schedstat(inst, &proc_pid)) == NULL) >+ return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; >+ >+ if (idp->item >= 0 && idp->item < NR_PROC_PID_SCHED) { >+ if ((f = _pm_getfield(entry->schedstat_buf, idp->item)) == NULL) >+ return PM_ERR_INST; >+ if (idp->item == PROC_PID_SCHED_PCOUNT && >+ mdesc->m_desc.type == PM_TYPE_U32) >+ sscanf(f, "%u", &atom->ul); >+ else >+#if defined(HAVE_64BIT_PTR) >+ sscanf(f, "%lu", &atom->ull); /* 64bit address */ >+#else >+ sscanf(f, "%u", &atom->ul); /* 32bit address */ >+#endif >+ } >+ else >+ return PM_ERR_PMID; >+ break; >+ >+ case CLUSTER_PID_IO: >+ if ((entry = fetch_proc_pid_io(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ case PROC_PID_IO_RCHAR: >+ if ((f = _pm_getfield(entry->io_lines.rchar, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_WCHAR: >+ if ((f = _pm_getfield(entry->io_lines.wchar, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_SYSCR: >+ if ((f = _pm_getfield(entry->io_lines.syscr, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_SYSCW: >+ if ((f = _pm_getfield(entry->io_lines.syscw, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_READ_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.readb, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_WRITE_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.writeb, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ case PROC_PID_IO_CANCELLED_BYTES: >+ if ((f = _pm_getfield(entry->io_lines.cancel, 1)) == NULL) >+ atom->ull = 0; >+ else >+ sscanf(f, "%llu", (unsigned long long *)&atom->ull); >+ break; >+ >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_PID_STATUS: >+ if ((entry = fetch_proc_pid_status(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ >+ switch (idp->item) { >+ >+ case PROC_PID_STATUS_UID: >+ case PROC_PID_STATUS_EUID: >+ case PROC_PID_STATUS_SUID: >+ case PROC_PID_STATUS_FSUID: >+ case PROC_PID_STATUS_UID_NM: >+ case PROC_PID_STATUS_EUID_NM: >+ case PROC_PID_STATUS_SUID_NM: >+ case PROC_PID_STATUS_FSUID_NM: >+ { >+ struct passwd *pwe; >+ >+ if ((f = _pm_getfield(entry->status_lines.uid, (idp->item % 4) + 1)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ if (idp->item > PROC_PID_STATUS_FSUID) { >+ if ((pwe = getpwuid((uid_t)atom->ul)) != NULL) >+ atom->cp = pwe->pw_name; >+ else >+ atom->cp = "UNKNOWN"; >+ } >+ } >+ break; >+ >+ case PROC_PID_STATUS_GID: >+ case PROC_PID_STATUS_EGID: >+ case PROC_PID_STATUS_SGID: >+ case PROC_PID_STATUS_FSGID: >+ case PROC_PID_STATUS_GID_NM: >+ case PROC_PID_STATUS_EGID_NM: >+ case PROC_PID_STATUS_SGID_NM: >+ case PROC_PID_STATUS_FSGID_NM: >+ { >+ struct group *gre; >+ >+ if ((f = _pm_getfield(entry->status_lines.gid, (idp->item % 4) + 1)) == NULL) >+ return PM_ERR_INST; >+ sscanf(f, "%u", &atom->ul); >+ if (idp->item > PROC_PID_STATUS_FSGID) { >+ if ((gre = getgrgid((gid_t)atom->ul)) != NULL) { >+ atom->cp = gre->gr_name; >+ } else { >+ atom->cp = "UNKNOWN"; >+ } >+ } >+ } >+ break; >+ >+ case PROC_PID_STATUS_SIGNAL: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigpnd, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_BLOCKED: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigblk, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_SIGCATCH: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigcgt, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_SIGIGNORE: >+ if ((atom->cp = _pm_getfield(entry->status_lines.sigign, 1)) == NULL) >+ return PM_ERR_INST; >+ break; >+ >+ case PROC_PID_STATUS_VMSIZE: >+ if ((f = _pm_getfield(entry->status_lines.vmsize, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMLOCK: >+ if ((f = _pm_getfield(entry->status_lines.vmlck, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMRSS: >+ if ((f = _pm_getfield(entry->status_lines.vmrss, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMDATA: >+ if ((f = _pm_getfield(entry->status_lines.vmdata, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMSTACK: >+ if ((f = _pm_getfield(entry->status_lines.vmstk, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMEXE: >+ if ((f = _pm_getfield(entry->status_lines.vmexe, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ case PROC_PID_STATUS_VMLIB: >+ if ((f = _pm_getfield(entry->status_lines.vmlib, 1)) == NULL) >+ atom->ul = 0; >+ else >+ sscanf(f, "%u", &atom->ul); >+ break; >+ >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_SEM_LIMITS: >+ switch (idp->item) { >+ case 0: /* ipc.sem.max_semmap */ >+ atom->ul = sem_limits.semmap; >+ break; >+ case 1: /* ipc.sem.max_semid */ >+ atom->ul = sem_limits.semmni; >+ break; >+ case 2: /* ipc.sem.max_sem */ >+ atom->ul = sem_limits.semmns; >+ break; >+ case 3: /* ipc.sem.num_undo */ >+ atom->ul = sem_limits.semmnu; >+ break; >+ case 4: /* ipc.sem.max_perid */ >+ atom->ul = sem_limits.semmsl; >+ break; >+ case 5: /* ipc.sem.max_ops */ >+ atom->ul = sem_limits.semopm; >+ break; >+ case 6: /* ipc.sem.max_undoent */ >+ atom->ul = sem_limits.semume; >+ break; >+ case 7: /* ipc.sem.sz_semundo */ >+ atom->ul = sem_limits.semusz; >+ break; >+ case 8: /* ipc.sem.max_semval */ >+ atom->ul = sem_limits.semvmx; >+ break; >+ case 9: /* ipc.sem.max_exit */ >+ atom->ul = sem_limits.semaem; >+ break; >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_MSG_LIMITS: >+ switch (idp->item) { >+ case 0: /* ipc.msg.sz_pool */ >+ atom->ul = msg_limits.msgpool; >+ break; >+ case 1: /* ipc.msg.mapent */ >+ atom->ul = msg_limits.msgmap; >+ break; >+ case 2: /* ipc.msg.max_msgsz */ >+ atom->ul = msg_limits.msgmax; >+ break; >+ case 3: /* ipc.msg.max_defmsgq */ >+ atom->ul = msg_limits.msgmnb; >+ break; >+ case 4: /* ipc.msg.max_msgqid */ >+ atom->ul = msg_limits.msgmni; >+ break; >+ case 5: /* ipc.msg.sz_msgseg */ >+ atom->ul = msg_limits.msgssz; >+ break; >+ case 6: /* ipc.msg.num_smsghdr */ >+ atom->ul = msg_limits.msgtql; >+ break; >+ case 7: /* ipc.msg.max_seg */ >+ atom->ul = (unsigned long) msg_limits.msgseg; >+ break; >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_SHM_LIMITS: >+ switch (idp->item) { >+ case 0: /* ipc.shm.max_segsz */ >+ atom->ul = shm_limits.shmmax; >+ break; >+ case 1: /* ipc.shm.min_segsz */ >+ atom->ul = shm_limits.shmmin; >+ break; >+ case 2: /* ipc.shm.max_seg */ >+ atom->ul = shm_limits.shmmni; >+ break; >+ case 3: /* ipc.shm.max_segproc */ >+ atom->ul = shm_limits.shmseg; >+ break; >+ case 4: /* ipc.shm.max_shmsys */ >+ atom->ul = shm_limits.shmall; >+ break; >+ default: >+ return PM_ERR_PMID; >+ } >+ break; >+ >+ /* >+ * Cluster added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ case CLUSTER_NUSERS: >+ { >+ /* count the number of users */ >+ struct utmp *ut; >+ atom->ul = 0; >+ setutent(); >+ while ((ut = getutent())) { >+ if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) >+ atom->ul++; >+ } >+ endutent(); >+ } >+ break; >+ >+ >+ case CLUSTER_CGROUP_SUBSYS: >+ switch (idp->item) { >+ case 0: /* cgroup.subsys.hierarchy */ >+ sts = pmdaCacheLookup(INDOM(CGROUP_SUBSYS_INDOM), inst, NULL, (void **)&ip); >+ if (sts < 0) >+ return sts; >+ if (sts != PMDA_CACHE_ACTIVE) >+ return PM_ERR_INST; >+ atom->ul = i; >+ break; >+ >+ case 1: /* cgroup.subsys.count */ >+ atom->ul = pmdaCacheOp(INDOM(CGROUP_SUBSYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >+ break; >+ } >+ break; >+ >+ case CLUSTER_CGROUP_MOUNTS: >+ switch (idp->item) { >+ case 0: /* cgroup.mounts.subsys */ >+ sts = pmdaCacheLookup(INDOM(CGROUP_MOUNTS_INDOM), inst, NULL, (void **)&fs); >+ if (sts < 0) >+ return sts; >+ if (sts != PMDA_CACHE_ACTIVE) >+ return PM_ERR_INST; >+ atom->cp = cgroup_find_subsys(INDOM(CGROUP_SUBSYS_INDOM), fs->options); >+ break; >+ >+ case 1: /* cgroup.mounts.count */ >+ atom->ul = pmdaCacheOp(INDOM(CGROUP_MOUNTS_INDOM), PMDA_CACHE_SIZE_ACTIVE); >+ break; >+ } >+ break; >+ >+ case CLUSTER_CPUSET_GROUPS: >+ case CLUSTER_CPUACCT_GROUPS: >+ case CLUSTER_CPUSCHED_GROUPS: >+ case CLUSTER_MEMORY_GROUPS: >+ case CLUSTER_NET_CLS_GROUPS: >+ return cgroup_group_fetch(idp->cluster, idp->item, inst, atom); >+ >+ case CLUSTER_CPUSET_PROCS: >+ case CLUSTER_CPUACCT_PROCS: >+ case CLUSTER_CPUSCHED_PROCS: >+ case CLUSTER_MEMORY_PROCS: >+ case CLUSTER_NET_CLS_PROCS: >+ return cgroup_procs_fetch(idp->cluster, idp->item, inst, atom); >+ >+ case CLUSTER_PID_FD: >+ if ((entry = fetch_proc_pid_fd(inst, &proc_pid)) == NULL) >+ return PM_ERR_INST; >+ if (idp->item != PROC_PID_FD_COUNT) >+ return PM_ERR_INST; >+ >+ atom->ul = entry->fd_count; >+ break; >+ >+ default: /* unknown cluster */ >+ return PM_ERR_PMID; >+ } >+ >+ return 1; >+} >+ >+ >+static int >+linux_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) >+{ >+ int i; >+ int need_refresh[NUM_CLUSTERS]; >+ >+ memset(need_refresh, 0, sizeof(need_refresh)); >+ for (i=0; i < numpmid; i++) { >+ __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); >+ if (idp->cluster >= 0 && idp->cluster < NUM_CLUSTERS) { >+ need_refresh[idp->cluster]++; >+ >+ if (idp->cluster == CLUSTER_STAT && >+ need_refresh[CLUSTER_PARTITIONS] == 0 && >+ is_partitions_metric(pmidlist[i])) >+ need_refresh[CLUSTER_PARTITIONS]++; >+ >+ if (idp->cluster == CLUSTER_CPUACCT_GROUPS) >+ need_refresh[CLUSTER_STAT]++; >+ } >+ >+ } >+ >+ linux_refresh(pmda, need_refresh); >+ return pmdaFetch(numpmid, pmidlist, resp, pmda); >+} >+ >+static int >+procfs_zero(const char *filename, pmValueSet *vsp) >+{ >+ FILE *fp; >+ int value; >+ int sts = 0; >+ >+ value = vsp->vlist[0].value.lval; >+ if (value < 0) >+ return PM_ERR_SIGN; >+ >+ fp = fopen(filename, "w"); >+ if (!fp) { >+ sts = -oserror(); >+ } else { >+ fprintf(fp, "%d\n", value); >+ fclose(fp); >+ } >+ return sts; >+} >+ >+static int >+linux_store(pmResult *result, pmdaExt *pmda) >+{ >+ return PM_ERR_PERMISSION; >+} >+ >+static int >+linux_text(int ident, int type, char **buf, pmdaExt *pmda) >+{ >+ if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { >+ int sts = proc_dynamic_lookup_text(ident, type, buf, pmda); >+ if (sts != -ENOENT) >+ return sts; >+ } >+ return pmdaText(ident, type, buf, pmda); >+} >+ >+static int >+linux_pmid(const char *name, pmID *pmid, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >+ return pmdaTreePMID(tree, name, pmid); >+} >+ >+static int >+linux_name(pmID pmid, char ***nameset, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_pmid(pmda, pmid); >+ return pmdaTreeName(tree, pmid, nameset); >+} >+ >+static int >+linux_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) >+{ >+ __pmnsTree *tree = proc_dynamic_lookup_name(pmda, name); >+ return pmdaTreeChildren(tree, name, flag, kids, sts); >+} >+ >+int >+linux_metrictable_size(void) >+{ >+ return sizeof(linux_metrictab)/sizeof(linux_metrictab[0]); >+} >+ >+/* >+ * Initialise the agent (both daemon and DSO). >+ */ >+ >+void >+linux_init(pmdaInterface *dp) >+{ >+ int i, major, minor; >+ __pmID_int *idp; >+ >+ _pm_system_pagesize = getpagesize(); >+ if (_isDSO) { >+ char helppath[MAXPATHLEN]; >+ int sep = __pmPathSeparator(); >+ snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", >+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >+ pmdaDSO(dp, PMDA_INTERFACE_4, "linux DSO", helppath); >+ } >+ >+ if (dp->status != 0) >+ return; >+ >+ dp->version.four.instance = linux_instance; >+ dp->version.four.store = linux_store; >+ dp->version.four.fetch = linux_fetch; >+ dp->version.four.text = linux_text; >+ dp->version.four.pmid = linux_pmid; >+ dp->version.four.name = linux_name; >+ dp->version.four.children = linux_children; >+ pmdaSetFetchCallBack(dp, linux_fetchCallBack); >+ >+ proc_pid.indom = &indomtab[PROC_INDOM]; >+ >+ /* >+ * Read System.map and /proc/ksyms. Used to translate wait channel >+ * addresses to symbol names. >+ * Added by Mike Mason <mmlnx@us.ibm.com> >+ */ >+ read_ksym_sources(kernel_uname.release); >+ >+ cgroup_init(); >+ >+ pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), linux_metrictab, >+ sizeof(linux_metrictab)/sizeof(linux_metrictab[0])); >+} >+ >+ >+static void >+usage(void) >+{ >+ fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); >+ fputs("Options:\n" >+ " -d domain use domain (numeric) for metrics domain of PMDA\n" >+ " -l logfile write log into logfile rather than using default log name\n", >+ stderr); >+ exit(1); >+} >+ >+/* >+ * Set up the agent if running as a daemon. >+ */ >+ >+int >+main(int argc, char **argv) >+{ >+ int sep = __pmPathSeparator(); >+ int err = 0; >+ int c; >+ pmdaInterface dispatch; >+ char helppath[MAXPATHLEN]; >+ >+ _isDSO = 0; >+ __pmSetProgname(argv[0]); >+ >+ snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", >+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep); >+ pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, LINUX, "linux.log", helppath); >+ >+ if ((c = pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err)) != EOF) >+ err++; >+ >+ if (err) >+ usage(); >+ >+ pmdaOpenLog(&dispatch); >+ linux_init(&dispatch); >+ pmdaConnect(&dispatch); >+ pmdaMain(&dispatch); >+ >+ exit(0); >+} >diff --git a/src/pmdas/proc/pmns b/src/pmdas/proc/pmns >new file mode 100644 >index 0000000..d93678b >--- /dev/null >+++ b/src/pmdas/proc/pmns >@@ -0,0 +1,155 @@ >+/* >+ * Metrics for the Linux proc PMDA >+ * >+ * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. >+ * Portions Copyright (c) International Business Machines Corp., 2002 >+ * Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. >+ * >+ * Note: >+ * names and pmids migrated from the Linux PMDA, with the domain >+ * number changed from LINUX (60) to PROC (3) >+ * >+ * 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 >+ */ >+ >+cgroup PROC:*:* >+ >+proc { >+ nprocs 60:8:99 >+ psinfo >+ memory >+ runq >+ id >+ io >+ schedstat >+ fd >+} >+ >+proc.psinfo { >+ pid PROC:8:0 >+ cmd PROC:8:1 >+ sname PROC:8:2 >+ ppid PROC:8:3 >+ pgrp PROC:8:4 >+ session PROC:8:5 >+ tty PROC:8:6 >+ tty_pgrp PROC:8:7 >+ flags PROC:8:8 >+ minflt PROC:8:9 >+ cmin_flt PROC:8:10 >+ maj_flt PROC:8:11 >+ cmaj_flt PROC:8:12 >+ utime PROC:8:13 >+ stime PROC:8:14 >+ cutime PROC:8:15 >+ cstime PROC:8:16 >+ priority PROC:8:17 >+ nice PROC:8:18 >+ /* not valid in 2.2.1 PROC:8:19 */ >+ it_real_value PROC:8:20 >+ start_time PROC:8:21 >+ vsize PROC:8:22 >+ rss PROC:8:23 >+ rss_rlim PROC:8:24 >+ start_code PROC:8:25 >+ end_code PROC:8:26 >+ start_stack PROC:8:27 >+ esp PROC:8:28 >+ eip PROC:8:29 >+ signal PROC:8:30 >+ blocked PROC:8:31 >+ sigignore PROC:8:32 >+ sigcatch PROC:8:33 >+ wchan PROC:8:34 >+ nswap PROC:8:35 >+ cnswap PROC:8:36 >+ exit_signal PROC:8:37 >+ processor PROC:8:38 >+ ttyname PROC:8:39 >+ wchan_s PROC:8:40 >+ psargs PROC:8:41 >+ signal_s PROC:24:16 >+ blocked_s PROC:24:17 >+ sigignore_s PROC:24:18 >+ sigcatch_s PROC:24:19 >+} >+ >+proc.id { >+ uid PROC:24:0 >+ euid PROC:24:1 >+ suid PROC:24:2 >+ fsuid PROC:24:3 >+ gid PROC:24:4 >+ egid PROC:24:5 >+ sgid PROC:24:6 >+ fsgid PROC:24:7 >+ uid_nm PROC:24:8 >+ euid_nm PROC:24:9 >+ suid_nm PROC:24:10 >+ fsuid_nm PROC:24:11 >+ gid_nm PROC:24:12 >+ egid_nm PROC:24:13 >+ sgid_nm PROC:24:14 >+ fsgid_nm PROC:24:15 >+} >+ >+proc.memory { >+ size PROC:9:0 >+ rss PROC:9:1 >+ share PROC:9:2 >+ textrss PROC:9:3 >+ librss PROC:9:4 >+ datrss PROC:9:5 >+ dirty PROC:9:6 >+ maps PROC:9:7 >+ vmsize PROC:24:20 >+ vmlock PROC:24:21 >+ vmrss PROC:24:22 >+ vmdata PROC:24:23 >+ vmstack PROC:24:24 >+ vmexe PROC:24:25 >+ vmlib PROC:24:26 >+} >+ >+proc.runq { >+ runnable PROC:13:0 >+ blocked PROC:13:1 >+ sleeping PROC:13:2 >+ stopped PROC:13:3 >+ swapped PROC:13:4 >+ defunct PROC:13:5 >+ unknown PROC:13:6 >+ kernel PROC:13:7 >+} >+ >+proc.io { >+ rchar PROC:32:0 >+ wchar PROC:32:1 >+ syscr PROC:32:2 >+ syscw PROC:32:3 >+ read_bytes PROC:32:4 >+ write_bytes PROC:32:5 >+ cancelled_write_bytes PROC:32:6 >+} >+ >+proc.schedstat { >+ cpu_time PROC:31:0 >+ run_delay PROC:31:1 >+ pcount PROC:31:2 >+} >+ >+proc.fd { >+ count PROC:51:0 >+} >diff --git a/src/pmdas/proc/root b/src/pmdas/proc/root >new file mode 100644 >index 0000000..834246f >--- /dev/null >+++ b/src/pmdas/proc/root >@@ -0,0 +1,10 @@ >+/* >+ * fake "root" for validating the local PMNS subtree >+ */ >+ >+#include <stdpmid> >+ >+root { proc } >+ >+#include "pmns" >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 840905
: 599902