systat - Enhance systat -pv
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 24 Aug 2010 04:55:55 +0000 (21:55 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 24 Aug 2010 04:55:55 +0000 (21:55 -0700)
* Enhance the -pv option to display the contention points on all cpus

usr.bin/systat/Makefile
usr.bin/systat/symbols.c [new file with mode: 0644]
usr.bin/systat/symbols.h [new file with mode: 0644]
usr.bin/systat/vmmeter.c

index e8f4619..eb67d47 100644 (file)
@@ -5,7 +5,7 @@ PROG=   systat
 CFLAGS+=-DINET6 -I${.CURDIR}/../../sys
 SRCS=  cmds.c cmdtab.c convtbl.c devs.c fetch.c ifcmds.c ifstat.c iostat.c \
        keyboard.c main.c mbufs.c netcmds.c netstat.c pigs.c sensors.c swap.c \
-       icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c
+       icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c symbols.c
 DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM} ${LIBDEVSTAT} ${LIBKINFO}
 LDADD= -lcurses -ltermcap -lm -lkvm -ldevstat -lkinfo
 BINGRP=        kmem
diff --git a/usr.bin/systat/symbols.c b/usr.bin/systat/symbols.c
new file mode 100644 (file)
index 0000000..3f821ba
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <devinfo.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <evtr.h>
+#include <stdarg.h>
+#include "symbols.h"
+
+struct symdata {
+       TAILQ_ENTRY(symdata) link;
+       const char *symname;
+       char *symaddr;
+       char symtype;
+};
+
+static TAILQ_HEAD(symlist, symdata) symlist;
+static struct symdata *symcache;
+static char *symbegin;
+static char *symend;
+
+void
+read_symbols(const char *file)
+{
+       char buf[256];
+       char cmd[256];
+       size_t buflen = sizeof(buf);
+       FILE *fp;
+       struct symdata *sym;
+       char *s1;
+       char *s2;
+       char *s3;
+
+       TAILQ_INIT(&symlist);
+
+       if (file == NULL) {
+               if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
+                       file = "/boot/kernel";
+               else
+                       file = buf;
+       }
+       snprintf(cmd, sizeof(cmd), "nm -n %s", file);
+       if ((fp = popen(cmd, "r")) != NULL) {
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                   s1 = strtok(buf, " \t\n");
+                   s2 = strtok(NULL, " \t\n");
+                   s3 = strtok(NULL, " \t\n");
+                   if (s1 && s2 && s3) {
+                       sym = malloc(sizeof(struct symdata));
+                       sym->symaddr = (char *)strtoul(s1, NULL, 16);
+                       sym->symtype = s2[0];
+                       sym->symname = strdup(s3);
+                       if (strcmp(s3, "kernbase") == 0)
+                               symbegin = sym->symaddr;
+                       if (strcmp(s3, "end") == 0)
+                               symend = sym->symaddr;
+                       TAILQ_INSERT_TAIL(&symlist, sym, link);
+                   }
+               }
+               pclose(fp);
+       }
+       symcache = TAILQ_FIRST(&symlist);
+}
+
+const char *
+address_to_symbol(void *kptr, struct save_ctx *ctx)
+{
+       char *buf = ctx->save_buf;
+       int size = sizeof(ctx->save_buf);
+
+       if (symcache == NULL ||
+          (char *)kptr < symbegin || (char *)kptr >= symend
+       ) {
+               snprintf(buf, size, "%p", kptr);
+               return(buf);
+       }
+       while ((char *)symcache->symaddr < (char *)kptr) {
+               if (TAILQ_NEXT(symcache, link) == NULL)
+                       break;
+               symcache = TAILQ_NEXT(symcache, link);
+       }
+       while ((char *)symcache->symaddr > (char *)kptr) {
+               if (symcache != TAILQ_FIRST(&symlist))
+                       symcache = TAILQ_PREV(symcache, symlist, link);
+       }
+       snprintf(buf, size, "%s+%d", symcache->symname,
+               (int)((char *)kptr - symcache->symaddr));
+       return(buf);
+}
diff --git a/usr.bin/systat/symbols.h b/usr.bin/systat/symbols.h
new file mode 100644 (file)
index 0000000..459ba83
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct save_ctx {
+       char save_buf[512];
+       const void *save_kptr;
+};
+
+void read_symbols(const char *);
+const char *address_to_symbol(void *, struct save_ctx *);
index d798549..11b5e51 100644 (file)
@@ -2,6 +2,7 @@
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <sys/vmmeter.h>
+#include "symbols.h"
 
 #include <err.h>
 #include <kinfo.h>
