1 /* $NetBSD: iostat.c,v 1.19 2002/01/28 13:20:43 augustss 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.19 2002/01/28 13:20:43 augustss 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 57 static int barlabels(int); 58 static void histogram(double, int, double); 59 static int numlabels(int); 60 static int stats(int, int, int); 61 static void stat1(int, int); 62 63 64 WINDOW * 65 openiostat(void) 66 { 67 68 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 69 } 70 71 void 72 closeiostat(WINDOW *w) 73 { 74 75 if (w == NULL) 76 return; 77 wclear(w); 78 wrefresh(w); 79 delwin(w); 80 } 81 82 int 83 initiostat(void) 84 { 85 86 dkinit(1); 87 dkreadstats(); 88 return(1); 89 } 90 91 void 92 fetchiostat(void) 93 { 94 95 if (dk_ndrive == 0) 96 return; 97 dkreadstats(); 98 } 99 100 #define INSET 14 101 102 void 103 labeliostat(void) 104 { 105 int row; 106 107 if (dk_ndrive == 0) { 108 error("No drives defined."); 109 return; 110 } 111 row = 0; 112 wmove(wnd, row, 0); wclrtobot(wnd); 113 mvwaddstr(wnd, row++, INSET, 114 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 115 mvwaddstr(wnd, row++, 0, " cpu user|"); 116 mvwaddstr(wnd, row++, 0, " nice|"); 117 mvwaddstr(wnd, row++, 0, " system|"); 118 mvwaddstr(wnd, row++, 0, " interrupt|"); 119 mvwaddstr(wnd, row++, 0, " idle|"); 120 if (numbers) 121 row = numlabels(row + 1); 122 else 123 row = barlabels(row + 1); 124 } 125 126 static int 127 numlabels(int row) 128 { 129 int i, col, regions, ndrives; 130 131 #define COLWIDTH 14 132 #define DRIVESPERLINE ((getmaxx(wnd) - INSET) / COLWIDTH) 133 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 134 if (cur.dk_select[i]) 135 ndrives++; 136 regions = howmany(ndrives, DRIVESPERLINE); 137 /* 138 * Deduct -regions for blank line after each scrolling region. 139 */ 140 linesperregion = (getmaxy(wnd) - row - regions) / 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 < dk_ndrive; i++) 149 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 150 if (col + COLWIDTH >= getmaxx(wnd) - INSET) { 151 col = 0, row += linesperregion + 1; 152 if (row > getmaxy(wnd) - (linesperregion + 1)) 153 break; 154 } 155 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]); 156 mvwaddstr(wnd, row + 1, col, "KBps tps sec"); 157 col += COLWIDTH; 158 } 159 if (col) 160 row += linesperregion + 1; 161 return (row); 162 } 163 164 static int 165 barlabels(int row) 166 { 167 int i; 168 169 mvwaddstr(wnd, row++, INSET, 170 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 171 linesperregion = 2 + secs; 172 for (i = 0; i < dk_ndrive; i++) 173 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 174 if (row > getmaxy(wnd) - linesperregion) 175 break; 176 mvwprintw(wnd, row++, 0, "%7.7s KBps|", cur.dk_name[i]); 177 mvwaddstr(wnd, row++, 0, " tps|"); 178 if (secs) 179 mvwaddstr(wnd, row++, 0, " msec|"); 180 } 181 return (row); 182 } 183 184 void 185 showiostat(void) 186 { 187 int i, row, col; 188 189 if (dk_ndrive == 0) 190 return; 191 dkswap(); 192 193 etime = 0; 194 for(i = 0; i < CPUSTATES; i++) { 195 etime += cur.cp_time[i]; 196 } 197 if (etime == 0.0) 198 etime = 1.0; 199 etime /= (float) hz; 200 row = 1; 201 202 /* 203 * Interrupt CPU state not calculated yet. 204 */ 205 for (i = 0; i < CPUSTATES; i++) 206 stat1(row++, i); 207 if (!numbers) { 208 row += 2; 209 for (i = 0; i < dk_ndrive; i++) 210 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 211 if (row > getmaxy(wnd) - linesperregion) 212 break; 213 row = stats(row, INSET, i); 214 } 215 return; 216 } 217 col = 0; 218 wmove(wnd, row + linesperregion, 0); 219 wdeleteln(wnd); 220 wmove(wnd, row + 3, 0); 221 winsertln(wnd); 222 for (i = 0; i < dk_ndrive; i++) 223 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 224 if (col + COLWIDTH >= getmaxx(wnd)) { 225 col = 0, row += linesperregion + 1; 226 if (row > getmaxy(wnd) - (linesperregion + 1)) 227 break; 228 wmove(wnd, row + linesperregion, 0); 229 wdeleteln(wnd); 230 wmove(wnd, row + 3, 0); 231 winsertln(wnd); 232 } 233 (void) stats(row + 3, col, i); 234 col += COLWIDTH; 235 } 236 } 237 238 static int 239 stats(int row, int col, int dn) 240 { 241 double atime, words; 242 243 /* time busy in disk activity */ 244 atime = (double)cur.dk_time[dn].tv_sec + 245 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 246 247 words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */ 248 if (numbers) { 249 mvwprintw(wnd, row, col, " %3.0f%4.0f%5.1f", 250 words / etime, cur.dk_xfer[dn] / etime, atime / etime); 251 return (row); 252 } 253 wmove(wnd, row++, col); 254 histogram(words / etime, 50, 0.5); 255 wmove(wnd, row++, col); 256 histogram(cur.dk_xfer[dn] / etime, 50, 0.5); 257 if (secs) { 258 wmove(wnd, row++, col); 259 atime *= 1000; /* In milliseconds */ 260 histogram(atime / etime, 50, 0.5); 261 } 262 return (row); 263 } 264 265 static void 266 stat1(int row, int o) 267 { 268 int i; 269 double time; 270 271 time = 0; 272 for (i = 0; i < CPUSTATES; i++) 273 time += cur.cp_time[i]; 274 if (time == 0.0) 275 time = 1.0; 276 wmove(wnd, row, INSET); 277 #define CPUSCALE 0.5 278 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 279 } 280 281 static void 282 histogram(double val, int colwidth, double scale) 283 { 284 char buf[10]; 285 int k; 286 int v = (int)(val * scale) + 0.5; 287 288 k = MIN(v, colwidth); 289 if (v > colwidth) { 290 snprintf(buf, sizeof buf, "%4.1f", val); 291 k -= strlen(buf); 292 while (k--) 293 waddch(wnd, 'X'); 294 waddstr(wnd, buf); 295 wclrtoeol(wnd); 296 return; 297 } 298 wclrtoeol(wnd); 299 whline(wnd, 'X', k); 300 } 301 302 void 303 iostat_bars(char *args) 304 { 305 numbers = 0; 306 wclear(wnd); 307 labeliostat(); 308 refresh(); 309 } 310 311 void 312 iostat_numbers(char *args) 313 { 314 numbers = 1; 315 wclear(wnd); 316 labeliostat(); 317 refresh(); 318 } 319 320 void 321 iostat_secs(char *args) 322 { 323 secs = !secs; 324 wclear(wnd); 325 labeliostat(); 326 refresh(); 327 } 328