1 /* $NetBSD: iostat.c,v 1.13 1999/12/20 03:45:02 jwise 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.13 1999/12/20 03:45:02 jwise 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 extern gid_t egid; 94 95 dkinit(1, egid); 96 dkreadstats(); 97 return(1); 98 } 99 100 void 101 fetchiostat() 102 { 103 104 if (dk_ndrive == 0) 105 return; 106 dkreadstats(); 107 } 108 109 #define INSET 14 110 111 void 112 labeliostat() 113 { 114 int row; 115 116 if (dk_ndrive == 0) { 117 error("No drives defined."); 118 return; 119 } 120 row = 0; 121 wmove(wnd, row, 0); wclrtobot(wnd); 122 mvwaddstr(wnd, row++, INSET, 123 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 124 mvwaddstr(wnd, row++, 0, " cpu user|"); 125 mvwaddstr(wnd, row++, 0, " nice|"); 126 mvwaddstr(wnd, row++, 0, " system|"); 127 mvwaddstr(wnd, row++, 0, " interrupt|"); 128 mvwaddstr(wnd, row++, 0, " idle|"); 129 if (numbers) 130 row = numlabels(row + 1); 131 else 132 row = barlabels(row + 1); 133 } 134 135 static int 136 numlabels(row) 137 int row; 138 { 139 int i, col, regions, ndrives; 140 141 #define COLWIDTH 14 142 #define DRIVESPERLINE ((getmaxx(wnd) - INSET) / COLWIDTH) 143 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 144 if (cur.dk_select[i]) 145 ndrives++; 146 regions = howmany(ndrives, DRIVESPERLINE); 147 /* 148 * Deduct -regions for blank line after each scrolling region. 149 */ 150 linesperregion = (getmaxy(wnd) - row - regions) / regions; 151 /* 152 * Minimum region contains space for two 153 * label lines and one line of statistics. 154 */ 155 if (linesperregion < 3) 156 linesperregion = 3; 157 col = 0; 158 for (i = 0; i < dk_ndrive; i++) 159 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 160 if (col + COLWIDTH >= getmaxx(wnd) - INSET) { 161 col = 0, row += linesperregion + 1; 162 if (row > getmaxy(wnd) - (linesperregion + 1)) 163 break; 164 } 165 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]); 166 mvwaddstr(wnd, row + 1, col, "KBps tps sec"); 167 col += COLWIDTH; 168 } 169 if (col) 170 row += linesperregion + 1; 171 return (row); 172 } 173 174 static int 175 barlabels(row) 176 int row; 177 { 178 int i; 179 180 mvwaddstr(wnd, row++, INSET, 181 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 182 linesperregion = 2 + secs; 183 for (i = 0; i < dk_ndrive; i++) 184 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 185 if (row > getmaxy(wnd) - linesperregion) 186 break; 187 mvwprintw(wnd, row++, 0, "%7.7s KBps|", cur.dk_name[i]); 188 mvwaddstr(wnd, row++, 0, " tps|"); 189 if (secs) 190 mvwaddstr(wnd, row++, 0, " msec|"); 191 } 192 return (row); 193 } 194 195 196 void 197 showiostat() 198 { 199 int i, row, col; 200 201 if (dk_ndrive == 0) 202 return; 203 dkswap(); 204 205 etime = 0; 206 for(i = 0; i < CPUSTATES; i++) { 207 etime += cur.cp_time[i]; 208 } 209 if (etime == 0.0) 210 etime = 1.0; 211 etime /= (float) hz; 212 row = 1; 213 214 /* 215 * Interrupt CPU state not calculated yet. 216 */ 217 for (i = 0; i < CPUSTATES; i++) 218 stat1(row++, i); 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 > getmaxy(wnd) - linesperregion) 224 break; 225 row = stats(row, INSET, i); 226 } 227 return; 228 } 229 col = 0; 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 >= getmaxx(wnd)) { 237 col = 0, row += linesperregion + 1; 238 if (row > getmaxy(wnd) - (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 250 static int 251 stats(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, " %3.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 278 static void 279 stat1(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 295 static void 296 histogram(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 320 void 321 iostat_bars (args) 322 char *args; 323 { 324 numbers = 0; 325 wclear(wnd); 326 labeliostat(); 327 refresh(); 328 } 329 330 void 331 iostat_numbers (args) 332 char *args; 333 { 334 numbers = 1; 335 wclear(wnd); 336 labeliostat(); 337 refresh(); 338 } 339 340 void 341 iostat_secs (args) 342 char *args; 343 { 344 secs = !secs; 345 wclear(wnd); 346 labeliostat(); 347 refresh(); 348 } 349