iostat.c revision 121836
1141240Snjl/* 2167905Snjl * Copyright (c) 1998 Kenneth D. Merry. 3141240Snjl * All rights reserved. 4141240Snjl * 5141240Snjl * Redistribution and use in source and binary forms, with or without 6141240Snjl * modification, are permitted provided that the following conditions 7141240Snjl * are met: 8141240Snjl * 1. Redistributions of source code must retain the above copyright 9141240Snjl * notice, this list of conditions and the following disclaimer. 10141240Snjl * 2. Redistributions in binary form must reproduce the above copyright 11141240Snjl * notice, this list of conditions and the following disclaimer in the 12141240Snjl * documentation and/or other materials provided with the distribution. 13141240Snjl * 3. The name of the author may not be used to endorse or promote products 14141240Snjl * derived from this software without specific prior written permission. 15141240Snjl * 16141240Snjl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17141240Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18141240Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19141240Snjl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20141240Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21141240Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22141240Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23141240Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24141240Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25141240Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26141240Snjl * SUCH DAMAGE. 27141240Snjl */ 28141240Snjl/* 29141240Snjl * Copyright (c) 1980, 1992, 1993 30141240Snjl * The Regents of the University of California. All rights reserved. 31141240Snjl * 32141240Snjl * Redistribution and use in source and binary forms, with or without 33141240Snjl * modification, are permitted provided that the following conditions 34141240Snjl * are met: 35142603Snjl * 1. Redistributions of source code must retain the above copyright 36141240Snjl * notice, this list of conditions and the following disclaimer. 37141240Snjl * 2. Redistributions in binary form must reproduce the above copyright 38141240Snjl * notice, this list of conditions and the following disclaimer in the 39141240Snjl * documentation and/or other materials provided with the distribution. 40173204Snjl * 3. All advertising materials mentioning features or use of this software 41141240Snjl * must display the following acknowledgement: 42173204Snjl * This product includes software developed by the University of 43141240Snjl * California, Berkeley and its contributors. 44141240Snjl * 4. Neither the name of the University nor the names of its contributors 45142603Snjl * may be used to endorse or promote products derived from this software 46141814Snjl * without specific prior written permission. 47167905Snjl * 48141240Snjl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49141240Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50141240Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51141240Snjl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52141240Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53141240Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54141240Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55141240Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56141240Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57141240Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58142395Snjl * SUCH DAMAGE. 59141240Snjl */ 60142395Snjl 61141240Snjl#include <sys/cdefs.h> 62150847Sume 63150847Sume__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 121836 2003-11-01 02:06:02Z tjr $"); 64150847Sume 65150847Sume#ifdef lint 66150847Sumestatic const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 67150847Sume#endif 68141240Snjl 69142603Snjl#include <sys/param.h> 70141240Snjl#include <sys/sysctl.h> 71141923Snjl#include <sys/resource.h> 72150847Sume 73141923Snjl#include <devstat.h> 74141413Snjl#include <err.h> 75141945Snjl#include <nlist.h> 76141240Snjl#include <paths.h> 77141240Snjl#include <stdlib.h> 78167905Snjl#include <string.h> 79210422Savg 80141240Snjl#include "systat.h" 81141240Snjl#include "extern.h" 82141240Snjl#include "devs.h" 83141240Snjl 84141240Snjlstruct statinfo cur, last; 85141240Snjl 86141240Snjlstatic int linesperregion; 87141240Snjlstatic double etime; 88141240Snjlstatic int numbers = 0; /* default display bar graphs */ 89141240Snjlstatic int kbpt = 0; /* default ms/seek shown */ 90142603Snjl 91142603Snjlstatic int barlabels(int); 92142603Snjlstatic void histogram(long double, int, double); 93142603Snjlstatic int numlabels(int); 94142603Snjlstatic int devstats(int, int, int); 95144876Snjlstatic void stat1(int, int); 96144876Snjl 97144876SnjlWINDOW * 98144876Snjlopeniostat() 99144876Snjl{ 100141240Snjl return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 101167905Snjl} 102141240Snjl 103141240Snjlvoid 104141240Snjlcloseiostat(w) 105141240Snjl WINDOW *w; 106141240Snjl{ 107141240Snjl if (w == NULL) 108141413Snjl return; 109141240Snjl wclear(w); 110141413Snjl wrefresh(w); 111141413Snjl delwin(w); 112141413Snjl} 113141413Snjl 114141240Snjlint 115141240Snjlinitiostat() 116142114Snjl{ 117141240Snjl if ((num_devices = devstat_getnumdevs(NULL)) < 0) 118141240Snjl return(0); 119141240Snjl 120141240Snjl cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 121141240Snjl last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 122141240Snjl bzero(cur.dinfo, sizeof(struct devinfo)); 123141240Snjl bzero(last.dinfo, sizeof(struct devinfo)); 124141240Snjl 125141240Snjl /* 126141240Snjl * This value for maxshowdevs (100) is bogus. I'm not sure exactly 127141240Snjl * how to calculate it, though. 128141240Snjl */ 129141240Snjl if (dsinit(100, &cur, &last, NULL) != 1) 130141240Snjl return(0); 131141240Snjl 132141240Snjl return(1); 133141240Snjl} 134142590Snjl 135144876Snjlvoid 136142590Snjlfetchiostat() 137144876Snjl{ 138227309Sed struct devinfo *tmp_dinfo; 139227309Sed size_t len; 140142590Snjl 141142590Snjl len = sizeof(cur.cp_time); 142144876Snjl if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 143144876Snjl || len != sizeof(cur.cp_time)) { 144142590Snjl perror("kern.cp_time"); 145141240Snjl exit (1); 146141240Snjl } 147141240Snjl tmp_dinfo = last.dinfo; 148141240Snjl last.dinfo = cur.dinfo; 149186154Smav cur.dinfo = tmp_dinfo; 150141240Snjl 151186154Smav last.snap_time = cur.snap_time; 152141240Snjl 153141240Snjl /* 154144876Snjl * Here what we want to do is refresh our device stats. 155141240Snjl * getdevs() returns 1 when the device list has changed. 156141240Snjl * If the device list has changed, we want to go through 157141240Snjl * the selection process again, in case a device that we 158141240Snjl * were previously displaying has gone away. 159141240Snjl */ 160142603Snjl switch (devstat_getdevs(NULL, &cur)) { 161141240Snjl case -1: 162150847Sume errx(1, "%s", devstat_errbuf); 163193155Snwhitehorn break; 164193155Snwhitehorn case 1: 165193155Snwhitehorn cmdiostat("refresh", NULL); 166193155Snwhitehorn break; 167193155Snwhitehorn default: 168193155Snwhitehorn break; 169193155Snwhitehorn } 170193155Snwhitehorn num_devices = cur.dinfo->numdevs; 171193155Snwhitehorn generation = cur.dinfo->generation; 172193155Snwhitehorn 173141240Snjl} 174141240Snjl 175141240Snjl#define INSET 10 176141240Snjl 177141240Snjlvoid 178141240Snjllabeliostat() 179141240Snjl{ 180141240Snjl int row; 181141240Snjl 182141240Snjl row = 0; 183144876Snjl wmove(wnd, row, 0); wclrtobot(wnd); 184144876Snjl mvwaddstr(wnd, row++, INSET, 185210422Savg "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 186210422Savg mvwaddstr(wnd, row++, 0, "cpu user|"); 187141240Snjl mvwaddstr(wnd, row++, 0, " nice|"); 188141240Snjl mvwaddstr(wnd, row++, 0, " system|"); 189141240Snjl mvwaddstr(wnd, row++, 0, "interrupt|"); 190141240Snjl mvwaddstr(wnd, row++, 0, " idle|"); 191141240Snjl if (numbers) 192141240Snjl row = numlabels(row + 1); 193141240Snjl else 194141240Snjl row = barlabels(row + 1); 195141240Snjl} 196167905Snjl 197167905Snjlstatic int 198167905Snjlnumlabels(row) 199167905Snjl int row; 200167905Snjl{ 201167905Snjl int i, _col, regions, ndrives; 202167905Snjl char tmpstr[10]; 203141240Snjl 204141240Snjl#define COLWIDTH 17 205141240Snjl#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 206167905Snjl for (ndrives = 0, i = 0; i < num_devices; i++) 207167905Snjl if (dev_select[i].selected) 208167905Snjl ndrives++; 209167905Snjl regions = howmany(ndrives, DRIVESPERLINE); 210167905Snjl /* 211167905Snjl * Deduct -regions for blank line after each scrolling region. 212167905Snjl */ 213167905Snjl linesperregion = (wnd->_maxy - row - regions) / regions; 214141240Snjl /* 215141240Snjl * Minimum region contains space for two 216141240Snjl * label lines and one line of statistics. 217141240Snjl */ 218150847Sume if (linesperregion < 3) 219141240Snjl linesperregion = 3; 220141240Snjl _col = INSET; 221144876Snjl for (i = 0; i < num_devices; i++) 222141240Snjl if (dev_select[i].selected) { 223141240Snjl if (_col + COLWIDTH >= wnd->_maxx - INSET) { 224141240Snjl _col = INSET, row += linesperregion + 1; 225150847Sume if (row > wnd->_maxy - (linesperregion + 1)) 226150847Sume break; 227150847Sume } 228150847Sume sprintf(tmpstr, "%s%d", dev_select[i].device_name, 229150847Sume dev_select[i].unit_number); 230141240Snjl mvwaddstr(wnd, row, _col + 4, tmpstr); 231141240Snjl mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 232144876Snjl _col += COLWIDTH; 233144876Snjl } 234210422Savg if (_col) 235144876Snjl row += linesperregion + 1; 236141240Snjl return (row); 237141240Snjl} 238141240Snjl 239141240Snjlstatic int 240141240Snjlbarlabels(row) 241141240Snjl int row; 242141240Snjl{ 243141240Snjl int i; 244141240Snjl char tmpstr[10]; 245150847Sume 246141814Snjl mvwaddstr(wnd, row++, INSET, 247171898Snjl "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 248141240Snjl linesperregion = 2 + kbpt; 249141240Snjl for (i = 0; i < num_devices; i++) 250142603Snjl if (dev_select[i].selected) { 251142603Snjl if (row > wnd->_maxy - linesperregion) 252150847Sume break; 253141240Snjl sprintf(tmpstr, "%s%d", dev_select[i].device_name, 254167905Snjl dev_select[i].unit_number); 255167905Snjl mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 256167905Snjl tmpstr); 257167905Snjl mvwaddstr(wnd, row++, 0, " tps|"); 258167905Snjl if (kbpt) 259156228Smnag mvwaddstr(wnd, row++, 0, " KB/t|"); 260141814Snjl } 261150847Sume return (row); 262150847Sume} 263173204Snjl 264141923Snjl 265173204Snjlvoid 266173204Snjlshowiostat() 267173204Snjl{ 268173204Snjl long t; 269173204Snjl int i, row, _col; 270173204Snjl 271173204Snjl#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 272173204Snjl etime = 0; 273173204Snjl for(i = 0; i < CPUSTATES; i++) { 274173204Snjl X(cp_time); 275173204Snjl etime += cur.cp_time[i]; 276173204Snjl } 277173204Snjl if (etime == 0.0) 278173204Snjl etime = 1.0; 279150847Sume etime /= hertz; 280150847Sume row = 1; 281150847Sume for (i = 0; i < CPUSTATES; i++) 282150847Sume stat1(row++, i); 283150847Sume if (!numbers) { 284150847Sume row += 2; 285150847Sume for (i = 0; i < num_devices; i++) 286150847Sume if (dev_select[i].selected) { 287150847Sume if (row > wnd->_maxy - linesperregion) 288150847Sume break; 289150847Sume row = devstats(row, INSET, i); 290141923Snjl } 291141923Snjl return; 292141923Snjl } 293141923Snjl _col = INSET; 294150847Sume wmove(wnd, row + linesperregion, 0); 295150847Sume wdeleteln(wnd); 296144876Snjl wmove(wnd, row + 3, 0); 297142603Snjl winsertln(wnd); 298142603Snjl for (i = 0; i < num_devices; i++) 299142603Snjl if (dev_select[i].selected) { 300150847Sume if (_col + COLWIDTH >= wnd->_maxx - INSET) { 301150847Sume _col = INSET, row += linesperregion + 1; 302150847Sume if (row > wnd->_maxy - (linesperregion + 1)) 303150847Sume break; 304142603Snjl wmove(wnd, row + linesperregion, 0); 305141923Snjl wdeleteln(wnd); 306142590Snjl wmove(wnd, row + 3, 0); 307148972Snjl winsertln(wnd); 308144876Snjl } 309144876Snjl (void) devstats(row + 3, _col, i); 310142603Snjl _col += COLWIDTH; 311142603Snjl } 312142603Snjl} 313142590Snjl 314141240Snjlstatic int 315144876Snjldevstats(row, _col, dn) 316144876Snjl int row, _col, dn; 317144876Snjl{ 318149239Sume long double transfers_per_second; 319144876Snjl long double kb_per_transfer, mb_per_second; 320141240Snjl long double busy_seconds; 321141240Snjl int di; 322141240Snjl 323141240Snjl di = dev_select[dn].position; 324141240Snjl 325141240Snjl busy_seconds = cur.snap_time - last.snap_time; 326141240Snjl 327141240Snjl if (devstat_compute_statistics(&cur.dinfo->devices[di], 328141943Snjl &last.dinfo->devices[di], busy_seconds, 329171898Snjl DSM_KB_PER_TRANSFER, &kb_per_transfer, 330141943Snjl DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 331171898Snjl DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 332171898Snjl errx(1, "%s", devstat_errbuf); 333171898Snjl 334144876Snjl if (numbers) { 335144876Snjl mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 336141240Snjl kb_per_transfer, transfers_per_second, 337171898Snjl mb_per_second); 338171898Snjl return(row); 339171898Snjl } 340141240Snjl wmove(wnd, row++, _col); 341141240Snjl histogram(mb_per_second, 50, .5); 342141240Snjl wmove(wnd, row++, _col); 343141240Snjl histogram(transfers_per_second, 50, .5); 344141240Snjl if (kbpt) { 345141413Snjl wmove(wnd, row++, _col); 346141413Snjl histogram(kb_per_transfer, 50, .5); 347141413Snjl } 348141413Snjl 349141413Snjl return(row); 350141413Snjl 351141413Snjl} 352141943Snjl 353171898Snjlstatic void 354141943Snjlstat1(row, o) 355171898Snjl int row, o; 356171898Snjl{ 357171898Snjl int i; 358144876Snjl double dtime; 359144876Snjl 360141413Snjl dtime = 0.0; 361171898Snjl for (i = 0; i < CPUSTATES; i++) 362171898Snjl dtime += cur.cp_time[i]; 363171898Snjl if (dtime == 0.0) 364141413Snjl dtime = 1.0; 365141413Snjl wmove(wnd, row, INSET); 366141413Snjl#define CPUSCALE 0.5 367141413Snjl histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 368141413Snjl} 369141240Snjl 370149239Sumestatic void 371141923Snjlhistogram(val, colwidth, scale) 372141923Snjl long double val; 373150847Sume int colwidth; 374141923Snjl double scale; 375141923Snjl{ 376150847Sume char buf[10]; 377144876Snjl int k; 378144876Snjl int v = (int)(val * scale) + 0.5; 379150847Sume 380150847Sume k = MIN(v, colwidth); 381150847Sume if (v > colwidth) { 382150847Sume snprintf(buf, sizeof(buf), "%5.2Lf", val); 383150847Sume k -= strlen(buf); 384150847Sume while (k--) 385150847Sume waddch(wnd, 'X'); 386150847Sume waddstr(wnd, buf); 387141923Snjl return; 388141240Snjl } 389141923Snjl while (k--) 390141240Snjl waddch(wnd, 'X'); 391150847Sume wclrtoeol(wnd); 392150847Sume} 393150847Sume 394150847Sumeint 395150847Sumecmdiostat(cmd, args) 396150847Sume const char *cmd, *args; 397150847Sume{ 398150847Sume 399141240Snjl if (prefix(cmd, "kbpt")) 400142603Snjl kbpt = !kbpt; 401167905Snjl else if (prefix(cmd, "numbers")) 402167905Snjl numbers = 1; 403167905Snjl else if (prefix(cmd, "bars")) 404167905Snjl numbers = 0; 405167905Snjl else if (!dscmd(cmd, args, 100, &cur)) 406167905Snjl return (0); 407142603Snjl wclear(wnd); 408141240Snjl labeliostat(); 409167905Snjl refresh(); 410141240Snjl return (1); 411141240Snjl} 412141240Snjl