1 /* $NetBSD: iostat.c,v 1.36 2006/04/14 13:14:06 blymn 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 __RCSID("$NetBSD: iostat.c,v 1.36 2006/04/14 13:14:06 blymn Exp $"); 38 #endif /* not lint */ 39 40 #include <sys/param.h> 41 42 #include <string.h> 43 44 #include "systat.h" 45 #include "extern.h" 46 #include "drvstats.h" 47 48 static int linesperregion; 49 static double etime; 50 static int numbers = 0; /* default display bar graphs */ 51 static int secs = 0; /* default seconds shown */ 52 static int read_write = 0; /* default read/write shown */ 53 54 static int barlabels(int); 55 static void histogram(double, int, double); 56 static int numlabels(int); 57 static int stats(int, int, int); 58 static void stat1(int, int); 59 60 61 WINDOW * 62 openiostat(void) 63 { 64 65 return (subwin(stdscr, -1, 0, 5, 0)); 66 } 67 68 void 69 closeiostat(WINDOW *w) 70 { 71 72 if (w == NULL) 73 return; 74 wclear(w); 75 wrefresh(w); 76 delwin(w); 77 } 78 79 int 80 initiostat(void) 81 { 82 83 drvinit(1); 84 cpureadstats(); 85 drvreadstats(); 86 return(1); 87 } 88 89 void 90 fetchiostat(void) 91 { 92 93 cpureadstats(); 94 95 if (ndrive != 0) 96 drvreadstats(); 97 } 98 99 #define INSET 14 100 101 void 102 labeliostat(void) 103 { 104 int row; 105 106 if (ndrive == 0) { 107 error("No drives defined."); 108 return; 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 125 static int 126 numlabels(int row) 127 { 128 int i, col, regions, ndrives; 129 130 #define COLWIDTH (9 + secs * 5 + 1 + read_write * 9 + 1) 131 #define DRIVESPERLINE ((getmaxx(wnd) + 1) / COLWIDTH) 132 for (ndrives = 0, i = 0; i < ndrive; i++) 133 if (cur.select[i]) 134 ndrives++; 135 136 regions = howmany(ndrives, DRIVESPERLINE); 137 /* 138 * Deduct -regions for blank line after each scrolling region. 139 */ 140 linesperregion = (getmaxy(wnd) - row - regions + 1) / regions; 141 /* 142 * Minimum region contains space for two 143 * label lines and one line of statistics. 144 */ 145 if (linesperregion < 3) 146 linesperregion = 3; 147 col = 0; 148 for (i = 0; i < ndrive; i++) 149 if (cur.select[i]) { 150 if (col + COLWIDTH - 1 > getmaxx(wnd)) { 151 col = 0, row += linesperregion + 1; 152 if (row > getmaxy(wnd) - (linesperregion)) 153 break; 154 } 155 156 mvwprintw(wnd, row, col + 5, "%s", cur.name[i]); 157 158 if (read_write) 159 mvwprintw(wnd, row, col + 11 + secs * 5, 160 "(write)"); 161 mvwprintw(wnd, row + 1, col, " kBps %s", 162 read_write ? "r/s" : "tps"); 163 if (secs) 164 waddstr(wnd, " sec"); 165 if (read_write) 166 waddstr(wnd, " kBps w/s"); 167 col += COLWIDTH; 168 } 169 if (col) 170 row += linesperregion + 1; 171 return (row); 172 } 173 174 static int 175 barlabels(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 + (read_write ? 2 : 0); 182 for (i = 0; i < ndrive; i++) { 183 if (cur.select[i]) { 184 if (row > getmaxy(wnd) - linesperregion) 185 break; 186 mvwprintw(wnd, row++, 0, "%7.7s kBps|", 187 cur.name[i]); 188 mvwaddstr(wnd, row++, 0, " tps|"); 189 if (read_write) { 190 mvwprintw(wnd, row++, 0, " (write) kBps|"); 191 mvwaddstr(wnd, row++, 0, " tps|"); 192 } 193 if (secs) 194 mvwaddstr(wnd, row++, 0, " msec|"); 195 } 196 } 197 198 return (row); 199 } 200 201 void 202 showiostat(void) 203 { 204 int i, row, col; 205 206 if (ndrive == 0) 207 return; 208 cpuswap(); 209 drvswap(); 210 211 etime = cur.cp_etime; 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 < ndrive; i++) 222 if (cur.select[i]) { 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 < ndrive; i++) 235 if (cur.select[i]) { 236 if (col + COLWIDTH - 1 > 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(int row, int col, int dn) 252 { 253 double atime, rwords, wwords; 254 uint64_t rxfer; 255 256 /* time busy in disk activity */ 257 atime = (double)cur.time[dn].tv_sec + 258 ((double)cur.time[dn].tv_usec / (double)1000000); 259 260 /* # of k transferred */ 261 rwords = cur.rbytes[dn] / 1024.0; 262 wwords = cur.wbytes[dn] / 1024.0; 263 rxfer = cur.rxfer[dn]; 264 if (!read_write) { 265 rwords += wwords; 266 rxfer += cur.wxfer[dn]; 267 } 268 if (numbers) { 269 mvwprintw(wnd, row, col, "%5.0f%4.0f", 270 rwords / etime, rxfer / etime); 271 if (secs) 272 wprintw(wnd, "%5.1f", atime / etime); 273 if (read_write) 274 wprintw(wnd, " %5.0f%4.0f", 275 wwords / etime, cur.wxfer[dn] / etime); 276 return (row); 277 } 278 279 wmove(wnd, row++, col); 280 histogram(rwords / etime, 50, 0.5); 281 wmove(wnd, row++, col); 282 histogram(rxfer / etime, 50, 0.5); 283 if (read_write) { 284 wmove(wnd, row++, col); 285 histogram(wwords / etime, 50, 0.5); 286 wmove(wnd, row++, col); 287 histogram(cur.wxfer[dn] / etime, 50, 0.5); 288 } 289 290 if (secs) { 291 wmove(wnd, row++, col); 292 atime *= 1000; /* In milliseconds */ 293 histogram(atime / etime, 50, 0.5); 294 } 295 return (row); 296 } 297 298 static void 299 stat1(int row, int o) 300 { 301 int i; 302 double total_time; 303 304 total_time = 0; 305 for (i = 0; i < CPUSTATES; i++) 306 total_time += cur.cp_time[i]; 307 if (total_time == 0.0) 308 total_time = 1.0; 309 wmove(wnd, row, INSET); 310 #define CPUSCALE 0.5 311 histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE); 312 } 313 314 static void 315 histogram(double val, int colwidth, double scale) 316 { 317 int v = (int)(val * scale + 0.5); 318 int factor = 1; 319 int y, x; 320 321 while (v > colwidth) { 322 v = (v + 5) / 10; 323 factor *= 10; 324 } 325 getyx(wnd, y, x); 326 wclrtoeol(wnd); 327 whline(wnd, 'X', v); 328 if (factor != 1) 329 mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor); 330 } 331 332 void 333 iostat_bars(char *args) 334 { 335 numbers = 0; 336 wclear(wnd); 337 labeliostat(); 338 refresh(); 339 } 340 341 void 342 iostat_numbers(char *args) 343 { 344 numbers = 1; 345 wclear(wnd); 346 labeliostat(); 347 refresh(); 348 } 349 350 void 351 iostat_secs(char *args) 352 { 353 secs = !secs; 354 wclear(wnd); 355 labeliostat(); 356 refresh(); 357 } 358 359 void 360 iostat_rw(char *args) 361 { 362 read_write ^= 1; 363 wclear(wnd); 364 labeliostat(); 365 refresh(); 366 } 367 368 void 369 iostat_all(char *args) 370 { 371 read_write = 0; 372 wclear(wnd); 373 labeliostat(); 374 refresh(); 375 } 376