iostat.c revision 1.17
1/* $OpenBSD: iostat.c,v 1.17 2002/02/16 21:27:54 millert 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.17 2002/02/16 21:27:54 millert 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() 72{ 73 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 74} 75 76void 77closeiostat(w) 78 WINDOW *w; 79{ 80 if (w == NULL) 81 return; 82 wclear(w); 83 wrefresh(w); 84 delwin(w); 85} 86 87int 88initiostat() 89{ 90 dkinit(1); 91 dkreadstats(); 92 return (1); 93} 94 95void 96fetchiostat() 97{ 98 if (dk_ndrive == 0) 99 return; 100 dkreadstats(); 101} 102 103#define INSET 10 104 105void 106labeliostat() 107{ 108 int row; 109 110 row = 0; 111 wmove(wnd, row, 0); wclrtobot(wnd); 112 mvwaddstr(wnd, row++, INSET, 113 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 114 mvwaddstr(wnd, row++, 0, "cpu user|"); 115 mvwaddstr(wnd, row++, 0, " nice|"); 116 mvwaddstr(wnd, row++, 0, " system|"); 117 mvwaddstr(wnd, row++, 0, "interrupt|"); 118 mvwaddstr(wnd, row++, 0, " idle|"); 119 if (numbers) 120 row = numlabels(row + 1); 121 else 122 row = barlabels(row + 1); 123} 124 125static int 126numlabels(row) 127 int row; 128{ 129 int i, col, regions, ndrives; 130 131 if (dk_ndrive == 0) { 132 mvwaddstr(wnd, row++, INSET, "No drives attached."); 133 return (row); 134 } 135#define COLWIDTH 17 136#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 137 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 138 if (cur.dk_select[i]) 139 ndrives++; 140 regions = howmany(ndrives, DRIVESPERLINE); 141 /* 142 * Deduct -regions for blank line after each scrolling region. 143 */ 144 linesperregion = (wnd->_maxy - row - regions) / regions; 145 /* 146 * Minimum region contains space for two 147 * label lines and one line of statistics. 148 */ 149 if (linesperregion < 3) 150 linesperregion = 3; 151 col = INSET; 152 for (i = 0; i < dk_ndrive; i++) 153 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 154 if (col + COLWIDTH >= wnd->_maxx) { 155 col = INSET, row += linesperregion + 1; 156 if (row > wnd->_maxy - (linesperregion + 1)) 157 break; 158 } 159 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]); 160 mvwaddstr(wnd, row + 1, col, " KBps tps sec"); 161 col += COLWIDTH; 162 } 163 if (col) 164 row += linesperregion + 1; 165 return (row); 166} 167 168static int 169barlabels(row) 170 int row; 171{ 172 int i; 173 174 if (dk_ndrive == 0) { 175 mvwaddstr(wnd, row++, INSET, "No drives attached."); 176 return (row); 177 } 178 mvwaddstr(wnd, row++, INSET, 179 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 180 linesperregion = 2 + secs; 181 for (i = 0; i < dk_ndrive; i++) 182 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 183 if (row > wnd->_maxy - linesperregion) 184 break; 185 mvwprintw(wnd, row++, 0, "%4.4s Kps|", cur.dk_name[i]); 186 mvwaddstr(wnd, row++, 0, " tps|"); 187 if (secs) 188 mvwaddstr(wnd, row++, 0, " msec|"); 189 } 190 return (row); 191} 192 193 194void 195showiostat() 196{ 197 int i, row, col; 198 199 dkswap(); 200 201 etime = 0; 202 for(i = 0; i < CPUSTATES; i++) { 203 etime += cur.cp_time[i]; 204 } 205 if (etime == 0.0) 206 etime = 1.0; 207 etime /= (float) hz; 208 row = 1; 209 210 /* 211 * Interrupt CPU state not calculated yet. 212 */ 213 for (i = 0; i < CPUSTATES; i++) 214 stat1(row++, i); 215 216 if (dk_ndrive == 0) 217 return; 218 219 if (!numbers) { 220 row += 2; 221 for (i = 0; i < dk_ndrive; i++) 222 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 223 if (row > wnd->_maxy - linesperregion) 224 break; 225 row = stats(row, INSET, i); 226 } 227 return; 228 } 229 col = INSET; 230 wmove(wnd, row + linesperregion, 0); 231 wdeleteln(wnd); 232 wmove(wnd, row + 3, 0); 233 winsertln(wnd); 234 for (i = 0; i < dk_ndrive; i++) 235 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 236 if (col + COLWIDTH >= wnd->_maxx) { 237 col = INSET, row += linesperregion + 1; 238 if (row > wnd->_maxy - (linesperregion + 1)) 239 break; 240 wmove(wnd, row + linesperregion, 0); 241 wdeleteln(wnd); 242 wmove(wnd, row + 3, 0); 243 winsertln(wnd); 244 } 245 (void) stats(row + 3, col, i); 246 col += COLWIDTH; 247 } 248} 249 250static int 251stats(row, col, dn) 252 int row, col, dn; 253{ 254 double atime, words; 255 256 /* time busy in disk activity */ 257 atime = (double)cur.dk_time[dn].tv_sec + 258 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 259 260 words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */ 261 if (numbers) { 262 mvwprintw(wnd, row, col, "%5.0f%4.0f%5.1f", 263 words / etime, cur.dk_xfer[dn] / etime, atime / etime); 264 return (row); 265 } 266 wmove(wnd, row++, col); 267 histogram(words / etime, 50, 0.5); 268 wmove(wnd, row++, col); 269 histogram(cur.dk_xfer[dn] / etime, 50, 0.5); 270 if (secs) { 271 wmove(wnd, row++, col); 272 atime *= 1000; /* In milliseconds */ 273 histogram(atime / etime, 50, 0.5); 274 } 275 return (row); 276} 277 278static void 279stat1(row, o) 280 int row, o; 281{ 282 int i; 283 double time; 284 285 time = 0; 286 for (i = 0; i < CPUSTATES; i++) 287 time += cur.cp_time[i]; 288 if (time == 0.0) 289 time = 1.0; 290 wmove(wnd, row, INSET); 291#define CPUSCALE 0.5 292 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 293} 294 295static void 296histogram(val, colwidth, scale) 297 double val; 298 int colwidth; 299 double scale; 300{ 301 char buf[10]; 302 int k; 303 int v = (int)(val * scale) + 0.5; 304 305 k = MIN(v, colwidth); 306 if (v > colwidth) { 307 snprintf(buf, sizeof buf, "%4.1f", val); 308 k -= strlen(buf); 309 while (k--) 310 waddch(wnd, 'X'); 311 waddstr(wnd, buf); 312 wclrtoeol(wnd); 313 return; 314 } 315 while (k--) 316 waddch(wnd, 'X'); 317 wclrtoeol(wnd); 318} 319 320int 321cmdiostat(cmd, args) 322 char *cmd, *args; 323{ 324 325 if (prefix(cmd, "secs")) 326 secs = !secs; 327 else if (prefix(cmd, "numbers")) 328 numbers = 1; 329 else if (prefix(cmd, "bars")) 330 numbers = 0; 331 else if (!dkcmd(cmd, args)) 332 return (0); 333 wclear(wnd); 334 labeliostat(); 335 refresh(); 336 return (1); 337} 338