iostat.c revision 1.31
1/* $NetBSD: iostat.c,v 1.31 2005/02/26 22:11:06 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 35static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 36#endif 37__RCSID("$NetBSD: iostat.c,v 1.31 2005/02/26 22:11:06 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 48static int linesperregion; 49static double etime; 50static int numbers = 0; /* default display bar graphs */ 51static int secs = 0; /* default seconds shown */ 52static int read_write = 0; /* default read/write shown */ 53 54static int barlabels(int); 55static void histogram(double, int, double); 56static int numlabels(int); 57static int stats(int, int, int); 58static void stat1(int, int); 59 60 61WINDOW * 62openiostat(void) 63{ 64 65 return (subwin(stdscr, -1, 0, 5, 0)); 66} 67 68void 69closeiostat(WINDOW *w) 70{ 71 72 if (w == NULL) 73 return; 74 wclear(w); 75 wrefresh(w); 76 delwin(w); 77} 78 79int 80initiostat(void) 81{ 82 83 dkinit(1); 84 dkreadstats(); 85 return(1); 86} 87 88void 89fetchiostat(void) 90{ 91 92 if (dk_ndrive == 0) 93 return; 94 dkreadstats(); 95} 96 97#define INSET 14 98 99void 100labeliostat(void) 101{ 102 int row; 103 104 if (dk_ndrive == 0) { 105 error("No drives defined."); 106 return; 107 } 108 row = 0; 109 wmove(wnd, row, 0); wclrtobot(wnd); 110 mvwaddstr(wnd, row++, INSET, 111 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 112 mvwaddstr(wnd, row++, 0, " CPU user|"); 113 mvwaddstr(wnd, row++, 0, " nice|"); 114 mvwaddstr(wnd, row++, 0, " system|"); 115 mvwaddstr(wnd, row++, 0, " interrupt|"); 116 mvwaddstr(wnd, row++, 0, " idle|"); 117 if (numbers) 118 row = numlabels(row + 1); 119 else 120 row = barlabels(row + 1); 121} 122 123static int 124numlabels(int row) 125{ 126 int i, col, regions, ndrives; 127 128#define COLWIDTH (8 + secs * 5 + read_write * 9 + 2) 129#define DRIVESPERLINE ((getmaxx(wnd) + 1) / COLWIDTH) 130 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 131 if (cur.dk_select[i]) 132 ndrives++; 133 regions = howmany(ndrives, DRIVESPERLINE); 134 /* 135 * Deduct -regions for blank line after each scrolling region. 136 */ 137 linesperregion = (getmaxy(wnd) - row - regions + 1) / regions; 138 /* 139 * Minimum region contains space for two 140 * label lines and one line of statistics. 141 */ 142 if (linesperregion < 3) 143 linesperregion = 3; 144 col = 0; 145 for (i = 0; i < dk_ndrive; i++) 146 if (cur.dk_select[i]) { 147 if (col + COLWIDTH - 1 > getmaxx(wnd)) { 148 col = 0, row += linesperregion + 1; 149 if (row > getmaxy(wnd) - (linesperregion)) 150 break; 151 } 152 mvwprintw(wnd, row, col + 4, "%s", cur.dk_name[i]); 153 if (read_write) 154 mvwprintw(wnd, row, col + 9 + secs * 5, 155 "(write)"); 156 mvwprintw(wnd, row + 1, col, "kBps %s", 157 read_write ? "r/s" : "tps"); 158 if (secs) 159 waddstr(wnd, " sec"); 160 if (read_write) 161 waddstr(wnd, " kBps w/s"); 162 col += COLWIDTH; 163 } 164 if (col) 165 row += linesperregion + 1; 166 return (row); 167} 168 169static int 170barlabels(int row) 171{ 172 int i; 173 174 mvwaddstr(wnd, row++, INSET, 175 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 176 linesperregion = 2 + secs + (read_write ? 2 : 0); 177 for (i = 0; i < dk_ndrive; i++) 178 if (cur.dk_select[i]) { 179 if (row > getmaxy(wnd) - linesperregion) 180 break; 181 mvwprintw(wnd, row++, 0, "%7.7s kBps|", 182 cur.dk_name[i]); 183 mvwaddstr(wnd, row++, 0, " tps|"); 184 if (read_write) { 185 mvwprintw(wnd, row++, 0, " (write) kBps|"); 186 mvwaddstr(wnd, row++, 0, " tps|"); 187 } 188 if (secs) 189 mvwaddstr(wnd, row++, 0, " msec|"); 190 } 191 return (row); 192} 193 194void 195showiostat(void) 196{ 197 int i, row, col; 198 199 if (dk_ndrive == 0) 200 return; 201 dkswap(); 202 203 etime = cur.cp_etime; 204 row = 1; 205 206 /* 207 * Interrupt CPU state not calculated yet. 208 */ 209 for (i = 0; i < CPUSTATES; i++) 210 stat1(row++, i); 211 if (!numbers) { 212 row += 2; 213 for (i = 0; i < dk_ndrive; i++) 214 if (cur.dk_select[i]) { 215 if (row > getmaxy(wnd) - linesperregion) 216 break; 217 row = stats(row, INSET, i); 218 } 219 return; 220 } 221 col = 0; 222 wmove(wnd, row + linesperregion, 0); 223 wdeleteln(wnd); 224 wmove(wnd, row + 3, 0); 225 winsertln(wnd); 226 for (i = 0; i < dk_ndrive; i++) 227 if (cur.dk_select[i]) { 228 if (col + COLWIDTH - 1 > getmaxx(wnd)) { 229 col = 0, row += linesperregion + 1; 230 if (row > getmaxy(wnd) - (linesperregion + 1)) 231 break; 232 wmove(wnd, row + linesperregion, 0); 233 wdeleteln(wnd); 234 wmove(wnd, row + 3, 0); 235 winsertln(wnd); 236 } 237 (void) stats(row + 3, col, i); 238 col += COLWIDTH; 239 } 240} 241 242static int 243stats(int row, int col, int dn) 244{ 245 double atime, rwords, wwords; 246 uint64_t rxfer; 247 248 /* time busy in disk activity */ 249 atime = (double)cur.dk_time[dn].tv_sec + 250 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 251 252 /* # of k transferred */ 253 rwords = cur.dk_rbytes[dn] / 1024.0; 254 wwords = cur.dk_wbytes[dn] / 1024.0; 255 rxfer = cur.dk_rxfer[dn]; 256 if (!read_write) { 257 rwords = wwords; 258 rxfer += cur.dk_wxfer[dn]; 259 } 260 if (numbers) { 261 mvwprintw(wnd, row, col, "%4.0f%4.0f", 262 rwords / etime, rxfer / etime); 263 if (secs) 264 wprintw(wnd, "%5.1f", atime / etime); 265 if (read_write) 266 wprintw(wnd, " %4.0f%4.0f", 267 wwords / etime, cur.dk_wxfer[dn] / etime); 268 return (row); 269 } 270 271 wmove(wnd, row++, col); 272 histogram(rwords / etime, 50, 0.5); 273 wmove(wnd, row++, col); 274 histogram(rxfer / etime, 50, 0.5); 275 if (read_write) { 276 wmove(wnd, row++, col); 277 histogram(wwords / etime, 50, 0.5); 278 wmove(wnd, row++, col); 279 histogram(cur.dk_wxfer[dn] / etime, 50, 0.5); 280 } 281 282 if (secs) { 283 wmove(wnd, row++, col); 284 atime *= 1000; /* In milliseconds */ 285 histogram(atime / etime, 50, 0.5); 286 } 287 return (row); 288} 289 290static void 291stat1(int row, int o) 292{ 293 int i; 294 double total_time; 295 296 total_time = 0; 297 for (i = 0; i < CPUSTATES; i++) 298 total_time += cur.cp_time[i]; 299 if (total_time == 0.0) 300 total_time = 1.0; 301 wmove(wnd, row, INSET); 302#define CPUSCALE 0.5 303 histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE); 304} 305 306static void 307histogram(double val, int colwidth, double scale) 308{ 309 int v = (int)(val * scale + 0.5); 310 int factor = 1; 311 int y, x; 312 313 while (v > colwidth) { 314 v = (v + 5) / 10; 315 factor *= 10; 316 } 317 getyx(wnd, y, x); 318 wclrtoeol(wnd); 319 whline(wnd, 'X', v); 320 if (factor != 1) 321 mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor); 322} 323 324void 325iostat_bars(char *args) 326{ 327 numbers = 0; 328 wclear(wnd); 329 labeliostat(); 330 refresh(); 331} 332 333void 334iostat_numbers(char *args) 335{ 336 numbers = 1; 337 wclear(wnd); 338 labeliostat(); 339 refresh(); 340} 341 342void 343iostat_secs(char *args) 344{ 345 secs = !secs; 346 wclear(wnd); 347 labeliostat(); 348 refresh(); 349} 350 351void 352iostat_rw(char *args) 353{ 354 read_write ^= 1; 355 wclear(wnd); 356 labeliostat(); 357 refresh(); 358} 359 360void 361iostat_all(char *args) 362{ 363 read_write = 0; 364 wclear(wnd); 365 labeliostat(); 366 refresh(); 367} 368