1 /* $NetBSD: iostat.c,v 1.24 2002/12/06 03:13:14 thorpej 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.24 2002/12/06 03:13:14 thorpej Exp $"); 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 46 #include <string.h> 47 48 #include "systat.h" 49 #include "extern.h" 50 #include "dkstats.h" 51 52 static int linesperregion; 53 static double etime; 54 static int numbers = 0; /* default display bar graphs */ 55 static int secs = 0; /* default seconds shown */ 56 static int read_write = 0; /* default read/write shown */ 57 58 static int barlabels(int); 59 static void histogram(double, int, double); 60 static int numlabels(int); 61 static int stats(int, int, int); 62 static void stat1(int, int); 63 64 65 WINDOW * 66 openiostat(void) 67 { 68 69 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 70 } 71 72 void 73 closeiostat(WINDOW *w) 74 { 75 76 if (w == NULL) 77 return; 78 wclear(w); 79 wrefresh(w); 80 delwin(w); 81 } 82 83 int 84 initiostat(void) 85 { 86 87 dkinit(1); 88 dkreadstats(); 89 return(1); 90 } 91 92 void 93 fetchiostat(void) 94 { 95 96 if (dk_ndrive == 0) 97 return; 98 dkreadstats(); 99 } 100 101 #define INSET 14 102 103 void 104 labeliostat(void) 105 { 106 int row; 107 108 if (dk_ndrive == 0) { 109 error("No drives defined."); 110 return; 111 } 112 row = 0; 113 wmove(wnd, row, 0); wclrtobot(wnd); 114 mvwaddstr(wnd, row++, INSET, 115 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 116 mvwaddstr(wnd, row++, 0, " cpu user|"); 117 mvwaddstr(wnd, row++, 0, " nice|"); 118 mvwaddstr(wnd, row++, 0, " system|"); 119 mvwaddstr(wnd, row++, 0, " interrupt|"); 120 mvwaddstr(wnd, row++, 0, " idle|"); 121 if (numbers) 122 row = numlabels(row + 1); 123 else 124 row = barlabels(row + 1); 125 } 126 127 static int 128 numlabels(int row) 129 { 130 int i, col, regions, ndrives; 131 132 #define COLWIDTH (read_write ? 24 : 14) 133 #define DRIVESPERLINE ((getmaxx(wnd) - 1) / COLWIDTH) 134 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 135 if (cur.dk_select[i]) 136 ndrives++; 137 regions = howmany(ndrives, DRIVESPERLINE); 138 /* 139 * Deduct -regions for blank line after each scrolling region. 140 */ 141 linesperregion = (getmaxy(wnd) - row - regions) / regions; 142 /* 143 * Minimum region contains space for two 144 * label lines and one line of statistics. 145 */ 146 if (linesperregion < 3) 147 linesperregion = 3; 148 col = 0; 149 for (i = 0; i < dk_ndrive; i++) 150 if (cur.dk_select[i]) { 151 if (col + COLWIDTH > getmaxx(wnd)) { 152 col = 0, row += linesperregion + 1; 153 if (row > getmaxy(wnd) - (linesperregion + 1)) 154 break; 155 } 156 mvwprintw(wnd, row, col + 4, "%s%s", 157 cur.dk_name[i], read_write ? " (write)" : ""); 158 if (read_write) 159 mvwaddstr(wnd, row + 1, col, 160 "kBps r/s sec kBps w/s"); 161 else 162 mvwaddstr(wnd, row + 1, col, "kBps tps sec"); 163 col += COLWIDTH; 164 } 165 if (col) 166 row += linesperregion + 1; 167 return (row); 168 } 169 170 static int 171 barlabels(int row) 172 { 173 int i; 174 175 mvwaddstr(wnd, row++, INSET, 176 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 177 linesperregion = 2 + secs + (read_write ? 2 : 0); 178 for (i = 0; i < dk_ndrive; i++) 179 if (cur.dk_select[i]) { 180 if (row > getmaxy(wnd) - linesperregion) 181 break; 182 mvwprintw(wnd, row++, 0, "%7.7s kBps|", 183 cur.dk_name[i]); 184 mvwaddstr(wnd, row++, 0, " tps|"); 185 if (read_write) { 186 mvwprintw(wnd, row++, 0, " (write) kBps|"); 187 mvwaddstr(wnd, row++, 0, " tps|"); 188 } 189 if (secs) 190 mvwaddstr(wnd, row++, 0, " msec|"); 191 } 192 return (row); 193 } 194 195 void 196 showiostat(void) 197 { 198 int i, row, col; 199 200 if (dk_ndrive == 0) 201 return; 202 dkswap(); 203 204 etime = cur.cp_etime; 205 row = 1; 206 207 /* 208 * Interrupt CPU state not calculated yet. 209 */ 210 for (i = 0; i < CPUSTATES; i++) 211 stat1(row++, i); 212 if (!numbers) { 213 row += 2; 214 for (i = 0; i < dk_ndrive; i++) 215 if (cur.dk_select[i]) { 216 if (row > getmaxy(wnd) - linesperregion) 217 break; 218 row = stats(row, INSET, i); 219 } 220 return; 221 } 222 col = 0; 223 wmove(wnd, row + linesperregion, 0); 224 wdeleteln(wnd); 225 wmove(wnd, row + 3, 0); 226 winsertln(wnd); 227 for (i = 0; i < dk_ndrive; i++) 228 if (cur.dk_select[i]) { 229 if (col + COLWIDTH > getmaxx(wnd)) { 230 col = 0, row += linesperregion + 1; 231 if (row > getmaxy(wnd) - (linesperregion + 1)) 232 break; 233 wmove(wnd, row + linesperregion, 0); 234 wdeleteln(wnd); 235 wmove(wnd, row + 3, 0); 236 winsertln(wnd); 237 } 238 (void) stats(row + 3, col, i); 239 col += COLWIDTH; 240 } 241 } 242 243 static int 244 stats(int row, int col, int dn) 245 { 246 double atime, rwords, wwords; 247 248 /* time busy in disk activity */ 249 atime = (double)cur.dk_time[dn].tv_sec + 250 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 251 252 /* # of k transferred */ 253 rwords = cur.dk_rbytes[dn] / 1024.0; 254 wwords = cur.dk_wbytes[dn] / 1024.0; 255 if (numbers) { 256 if (read_write) 257 mvwprintw(wnd, row, col, " %3.0f%4.0f%5.1f %3.0f%4.0f", 258 rwords / etime, cur.dk_rxfer[dn] / etime, 259 atime / etime, 260 wwords / etime, cur.dk_wxfer[dn] / etime); 261 else 262 mvwprintw(wnd, row, col, " %3.0f%4.0f%5.1f", 263 (rwords + wwords) / etime, 264 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime, 265 atime / etime); 266 return (row); 267 } 268 269 if (read_write) { 270 wmove(wnd, row++, col); 271 histogram(rwords / etime, 50, 0.5); 272 wmove(wnd, row++, col); 273 histogram(cur.dk_rxfer[dn] / etime, 50, 0.5); 274 wmove(wnd, row++, col); 275 histogram(wwords / etime, 50, 0.5); 276 wmove(wnd, row++, col); 277 histogram(cur.dk_wxfer[dn] / etime, 50, 0.5); 278 } else { 279 wmove(wnd, row++, col); 280 histogram((rwords + wwords) / etime, 50, 0.5); 281 wmove(wnd, row++, col); 282 histogram((cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime, 50, 0.5); 283 } 284 285 if (secs) { 286 wmove(wnd, row++, col); 287 atime *= 1000; /* In milliseconds */ 288 histogram(atime / etime, 50, 0.5); 289 } 290 return (row); 291 } 292 293 static void 294 stat1(int row, int o) 295 { 296 int i; 297 double time; 298 299 time = 0; 300 for (i = 0; i < CPUSTATES; i++) 301 time += cur.cp_time[i]; 302 if (time == 0.0) 303 time = 1.0; 304 wmove(wnd, row, INSET); 305 #define CPUSCALE 0.5 306 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 307 } 308 309 static void 310 histogram(double val, int colwidth, double scale) 311 { 312 char buf[10]; 313 int k; 314 int v = (int)(val * scale) + 0.5; 315 316 k = MIN(v, colwidth); 317 if (v > colwidth) { 318 snprintf(buf, sizeof buf, "%4.1f", val); 319 k -= strlen(buf); 320 while (k--) 321 waddch(wnd, 'X'); 322 waddstr(wnd, buf); 323 wclrtoeol(wnd); 324 return; 325 } 326 wclrtoeol(wnd); 327 whline(wnd, 'X', k); 328 } 329 330 void 331 iostat_bars(char *args) 332 { 333 numbers = 0; 334 wclear(wnd); 335 labeliostat(); 336 refresh(); 337 } 338 339 void 340 iostat_numbers(char *args) 341 { 342 numbers = 1; 343 wclear(wnd); 344 labeliostat(); 345 refresh(); 346 } 347 348 void 349 iostat_secs(char *args) 350 { 351 secs = !secs; 352 wclear(wnd); 353 labeliostat(); 354 refresh(); 355 } 356 357 void 358 iostat_rw(char *args) 359 { 360 read_write = 1; 361 wclear(wnd); 362 labeliostat(); 363 refresh(); 364 } 365 366 void 367 iostat_all(char *args) 368 { 369 read_write = 0; 370 wclear(wnd); 371 labeliostat(); 372 refresh(); 373 } 374