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