iostat.c revision 83131
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 * 2850477Speter * $FreeBSD: head/usr.bin/systat/iostat.c 83131 2001-09-06 04:06:12Z ken $ 2939230Sgibbs */ 3039230Sgibbs/* 311590Srgrimes * Copyright (c) 1980, 1992, 1993 321590Srgrimes * The Regents of the University of California. All rights reserved. 331590Srgrimes * 341590Srgrimes * Redistribution and use in source and binary forms, with or without 351590Srgrimes * modification, are permitted provided that the following conditions 361590Srgrimes * are met: 371590Srgrimes * 1. Redistributions of source code must retain the above copyright 381590Srgrimes * notice, this list of conditions and the following disclaimer. 391590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 401590Srgrimes * notice, this list of conditions and the following disclaimer in the 411590Srgrimes * documentation and/or other materials provided with the distribution. 421590Srgrimes * 3. All advertising materials mentioning features or use of this software 431590Srgrimes * must display the following acknowledgement: 441590Srgrimes * This product includes software developed by the University of 451590Srgrimes * California, Berkeley and its contributors. 461590Srgrimes * 4. Neither the name of the University nor the names of its contributors 471590Srgrimes * may be used to endorse or promote products derived from this software 481590Srgrimes * without specific prior written permission. 491590Srgrimes * 501590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 511590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 521590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 531590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 541590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 551590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 561590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 571590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 581590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 591590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 601590Srgrimes * SUCH DAMAGE. 611590Srgrimes */ 621590Srgrimes 631590Srgrimes#ifndef lint 641590Srgrimesstatic char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 651590Srgrimes#endif not lint 661590Srgrimes 671590Srgrimes#include <sys/param.h> 681590Srgrimes#include <sys/dkstat.h> 6974671Stmm#include <sys/sysctl.h> 701590Srgrimes 711590Srgrimes#include <string.h> 721590Srgrimes#include <stdlib.h> 731590Srgrimes#include <nlist.h> 741590Srgrimes#include <paths.h> 7539230Sgibbs#include <devstat.h> 7640060Sobrien#include <err.h> 771590Srgrimes#include "systat.h" 781590Srgrimes#include "extern.h" 7940060Sobrien#include "devs.h" 801590Srgrimes 8139230Sgibbsstruct statinfo cur, last; 821590Srgrimes 831590Srgrimesstatic int linesperregion; 841590Srgrimesstatic double etime; 851590Srgrimesstatic int numbers = 0; /* default display bar graphs */ 8639230Sgibbsstatic int kbpt = 0; /* default ms/seek shown */ 871590Srgrimes 881590Srgrimesstatic int barlabels __P((int)); 8939230Sgibbsstatic void histogram __P((long double, int, double)); 901590Srgrimesstatic int numlabels __P((int)); 9139230Sgibbsstatic int devstats __P((int, int, int)); 921590Srgrimesstatic void stat1 __P((int, int)); 931590Srgrimes 941590SrgrimesWINDOW * 951590Srgrimesopeniostat() 961590Srgrimes{ 971590Srgrimes return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 981590Srgrimes} 991590Srgrimes 1001590Srgrimesvoid 1011590Srgrimescloseiostat(w) 1021590Srgrimes WINDOW *w; 1031590Srgrimes{ 1041590Srgrimes if (w == NULL) 1051590Srgrimes return; 1061590Srgrimes wclear(w); 1071590Srgrimes wrefresh(w); 1081590Srgrimes delwin(w); 1091590Srgrimes} 1101590Srgrimes 1111590Srgrimesint 1121590Srgrimesinitiostat() 1131590Srgrimes{ 11483131Sken if ((num_devices = devstat_getnumdevs(NULL)) < 0) 1151590Srgrimes return(0); 11639230Sgibbs 11739230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 11839230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 11939230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 12039230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 12139230Sgibbs 12239230Sgibbs /* 12339230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 12439230Sgibbs * how to calculate it, though. 12539230Sgibbs */ 12639230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 12739230Sgibbs return(0); 12839230Sgibbs 1291590Srgrimes return(1); 1301590Srgrimes} 1311590Srgrimes 1321590Srgrimesvoid 1331590Srgrimesfetchiostat() 1341590Srgrimes{ 13539230Sgibbs struct devinfo *tmp_dinfo; 13669141Srwatson size_t len; 13769141Srwatson int err; 13839230Sgibbs 13969141Srwatson len = sizeof(cur.cp_time); 14069141Srwatson err = sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0); 14169141Srwatson if (err || len != sizeof(cur.cp_time)) { 14269141Srwatson perror("kern.cp_time"); 14369141Srwatson exit (1); 14469141Srwatson } 14539230Sgibbs tmp_dinfo = last.dinfo; 14639230Sgibbs last.dinfo = cur.dinfo; 14739230Sgibbs cur.dinfo = tmp_dinfo; 14839230Sgibbs 14939230Sgibbs last.busy_time = cur.busy_time; 15039230Sgibbs 15139230Sgibbs /* 15239230Sgibbs * Here what we want to do is refresh our device stats. 15339230Sgibbs * getdevs() returns 1 when the device list has changed. 15439230Sgibbs * If the device list has changed, we want to go through 15539230Sgibbs * the selection process again, in case a device that we 15639230Sgibbs * were previously displaying has gone away. 15739230Sgibbs */ 15883131Sken switch (devstat_getdevs(NULL, &cur)) { 15939230Sgibbs case -1: 16039230Sgibbs errx(1, "%s", devstat_errbuf); 16139230Sgibbs break; 16239230Sgibbs case 1: 16339230Sgibbs cmdiostat("refresh", NULL); 16439230Sgibbs break; 16539230Sgibbs default: 16639230Sgibbs break; 16739230Sgibbs } 16839230Sgibbs num_devices = cur.dinfo->numdevs; 16939230Sgibbs generation = cur.dinfo->generation; 17039230Sgibbs 1711590Srgrimes} 1721590Srgrimes 1731590Srgrimes#define INSET 10 1741590Srgrimes 1751590Srgrimesvoid 1761590Srgrimeslabeliostat() 1771590Srgrimes{ 1781590Srgrimes int row; 1791590Srgrimes 1801590Srgrimes row = 0; 1811590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1821590Srgrimes mvwaddstr(wnd, row++, INSET, 1831590Srgrimes "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1841590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1851590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 1861590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 1874930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 1881590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 1891590Srgrimes if (numbers) 1901590Srgrimes row = numlabels(row + 1); 1911590Srgrimes else 1921590Srgrimes row = barlabels(row + 1); 1931590Srgrimes} 1941590Srgrimes 1951590Srgrimesstatic int 1961590Srgrimesnumlabels(row) 1971590Srgrimes int row; 1981590Srgrimes{ 1991590Srgrimes 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; 21816301Sjkh col = INSET; 21939230Sgibbs for (i = 0; i < num_devices; i++) 22039230Sgibbs if (dev_select[i].selected) { 22150635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 22216301Sjkh 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); 22839230Sgibbs mvwaddstr(wnd, row, col + 4, tmpstr); 22939230Sgibbs mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s "); 2301590Srgrimes col += COLWIDTH; 2311590Srgrimes } 2321590Srgrimes if (col) 2331590Srgrimes row += linesperregion + 1; 2341590Srgrimes return (row); 2351590Srgrimes} 2361590Srgrimes 2371590Srgrimesstatic int 2381590Srgrimesbarlabels(row) 2391590Srgrimes int row; 2401590Srgrimes{ 2411590Srgrimes int i; 24239230Sgibbs char tmpstr[10]; 2431590Srgrimes 2441590Srgrimes mvwaddstr(wnd, row++, INSET, 24561147Sphk "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 24639230Sgibbs linesperregion = 2 + kbpt; 24739230Sgibbs for (i = 0; i < num_devices; i++) 24839230Sgibbs if (dev_select[i].selected) { 24950635Speter if (row > wnd->_maxy - linesperregion) 2501590Srgrimes break; 25139230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 25239230Sgibbs dev_select[i].unit_number); 25339230Sgibbs mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 25439230Sgibbs tmpstr); 2551590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 25639230Sgibbs if (kbpt) 25739230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2581590Srgrimes } 2591590Srgrimes return (row); 2601590Srgrimes} 2611590Srgrimes 2621590Srgrimes 2631590Srgrimesvoid 2641590Srgrimesshowiostat() 2651590Srgrimes{ 2661590Srgrimes register long t; 2671590Srgrimes register int i, row, col; 2681590Srgrimes 26939230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2701590Srgrimes etime = 0; 2711590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2721590Srgrimes X(cp_time); 27339230Sgibbs etime += cur.cp_time[i]; 2741590Srgrimes } 2751590Srgrimes if (etime == 0.0) 2761590Srgrimes etime = 1.0; 2774930Sbde etime /= hertz; 2781590Srgrimes row = 1; 2794930Sbde for (i = 0; i < CPUSTATES; i++) 2801590Srgrimes stat1(row++, i); 2811590Srgrimes if (!numbers) { 2821590Srgrimes row += 2; 28339230Sgibbs for (i = 0; i < num_devices; i++) 28439230Sgibbs if (dev_select[i].selected) { 28550635Speter if (row > wnd->_maxy - linesperregion) 2861590Srgrimes break; 28739230Sgibbs row = devstats(row, INSET, i); 2881590Srgrimes } 2891590Srgrimes return; 2901590Srgrimes } 29116301Sjkh col = INSET; 2921590Srgrimes wmove(wnd, row + linesperregion, 0); 2931590Srgrimes wdeleteln(wnd); 2941590Srgrimes wmove(wnd, row + 3, 0); 2951590Srgrimes winsertln(wnd); 29639230Sgibbs for (i = 0; i < num_devices; i++) 29739230Sgibbs if (dev_select[i].selected) { 29850635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 29916301Sjkh col = INSET, row += linesperregion + 1; 30050635Speter if (row > wnd->_maxy - (linesperregion + 1)) 3011590Srgrimes break; 3021590Srgrimes wmove(wnd, row + linesperregion, 0); 3031590Srgrimes wdeleteln(wnd); 3041590Srgrimes wmove(wnd, row + 3, 0); 3051590Srgrimes winsertln(wnd); 3061590Srgrimes } 30739230Sgibbs (void) devstats(row + 3, col, i); 3081590Srgrimes col += COLWIDTH; 3091590Srgrimes } 3101590Srgrimes} 3111590Srgrimes 3121590Srgrimesstatic int 31339230Sgibbsdevstats(row, col, dn) 3141590Srgrimes int row, col, dn; 3151590Srgrimes{ 31639230Sgibbs long double transfers_per_second; 31739230Sgibbs long double kb_per_transfer, mb_per_second; 31839230Sgibbs long double busy_seconds; 31939230Sgibbs int di; 32039230Sgibbs 32139230Sgibbs di = dev_select[dn].position; 3221590Srgrimes 32383131Sken busy_seconds = devstat_compute_etime(cur.busy_time, last.busy_time); 32439230Sgibbs 32583131Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 32683131Sken &last.dinfo->devices[di], busy_seconds, 32783131Sken DSM_KB_PER_TRANSFER, &kb_per_transfer, 32883131Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 32983131Sken DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 33039230Sgibbs errx(1, "%s", devstat_errbuf); 33139230Sgibbs 3321590Srgrimes if (numbers) { 33339230Sgibbs mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ", 33439230Sgibbs kb_per_transfer, transfers_per_second, 33539230Sgibbs mb_per_second); 33639230Sgibbs return(row); 3371590Srgrimes } 3381590Srgrimes wmove(wnd, row++, col); 33961148Sphk histogram(mb_per_second, 50, .5); 3401590Srgrimes wmove(wnd, row++, col); 34161148Sphk histogram(transfers_per_second, 50, .5); 34239230Sgibbs if (kbpt) { 3431590Srgrimes wmove(wnd, row++, col); 34461148Sphk histogram(kb_per_transfer, 50, .5); 3451590Srgrimes } 34639230Sgibbs 34739230Sgibbs return(row); 34839230Sgibbs 3491590Srgrimes} 3501590Srgrimes 3511590Srgrimesstatic void 3521590Srgrimesstat1(row, o) 3531590Srgrimes int row, o; 3541590Srgrimes{ 3551590Srgrimes register int i; 3561590Srgrimes double time; 3571590Srgrimes 3581590Srgrimes time = 0; 3591590Srgrimes for (i = 0; i < CPUSTATES; i++) 36039230Sgibbs time += cur.cp_time[i]; 3611590Srgrimes if (time == 0.0) 3621590Srgrimes time = 1.0; 3631590Srgrimes wmove(wnd, row, INSET); 3641590Srgrimes#define CPUSCALE 0.5 36539230Sgibbs histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 3661590Srgrimes} 3671590Srgrimes 3681590Srgrimesstatic void 3691590Srgrimeshistogram(val, colwidth, scale) 37039230Sgibbs long double val; 3711590Srgrimes int colwidth; 3721590Srgrimes double scale; 3731590Srgrimes{ 3741590Srgrimes char buf[10]; 3751590Srgrimes register int k; 3761590Srgrimes register int v = (int)(val * scale) + 0.5; 3771590Srgrimes 3781590Srgrimes k = MIN(v, colwidth); 3791590Srgrimes if (v > colwidth) { 38039230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3811590Srgrimes k -= strlen(buf); 3821590Srgrimes while (k--) 3831590Srgrimes waddch(wnd, 'X'); 3841590Srgrimes waddstr(wnd, buf); 3851590Srgrimes return; 3861590Srgrimes } 3871590Srgrimes while (k--) 3881590Srgrimes waddch(wnd, 'X'); 3891590Srgrimes wclrtoeol(wnd); 3901590Srgrimes} 3911590Srgrimes 3921590Srgrimesint 3931590Srgrimescmdiostat(cmd, args) 3941590Srgrimes char *cmd, *args; 3951590Srgrimes{ 3961590Srgrimes 39739230Sgibbs if (prefix(cmd, "kbpt")) 39839230Sgibbs kbpt = !kbpt; 3991590Srgrimes else if (prefix(cmd, "numbers")) 4001590Srgrimes numbers = 1; 4011590Srgrimes else if (prefix(cmd, "bars")) 4021590Srgrimes numbers = 0; 40339230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 4041590Srgrimes return (0); 4051590Srgrimes wclear(wnd); 4061590Srgrimes labeliostat(); 4071590Srgrimes refresh(); 4081590Srgrimes return (1); 4091590Srgrimes} 410