iostat.c revision 69141
1/* 2 * Copyright (c) 1998 Kenneth D. Merry. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: head/usr.bin/systat/iostat.c 69141 2000-11-25 03:47:36Z rwatson $ 29 */ 30/* 31 * Copyright (c) 1980, 1992, 1993 32 * The Regents of the University of California. All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 3. All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Berkeley and its contributors. 46 * 4. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 */ 62 63#ifndef lint 64static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 65#endif not lint 66 67#include <sys/param.h> 68#include <sys/dkstat.h> 69 70#include <string.h> 71#include <stdlib.h> 72#include <nlist.h> 73#include <paths.h> 74#include <devstat.h> 75#include <err.h> 76#include "systat.h" 77#include "extern.h" 78#include "devs.h" 79 80struct statinfo cur, last; 81 82static int linesperregion; 83static double etime; 84static int numbers = 0; /* default display bar graphs */ 85static int kbpt = 0; /* default ms/seek shown */ 86 87static int barlabels __P((int)); 88static void histogram __P((long double, int, double)); 89static int numlabels __P((int)); 90static int devstats __P((int, int, int)); 91static void stat1 __P((int, int)); 92 93WINDOW * 94openiostat() 95{ 96 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 97} 98 99void 100closeiostat(w) 101 WINDOW *w; 102{ 103 if (w == NULL) 104 return; 105 wclear(w); 106 wrefresh(w); 107 delwin(w); 108} 109 110int 111initiostat() 112{ 113 if (num_devices = getnumdevs() < 0) 114 return(0); 115 116 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 117 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 118 bzero(cur.dinfo, sizeof(struct devinfo)); 119 bzero(last.dinfo, sizeof(struct devinfo)); 120 121 /* 122 * This value for maxshowdevs (100) is bogus. I'm not sure exactly 123 * how to calculate it, though. 124 */ 125 if (dsinit(100, &cur, &last, NULL) != 1) 126 return(0); 127 128 return(1); 129} 130 131void 132fetchiostat() 133{ 134 struct devinfo *tmp_dinfo; 135 size_t len; 136 int err; 137 138 len = sizeof(cur.cp_time); 139 err = sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0); 140 if (err || len != sizeof(cur.cp_time)) { 141 perror("kern.cp_time"); 142 exit (1); 143 } 144 tmp_dinfo = last.dinfo; 145 last.dinfo = cur.dinfo; 146 cur.dinfo = tmp_dinfo; 147 148 last.busy_time = cur.busy_time; 149 150 /* 151 * Here what we want to do is refresh our device stats. 152 * getdevs() returns 1 when the device list has changed. 153 * If the device list has changed, we want to go through 154 * the selection process again, in case a device that we 155 * were previously displaying has gone away. 156 */ 157 switch (getdevs(&cur)) { 158 case -1: 159 errx(1, "%s", devstat_errbuf); 160 break; 161 case 1: 162 cmdiostat("refresh", NULL); 163 break; 164 default: 165 break; 166 } 167 num_devices = cur.dinfo->numdevs; 168 generation = cur.dinfo->generation; 169 170} 171 172#define INSET 10 173 174void 175labeliostat() 176{ 177 int row; 178 179 row = 0; 180 wmove(wnd, row, 0); wclrtobot(wnd); 181 mvwaddstr(wnd, row++, INSET, 182 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 183 mvwaddstr(wnd, row++, 0, "cpu user|"); 184 mvwaddstr(wnd, row++, 0, " nice|"); 185 mvwaddstr(wnd, row++, 0, " system|"); 186 mvwaddstr(wnd, row++, 0, "interrupt|"); 187 mvwaddstr(wnd, row++, 0, " idle|"); 188 if (numbers) 189 row = numlabels(row + 1); 190 else 191 row = barlabels(row + 1); 192} 193 194static int 195numlabels(row) 196 int row; 197{ 198 int i, col, regions, ndrives; 199 char tmpstr[10]; 200 201#define COLWIDTH 17 202#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 203 for (ndrives = 0, i = 0; i < num_devices; i++) 204 if (dev_select[i].selected) 205 ndrives++; 206 regions = howmany(ndrives, DRIVESPERLINE); 207 /* 208 * Deduct -regions for blank line after each scrolling region. 209 */ 210 linesperregion = (wnd->_maxy - row - regions) / regions; 211 /* 212 * Minimum region contains space for two 213 * label lines and one line of statistics. 214 */ 215 if (linesperregion < 3) 216 linesperregion = 3; 217 col = INSET; 218 for (i = 0; i < num_devices; i++) 219 if (dev_select[i].selected) { 220 if (col + COLWIDTH >= wnd->_maxx - INSET) { 221 col = INSET, row += linesperregion + 1; 222 if (row > wnd->_maxy - (linesperregion + 1)) 223 break; 224 } 225 sprintf(tmpstr, "%s%d", dev_select[i].device_name, 226 dev_select[i].unit_number); 227 mvwaddstr(wnd, row, col + 4, tmpstr); 228 mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s "); 229 col += COLWIDTH; 230 } 231 if (col) 232 row += linesperregion + 1; 233 return (row); 234} 235 236static int 237barlabels(row) 238 int row; 239{ 240 int i; 241 char tmpstr[10]; 242 243 mvwaddstr(wnd, row++, INSET, 244 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 245 linesperregion = 2 + kbpt; 246 for (i = 0; i < num_devices; i++) 247 if (dev_select[i].selected) { 248 if (row > wnd->_maxy - linesperregion) 249 break; 250 sprintf(tmpstr, "%s%d", dev_select[i].device_name, 251 dev_select[i].unit_number); 252 mvwprintw(wnd, row++, 0, "%-5.5s MB/s|", 253 tmpstr); 254 mvwaddstr(wnd, row++, 0, " tps|"); 255 if (kbpt) 256 mvwaddstr(wnd, row++, 0, " KB/t|"); 257 } 258 return (row); 259} 260 261 262void 263showiostat() 264{ 265 register long t; 266 register int i, row, col; 267 268#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t 269 etime = 0; 270 for(i = 0; i < CPUSTATES; i++) { 271 X(cp_time); 272 etime += cur.cp_time[i]; 273 } 274 if (etime == 0.0) 275 etime = 1.0; 276 etime /= hertz; 277 row = 1; 278 for (i = 0; i < CPUSTATES; i++) 279 stat1(row++, i); 280 if (!numbers) { 281 row += 2; 282 for (i = 0; i < num_devices; i++) 283 if (dev_select[i].selected) { 284 if (row > wnd->_maxy - linesperregion) 285 break; 286 row = devstats(row, INSET, i); 287 } 288 return; 289 } 290 col = INSET; 291 wmove(wnd, row + linesperregion, 0); 292 wdeleteln(wnd); 293 wmove(wnd, row + 3, 0); 294 winsertln(wnd); 295 for (i = 0; i < num_devices; i++) 296 if (dev_select[i].selected) { 297 if (col + COLWIDTH >= wnd->_maxx - INSET) { 298 col = INSET, row += linesperregion + 1; 299 if (row > wnd->_maxy - (linesperregion + 1)) 300 break; 301 wmove(wnd, row + linesperregion, 0); 302 wdeleteln(wnd); 303 wmove(wnd, row + 3, 0); 304 winsertln(wnd); 305 } 306 (void) devstats(row + 3, col, i); 307 col += COLWIDTH; 308 } 309} 310 311static int 312devstats(row, col, dn) 313 int row, col, dn; 314{ 315 long double transfers_per_second; 316 long double kb_per_transfer, mb_per_second; 317 long double busy_seconds; 318 int di; 319 320 di = dev_select[dn].position; 321 322 busy_seconds = compute_etime(cur.busy_time, last.busy_time); 323 324 if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di], 325 busy_seconds, NULL, NULL, NULL, 326 &kb_per_transfer, &transfers_per_second, 327 &mb_per_second, NULL, NULL) != 0) 328 errx(1, "%s", devstat_errbuf); 329 330 if (numbers) { 331 mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ", 332 kb_per_transfer, transfers_per_second, 333 mb_per_second); 334 return(row); 335 } 336 wmove(wnd, row++, col); 337 histogram(mb_per_second, 50, .5); 338 wmove(wnd, row++, col); 339 histogram(transfers_per_second, 50, .5); 340 if (kbpt) { 341 wmove(wnd, row++, col); 342 histogram(kb_per_transfer, 50, .5); 343 } 344 345 return(row); 346 347} 348 349static void 350stat1(row, o) 351 int row, o; 352{ 353 register int i; 354 double time; 355 356 time = 0; 357 for (i = 0; i < CPUSTATES; i++) 358 time += cur.cp_time[i]; 359 if (time == 0.0) 360 time = 1.0; 361 wmove(wnd, row, INSET); 362#define CPUSCALE 0.5 363 histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE); 364} 365 366static void 367histogram(val, colwidth, scale) 368 long double val; 369 int colwidth; 370 double scale; 371{ 372 char buf[10]; 373 register int k; 374 register int v = (int)(val * scale) + 0.5; 375 376 k = MIN(v, colwidth); 377 if (v > colwidth) { 378 snprintf(buf, sizeof(buf), "%5.2Lf", val); 379 k -= strlen(buf); 380 while (k--) 381 waddch(wnd, 'X'); 382 waddstr(wnd, buf); 383 return; 384 } 385 while (k--) 386 waddch(wnd, 'X'); 387 wclrtoeol(wnd); 388} 389 390int 391cmdiostat(cmd, args) 392 char *cmd, *args; 393{ 394 395 if (prefix(cmd, "kbpt")) 396 kbpt = !kbpt; 397 else if (prefix(cmd, "numbers")) 398 numbers = 1; 399 else if (prefix(cmd, "bars")) 400 numbers = 0; 401 else if (!dscmd(cmd, args, 100, &cur)) 402 return (0); 403 wclear(wnd); 404 labeliostat(); 405 refresh(); 406 return (1); 407} 408