iostat.c revision 287633
112115Sdyson/* 212115Sdyson * Copyright (c) 1998 Kenneth D. Merry. 312115Sdyson * All rights reserved. 412115Sdyson * 512115Sdyson * Redistribution and use in source and binary forms, with or without 612115Sdyson * modification, are permitted provided that the following conditions 712115Sdyson * are met: 812115Sdyson * 1. Redistributions of source code must retain the above copyright 912115Sdyson * notice, this list of conditions and the following disclaimer. 1012115Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1112115Sdyson * notice, this list of conditions and the following disclaimer in the 1212115Sdyson * documentation and/or other materials provided with the distribution. 1312115Sdyson * 3. The name of the author may not be used to endorse or promote products 1412115Sdyson * derived from this software without specific prior written permission. 1512115Sdyson * 1612115Sdyson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1712115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1812115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1912115Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2012115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2112115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2212115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2312115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2412115Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2512115Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2612115Sdyson * SUCH DAMAGE. 2712115Sdyson */ 2812115Sdyson/* 2912115Sdyson * Copyright (c) 1980, 1992, 1993 3012115Sdyson * The Regents of the University of California. All rights reserved. 3112115Sdyson * 3212115Sdyson * Redistribution and use in source and binary forms, with or without 3312115Sdyson * modification, are permitted provided that the following conditions 3412115Sdyson * are met: 3512115Sdyson * 1. Redistributions of source code must retain the above copyright 3612115Sdyson * notice, this list of conditions and the following disclaimer. 3712115Sdyson * 2. Redistributions in binary form must reproduce the above copyright 3812115Sdyson * notice, this list of conditions and the following disclaimer in the 3912115Sdyson * documentation and/or other materials provided with the distribution. 4012115Sdyson * 4. Neither the name of the University nor the names of its contributors 4112115Sdyson * may be used to endorse or promote products derived from this software 4213260Swollman * without specific prior written permission. 4312115Sdyson * 4412115Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4512115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4612115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4712115Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 4812115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4912115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5012115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5112115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5229906Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5324131Sbde * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5412115Sdyson * SUCH DAMAGE. 5512115Sdyson */ 5612115Sdyson 5712115Sdyson#include <sys/cdefs.h> 5812115Sdyson 5912115Sdyson__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 287633 2015-09-10 22:07:52Z delphij $"); 6012115Sdyson 6112115Sdyson#ifdef lint 6212115Sdysonstatic const char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 6312115Sdyson#endif 6412115Sdyson 6512115Sdyson#include <sys/param.h> 6612115Sdyson#include <sys/sysctl.h> 6712115Sdyson#include <sys/resource.h> 6812115Sdyson 6912115Sdyson#include <devstat.h> 7028270Swollman#include <err.h> 7112911Sphk#include <nlist.h> 7212911Sphk#include <paths.h> 7312911Sphk#include <stdlib.h> 7412911Sphk#include <string.h> 7512911Sphk 7612911Sphk#include "systat.h" 7712911Sphk#include "extern.h" 7812911Sphk#include "devs.h" 7912911Sphk 8012911Sphkstruct statinfo cur, last; 8112911Sphk 8212911Sphkstatic int linesperregion; 8312911Sphkstatic double etime; 8412115Sdysonstatic int numbers = 0; /* default display bar graphs */ 8531315Sbdestatic int kbpt = 0; /* default ms/seek shown */ 8630280Sphk 8712911Sphkstatic int barlabels(int); 8812115Sdysonstatic void histogram(long double, int, double); 8912115Sdysonstatic int numlabels(int); 9012115Sdysonstatic int devstats(int, int, int); 9112115Sdysonstatic void stat1(int, int); 9212115Sdyson 9312115SdysonWINDOW * 9412115Sdysonopeniostat(void) 9512115Sdyson{ 9612115Sdyson return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0)); 9712115Sdyson} 9812115Sdyson 9912115Sdysonvoid 10012115Sdysoncloseiostat(WINDOW *w) 10138909Sbde{ 10212115Sdyson if (w == NULL) 10312115Sdyson return; 10412115Sdyson wclear(w); 10512911Sphk wrefresh(w); 10612115Sdyson delwin(w); 10716322Sgpalmer} 10816322Sgpalmer 10916322Sgpalmerint 11016322Sgpalmerinitiostat(void) 11116322Sgpalmer{ 11216322Sgpalmer if ((num_devices = devstat_getnumdevs(NULL)) < 0) 11316322Sgpalmer return(0); 11412115Sdyson 11516322Sgpalmer cur.dinfo = calloc(1, sizeof(struct devinfo)); 11612115Sdyson last.dinfo = calloc(1, sizeof(struct devinfo)); 11712115Sdyson 11812115Sdyson /* 11912115Sdyson * This value for maxshowdevs (100) is bogus. I'm not sure exactly 12012115Sdyson * how to calculate it, though. 12112911Sphk */ 12212115Sdyson if (dsinit(100, &cur, &last, NULL) != 1) 12312115Sdyson return(0); 12412115Sdyson 12512115Sdyson return(1); 12612115Sdyson} 12712115Sdyson 12812115Sdysonvoid 12912115Sdysonfetchiostat(void) 13012115Sdyson{ 13129208Sbde struct devinfo *tmp_dinfo; 13229208Sbde size_t len; 13329208Sbde 13429208Sbde len = sizeof(cur.cp_time); 13512115Sdyson if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) 13612115Sdyson || len != sizeof(cur.cp_time)) { 13712115Sdyson perror("kern.cp_time"); 13812115Sdyson exit (1); 13929888Skato } 14029888Skato tmp_dinfo = last.dinfo; 14129888Skato last.dinfo = cur.dinfo; 14229888Skato cur.dinfo = tmp_dinfo; 14312115Sdyson 14412115Sdyson last.snap_time = cur.snap_time; 14512115Sdyson 14612115Sdyson /* 14712115Sdyson * Here what we want to do is refresh our device stats. 14812115Sdyson * getdevs() returns 1 when the device list has changed. 14912115Sdyson * If the device list has changed, we want to go through 15012115Sdyson * the selection process again, in case a device that we 15112115Sdyson * were previously displaying has gone away. 15230469Sjulian */ 15312115Sdyson switch (devstat_getdevs(NULL, &cur)) { 15412115Sdyson case -1: 15512115Sdyson errx(1, "%s", devstat_errbuf); 15612115Sdyson break; 15712115Sdyson case 1: 15812115Sdyson cmdiostat("refresh", NULL); 15912115Sdyson break; 16012115Sdyson default: 16112115Sdyson break; 16212115Sdyson } 16312115Sdyson num_devices = cur.dinfo->numdevs; 16412115Sdyson generation = cur.dinfo->generation; 16512115Sdyson 16612115Sdyson} 16712115Sdyson 16812115Sdyson#define INSET 10 16916322Sgpalmer 17012115Sdysonvoid 17112115Sdysonlabeliostat(void) 17212115Sdyson{ 17312115Sdyson int row; 17412115Sdyson 17512115Sdyson row = 0; 17612911Sphk wmove(wnd, row, 0); wclrtobot(wnd); 17712115Sdyson mvwaddstr(wnd, row++, INSET, 17812115Sdyson "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 17912115Sdyson mvwaddstr(wnd, row++, 0, "cpu user|"); 18012115Sdyson mvwaddstr(wnd, row++, 0, " nice|"); 18112115Sdyson mvwaddstr(wnd, row++, 0, " system|"); 18212115Sdyson mvwaddstr(wnd, row++, 0, "interrupt|"); 18312115Sdyson mvwaddstr(wnd, row++, 0, " idle|"); 18412115Sdyson if (numbers) 18512115Sdyson row = numlabels(row + 1); 18612115Sdyson else 18712115Sdyson row = barlabels(row + 1); 18812115Sdyson} 18912115Sdyson 19039028Sbdestatic int 19112115Sdysonnumlabels(int row) 19243301Sdillon{ 19312115Sdyson int i, _col, regions, ndrives; 19412115Sdyson char tmpstr[10]; 19512115Sdyson 19612115Sdyson#define COLWIDTH 17 19729888Skato#define DRIVESPERLINE ((getmaxx(wnd) - 1 - INSET) / COLWIDTH) 19829888Skato for (ndrives = 0, i = 0; i < num_devices; i++) 19912115Sdyson if (dev_select[i].selected) 20012115Sdyson ndrives++; 20112115Sdyson regions = howmany(ndrives, DRIVESPERLINE); 20212115Sdyson /* 20312115Sdyson * Deduct -regions for blank line after each scrolling region. 20429888Skato */ 20529888Skato linesperregion = (getmaxy(wnd) - 1 - row - regions) / regions; 20629888Skato /* 20729888Skato * Minimum region contains space for two 20812115Sdyson * label lines and one line of statistics. 20912115Sdyson */ 21012115Sdyson if (linesperregion < 3) 21112115Sdyson linesperregion = 3; 21222521Sdyson _col = INSET; 21312115Sdyson for (i = 0; i < num_devices; i++) 21412115Sdyson if (dev_select[i].selected) { 21522521Sdyson if (_col + COLWIDTH >= getmaxx(wnd) - 1 - INSET) { 21639670Sbde _col = INSET, row += linesperregion + 1; 21739670Sbde if (row > getmaxy(wnd) - 1 - (linesperregion + 1)) 21839670Sbde break; 21939670Sbde } 22039670Sbde sprintf(tmpstr, "%s%d", dev_select[i].device_name, 22112115Sdyson dev_select[i].unit_number); 22212115Sdyson mvwaddstr(wnd, row, _col + 4, tmpstr); 22312115Sdyson mvwaddstr(wnd, row + 1, _col, " KB/t tps MB/s "); 22412115Sdyson _col += COLWIDTH; 22512115Sdyson } 22639028Sbde if (_col) 22739028Sbde row += linesperregion + 1; 22839028Sbde return (row); 22939028Sbde} 23039028Sbde 23139028Sbdestatic int 23239028Sbdebarlabels(int row) 23339028Sbde{ 23443301Sdillon int i; 23543301Sdillon char tmpstr[10]; 23639028Sbde 23739028Sbde mvwaddstr(wnd, row++, INSET, 23839028Sbde "/0% /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 23939028Sbde linesperregion = 2 + kbpt; 24039028Sbde for (i = 0; i < num_devices; i++) 24139028Sbde if (dev_select[i].selected) { 24239670Sbde if (row > getmaxy(wnd) - 1 - linesperregion) 24339670Sbde break; 24439670Sbde sprintf(tmpstr, "%s%d", dev_select[i].device_name, 24539670Sbde dev_select[i].unit_number); 24639670Sbde mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 24739670Sbde tmpstr); 24839670Sbde mvwaddstr(wnd, row++, 0, " tps|"); 24939670Sbde if (kbpt) 25039670Sbde mvwaddstr(wnd, row++, 0, " KB/t|"); 25139670Sbde } 25239670Sbde return (row); 25339670Sbde} 25439670Sbde 25512115Sdysonvoid 25612115Sdysonshowiostat(void) 25739670Sbde{ 25812115Sdyson long t; 25912115Sdyson int i, row, _col; 26012115Sdyson 26112115Sdyson#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 26212115Sdyson etime = 0; 26312115Sdyson for(i = 0; i < CPUSTATES; i++) { 26412115Sdyson X(cp_time); 26512115Sdyson etime += cur.cp_time[i]; 26612115Sdyson } 26712115Sdyson if (etime == 0.0) 26812115Sdyson etime = 1.0; 26912115Sdyson etime /= hertz; 27012115Sdyson row = 1; 27143301Sdillon for (i = 0; i < CPUSTATES; i++) 27212115Sdyson stat1(row++, i); 27312115Sdyson if (!numbers) { 27412115Sdyson row += 2; 27512115Sdyson for (i = 0; i < num_devices; i++) 27612115Sdyson if (dev_select[i].selected) { 27712115Sdyson if (row > getmaxy(wnd) - linesperregion) 27812115Sdyson break; 27940651Sbde row = devstats(row, INSET, i); 28040651Sbde } 28112115Sdyson return; 28212115Sdyson } 28312115Sdyson _col = INSET; 28439028Sbde wmove(wnd, row + linesperregion, 0); 28539028Sbde wdeleteln(wnd); 28639028Sbde wmove(wnd, row + 3, 0); 28739028Sbde winsertln(wnd); 28839028Sbde for (i = 0; i < num_devices; i++) 28939028Sbde if (dev_select[i].selected) { 29039028Sbde if (_col + COLWIDTH >= getmaxx(wnd) - 1 - INSET) { 29139028Sbde _col = INSET, row += linesperregion + 1; 29239028Sbde if (row > getmaxy(wnd) - 1 - (linesperregion + 1)) 29339028Sbde break; 29443301Sdillon wmove(wnd, row + linesperregion, 0); 29539028Sbde wdeleteln(wnd); 29639028Sbde wmove(wnd, row + 3, 0); 29739028Sbde winsertln(wnd); 29839028Sbde } 29939028Sbde (void) devstats(row + 3, _col, i); 30039028Sbde _col += COLWIDTH; 30129888Skato } 30229888Skato} 30329888Skato 30429888Skatostatic int 30529888Skatodevstats(int row, int _col, int dn) 30612115Sdyson{ 30729888Skato long double transfers_per_second; 30812115Sdyson long double kb_per_transfer, mb_per_second; 30912115Sdyson long double busy_seconds; 31012115Sdyson int di; 31112115Sdyson 31212115Sdyson di = dev_select[dn].position; 31312115Sdyson 31412115Sdyson busy_seconds = cur.snap_time - last.snap_time; 31512115Sdyson 31612115Sdyson if (devstat_compute_statistics(&cur.dinfo->devices[di], 31712115Sdyson &last.dinfo->devices[di], busy_seconds, 31812115Sdyson DSM_KB_PER_TRANSFER, &kb_per_transfer, 31912115Sdyson DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 32012115Sdyson DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0) 32112115Sdyson errx(1, "%s", devstat_errbuf); 32212115Sdyson 32312115Sdyson if (numbers) { 32412115Sdyson mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ", 32512115Sdyson kb_per_transfer, transfers_per_second, 32612115Sdyson mb_per_second); 32712115Sdyson return(row); 32812115Sdyson } 32912115Sdyson wmove(wnd, row++, _col); 33012115Sdyson histogram(mb_per_second, 50, .5); 33112115Sdyson wmove(wnd, row++, _col); 33212115Sdyson histogram(transfers_per_second, 50, .5); 33312115Sdyson if (kbpt) { 33412115Sdyson wmove(wnd, row++, _col); 33512115Sdyson histogram(kb_per_transfer, 50, .5); 33612115Sdyson } 33712115Sdyson 33812115Sdyson return(row); 33912115Sdyson 34012115Sdyson} 34112115Sdyson 34212115Sdysonstatic void 34312115Sdysonstat1(int row, int o) 34412115Sdyson{ 34512115Sdyson int i; 34612115Sdyson double dtime; 34712115Sdyson 34812115Sdyson dtime = 0.0; 34912115Sdyson for (i = 0; i < CPUSTATES; i++) 35012115Sdyson dtime += cur.cp_time[i]; 35112115Sdyson if (dtime == 0.0) 35212115Sdyson dtime = 1.0; 35312115Sdyson wmove(wnd, row, INSET); 35439671Sbde#define CPUSCALE 0.5 35512115Sdyson histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE); 35612115Sdyson} 35712115Sdyson 35812115Sdysonstatic void 35912115Sdysonhistogram(long double val, int colwidth, double scale) 36012115Sdyson{ 36112115Sdyson char buf[10]; 36212115Sdyson int k; 36339671Sbde int v = (int)(val * scale) + 0.5; 36412115Sdyson 36512115Sdyson k = MIN(v, colwidth); 36612115Sdyson if (v > colwidth) { 36712115Sdyson snprintf(buf, sizeof(buf), "%5.2Lf", val); 36812115Sdyson k -= strlen(buf); 36912115Sdyson while (k--) 37012115Sdyson waddch(wnd, 'X'); 37112115Sdyson waddstr(wnd, buf); 37212115Sdyson return; 37339671Sbde } 37412115Sdyson while (k--) 37512115Sdyson waddch(wnd, 'X'); 37612115Sdyson wclrtoeol(wnd); 37712115Sdyson} 37812115Sdyson 37912115Sdysonint 38012115Sdysoncmdiostat(const char *cmd, const char *args) 38112115Sdyson{ 38212115Sdyson 38312115Sdyson if (prefix(cmd, "kbpt")) 38412115Sdyson kbpt = !kbpt; 38512115Sdyson else if (prefix(cmd, "numbers")) 38612115Sdyson numbers = 1; 38712115Sdyson else if (prefix(cmd, "bars")) 38812115Sdyson numbers = 0; 38912115Sdyson else if (!dscmd(cmd, args, 100, &cur)) 39012115Sdyson return (0); 39112115Sdyson wclear(wnd); 39212115Sdyson labeliostat(); 39312115Sdyson refresh(); 39412115Sdyson return (1); 39512115Sdyson} 39612115Sdyson