iostat.c revision 200462
11590Srgrimes/* 239230Sgibbs * Copyright (c) 1998 Kenneth D. Merry. 339230Sgibbs * All rights reserved. 439230Sgibbs * 539230Sgibbs * Redistribution and use in source and binary forms, with or without 639230Sgibbs * modification, are permitted provided that the following conditions 739230Sgibbs * are met: 839230Sgibbs * 1. Redistributions of source code must retain the above copyright 939230Sgibbs * notice, this list of conditions and the following disclaimer. 1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139230Sgibbs * notice, this list of conditions and the following disclaimer in the 1239230Sgibbs * documentation and/or other materials provided with the distribution. 1339230Sgibbs * 3. The name of the author may not be used to endorse or promote products 1439230Sgibbs * derived from this software without specific prior written permission. 1539230Sgibbs * 1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939230Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639230Sgibbs * SUCH DAMAGE. 2739230Sgibbs */ 2839230Sgibbs/* 291590Srgrimes * Copyright (c) 1980, 1992, 1993 301590Srgrimes * The Regents of the University of California. All rights reserved. 311590Srgrimes * 321590Srgrimes * Redistribution and use in source and binary forms, with or without 331590Srgrimes * modification, are permitted provided that the following conditions 341590Srgrimes * are met: 351590Srgrimes * 1. Redistributions of source code must retain the above copyright 361590Srgrimes * notice, this list of conditions and the following disclaimer. 371590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 381590Srgrimes * notice, this list of conditions and the following disclaimer in the 391590Srgrimes * documentation and/or other materials provided with the distribution. 401590Srgrimes * 3. All advertising materials mentioning features or use of this software 411590Srgrimes * must display the following acknowledgement: 421590Srgrimes * This product includes software developed by the University of 431590Srgrimes * California, Berkeley and its contributors. 441590Srgrimes * 4. Neither the name of the University nor the names of its contributors 451590Srgrimes * may be used to endorse or promote products derived from this software 461590Srgrimes * without specific prior written permission. 471590Srgrimes * 481590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 491590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 501590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 511590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 521590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 531590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 541590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 551590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 561590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 571590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 581590Srgrimes * SUCH DAMAGE. 591590Srgrimes */ 601590Srgrimes 6187715Smarkm#include <sys/cdefs.h> 621590Srgrimes 6387715Smarkm__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 200462 2009-12-13 03:14:06Z delphij $"); 6487715Smarkm 6587715Smarkm#ifdef lint 6687715Smarkmstatic const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 6787715Smarkm#endif 6887715Smarkm 691590Srgrimes#include <sys/param.h> 7074671Stmm#include <sys/sysctl.h> 71111007Sphk#include <sys/resource.h> 721590Srgrimes 7387715Smarkm#include <devstat.h> 7487715Smarkm#include <err.h> 751590Srgrimes#include <nlist.h> 76200462Sdelphij#include <paths.h> 7787715Smarkm#include <stdlib.h> 7887715Smarkm#include <string.h> 7987715Smarkm 801590Srgrimes#include "systat.h" 811590Srgrimes#include "extern.h" 8240060Sobrien#include "devs.h" 831590Srgrimes 8439230Sgibbsstruct statinfo cur, last; 851590Srgrimes 861590Srgrimesstatic int linesperregion; 871590Srgrimesstatic double etime; 881590Srgrimesstatic int numbers = 0; /* default display bar graphs */ 8939230Sgibbsstatic int kbpt = 0; /* default ms/seek shown */ 901590Srgrimes 9192922Simpstatic int barlabels(int); 9292922Simpstatic void histogram(long double, int, double); 9392922Simpstatic int numlabels(int); 9492922Simpstatic int devstats(int, int, int); 9592922Simpstatic void stat1(int, int); 961590Srgrimes 971590SrgrimesWINDOW * 98175387Sdelphijopeniostat(void) 991590Srgrimes{ 100158160Sbde return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); 1011590Srgrimes} 1021590Srgrimes 1031590Srgrimesvoid 104175387Sdelphijcloseiostat(WINDOW *w) 1051590Srgrimes{ 1061590Srgrimes if (w == NULL) 1071590Srgrimes return; 1081590Srgrimes wclear(w); 1091590Srgrimes wrefresh(w); 1101590Srgrimes delwin(w); 1111590Srgrimes} 1121590Srgrimes 1131590Srgrimesint 114175387Sdelphijinitiostat(void) 1151590Srgrimes{ 11683131Sken if ((num_devices = devstat_getnumdevs(NULL)) < 0) 1171590Srgrimes return(0); 11839230Sgibbs 11939230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 12039230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 12139230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 12239230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 123158161Sbde 12439230Sgibbs /* 12539230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 12639230Sgibbs * how to calculate it, though. 12739230Sgibbs */ 12839230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 12939230Sgibbs return(0); 13039230Sgibbs 1311590Srgrimes return(1); 1321590Srgrimes} 1331590Srgrimes 1341590Srgrimesvoid 135175387Sdelphijfetchiostat(void) 1361590Srgrimes{ 13739230Sgibbs struct devinfo *tmp_dinfo; 13869141Srwatson size_t len; 13939230Sgibbs 14069141Srwatson len = sizeof(cur.cp_time); 14187715Smarkm if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 14287715Smarkm || len != sizeof(cur.cp_time)) { 14369141Srwatson perror("kern.cp_time"); 14469141Srwatson exit (1); 14569141Srwatson } 14639230Sgibbs tmp_dinfo = last.dinfo; 14739230Sgibbs last.dinfo = cur.dinfo; 14839230Sgibbs cur.dinfo = tmp_dinfo; 149121836Stjr 150121836Stjr last.snap_time = cur.snap_time; 151158161Sbde 15239230Sgibbs /* 15339230Sgibbs * Here what we want to do is refresh our device stats. 15439230Sgibbs * getdevs() returns 1 when the device list has changed. 15539230Sgibbs * If the device list has changed, we want to go through 15639230Sgibbs * the selection process again, in case a device that we 15739230Sgibbs * were previously displaying has gone away. 15839230Sgibbs */ 15983131Sken switch (devstat_getdevs(NULL, &cur)) { 16039230Sgibbs case -1: 16139230Sgibbs errx(1, "%s", devstat_errbuf); 16239230Sgibbs break; 16339230Sgibbs case 1: 16439230Sgibbs cmdiostat("refresh", NULL); 16539230Sgibbs break; 16639230Sgibbs default: 16739230Sgibbs break; 16839230Sgibbs } 16939230Sgibbs num_devices = cur.dinfo->numdevs; 17039230Sgibbs generation = cur.dinfo->generation; 17139230Sgibbs 1721590Srgrimes} 1731590Srgrimes 1741590Srgrimes#define INSET 10 1751590Srgrimes 1761590Srgrimesvoid 177175387Sdelphijlabeliostat(void) 1781590Srgrimes{ 1791590Srgrimes int row; 1801590Srgrimes 1811590Srgrimes row = 0; 1821590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1831590Srgrimes mvwaddstr(wnd, row++, INSET, 184164689Syar "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1851590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1861590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 1871590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 1884930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 1891590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 1901590Srgrimes if (numbers) 1911590Srgrimes row = numlabels(row + 1); 1921590Srgrimes else 1931590Srgrimes row = barlabels(row + 1); 1941590Srgrimes} 1951590Srgrimes 1961590Srgrimesstatic int 197175387Sdelphijnumlabels(int row) 1981590Srgrimes{ 19987715Smarkm int i, _col, regions, ndrives; 20039230Sgibbs char tmpstr[10]; 2011590Srgrimes 20239230Sgibbs#define COLWIDTH 17 20350635Speter#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 20439230Sgibbs for (ndrives = 0, i = 0; i < num_devices; i++) 20539230Sgibbs if (dev_select[i].selected) 2061590Srgrimes ndrives++; 2071590Srgrimes regions = howmany(ndrives, DRIVESPERLINE); 2081590Srgrimes /* 2091590Srgrimes * Deduct -regions for blank line after each scrolling region. 2101590Srgrimes */ 21150635Speter linesperregion = (wnd->_maxy - row - regions) / regions; 2121590Srgrimes /* 2131590Srgrimes * Minimum region contains space for two 2141590Srgrimes * label lines and one line of statistics. 2151590Srgrimes */ 2161590Srgrimes if (linesperregion < 3) 2171590Srgrimes linesperregion = 3; 21887715Smarkm _col = INSET; 21939230Sgibbs for (i = 0; i < num_devices; i++) 22039230Sgibbs if (dev_select[i].selected) { 22187715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 22287715Smarkm _col = INSET, row += linesperregion + 1; 22350635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2241590Srgrimes break; 2251590Srgrimes } 22639230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 22739230Sgibbs dev_select[i].unit_number); 22887715Smarkm mvwaddstr(wnd, row, _col + 4, tmpstr); 22987715Smarkm mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 23087715Smarkm _col += COLWIDTH; 2311590Srgrimes } 23287715Smarkm if (_col) 2331590Srgrimes row += linesperregion + 1; 2341590Srgrimes return (row); 2351590Srgrimes} 2361590Srgrimes 2371590Srgrimesstatic int 238175387Sdelphijbarlabels(int row) 2391590Srgrimes{ 2401590Srgrimes int i; 24139230Sgibbs char tmpstr[10]; 2421590Srgrimes 2431590Srgrimes mvwaddstr(wnd, row++, INSET, 244164689Syar "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 24539230Sgibbs linesperregion = 2 + kbpt; 24639230Sgibbs for (i = 0; i < num_devices; i++) 24739230Sgibbs if (dev_select[i].selected) { 24850635Speter if (row > wnd->_maxy - linesperregion) 2491590Srgrimes break; 25039230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 25139230Sgibbs dev_select[i].unit_number); 252158161Sbde mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 25339230Sgibbs tmpstr); 2541590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 25539230Sgibbs if (kbpt) 25639230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2571590Srgrimes } 2581590Srgrimes return (row); 2591590Srgrimes} 2601590Srgrimes 2611590Srgrimes 2621590Srgrimesvoid 263175387Sdelphijshowiostat(void) 2641590Srgrimes{ 26587715Smarkm long t; 26687715Smarkm int i, row, _col; 2671590Srgrimes 26839230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2691590Srgrimes etime = 0; 2701590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2711590Srgrimes X(cp_time); 27239230Sgibbs etime += cur.cp_time[i]; 2731590Srgrimes } 2741590Srgrimes if (etime == 0.0) 2751590Srgrimes etime = 1.0; 2764930Sbde etime /= hertz; 2771590Srgrimes row = 1; 2784930Sbde for (i = 0; i < CPUSTATES; i++) 2791590Srgrimes stat1(row++, i); 2801590Srgrimes if (!numbers) { 2811590Srgrimes row += 2; 28239230Sgibbs for (i = 0; i < num_devices; i++) 28339230Sgibbs if (dev_select[i].selected) { 28450635Speter if (row > wnd->_maxy - linesperregion) 2851590Srgrimes break; 28639230Sgibbs row = devstats(row, INSET, i); 2871590Srgrimes } 2881590Srgrimes return; 2891590Srgrimes } 29087715Smarkm _col = INSET; 2911590Srgrimes wmove(wnd, row + linesperregion, 0); 2921590Srgrimes wdeleteln(wnd); 2931590Srgrimes wmove(wnd, row + 3, 0); 2941590Srgrimes winsertln(wnd); 29539230Sgibbs for (i = 0; i < num_devices; i++) 29639230Sgibbs if (dev_select[i].selected) { 29787715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 29887715Smarkm _col = INSET, row += linesperregion + 1; 29950635Speter if (row > wnd->_maxy - (linesperregion + 1)) 3001590Srgrimes break; 3011590Srgrimes wmove(wnd, row + linesperregion, 0); 3021590Srgrimes wdeleteln(wnd); 3031590Srgrimes wmove(wnd, row + 3, 0); 3041590Srgrimes winsertln(wnd); 3051590Srgrimes } 30687715Smarkm (void) devstats(row + 3, _col, i); 30787715Smarkm _col += COLWIDTH; 3081590Srgrimes } 3091590Srgrimes} 3101590Srgrimes 3111590Srgrimesstatic int 312175387Sdelphijdevstats(int row, int _col, int dn) 3131590Srgrimes{ 31439230Sgibbs long double transfers_per_second; 31539230Sgibbs long double kb_per_transfer, mb_per_second; 31639230Sgibbs long double busy_seconds; 31739230Sgibbs int di; 318158161Sbde 31939230Sgibbs di = dev_select[dn].position; 3201590Srgrimes 321112288Sphk busy_seconds = cur.snap_time - last.snap_time; 32239230Sgibbs 32383131Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 32483131Sken &last.dinfo->devices[di], busy_seconds, 32583131Sken DSM_KB_PER_TRANSFER, &kb_per_transfer, 32683131Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 32783131Sken DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 32839230Sgibbs errx(1, "%s", devstat_errbuf); 32939230Sgibbs 3301590Srgrimes if (numbers) { 33187715Smarkm mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 33239230Sgibbs kb_per_transfer, transfers_per_second, 33339230Sgibbs mb_per_second); 33439230Sgibbs return(row); 3351590Srgrimes } 33687715Smarkm wmove(wnd, row++, _col); 33761148Sphk histogram(mb_per_second, 50, .5); 33887715Smarkm wmove(wnd, row++, _col); 33961148Sphk histogram(transfers_per_second, 50, .5); 34039230Sgibbs if (kbpt) { 34187715Smarkm wmove(wnd, row++, _col); 34261148Sphk histogram(kb_per_transfer, 50, .5); 3431590Srgrimes } 34439230Sgibbs 34539230Sgibbs return(row); 34639230Sgibbs 3471590Srgrimes} 3481590Srgrimes 3491590Srgrimesstatic void 350175387Sdelphijstat1(int row, int o) 3511590Srgrimes{ 35287715Smarkm int i; 35387715Smarkm double dtime; 3541590Srgrimes 35587715Smarkm dtime = 0.0; 3561590Srgrimes for (i = 0; i < CPUSTATES; i++) 35787715Smarkm dtime += cur.cp_time[i]; 35887715Smarkm if (dtime == 0.0) 35987715Smarkm dtime = 1.0; 3601590Srgrimes wmove(wnd, row, INSET); 3611590Srgrimes#define CPUSCALE 0.5 36287715Smarkm histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 3631590Srgrimes} 3641590Srgrimes 3651590Srgrimesstatic void 366175387Sdelphijhistogram(long double val, int colwidth, double scale) 3671590Srgrimes{ 3681590Srgrimes char buf[10]; 36987715Smarkm int k; 37087715Smarkm int v = (int)(val * scale) + 0.5; 3711590Srgrimes 3721590Srgrimes k = MIN(v, colwidth); 3731590Srgrimes if (v > colwidth) { 37439230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3751590Srgrimes k -= strlen(buf); 3761590Srgrimes while (k--) 3771590Srgrimes waddch(wnd, 'X'); 3781590Srgrimes waddstr(wnd, buf); 3791590Srgrimes return; 3801590Srgrimes } 3811590Srgrimes while (k--) 3821590Srgrimes waddch(wnd, 'X'); 3831590Srgrimes wclrtoeol(wnd); 3841590Srgrimes} 3851590Srgrimes 3861590Srgrimesint 387175387Sdelphijcmdiostat(const char *cmd, const char *args) 3881590Srgrimes{ 3891590Srgrimes 39039230Sgibbs if (prefix(cmd, "kbpt")) 39139230Sgibbs kbpt = !kbpt; 3921590Srgrimes else if (prefix(cmd, "numbers")) 3931590Srgrimes numbers = 1; 3941590Srgrimes else if (prefix(cmd, "bars")) 3951590Srgrimes numbers = 0; 39639230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 3971590Srgrimes return (0); 3981590Srgrimes wclear(wnd); 3991590Srgrimes labeliostat(); 4001590Srgrimes refresh(); 4011590Srgrimes return (1); 4021590Srgrimes} 403