iostat.c revision 175250
1101099Srwatson/* 2145412Strhodes * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry 3126097Srwatson * All rights reserved. 4145412Strhodes * 5101099Srwatson * Redistribution and use in source and binary forms, with or without 6101099Srwatson * modification, are permitted provided that the following conditions 7101099Srwatson * are met: 8145412Strhodes * 1. Redistributions of source code must retain the above copyright 9101099Srwatson * notice, this list of conditions and the following disclaimer. 10106393Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11106393Srwatson * notice, this list of conditions and the following disclaimer in the 12106393Srwatson * documentation and/or other materials provided with the distribution. 13106393Srwatson * 3. The name of the author may not be used to endorse or promote products 14101099Srwatson * derived from this software without specific prior written permission. 15101099Srwatson * 16101099Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17101099Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18101099Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19101099Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20101099Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21101099Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22101099Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23101099Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24101099Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26101099Srwatson * SUCH DAMAGE. 27101099Srwatson * 28101099Srwatson * $FreeBSD: head/usr.sbin/iostat/iostat.c 175250 2008-01-12 20:37:06Z maxim $ 29101099Srwatson */ 30101099Srwatson/* 31101099Srwatson * Parts of this program are derived from the original FreeBSD iostat 32101099Srwatson * program: 33101099Srwatson */ 34101099Srwatson/*- 35101099Srwatson * Copyright (c) 1986, 1991, 1993 36101099Srwatson * The Regents of the University of California. All rights reserved. 37101099Srwatson * 38136774Srwatson * Redistribution and use in source and binary forms, with or without 39101099Srwatson * modification, are permitted provided that the following conditions 40101099Srwatson * are met: 41101099Srwatson * 1. Redistributions of source code must retain the above copyright 42101099Srwatson * notice, this list of conditions and the following disclaimer. 43101099Srwatson * 2. Redistributions in binary form must reproduce the above copyright 44101099Srwatson * notice, this list of conditions and the following disclaimer in the 45101099Srwatson * documentation and/or other materials provided with the distribution. 46101099Srwatson * 3. All advertising materials mentioning features or use of this software 47101099Srwatson * must display the following acknowledgement: 48101099Srwatson * This product includes software developed by the University of 49101099Srwatson * California, Berkeley and its contributors. 50145412Strhodes * 4. Neither the name of the University nor the names of its contributors 51101099Srwatson * may be used to endorse or promote products derived from this software 52101099Srwatson * without specific prior written permission. 53101099Srwatson * 54145412Strhodes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55101099Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56101099Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57101099Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58101099Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59101099Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60101099Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61101099Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62101099Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64134132Strhodes * SUCH DAMAGE. 65101099Srwatson */ 66101099Srwatson/* 67101099Srwatson * Ideas for the new iostat statistics output modes taken from the NetBSD 68101099Srwatson * version of iostat: 69101099Srwatson */ 70101099Srwatson/* 71101099Srwatson * Copyright (c) 1996 John M. Vinopal 72101099Srwatson * All rights reserved. 73101099Srwatson * 74101099Srwatson * Redistribution and use in source and binary forms, with or without 75101099Srwatson * modification, are permitted provided that the following conditions 76101099Srwatson * are met: 77145412Strhodes * 1. Redistributions of source code must retain the above copyright 78145412Strhodes * notice, this list of conditions and the following disclaimer. 79101099Srwatson * 2. Redistributions in binary form must reproduce the above copyright 80101099Srwatson * notice, this list of conditions and the following disclaimer in the 81101099Srwatson * documentation and/or other materials provided with the distribution. 82101099Srwatson * 3. All advertising materials mentioning features or use of this software 83101099Srwatson * must display the following acknowledgement: 84101099Srwatson * This product includes software developed for the NetBSD Project 85101099Srwatson * by John M. Vinopal. 86101099Srwatson * 4. The name of the author may not be used to endorse or promote products 87101099Srwatson * derived from this software without specific prior written permission. 88101099Srwatson * 89101099Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 90101099Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 91101099Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 92101099Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 93101099Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 94101099Srwatson * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 95101099Srwatson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 96101099Srwatson * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 97101099Srwatson * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 98101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 99101099Srwatson * SUCH DAMAGE. 100101099Srwatson */ 101134132Strhodes 102145412Strhodes 103134132Strhodes#include <sys/param.h> 104134132Strhodes#include <sys/errno.h> 105134132Strhodes#include <sys/resource.h> 106134132Strhodes#include <sys/sysctl.h> 107134132Strhodes 108134132Strhodes#include <err.h> 109134132Strhodes#include <ctype.h> 110134131Strhodes#include <fcntl.h> 111134131Strhodes#include <kvm.h> 112134131Strhodes#include <nlist.h> 113134131Strhodes#include <stdio.h> 114101099Srwatson#include <stdlib.h> 115134131Strhodes#include <string.h> 116134131Strhodes#include <unistd.h> 117135039Strhodes#include <limits.h> 118134131Strhodes#include <devstat.h> 119134131Strhodes#include <math.h> 120134131Strhodes 121101099Srwatsonstruct nlist namelist[] = { 122101099Srwatson#define X_TK_NIN 0 123101099Srwatson { "_tk_nin" }, 124101099Srwatson#define X_TK_NOUT 1 125101099Srwatson { "_tk_nout" }, 126101099Srwatson#define X_CP_TIME 2 127101099Srwatson { "_cp_time" }, 128101099Srwatson#define X_BOOTTIME 3 129101099Srwatson { "_boottime" }, 130136739Srwatson#define X_END 3 131101099Srwatson { NULL }, 132101099Srwatson}; 133101099Srwatson 134101099Srwatsonstruct statinfo cur, last; 135101099Srwatsonint num_devices; 136101099Srwatsonstruct device_selection *dev_select; 137101099Srwatsonint maxshowdevs; 138101099Srwatsonvolatile sig_atomic_t headercount; 139101099Srwatsonint dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 140101099Srwatsonint xflag = 0, zflag = 0; 141101099Srwatson 142101099Srwatson/* local function declarations */ 143145412Strhodesstatic void usage(void); 144101099Srwatsonstatic void needhdr(int signo); 145101099Srwatsonstatic void phdr(void); 146101099Srwatsonstatic void devstats(int perf_select, long double etime, int havelast); 147101099Srwatsonstatic void cpustats(void); 148101099Srwatsonstatic int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 149101099Srwatson size_t len); 150101099Srwatson 151101099Srwatsonstatic void 152101099Srwatsonusage(void) 153154386Scsjp{ 154101099Srwatson /* 155101099Srwatson * We also support the following 'traditional' syntax: 156145412Strhodes * iostat [drives] [wait [count]] 157145412Strhodes * This isn't mentioned in the man page, or the usage statement, 158145412Strhodes * but it is supported. 159101099Srwatson */ 160101099Srwatson fprintf(stderr, "usage: iostat [-CdhIKoTxz?] [-c count] [-M core]" 161145412Strhodes " [-n devs] [-N system]\n" 162145412Strhodes "\t [-t type,if,pass] [-w wait] [drives]\n"); 163101099Srwatson} 164101099Srwatson 165145412Strhodesint 166145412Strhodesmain(int argc, char **argv) 167145412Strhodes{ 168145412Strhodes int c, i; 169145412Strhodes int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 170145412Strhodes int count = 0, waittime = 0; 171101099Srwatson char *memf = NULL, *nlistf = NULL; 172145412Strhodes struct devstat_match *matches; 173145412Strhodes int num_matches = 0; 174145412Strhodes char errbuf[_POSIX2_LINE_MAX]; 175145412Strhodes kvm_t *kd = NULL; 176145412Strhodes long generation; 177145412Strhodes int num_devices_specified; 178101099Srwatson int num_selected, num_selections; 179145412Strhodes long select_generation; 180145412Strhodes char **specified_devices; 181145412Strhodes devstat_select_mode select_mode; 182145412Strhodes int havelast = 0; 183145412Strhodes 184145412Strhodes matches = NULL; 185145412Strhodes maxshowdevs = 3; 186145412Strhodes 187145412Strhodes while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) { 188145412Strhodes switch(c) { 189145412Strhodes case 'c': 190101099Srwatson cflag++; 191101099Srwatson count = atoi(optarg); 192145412Strhodes if (count < 1) 193101099Srwatson errx(1, "count %d is < 1", count); 194101099Srwatson break; 195101099Srwatson case 'C': 196101099Srwatson Cflag++; 197101099Srwatson break; 198145412Strhodes case 'd': 199145412Strhodes dflag++; 200145412Strhodes break; 201101099Srwatson case 'h': 202101099Srwatson hflag++; 203101099Srwatson break; 204101099Srwatson case 'I': 205101099Srwatson Iflag++; 206101099Srwatson break; 207101099Srwatson case 'K': 208145412Strhodes Kflag++; 209145412Strhodes break; 210145412Strhodes case 'M': 211145412Strhodes memf = optarg; 212148482Strhodes break; 213145412Strhodes case 'n': 214145412Strhodes nflag++; 215148482Strhodes maxshowdevs = atoi(optarg); 216101099Srwatson if (maxshowdevs < 0) 217101099Srwatson errx(1, "number of devices %d is < 0", 218101099Srwatson maxshowdevs); 219101099Srwatson break; 220101099Srwatson case 'N': 221101099Srwatson nlistf = optarg; 222101099Srwatson break; 223101099Srwatson case 'o': 224101099Srwatson oflag++; 225101099Srwatson break; 226145412Strhodes case 't': 227145412Strhodes tflag++; 228101099Srwatson if (devstat_buildmatch(optarg, &matches, 229101099Srwatson &num_matches) != 0) 230101099Srwatson errx(1, "%s", devstat_errbuf); 231101099Srwatson break; 232101099Srwatson case 'T': 233101099Srwatson Tflag++; 234101099Srwatson break; 235145412Strhodes case 'w': 236145412Strhodes wflag++; 237145412Strhodes waittime = atoi(optarg); 238101099Srwatson if (waittime < 1) 239101099Srwatson errx(1, "wait time is < 1"); 240101099Srwatson break; 241101099Srwatson case 'x': 242101099Srwatson xflag++; 243106212Srwatson break; 244101099Srwatson case 'z': 245101099Srwatson zflag++; 246101099Srwatson break; 247101099Srwatson default: 248101099Srwatson usage(); 249101099Srwatson exit(1); 250145412Strhodes break; 251101099Srwatson } 252101099Srwatson } 253101099Srwatson 254101099Srwatson argc -= optind; 255101099Srwatson argv += optind; 256101099Srwatson 257101099Srwatson if (nlistf != NULL || memf != NULL) { 258101099Srwatson kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 259101099Srwatson 260101099Srwatson if (kd == NULL) 261101099Srwatson errx(1, "kvm_openfiles: %s", errbuf); 262101099Srwatson 263101099Srwatson if (kvm_nlist(kd, namelist) == -1) 264101099Srwatson errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 265101099Srwatson } 266101099Srwatson 267101099Srwatson /* 268101099Srwatson * Make sure that the userland devstat version matches the kernel 269101099Srwatson * devstat version. If not, exit and print a message informing 270101099Srwatson * the user of his mistake. 271101099Srwatson */ 272101099Srwatson if (devstat_checkversion(kd) < 0) 273101099Srwatson errx(1, "%s", devstat_errbuf); 274101099Srwatson 275101099Srwatson /* 276101099Srwatson * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 277101099Srwatson * greater than 0, they may be 0 or non-zero. 278101099Srwatson */ 279101099Srwatson if (dflag == 0 && xflag == 0) { 280101099Srwatson Cflag = 1; 281101099Srwatson Tflag = 1; 282101099Srwatson } 283101099Srwatson 284101099Srwatson /* find out how many devices we have */ 285101099Srwatson if ((num_devices = devstat_getnumdevs(kd)) < 0) 286101099Srwatson err(1, "can't get number of devices"); 287101099Srwatson 288101099Srwatson /* 289101099Srwatson * Figure out how many devices we should display. 290101099Srwatson */ 291101099Srwatson if (nflag == 0) { 292101099Srwatson if (xflag > 0) 293101099Srwatson maxshowdevs = num_devices; 294101099Srwatson else if (oflag > 0) { 295101099Srwatson if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 296101099Srwatson maxshowdevs = 5; 297101099Srwatson else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 298101099Srwatson maxshowdevs = 5; 299101099Srwatson else 300101099Srwatson maxshowdevs = 4; 301101099Srwatson } else { 302134132Strhodes if ((dflag > 0) && (Cflag == 0)) 303134132Strhodes maxshowdevs = 4; 304134132Strhodes else 305134132Strhodes maxshowdevs = 3; 306134132Strhodes } 307101099Srwatson } 308145412Strhodes 309134131Strhodes cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 310145412Strhodes if (cur.dinfo == NULL) 311145412Strhodes err(1, "malloc failed"); 312134131Strhodes 313134131Strhodes last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 314134131Strhodes if (last.dinfo == NULL) 315134131Strhodes err(1, "malloc failed"); 316134131Strhodes 317101099Srwatson bzero(cur.dinfo, sizeof(struct devinfo)); 318101099Srwatson bzero(last.dinfo, sizeof(struct devinfo)); 319101099Srwatson 320101099Srwatson /* 321106212Srwatson * Grab all the devices. We don't look to see if the list has 322101099Srwatson * changed here, since it almost certainly has. We only look for 323101099Srwatson * errors. 324101099Srwatson */ 325132563Srwatson if (devstat_getdevs(kd, &cur) == -1) 326132563Srwatson errx(1, "%s", devstat_errbuf); 327132563Srwatson 328145412Strhodes num_devices = cur.dinfo->numdevs; 329101099Srwatson generation = cur.dinfo->generation; 330101099Srwatson 331101099Srwatson /* 332101099Srwatson * If the user specified any devices on the command line, see if 333108376Srwatson * they are in the list of devices we have now. 334145412Strhodes */ 335108376Srwatson specified_devices = (char **)malloc(sizeof(char *)); 336108376Srwatson if (specified_devices == NULL) 337136739Srwatson err(1, "malloc failed"); 338136739Srwatson 339136739Srwatson for (num_devices_specified = 0; *argv; ++argv) { 340108376Srwatson if (isdigit(**argv)) 341108376Srwatson break; 342101099Srwatson num_devices_specified++; 343101099Srwatson specified_devices = (char **)realloc(specified_devices, 344134131Strhodes sizeof(char *) * 345134131Strhodes num_devices_specified); 346145412Strhodes if (specified_devices == NULL) 347145412Strhodes err(1, "realloc failed"); 348101099Srwatson 349145412Strhodes specified_devices[num_devices_specified - 1] = *argv; 350101099Srwatson 351145412Strhodes } 352101099Srwatson if (nflag == 0 && maxshowdevs < num_devices_specified) 353101099Srwatson maxshowdevs = num_devices_specified; 354101099Srwatson 355101099Srwatson dev_select = NULL; 356156300Sdwmalone 357112575Srwatson if ((num_devices_specified == 0) && (num_matches == 0)) 358156300Sdwmalone select_mode = DS_SELECT_ADD; 359112575Srwatson else 360112575Srwatson select_mode = DS_SELECT_ONLY; 361112575Srwatson 362112575Srwatson /* 363112575Srwatson * At this point, selectdevs will almost surely indicate that the 364112575Srwatson * device list has changed, so we don't look for return values of 0 365112575Srwatson * or 1. If we get back -1, though, there is an error. 366112575Srwatson */ 367156300Sdwmalone if (devstat_selectdevs(&dev_select, &num_selected, 368136739Srwatson &num_selections, &select_generation, generation, 369156300Sdwmalone cur.dinfo->devices, num_devices, matches, 370112575Srwatson num_matches, specified_devices, 371112575Srwatson num_devices_specified, select_mode, maxshowdevs, 372112575Srwatson hflag) == -1) 373156300Sdwmalone errx(1, "%s", devstat_errbuf); 374156300Sdwmalone 375156300Sdwmalone /* 376156300Sdwmalone * Look for the traditional wait time and count arguments. 377156300Sdwmalone */ 378156300Sdwmalone if (*argv) { 379156300Sdwmalone waittime = atoi(*argv); 380156300Sdwmalone 381101099Srwatson /* Let the user know he goofed, but keep going anyway */ 382106212Srwatson if (wflag != 0) 383101099Srwatson warnx("discarding previous wait interval, using" 384101099Srwatson " %d instead", waittime); 385156300Sdwmalone wflag++; 386101099Srwatson 387101099Srwatson if (*++argv) { 388101099Srwatson count = atoi(*argv); 389101099Srwatson if (cflag != 0) 390101099Srwatson warnx("discarding previous count, using %d" 391101099Srwatson " instead", count); 392101099Srwatson cflag++; 393156300Sdwmalone } else 394101099Srwatson count = -1; 395101099Srwatson } 396101099Srwatson 397101099Srwatson /* 398101099Srwatson * If the user specified a count, but not an interval, we default 399101099Srwatson * to an interval of 1 second. 400101099Srwatson */ 401156300Sdwmalone if ((wflag == 0) && (cflag > 0)) 402101099Srwatson waittime = 1; 403101099Srwatson 404101099Srwatson /* 405101099Srwatson * If the user specified a wait time, but not a count, we want to 406101099Srwatson * go on ad infinitum. This can be redundant if the user uses the 407101099Srwatson * traditional method of specifying the wait, since in that case we 408101099Srwatson * already set count = -1 above. Oh well. 409156300Sdwmalone */ 410101099Srwatson if ((wflag > 0) && (cflag == 0)) 411101099Srwatson count = -1; 412101099Srwatson 413101099Srwatson bzero(&cur.cp_time, sizeof(cur.cp_time)); 414101099Srwatson cur.tk_nout = 0; 415101099Srwatson cur.tk_nin = 0; 416101099Srwatson 417101099Srwatson /* 418101099Srwatson * Set the snap time to the system boot time (ie: zero), so the 419156300Sdwmalone * stats are calculated since system boot. 420101099Srwatson */ 421101099Srwatson cur.snap_time = 0; 422101099Srwatson 423156300Sdwmalone /* 424101099Srwatson * If the user stops the program (control-Z) and then resumes it, 425101099Srwatson * print out the header again. 426101099Srwatson */ 427101099Srwatson (void)signal(SIGCONT, needhdr); 428101099Srwatson 429101099Srwatson for (headercount = 1;;) { 430101099Srwatson struct devinfo *tmp_dinfo; 431156300Sdwmalone long tmp; 432101099Srwatson long double etime; 433101099Srwatson 434101099Srwatson if (Tflag > 0) { 435119202Srwatson if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 436119202Srwatson sizeof(cur.tk_nin)) != 0) 437119202Srwatson || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 438119202Srwatson &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 439156300Sdwmalone Tflag = 0; 440119202Srwatson warnx("disabling TTY statistics"); 441119202Srwatson } 442119202Srwatson } 443101099Srwatson 444106648Srwatson if (Cflag > 0) { 445106648Srwatson if (readvar(kd, "kern.cp_time", X_CP_TIME, 446101099Srwatson &cur.cp_time, sizeof(cur.cp_time)) != 0) { 447101099Srwatson Cflag = 0; 448156300Sdwmalone warnx("disabling CPU time statistics"); 449101099Srwatson } 450101099Srwatson } 451101099Srwatson 452101099Srwatson if (!--headercount) { 453101099Srwatson phdr(); 454101099Srwatson headercount = 20; 455101099Srwatson } 456156300Sdwmalone 457101099Srwatson tmp_dinfo = last.dinfo; 458101099Srwatson last.dinfo = cur.dinfo; 459101099Srwatson cur.dinfo = tmp_dinfo; 460101099Srwatson 461101099Srwatson last.snap_time = cur.snap_time; 462101099Srwatson 463101099Srwatson /* 464156300Sdwmalone * Here what we want to do is refresh our device stats. 465101099Srwatson * devstat_getdevs() returns 1 when the device list has changed. 466101099Srwatson * If the device list has changed, we want to go through 467101099Srwatson * the selection process again, in case a device that we 468104530Srwatson * were previously displaying has gone away. 469104530Srwatson */ 470104530Srwatson switch (devstat_getdevs(kd, &cur)) { 471104530Srwatson case -1: 472104530Srwatson errx(1, "%s", devstat_errbuf); 473104530Srwatson break; 474156300Sdwmalone case 1: { 475104530Srwatson int retval; 476104530Srwatson 477104530Srwatson num_devices = cur.dinfo->numdevs; 478156300Sdwmalone generation = cur.dinfo->generation; 479104530Srwatson retval = devstat_selectdevs(&dev_select, &num_selected, 480104530Srwatson &num_selections, 481104530Srwatson &select_generation, 482104530Srwatson generation, 483104530Srwatson cur.dinfo->devices, 484104530Srwatson num_devices, matches, 485119202Srwatson num_matches, 486119202Srwatson specified_devices, 487119202Srwatson num_devices_specified, 488119202Srwatson select_mode, maxshowdevs, 489156300Sdwmalone hflag); 490119202Srwatson switch(retval) { 491119202Srwatson case -1: 492119202Srwatson errx(1, "%s", devstat_errbuf); 493101099Srwatson break; 494101099Srwatson case 1: 495101099Srwatson phdr(); 496117247Srwatson headercount = 20; 497156300Sdwmalone break; 498101099Srwatson default: 499101099Srwatson break; 500101099Srwatson } 501101099Srwatson break; 502106212Srwatson } 503101099Srwatson default: 504101099Srwatson break; 505156300Sdwmalone } 506101099Srwatson 507101099Srwatson /* 508101099Srwatson * We only want to re-select devices if we're in 'top' 509101099Srwatson * mode. This is the only mode where the devices selected 510101099Srwatson * could actually change. 511101099Srwatson */ 512101099Srwatson if (hflag > 0) { 513156300Sdwmalone int retval; 514101099Srwatson retval = devstat_selectdevs(&dev_select, &num_selected, 515101099Srwatson &num_selections, 516101099Srwatson &select_generation, 517101099Srwatson generation, 518101099Srwatson cur.dinfo->devices, 519101099Srwatson num_devices, matches, 520101099Srwatson num_matches, 521156300Sdwmalone specified_devices, 522101099Srwatson num_devices_specified, 523101099Srwatson select_mode, maxshowdevs, 524101099Srwatson hflag); 525101099Srwatson switch(retval) { 526101099Srwatson case -1: 527101099Srwatson errx(1,"%s", devstat_errbuf); 528101099Srwatson break; 529101099Srwatson case 1: 530101099Srwatson phdr(); 531156300Sdwmalone headercount = 20; 532101099Srwatson break; 533101099Srwatson default: 534156300Sdwmalone break; 535101099Srwatson } 536101099Srwatson } 537101099Srwatson 538101099Srwatson if (Tflag > 0) { 539101099Srwatson tmp = cur.tk_nin; 540101099Srwatson cur.tk_nin -= last.tk_nin; 541101099Srwatson last.tk_nin = tmp; 542101099Srwatson tmp = cur.tk_nout; 543101099Srwatson cur.tk_nout -= last.tk_nout; 544101099Srwatson last.tk_nout = tmp; 545101099Srwatson } 546156300Sdwmalone 547101099Srwatson etime = cur.snap_time - last.snap_time; 548101099Srwatson 549101099Srwatson if (etime == 0.0) 550156300Sdwmalone etime = 1.0; 551156300Sdwmalone 552101099Srwatson for (i = 0; i < CPUSTATES; i++) { 553101099Srwatson tmp = cur.cp_time[i]; 554101099Srwatson cur.cp_time[i] -= last.cp_time[i]; 555101099Srwatson last.cp_time[i] = tmp; 556101099Srwatson } 557101099Srwatson 558101099Srwatson if (xflag == 0 && Tflag > 0) 559101099Srwatson printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 560101099Srwatson cur.tk_nout / etime); 561156300Sdwmalone 562101099Srwatson devstats(hflag, etime, havelast); 563101099Srwatson 564101099Srwatson if (xflag == 0) { 565101099Srwatson if (Cflag > 0) 566101099Srwatson cpustats(); 567101099Srwatson 568101099Srwatson printf("\n"); 569156300Sdwmalone } 570101099Srwatson fflush(stdout); 571101099Srwatson 572101099Srwatson if (count >= 0 && --count <= 0) 573101099Srwatson break; 574101099Srwatson 575101099Srwatson sleep(waittime); 576101099Srwatson havelast = 1; 577156300Sdwmalone } 578101099Srwatson 579101099Srwatson exit(0); 580101099Srwatson} 581101099Srwatson 582101099Srwatson/* 583101099Srwatson * Force a header to be prepended to the next output. 584101099Srwatson */ 585156300Sdwmalonevoid 586101099Srwatsonneedhdr(int signo) 587101099Srwatson{ 588101099Srwatson 589101099Srwatson headercount = 1; 590101099Srwatson} 591101099Srwatson 592101099Srwatsonstatic void 593156300Sdwmalonephdr(void) 594101099Srwatson{ 595101099Srwatson int i, printed; 596101099Srwatson 597101099Srwatson /* 598101099Srwatson * If xflag is set, we need a per-loop header, not a page header, so 599101099Srwatson * just return. We'll print the header in devstats(). 600101099Srwatson */ 601156300Sdwmalone if (xflag > 0) 602101099Srwatson return; 603101099Srwatson 604101099Srwatson if (Tflag > 0) 605101099Srwatson (void)printf(" tty"); 606101099Srwatson for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 607101099Srwatson int di; 608101099Srwatson if ((dev_select[i].selected != 0) 609156300Sdwmalone && (dev_select[i].selected <= maxshowdevs)) { 610101099Srwatson di = dev_select[i].position; 611101099Srwatson if (oflag > 0) 612101099Srwatson (void)printf("%12.6s%d ", 613102129Srwatson cur.dinfo->devices[di].device_name, 614102129Srwatson cur.dinfo->devices[di].unit_number); 615101099Srwatson else 616101099Srwatson printf("%15.6s%d ", 617156300Sdwmalone cur.dinfo->devices[di].device_name, 618101099Srwatson cur.dinfo->devices[di].unit_number); 619101099Srwatson printed++; 620106217Srwatson } 621101099Srwatson } 622106217Srwatson if (Cflag > 0) 623106217Srwatson (void)printf(" cpu\n"); 624112575Srwatson else 625106217Srwatson (void)printf("\n"); 626106217Srwatson 627106217Srwatson if (Tflag > 0) 628106217Srwatson (void)printf(" tin tout"); 629106217Srwatson 630106217Srwatson for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 631119202Srwatson if ((dev_select[i].selected != 0) 632106217Srwatson && (dev_select[i].selected <= maxshowdevs)) { 633106217Srwatson if (oflag > 0) { 634106217Srwatson if (Iflag == 0) 635106217Srwatson (void)printf(" sps tps msps "); 636119202Srwatson else 637106217Srwatson (void)printf(" blk xfr msps "); 638106217Srwatson } else { 639106217Srwatson if (Iflag == 0) 640106217Srwatson printf(" KB/t tps MB/s "); 641106217Srwatson else 642106217Srwatson printf(" KB/t xfrs MB "); 643106217Srwatson } 644106217Srwatson printed++; 645106217Srwatson } 646106217Srwatson } 647106217Srwatson if (Cflag > 0) 648106217Srwatson (void)printf(" us ni sy in id\n"); 649106217Srwatson else 650106217Srwatson printf("\n"); 651101099Srwatson 652101099Srwatson} 653112717Srwatson 654101099Srwatsonstatic void 655devstats(int perf_select, long double etime, int havelast) 656{ 657 int dn; 658 long double transfers_per_second, transfers_per_second_read, transfers_per_second_write; 659 long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write; 660 u_int64_t total_bytes, total_transfers, total_blocks; 661 u_int64_t total_bytes_read, total_transfers_read; 662 u_int64_t total_bytes_write, total_transfers_write; 663 long double busy_pct; 664 u_int64_t queue_len; 665 long double total_mb; 666 long double blocks_per_second, ms_per_transaction; 667 int firstline = 1; 668 char *devname; 669 670 if (xflag > 0) { 671 printf(" extended device statistics "); 672 if (Tflag > 0) 673 printf(" tty "); 674 if (Cflag > 0) 675 printf(" cpu "); 676 printf("\n"); 677 if (Iflag == 0) 678 printf( 679 "device r/s w/s kr/s kw/s wait svc_t %%b " 680 ); 681 else 682 printf( 683 "device r/i w/i kr/i kw/i wait svc_t %%b " 684 ); 685 if (Tflag > 0) 686 printf("tin tout "); 687 if (Cflag > 0) 688 printf("us ni sy in id "); 689 printf("\n"); 690 } 691 692 for (dn = 0; dn < num_devices; dn++) { 693 int di; 694 695 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 696 || (dev_select[dn].selected > maxshowdevs)) 697 continue; 698 699 di = dev_select[dn].position; 700 701 if (devstat_compute_statistics(&cur.dinfo->devices[di], 702 havelast ? &last.dinfo->devices[di] : NULL, etime, 703 DSM_TOTAL_BYTES, &total_bytes, 704 DSM_TOTAL_BYTES_READ, &total_bytes_read, 705 DSM_TOTAL_BYTES_WRITE, &total_bytes_write, 706 DSM_TOTAL_TRANSFERS, &total_transfers, 707 DSM_TOTAL_TRANSFERS_READ, &total_transfers_read, 708 DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write, 709 DSM_TOTAL_BLOCKS, &total_blocks, 710 DSM_KB_PER_TRANSFER, &kb_per_transfer, 711 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 712 DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read, 713 DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write, 714 DSM_MB_PER_SECOND, &mb_per_second, 715 DSM_MB_PER_SECOND_READ, &mb_per_second_read, 716 DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, 717 DSM_BLOCKS_PER_SECOND, &blocks_per_second, 718 DSM_MS_PER_TRANSACTION, &ms_per_transaction, 719 DSM_BUSY_PCT, &busy_pct, 720 DSM_QUEUE_LENGTH, &queue_len, 721 DSM_NONE) != 0) 722 errx(1, "%s", devstat_errbuf); 723 724 if (perf_select != 0) { 725 dev_select[dn].bytes = total_bytes; 726 if ((dev_select[dn].selected == 0) 727 || (dev_select[dn].selected > maxshowdevs)) 728 continue; 729 } 730 731 if (Kflag > 0 || xflag > 0) { 732 int block_size = cur.dinfo->devices[di].block_size; 733 total_blocks = total_blocks * (block_size ? 734 block_size : 512) / 1024; 735 } 736 737 if (xflag > 0) { 738 if (asprintf(&devname, "%s%d", 739 cur.dinfo->devices[di].device_name, 740 cur.dinfo->devices[di].unit_number) == 1) 741 errx(1, "asprintf() failed (out of memory?)"); 742 /* 743 * If zflag is set, skip any devices with zero I/O. 744 */ 745 if (zflag == 0 || transfers_per_second_read > 0.05 || 746 transfers_per_second_write > 0.05 || 747 mb_per_second_read > ((long double).0005)/1024 || 748 mb_per_second_write > ((long double).0005)/1024 || 749 busy_pct > 0.5) { 750 if (Iflag == 0) 751 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 752 devname, transfers_per_second_read, 753 transfers_per_second_write, 754 mb_per_second_read * 1024, 755 mb_per_second_write * 1024, 756 queue_len, 757 ms_per_transaction, busy_pct); 758 else 759 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 760 devname, 761 (long double)total_transfers_read, 762 (long double)total_transfers_write, 763 (long double) 764 total_bytes_read / 1024, 765 (long double) 766 total_bytes_write / 1024, 767 queue_len, 768 ms_per_transaction, busy_pct); 769 if (firstline) { 770 /* 771 * If this is the first device 772 * we're printing, also print 773 * CPU or TTY stats if requested. 774 */ 775 firstline = 0; 776 if (Tflag > 0) 777 printf("%4.0Lf%5.0Lf", 778 cur.tk_nin / etime, 779 cur.tk_nout / etime); 780 if (Cflag > 0) 781 cpustats(); 782 } 783 printf("\n"); 784 } 785 free(devname); 786 } else if (oflag > 0) { 787 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 788 789 if (Iflag == 0) 790 printf("%4.0Lf%4.0Lf%5.*Lf ", 791 blocks_per_second, 792 transfers_per_second, 793 msdig, 794 ms_per_transaction); 795 else 796 printf("%4.1qu%4.1qu%5.*Lf ", 797 total_blocks, 798 total_transfers, 799 msdig, 800 ms_per_transaction); 801 } else { 802 if (Iflag == 0) 803 printf(" %5.2Lf %3.0Lf %5.2Lf ", 804 kb_per_transfer, 805 transfers_per_second, 806 mb_per_second); 807 else { 808 total_mb = total_bytes; 809 total_mb /= 1024 * 1024; 810 811 printf(" %5.2Lf %3.1qu %5.2Lf ", 812 kb_per_transfer, 813 total_transfers, 814 total_mb); 815 } 816 } 817 } 818 if (xflag > 0 && zflag > 0 && firstline == 1 && 819 (Tflag > 0 || Cflag > 0)) { 820 /* 821 * If zflag is set and we did not print any device 822 * lines I/O because they were all zero, 823 * print TTY/CPU stats. 824 */ 825 printf("%52s",""); 826 if (Tflag > 0) 827 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 828 cur.tk_nout / etime); 829 if (Cflag > 0) 830 cpustats(); 831 printf("\n"); 832 } 833} 834 835static void 836cpustats(void) 837{ 838 int state; 839 double time; 840 841 time = 0.0; 842 843 for (state = 0; state < CPUSTATES; ++state) 844 time += cur.cp_time[state]; 845 for (state = 0; state < CPUSTATES; ++state) 846 printf(" %2.0f", 847 rint(100. * cur.cp_time[state] / (time ? time : 1))); 848} 849 850static int 851readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 852{ 853 if (kd != NULL) { 854 ssize_t nbytes; 855 856 nbytes = kvm_read(kd, namelist[nlid].n_value, ptr, len); 857 858 if (nbytes < 0) { 859 warnx("kvm_read(%s): %s", namelist[nlid].n_name, 860 kvm_geterr(kd)); 861 return (1); 862 } 863 if (nbytes != len) { 864 warnx("kvm_read(%s): expected %zu bytes, got %zd bytes", 865 namelist[nlid].n_name, len, nbytes); 866 return (1); 867 } 868 } else { 869 size_t nlen = len; 870 871 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 872 warn("sysctl(%s...) failed", name); 873 return (1); 874 } 875 if (nlen != len) { 876 warnx("sysctl(%s...): expected %lu, got %lu", name, 877 (unsigned long)len, (unsigned long)nlen); 878 return (1); 879 } 880 } 881 return (0); 882} 883