1 /* $OpenBSD: iostat.c,v 1.21 2003/06/03 02:56:17 millert Exp $ */ 2 /* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 static char rcsid[] = "$OpenBSD: iostat.c,v 1.21 2003/06/03 02:56:17 millert Exp $"; 38 #endif /* not lint */ 39 40 #include <sys/param.h> 41 #include <sys/dkstat.h> 42 #include <sys/buf.h> 43 #include <sys/time.h> 44 45 #include <string.h> 46 #include <stdlib.h> 47 #include <paths.h> 48 #include "systat.h" 49 #include "extern.h" 50 51 #include "dkstats.h" 52 extern struct _disk cur, last; 53 54 static int linesperregion; 55 static double etime; 56 static int numbers = 0; /* default display bar graphs */ 57 static int secs = 0; /* default seconds shown */ 58 59 static int barlabels(int); 60 static void histogram(double, int, double); 61 static int numlabels(int); 62 static int stats(int, int, int); 63 static void stat1(int, int); 64 65 66 WINDOW * 67 openiostat(void) 68 { 69 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 70 } 71 72 void 73 closeiostat(WINDOW *w) 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 dkinit(1); 86 dkreadstats(); 87 return (1); 88 } 89 90 void 91 fetchiostat(void) 92 { 93 if (cur.dk_ndrive == 0) 94 return; 95 dkreadstats(); 96 } 97 98 #define INSET 10 99 100 void 101 labeliostat(void) 102 { 103 int row; 104 105 row = 0; 106 wmove(wnd, row, 0); wclrtobot(wnd); 107 mvwaddstr(wnd, row++, INSET, 108 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 109 mvwaddstr(wnd, row++, 0, "cpu user|"); 110 mvwaddstr(wnd, row++, 0, " nice|"); 111 mvwaddstr(wnd, row++, 0, " system|"); 112 mvwaddstr(wnd, row++, 0, "interrupt|"); 113 mvwaddstr(wnd, row++, 0, " idle|"); 114 if (numbers) 115 row = numlabels(row + 1); 116 else 117 row = barlabels(row + 1); 118 } 119 120 static int 121 numlabels(int row) 122 { 123 int i, col, regions, ndrives; 124 125 if (cur.dk_ndrive == 0) { 126 mvwaddstr(wnd, row++, INSET, "No drives attached."); 127 return (row); 128 } 129 #define COLWIDTH 17 130 #define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 131 for (ndrives = 0, i = 0; i < cur.dk_ndrive; i++) 132 if (cur.dk_select[i]) 133 ndrives++; 134 regions = howmany(ndrives, DRIVESPERLINE); 135 /* 136 * Deduct -regions for blank line after each scrolling region. 137 */ 138 linesperregion = (wnd->_maxy - row - regions) / regions; 139 /* 140 * Minimum region contains space for two 141 * label lines and one line of statistics. 142 */ 143 if (linesperregion < 3) 144 linesperregion = 3; 145 col = INSET; 146 for (i = 0; i < cur.dk_ndrive; i++) 147 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 148 if (col + COLWIDTH >= wnd->_maxx) { 149 col = INSET, row += linesperregion + 1; 150 if (row > wnd->_maxy - (linesperregion + 1)) 151 break; 152 } 153 mvwaddstr(wnd, row, col + 4, cur.dk_name[i]); 154 mvwaddstr(wnd, row + 1, col, " KBps tps sec"); 155 col += COLWIDTH; 156 } 157 if (col) 158 row += linesperregion + 1; 159 return (row); 160 } 161 162 static int 163 barlabels(int row) 164 { 165 int i; 166 167 if (cur.dk_ndrive == 0) { 168 mvwaddstr(wnd, row++, INSET, "No drives attached."); 169 return (row); 170 } 171 mvwaddstr(wnd, row++, INSET, 172 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 173 linesperregion = 2 + secs; 174 for (i = 0; i < dk_ndrive; i++) 175 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 176 if (row > wnd->_maxy - linesperregion) 177 break; 178 mvwprintw(wnd, row++, 0, "%4.4s Kps|", cur.dk_name[i]); 179 mvwaddstr(wnd, row++, 0, " tps|"); 180 if (secs) 181 mvwaddstr(wnd, row++, 0, " msec|"); 182 } 183 return (row); 184 } 185 186 187 void 188 showiostat(void) 189 { 190 int i, row, col; 191 192 dkswap(); 193 194 etime = 0; 195 for (i = 0; i < CPUSTATES; i++) { 196 etime += cur.cp_time[i]; 197 } 198 if (etime == 0.0) 199 etime = 1.0; 200 etime /= (float) hz; 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 209 if (last.dk_ndrive != cur.dk_ndrive) 210 labeliostat(); 211 212 if (cur.dk_ndrive == 0) 213 return; 214 215 if (!numbers) { 216 row += 2; 217 for (i = 0; i < cur.dk_ndrive; i++) 218 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 219 if (row > wnd->_maxy - linesperregion) 220 break; 221 row = stats(row, INSET, i); 222 } 223 return; 224 } 225 col = INSET; 226 wmove(wnd, row + linesperregion, 0); 227 wdeleteln(wnd); 228 wmove(wnd, row + 3, 0); 229 winsertln(wnd); 230 for (i = 0; i < cur.dk_ndrive; i++) 231 if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) { 232 if (col + COLWIDTH >= wnd->_maxx) { 233 col = INSET, row += linesperregion + 1; 234 if (row > wnd->_maxy - (linesperregion + 1)) 235 break; 236 wmove(wnd, row + linesperregion, 0); 237 wdeleteln(wnd); 238 wmove(wnd, row + 3, 0); 239 winsertln(wnd); 240 } 241 (void) stats(row + 3, col, i); 242 col += COLWIDTH; 243 } 244 } 245 246 static int 247 stats(int row, int col, int dn) 248 { 249 double atime, words; 250 251 /* time busy in disk activity */ 252 atime = (double)cur.dk_time[dn].tv_sec + 253 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 254 255 words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */ 256 if (numbers) { 257 mvwprintw(wnd, row, col, "%5.0f%4.0f%5.1f", 258 words / etime, cur.dk_xfer[dn] / etime, atime / etime); 259 return (row); 260 } 261 wmove(wnd, row++, col); 262 histogram(words / etime, 50, 0.5); 263 wmove(wnd, row++, col); 264 histogram(cur.dk_xfer[dn] / etime, 50, 0.5); 265 if (secs) { 266 wmove(wnd, row++, col); 267 atime *= 1000; /* In milliseconds */ 268 histogram(atime / etime, 50, 0.5); 269 } 270 return (row); 271 } 272 273 static void 274 stat1(int row, int o) 275 { 276 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(double val, int colwidth, double scale) 291 { 292 int v = (int)(val * scale + 0.5); 293 int factor = 1; 294 int y, x; 295 296 while (v > colwidth) { 297 v = (v + 5) / 10; 298 factor *= 10; 299 } 300 getyx(wnd, y, x); 301 wclrtoeol(wnd); 302 whline(wnd, 'X', v); 303 if (factor != 1) 304 mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor); 305 } 306 307 int 308 cmdiostat(char *cmd, char *args) 309 { 310 311 if (prefix(cmd, "secs")) 312 secs = !secs; 313 else if (prefix(cmd, "numbers")) 314 numbers = 1; 315 else if (prefix(cmd, "bars")) 316 numbers = 0; 317 else if (!dkcmd(cmd, args)) 318 return (0); 319 wclear(wnd); 320 labeliostat(); 321 refresh(); 322 return (1); 323 } 324