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