Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/vmstat Defer nlist processing until we know we need ...



details:   https://anonhg.NetBSD.org/src/rev/a2216aff046a
branches:  trunk
changeset: 761488:a2216aff046a
user:      matt <matt%NetBSD.org@localhost>
date:      Sat Jan 29 18:10:08 2011 +0000

description:
Defer nlist processing until we know we need to it.  If everything can be
obtained via sysctl, we can skip it entirely.  This means we can run even
if not setgid.

getuptime will now use sysctl/clock_gettime if memf is NULL.
doevcnt now sues sysctl(kern.evcnt) is memf is NULL.  It falls back to
groveling if sysctl returns an error of ENOENT.
dointr will call doevcnt to evcnt based intr stats.

diffstat:

 usr.bin/vmstat/vmstat.c |  253 ++++++++++++++++++++++++++++++++---------------
 1 files changed, 169 insertions(+), 84 deletions(-)

diffs (truncated from 408 to 300 lines):

diff -r 284de030cfc9 -r a2216aff046a usr.bin/vmstat/vmstat.c
--- a/usr.bin/vmstat/vmstat.c   Sat Jan 29 17:35:23 2011 +0000
+++ b/usr.bin/vmstat/vmstat.c   Sat Jan 29 18:10:08 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vmstat.c,v 1.175 2010/12/25 23:36:59 christos Exp $ */
+/* $NetBSD: vmstat.c,v 1.176 2011/01/29 18:10:08 matt Exp $ */
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
 #if 0
 static char sccsid[] = "@(#)vmstat.c   8.2 (Berkeley) 3/1/95";
 #else
-__RCSID("$NetBSD: vmstat.c,v 1.175 2010/12/25 23:36:59 christos Exp $");
+__RCSID("$NetBSD: vmstat.c,v 1.176 2011/01/29 18:10:08 matt Exp $");
 #endif
 #endif /* not lint */
 
@@ -298,7 +298,7 @@
 void   cpucounters(struct cpu_counter *);
 void   deref_kptr(const void *, void *, size_t, const char *);
 void   drvstats(int *);
-void   doevcnt(int verbose);
+void   doevcnt(int verbose, int type);
 void   dohashstat(int, int, const char *);
 void   dointr(int verbose);
 void   domem(void);
@@ -311,6 +311,7 @@
 void   kread(struct nlist *, int, void *, size_t);
 int    kreadc(struct nlist *, int, void *, size_t);
 void   needhdr(int);
+void   getnlist(int);
 long   getuptime(void);
 void   printhdr(void);
 long   pct(long, long);
@@ -331,6 +332,8 @@
 
 static const int vmmeter_mib[] = { CTL_VM, VM_METER };
 static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 };
+static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME };
+static char kvm_errbuf[_POSIX2_LINE_MAX];
 
 int
 main(int argc, char *argv[])
@@ -338,10 +341,8 @@
        int c, todo, verbose, wide;
        struct timespec interval;
        int reps;
-       char errbuf[_POSIX2_LINE_MAX];
        gid_t egid = getegid();
        const char *histname, *hashname;
-       size_t i;
 
        histname = hashname = NULL;
        (void)setegid(getgid());
@@ -430,39 +431,16 @@
        else
                (void)setegid(egid);
 
-       kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
-       if (kd == NULL)
-               errx(1, "kvm_openfiles: %s", errbuf);
+       kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, kvm_errbuf);
+       if (kd == NULL) {
+               if (nlistf != NULL || memf != NULL) {
+                       errx(1, "kvm_openfiles: %s", kvm_errbuf);
+               }
+       }
 
        if (nlistf == NULL && memf == NULL)
                (void)setgid(getgid());
 
