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