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