-       if ((c = kvm_nlist(kd, namelist)) != 0) {
-               int doexit = 0;
-               if (c == -1)
-                       errx(1, "kvm_nlist: %s %s", "namelist", kvm_geterr(kd));
-               for (i = 0; i < sizeof(namelist) / sizeof(namelist[0])-1; i++)
-                       if (namelist[i].n_type == 0 &&
-                           i != X_TIME_SECOND &&
-                           i != X_TIME) {
-                               if (doexit++ == 0)
-                                       (void)fprintf(stderr,
-                                           "%s: undefined symbols:",
-                                           getprogname());
-                               (void)fprintf(stderr, " %s",
-                                   namelist[i].n_name);
-                       }
-               if (doexit) {
-                       (void)fputc('\n', stderr);
-                       exit(1);
-               }
-       }
-       if (todo & INTRSTAT)
-               (void) kvm_nlist(kd, intrnl);
-       if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
-               errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
-       if (kvm_nlist(kd, histnl) == -1)
-               errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
 
        if (todo & VMSTAT) {
                struct winsize winsize;
@@ -531,7 +509,7 @@
                                (void)putchar('\n');
                        }
                        if (todo & EVCNTSTAT) {
-                               doevcnt(verbose);
+                               doevcnt(verbose, EVCNT_TYPE_ANY);
                                (void)putchar('\n');
                        }
                        if (todo & (HASHLIST|HASHSTAT)) {
@@ -560,6 +538,59 @@
        return 0;
 }
 
