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 * 4. Neither the name of the University nor the names of its contributors 411590Srgrimes * may be used to endorse or promote products derived from this software 421590Srgrimes * without specific prior written permission. 431590Srgrimes * 441590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 451590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 461590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 471590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 481590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 491590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 501590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 511590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 521590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 531590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 541590Srgrimes * SUCH DAMAGE. 551590Srgrimes */ 561590Srgrimes 5787715Smarkm#include <sys/cdefs.h> 581590Srgrimes 5987715Smarkm__FBSDID("$FreeBSD$"); 6087715Smarkm 6187715Smarkm#ifdef lint 6287715Smarkmstatic const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 6387715Smarkm#endif 6487715Smarkm 651590Srgrimes#include <sys/param.h> 6674671Stmm#include <sys/sysctl.h> 67111007Sphk#include <sys/resource.h> 681590Srgrimes 6987715Smarkm#include <devstat.h> 7087715Smarkm#include <err.h> 711590Srgrimes#include <nlist.h> 72200462Sdelphij#include <paths.h> 7387715Smarkm#include <stdlib.h> 7487715Smarkm#include <string.h> 7587715Smarkm 761590Srgrimes#include "systat.h" 771590Srgrimes#include "extern.h" 7840060Sobrien#include "devs.h" 791590Srgrimes 8039230Sgibbsstruct statinfo cur, last; 811590Srgrimes 821590Srgrimesstatic int linesperregion; 831590Srgrimesstatic double etime; 841590Srgrimesstatic int numbers = 0; /* default display bar graphs */ 8539230Sgibbsstatic int kbpt = 0; /* default ms/seek shown */ 861590Srgrimes 8792922Simpstatic int barlabels(int); 8892922Simpstatic void histogram(long double, int, double); 8992922Simpstatic int numlabels(int); 9092922Simpstatic int devstats(int, int, int); 9192922Simpstatic void stat1(int, int); 921590Srgrimes 931590SrgrimesWINDOW * 94175387Sdelphijopeniostat(void) 951590Srgrimes{ 96158160Sbde return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); 971590Srgrimes} 981590Srgrimes 991590Srgrimesvoid 100175387Sdelphijcloseiostat(WINDOW *w) 1011590Srgrimes{ 1021590Srgrimes if (w == NULL) 1031590Srgrimes return; 1041590Srgrimes wclear(w); 1051590Srgrimes wrefresh(w); 1061590Srgrimes delwin(w); 1071590Srgrimes} 1081590Srgrimes 1091590Srgrimesint 110175387Sdelphijinitiostat(void) 1111590Srgrimes{ 11283131Sken if ((num_devices = devstat_getnumdevs(NULL)) < 0) 1131590Srgrimes return(0); 11439230Sgibbs 11539230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 11639230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 11739230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 11839230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 119158161Sbde 12039230Sgibbs /* 12139230Sgibbs * This value for maxshowdevs (100) is bogus. I'm not sure exactly 12239230Sgibbs * how to calculate it, though. 12339230Sgibbs */ 12439230Sgibbs if (dsinit(100, &cur, &last, NULL) != 1) 12539230Sgibbs return(0); 12639230Sgibbs 1271590Srgrimes return(1); 1281590Srgrimes} 1291590Srgrimes 1301590Srgrimesvoid 131175387Sdelphijfetchiostat(void) 1321590Srgrimes{ 13339230Sgibbs struct devinfo *tmp_dinfo; 13469141Srwatson size_t len; 13539230Sgibbs 13669141Srwatson len = sizeof(cur.cp_time); 13787715Smarkm if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 13887715Smarkm || len != sizeof(cur.cp_time)) { 13969141Srwatson perror("kern.cp_time"); 14069141Srwatson exit (1); 14169141Srwatson } 14239230Sgibbs tmp_dinfo = last.dinfo; 14339230Sgibbs last.dinfo = cur.dinfo; 14439230Sgibbs cur.dinfo = tmp_dinfo; 145121836Stjr 146121836Stjr last.snap_time = cur.snap_time; 147158161Sbde 14839230Sgibbs /* 14939230Sgibbs * Here what we want to do is refresh our device stats. 15039230Sgibbs * getdevs() returns 1 when the device list has changed. 15139230Sgibbs * If the device list has changed, we want to go through 15239230Sgibbs * the selection process again, in case a device that we 15339230Sgibbs * were previously displaying has gone away. 15439230Sgibbs */ 15583131Sken switch (devstat_getdevs(NULL, &cur)) { 15639230Sgibbs case -1: 15739230Sgibbs errx(1, "%s", devstat_errbuf); 15839230Sgibbs break; 15939230Sgibbs case 1: 16039230Sgibbs cmdiostat("refresh", NULL); 16139230Sgibbs break; 16239230Sgibbs default: 16339230Sgibbs break; 16439230Sgibbs } 16539230Sgibbs num_devices = cur.dinfo->numdevs; 16639230Sgibbs generation = cur.dinfo->generation; 16739230Sgibbs 1681590Srgrimes} 1691590Srgrimes 1701590Srgrimes#define INSET 10 1711590Srgrimes 1721590Srgrimesvoid 173175387Sdelphijlabeliostat(void) 1741590Srgrimes{ 1751590Srgrimes int row; 1761590Srgrimes 1771590Srgrimes row = 0; 1781590Srgrimes wmove(wnd, row, 0); wclrtobot(wnd); 1791590Srgrimes mvwaddstr(wnd, row++, INSET, 180164689Syar "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 1811590Srgrimes mvwaddstr(wnd, row++, 0, "cpu user|"); 1821590Srgrimes mvwaddstr(wnd, row++, 0, " nice|"); 1831590Srgrimes mvwaddstr(wnd, row++, 0, " system|"); 1844930Sbde mvwaddstr(wnd, row++, 0, "interrupt|"); 1851590Srgrimes mvwaddstr(wnd, row++, 0, " idle|"); 1861590Srgrimes if (numbers) 1871590Srgrimes row = numlabels(row + 1); 1881590Srgrimes else 1891590Srgrimes row = barlabels(row + 1); 1901590Srgrimes} 1911590Srgrimes 1921590Srgrimesstatic int 193175387Sdelphijnumlabels(int row) 1941590Srgrimes{ 19587715Smarkm int i, _col, regions, ndrives; 19639230Sgibbs char tmpstr[10]; 1971590Srgrimes 19839230Sgibbs#define COLWIDTH 17 19950635Speter#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 20039230Sgibbs for (ndrives = 0, i = 0; i < num_devices; i++) 20139230Sgibbs if (dev_select[i].selected) 2021590Srgrimes ndrives++; 2031590Srgrimes regions = howmany(ndrives, DRIVESPERLINE); 2041590Srgrimes /* 2051590Srgrimes * Deduct -regions for blank line after each scrolling region. 2061590Srgrimes */ 20750635Speter linesperregion = (wnd->_maxy - row - regions) / regions; 2081590Srgrimes /* 2091590Srgrimes * Minimum region contains space for two 2101590Srgrimes * label lines and one line of statistics. 2111590Srgrimes */ 2121590Srgrimes if (linesperregion < 3) 2131590Srgrimes linesperregion = 3; 21487715Smarkm _col = INSET; 21539230Sgibbs for (i = 0; i < num_devices; i++) 21639230Sgibbs if (dev_select[i].selected) { 21787715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 21887715Smarkm _col = INSET, row += linesperregion + 1; 21950635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2201590Srgrimes break; 2211590Srgrimes } 22239230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 22339230Sgibbs dev_select[i].unit_number); 22487715Smarkm mvwaddstr(wnd, row, _col + 4, tmpstr); 22587715Smarkm mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 22687715Smarkm _col += COLWIDTH; 2271590Srgrimes } 22887715Smarkm if (_col) 2291590Srgrimes row += linesperregion + 1; 2301590Srgrimes return (row); 2311590Srgrimes} 2321590Srgrimes 2331590Srgrimesstatic int 234175387Sdelphijbarlabels(int row) 2351590Srgrimes{ 2361590Srgrimes int i; 23739230Sgibbs char tmpstr[10]; 2381590Srgrimes 2391590Srgrimes mvwaddstr(wnd, row++, INSET, 240164689Syar "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 24139230Sgibbs linesperregion = 2 + kbpt; 24239230Sgibbs for (i = 0; i < num_devices; i++) 24339230Sgibbs if (dev_select[i].selected) { 24450635Speter if (row > wnd->_maxy - linesperregion) 2451590Srgrimes break; 24639230Sgibbs sprintf(tmpstr, "%s%d", dev_select[i].device_name, 24739230Sgibbs dev_select[i].unit_number); 248158161Sbde mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 24939230Sgibbs tmpstr); 2501590Srgrimes mvwaddstr(wnd, row++, 0, " tps|"); 25139230Sgibbs if (kbpt) 25239230Sgibbs mvwaddstr(wnd, row++, 0, " KB/t|"); 2531590Srgrimes } 2541590Srgrimes return (row); 2551590Srgrimes} 2561590Srgrimes 2571590Srgrimes 2581590Srgrimesvoid 259175387Sdelphijshowiostat(void) 2601590Srgrimes{ 26187715Smarkm long t; 26287715Smarkm int i, row, _col; 2631590Srgrimes 26439230Sgibbs#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 2651590Srgrimes etime = 0; 2661590Srgrimes for(i = 0; i < CPUSTATES; i++) { 2671590Srgrimes X(cp_time); 26839230Sgibbs etime += cur.cp_time[i]; 2691590Srgrimes } 2701590Srgrimes if (etime == 0.0) 2711590Srgrimes etime = 1.0; 2724930Sbde etime /= hertz; 2731590Srgrimes row = 1; 2744930Sbde for (i = 0; i < CPUSTATES; i++) 2751590Srgrimes stat1(row++, i); 2761590Srgrimes if (!numbers) { 2771590Srgrimes row += 2; 27839230Sgibbs for (i = 0; i < num_devices; i++) 27939230Sgibbs if (dev_select[i].selected) { 28050635Speter if (row > wnd->_maxy - linesperregion) 2811590Srgrimes break; 28239230Sgibbs row = devstats(row, INSET, i); 2831590Srgrimes } 2841590Srgrimes return; 2851590Srgrimes } 28687715Smarkm _col = INSET; 2871590Srgrimes wmove(wnd, row + linesperregion, 0); 2881590Srgrimes wdeleteln(wnd); 2891590Srgrimes wmove(wnd, row + 3, 0); 2901590Srgrimes winsertln(wnd); 29139230Sgibbs for (i = 0; i < num_devices; i++) 29239230Sgibbs if (dev_select[i].selected) { 29387715Smarkm if (_col + COLWIDTH >= wnd->_maxx - INSET) { 29487715Smarkm _col = INSET, row += linesperregion + 1; 29550635Speter if (row > wnd->_maxy - (linesperregion + 1)) 2961590Srgrimes break; 2971590Srgrimes wmove(wnd, row + linesperregion, 0); 2981590Srgrimes wdeleteln(wnd); 2991590Srgrimes wmove(wnd, row + 3, 0); 3001590Srgrimes winsertln(wnd); 3011590Srgrimes } 30287715Smarkm (void) devstats(row + 3, _col, i); 30387715Smarkm _col += COLWIDTH; 3041590Srgrimes } 3051590Srgrimes} 3061590Srgrimes 3071590Srgrimesstatic int 308175387Sdelphijdevstats(int row, int _col, int dn) 3091590Srgrimes{ 31039230Sgibbs long double transfers_per_second; 31139230Sgibbs long double kb_per_transfer, mb_per_second; 31239230Sgibbs long double busy_seconds; 31339230Sgibbs int di; 314158161Sbde 31539230Sgibbs di = dev_select[dn].position; 3161590Srgrimes 317112288Sphk busy_seconds = cur.snap_time - last.snap_time; 31839230Sgibbs 31983131Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 32083131Sken &last.dinfo->devices[di], busy_seconds, 32183131Sken DSM_KB_PER_TRANSFER, &kb_per_transfer, 32283131Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 32383131Sken DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 32439230Sgibbs errx(1, "%s", devstat_errbuf); 32539230Sgibbs 3261590Srgrimes if (numbers) { 32787715Smarkm mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 32839230Sgibbs kb_per_transfer, transfers_per_second, 32939230Sgibbs mb_per_second); 33039230Sgibbs return(row); 3311590Srgrimes } 33287715Smarkm wmove(wnd, row++, _col); 33361148Sphk histogram(mb_per_second, 50, .5); 33487715Smarkm wmove(wnd, row++, _col); 33561148Sphk histogram(transfers_per_second, 50, .5); 33639230Sgibbs if (kbpt) { 33787715Smarkm wmove(wnd, row++, _col); 33861148Sphk histogram(kb_per_transfer, 50, .5); 3391590Srgrimes } 34039230Sgibbs 34139230Sgibbs return(row); 34239230Sgibbs 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimesstatic void 346175387Sdelphijstat1(int row, int o) 3471590Srgrimes{ 34887715Smarkm int i; 34987715Smarkm double dtime; 3501590Srgrimes 35187715Smarkm dtime = 0.0; 3521590Srgrimes for (i = 0; i < CPUSTATES; i++) 35387715Smarkm dtime += cur.cp_time[i]; 35487715Smarkm if (dtime == 0.0) 35587715Smarkm dtime = 1.0; 3561590Srgrimes wmove(wnd, row, INSET); 3571590Srgrimes#define CPUSCALE 0.5 35887715Smarkm histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 3591590Srgrimes} 3601590Srgrimes 3611590Srgrimesstatic void 362175387Sdelphijhistogram(long double val, int colwidth, double scale) 3631590Srgrimes{ 3641590Srgrimes char buf[10]; 36587715Smarkm int k; 36687715Smarkm int v = (int)(val * scale) + 0.5; 3671590Srgrimes 3681590Srgrimes k = MIN(v, colwidth); 3691590Srgrimes if (v > colwidth) { 37039230Sgibbs snprintf(buf, sizeof(buf), "%5.2Lf", val); 3711590Srgrimes k -= strlen(buf); 3721590Srgrimes while (k--) 3731590Srgrimes waddch(wnd, 'X'); 3741590Srgrimes waddstr(wnd, buf); 3751590Srgrimes return; 3761590Srgrimes } 3771590Srgrimes while (k--) 3781590Srgrimes waddch(wnd, 'X'); 3791590Srgrimes wclrtoeol(wnd); 3801590Srgrimes} 3811590Srgrimes 3821590Srgrimesint 383175387Sdelphijcmdiostat(const char *cmd, const char *args) 3841590Srgrimes{ 3851590Srgrimes 38639230Sgibbs if (prefix(cmd, "kbpt")) 38739230Sgibbs kbpt = !kbpt; 3881590Srgrimes else if (prefix(cmd, "numbers")) 3891590Srgrimes numbers = 1; 3901590Srgrimes else if (prefix(cmd, "bars")) 3911590Srgrimes numbers = 0; 39239230Sgibbs else if (!dscmd(cmd, args, 100, &cur)) 3931590Srgrimes return (0); 3941590Srgrimes wclear(wnd); 3951590Srgrimes labeliostat(); 3961590Srgrimes refresh(); 3971590Srgrimes return (1); 3981590Srgrimes} 399