summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2009-01-15 23:20:54 +0000
committerStef Walter <stef@memberwebs.com>2009-01-15 23:20:54 +0000
commit663a4dce7c52dd50fefd1d71d9ff3ec811acb795 (patch)
tree099c9b8aa7a1298e949e2b1c0601d5a5ccfacbc1
parente0efaf285c3d7daff0037d4fd446aa5dd55741f4 (diff)
Add support for monitoring CPU usage.
-rw-r--r--ChangeLog3
-rw-r--r--configure.in4
-rw-r--r--doc/JAILS-MIB.txt9
-rw-r--r--doc/bsnmp-jails.82
-rw-r--r--module/bsnmp-jails.c199
-rw-r--r--module/jails-tree.def1
6 files changed, 206 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index e53ffc4..5d59ee8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+0.4
+ - Add support for monitoring CPU time of a jail.
+
0.3
- Support multiple IPs per jail.
diff --git a/configure.in b/configure.in
index 4de57f6..cfedb14 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,6 @@
# Process this file with autoconf to produce a configure script.
-AC_INIT(bsnmp-jails, 0.3, stef@memberwebs.com)
-AM_INIT_AUTOMAKE(bsnmp-jails, 0.3)
+AC_INIT(bsnmp-jails, 0.4, stef@memberwebs.com)
+AM_INIT_AUTOMAKE(bsnmp-jails, 0.4)
AC_CONFIG_SRCDIR([module/bsnmp-jails.c])
AM_CONFIG_HEADER([config.h])
diff --git a/doc/JAILS-MIB.txt b/doc/JAILS-MIB.txt
index 6fac74f..c7016fc 100644
--- a/doc/JAILS-MIB.txt
+++ b/doc/JAILS-MIB.txt
@@ -71,6 +71,8 @@ JailEntry ::=
jailInPackets Counter64,
jailOutOctets Counter64,
jailOutPackets Counter64,
+ jailProcesses Integer32,
+ jailCpuTime TimeTicks
}
jailIndex OBJECT-TYPE
@@ -122,6 +124,13 @@ jailProcesses OBJECT-TYPE
DESCRIPTION "Number of processes running in this jail."
::= { jailEntry 20 }
+jailCpuTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "Amount of CPU time taken by this jail."
+ ::= { jailEntry 21 }
+
jailDiskSpace OBJECT-TYPE
SYNTAX Counter64
MAX-ACCESS read-only
diff --git a/doc/bsnmp-jails.8 b/doc/bsnmp-jails.8
index daaf2db..93ea091 100644
--- a/doc/bsnmp-jails.8
+++ b/doc/bsnmp-jails.8
@@ -76,6 +76,8 @@ The number of octets sent by the jail over the network.
The number of packets sent by the jail over the network.
.It Ar jails.jailTable.jailEntry.jailProcesses.X
The number of processes running in the jail.
+.It Ar jails.jailTable.jailEntry.jailCpuTime.X
+The amount of CPU time (in SNMP time ticks) the jail has used.
.It Ar jails.jailNetworkFilter
A tcpdump style filter for the network traffic. Only matched traffic
is counted in the jail statistics.
diff --git a/module/bsnmp-jails.c b/module/bsnmp-jails.c
index 5e5e030..b88cdd7 100644
--- a/module/bsnmp-jails.c
+++ b/module/bsnmp-jails.c
@@ -130,6 +130,17 @@ TAILQ_HEAD(monitor_list, monitor);
/* list of monitor structures */
static struct monitor_list monitors = TAILQ_HEAD_INITIALIZER (monitors);
+/* Represents a 'top level' process */
+struct ptop {
+ pid_t pid;
+ uint32_t cpu_time;
+
+ #define PROC_GONE 0
+ #define PROC_EXISTS 1
+ #define PROC_NEW 2
+ int status;
+};
+
struct jaildat {
uint32_t index;
TAILQ_ENTRY(jaildat) link;
@@ -152,9 +163,15 @@ struct jaildat {
uint64_t in_packets;
uint64_t out_octets;
uint64_t out_packets;
- uint32_t n_processes;
uint64_t disk_space;
uint64_t disk_files;
+ uint32_t cpu_time_total;
+ uint32_t cpu_time_offset;
+ uint32_t n_processes;
+
+ /* Top process information */
+ uint32_t n_ptops;
+ struct ptop *ptops;
};
TAILQ_HEAD(jaildat_list, jaildat);
@@ -207,8 +224,21 @@ emsg(const char *format, ...)
va_start (va, format);
vsyslog (LOG_ERR, format, va);
vfprintf (stderr, format, va);
+ fputc ('\n', stderr);
+ va_end (va);
+}
+
+#if 0
+static void
+msg(const char *format, ...)
+{
+ va_list va;
+ va_start (va, format);
+ vfprintf (stderr, format, va);
+ fputc ('\n', stderr);
va_end (va);
}
+#endif
typedef void* (*if_enumerator) (struct ifreq *ifr, void* data);
@@ -787,12 +817,75 @@ measure_start (void *unused)
* PROCESS LOOKUPS
*/
+static int
+process_compar_kp_pid (const void *a, const void *b)
+{
+ pid_t pida, pidb;
+
+ pida = ((const struct kinfo_proc*)a)->ki_pid;
+ pidb = ((const struct kinfo_proc*)b)->ki_pid;
+
+ if (pida == pidb)
+ return 0;
+
+ /* Note we're sorting in reverse */
+ return (pida < pidb) ? 1 : -1;
+}
+
+static int
+process_compapre_kp_ppid_pid (const void *a, const void *b)
+{
+ pid_t pida, pidb;
+
+ pida = ((const struct kinfo_proc*)a)->ki_ppid;
+ pidb = ((const struct kinfo_proc*)b)->ki_pid;
+
+ if (pida == pidb)
+ return 0;
+
+ /* Note we're sorting in reverse */
+ return (pida < pidb) ? 1 : -1;
+}
+
+static int
+process_compare_kp_ptop_pid (const void *a, const void *b)
+{
+ pid_t pida, pidb;
+
+ pida = ((const struct kinfo_proc*)a)->ki_pid;
+ pidb = ((const struct ptop*)b)->pid;
+
+ if (pida == pidb)
+ return 0;
+
+ /* Note we're sorting in reverse */
+ return (pida < pidb) ? 1 : -1;
+}
+
+static int
+process_compare_ptop_pid (const void *a, const void *b)
+{
+ pid_t pida, pidb;
+
+ pida = ((const struct ptop*)a)->pid;
+ pidb = ((const struct ptop*)b)->pid;
+
+ if (pida == pidb)
+ return 0;
+
+ /* Note we're sorting in reverse */
+ return (pida < pidb) ? 1 : -1;
+}
+
static void
process_refresh_all (void)
{
+ struct kinfo_proc *kp, *tkp, *k;
struct jaildat *jail;
- struct kinfo_proc *kp;
- int nentries, i, id;
+ struct ptop *ptop;
+ int nentries, i, jid;
+ uint32_t cpu_time;
+ void *alloc;
/* Get a process listing */
kp = kvm_getprocs (kvm_handle, KERN_PROC_PROC, 0, &nentries);
@@ -801,20 +894,100 @@ process_refresh_all (void)
return;
}
- /* Clear process counts for each jail */
- TAILQ_FOREACH (jail, &jaildats, link)
+ /* Sort the input we get, in reverse */
+ qsort (kp, nentries, sizeof (*kp), process_compar_kp_pid);
+
+ /* Mark all processes in the jail for later sweep */
+ TAILQ_FOREACH (jail, &jaildats, link) {
+ for (i = 0; i < jail->n_ptops; ++i)
+ jail->ptops[i].status = PROC_GONE;
+
jail->n_processes = 0;
+ jail->cpu_time_total = jail->cpu_time_offset;
+ }
/* Okay now loop and add to each process's jail */
for (i = 0; i < nentries; i++) {
- id = kp[i].ki_jid;
- if (id == 0)
+ jid = kp[i].ki_jid;
+
+ /* No jail? */
+ if (jid == 0)
continue;
- jail = hsh_get (jaildat_by_id, &id, sizeof (id));
- if (jail)
- jail->n_processes++;
+ jail = hsh_get (jaildat_by_id, &jid, sizeof (jid));
+ if (jail == NULL)
+ continue;
+
+ jail->n_processes += 1;
+
+ /* Find the top level process within jail to account to */
+ tkp = &kp[i];
+ for (;;) {
+ if (tkp->ki_pid == tkp->ki_ppid)
+ break;
+ k = bsearch (tkp, kp, nentries, sizeof (*kp), process_compapre_kp_ppid_pid);
+ if (k == NULL || k->ki_jid != jid)
+ break;
+ tkp = k;
+ }
+
+ /* Find top process for that pid */
+ ptop = bsearch (tkp, jail->ptops, jail->n_ptops,
+ sizeof (struct ptop), process_compare_kp_ptop_pid);
+ if (ptop == NULL) {
+ alloc = realloc (jail->ptops, (jail->n_ptops + 1) * sizeof (struct ptop));
+ if (alloc == NULL) {
+ emsg ("out of memory");
+ continue;
+ }
+
+ jail->ptops = alloc;
+ ptop = jail->ptops + jail->n_ptops;
+ jail->n_ptops += 1;
+
+ ptop->pid = tkp->ki_pid;
+ ptop->cpu_time = 0;
+ ptop->status = PROC_NEW;
+ }
+
+ /* Account CPU time to this process */
+ cpu_time = kp[i].ki_runtime + kp[i].ki_childtime.tv_usec;
+ cpu_time /= 10000;
+ cpu_time += kp[i].ki_childtime.tv_sec * 100;
+
+ if (ptop->status == PROC_GONE) {
+ ptop->cpu_time = 0;
+ ptop->status = PROC_EXISTS;
+ }
+
+ ptop->cpu_time += cpu_time;
+ jail->cpu_time_total += cpu_time;
+
+ /* Sort the array if added */
+ qsort (jail->ptops, jail->n_ptops, sizeof (struct ptop), process_compare_ptop_pid);
+ }
+
+ TAILQ_FOREACH (jail, &jaildats, link) {
+
+ for (i = 0; i < jail->n_ptops; ++i) {
+ if (jail->ptops[i].status != PROC_GONE)
+ continue;
+
+ /*
+ * Add time to the cpu_time_offset if it's a 'top level'
+ * process that's going away.
+ */
+
+ jail->cpu_time_offset += jail->ptops[i].cpu_time;
+ jail->cpu_time_total += jail->ptops[i].cpu_time;
+
+ /* Remove nonexistant ptop */
+ memmove (jail->ptops + i, jail->ptops + i + 1,
+ (jail->n_ptops - i) * sizeof (struct ptop));
+ jail->n_ptops -= 1;
+ i -= 1;
+ }
}
}
@@ -858,6 +1031,9 @@ jail_free (struct jaildat *jail)
jaildat_count--;
}
+ free (jail->ptops);
+ jail->ptops = NULL;
+
free (jail);
}
@@ -1262,6 +1438,9 @@ op_jailentry (struct snmp_context *ctx, struct snmp_value *value,
case LEAF_jailProcesses:
value->v.integer = jail->n_processes;
return SNMP_ERR_NOERROR;
+ case LEAF_jailCpuTime:
+ value->v.integer = jail->cpu_time_total;
+ return SNMP_ERR_NOERROR;
case LEAF_jailDiskSpace:
value->v.counter64 = jail->disk_space;
return SNMP_ERR_NOERROR;
diff --git a/module/jails-tree.def b/module/jails-tree.def
index 2efcb4a..06bb10f 100644
--- a/module/jails-tree.def
+++ b/module/jails-tree.def
@@ -53,6 +53,7 @@
(13 jailOutPackets COUNTER64 GET)
(20 jailProcesses INTEGER GET)
+ (21 jailCpuTime TIMETICKS GET)
(30 jailDiskSpace COUNTER64 GET)
(31 jailDiskFiles COUNTER64 GET)