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