iostat.c revision 74671
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1998 Kenneth D. Merry. 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. The name of the author may not be used to endorse or promote products 141541Srgrimes * derived from this software without specific prior written permission. 151541Srgrimes * 161541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261541Srgrimes * SUCH DAMAGE. 271541Srgrimes * 281541Srgrimes * $FreeBSD: head/usr.bin/systat/iostat.c 74671 2001-03-23 03:58:25Z tmm $ 291541Srgrimes */ 301541Srgrimes/* 311541Srgrimes * Copyright (c) 1980, 1992, 1993 321541Srgrimes * The Regents of the University of California. All rights reserved. 331541Srgrimes * 341541Srgrimes * Redistribution and use in source and binary forms, with or without 351541Srgrimes * modification, are permitted provided that the following conditions 3622521Sdyson * are met: 371541Srgrimes * 1. Redistributions of source code must retain the above copyright 3822521Sdyson * notice, this list of conditions and the following disclaimer. 3922521Sdyson * 2. Redistributions in binary form must reproduce the above copyright 4022521Sdyson * notice, this list of conditions and the following disclaimer in the 4122521Sdyson * documentation and/or other materials provided with the distribution. 4222521Sdyson * 3. All advertising materials mentioning features or use of this software 4350477Speter * must display the following acknowledgement: 441541Srgrimes * This product includes software developed by the University of 451541Srgrimes * California, Berkeley and its contributors. 461541Srgrimes * 4. Neither the name of the University nor the names of its contributors 471541Srgrimes * may be used to endorse or promote products derived from this software 481541Srgrimes * without specific prior written permission. 4977130Sru * 501541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5196755Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 521541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5396755Strhodes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 541541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5535256Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 561541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 571541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 581541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 591541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6096755Strhodes * SUCH DAMAGE. 611541Srgrimes */ 621541Srgrimes 6396755Strhodes#ifndef lint 641541Srgrimesstatic char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 651541Srgrimes#endif not lint 661541Srgrimes 671541Srgrimes#include <sys/param.h> 681541Srgrimes#include <sys/dkstat.h> 691541Srgrimes#include <sys/sysctl.h> 701541Srgrimes 711541Srgrimes#include <string.h> 7277130Sru#include <stdlib.h> 7377130Sru#include <nlist.h> 741541Srgrimes#include <paths.h> 751541Srgrimes#include <devstat.h> 761541Srgrimes#include <err.h> 771541Srgrimes#include "systat.h" 781541Srgrimes#include "extern.h" 791541Srgrimes#include "devs.h" 801541Srgrimes 811541Srgrimesstruct statinfo cur, last; 8296755Strhodes 831541Srgrimesstatic int linesperregion; 841541Srgrimesstatic double etime; 8526963Salexstatic int numbers = 0; /* default display bar graphs */ 861541Srgrimesstatic int kbpt = 0; /* default ms/seek shown */ 871541Srgrimes 881541Srgrimesstatic int barlabels __P((int)); 891541Srgrimesstatic void histogram __P((long double, int, double)); 901541Srgrimesstatic int numlabels __P((int)); 911541Srgrimesstatic int devstats __P((int, int, int)); 921541Srgrimesstatic void stat1 __P((int, int)); 931541Srgrimes 941541SrgrimesWINDOW * 951541Srgrimesopeniostat() 9622521Sdyson{ 9722521Sdyson return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 9822521Sdyson} 9922521Sdyson 10022521Sdysonvoid 1011541Srgrimescloseiostat(w) 10222521Sdyson WINDOW *w; 10322521Sdyson{ 10422521Sdyson if (w == NULL) 10522521Sdyson return; 10622521Sdyson wclear(w); 10722521Sdyson wrefresh(w); 10822521Sdyson delwin(w); 10922521Sdyson} 11022521Sdyson 1111541Srgrimesint 1121541Srgrimesinitiostat() 1131541Srgrimes{ 1141541Srgrimes if ((num_devices = getnumdevs()) < 0) 1151541Srgrimes return(0); 1161541Srgrimes 1171541Srgrimes cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 1181541Srgrimes last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 1191541Srgrimes bzero(cur.dinfo, sizeof(struct devinfo)); 1201541Srgrimes bzero(last.dinfo, sizeof(struct devinfo)); 1211541Srgrimes 1221541Srgrimes /* 1231541Srgrimes * This value for maxshowdevs (100) is bogus. I'm not sure exactly 1241541Srgrimes * how to calculate it, though. 1258876Srgrimes */ 1261541Srgrimes if (dsinit(100, &cur, &last, NULL) != 1) 1271541Srgrimes return(0); 1281541Srgrimes 1291541Srgrimes return(1); 13077130Sru} 1311541Srgrimes 1321541Srgrimesvoid 1331541Srgrimesfetchiostat() 1341541Srgrimes{ 1358876Srgrimes struct devinfo *tmp_dinfo; 1361541Srgrimes size_t len; 1371541Srgrimes int err; 1381541Srgrimes 1391541Srgrimes len = sizeof(cur.cp_time); 1401541Srgrimes err = sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0); 1411541Srgrimes if (err || len != sizeof(cur.cp_time)) { 1421541Srgrimes perror("kern.cp_time"); 1431541Srgrimes exit (1); 14496755Strhodes } 1451541Srgrimes tmp_dinfo = last.dinfo; 1461541Srgrimes last.dinfo = cur.dinfo; 1471541Srgrimes cur.dinfo = tmp_dinfo; 1481541Srgrimes 1498876Srgrimes last.busy_time = cur.busy_time; 1501541Srgrimes 1511541Srgrimes /* 1521541Srgrimes * Here what we want to do is refresh our device stats. 1531541Srgrimes * getdevs() returns 1 when the device list has changed. 1541541Srgrimes * If the device list has changed, we want to go through 1558876Srgrimes * the selection process again, in case a device that we 1561541Srgrimes * were previously displaying has gone away. 1571541Srgrimes */ 1581541Srgrimes switch (getdevs(&cur)) { 1591541Srgrimes case -1: 160108470Sschweikh errx(1, "%s", devstat_errbuf); 1611541Srgrimes break; 1621541Srgrimes case 1: 1631541Srgrimes cmdiostat("refresh", NULL); 16426964Salex break; 1651541Srgrimes default: 1661541Srgrimes break; 1671541Srgrimes } 16826964Salex num_devices = cur.dinfo->numdevs; 1691541Srgrimes generation = cur.dinfo->generation; 1701541Srgrimes 1711541Srgrimes} 17226964Salex 1731541Srgrimes#define INSET 10 1741541Srgrimes 1751541Srgrimesvoid 1761541Srgrimeslabeliostat() 1771541Srgrimes{ 17876166Smarkm int row; 1792960Swollman 18076166Smarkm row = 0; 18176166Smarkm wmove(wnd, row, 0); wclrtobot(wnd); 18276166Smarkm mvwaddstr(wnd, row++, INSET, 18376166Smarkm "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 18476166Smarkm mvwaddstr(wnd, row++, 0, "cpu user|"); 18512769Sphk mvwaddstr(wnd, row++, 0, " nice|"); 1861541Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 18776166Smarkm mvwaddstr(wnd, row++, 0, "interrupt|"); 18877031Sru mvwaddstr(wnd, row++, 0, " idle|"); 1891541Srgrimes if (numbers) 19066356Sbp row = numlabels(row + 1); 19166356Sbp else 19266356Sbp row = barlabels(row + 1); 19366356Sbp} 19466356Sbp 19512769Sphkstatic int 19612769Sphknumlabels(row) 19712769Sphk int row; 1981541Srgrimes{ 19965464Sbp int i, col, regions, ndrives; 20066356Sbp char tmpstr[10]; 20166356Sbp 20265464Sbp#define COLWIDTH 17 20366356Sbp#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 20465464Sbp for (ndrives = 0, i = 0; i < num_devices; i++) 20566356Sbp if (dev_select[i].selected) 20665464Sbp ndrives++; 20765464Sbp regions = howmany(ndrives, DRIVESPERLINE); 20865467Sbp /* 20965464Sbp * Deduct -regions for blank line after each scrolling region. 21065464Sbp */ 21165467Sbp linesperregion = (wnd->_maxy - row - regions) / regions; 21265464Sbp /* 21365464Sbp * Minimum region contains space for two 21412595Sbde * label lines and one line of statistics. 2151541Srgrimes */ 2161541Srgrimes if (linesperregion < 3) 2171541Srgrimes linesperregion = 3; 2181541Srgrimes col = INSET; 2191541Srgrimes for (i = 0; i < num_devices; i++) 2201541Srgrimes if (dev_select[i].selected) { 2211541Srgrimes if (col + COLWIDTH >= wnd->_maxx - INSET) { 2221541Srgrimes col = INSET, row += linesperregion + 1; 2231541Srgrimes if (row > wnd->_maxy - (linesperregion + 1)) 2241541Srgrimes break; 2251541Srgrimes } 2261541Srgrimes sprintf(tmpstr, "%s%d", dev_select[i].device_name, 2271541Srgrimes dev_select[i].unit_number); 2281541Srgrimes mvwaddstr(wnd, row, col + 4, tmpstr); 2291541Srgrimes mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s "); 2301541Srgrimes col += COLWIDTH; 2311541Srgrimes } 2321541Srgrimes if (col) 2331541Srgrimes row += linesperregion + 1; 2341541Srgrimes return (row); 2351541Srgrimes} 2361541Srgrimes 2371541Srgrimesstatic int 2388876Srgrimesbarlabels(row) 23922521Sdyson int row; 2401541Srgrimes{ 2411541Srgrimes int i; 2421541Srgrimes char tmpstr[10]; 2431541Srgrimes 2441541Srgrimes mvwaddstr(wnd, row++, INSET, 2451541Srgrimes "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 2461541Srgrimes linesperregion = 2 + kbpt; 2471541Srgrimes for (i = 0; i < num_devices; i++) 2481541Srgrimes if (dev_select[i].selected) { 2491541Srgrimes if (row > wnd->_maxy - linesperregion) 2501541Srgrimes break; 2511541Srgrimes sprintf(tmpstr, "%s%d", dev_select[i].device_name, 2521541Srgrimes dev_select[i].unit_number); 2531541Srgrimes mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 2541541Srgrimes tmpstr); 2551541Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 2561541Srgrimes if (kbpt) 25750616Sbde mvwaddstr(wnd, row++, 0, " KB/t|"); 2581541Srgrimes } 2591541Srgrimes return (row); 2601541Srgrimes} 2611541Srgrimes 2621541Srgrimes 26350616Sbdevoid 2641541Srgrimesshowiostat() 2651541Srgrimes{ 2661541Srgrimes register long t; 2671541Srgrimes register int i, row, col; 2681541Srgrimes 2691541Srgrimes#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2701541Srgrimes etime = 0; 2711541Srgrimes for(i = 0; i < CPUSTATES; i++) { 2721541Srgrimes X(cp_time); 2731541Srgrimes etime += cur.cp_time[i]; 2741541Srgrimes } 2758876Srgrimes if (etime == 0.0) 2761541Srgrimes etime = 1.0; 2771541Srgrimes etime /= hertz; 2781541Srgrimes row = 1; 2791541Srgrimes for (i = 0; i < CPUSTATES; i++) 2801541Srgrimes stat1(row++, i); 2811541Srgrimes if (!numbers) { 28224987Skato row += 2; 28322521Sdyson for (i = 0; i < num_devices; i++) 28424987Skato if (dev_select[i].selected) { 2851541Srgrimes if (row > wnd->_maxy - linesperregion) 2861541Srgrimes break; 2871541Srgrimes row = devstats(row, INSET, i); 2881541Srgrimes } 2891541Srgrimes return; 2901541Srgrimes } 2911541Srgrimes col = INSET; 2921541Srgrimes wmove(wnd, row + linesperregion, 0); 29366356Sbp wdeleteln(wnd); 2941541Srgrimes wmove(wnd, row + 3, 0); 2951541Srgrimes winsertln(wnd); 2968876Srgrimes for (i = 0; i < num_devices; i++) 2971541Srgrimes if (dev_select[i].selected) { 2981541Srgrimes if (col + COLWIDTH >= wnd->_maxx - INSET) { 2991541Srgrimes col = INSET, row += linesperregion + 1; 3001541Srgrimes if (row > wnd->_maxy - (linesperregion + 1)) 3011541Srgrimes break; 3021541Srgrimes wmove(wnd, row + linesperregion, 0); 30366356Sbp wdeleteln(wnd); 30466356Sbp wmove(wnd, row + 3, 0); 30566356Sbp winsertln(wnd); 30666356Sbp } 30766356Sbp (void) devstats(row + 3, col, i); 30866356Sbp col += COLWIDTH; 3091541Srgrimes } 3101541Srgrimes} 3111541Srgrimes 3121541Srgrimesstatic int 3131541Srgrimesdevstats(row, col, dn) 3141541Srgrimes int row, col, dn; 3151541Srgrimes{ 3161541Srgrimes long double transfers_per_second; 3171541Srgrimes long double kb_per_transfer, mb_per_second; 3181541Srgrimes long double busy_seconds; 3191541Srgrimes int di; 3201541Srgrimes 32166356Sbp di = dev_select[dn].position; 32266356Sbp 32383366Sjulian busy_seconds = compute_etime(cur.busy_time, last.busy_time); 32466356Sbp 32566356Sbp if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di], 3261541Srgrimes busy_seconds, NULL, NULL, NULL, 3271541Srgrimes &kb_per_transfer, &transfers_per_second, 3281541Srgrimes &mb_per_second, NULL, NULL) != 0) 3291541Srgrimes errx(1, "%s", devstat_errbuf); 3301541Srgrimes 3311541Srgrimes if (numbers) { 3321541Srgrimes mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ", 3331541Srgrimes kb_per_transfer, transfers_per_second, 3341541Srgrimes mb_per_second); 3351541Srgrimes return(row); 3361541Srgrimes } 3371541Srgrimes wmove(wnd, row++, col); 3381541Srgrimes histogram(mb_per_second, 50, .5); 3391541Srgrimes wmove(wnd, row++, col); 3401541Srgrimes histogram(transfers_per_second, 50, .5); 3411541Srgrimes if (kbpt) { 3421541Srgrimes wmove(wnd, row++, col); 3431541Srgrimes histogram(kb_per_transfer, 50, .5); 3441541Srgrimes } 3451541Srgrimes 3461541Srgrimes return(row); 3471541Srgrimes 34829584Sphk} 34998183Ssemenu 3501541Srgrimesstatic void 3511541Srgrimesstat1(row, o) 3521541Srgrimes int row, o; 3531541Srgrimes{ 3541541Srgrimes register int i; 3551541Srgrimes double time; 35622521Sdyson 35722521Sdyson time = 0; 35822521Sdyson for (i = 0; i < CPUSTATES; i++) 35922521Sdyson time += cur.cp_time[i]; 36022521Sdyson if (time == 0.0) 36122521Sdyson time = 1.0; 36222521Sdyson wmove(wnd, row, INSET); 36322521Sdyson#define CPUSCALE 0.5 36422521Sdyson histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 36522521Sdyson} 36622521Sdyson 36722521Sdysonstatic void 36822521Sdysonhistogram(val, colwidth, scale) 36922521Sdyson long double val; 37066356Sbp int colwidth; 37183366Sjulian double scale; 37222521Sdyson{ 37366356Sbp char buf[10]; 37422521Sdyson register int k; 3751541Srgrimes register int v = (int)(val * scale) + 0.5; 37666356Sbp 37722521Sdyson k = MIN(v, colwidth); 37822521Sdyson if (v > colwidth) { 37966356Sbp snprintf(buf, sizeof(buf), "%5.2Lf", val); 38066356Sbp k -= strlen(buf); 38166356Sbp while (k--) 38266356Sbp waddch(wnd, 'X'); 38366356Sbp waddstr(wnd, buf); 38466356Sbp return; 38566356Sbp } 38622521Sdyson while (k--) 38766356Sbp waddch(wnd, 'X'); 38822521Sdyson wclrtoeol(wnd); 38922521Sdyson} 39066356Sbp 39122521Sdysonint 39266356Sbpcmdiostat(cmd, args) 39366356Sbp char *cmd, *args; 39422521Sdyson{ 39566356Sbp 39683366Sjulian if (prefix(cmd, "kbpt")) 39766356Sbp kbpt = !kbpt; 39866356Sbp else if (prefix(cmd, "numbers")) 39966356Sbp numbers = 1; 40066356Sbp else if (prefix(cmd, "bars")) 40166356Sbp numbers = 0; 40266356Sbp else if (!dscmd(cmd, args, 100, &cur)) 40398183Ssemenu return (0); 40498183Ssemenu wclear(wnd); 40598183Ssemenu labeliostat(); 40698183Ssemenu refresh(); 40798183Ssemenu return (1); 40898183Ssemenu} 40966356Sbp