systat(1): vmstat: measure elapsed time with clock_gettime(2) instead of ticks
authorcheloha <cheloha@openbsd.org>
Sun, 4 Dec 2022 18:01:57 +0000 (18:01 +0000)
committercheloha <cheloha@openbsd.org>
Sun, 4 Dec 2022 18:01:57 +0000 (18:01 +0000)
The vmstat view in systat(1) should not use statclock() ticks to count
elapsed time.  First, ticks are low resolution.  Second, the statclock
is sometimes randomized, so each tick is not necessarily of equal
length.  Third, we're counting ticks from every CPU on the system, so
every rate in the view is divided by the number of CPUs.  For example,
on an amd64 system with 8 CPUs you currently see:

     200 clock

... when the true clock interrupt rate on that system is 1600.

Instead, measure elapsed time with clock_gettime(2).  Use CLOCK_UPTIME
here so we exclude time when the system is suspended.  With this
change we no longer need "stathz" or "hertz".  We can also get rid of
the anachronistic secondary clock failure test.

Prompted by dlg@ and jmatthew@.  deraadt@ says this has been in snaps
since 2022-11-21; no complaints.

Link: https://marc.info/?l=openbsd-tech&m=166898960831136&w=2
ok dlg@ deraadt@

usr.bin/systat/main.c
usr.bin/systat/systat.h
usr.bin/systat/vmstat.c

index 7a4225c..ce7851d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.76 2021/07/12 15:09:20 beck Exp $       */
+/* $OpenBSD: main.c,v 1.77 2022/12/04 18:01:57 cheloha Exp $    */
 /*
  * Copyright (c) 2001, 2007 Can Erkin Acar
  * Copyright (c) 2001 Daniel Hartmeier
@@ -65,7 +65,7 @@ double        avenrun[3];
 double naptime = 5.0;
 int    verbose = 1;            /* to report kvm read errs */
 int    nflag = 1;
-int    ut, hz, stathz;
+int    ut, hz;
 char    hostname[HOST_NAME_MAX+1];
 WINDOW  *wnd;
 int    CMDLINE;
@@ -414,7 +414,6 @@ gethz(void)
        mib[1] = KERN_CLOCKRATE;
        if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
                return;
-       stathz = cinf.stathz;
        hz = cinf.hz;
 }
 
index e7d2007..776be5a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: systat.h,v 1.24 2021/01/18 00:49:09 mortimer Exp $    */
+/*     $OpenBSD: systat.h,v 1.25 2022/12/04 18:01:57 cheloha Exp $     */
 /*     $NetBSD: systat.h,v 1.2 1995/01/20 08:52:14 jtc Exp $   */
 
 /*-
@@ -58,7 +58,7 @@ extern kvm_t  *kd;
 extern long    ntext;
 extern int     *dk_select;
 extern int     dk_ndrive;
-extern int     hz, stathz;
+extern int     hz;
 extern double  naptime;
 extern size_t  nhosts;
 extern size_t  nports;
index ce22f73..9cb4327 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vmstat.c,v 1.94 2022/02/22 17:35:01 deraadt Exp $     */
+/*     $OpenBSD: vmstat.c,v 1.95 2022/12/04 18:01:57 cheloha Exp $     */
 /*     $NetBSD: vmstat.c,v 1.5 1996/05/10 23:16:40 thorpej Exp $       */
 
 /*-
@@ -98,7 +98,6 @@ int select_vm(void);
 int vm_keyboard_callback(int);
 
 static time_t t;
-static float hertz;
 static int nintr;
 static long *intrloc;
 static char **intrname;
@@ -170,7 +169,6 @@ initvmstat(void)
        int mib[4], i;
        size_t size;
 
-       hertz = stathz;
        if (!dkinit(1))
                return(0);
 
@@ -323,7 +321,6 @@ labelkre(void)
                Y(fld); \
                putint((int)((float)s.fld/etime + 0.5), l, c, w); \
        } while (0)
-#define MAXFAIL 5
 
 static char cpuchar[] = { '|', '@', '=', '>', ' ' };
 static char cpuorder[] = { CP_INTR, CP_SPIN, CP_SYS, CP_USER, CP_IDLE };
@@ -331,33 +328,27 @@ static    char cpuorder[] = { CP_INTR, CP_SPIN, CP_SYS, CP_USER, CP_IDLE };
 void
 showkre(void)
 {
+       static struct timespec prev;
+       struct timespec elapsed, now;
        float f1, f2;
        int psiz;
        u_int64_t inttotal, intcnt;
        int i, l, c;
-       static int failcnt = 0, first_run = 0;
+       static int first_run = 0;
        double etime;
 
+       clock_gettime(CLOCK_UPTIME, &now);
+       timespecsub(&now, &prev, &elapsed);
+       prev = now;
        if (state == TIME) {
                if (!first_run) {
                        first_run = 1;
                        return;
                }
        }
-       etime = 0;
-       for (i = 0; i < CPUSTATES; i++) {
+       etime = elapsed.tv_sec + elapsed.tv_nsec / 1000000000.0;
+       for (i = 0; i < CPUSTATES; i++)
                X(cpustats.cs_time);
-               etime += s.cpustats.cs_time[i];
-       }
-       if (etime < 5.0) {      /* < 5 ticks - ignore this trash */
-               if (failcnt++ >= MAXFAIL) {
-                       error("The alternate system clock has died!");
-                       failcnt = 0;
-               }
-               return;
-       }
-       failcnt = 0;
-       etime /= hertz;
        inttotal = 0;
        for (i = 0; i < nintr; i++) {
                t = intcnt = s.intrcnt[i];