iostat.c revision 50635
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 50635 1999-08-30 08:18:09Z peter $ 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> 6839230Sgibbs#include <sys/buf.h> 691590Srgrimes#include <sys/dkstat.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 811590Srgrimesstatic struct nlist namelist[] = { 8239230Sgibbs#define X_CP_TIME 0 831590Srgrimes { "_cp_time" }, 841590Srgrimes#ifdef vax 851590Srgrimes#define X_MBDINIT (X_CP_TIME+1) 861590Srgrimes { "_mbdinit" }, 871590Srgrimes#define X_UBDINIT (X_CP_TIME+2) 881590Srgrimes { "_ubdinit" }, 891590Srgrimes#endif 901590Srgrimes#ifdef tahoe 911590Srgrimes#define X_VBDINIT (X_CP_TIME+1) 921590Srgrimes { "_vbdinit" }, 931590Srgrimes#endif 941590Srgrimes { "" }, 951590Srgrimes}; 961590Srgrimes 9739230Sgibbsstruct statinfo cur, last; 981590Srgrimes 991590Srgrimesstatic int linesperregion; 1001590Srgrimesstatic double etime; 1011590Srgrimesstatic int numbers = 0; /* default display bar graphs */ 10239230Sgibbsstatic int kbpt = 0; /* default ms/seek shown */ 1031590Srgrimes 1041590Srgrimesstatic int barlabels __P((int)); 10539230Sgibbsstatic void histogram __P((long double, int, double)); 1061590Srgrimesstatic int numlabels __P((int)); 10739230Sgibbsstatic int devstats __P((int, int, int)); 1081590Srgrimesstatic void stat1 __P((int, int)); 1091590Srgrimes 1101590SrgrimesWINDOW * 1111590Srgrimesopeniostat() 1121590Srgrimes{ 1131590Srgrimes return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 1141590Srgrimes} 1151590Srgrimes 1161590Srgrimesvoid 1171590Srgrimescloseiostat(w) 1181590Srgrimes WINDOW *w; 1191590Srgrimes{ 1201590Srgrimes if (w == NULL) 1211590Srgrimes return; 1221590Srgrimes wclear(w); 1231590Srgrimes wrefresh(w); 1241590Srgrimes delwin(w); 1251590Srgrimes} 1261590Srgrimes 1271590Srgrimesint 1281590Srgrimesinitiostat() 1291590Srgrimes{ 13039230Sgibbs if (num_devices = getnumdevs() < 0) 1311590Srgrimes return(0); 13239230Sgibbs 13339230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 13439230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 13539230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 13639230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 13739230Sgibbs 13839230Sgibbs /* 13939230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 14039230Sgibbs * how to calculate it, though. 14139230Sgibbs */ 14239230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 14339230Sgibbs return(0); 14439230Sgibbs 14539230Sgibbs if (kvm_nlist(kd, namelist)) { 14639230Sgibbs nlisterr(namelist); 14739230Sgibbs return(0); 1481590Srgrimes } 14939230Sgibbs 1501590Srgrimes return(1); 1511590Srgrimes} 1521590Srgrimes 1531590Srgrimesvoid 1541590Srgrimesfetchiostat() 1551590Srgrimes{ 15639230Sgibbs struct devinfo *tmp_dinfo; 15739230Sgibbs 15839230Sgibbs NREAD(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); 15939230Sgibbs tmp_dinfo = last.dinfo; 16039230Sgibbs last.dinfo = cur.dinfo; 16139230Sgibbs cur.dinfo = tmp_dinfo; 16239230Sgibbs 16339230Sgibbs last.busy_time = cur.busy_time; 16439230Sgibbs 16539230Sgibbs /* 16639230Sgibbs * Here what we want to do is refresh our device stats. 16739230Sgibbs * getdevs() returns 1 when the device list has changed. 16839230Sgibbs * If the device list has changed, we want to go through 16939230Sgibbs * the selection process again, in case a device that we 17039230Sgibbs * were previously displaying has gone away. 17139230Sgibbs */ 17239230Sgibbs switch (getdevs(&cur)) { 17339230Sgibbs case -1: 17439230Sgibbs errx(1, "%s", devstat_errbuf); 17539230Sgibbs break; 17639230Sgibbs case 1: 17739230Sgibbs cmdiostat("refresh", NULL); 17839230Sgibbs break; 17939230Sgibbs default: 18039230Sgibbs break; 18139230Sgibbs } 18239230Sgibbs num_devices = cur.dinfo->numdevs; 18339230Sgibbs generation = cur.dinfo->generation; 18439230Sgibbs 1851590Srgrimes} 1861590Srgrimes 1871590Srgrimes#define INSET 10 1881590Srgrimes 1891590Srgrimesvoid 1901590Srgrimeslabeliostat() 1911590Srgrimes{ 1921590Srgrimes int row; 1931590Srgrimes 1941590Srgrimes row = 0; 1951590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1961590Srgrimes mvwaddstr(wnd, row++, INSET, 1971590Srgrimes "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1981590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1991590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 2001590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 2014930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 2021590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 2031590Srgrimes if (numbers) 2041590Srgrimes row = numlabels(row + 1); 2051590Srgrimes else 2061590Srgrimes row = barlabels(row + 1); 2071590Srgrimes} 2081590Srgrimes 2091590Srgrimesstatic int 2101590Srgrimesnumlabels(row) 2111590Srgrimes int row; 2121590Srgrimes{ 2131590Srgrimes int i, col, regions, ndrives; 21439230Sgibbs char tmpstr[10]; 2151590Srgrimes 21639230Sgibbs#define COLWIDTH 17 21750635Speter#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 21839230Sgibbs for (ndrives = 0, i = 0; i < num_devices; i++) 21939230Sgibbs if (dev_select[i].selected) 2201590Srgrimes ndrives++; 2211590Srgrimes regions = howmany(ndrives, DRIVESPERLINE); 2221590Srgrimes /* 2231590Srgrimes * Deduct -regions for blank line after each scrolling region. 2241590Srgrimes */ 22550635Speter linesperregion = (wnd->_maxy - row - regions) / regions; 2261590Srgrimes /* 2271590Srgrimes * Minimum region contains space for two 2281590Srgrimes * label lines and one line of statistics. 2291590Srgrimes */ 2301590Srgrimes if (linesperregion < 3) 2311590Srgrimes linesperregion = 3; 23216301Sjkh col = INSET; 23339230Sgibbs for (i = 0; i < num_devices; i++) 23439230Sgibbs if (dev_select[i].selected) { 23550635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 23616301Sjkh col = INSET, row += linesperregion + 1; 23750635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2381590Srgrimes break; 2391590Srgrimes } 24039230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 24139230Sgibbs dev_select[i].unit_number); 24239230Sgibbs mvwaddstr(wnd, row, col + 4, tmpstr); 24339230Sgibbs mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s "); 2441590Srgrimes col += COLWIDTH; 2451590Srgrimes } 2461590Srgrimes if (col) 2471590Srgrimes row += linesperregion + 1; 2481590Srgrimes return (row); 2491590Srgrimes} 2501590Srgrimes 2511590Srgrimesstatic int 2521590Srgrimesbarlabels(row) 2531590Srgrimes int row; 2541590Srgrimes{ 2551590Srgrimes int i; 25639230Sgibbs char tmpstr[10]; 2571590Srgrimes 2581590Srgrimes mvwaddstr(wnd, row++, INSET, 2591590Srgrimes "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50"); 26039230Sgibbs linesperregion = 2 + kbpt; 26139230Sgibbs for (i = 0; i < num_devices; i++) 26239230Sgibbs if (dev_select[i].selected) { 26350635Speter if (row > wnd->_maxy - linesperregion) 2641590Srgrimes break; 26539230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 26639230Sgibbs dev_select[i].unit_number); 26739230Sgibbs mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 26839230Sgibbs tmpstr); 2691590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 27039230Sgibbs if (kbpt) 27139230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2721590Srgrimes } 2731590Srgrimes return (row); 2741590Srgrimes} 2751590Srgrimes 2761590Srgrimes 2771590Srgrimesvoid 2781590Srgrimesshowiostat() 2791590Srgrimes{ 2801590Srgrimes register long t; 2811590Srgrimes register int i, row, col; 2821590Srgrimes 28339230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2841590Srgrimes etime = 0; 2851590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2861590Srgrimes X(cp_time); 28739230Sgibbs etime += cur.cp_time[i]; 2881590Srgrimes } 2891590Srgrimes if (etime == 0.0) 2901590Srgrimes etime = 1.0; 2914930Sbde etime /= hertz; 2921590Srgrimes row = 1; 2934930Sbde for (i = 0; i < CPUSTATES; i++) 2941590Srgrimes stat1(row++, i); 2951590Srgrimes if (!numbers) { 2961590Srgrimes row += 2; 29739230Sgibbs for (i = 0; i < num_devices; i++) 29839230Sgibbs if (dev_select[i].selected) { 29950635Speter if (row > wnd->_maxy - linesperregion) 3001590Srgrimes break; 30139230Sgibbs row = devstats(row, INSET, i); 3021590Srgrimes } 3031590Srgrimes return; 3041590Srgrimes } 30516301Sjkh col = INSET; 3061590Srgrimes wmove(wnd, row + linesperregion, 0); 3071590Srgrimes wdeleteln(wnd); 3081590Srgrimes wmove(wnd, row + 3, 0); 3091590Srgrimes winsertln(wnd); 31039230Sgibbs for (i = 0; i < num_devices; i++) 31139230Sgibbs if (dev_select[i].selected) { 31250635Speter if (col + COLWIDTH >= wnd->_maxx - INSET) { 31316301Sjkh col = INSET, row += linesperregion + 1; 31450635Speter if (row > wnd->_maxy - (linesperregion + 1)) 3151590Srgrimes break; 3161590Srgrimes wmove(wnd, row + linesperregion, 0); 3171590Srgrimes wdeleteln(wnd); 3181590Srgrimes wmove(wnd, row + 3, 0); 3191590Srgrimes winsertln(wnd); 3201590Srgrimes } 32139230Sgibbs (void) devstats(row + 3, col, i); 3221590Srgrimes col += COLWIDTH; 3231590Srgrimes } 3241590Srgrimes} 3251590Srgrimes 3261590Srgrimesstatic int 32739230Sgibbsdevstats(row, col, dn) 3281590Srgrimes int row, col, dn; 3291590Srgrimes{ 33039230Sgibbs long double transfers_per_second; 33139230Sgibbs long double kb_per_transfer, mb_per_second; 33239230Sgibbs long double busy_seconds; 33339230Sgibbs int di; 33439230Sgibbs 33539230Sgibbs di = dev_select[dn].position; 3361590Srgrimes 33739230Sgibbs busy_seconds = compute_etime(cur.busy_time, last.busy_time); 33839230Sgibbs 33939230Sgibbs if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di], 34039230Sgibbs busy_seconds, NULL, NULL, NULL, 34139230Sgibbs &kb_per_transfer, &transfers_per_second, 34239230Sgibbs &mb_per_second, NULL, NULL) != 0) 34339230Sgibbs errx(1, "%s", devstat_errbuf); 34439230Sgibbs 3451590Srgrimes if (numbers) { 34639230Sgibbs mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ", 34739230Sgibbs kb_per_transfer, transfers_per_second, 34839230Sgibbs mb_per_second); 34939230Sgibbs return(row); 3501590Srgrimes } 3511590Srgrimes wmove(wnd, row++, col); 35239230Sgibbs histogram(mb_per_second, 50, 1.0); 3531590Srgrimes wmove(wnd, row++, col); 35439230Sgibbs histogram(transfers_per_second, 50, 1.0); 35539230Sgibbs if (kbpt) { 3561590Srgrimes wmove(wnd, row++, col); 35739230Sgibbs histogram(kb_per_transfer, 50, 1.0); 3581590Srgrimes } 35939230Sgibbs 36039230Sgibbs return(row); 36139230Sgibbs 3621590Srgrimes} 3631590Srgrimes 3641590Srgrimesstatic void 3651590Srgrimesstat1(row, o) 3661590Srgrimes int row, o; 3671590Srgrimes{ 3681590Srgrimes register int i; 3691590Srgrimes double time; 3701590Srgrimes 3711590Srgrimes time = 0; 3721590Srgrimes for (i = 0; i < CPUSTATES; i++) 37339230Sgibbs time += cur.cp_time[i]; 3741590Srgrimes if (time == 0.0) 3751590Srgrimes time = 1.0; 3761590Srgrimes wmove(wnd, row, INSET); 3771590Srgrimes#define CPUSCALE 0.5 37839230Sgibbs histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 3791590Srgrimes} 3801590Srgrimes 3811590Srgrimesstatic void 3821590Srgrimeshistogram(val, colwidth, scale) 38339230Sgibbs long double val; 3841590Srgrimes int colwidth; 3851590Srgrimes double scale; 3861590Srgrimes{ 3871590Srgrimes char buf[10]; 3881590Srgrimes register int k; 3891590Srgrimes register int v = (int)(val * scale) + 0.5; 3901590Srgrimes 3911590Srgrimes k = MIN(v, colwidth); 3921590Srgrimes if (v > colwidth) { 39339230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3941590Srgrimes k -= strlen(buf); 3951590Srgrimes while (k--) 3961590Srgrimes waddch(wnd, 'X'); 3971590Srgrimes waddstr(wnd, buf); 3981590Srgrimes return; 3991590Srgrimes } 4001590Srgrimes while (k--) 4011590Srgrimes waddch(wnd, 'X'); 4021590Srgrimes wclrtoeol(wnd); 4031590Srgrimes} 4041590Srgrimes 4051590Srgrimesint 4061590Srgrimescmdiostat(cmd, args) 4071590Srgrimes char *cmd, *args; 4081590Srgrimes{ 4091590Srgrimes 41039230Sgibbs if (prefix(cmd, "kbpt")) 41139230Sgibbs kbpt = !kbpt; 4121590Srgrimes else if (prefix(cmd, "numbers")) 4131590Srgrimes numbers = 1; 4141590Srgrimes else if (prefix(cmd, "bars")) 4151590Srgrimes numbers = 0; 41639230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 4171590Srgrimes return (0); 4181590Srgrimes wclear(wnd); 4191590Srgrimes labeliostat(); 4201590Srgrimes refresh(); 4211590Srgrimes return (1); 4221590Srgrimes} 423