iostat.c revision 1.18
1/* $OpenBSD: iostat.c,v 1.18 2002/06/18 00:46:47 deraadt Exp $ */ 2/* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */ 3 4/* 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38#if 0 39static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 40#endif 41static char rcsid[] = "$OpenBSD: iostat.c,v 1.18 2002/06/18 00:46:47 deraadt Exp $"; 42#endif /* not lint */ 43 44#include <sys/param.h> 45#include <sys/dkstat.h> 46#include <sys/buf.h> 47#include <sys/time.h> 48 49#include <string.h> 50#include <stdlib.h> 51#include <paths.h> 52#include "systat.h" 53#include "extern.h" 54 55#include "dkstats.h" 56extern struct _disk cur; 57 58static int linesperregion; 59static double etime; 60static int numbers = 0; /* default display bar graphs */ 61static int secs = 0; /* default seconds shown */ 62 63static int barlabels(int); 64static void histogram(double, int, double); 65static int numlabels(int); 66static int stats(int, int, int); 67static void stat1(int, int); 68 69 70WINDOW * 71openiostat(void) 72{ 73 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 74} 75 76void 77closeiostat(WINDOW *w) 78{ 79 if (w == NULL) 80 return; 81 wclear(w); 82 wrefresh(w); 83 delwin(w); 84} 85 86int 87initiostat(void) 88{ 89 dkinit(1); 90 dkreadstats(); 91 return (1); 92} 93 94void 95fetchiostat(void) 96{ 97 if (dk_ndrive == 0) 98 return; 99 dkreadstats(); 100} 101 102#define INSET 10 103 104void 105labeliostat(void) 106{ 107 int row; 108 109 row = 0; 110 wmove(wnd, row, 0); wclrtobot(wnd); 111 mvwaddstr(wnd, row++, INSET, 112 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 113 mvwaddstr(wnd, row++, 0, "cpu user|"); 114 mvwaddstr(wnd, row++, 0, " nice|"); 115 mvwaddstr(wnd, row++, 0, " system|"); 116 mvwaddstr(wnd, row++, 0, "interrupt|"); 117 mvwaddstr(wnd, row++, 0, " idle|"); 118 if (numbers) 119 row = numlabels(row + 1); 120 else 121 row = barlabels(row + 1); 122} 123 124static int 125numlabels(int row) 126{ 127 int i, col, regions, ndrives; 128 129 if (dk_ndrive == 0) { 130 mvwaddstr(wnd, row++, INSET, "No drives attached."); 131 return (row); 132 } 133#define COLWIDTH 17 134#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 135 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 136 if (cur.dk_select[i]) 137 ndrives++; 138 regions = howmany(ndrives, DRIVESPERLINE); 139 /* 140 * Deduct -regions for blank line after each scrolling region. 141 */ 142 linesperregion = (wnd->_maxy - row - regions) / regions; 143 /* 144 * Minimum region contains space for two 145 * label lines and one line of statistics. 146 */ 147 if (linesperregion < 3) 148 linesperregion = 3; 149 col = INSET; 150 for (i = 0; i < dk_ndrive; i++) 151 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 152 if (col + COLWIDTH >= wnd->_maxx) { 153 col = INSET, row += linesperregion + 1; 154 if (row > wnd->_maxy - (linesperregion + 1)) 155 break; 156 } 157 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]); 158 mvwaddstr(wnd, row + 1, col, " KBps tps sec"); 159 col += COLWIDTH; 160 } 161 if (col) 162 row += linesperregion + 1; 163 return (row); 164} 165 166static int 167barlabels(int row) 168{ 169 int i; 170 171 if (dk_ndrive == 0) { 172 mvwaddstr(wnd, row++, INSET, "No drives attached."); 173 return (row); 174 } 175 mvwaddstr(wnd, row++, INSET, 176 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 177 linesperregion = 2 + secs; 178 for (i = 0; i < dk_ndrive; i++) 179 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 180 if (row > wnd->_maxy - linesperregion) 181 break; 182 mvwprintw(wnd, row++, 0, "%4.4s Kps|", cur.dk_name[i]); 183 mvwaddstr(wnd, row++, 0, " tps|"); 184 if (secs) 185 mvwaddstr(wnd, row++, 0, " msec|"); 186 } 187 return (row); 188} 189 190 191void 192showiostat(void) 193{ 194 int i, row, col; 195 196 dkswap(); 197 198 etime = 0; 199 for (i = 0; i < CPUSTATES; i++) { 200 etime += cur.cp_time[i]; 201 } 202 if (etime == 0.0) 203 etime = 1.0; 204 etime /= (float) hz; 205 row = 1; 206 207 /* 208 * Interrupt CPU state not calculated yet. 209 */ 210 for (i = 0; i < CPUSTATES; i++) 211 stat1(row++, i); 212 213 if (dk_ndrive == 0) 214 return; 215 216 if (!numbers) { 217 row += 2; 218 for (i = 0; i < dk_ndrive; i++) 219 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 220 if (row > wnd->_maxy - linesperregion) 221 break; 222 row = stats(row, INSET, i); 223 } 224 return; 225 } 226 col = INSET; 227 wmove(wnd, row + linesperregion, 0); 228 wdeleteln(wnd); 229 wmove(wnd, row + 3, 0); 230 winsertln(wnd); 231 for (i = 0; i < dk_ndrive; i++) 232 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 233 if (col + COLWIDTH >= wnd->_maxx) { 234 col = INSET, row += linesperregion + 1; 235 if (row > wnd->_maxy - (linesperregion + 1)) 236 break; 237 wmove(wnd, row + linesperregion, 0); 238 wdeleteln(wnd); 239 wmove(wnd, row + 3, 0); 240 winsertln(wnd); 241 } 242 (void) stats(row + 3, col, i); 243 col += COLWIDTH; 244 } 245} 246 247static int 248stats(int row, int col, int dn) 249{ 250 double atime, words; 251 252 /* time busy in disk activity */ 253 atime = (double)cur.dk_time[dn].tv_sec + 254 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 255 256 words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */ 257 if (numbers) { 258 mvwprintw(wnd, row, col, "%5.0f%4.0f%5.1f", 259 words / etime, cur.dk_xfer[dn] / etime, atime / etime); 260 return (row); 261 } 262 wmove(wnd, row++, col); 263 histogram(words / etime, 50, 0.5); 264 wmove(wnd, row++, col); 265 histogram(cur.dk_xfer[dn] / etime, 50, 0.5); 266 if (secs) { 267 wmove(wnd, row++, col); 268 atime *= 1000; /* In milliseconds */ 269 histogram(atime / etime, 50, 0.5); 270 } 271 return (row); 272} 273 274static void 275stat1(int row, int o) 276{ 277 int i; 278 double time; 279 280 time = 0; 281 for (i = 0; i < CPUSTATES; i++) 282 time += cur.cp_time[i]; 283 if (time == 0.0) 284 time = 1.0; 285 wmove(wnd, row, INSET); 286#define CPUSCALE 0.5 287 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 288} 289 290static void 291histogram(double val, int colwidth, double scale) 292{ 293 char buf[10]; 294 int k; 295 int v = (int)(val * scale) + 0.5; 296 297 k = MIN(v, colwidth); 298 if (v > colwidth) { 299 snprintf(buf, sizeof buf, "%4.1f", val); 300 k -= strlen(buf); 301 while (k--) 302 waddch(wnd, 'X'); 303 waddstr(wnd, buf); 304 wclrtoeol(wnd); 305 return; 306 } 307 while (k--) 308 waddch(wnd, 'X'); 309 wclrtoeol(wnd); 310} 311 312int 313cmdiostat(char *cmd, char *args) 314{ 315 316 if (prefix(cmd, "secs")) 317 secs = !secs; 318 else if (prefix(cmd, "numbers")) 319 numbers = 1; 320 else if (prefix(cmd, "bars")) 321 numbers = 0; 322 else if (!dkcmd(cmd, args)) 323 return (0); 324 wclear(wnd); 325 labeliostat(); 326 refresh(); 327 return (1); 328} 329