iostat.c revision 61148
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 61148 2000-06-01 08:49:46Z phk $ 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> 691590Srgrimes 701590Srgrimes#include <string.h> 711590Srgrimes#include <stdlib.h> 721590Srgrimes#include <nlist.h> 731590Srgrimes#include <paths.h> 7439230Sgibbs#include <devstat.h> 7540060Sobrien#include <err.h> 761590Srgrimes#include "systat.h" 771590Srgrimes#include "extern.h" 7840060Sobrien#include "devs.h" 791590Srgrimes 801590Srgrimesstatic struct nlist namelist[] = { 8139230Sgibbs#define X_CP_TIME 0 821590Srgrimes { "_cp_time" }, 831590Srgrimes#ifdef vax 841590Srgrimes#define X_MBDINIT (X_CP_TIME+1) 851590Srgrimes { "_mbdinit" }, 861590Srgrimes#define X_UBDINIT (X_CP_TIME+2) 871590Srgrimes { "_ubdinit" }, 881590Srgrimes#endif 891590Srgrimes#ifdef tahoe 901590Srgrimes#define X_VBDINIT (X_CP_TIME+1) 911590Srgrimes { "_vbdinit" }, 921590Srgrimes#endif 931590Srgrimes { "" }, 941590Srgrimes}; 951590Srgrimes 9639230Sgibbsstruct statinfo cur, last; 971590Srgrimes 981590Srgrimesstatic int linesperregion; 991590Srgrimesstatic double etime; 1001590Srgrimesstatic int numbers = 0; /* default display bar graphs */ 10139230Sgibbsstatic int kbpt = 0; /* default ms/seek shown */ 1021590Srgrimes 1031590Srgrimesstatic int barlabels __P((int)); 10439230Sgibbsstatic void histogram __P((long double, int, double)); 1051590Srgrimesstatic int numlabels __P((int)); 10639230Sgibbsstatic int devstats __P((int, int, int)); 1071590Srgrimesstatic void stat1 __P((int, int)); 1081590Srgrimes 1091590SrgrimesWINDOW * 1101590Srgrimesopeniostat() 1111590Srgrimes{ 1121590Srgrimes return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 1131590Srgrimes} 1141590Srgrimes 1151590Srgrimesvoid 1161590Srgrimescloseiostat(w) 1171590Srgrimes WINDOW *w; 1181590Srgrimes{ 1191590Srgrimes if (w == NULL) 1201590Srgrimes return; 1211590Srgrimes wclear(w); 1221590Srgrimes wrefresh(w); 1231590Srgrimes delwin(w); 1241590Srgrimes} 1251590Srgrimes 1261590Srgrimesint 1271590Srgrimesinitiostat() 1281590Srgrimes{ 12939230Sgibbs if (num_devices = getnumdevs() < 0) 1301590Srgrimes return(0); 13139230Sgibbs 13239230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 13339230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 13439230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 13539230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 13639230Sgibbs 13739230Sgibbs /* 13839230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 13939230Sgibbs * how to calculate it, though. 14039230Sgibbs */ 14139230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 14239230Sgibbs return(0); 14339230Sgibbs 14439230Sgibbs if (kvm_nlist(kd, namelist)) { 14539230Sgibbs nlisterr(namelist); 14639230Sgibbs return(0); 1471590Srgrimes } 14839230Sgibbs 1491590Srgrimes return(1); 1501590Srgrimes} 1511590Srgrimes 1521590Srgrimesvoid 1531590Srgrimesfetchiostat() 1541590Srgrimes{ 15539230Sgibbs struct devinfo *tmp_dinfo; 15639230Sgibbs 15739230Sgibbs NREAD(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); 15839230Sgibbs tmp_dinfo = last.dinfo; 15939230Sgibbs last.dinfo = cur.dinfo; 16039230Sgibbs cur.dinfo = tmp_dinfo; 16139230Sgibbs 16239230Sgibbs last.busy_time = cur.busy_time; 16339230Sgibbs 16439230Sgibbs /* 16539230Sgibbs * Here what we want to do is refresh our device stats. 16639230Sgibbs * getdevs() returns 1 when the device list has changed. 16739230Sgibbs * If the device list has changed, we want to go through 16839230Sgibbs * the selection process again, in case a device that we 16939230Sgibbs * were previously displaying has gone away. 17039230Sgibbs */ 17139230Sgibbs switch (getdevs(&cur)) { 17239230Sgibbs case -1: 17339230Sgibbs errx(1, "%s", devstat_errbuf); 17439230Sgibbs break; 17539230Sgibbs case 1: 17639230Sgibbs cmdiostat("refresh", NULL); 17739230Sgibbs break; 17839230Sgibbs default: 17939230Sgibbs break; 18039230Sgibbs } 18139230Sgibbs num_devices = cur.dinfo->numdevs; 18239230Sgibbs generation = cur.dinfo->generation; 18339230Sgibbs 1841590Srgrimes} 1851590Srgrimes 1861590Srgrimes#define INSET 10 1871590Srgrimes 1881590Srgrimesvoid 1891590Srgrimeslabeliostat() 1901590Srgrimes{ 1911590Srgrimes int row; 1921590Srgrimes 1931590Srgrimes row = 0; 1941590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1951590Srgrimes mvwaddstr(wnd, row++, INSET, 1961590Srgrimes "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1971590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1981590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 1991590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 2004930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 2011590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 2021590Srgrimes if (numbers) 2031590Srgrimes row = numlabels(row + 1); 2041590Srgrimes else 2051590Srgrimes row = barlabels(row + 1); 2061590Srgrimes} 2071590Srgrimes 2081590Srgrimesstatic int 2091590Srgrimesnumlabels(row) 2101590Srgrimes int row; 2111590Srgrimes{ 2121590Srgrimes int i, col, regions, ndrives; 21339230Sgibbs char tmpstr[10]; 2141590Srgrimes 21539230Sgibbs#define COLWIDTH 17 21650635Speter#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 21739230Sgibbs for (ndrives = 0, i = 0; i < num_devices; i++) 21839230Sgibbs if (dev_select[i].selected) 2191590Srgrimes ndrives++; 2201590Srgrimes regions = howmany(ndrives, DRIVESPERLINE); 2211590Srgrimes /* 2221590Srgrimes * Deduct -regions for blank line after each scrolling region. 2231590Srgrimes */ 22450635Speter linesperregion = (wnd->_maxy - row - regions) / regions; 2251590Srgrimes /* 2261590Srgrimes * Minimum region contains space for two 2271590Srgrimes * label lines and one line of statistics. 2281590Srgrimes */ 2291590Srgrimes if (linesperregion < 3) 2301590Srgrimes linesperregion = 3; 23116301Sjkh col = INSET; 23239230Sgibbs for (i = 0; i < num_devices; i++) 23339230Sgibbs if (dev_select[i].selected) { 23450635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 23516301Sjkh col = INSET, row += linesperregion + 1; 23650635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2371590Srgrimes break; 2381590Srgrimes } 23939230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 24039230Sgibbs dev_select[i].unit_number); 24139230Sgibbs mvwaddstr(wnd, row, col + 4, tmpstr); 24239230Sgibbs mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s "); 2431590Srgrimes col += COLWIDTH; 2441590Srgrimes } 2451590Srgrimes if (col) 2461590Srgrimes row += linesperregion + 1; 2471590Srgrimes return (row); 2481590Srgrimes} 2491590Srgrimes 2501590Srgrimesstatic int 2511590Srgrimesbarlabels(row) 2521590Srgrimes int row; 2531590Srgrimes{ 2541590Srgrimes int i; 25539230Sgibbs char tmpstr[10]; 2561590Srgrimes 2571590Srgrimes mvwaddstr(wnd, row++, INSET, 25861147Sphk "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 25939230Sgibbs linesperregion = 2 + kbpt; 26039230Sgibbs for (i = 0; i < num_devices; i++) 26139230Sgibbs if (dev_select[i].selected) { 26250635Speter if (row > wnd->_maxy - linesperregion) 2631590Srgrimes break; 26439230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 26539230Sgibbs dev_select[i].unit_number); 26639230Sgibbs mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 26739230Sgibbs tmpstr); 2681590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 26939230Sgibbs if (kbpt) 27039230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2711590Srgrimes } 2721590Srgrimes return (row); 2731590Srgrimes} 2741590Srgrimes 2751590Srgrimes 2761590Srgrimesvoid 2771590Srgrimesshowiostat() 2781590Srgrimes{ 2791590Srgrimes register long t; 2801590Srgrimes register int i, row, col; 2811590Srgrimes 28239230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2831590Srgrimes etime = 0; 2841590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2851590Srgrimes X(cp_time); 28639230Sgibbs etime += cur.cp_time[i]; 2871590Srgrimes } 2881590Srgrimes if (etime == 0.0) 2891590Srgrimes etime = 1.0; 2904930Sbde etime /= hertz; 2911590Srgrimes row = 1; 2924930Sbde for (i = 0; i < CPUSTATES; i++) 2931590Srgrimes stat1(row++, i); 2941590Srgrimes if (!numbers) { 2951590Srgrimes row += 2; 29639230Sgibbs for (i = 0; i < num_devices; i++) 29739230Sgibbs if (dev_select[i].selected) { 29850635Speter if (row > wnd->_maxy - linesperregion) 2991590Srgrimes break; 30039230Sgibbs row = devstats(row, INSET, i); 3011590Srgrimes } 3021590Srgrimes return; 3031590Srgrimes } 30416301Sjkh col = INSET; 3051590Srgrimes wmove(wnd, row + linesperregion, 0); 3061590Srgrimes wdeleteln(wnd); 3071590Srgrimes wmove(wnd, row + 3, 0); 3081590Srgrimes winsertln(wnd); 30939230Sgibbs for (i = 0; i < num_devices; i++) 31039230Sgibbs if (dev_select[i].selected) { 31150635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 31216301Sjkh col = INSET, row += linesperregion + 1; 31350635Speter if (row > wnd->_maxy - (linesperregion + 1)) 3141590Srgrimes break; 3151590Srgrimes wmove(wnd, row + linesperregion, 0); 3161590Srgrimes wdeleteln(wnd); 3171590Srgrimes wmove(wnd, row + 3, 0); 3181590Srgrimes winsertln(wnd); 3191590Srgrimes } 32039230Sgibbs (void) devstats(row + 3, col, i); 3211590Srgrimes col += COLWIDTH; 3221590Srgrimes } 3231590Srgrimes} 3241590Srgrimes 3251590Srgrimesstatic int 32639230Sgibbsdevstats(row, col, dn) 3271590Srgrimes int row, col, dn; 3281590Srgrimes{ 32939230Sgibbs long double transfers_per_second; 33039230Sgibbs long double kb_per_transfer, mb_per_second; 33139230Sgibbs long double busy_seconds; 33239230Sgibbs int di; 33339230Sgibbs 33439230Sgibbs di = dev_select[dn].position; 3351590Srgrimes 33639230Sgibbs busy_seconds = compute_etime(cur.busy_time, last.busy_time); 33739230Sgibbs 33839230Sgibbs if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di], 33939230Sgibbs busy_seconds, NULL, NULL, NULL, 34039230Sgibbs &kb_per_transfer, &transfers_per_second, 34139230Sgibbs &mb_per_second, NULL, NULL) != 0) 34239230Sgibbs errx(1, "%s", devstat_errbuf); 34339230Sgibbs 3441590Srgrimes if (numbers) { 34539230Sgibbs mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ", 34639230Sgibbs kb_per_transfer, transfers_per_second, 34739230Sgibbs mb_per_second); 34839230Sgibbs return(row); 3491590Srgrimes } 3501590Srgrimes wmove(wnd, row++, col); 35161148Sphk histogram(mb_per_second, 50, .5); 3521590Srgrimes wmove(wnd, row++, col); 35361148Sphk histogram(transfers_per_second, 50, .5); 35439230Sgibbs if (kbpt) { 3551590Srgrimes wmove(wnd, row++, col); 35661148Sphk histogram(kb_per_transfer, 50, .5); 3571590Srgrimes } 35839230Sgibbs 35939230Sgibbs return(row); 36039230Sgibbs 3611590Srgrimes} 3621590Srgrimes 3631590Srgrimesstatic void 3641590Srgrimesstat1(row, o) 3651590Srgrimes int row, o; 3661590Srgrimes{ 3671590Srgrimes register int i; 3681590Srgrimes double time; 3691590Srgrimes 3701590Srgrimes time = 0; 3711590Srgrimes for (i = 0; i < CPUSTATES; i++) 37239230Sgibbs time += cur.cp_time[i]; 3731590Srgrimes if (time == 0.0) 3741590Srgrimes time = 1.0; 3751590Srgrimes wmove(wnd, row, INSET); 3761590Srgrimes#define CPUSCALE 0.5 37739230Sgibbs histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 3781590Srgrimes} 3791590Srgrimes 3801590Srgrimesstatic void 3811590Srgrimeshistogram(val, colwidth, scale) 38239230Sgibbs long double val; 3831590Srgrimes int colwidth; 3841590Srgrimes double scale; 3851590Srgrimes{ 3861590Srgrimes char buf[10]; 3871590Srgrimes register int k; 3881590Srgrimes register int v = (int)(val * scale) + 0.5; 3891590Srgrimes 3901590Srgrimes k = MIN(v, colwidth); 3911590Srgrimes if (v > colwidth) { 39239230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3931590Srgrimes k -= strlen(buf); 3941590Srgrimes while (k--) 3951590Srgrimes waddch(wnd, 'X'); 3961590Srgrimes waddstr(wnd, buf); 3971590Srgrimes return; 3981590Srgrimes } 3991590Srgrimes while (k--) 4001590Srgrimes waddch(wnd, 'X'); 4011590Srgrimes wclrtoeol(wnd); 4021590Srgrimes} 4031590Srgrimes 4041590Srgrimesint 4051590Srgrimescmdiostat(cmd, args) 4061590Srgrimes char *cmd, *args; 4071590Srgrimes{ 4081590Srgrimes 40939230Sgibbs if (prefix(cmd, "kbpt")) 41039230Sgibbs kbpt = !kbpt; 4111590Srgrimes else if (prefix(cmd, "numbers")) 4121590Srgrimes numbers = 1; 4131590Srgrimes else if (prefix(cmd, "bars")) 4141590Srgrimes numbers = 0; 41539230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 4161590Srgrimes return (0); 4171590Srgrimes wclear(wnd); 4181590Srgrimes labeliostat(); 4191590Srgrimes refresh(); 4201590Srgrimes return (1); 4211590Srgrimes} 422