+void
+getnlist(int todo)
+{
+       static int namelist_done = 0;
+       static int hash_done = 0;
+       static int hist_done = 0;
+       static int intr_done = 0;
+       int c;
+       size_t i;
+
+       if (kd == NULL)
+               errx(1, "kvm_openfiles: %s", kvm_errbuf);
+
+       if (!namelist_done) {
+               namelist_done = 1;
+               if ((c = kvm_nlist(kd, namelist)) != 0) {
+                       int doexit = 0;
+                       if (c == -1)
+                               errx(1, "kvm_nlist: %s %s",
+                                   "namelist", kvm_geterr(kd));
+                       for (i = 0; i < __arraycount(namelist)-1; i++)
+                               if (namelist[i].n_type == 0 &&
+                                   i != X_TIME_SECOND &&
+                                   i != X_TIME) {
+                                       if (doexit++ == 0)
+                                               (void)fprintf(stderr,
+                                                   "%s: undefined symbols:",
+                                                   getprogname());
+                                       (void)fprintf(stderr, " %s",
+                                           namelist[i].n_name);
+                               }
+                       if (doexit) {
+                               (void)fputc('\n', stderr);
+                               exit(1);
+                       }
+               }
+       }
+       if ((todo & INTRSTAT) && !intr_done) {
+               intr_done = 1;
+               (void) kvm_nlist(kd, intrnl);
+       }
+       if ((todo & HASHLIST) && !hash_done) {
+               hash_done = 1;
+               if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
+                       errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
+       }
+       if ((todo & (HISTLIST|HISTDUMP)) && !hist_done) {
+               hist_done = 1;
+               if (kvm_nlist(kd, histnl) == -1)
+                       errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
+       }
+}
+
 char **
 choosedrives(char **argv)
 {
@@ -598,21 +629,32 @@
 long
 getuptime(void)
 {
-       static struct timeval boottime;
-       struct timeval now;
+       static struct timespec boottime;
+       struct timespec now;
        time_t uptime, nowsec;
 
-       if (boottime.tv_sec == 0)
-               kread(namelist, X_BOOTTIME, &boottime, sizeof(boottime));
-       if (kreadc(namelist, X_TIME_SECOND, &nowsec, sizeof(nowsec))) {
-               /*
-                * XXX this assignment dance can be removed once timeval tv_sec
-                * is SUS mandated time_t
-                */
-               now.tv_sec = nowsec;
-               now.tv_usec = 0;
+       if (memf == NULL) {
+               if (boottime.tv_sec == 0) {
+                       size_t buflen = sizeof(boottime);
+                       if (sysctl(boottime_mib, __arraycount(boottime_mib),
+                           &boottime, &buflen, NULL, 0) == -1)
+                               warn("Can't get boottime");
+               }
+               clock_gettime(CLOCK_REALTIME, &now);
        } else {
-               kread(namelist, X_TIME, &now, sizeof(now));
+               if (boottime.tv_sec == 0)
+                       kread(namelist, X_BOOTTIME, &boottime,
+                           sizeof(boottime));
+               if (kreadc(namelist, X_TIME_SECOND, &nowsec, sizeof(nowsec))) {
+                       /*
+                        * XXX this assignment dance can be removed once
+                        * timeval tv_sec is SUS mandated time_t
+                        */
+                       now.tv_sec = nowsec;
+                       now.tv_nsec = 0;
+               } else {
+                       kread(namelist, X_TIME, &now, sizeof(now));
+               }
        }
        uptime = now.tv_sec - boottime.tv_sec;
        if (uptime <= 0 || uptime > 60*60*24*365*10)
@@ -1049,10 +1091,8 @@
        unsigned long long inttotal, uptime;
        int nintr, inamlen;
        char *intrname, *ointrname;
-       struct evcntlist allevents;
-       struct evcnt evcnt, *evptr;
-       char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
 
+       getnlist(INTRSTAT);
        inttotal = 0;
        uptime = getuptime();
        (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
@@ -1079,46 +1119,78 @@
                free(ointrname);
        }
 
-       kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
-       evptr = TAILQ_FIRST(&allevents);
-       while (evptr) {
-               deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
-               evptr = TAILQ_NEXT(&evcnt, ev_list);
-               if (evcnt.ev_type != EVCNT_TYPE_INTR)
-                       continue;
-
-               if (evcnt.ev_count == 0 && !verbose)
-                       continue;
-
-               deref_kptr(evcnt.ev_group, evgroup,
-                   (size_t)evcnt.ev_grouplen + 1, "event chain trashed");
-               deref_kptr(evcnt.ev_name, evname,
-                   (size_t)evcnt.ev_namelen + 1, "event chain trashed");
-
-               (void)printf("%s %s%*s %16llu %8llu\n", evgroup, evname,
-                   34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
-                   (unsigned long long)evcnt.ev_count,
-                   (unsigned long long)(evcnt.ev_count / uptime));
-
-               inttotal += evcnt.ev_count++;
-       }
-       (void)printf("%-34s %16llu %8llu\n", "Total", inttotal,
-           (unsigned long long)(inttotal / uptime));
+       doevcnt(verbose, EVCNT_TYPE_INTR);
 }
 
 void
-doevcnt(int verbose)
+doevcnt(int verbose, int type)
 {
-       static const char * evtypes [] = { "misc", "intr", "trap" };
-       unsigned long long uptime;
+       static const char * const evtypes [] = { "misc", "intr", "trap" };
+       uint64_t counttotal, uptime;
        struct evcntlist allevents;
        struct evcnt evcnt, *evptr;
        char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
 
-       /* XXX should print type! */
-
+       counttotal = 0;
        uptime = getuptime();
        (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", "type");
+
+       if (memf == NULL) do {
+               const int mib[4] = { CTL_KERN, KERN_EVCNT, type,
+                   verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO };
+               size_t buflen = 0;
+               void *buf = NULL;
+               const struct evcnt_sysctl *evs, *last_evs;
+               for (;;) {
+                       size_t newlen;
+                       int error;
+                       if (buflen)
+                               buf = malloc(buflen);
+                       error = sysctl(mib, __arraycount(mib),
+                           buf, &newlen, NULL, 0);
+                       if (error) {
+                               /* if the sysctl is unknown, try groveling */
+                               if (error == ENOENT)
+                                       break;
+                               perror("sysctl: kern.evcnt");
+                               if (buf)
+                                       free(buf);
+                               return;
+                       }
+                       if (newlen <= buflen) {



Home | Main Index | Thread Index | Old Index