iostat.c revision 158161
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 158161 2006-04-30 04:47:23Z bde $"); 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> 761590Srgrimes#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 * 981590Srgrimesopeniostat() 991590Srgrimes{ 100158160Sbde return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); 1011590Srgrimes} 1021590Srgrimes 1031590Srgrimesvoid 1041590Srgrimescloseiostat(w) 1051590Srgrimes WINDOW *w; 1061590Srgrimes{ 1071590Srgrimes if (w == NULL) 1081590Srgrimes return; 1091590Srgrimes wclear(w); 1101590Srgrimes wrefresh(w); 1111590Srgrimes delwin(w); 1121590Srgrimes} 1131590Srgrimes 1141590Srgrimesint 1151590Srgrimesinitiostat() 1161590Srgrimes{ 11783131Sken if ((num_devices = devstat_getnumdevs(NULL)) < 0) 1181590Srgrimes return(0); 11939230Sgibbs 12039230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 12139230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 12239230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 12339230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 124158161Sbde 12539230Sgibbs /* 12639230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 12739230Sgibbs * how to calculate it, though. 12839230Sgibbs */ 12939230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 13039230Sgibbs return(0); 13139230Sgibbs 1321590Srgrimes return(1); 1331590Srgrimes} 1341590Srgrimes 1351590Srgrimesvoid 1361590Srgrimesfetchiostat() 1371590Srgrimes{ 13839230Sgibbs struct devinfo *tmp_dinfo; 13969141Srwatson size_t len; 14039230Sgibbs 14169141Srwatson len = sizeof(cur.cp_time); 14287715Smarkm if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 14387715Smarkm || len != sizeof(cur.cp_time)) { 14469141Srwatson perror("kern.cp_time"); 14569141Srwatson exit (1); 14669141Srwatson } 14739230Sgibbs tmp_dinfo = last.dinfo; 14839230Sgibbs last.dinfo = cur.dinfo; 14939230Sgibbs cur.dinfo = tmp_dinfo; 150121836Stjr 151121836Stjr last.snap_time = cur.snap_time; 152158161Sbde 15339230Sgibbs /* 15439230Sgibbs * Here what we want to do is refresh our device stats. 15539230Sgibbs * getdevs() returns 1 when the device list has changed. 15639230Sgibbs * If the device list has changed, we want to go through 15739230Sgibbs * the selection process again, in case a device that we 15839230Sgibbs * were previously displaying has gone away. 15939230Sgibbs */ 16083131Sken switch (devstat_getdevs(NULL, &cur)) { 16139230Sgibbs case -1: 16239230Sgibbs errx(1, "%s", devstat_errbuf); 16339230Sgibbs break; 16439230Sgibbs case 1: 16539230Sgibbs cmdiostat("refresh", NULL); 16639230Sgibbs break; 16739230Sgibbs default: 16839230Sgibbs break; 16939230Sgibbs } 17039230Sgibbs num_devices = cur.dinfo->numdevs; 17139230Sgibbs generation = cur.dinfo->generation; 17239230Sgibbs 1731590Srgrimes} 1741590Srgrimes 1751590Srgrimes#define INSET 10 1761590Srgrimes 1771590Srgrimesvoid 1781590Srgrimeslabeliostat() 1791590Srgrimes{ 1801590Srgrimes int row; 1811590Srgrimes 1821590Srgrimes row = 0; 1831590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1841590Srgrimes mvwaddstr(wnd, row++, INSET, 1851590Srgrimes "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1861590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1871590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 1881590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 1894930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 1901590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 1911590Srgrimes if (numbers) 1921590Srgrimes row = numlabels(row + 1); 1931590Srgrimes else 1941590Srgrimes row = barlabels(row + 1); 1951590Srgrimes} 1961590Srgrimes 1971590Srgrimesstatic int 1981590Srgrimesnumlabels(row) 1991590Srgrimes int row; 2001590Srgrimes{ 20187715Smarkm int i, _col, regions, ndrives; 20239230Sgibbs char tmpstr[10]; 2031590Srgrimes 20439230Sgibbs#define COLWIDTH 17 20550635Speter#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 20639230Sgibbs for (ndrives = 0, i = 0; i < num_devices; i++) 20739230Sgibbs if (dev_select[i].selected) 2081590Srgrimes ndrives++; 2091590Srgrimes regions = howmany(ndrives, DRIVESPERLINE); 2101590Srgrimes /* 2111590Srgrimes * Deduct -regions for blank line after each scrolling region. 2121590Srgrimes */ 21350635Speter linesperregion = (wnd->_maxy - row - regions) / regions; 2141590Srgrimes /* 2151590Srgrimes * Minimum region contains space for two 2161590Srgrimes * label lines and one line of statistics. 2171590Srgrimes */ 2181590Srgrimes if (linesperregion < 3) 2191590Srgrimes linesperregion = 3; 22087715Smarkm _col = INSET; 22139230Sgibbs for (i = 0; i < num_devices; i++) 22239230Sgibbs if (dev_select[i].selected) { 22387715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 22487715Smarkm _col = INSET, row += linesperregion + 1; 22550635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2261590Srgrimes break; 2271590Srgrimes } 22839230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 22939230Sgibbs dev_select[i].unit_number); 23087715Smarkm mvwaddstr(wnd, row, _col + 4, tmpstr); 23187715Smarkm mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 23287715Smarkm _col += COLWIDTH; 2331590Srgrimes } 23487715Smarkm if (_col) 2351590Srgrimes row += linesperregion + 1; 2361590Srgrimes return (row); 2371590Srgrimes} 2381590Srgrimes 2391590Srgrimesstatic int 2401590Srgrimesbarlabels(row) 2411590Srgrimes int row; 2421590Srgrimes{ 2431590Srgrimes int i; 24439230Sgibbs char tmpstr[10]; 2451590Srgrimes 2461590Srgrimes mvwaddstr(wnd, row++, INSET, 24761147Sphk "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 24839230Sgibbs linesperregion = 2 + kbpt; 24939230Sgibbs for (i = 0; i < num_devices; i++) 25039230Sgibbs if (dev_select[i].selected) { 25150635Speter if (row > wnd->_maxy - linesperregion) 2521590Srgrimes break; 25339230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 25439230Sgibbs dev_select[i].unit_number); 255158161Sbde mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 25639230Sgibbs tmpstr); 2571590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 25839230Sgibbs if (kbpt) 25939230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2601590Srgrimes } 2611590Srgrimes return (row); 2621590Srgrimes} 2631590Srgrimes 2641590Srgrimes 2651590Srgrimesvoid 2661590Srgrimesshowiostat() 2671590Srgrimes{ 26887715Smarkm long t; 26987715Smarkm int i, row, _col; 2701590Srgrimes 27139230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2721590Srgrimes etime = 0; 2731590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2741590Srgrimes X(cp_time); 27539230Sgibbs etime += cur.cp_time[i]; 2761590Srgrimes } 2771590Srgrimes if (etime == 0.0) 2781590Srgrimes etime = 1.0; 2794930Sbde etime /= hertz; 2801590Srgrimes row = 1; 2814930Sbde for (i = 0; i < CPUSTATES; i++) 2821590Srgrimes stat1(row++, i); 2831590Srgrimes if (!numbers) { 2841590Srgrimes row += 2; 28539230Sgibbs for (i = 0; i < num_devices; i++) 28639230Sgibbs if (dev_select[i].selected) { 28750635Speter if (row > wnd->_maxy - linesperregion) 2881590Srgrimes break; 28939230Sgibbs row = devstats(row, INSET, i); 2901590Srgrimes } 2911590Srgrimes return; 2921590Srgrimes } 29387715Smarkm _col = INSET; 2941590Srgrimes wmove(wnd, row + linesperregion, 0); 2951590Srgrimes wdeleteln(wnd); 2961590Srgrimes wmove(wnd, row + 3, 0); 2971590Srgrimes winsertln(wnd); 29839230Sgibbs for (i = 0; i < num_devices; i++) 29939230Sgibbs if (dev_select[i].selected) { 30087715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 30187715Smarkm _col = INSET, row += linesperregion + 1; 30250635Speter if (row > wnd->_maxy - (linesperregion + 1)) 3031590Srgrimes break; 3041590Srgrimes wmove(wnd, row + linesperregion, 0); 3051590Srgrimes wdeleteln(wnd); 3061590Srgrimes wmove(wnd, row + 3, 0); 3071590Srgrimes winsertln(wnd); 3081590Srgrimes } 30987715Smarkm (void) devstats(row + 3, _col, i); 31087715Smarkm _col += COLWIDTH; 3111590Srgrimes } 3121590Srgrimes} 3131590Srgrimes 3141590Srgrimesstatic int 31587715Smarkmdevstats(row, _col, dn) 31687715Smarkm int row, _col, dn; 3171590Srgrimes{ 31839230Sgibbs long double transfers_per_second; 31939230Sgibbs long double kb_per_transfer, mb_per_second; 32039230Sgibbs long double busy_seconds; 32139230Sgibbs int di; 322158161Sbde 32339230Sgibbs di = dev_select[dn].position; 3241590Srgrimes 325112288Sphk busy_seconds = cur.snap_time - last.snap_time; 32639230Sgibbs 32783131Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 32883131Sken &last.dinfo->devices[di], busy_seconds, 32983131Sken DSM_KB_PER_TRANSFER, &kb_per_transfer, 33083131Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 33183131Sken DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 33239230Sgibbs errx(1, "%s", devstat_errbuf); 33339230Sgibbs 3341590Srgrimes if (numbers) { 33587715Smarkm mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 33639230Sgibbs kb_per_transfer, transfers_per_second, 33739230Sgibbs mb_per_second); 33839230Sgibbs return(row); 3391590Srgrimes } 34087715Smarkm wmove(wnd, row++, _col); 34161148Sphk histogram(mb_per_second, 50, .5); 34287715Smarkm wmove(wnd, row++, _col); 34361148Sphk histogram(transfers_per_second, 50, .5); 34439230Sgibbs if (kbpt) { 34587715Smarkm wmove(wnd, row++, _col); 34661148Sphk histogram(kb_per_transfer, 50, .5); 3471590Srgrimes } 34839230Sgibbs 34939230Sgibbs return(row); 35039230Sgibbs 3511590Srgrimes} 3521590Srgrimes 3531590Srgrimesstatic void 3541590Srgrimesstat1(row, o) 3551590Srgrimes int row, o; 3561590Srgrimes{ 35787715Smarkm int i; 35887715Smarkm double dtime; 3591590Srgrimes 36087715Smarkm dtime = 0.0; 3611590Srgrimes for (i = 0; i < CPUSTATES; i++) 36287715Smarkm dtime += cur.cp_time[i]; 36387715Smarkm if (dtime == 0.0) 36487715Smarkm dtime = 1.0; 3651590Srgrimes wmove(wnd, row, INSET); 3661590Srgrimes#define CPUSCALE 0.5 36787715Smarkm histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 3681590Srgrimes} 3691590Srgrimes 3701590Srgrimesstatic void 3711590Srgrimeshistogram(val, colwidth, scale) 37239230Sgibbs long double val; 3731590Srgrimes int colwidth; 3741590Srgrimes double scale; 3751590Srgrimes{ 3761590Srgrimes char buf[10]; 37787715Smarkm int k; 37887715Smarkm int v = (int)(val * scale) + 0.5; 3791590Srgrimes 3801590Srgrimes k = MIN(v, colwidth); 3811590Srgrimes if (v > colwidth) { 38239230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3831590Srgrimes k -= strlen(buf); 3841590Srgrimes while (k--) 3851590Srgrimes waddch(wnd, 'X'); 3861590Srgrimes waddstr(wnd, buf); 3871590Srgrimes return; 3881590Srgrimes } 3891590Srgrimes while (k--) 3901590Srgrimes waddch(wnd, 'X'); 3911590Srgrimes wclrtoeol(wnd); 3921590Srgrimes} 3931590Srgrimes 3941590Srgrimesint 3951590Srgrimescmdiostat(cmd, args) 39687715Smarkm const char *cmd, *args; 3971590Srgrimes{ 3981590Srgrimes 39939230Sgibbs if (prefix(cmd, "kbpt")) 40039230Sgibbs kbpt = !kbpt; 4011590Srgrimes else if (prefix(cmd, "numbers")) 4021590Srgrimes numbers = 1; 4031590Srgrimes else if (prefix(cmd, "bars")) 4041590Srgrimes numbers = 0; 40539230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 4061590Srgrimes return (0); 4071590Srgrimes wclear(wnd); 4081590Srgrimes labeliostat(); 4091590Srgrimes refresh(); 4101590Srgrimes return (1); 4111590Srgrimes} 412