Home | History | Annotate | Line # | Download | only in systat
iostat.c revision 1.34
      1 /*	$NetBSD: iostat.c,v 1.34 2006/02/05 09:58:39 dsl 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.34 2006/02/05 09:58:39 dsl 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 #include "tpstats.h"
     48 
     49 static  int linesperregion;
     50 static  double etime;
     51 static  int numbers = 0;		/* default display bar graphs */
     52 static  int secs = 0;			/* default seconds shown */
     53 static  int read_write = 0;		/* default read/write shown */
     54 
     55 static int barlabels(int);
     56 static void histogram(double, int, double);
     57 static int numlabels(int);
     58 static int stats(int, int, int);
     59 static int tpstats(int, int, int);
     60 static void stat1(int, int);
     61 
     62 
     63 WINDOW *
     64 openiostat(void)
     65 {
     66 
     67 	return (subwin(stdscr, -1, 0, 5, 0));
     68 }
     69 
     70 void
     71 closeiostat(WINDOW *w)
     72 {
     73 
     74 	if (w == NULL)
     75 		return;
     76 	wclear(w);
     77 	wrefresh(w);
     78 	delwin(w);
     79 }
     80 
     81 int
     82 initiostat(void)
     83 {
     84 
     85 	dkinit(1);
     86 	tpinit(1);
     87 	cpureadstats();
     88 	dkreadstats();
     89 	tpreadstats();
     90 	return(1);
     91 }
     92 
     93 void
     94 fetchiostat(void)
     95 {
     96 
     97 	cpureadstats();
     98 
     99 	if (dk_ndrive != 0)
    100 		dkreadstats();
    101 
    102 	if (tp_ndrive != 0)
    103 		tpreadstats();
    104 }
    105 
    106 #define	INSET	14
    107 
    108 void
    109 labeliostat(void)
    110 {
    111 	int row;
    112 
    113 	if ((dk_ndrive == 0) && (tp_ndrive == 0)) {
    114 		error("No drives defined.");
    115 		return;
    116 	}
    117 	row = 0;
    118 	wmove(wnd, row, 0); wclrtobot(wnd);
    119 	mvwaddstr(wnd, row++, INSET,
    120 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
    121 	mvwaddstr(wnd, row++, 0, "    CPU  user|");
    122 	mvwaddstr(wnd, row++, 0, "         nice|");
    123 	mvwaddstr(wnd, row++, 0, "       system|");
    124 	mvwaddstr(wnd, row++, 0, "    interrupt|");
    125 	mvwaddstr(wnd, row++, 0, "         idle|");
    126 	if (numbers)
    127 		row = numlabels(row + 1);
    128 	else
    129 		row = barlabels(row + 1);
    130 }
    131 
    132 static int
    133 numlabels(int row)
    134 {
    135 	int i, col, regions, ndrives;
    136 
    137 #define COLWIDTH	(9 + secs * 5 + 1 + read_write * 9 + 1)
    138 #define DRIVESPERLINE	((getmaxx(wnd) + 1) / COLWIDTH)
    139 	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
    140 		if (cur.dk_select[i])
    141 			ndrives++;
    142 	for (i = 0; i < tp_ndrive; i++)
    143 		if (cur_tape.select[i])
    144 			ndrives++;
    145 
    146 	regions = howmany(ndrives, DRIVESPERLINE);
    147 	/*
    148 	 * Deduct -regions for blank line after each scrolling region.
    149 	 */
    150 	linesperregion = (getmaxy(wnd) - row - regions + 1) / regions;
    151 	/*
    152 	 * Minimum region contains space for two
    153 	 * label lines and one line of statistics.
    154 	 */
    155 	if (linesperregion < 3)
    156 		linesperregion = 3;
    157 	col = 0;
    158 	for (i = 0; i < (dk_ndrive + tp_ndrive); i++)
    159 		if (((i < dk_ndrive) && (cur.dk_select[i])) ||
    160 		    ((i >= dk_ndrive) && (cur_tape.select[i - dk_ndrive]))) {
    161 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
    162 				col = 0, row += linesperregion + 1;
    163 				if (row > getmaxy(wnd) - (linesperregion))
    164 					break;
    165 			}
    166 
    167 			if (i < dk_ndrive)
    168 				mvwprintw(wnd, row, col + 5, "%s",
    169 					  cur.dk_name[i]);
    170 			else
    171 				mvwprintw(wnd, row, col + 5, "%s",
    172 					  cur_tape.name[i - dk_ndrive]);
    173 
    174 			if (read_write)
    175 				mvwprintw(wnd, row, col + 11 + secs * 5,
    176 				    "(write)");
    177 			mvwprintw(wnd, row + 1, col, " kBps %s",
    178 				read_write ? "r/s" : "tps");
    179 			if (secs)
    180 				waddstr(wnd, "  sec");
    181 			if (read_write)
    182 				waddstr(wnd, "  kBps w/s");
    183 			col += COLWIDTH;
    184 		}
    185 	if (col)
    186 		row += linesperregion + 1;
    187 	return (row);
    188 }
    189 
    190 static int
    191 barlabels(int row)
    192 {
    193 	int i;
    194 
    195 	mvwaddstr(wnd, row++, INSET,
    196 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
    197 	linesperregion = 2 + secs + (read_write ? 2 : 0);
    198 	for (i = 0; i < dk_ndrive; i++)
    199 		if (cur.dk_select[i]) {
    200 			if (row > getmaxy(wnd) - linesperregion)
    201 				break;
    202 			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
    203 			    cur.dk_name[i]);
    204 			mvwaddstr(wnd, row++, 0, "          tps|");
    205 			if (read_write) {
    206 				mvwprintw(wnd, row++, 0, " (write) kBps|");
    207 				mvwaddstr(wnd, row++, 0, "          tps|");
    208 			}
    209 			if (secs)
    210 				mvwaddstr(wnd, row++, 0, "         msec|");
    211 		}
    212 	for (i = 0; i < tp_ndrive; i++)
    213 		if (cur_tape.select[i]) {
    214 			if (row > getmaxy(wnd) - linesperregion)
    215 				break;
    216 			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
    217 			    cur_tape.name[i]);
    218 			mvwaddstr(wnd, row++, 0, "          tps|");
    219 			if (read_write) {
    220 				mvwprintw(wnd, row++, 0, " (write) kBps|");
    221 				mvwaddstr(wnd, row++, 0, "          tps|");
    222 			}
    223 			if (secs)
    224 				mvwaddstr(wnd, row++, 0, "         msec|");
    225 		}
    226 	return (row);
    227 }
    228 
    229 void
    230 showiostat(void)
    231 {
    232 	int i, row, col;
    233 
    234 	if (dk_ndrive == 0)
    235 		return;
    236 	dkswap();
    237 	cpuswap();
    238 	tpswap();
    239 
    240 	etime = cur.cp_etime;
    241 	row = 1;
    242 
    243 	/*
    244 	 * Interrupt CPU state not calculated yet.
    245 	 */
    246 	for (i = 0; i < CPUSTATES; i++)
    247 		stat1(row++, i);
    248 	if (!numbers) {
    249 		row += 2;
    250 		for (i = 0; i < dk_ndrive; i++)
    251 			if (cur.dk_select[i]) {
    252 				if (row > getmaxy(wnd) - linesperregion)
    253 					break;
    254 				row = stats(row, INSET, i);
    255 			}
    256 		for (i = 0; i < tp_ndrive; i++)
    257 			if (cur_tape.select[i]) {
    258 				if (row > getmaxy(wnd) - linesperregion)
    259 					break;
    260 				row = tpstats(row, INSET, i);
    261 			}
    262 		return;
    263 	}
    264 	col = 0;
    265 	wmove(wnd, row + linesperregion, 0);
    266 	wdeleteln(wnd);
    267 	wmove(wnd, row + 3, 0);
    268 	winsertln(wnd);
    269 	for (i = 0; i < dk_ndrive; i++)
    270 		if (cur.dk_select[i]) {
    271 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
    272 				col = 0, row += linesperregion + 1;
    273 				if (row > getmaxy(wnd) - (linesperregion + 1))
    274 					break;
    275 				wmove(wnd, row + linesperregion, 0);
    276 				wdeleteln(wnd);
    277 				wmove(wnd, row + 3, 0);
    278 				winsertln(wnd);
    279 			}
    280 			(void) stats(row + 3, col, i);
    281 			col += COLWIDTH;
    282 		}
    283 	for (i = 0; i < tp_ndrive; i++)
    284 		if (cur_tape.select[i]) {
    285 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
    286 				col = 0, row += linesperregion + 1;
    287 				if (row > getmaxy(wnd) - (linesperregion + 1))
    288 					break;
    289 				wmove(wnd, row + linesperregion, 0);
    290 				wdeleteln(wnd);
    291 				wmove(wnd, row + 3, 0);
    292 				winsertln(wnd);
    293 			}
    294 			(void) stats(row + 3, col, i);
    295 			col += COLWIDTH;
    296 		}
    297 }
    298 
    299 static int
    300 stats(int row, int col, int dn)
    301 {
    302 	double atime, rwords, wwords;
    303 	uint64_t rxfer;
    304 
    305 	/* time busy in disk activity */
    306 	atime = (double)cur.dk_time[dn].tv_sec +
    307 		((double)cur.dk_time[dn].tv_usec / (double)1000000);
    308 
    309 	/* # of k transferred */
    310 	rwords = cur.dk_rbytes[dn] / 1024.0;
    311 	wwords = cur.dk_wbytes[dn] / 1024.0;
    312 	rxfer = cur.dk_rxfer[dn];
    313 	if (!read_write) {
    314 		rwords = wwords;
    315 		rxfer += cur.dk_wxfer[dn];
    316 	}
    317 	if (numbers) {
    318 		mvwprintw(wnd, row, col, "%5.0f%4.0f",
    319 		    rwords / etime, rxfer / etime);
    320 		if (secs)
    321 			wprintw(wnd, "%5.1f", atime / etime);
    322 		if (read_write)
    323 			wprintw(wnd, " %5.0f%4.0f",
    324 			    wwords / etime, cur.dk_wxfer[dn] / etime);
    325 		return (row);
    326 	}
    327 
    328 	wmove(wnd, row++, col);
    329 	histogram(rwords / etime, 50, 0.5);
    330 	wmove(wnd, row++, col);
    331 	histogram(rxfer / etime, 50, 0.5);
    332 	if (read_write) {
    333 		wmove(wnd, row++, col);
    334 		histogram(wwords / etime, 50, 0.5);
    335 		wmove(wnd, row++, col);
    336 		histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
    337 	}
    338 
    339 	if (secs) {
    340 		wmove(wnd, row++, col);
    341 		atime *= 1000;	/* In milliseconds */
    342 		histogram(atime / etime, 50, 0.5);
    343 	}
    344 	return (row);
    345 }
    346 
    347 static int
    348 tpstats(int row, int col, int dn)
    349 {
    350 	double atime, rwords, wwords;
    351 	uint64_t rxfer;
    352 
    353 	/* time busy in disk activity */
    354 	atime = (double)cur_tape.time[dn].tv_sec +
    355 		((double)cur_tape.time[dn].tv_usec / (double)1000000);
    356 
    357 	/* # of k transferred */
    358 	rwords = cur_tape.rbytes[dn] / 1024.0;
    359 	wwords = cur_tape.wbytes[dn] / 1024.0;
    360 	rxfer = cur_tape.rxfer[dn];
    361 	if (!read_write) {
    362 		rwords = wwords;
    363 		rxfer += cur_tape.wxfer[dn];
    364 	}
    365 	if (numbers) {
    366 		mvwprintw(wnd, row, col, "%5.0f%4.0f",
    367 		    rwords / etime, rxfer / etime);
    368 		if (secs)
    369 			wprintw(wnd, "%5.1f", atime / etime);
    370 		if (read_write)
    371 			wprintw(wnd, " %5.0f%4.0f",
    372 			    wwords / etime, cur_tape.wxfer[dn] / etime);
    373 		return (row);
    374 	}
    375 
    376 	wmove(wnd, row++, col);
    377 	histogram(rwords / etime, 50, 0.5);
    378 	wmove(wnd, row++, col);
    379 	histogram(rxfer / etime, 50, 0.5);
    380 	if (read_write) {
    381 		wmove(wnd, row++, col);
    382 		histogram(wwords / etime, 50, 0.5);
    383 		wmove(wnd, row++, col);
    384 		histogram(cur_tape.wxfer[dn] / etime, 50, 0.5);
    385 	}
    386 
    387 	if (secs) {
    388 		wmove(wnd, row++, col);
    389 		atime *= 1000;	/* In milliseconds */
    390 		histogram(atime / etime, 50, 0.5);
    391 	}
    392 	return (row);
    393 }
    394 
    395 static void
    396 stat1(int row, int o)
    397 {
    398 	int i;
    399 	double total_time;
    400 
    401 	total_time = 0;
    402 	for (i = 0; i < CPUSTATES; i++)
    403 		total_time += cur.cp_time[i];
    404 	if (total_time == 0.0)
    405 		total_time = 1.0;
    406 	wmove(wnd, row, INSET);
    407 #define CPUSCALE	0.5
    408 	histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE);
    409 }
    410 
    411 static void
    412 histogram(double val, int colwidth, double scale)
    413 {
    414 	int v = (int)(val * scale + 0.5);
    415 	int factor = 1;
    416 	int y, x;
    417 
    418 	while (v > colwidth) {
    419 		v = (v + 5) / 10;
    420 		factor *= 10;
    421 	}
    422 	getyx(wnd, y, x);
    423 	wclrtoeol(wnd);
    424 	whline(wnd, 'X', v);
    425 	if (factor != 1)
    426 		mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor);
    427 }
    428 
    429 void
    430 iostat_bars(char *args)
    431 {
    432 	numbers = 0;
    433 	wclear(wnd);
    434 	labeliostat();
    435 	refresh();
    436 }
    437 
    438 void
    439 iostat_numbers(char *args)
    440 {
    441 	numbers = 1;
    442 	wclear(wnd);
    443 	labeliostat();
    444 	refresh();
    445 }
    446 
    447 void
    448 iostat_secs(char *args)
    449 {
    450 	secs = !secs;
    451 	wclear(wnd);
    452 	labeliostat();
    453 	refresh();
    454 }
    455 
    456 void
    457 iostat_rw(char *args)
    458 {
    459 	read_write ^= 1;
    460 	wclear(wnd);
    461 	labeliostat();
    462 	refresh();
    463 }
    464 
    465 void
    466 iostat_all(char *args)
    467 {
    468 	read_write = 0;
    469 	wclear(wnd);
    470 	labeliostat();
    471 	refresh();
    472 }
    473