pcp
[Top] [All Lists]

[PATCH] Add open file-descriptor count metric to the Linux PMDA

To: pcp@xxxxxxxxxxx
Subject: [PATCH] Add open file-descriptor count metric to the Linux PMDA
From: David Disseldorp <ddiss@xxxxxxx>
Date: Mon, 25 Jul 2011 11:59:24 +0200
Cc: David Disseldorp <ddiss@xxxxxxx>
In-reply-to: <1311587964-26531-1-git-send-email-ddiss@xxxxxxx>
References: <1311587964-26531-1-git-send-email-ddiss@xxxxxxx>
The proc.fd.count Linux PMDA metric is calculated for a process by
counting symlinks in the proc/<pid>/fd directory.
---
 src/pmdas/linux/clusters.h |    1 +
 src/pmdas/linux/help       |    3 +++
 src/pmdas/linux/pmda.c     |   19 ++++++++++++++++++-
 src/pmdas/linux/proc_pid.c |   38 ++++++++++++++++++++++++++++++++++++++
 src/pmdas/linux/proc_pid.h |   14 ++++++++++++++
 src/pmdas/linux/root_linux |    7 ++++++-
 6 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/src/pmdas/linux/clusters.h b/src/pmdas/linux/clusters.h
index fd5dd1c..be845bf 100644
--- a/src/pmdas/linux/clusters.h
+++ b/src/pmdas/linux/clusters.h
@@ -70,6 +70,7 @@ enum {
        CLUSTER_NET_CLS_PROCS,  /* 48 network classification group processes */
        CLUSTER_INTERRUPT_LINES,/* 49 /proc/interrupts percpu interrupts */
        CLUSTER_INTERRUPT_OTHER,/* 50 /proc/interrupts percpu interrupts */
+       CLUSTER_PID_FD,         /* 51 /proc/<pid>/fd */
 
        NUM_CLUSTERS            /* one more than highest numbered cluster */
 };
diff --git a/src/pmdas/linux/help b/src/pmdas/linux/help
index 169fb80..9616c90 100644
--- a/src/pmdas/linux/help
+++ b/src/pmdas/linux/help
@@ -972,6 +972,9 @@ 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.
+
 @ network.ip.forwarding count of ip forwarding
 @ network.ip.defaultttl count of ip defaultttl
 @ network.ip.inreceives count of ip inreceives
diff --git a/src/pmdas/linux/pmda.c b/src/pmdas/linux/pmda.c
index 77bfe71..f7eddd5 100644
--- a/src/pmdas/linux/pmda.c
+++ b/src/pmdas/linux/pmda.c
@@ -4390,6 +4390,13 @@ pmdaMetric linux_metrictab[] = {
     { 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
@@ -4484,7 +4491,7 @@ linux_refresh(pmdaExt *pmda, int *need_refresh)
 
     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_SCHEDSTAT] || need_refresh[CLUSTER_PID_FD])
        refresh_proc_pid(&proc_pid);
 
     if (need_refresh[CLUSTER_KERNEL_UNAME])
@@ -4582,6 +4589,7 @@ linux_instance(pmInDom indom, int inst, char *name, 
__pmInResult **result, pmdaE
         need_refresh[CLUSTER_PID_STATUS]++;
         need_refresh[CLUSTER_PID_SCHEDSTAT]++;
         need_refresh[CLUSTER_PID_IO]++;
+        need_refresh[CLUSTER_PID_FD]++;
        break;
     case SCSI_INDOM:
        need_refresh[CLUSTER_SCSI]++;
@@ -6563,6 +6571,15 @@ linux_fetchCallBack(pmdaMetric *mdesc, unsigned int 
inst, pmAtomValue *atom)
            return PM_ERR_INST;
        return interrupts_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;
     }
diff --git a/src/pmdas/linux/proc_pid.c b/src/pmdas/linux/proc_pid.c
index dab510e..b35928c 100644
--- a/src/pmdas/linux/proc_pid.c
+++ b/src/pmdas/linux/proc_pid.c
@@ -108,6 +108,7 @@ refresh_proc_pidlist(proc_pid_t *proc_pid, proc_pid_list_t 
*pidlist)
            ep->maps_fetched = 0;
            ep->io_fetched = 0;
            ep->wchan_fetched = 0;
+           ep->fd_fetched = 0;
        }
     }
 
@@ -638,6 +639,43 @@ fetch_proc_pid_io(int id, proc_pid_t *proc_pid)
 }
 
 /*
+ * 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;
+       struct dirent *de;
+
+       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 ((de = 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.
diff --git a/src/pmdas/linux/proc_pid.h b/src/pmdas/linux/proc_pid.h
index dd59c68..ddcb2cc 100644
--- a/src/pmdas/linux/proc_pid.h
+++ b/src/pmdas/linux/proc_pid.h
@@ -139,6 +139,11 @@
 #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;
@@ -204,6 +209,12 @@ typedef struct {
     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 {
@@ -247,6 +258,9 @@ 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 */
diff --git a/src/pmdas/linux/root_linux b/src/pmdas/linux/root_linux
index 2c4ff8f..8df9f4f 100644
--- a/src/pmdas/linux/root_linux
+++ b/src/pmdas/linux/root_linux
@@ -677,9 +677,10 @@ proc {
     psinfo
     memory
     runq
-    id 
+    id
     io
     schedstat
+    fd
 }
 
 proc.psinfo {
@@ -795,6 +796,10 @@ proc.schedstat {
     pcount             60:31:2
 }
 
+proc.fd {
+    count              60:51:0
+}
+
 xfs {
     allocs
     alloc_btree
-- 
1.7.1

<Prev in Thread] Current Thread [Next in Thread>