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