@@ -15,6 +16,7 @@
 
 #define X_START                1
 #define CPU_START      1
+#define CPU_STARTX     (3 + vmm_ncpus)
 #define CPU_LABEL_W    7
 
 #define DRAW_ROW(n, y, w, fmt, args...) \
@@ -27,6 +29,8 @@ static int vmm_ncpus;
 static int vmm_fetched;
 static struct vmmeter *vmm_cur, *vmm_prev;
 static struct kinfo_cputime *vmm_cptime_cur, *vmm_cptime_prev;
+static struct save_ctx symctx;
+static int symbols_read;
 
 static void
 getvmm(void)
@@ -107,6 +111,15 @@ do { \
 
 #undef CPUV
 #undef CPUD
+#define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
+
+               n = X_START + CPU_LABEL_W;
+
+               DRAW_ROW(n, CPU_STARTX + i, 15, "%-*s", CPUC(i, msg));
+               DRAW_ROW(n, CPU_STARTX + i, 35, "%-*s",
+                       address_to_symbol((void *)(intptr_t)CPUC(i, stallpc),
+                                         &symctx));
+#undef CPUC
        }
 }
 
@@ -130,22 +143,34 @@ labelvmm(void)
 
        n = X_START + CPU_LABEL_W;
 
-       DRAW_ROW(n, 0, 6, "%*s", "timer");
-       DRAW_ROW(n, 0, 8, "%*s", "ipi");
-       DRAW_ROW(n, 0, 8, "%*s", "extint");
-       DRAW_ROW(n, 0, 7, "%*s", "user%");
-       DRAW_ROW(n, 0, 7, "%*s", "nice%");
-       DRAW_ROW(n, 0, 7, "%*s", "sys%");
-       DRAW_ROW(n, 0, 7, "%*s", "intr%");
-       DRAW_ROW(n, 0, 7, "%*s", "idle%");
+       DRAW_ROW(n, CPU_START - 1, 6, "%*s", "timer");
+       DRAW_ROW(n, CPU_START - 1, 8, "%*s", "ipi");
+       DRAW_ROW(n, CPU_START - 1, 8, "%*s", "extint");
+       DRAW_ROW(n, CPU_START - 1, 7, "%*s", "user%");
+       DRAW_ROW(n, CPU_START - 1, 7, "%*s", "nice%");
+       DRAW_ROW(n, CPU_START - 1, 7, "%*s", "sys%");
+       DRAW_ROW(n, CPU_START - 1, 7, "%*s", "intr%");
+       DRAW_ROW(n, CPU_START - 1, 7, "%*s", "idle%");
 
        for (i = 0; i < vmm_ncpus; ++i)
                mvprintw(CPU_START + i, X_START, "cpu%d", i);
+
+       n = X_START + CPU_LABEL_W;
+       DRAW_ROW(n, CPU_STARTX - 1, 15, "%-*s", "contention");
+       DRAW_ROW(n, CPU_STARTX - 1, 35, "%-*s", "function");
+
+       for (i = 0; i < vmm_ncpus; ++i)
+               mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
 }
 
 WINDOW *
 openvmm(void)
 {
+       if (symbols_read == 0) {
+               symbols_read = 1;
+               read_symbols(NULL);
+       }
+
        if (kinfo_get_cpus(&vmm_ncpus))
                err(1, "kinfo_get_cpus");