1 /* $NetBSD: iostat.c,v 1.37 2009/04/13 23:20:27 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. 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.37 2009/04/13 23:20:27 lukem 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 col, regions; 129 size_t i, ndrives; 130 131 #define COLWIDTH (9 + secs * 5 + 1 + read_write * 9 + 1) 132 #define DRIVESPERLINE ((getmaxx(wnd) + 1) / COLWIDTH) 133 for (ndrives = 0, i = 0; i < ndrive; i++) 134 if (cur.select[i]) 135 ndrives++; 136 137 regions = howmany(ndrives, DRIVESPERLINE); 138 /* 139 * Deduct -regions for blank line after each scrolling region. 140 */ 141 linesperregion = (getmaxy(wnd) - row - regions + 1) / 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 < ndrive; i++) 150 if (cur.select[i]) { 151 if (col + COLWIDTH - 1 > getmaxx(wnd)) { 152 col = 0, row += linesperregion + 1; 153 if (row > getmaxy(wnd) - (linesperregion)) 154 break; 155 } 156 157 mvwprintw(wnd, row, col + 5, "%s", cur.name[i]); 158 159 if (read_write) 160 mvwprintw(wnd, row, col + 11 + secs * 5, 161 "(write)"); 162 mvwprintw(wnd, row + 1, col, " kBps %s", 163 read_write ? "r/s" : "tps"); 164 if (secs) 165 waddstr(wnd, " sec"); 166 if (read_write) 167 waddstr(wnd, " kBps w/s"); 168 col += COLWIDTH; 169 } 170 if (col) 171 row += linesperregion + 1; 172 return (row); 173 } 174 175 static int 176 barlabels(int row) 177 { 178 size_t i; 179 180 mvwaddstr(wnd, row++, INSET, 181 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 182 linesperregion = 2 + secs + (read_write ? 2 : 0); 183 for (i = 0; i < ndrive; i++) { 184 if (cur.select[i]) { 185 if (row > getmaxy(wnd) - linesperregion) 186 break; 187 mvwprintw(wnd, row++, 0, "%7.7s kBps|", 188 cur.name[i]); 189 mvwaddstr(wnd, row++, 0, " tps|"); 190 if (read_write) { 191 mvwprintw(wnd, row++, 0, " (write) kBps|"); 192 mvwaddstr(wnd, row++, 0, " tps|"); 193 } 194 if (secs) 195 mvwaddstr(wnd, row++, 0, " msec|"); 196 } 197 } 198 199 return (row); 200 } 201 202 void 203 showiostat(void) 204 { 205 int row, col; 206 size_t i; 207 208 if (ndrive == 0) 209 return; 210 cpuswap(); 211 drvswap(); 212 213 etime = cur.cp_etime; 214 row = 1; 215 216 /* 217 * Interrupt CPU state not calculated yet. 218 */ 219 for (i = 0; i < CPUSTATES; i++) 220 stat1(row++, i); 221 if (!numbers) { 222 row += 2; 223 for (i = 0; i < ndrive; i++) 224 if (cur.select[i]) { 225 if (row > getmaxy(wnd) - linesperregion) 226 break; 227 row = stats(row, INSET, i); 228 } 229 return; 230 } 231 col = 0; 232 wmove(wnd, row + linesperregion, 0); 233 wdeleteln(wnd); 234 wmove(wnd, row + 3, 0); 235 winsertln(wnd); 236 for (i = 0; i < ndrive; i++) 237 if (cur.select[i]) { 238 if (col + COLWIDTH - 1 > getmaxx(wnd)) { 239 col = 0, row += linesperregion + 1; 240 if (row > getmaxy(wnd) - (linesperregion + 1)) 241 break; 242 wmove(wnd, row + linesperregion, 0); 243 wdeleteln(wnd); 244 wmove(wnd, row + 3, 0); 245 winsertln(wnd); 246 } 247 (void) stats(row + 3, col, i); 248 col += COLWIDTH; 249 } 250 } 251 252 static int 253 stats(int row, int col, int dn) 254 { 255 double atime, rwords, wwords; 256 uint64_t rxfer; 257 258 /* time busy in disk activity */ 259 atime = (double)cur.time[dn].tv_sec + 260 ((double)cur.time[dn].tv_usec / (double)1000000); 261 262 /* # of k transferred */ 263 rwords = cur.rbytes[dn] / 1024.0; 264 wwords = cur.wbytes[dn] / 1024.0; 265 rxfer = cur.rxfer[dn]; 266 if (!read_write) { 267 rwords += wwords; 268 rxfer += cur.wxfer[dn]; 269 } 270 if (numbers) { 271 mvwprintw(wnd, row, col, "%5.0f%4.0f", 272 rwords / etime, rxfer / etime); 273 if (secs) 274 wprintw(wnd, "%5.1f", atime / etime); 275 if (read_write) 276 wprintw(wnd, " %5.0f%4.0f", 277 wwords / etime, cur.wxfer[dn] / etime); 278 return (row); 279 } 280 281 wmove(wnd, row++, col); 282 histogram(rwords / etime, 50, 0.5); 283 wmove(wnd, row++, col); 284 histogram(rxfer / etime, 50, 0.5); 285 if (read_write) { 286 wmove(wnd, row++, col); 287 histogram(wwords / etime, 50, 0.5); 288 wmove(wnd, row++, col); 289 histogram(cur.wxfer[dn] / etime, 50, 0.5); 290 } 291 292 if (secs) { 293 wmove(wnd, row++, col); 294 atime *= 1000; /* In milliseconds */ 295 histogram(atime / etime, 50, 0.5); 296 } 297 return (row); 298 } 299 300 static void 301 stat1(int row, int o) 302 { 303 size_t i; 304 double total_time; 305 306 total_time = 0; 307 for (i = 0; i < CPUSTATES; i++) 308 total_time += cur.cp_time[i]; 309 if (total_time == 0.0) 310 total_time = 1.0; 311 wmove(wnd, row, INSET); 312 #define CPUSCALE 0.5 313 histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE); 314 } 315 316 static void 317 histogram(double val, int colwidth, double scale) 318 { 319 int v = (int)(val * scale + 0.5); 320 int factor = 1; 321 int y, x; 322 323 while (v > colwidth) { 324 v = (v + 5) / 10; 325 factor *= 10; 326 } 327 getyx(wnd, y, x); 328 wclrtoeol(wnd); 329 whline(wnd, 'X', v); 330 if (factor != 1) 331 mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor); 332 } 333 334 void 335 iostat_bars(char *args) 336 { 337 numbers = 0; 338 wclear(wnd); 339 labeliostat(); 340 refresh(); 341 } 342 343 void 344 iostat_numbers(char *args) 345 { 346 numbers = 1; 347 wclear(wnd); 348 labeliostat(); 349 refresh(); 350 } 351 352 void 353 iostat_secs(char *args) 354 { 355 secs = !secs; 356 wclear(wnd); 357 labeliostat(); 358 refresh(); 359 } 360 361 void 362 iostat_rw(char *args) 363 { 364 read_write ^= 1; 365 wclear(wnd); 366 labeliostat(); 367 refresh(); 368 } 369 370 void 371 iostat_all(char *args) 372 { 373 read_write = 0; 374 wclear(wnd); 375 labeliostat(); 376 refresh(); 377 } 378