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