From 4d983f7917ea342ad7c6d58fd6de4b3b443c7786 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 23 Aug 2010 21:55:55 -0700 Subject: [PATCH] systat - Enhance systat -pv * Enhance the -pv option to display the contention points on all cpus --- usr.bin/systat/Makefile | 2 +- usr.bin/systat/symbols.c | 133 +++++++++++++++++++++++++++++++++++++++ usr.bin/systat/symbols.h | 41 ++++++++++++ usr.bin/systat/vmmeter.c | 41 +++++++++--- 4 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 usr.bin/systat/symbols.c create mode 100644 usr.bin/systat/symbols.h diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index e8f4619a0d..eb67d471f6 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -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 index 0000000000..3f821ba37e --- /dev/null +++ b/usr.bin/systat/symbols.c @@ -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 + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..459ba830b3 --- /dev/null +++ b/usr.bin/systat/symbols.h @@ -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 + * + * 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 *); diff --git a/usr.bin/systat/vmmeter.c b/usr.bin/systat/vmmeter.c index d798549e4f..11b5e51c42 100644 --- a/usr.bin/systat/vmmeter.c +++ b/usr.bin/systat/vmmeter.c @@ -2,6 +2,7 @@ #include #include #include +#include "symbols.h" #include #include @@ -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"); -- 2.41.0