From: Scott Cheloha Subject: systat(1): iostat: compute rates with elapsed time To: tech@openbsd.org Date: Thu, 4 Apr 2024 14:18:54 -0500 In TIME mode, the iostat view sets etime to naptime before computing rates. This is wrong. The elapsed time is never exactly naptime. Instead, measure the real elapsed time between each print_io() call. We need to read the clock during every call, regardless of mode, because the mode can change between updates. This patch also changes the iostat view's behavior during the first update. During that first update, iostat has no prior data to use when computing rates. Currently, the resulting output is "totals since boot divided by naptime". Here's a concrete example: $ systat -d1 io 1 DEVICE READ WRITE RTPS WTPS SEC sd0 4544872K 7316640K 365102 687727 101.9 sd1 0 0 0 0 0.0 Totals 4544872K 7316640K 365102 687727 101.9 $ systat -d1 io 2 DEVICE READ WRITE RTPS WTPS SEC sd0 2272436K 3658335K 182551 343866 50.9 sd1 0 0 0 0 0.0 Totals 2272436K 3658335K 182551 343866 50.9 $ systat -d io 0.5 DEVICE READ WRITE RTPS WTPS SEC sd0 9089744K 14295M 730204 1376152 204.7 sd1 0 0 0 0 0.0 Totals 9089744K 14295M 730204 1376152 204.7 The second output is half the first (1 / 2). The third output is twice the first (1 / 0.5). This is difficult to explain, let alone document. The numbers are also meaningless. IMHO, if we're going to print something during that first update, it makes more sense to unconditionally set etime to 1.0 and print the totals. Thoughts? ok? Index: iostat.c =================================================================== RCS file: /cvs/src/usr.bin/systat/iostat.c,v diff -u -p -r1.50 iostat.c --- iostat.c 14 Aug 2021 14:22:26 -0000 1.50 +++ iostat.c 4 Apr 2024 19:15:29 -0000 @@ -166,13 +166,23 @@ read_io(void) void print_io(void) { + static struct timespec prev; + struct timespec elapsed, now; + static int first = 1; int n, count = 0; int curr; - if (state == BOOT) + clock_gettime(CLOCK_MONOTONIC, &now); + if (first) { + first = 0; etime = 1.0; - else - etime = naptime; + } else if (state == BOOT) { + etime = 1.0; + } else { + timespecsub(&now, &prev, &elapsed); + etime = elapsed.tv_sec + elapsed.tv_nsec / 1000000000.0; + } + prev = now; /* XXX engine internals: save and restore curr_line for bcache */ curr = curr_line;