iostat.c revision 200462
1184610Salfred/* 2184610Salfred * Copyright (c) 1998 Kenneth D. Merry. 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 3. The name of the author may not be used to endorse or promote products 14184610Salfred * derived from this software without specific prior written permission. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred/* 29184610Salfred * Copyright (c) 1980, 1992, 1993 30184610Salfred * The Regents of the University of California. All rights reserved. 31184610Salfred * 32184610Salfred * Redistribution and use in source and binary forms, with or without 33184610Salfred * modification, are permitted provided that the following conditions 34184610Salfred * are met: 35184610Salfred * 1. Redistributions of source code must retain the above copyright 36184610Salfred * notice, this list of conditions and the following disclaimer. 37184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 38184610Salfred * notice, this list of conditions and the following disclaimer in the 39184610Salfred * documentation and/or other materials provided with the distribution. 40184610Salfred * 3. All advertising materials mentioning features or use of this software 41187170Sthompsa * must display the following acknowledgement: 42187170Sthompsa * This product includes software developed by the University of 43184610Salfred * California, Berkeley and its contributors. 44184610Salfred * 4. Neither the name of the University nor the names of its contributors 45184610Salfred * may be used to endorse or promote products derived from this software 46184610Salfred * without specific prior written permission. 47184610Salfred * 48184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58184610Salfred * SUCH DAMAGE. 59184610Salfred */ 60184610Salfred 61184610Salfred#include <sys/cdefs.h> 62184610Salfred 63184610Salfred__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 200462 2009-12-13 03:14:06Z delphij $"); 64184610Salfred 65184610Salfred#ifdef lint 66184610Salfredstatic const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 67184610Salfred#endif 68184610Salfred 69184610Salfred#include <sys/param.h> 70184610Salfred#include <sys/sysctl.h> 71184610Salfred#include <sys/resource.h> 72184610Salfred 73184610Salfred#include <devstat.h> 74184610Salfred#include <err.h> 75184610Salfred#include <nlist.h> 76184610Salfred#include <paths.h> 77184610Salfred#include <stdlib.h> 78184610Salfred#include <string.h> 79184610Salfred 80184610Salfred#include "systat.h" 81184610Salfred#include "extern.h" 82184610Salfred#include "devs.h" 83184610Salfred 84184610Salfredstruct statinfo cur, last; 85184610Salfred 86184610Salfredstatic int linesperregion; 87184610Salfredstatic double etime; 88184610Salfredstatic int numbers = 0; /* default display bar graphs */ 89184610Salfredstatic int kbpt = 0; /* default ms/seek shown */ 90184610Salfred 91184610Salfredstatic int barlabels(int); 92184610Salfredstatic void histogram(long double, int, double); 93184610Salfredstatic int numlabels(int); 94184610Salfredstatic int devstats(int, int, int); 95184610Salfredstatic void stat1(int, int); 96184610Salfred 97184610SalfredWINDOW * 98184610Salfredopeniostat(void) 99184610Salfred{ 100184610Salfred return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); 101184610Salfred} 102184610Salfred 103184610Salfredvoid 104184610Salfredcloseiostat(WINDOW *w) 105184610Salfred{ 106184610Salfred if (w == NULL) 107184610Salfred return; 108184610Salfred wclear(w); 109184610Salfred wrefresh(w); 110184610Salfred delwin(w); 111184610Salfred} 112184610Salfred 113184610Salfredint 114184610Salfredinitiostat(void) 115184610Salfred{ 116184610Salfred if ((num_devices = devstat_getnumdevs(NULL)) < 0) 117184610Salfred return(0); 118184610Salfred 119184610Salfred cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 120184610Salfred last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 121184610Salfred bzero(cur.dinfo, sizeof(struct devinfo)); 122184610Salfred bzero(last.dinfo, sizeof(struct devinfo)); 123184610Salfred 124184610Salfred /* 125184610Salfred * This value for maxshowdevs (100) is bogus. I'm not sure exactly 126184610Salfred * how to calculate it, though. 127184610Salfred */ 128184610Salfred if (dsinit(100, &cur, &last, NULL) != 1) 129184610Salfred return(0); 130184610Salfred 131184610Salfred return(1); 132184610Salfred} 133184610Salfred 134184610Salfredvoid 135184610Salfredfetchiostat(void) 136184610Salfred{ 137184610Salfred struct devinfo *tmp_dinfo; 138184610Salfred size_t len; 139184610Salfred 140184610Salfred len = sizeof(cur.cp_time); 141184610Salfred if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 142184610Salfred || len != sizeof(cur.cp_time)) { 143184610Salfred perror("kern.cp_time"); 144184610Salfred exit (1); 145184610Salfred } 146184610Salfred tmp_dinfo = last.dinfo; 147184610Salfred last.dinfo = cur.dinfo; 148184610Salfred cur.dinfo = tmp_dinfo; 149184610Salfred 150184610Salfred last.snap_time = cur.snap_time; 151184610Salfred 152184610Salfred /* 153184610Salfred * Here what we want to do is refresh our device stats. 154184610Salfred * getdevs() returns 1 when the device list has changed. 155184610Salfred * If the device list has changed, we want to go through 156184610Salfred * the selection process again, in case a device that we 157184610Salfred * were previously displaying has gone away. 158184610Salfred */ 159184610Salfred switch (devstat_getdevs(NULL, &cur)) { 160184610Salfred case -1: 161184610Salfred errx(1, "%s", devstat_errbuf); 162184610Salfred break; 163184610Salfred case 1: 164184610Salfred cmdiostat("refresh", NULL); 165186730Salfred break; 166186730Salfred default: 167186730Salfred break; 168186730Salfred } 169186730Salfred num_devices = cur.dinfo->numdevs; 170186730Salfred generation = cur.dinfo->generation; 171186730Salfred 172186730Salfred} 173186730Salfred 174184610Salfred#define INSET 10 175184610Salfred 176184610Salfredvoid 177184610Salfredlabeliostat(void) 178184610Salfred{ 179184610Salfred int row; 180184610Salfred 181184610Salfred row = 0; 182184610Salfred wmove(wnd, row, 0); wclrtobot(wnd); 183184610Salfred mvwaddstr(wnd, row++, INSET, 184184610Salfred "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 185184610Salfred mvwaddstr(wnd, row++, 0, "cpu user|"); 186184610Salfred mvwaddstr(wnd, row++, 0, " nice|"); 187184610Salfred mvwaddstr(wnd, row++, 0, " system|"); 188184610Salfred mvwaddstr(wnd, row++, 0, "interrupt|"); 189184610Salfred mvwaddstr(wnd, row++, 0, " idle|"); 190184610Salfred if (numbers) 191184610Salfred row = numlabels(row + 1); 192184610Salfred else 193184610Salfred row = barlabels(row + 1); 194184610Salfred} 195184610Salfred 196184610Salfredstatic int 197184610Salfrednumlabels(int row) 198184610Salfred{ 199184610Salfred int i, _col, regions, ndrives; 200184610Salfred char tmpstr[10]; 201184610Salfred 202184610Salfred#define COLWIDTH 17 203184610Salfred#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 204184610Salfred for (ndrives = 0, i = 0; i < num_devices; i++) 205184610Salfred if (dev_select[i].selected) 206184610Salfred ndrives++; 207184610Salfred regions = howmany(ndrives, DRIVESPERLINE); 208184610Salfred /* 209184610Salfred * Deduct -regions for blank line after each scrolling region. 210184610Salfred */ 211184610Salfred linesperregion = (wnd->_maxy - row - regions) / regions; 212184610Salfred /* 213184610Salfred * Minimum region contains space for two 214184610Salfred * label lines and one line of statistics. 215184610Salfred */ 216184610Salfred if (linesperregion < 3) 217184610Salfred linesperregion = 3; 218184610Salfred _col = INSET; 219184610Salfred for (i = 0; i < num_devices; i++) 220184610Salfred if (dev_select[i].selected) { 221184610Salfred if (_col + COLWIDTH >= wnd->_maxx - INSET) { 222184610Salfred _col = INSET, row += linesperregion + 1; 223184610Salfred if (row > wnd->_maxy - (linesperregion + 1)) 224184610Salfred break; 225184610Salfred } 226184610Salfred sprintf(tmpstr, "%s%d", dev_select[i].device_name, 227184610Salfred dev_select[i].unit_number); 228184610Salfred mvwaddstr(wnd, row, _col + 4, tmpstr); 229184610Salfred mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 230184610Salfred _col += COLWIDTH; 231184610Salfred } 232184610Salfred if (_col) 233184610Salfred row += linesperregion + 1; 234184610Salfred return (row); 235184610Salfred} 236184610Salfred 237184610Salfredstatic int 238184610Salfredbarlabels(int row) 239184610Salfred{ 240184610Salfred int i; 241184610Salfred char tmpstr[10]; 242184610Salfred 243184610Salfred mvwaddstr(wnd, row++, INSET, 244184610Salfred "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 245184610Salfred linesperregion = 2 + kbpt; 246184610Salfred for (i = 0; i < num_devices; i++) 247184610Salfred if (dev_select[i].selected) { 248184610Salfred if (row > wnd->_maxy - linesperregion) 249184610Salfred break; 250184610Salfred sprintf(tmpstr, "%s%d", dev_select[i].device_name, 251184610Salfred dev_select[i].unit_number); 252184610Salfred mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 253184610Salfred tmpstr); 254184610Salfred mvwaddstr(wnd, row++, 0, " tps|"); 255184610Salfred if (kbpt) 256184610Salfred mvwaddstr(wnd, row++, 0, " KB/t|"); 257184610Salfred } 258184610Salfred return (row); 259184610Salfred} 260184610Salfred 261184610Salfred 262184610Salfredvoid 263184610Salfredshowiostat(void) 264184610Salfred{ 265184610Salfred long t; 266184610Salfred int i, row, _col; 267184610Salfred 268184610Salfred#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 269184610Salfred etime = 0; 270184610Salfred for(i = 0; i < CPUSTATES; i++) { 271184610Salfred X(cp_time); 272184610Salfred etime += cur.cp_time[i]; 273184610Salfred } 274184610Salfred if (etime == 0.0) 275184610Salfred etime = 1.0; 276184610Salfred etime /= hertz; 277184610Salfred row = 1; 278184610Salfred for (i = 0; i < CPUSTATES; i++) 279184610Salfred stat1(row++, i); 280184610Salfred if (!numbers) { 281184610Salfred row += 2; 282184610Salfred for (i = 0; i < num_devices; i++) 283184610Salfred if (dev_select[i].selected) { 284184610Salfred if (row > wnd->_maxy - linesperregion) 285184610Salfred break; 286184610Salfred row = devstats(row, INSET, i); 287184610Salfred } 288184610Salfred return; 289184610Salfred } 290184610Salfred _col = INSET; 291184610Salfred wmove(wnd, row + linesperregion, 0); 292184610Salfred wdeleteln(wnd); 293184610Salfred wmove(wnd, row + 3, 0); 294184610Salfred winsertln(wnd); 295184610Salfred for (i = 0; i < num_devices; i++) 296184610Salfred if (dev_select[i].selected) { 297184610Salfred if (_col + COLWIDTH >= wnd->_maxx - INSET) { 298184610Salfred _col = INSET, row += linesperregion + 1; 299184610Salfred if (row > wnd->_maxy - (linesperregion + 1)) 300184610Salfred break; 301184610Salfred wmove(wnd, row + linesperregion, 0); 302184610Salfred wdeleteln(wnd); 303184610Salfred wmove(wnd, row + 3, 0); 304184610Salfred winsertln(wnd); 305184610Salfred } 306184610Salfred (void) devstats(row + 3, _col, i); 307184610Salfred _col += COLWIDTH; 308184610Salfred } 309184610Salfred} 310184610Salfred 311184610Salfredstatic int 312184610Salfreddevstats(int row, int _col, int dn) 313184610Salfred{ 314184610Salfred long double transfers_per_second; 315184610Salfred long double kb_per_transfer, mb_per_second; 316184610Salfred long double busy_seconds; 317184610Salfred int di; 318184610Salfred 319184610Salfred di = dev_select[dn].position; 320184610Salfred 321184610Salfred busy_seconds = cur.snap_time - last.snap_time; 322184610Salfred 323184610Salfred if (devstat_compute_statistics(&cur.dinfo->devices[di], 324184610Salfred &last.dinfo->devices[di], busy_seconds, 325184610Salfred DSM_KB_PER_TRANSFER, &kb_per_transfer, 326184610Salfred DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 327184610Salfred DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 328184610Salfred errx(1, "%s", devstat_errbuf); 329184610Salfred 330184610Salfred if (numbers) { 331184610Salfred mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 332184610Salfred kb_per_transfer, transfers_per_second, 333184610Salfred mb_per_second); 334184610Salfred return(row); 335184610Salfred } 336184610Salfred wmove(wnd, row++, _col); 337184610Salfred histogram(mb_per_second, 50, .5); 338184610Salfred wmove(wnd, row++, _col); 339184610Salfred histogram(transfers_per_second, 50, .5); 340184610Salfred if (kbpt) { 341184610Salfred wmove(wnd, row++, _col); 342184610Salfred histogram(kb_per_transfer, 50, .5); 343184610Salfred } 344184610Salfred 345184610Salfred return(row); 346184610Salfred 347184610Salfred} 348184610Salfred 349184610Salfredstatic void 350184610Salfredstat1(int row, int o) 351184610Salfred{ 352184610Salfred int i; 353184610Salfred double dtime; 354184610Salfred 355184610Salfred dtime = 0.0; 356184610Salfred for (i = 0; i < CPUSTATES; i++) 357184610Salfred dtime += cur.cp_time[i]; 358184610Salfred if (dtime == 0.0) 359184610Salfred dtime = 1.0; 360184610Salfred wmove(wnd, row, INSET); 361184610Salfred#define CPUSCALE 0.5 362184610Salfred histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 363184610Salfred} 364184610Salfred 365184610Salfredstatic void 366184610Salfredhistogram(long double val, int colwidth, double scale) 367184610Salfred{ 368184610Salfred char buf[10]; 369184610Salfred int k; 370184610Salfred int v = (int)(val * scale) + 0.5; 371184610Salfred 372184610Salfred k = MIN(v, colwidth); 373184610Salfred if (v > colwidth) { 374184610Salfred snprintf(buf, sizeof(buf), "%5.2Lf", val); 375184610Salfred k -= strlen(buf); 376184610Salfred while (k--) 377184610Salfred waddch(wnd, 'X'); 378184610Salfred waddstr(wnd, buf); 379184610Salfred return; 380184610Salfred } 381184610Salfred while (k--) 382184610Salfred waddch(wnd, 'X'); 383184610Salfred wclrtoeol(wnd); 384184610Salfred} 385184610Salfred 386184610Salfredint 387184610Salfredcmdiostat(const char *cmd, const char *args) 388184610Salfred{ 389184610Salfred 390184610Salfred if (prefix(cmd, "kbpt")) 391184610Salfred kbpt = !kbpt; 392184610Salfred else if (prefix(cmd, "numbers")) 393184610Salfred numbers = 1; 394184610Salfred else if (prefix(cmd, "bars")) 395184610Salfred numbers = 0; 396184610Salfred else if (!dscmd(cmd, args, 100, &cur)) 397184610Salfred return (0); 398184610Salfred wclear(wnd); 399184610Salfred labeliostat(); 400184610Salfred refresh(); 401184610Salfred return (1); 402184610Salfred} 403184610Salfred