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