1 /*- 2 * Copyright (c) 1983, 1989, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)vmstat.c 8.2 (Berkeley) 1/12/94 34 * $FreeBSD: src/usr.bin/systat/vmstat.c,v 1.38.2.4 2002/03/12 19:50:23 phantom Exp $ 35 * $DragonFly: src/usr.bin/systat/vmstat.c,v 1.12 2008/11/10 04:59:45 swildner Exp $ 36 */ 37 38 /* 39 * Cursed vmstat -- from Robert Elz. 40 */ 41 42 #include <sys/user.h> 43 #include <sys/param.h> 44 #include <sys/stat.h> 45 #include <sys/time.h> 46 #include <sys/uio.h> 47 #include <sys/namei.h> 48 #include <sys/sysctl.h> 49 #include <sys/vmmeter.h> 50 51 #include <vm/vm_param.h> 52 53 #include <ctype.h> 54 #include <err.h> 55 #include <errno.h> 56 #include <kinfo.h> 57 #include <langinfo.h> 58 #include <nlist.h> 59 #include <paths.h> 60 #include <signal.h> 61 #include <stddef.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <time.h> 65 #include <unistd.h> 66 #include "utmpentry.h" 67 #include <devstat.h> 68 #include "systat.h" 69 #include "extern.h" 70 #include "devs.h" 71 72 static struct Info { 73 struct kinfo_cputime cp_time; 74 struct vmmeter Vmm; 75 struct vmtotal Total; 76 struct vmstats Vms; 77 struct nchstats nchstats; 78 long nchcount; 79 long nchpathcount; 80 long *intrcnt; 81 int bufspace; 82 int desiredvnodes; 83 int numvnodes; 84 int freevnodes; 85 int dirtybufspace; 86 } s, s1, s2, z; 87 88 struct kinfo_cputime cp_time, old_cp_time; 89 struct statinfo cur, last, run; 90 91 #define vmm s.Vmm 92 #define vms s.Vms 93 #define oldvmm s1.Vmm 94 #define oldvms s1.Vms 95 #define total s.Total 96 #define nchtotal s.nchstats 97 #define oldnchtotal s1.nchstats 98 99 static enum state { BOOT, TIME, RUN } state = TIME; 100 101 static void allocinfo(struct Info *); 102 static void copyinfo(struct Info *, struct Info *); 103 static void dinfo(int, int, struct statinfo *, struct statinfo *); 104 static void getinfo(struct Info *); 105 static void putlong(long, int, int, int, int); 106 static void putfloat(double, int, int, int, int, int); 107 static void putlongdouble(long double, int, int, int, int, int); 108 static void putlongdoublez(long double, int, int, int, int, int); 109 static int ucount(void); 110 111 static int ncpu; 112 static char buf[26]; 113 static time_t t; 114 static double etime; 115 static int nintr; 116 static long *intrloc; 117 static char **intrname; 118 static int nextintsrow; 119 static int extended_vm_stats; 120 121 122 123 WINDOW * 124 openkre(void) 125 { 126 127 return (stdscr); 128 } 129 130 void 131 closekre(WINDOW *w) 132 { 133 134 if (w == NULL) 135 return; 136 wclear(w); 137 wrefresh(w); 138 } 139 140 141 static struct nlist namelist[] = { 142 #define X_BUFFERSPACE 0 143 { .n_name = "_bufspace" }, 144 #define X_NCHSTATS 1 145 { .n_name = "_nchstats" }, 146 #define X_DESIREDVNODES 2 147 { .n_name = "_desiredvnodes" }, 148 #define X_NUMVNODES 3 149 { .n_name = "_numvnodes" }, 150 #define X_FREEVNODES 4 151 { .n_name = "_freevnodes" }, 152 #define X_NUMDIRTYBUFFERS 5 153 { .n_name = "_dirtybufspace" }, 154 { .n_name = "" }, 155 }; 156 157 /* 158 * These constants define where the major pieces are laid out 159 */ 160 #define STATROW 0 /* uses 1 row and 68 cols */ 161 #define STATCOL 2 162 #define MEMROW 2 /* uses 4 rows and 31 cols */ 163 #define MEMCOL 0 164 #define PAGEROW 2 /* uses 4 rows and 26 cols */ 165 #define PAGECOL 46 166 #define INTSROW 6 /* uses all rows to bottom and 17 cols */ 167 #define INTSCOL 61 168 #define PROCSROW 7 /* uses 2 rows and 20 cols */ 169 #define PROCSCOL 0 170 #define GENSTATROW 7 /* uses 2 rows and 30 cols */ 171 #define GENSTATCOL 16 172 #define VMSTATROW 6 /* uses 17 rows and 12 cols */ 173 #define VMSTATCOL 48 174 #define GRAPHROW 10 /* uses 3 rows and 51 cols */ 175 #define GRAPHCOL 0 176 #define NAMEIROW 14 /* uses 3 rows and 38 cols */ 177 #define NAMEICOL 0 178 #define DISKROW 17 /* uses 6 rows and 50 cols (for 9 drives) */ 179 #define DISKCOL 0 180 181 #define DRIVESPACE 7 /* max # for space */ 182 183 #define MAXDRIVES DRIVESPACE /* max # to display */ 184 185 int 186 initkre(void) 187 { 188 char *intrnamebuf; 189 size_t bytes; 190 size_t b; 191 size_t i; 192 193 if (namelist[0].n_type == 0) { 194 if (kvm_nlist(kd, namelist)) { 195 nlisterr(namelist); 196 return(0); 197 } 198 if (namelist[0].n_type == 0) { 199 error("No namelist"); 200 return(0); 201 } 202 } 203 204 if ((num_devices = getnumdevs()) < 0) { 205 warnx("%s", devstat_errbuf); 206 return(0); 207 } 208 209 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 210 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 211 run.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 212 bzero(cur.dinfo, sizeof(struct devinfo)); 213 bzero(last.dinfo, sizeof(struct devinfo)); 214 bzero(run.dinfo, sizeof(struct devinfo)); 215 216 if (dsinit(MAXDRIVES, &cur, &last, &run) != 1) 217 return(0); 218 219 if (nintr == 0) { 220 if (sysctlbyname("hw.intrnames", NULL, &bytes, NULL, 0) == 0) { 221 intrnamebuf = malloc(bytes); 222 sysctlbyname("hw.intrnames", intrnamebuf, &bytes, 223 NULL, 0); 224 for (i = 0; i < bytes; ++i) { 225 if (intrnamebuf[i] == 0) 226 ++nintr; 227 } 228 intrname = malloc(nintr * sizeof(char *)); 229 intrloc = malloc(nintr * sizeof(*intrloc)); 230 nintr = 0; 231 for (b = i = 0; i < bytes; ++i) { 232 if (intrnamebuf[i] == 0) { 233 intrname[nintr] = intrnamebuf + b; 234 intrloc[nintr] = 0; 235 b = i + 1; 236 ++nintr; 237 } 238 } 239 } 240 nextintsrow = INTSROW + 2; 241 allocinfo(&s); 242 allocinfo(&s1); 243 allocinfo(&s2); 244 allocinfo(&z); 245 } 246 getinfo(&s2); 247 copyinfo(&s2, &s1); 248 return(1); 249 } 250 251 void 252 fetchkre(void) 253 { 254 time_t now; 255 struct tm *tp; 256 static int d_first = -1; 257 258 if (d_first < 0) 259 d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 260 261 time(&now); 262 tp = localtime(&now); 263 (void) strftime(buf, sizeof(buf), 264 d_first ? "%e %b %R" : "%b %e %R", tp); 265 getinfo(&s); 266 } 267 268 void 269 labelkre(void) 270 { 271 int i, j; 272 273 clear(); 274 mvprintw(STATROW, STATCOL + 4, "users Load"); 275 mvprintw(MEMROW, MEMCOL, "Mem:MB REAL VIRTUAL"); 276 mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share"); 277 mvprintw(MEMROW + 2, MEMCOL, "Act"); 278 mvprintw(MEMROW + 3, MEMCOL, "All"); 279 280 mvprintw(MEMROW + 1, MEMCOL + 41, "Free"); 281 282 mvprintw(PAGEROW, PAGECOL, " VN PAGER SWAP PAGER "); 283 mvprintw(PAGEROW + 1, PAGECOL, " in out in out "); 284 mvprintw(PAGEROW + 2, PAGECOL, "count"); 285 mvprintw(PAGEROW + 3, PAGECOL, "pages"); 286 287 mvprintw(INTSROW, INTSCOL + 3, " Interrupts"); 288 mvprintw(INTSROW + 1, INTSCOL + 9, "total"); 289 290 mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "cow"); 291 mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "wire"); 292 mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "act"); 293 mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "inact"); 294 mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "cache"); 295 mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "free"); 296 mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "daefr"); 297 mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "prcfr"); 298 mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "react"); 299 mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "pdwake"); 300 mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "pdpgs"); 301 mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "intrn"); 302 mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "buf"); 303 mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "dirtybuf"); 304 305 mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "desiredvnodes"); 306 mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "numvnodes"); 307 mvprintw(VMSTATROW + 17, VMSTATCOL + 10, "freevnodes"); 308 309 mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt"); 310 311 mvprintw(GRAPHROW, GRAPHCOL, 312 " . %%Sys . %%Intr . %%User . %%Nice . %%Idle"); 313 mvprintw(PROCSROW, PROCSCOL, " r p d s w"); 314 mvprintw(GRAPHROW + 1, GRAPHCOL, 315 "| | | | | | | | | | |"); 316 317 mvprintw(NAMEIROW, NAMEICOL, "Path-lookups hits %% Components"); 318 mvprintw(DISKROW, DISKCOL, "Disks"); 319 mvprintw(DISKROW + 1, DISKCOL, "KB/t"); 320 mvprintw(DISKROW + 2, DISKCOL, "tpr/s"); 321 mvprintw(DISKROW + 3, DISKCOL, "MBr/s"); 322 mvprintw(DISKROW + 4, DISKCOL, "tpw/s"); 323 mvprintw(DISKROW + 5, DISKCOL, "MBw/s"); 324 mvprintw(DISKROW + 6, DISKCOL, "%% busy"); 325 /* 326 * For now, we don't support a fourth disk statistic. So there's 327 * no point in providing a label for it. If someone can think of a 328 * fourth useful disk statistic, there is room to add it. 329 */ 330 j = 0; 331 for (i = 0; i < num_devices && j < MAXDRIVES; i++) 332 if (dev_select[i].selected) { 333 char tmpstr[80]; 334 sprintf(tmpstr, "%s%d", dev_select[i].device_name, 335 dev_select[i].unit_number); 336 mvprintw(DISKROW, DISKCOL + 5 + 6 * j, 337 " %5.5s", tmpstr); 338 j++; 339 } 340 341 if (j <= 4) { 342 /* 343 * room for extended VM stats 344 */ 345 mvprintw(VMSTATROW + 11, VMSTATCOL - 6, "zfod"); 346 mvprintw(VMSTATROW + 12, VMSTATCOL - 6, "ozfod"); 347 mvprintw(VMSTATROW + 13, VMSTATCOL - 6, "%%slo-z"); 348 mvprintw(VMSTATROW + 14, VMSTATCOL - 6, "tfree"); 349 extended_vm_stats = 1; 350 } else { 351 extended_vm_stats = 0; 352 mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "zfod"); 353 } 354 355 for (i = 0; i < nintr; i++) { 356 if (intrloc[i] == 0) 357 continue; 358 mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s", intrname[i]); 359 } 360 } 361 362 #define CP_UPDATE(fld) do { \ 363 uint64_t lt; \ 364 lt=s.fld; \ 365 s.fld-=s1.fld; \ 366 if(state==TIME) \ 367 s1.fld=lt; \ 368 lt=fld; \ 369 fld-=old_##fld; \ 370 if(state==TIME) \ 371 old_##fld=lt; \ 372 etime += s.fld; \ 373 } while(0) 374 #define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;} 375 #define Y(fld) {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;} 376 #define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \ 377 if(state == TIME) s1.nchstats.fld = t;} 378 #define PUTRATE(fld, l, c, w) \ 379 Y(fld); \ 380 putlong((long)((float)s.fld/etime + 0.5), l, c, w, 'D') 381 #define MAXFAIL 5 382 383 #define CPUSTATES 5 384 static const char cpuchar[5] = { '=' , '+', '>', '-', ' ' }; 385 386 static const size_t cpuoffsets[] = { 387 offsetof(struct kinfo_cputime, cp_sys), 388 offsetof(struct kinfo_cputime, cp_intr), 389 offsetof(struct kinfo_cputime, cp_user), 390 offsetof(struct kinfo_cputime, cp_nice), 391 offsetof(struct kinfo_cputime, cp_idle) 392 }; 393 394 void 395 showkre(void) 396 { 397 float f1, f2; 398 int psiz; 399 int i, lc; 400 long inttotal; 401 long l; 402 static int failcnt = 0; 403 double total_time; 404 405 etime = 0; 406 CP_UPDATE(cp_time.cp_user); 407 CP_UPDATE(cp_time.cp_nice); 408 CP_UPDATE(cp_time.cp_sys); 409 CP_UPDATE(cp_time.cp_intr); 410 CP_UPDATE(cp_time.cp_idle); 411 412 total_time = etime; 413 if (total_time == 0.0) 414 total_time = 1.0; 415 416 if (etime < 100000.0) { /* < 100ms ignore this trash */ 417 if (failcnt++ >= MAXFAIL) { 418 clear(); 419 mvprintw(2, 10, "The alternate system clock has died!"); 420 mvprintw(3, 10, "Reverting to ``pigs'' display."); 421 move(CMDLINE, 0); 422 refresh(); 423 failcnt = 0; 424 sleep(5); 425 command("pigs"); 426 } 427 return; 428 } 429 failcnt = 0; 430 etime /= 1000000.0; 431 etime /= ncpu; 432 if (etime == 0) 433 etime = 1; 434 inttotal = 0; 435 for (i = 0; i < nintr; i++) { 436 if (s.intrcnt[i] == 0) 437 continue; 438 if (intrloc[i] == 0) { 439 if (nextintsrow == LINES) 440 continue; 441 intrloc[i] = nextintsrow++; 442 mvprintw(intrloc[i], INTSCOL + 9, "%-10.10s", 443 intrname[i]); 444 } 445 X(intrcnt); 446 l = (long)((float)s.intrcnt[i]/etime + 0.5); 447 inttotal += l; 448 putlong(l, intrloc[i], INTSCOL + 2, 6, 'D'); 449 } 450 putlong(inttotal, INTSROW + 1, INTSCOL + 2, 6, 'D'); 451 Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss); 452 Z(ncs_longhits); Z(ncs_longmiss); Z(ncs_neghits); 453 s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits + 454 nchtotal.ncs_miss + nchtotal.ncs_neghits; 455 s.nchpathcount = nchtotal.ncs_longhits + nchtotal.ncs_longmiss; 456 if (state == TIME) { 457 s1.nchcount = s.nchcount; 458 s1.nchpathcount = s.nchpathcount; 459 } 460 461 psiz = 0; 462 f2 = 0.0; 463 for (lc = 0; lc < CPUSTATES; lc++) { 464 uint64_t val = *(uint64_t *)(((uint8_t *)&s.cp_time) + 465 cpuoffsets[lc]); 466 f1 = 100.0 * val / total_time; 467 f2 += f1; 468 l = (int) ((f2 + 1.0) / 2.0) - psiz; 469 if (f1 > 99.9) 470 f1 = 99.9; /* no room to display 100.0 */ 471 putfloat(f1, GRAPHROW, GRAPHCOL + 10 * lc, 4, 1, 0); 472 move(GRAPHROW + 2, psiz); 473 psiz += l; 474 while (l-- > 0) 475 addch(cpuchar[lc]); 476 } 477 478 putlong(ucount(), STATROW, STATCOL, 3, 'D'); 479 putfloat(avenrun[0], STATROW, STATCOL + 18, 6, 2, 0); 480 putfloat(avenrun[1], STATROW, STATCOL + 25, 6, 2, 0); 481 putfloat(avenrun[2], STATROW, STATCOL + 32, 6, 2, 0); 482 mvaddstr(STATROW, STATCOL + 53, buf); 483 #define pgtokb(pg) (long)((intmax_t)(pg) * vms.v_page_size / 1024) 484 #define pgtomb(pg) (long)((intmax_t)(pg) * vms.v_page_size / (1024 * 1024)) 485 putlong(pgtomb(total.t_arm), MEMROW + 2, MEMCOL + 3, 8, 'M'); 486 putlong(pgtomb(total.t_armshr), MEMROW + 2, MEMCOL + 11, 8, 'M'); 487 putlong(pgtomb(total.t_avm), MEMROW + 2, MEMCOL + 19, 9, 'M'); 488 putlong(pgtomb(total.t_avmshr), MEMROW + 2, MEMCOL + 28, 9, 'M'); 489 putlong(pgtomb(total.t_rm), MEMROW + 3, MEMCOL + 3, 8, 'M'); 490 putlong(pgtomb(total.t_rmshr), MEMROW + 3, MEMCOL + 11, 8, 'M'); 491 putlong(pgtomb(total.t_vm), MEMROW + 3, MEMCOL + 19, 9, 'M'); 492 putlong(pgtomb(total.t_vmshr), MEMROW + 3, MEMCOL + 28, 9, 'M'); 493 putlong(pgtomb(total.t_free), MEMROW + 2, MEMCOL + 37, 8, 'M'); 494 putlong(total.t_rq - 1, PROCSROW + 1, PROCSCOL + 0, 3, 'D'); 495 putlong(total.t_pw, PROCSROW + 1, PROCSCOL + 3, 3, 'D'); 496 putlong(total.t_dw, PROCSROW + 1, PROCSCOL + 6, 3, 'D'); 497 putlong(total.t_sl, PROCSROW + 1, PROCSCOL + 9, 3, 'D'); 498 putlong(total.t_sw, PROCSROW + 1, PROCSCOL + 12, 3, 'D'); 499 if (extended_vm_stats == 0) { 500 PUTRATE(Vmm.v_zfod, VMSTATROW + 0, VMSTATCOL + 4, 5); 501 } 502 PUTRATE(Vmm.v_cow_faults, VMSTATROW + 1, VMSTATCOL + 3, 6); 503 putlong(pgtokb(vms.v_wire_count), VMSTATROW + 2, VMSTATCOL, 9, 'K'); 504 putlong(pgtokb(vms.v_active_count), VMSTATROW + 3, VMSTATCOL, 9, 'K'); 505 putlong(pgtokb(vms.v_inactive_count), VMSTATROW + 4, VMSTATCOL, 9, 'K'); 506 putlong(pgtokb(vms.v_cache_count), VMSTATROW + 5, VMSTATCOL, 9, 'K'); 507 putlong(pgtokb(vms.v_free_count), VMSTATROW + 6, VMSTATCOL, 9, 'K'); 508 PUTRATE(Vmm.v_dfree, VMSTATROW + 7, VMSTATCOL, 9); 509 PUTRATE(Vmm.v_pfree, VMSTATROW + 8, VMSTATCOL, 9); 510 PUTRATE(Vmm.v_reactivated, VMSTATROW + 9, VMSTATCOL, 9); 511 PUTRATE(Vmm.v_pdwakeups, VMSTATROW + 10, VMSTATCOL, 9); 512 PUTRATE(Vmm.v_pdpages, VMSTATROW + 11, VMSTATCOL, 9); 513 PUTRATE(Vmm.v_intrans, VMSTATROW + 12, VMSTATCOL, 9); 514 515 if (extended_vm_stats) { 516 PUTRATE(Vmm.v_zfod, VMSTATROW + 11, VMSTATCOL - 16, 9); 517 PUTRATE(Vmm.v_ozfod, VMSTATROW + 12, VMSTATCOL - 16, 9); 518 #define nz(x) ((x) ? (x) : 1) 519 putlong((s.Vmm.v_zfod - s.Vmm.v_ozfod) * 100 / nz(s.Vmm.v_zfod), 520 VMSTATROW + 13, VMSTATCOL - 16, 9, 'D'); 521 #undef nz 522 PUTRATE(Vmm.v_tfree, VMSTATROW + 14, VMSTATCOL - 16, 9); 523 } 524 525 putlong(s.bufspace/1024, VMSTATROW + 13, VMSTATCOL, 9, 'K'); 526 putlong(s.dirtybufspace/1024, VMSTATROW + 14, VMSTATCOL, 9, 'K'); 527 putlong(s.desiredvnodes, VMSTATROW + 15, VMSTATCOL, 9, 'D'); 528 putlong(s.numvnodes, VMSTATROW + 16, VMSTATCOL, 9, 'D'); 529 putlong(s.freevnodes, VMSTATROW + 17, VMSTATCOL, 9, 'D'); 530 PUTRATE(Vmm.v_vnodein, PAGEROW + 2, PAGECOL + 5, 5); 531 PUTRATE(Vmm.v_vnodeout, PAGEROW + 2, PAGECOL + 10, 5); 532 PUTRATE(Vmm.v_swapin, PAGEROW + 2, PAGECOL + 17, 5); 533 PUTRATE(Vmm.v_swapout, PAGEROW + 2, PAGECOL + 22, 5); 534 PUTRATE(Vmm.v_vnodepgsin, PAGEROW + 3, PAGECOL + 5, 5); 535 PUTRATE(Vmm.v_vnodepgsout, PAGEROW + 3, PAGECOL + 10, 5); 536 PUTRATE(Vmm.v_swappgsin, PAGEROW + 3, PAGECOL + 17, 5); 537 PUTRATE(Vmm.v_swappgsout, PAGEROW + 3, PAGECOL + 22, 5); 538 PUTRATE(Vmm.v_swtch, GENSTATROW + 1, GENSTATCOL, 5); 539 PUTRATE(Vmm.v_trap, GENSTATROW + 1, GENSTATCOL + 6, 5); 540 PUTRATE(Vmm.v_syscall, GENSTATROW + 1, GENSTATCOL + 12, 5); 541 PUTRATE(Vmm.v_intr, GENSTATROW + 1, GENSTATCOL + 18, 5); 542 PUTRATE(Vmm.v_soft, GENSTATROW + 1, GENSTATCOL + 23, 5); 543 PUTRATE(Vmm.v_vm_faults, GENSTATROW + 1, GENSTATCOL + 29, 5); 544 mvprintw(DISKROW, DISKCOL + 5, " "); 545 for (i = 0, lc = 0; i < num_devices && lc < MAXDRIVES; i++) 546 if (dev_select[i].selected) { 547 char tmpstr[80]; 548 sprintf(tmpstr, "%s%d", dev_select[i].device_name, 549 dev_select[i].unit_number); 550 mvprintw(DISKROW, DISKCOL + 5 + 6 * lc, 551 " %5.5s", tmpstr); 552 switch(state) { 553 case TIME: 554 dinfo(i, ++lc, &cur, &last); 555 break; 556 case RUN: 557 dinfo(i, ++lc, &cur, &run); 558 break; 559 case BOOT: 560 dinfo(i, ++lc, &cur, NULL); 561 break; 562 } 563 } 564 #define nz(x) ((x) ? (x) : 1) 565 putlong(s.nchpathcount, NAMEIROW + 1, NAMEICOL + 3, 9, 'D'); 566 567 putlong(nchtotal.ncs_longhits, NAMEIROW + 1, NAMEICOL + 12, 7, 'D'); 568 putfloat(nchtotal.ncs_longhits * 100.0 / nz(s.nchpathcount), 569 NAMEIROW + 1, NAMEICOL + 19, 4, 0, 0); 570 571 putfloat((double)s.nchcount / nz(s.nchpathcount), 572 NAMEIROW + 1, NAMEICOL + 27, 5, 2, 1); 573 #undef nz 574 } 575 576 int 577 cmdkre(const char *cmd, char *args) 578 { 579 int retval; 580 581 if (prefix(cmd, "run")) { 582 retval = 1; 583 copyinfo(&s2, &s1); 584 switch (getdevs(&run)) { 585 case -1: 586 errx(1, "%s", devstat_errbuf); 587 break; 588 case 1: 589 num_devices = run.dinfo->numdevs; 590 generation = run.dinfo->generation; 591 retval = dscmd("refresh", NULL, MAXDRIVES, &cur); 592 if (retval == 2) 593 labelkre(); 594 break; 595 default: 596 break; 597 } 598 state = RUN; 599 return (retval); 600 } 601 if (prefix(cmd, "boot")) { 602 state = BOOT; 603 copyinfo(&z, &s1); 604 return (1); 605 } 606 if (prefix(cmd, "time")) { 607 state = TIME; 608 return (1); 609 } 610 if (prefix(cmd, "zero")) { 611 retval = 1; 612 if (state == RUN) { 613 getinfo(&s1); 614 switch (getdevs(&run)) { 615 case -1: 616 errx(1, "%s", devstat_errbuf); 617 break; 618 case 1: 619 num_devices = run.dinfo->numdevs; 620 generation = run.dinfo->generation; 621 retval = dscmd("refresh",NULL, MAXDRIVES, &cur); 622 if (retval == 2) 623 labelkre(); 624 break; 625 default: 626 break; 627 } 628 } 629 return (retval); 630 } 631 retval = dscmd(cmd, args, MAXDRIVES, &cur); 632 633 if (retval == 2) 634 labelkre(); 635 636 return(retval); 637 } 638 639 /* calculate number of users on the system */ 640 static int 641 ucount(void) 642 { 643 struct utmpentry *ep; 644 int nusers = 0; 645 646 getutentries(NULL, &ep); 647 for (; ep; ep = ep->next) 648 nusers++; 649 650 return (nusers); 651 } 652 653 static void 654 putlong(long n, int l, int lc, int w, int type) 655 { 656 char b[128]; 657 int xtype; 658 659 move(l, lc); 660 if (n == 0) { 661 while (w-- > 0) 662 addch(' '); 663 return; 664 } 665 snprintf(b, sizeof(b), "%*ld", w, n); 666 if (strlen(b) > (size_t)w) { 667 if (type == 'D') { 668 n /= 1000; 669 xtype = 'K'; 670 } else { 671 n /= 1024; 672 xtype = 'M'; 673 } 674 snprintf(b, sizeof(b), "%*ld%c", w - 1, n, xtype); 675 if (strlen(b) > (size_t)w) { 676 if (type == 'D') { 677 n /= 1000; 678 xtype = 'M'; 679 } else { 680 n /= 1024; 681 xtype = 'G'; 682 } 683 snprintf(b, sizeof(b), "%*ld%c", w - 1, n, xtype); 684 if (strlen(b) > (size_t)w) { 685 while (w-- > 0) 686 addch('*'); 687 return; 688 } 689 } 690 } 691 addstr(b); 692 } 693 694 static void 695 putfloat(double f, int l, int lc, int w, int d, int nz) 696 { 697 char b[128]; 698 699 move(l, lc); 700 if (nz && f == 0.0) { 701 while (--w >= 0) 702 addch(' '); 703 return; 704 } 705 snprintf(b, sizeof(b), "%*.*f", w, d, f); 706 if (strlen(b) > (size_t)w) 707 snprintf(b, sizeof(b), "%*.0f", w, f); 708 if (strlen(b) > (size_t)w) { 709 while (--w >= 0) 710 addch('*'); 711 return; 712 } 713 addstr(b); 714 } 715 716 static void 717 putlongdouble(long double f, int l, int lc, int w, int d, int nz) 718 { 719 char b[128]; 720 721 move(l, lc); 722 if (nz && f == 0.0) { 723 while (--w >= 0) 724 addch(' '); 725 return; 726 } 727 sprintf(b, "%*.*Lf", w, d, f); 728 if (strlen(b) > (size_t)w) 729 sprintf(b, "%*.0Lf", w, f); 730 if (strlen(b) > (size_t)w) { 731 while (--w >= 0) 732 addch('*'); 733 return; 734 } 735 addstr(b); 736 } 737 738 static void 739 putlongdoublez(long double f, int l, int lc, int w, int d, int nz) 740 { 741 char b[128]; 742 743 if (f == 0.0) { 744 move(l, lc); 745 sprintf(b, "%*.*s", w, w, ""); 746 addstr(b); 747 } else { 748 putlongdouble(f, l, lc, w, d, nz); 749 } 750 } 751 752 static void 753 getinfo(struct Info *ls) 754 { 755 struct devinfo *tmp_dinfo; 756 struct nchstats *nch_tmp; 757 size_t size; 758 size_t vms_size = sizeof(ls->Vms); 759 size_t vmm_size = sizeof(ls->Vmm); 760 size_t nch_size = sizeof(ls->nchstats) * SMP_MAXCPU; 761 762 if (sysctlbyname("vm.vmstats", &ls->Vms, &vms_size, NULL, 0)) { 763 perror("sysctlbyname: vm.vmstats"); 764 exit(1); 765 } 766 if (sysctlbyname("vm.vmmeter", &ls->Vmm, &vmm_size, NULL, 0)) { 767 perror("sysctlbyname: vm.vmstats"); 768 exit(1); 769 } 770 771 if (kinfo_get_sched_cputime(&ls->cp_time)) 772 err(1, "kinfo_get_sched_cputime"); 773 if (kinfo_get_sched_cputime(&cp_time)) 774 err(1, "kinfo_get_sched_cputime"); 775 NREAD(X_BUFFERSPACE, &ls->bufspace, sizeof(ls->bufspace)); 776 NREAD(X_DESIREDVNODES, &ls->desiredvnodes, sizeof(ls->desiredvnodes)); 777 NREAD(X_NUMVNODES, &ls->numvnodes, sizeof(ls->numvnodes)); 778 NREAD(X_FREEVNODES, &ls->freevnodes, sizeof(ls->freevnodes)); 779 NREAD(X_NUMDIRTYBUFFERS, &ls->dirtybufspace, sizeof(ls->dirtybufspace)); 780 781 if (nintr) { 782 size = nintr * sizeof(ls->intrcnt[0]); 783 sysctlbyname("hw.intrcnt", ls->intrcnt, &size, NULL, 0); 784 } 785 size = sizeof(ls->Total); 786 if (sysctlbyname("vm.vmtotal", &ls->Total, &size, NULL, 0) < 0) { 787 error("Can't get kernel info: %s\n", strerror(errno)); 788 bzero(&ls->Total, sizeof(ls->Total)); 789 } 790 791 if ((nch_tmp = malloc(nch_size)) == NULL) { 792 perror("malloc"); 793 exit(1); 794 } else { 795 if (sysctlbyname("vfs.cache.nchstats", nch_tmp, &nch_size, NULL, 0)) { 796 perror("sysctlbyname vfs.cache.nchstats"); 797 free(nch_tmp); 798 exit(1); 799 } else { 800 if ((nch_tmp = realloc(nch_tmp, nch_size)) == NULL) { 801 perror("realloc"); 802 exit(1); 803 } 804 } 805 } 806 807 if (kinfo_get_cpus(&ncpu)) 808 err(1, "kinfo_get_cpus"); 809 kvm_nch_cpuagg(nch_tmp, &ls->nchstats, ncpu); 810 free(nch_tmp); 811 812 tmp_dinfo = last.dinfo; 813 last.dinfo = cur.dinfo; 814 cur.dinfo = tmp_dinfo; 815 816 last.busy_time = cur.busy_time; 817 switch (getdevs(&cur)) { 818 case -1: 819 errx(1, "%s", devstat_errbuf); 820 break; 821 case 1: 822 num_devices = cur.dinfo->numdevs; 823 generation = cur.dinfo->generation; 824 cmdkre("refresh", NULL); 825 break; 826 default: 827 break; 828 } 829 } 830 831 static void 832 allocinfo(struct Info *ls) 833 { 834 ls->intrcnt = (long *) calloc(nintr, sizeof(long)); 835 if (ls->intrcnt == NULL) 836 errx(2, "out of memory"); 837 } 838 839 static void 840 copyinfo(struct Info *from, struct Info *to) 841 { 842 long *intrcnt; 843 844 /* 845 * time, wds, seek, and xfer are malloc'd so we have to 846 * save the pointers before the structure copy and then 847 * copy by hand. 848 */ 849 intrcnt = to->intrcnt; 850 *to = *from; 851 852 bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int)); 853 } 854 855 static void 856 dinfo(int dn, int lc, struct statinfo *now, struct statinfo *then) 857 { 858 long double kb_per_transfer; 859 long double transfers_per_secondr; 860 long double transfers_per_secondw; 861 long double mb_per_secondr; 862 long double mb_per_secondw; 863 long double elapsed_time, device_busy; 864 int di; 865 866 di = dev_select[dn].position; 867 868 elapsed_time = compute_etime(now->busy_time, then ? 869 then->busy_time : 870 now->dinfo->devices[di].dev_creation_time); 871 872 device_busy = compute_etime(now->dinfo->devices[di].busy_time, then ? 873 then->dinfo->devices[di].busy_time : 874 now->dinfo->devices[di].dev_creation_time); 875 876 if (compute_stats( 877 &now->dinfo->devices[di], 878 (then ? &then->dinfo->devices[di] : NULL), 879 elapsed_time, 880 NULL, NULL, NULL, 881 &kb_per_transfer, 882 NULL, 883 NULL, 884 NULL, NULL) != 0) 885 errx(1, "%s", devstat_errbuf); 886 887 if (compute_stats_read( 888 &now->dinfo->devices[di], 889 (then ? &then->dinfo->devices[di] : NULL), 890 elapsed_time, 891 NULL, NULL, NULL, 892 NULL, 893 &transfers_per_secondr, 894 &mb_per_secondr, 895 NULL, NULL) != 0) 896 errx(1, "%s", devstat_errbuf); 897 898 if (compute_stats_write( 899 &now->dinfo->devices[di], 900 (then ? &then->dinfo->devices[di] : NULL), 901 elapsed_time, 902 NULL, NULL, NULL, 903 NULL, 904 &transfers_per_secondw, 905 &mb_per_secondw, 906 NULL, NULL) != 0) 907 errx(1, "%s", devstat_errbuf); 908 909 if ((device_busy == 0) && 910 (transfers_per_secondr > 5 || transfers_per_secondw > 5)) { 911 /* the device has been 100% busy, fake it because 912 * as long as the device is 100% busy the busy_time 913 * field in the devstat struct is not updated */ 914 device_busy = elapsed_time; 915 } 916 if (device_busy > elapsed_time) { 917 /* this normally happens after one or more periods 918 * where the device has been 100% busy, correct it */ 919 device_busy = elapsed_time; 920 } 921 922 lc = DISKCOL + lc * 6; 923 putlongdoublez(kb_per_transfer, DISKROW + 1, lc, 5, 2, 0); 924 putlongdoublez(transfers_per_secondr, DISKROW + 2, lc, 5, 0, 0); 925 putlongdoublez(mb_per_secondr, DISKROW + 3, lc, 5, 2, 0); 926 putlongdoublez(transfers_per_secondw, DISKROW + 4, lc, 5, 0, 0); 927 putlongdoublez(mb_per_secondw, DISKROW + 5, lc, 5, 2, 0); 928 putlongdouble(device_busy * 100 / elapsed_time, 929 DISKROW + 6, lc, 5, 0, 0); 930 } 931