1 1.262 skrll /* $NetBSD: vmstat.c,v 1.262 2025/02/16 10:56:31 skrll Exp $ */ 2 1.45 thorpej 3 1.45 thorpej /*- 4 1.235 ad * Copyright (c) 1998, 2000, 2001, 2007, 2019, 2020 5 1.235 ad * The NetBSD Foundation, Inc. 6 1.45 thorpej * All rights reserved. 7 1.45 thorpej * 8 1.87 lukem * This code is derived from software contributed to The NetBSD Foundation by: 9 1.87 lukem * - Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 1.87 lukem * NASA Ames Research Center. 11 1.87 lukem * - Simon Burge and Luke Mewburn of Wasabi Systems, Inc. 12 1.45 thorpej * 13 1.45 thorpej * Redistribution and use in source and binary forms, with or without 14 1.45 thorpej * modification, are permitted provided that the following conditions 15 1.45 thorpej * are met: 16 1.45 thorpej * 1. Redistributions of source code must retain the above copyright 17 1.45 thorpej * notice, this list of conditions and the following disclaimer. 18 1.45 thorpej * 2. Redistributions in binary form must reproduce the above copyright 19 1.45 thorpej * notice, this list of conditions and the following disclaimer in the 20 1.45 thorpej * documentation and/or other materials provided with the distribution. 21 1.45 thorpej * 22 1.45 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 1.45 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 1.45 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 1.45 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 1.45 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 1.45 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 1.45 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 1.45 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 1.45 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 1.45 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 1.45 thorpej * POSSIBILITY OF SUCH DAMAGE. 33 1.45 thorpej */ 34 1.21 cgd 35 1.1 cgd /* 36 1.13 cgd * Copyright (c) 1980, 1986, 1991, 1993 37 1.13 cgd * The Regents of the University of California. All rights reserved. 38 1.1 cgd * 39 1.1 cgd * Redistribution and use in source and binary forms, with or without 40 1.1 cgd * modification, are permitted provided that the following conditions 41 1.1 cgd * are met: 42 1.1 cgd * 1. Redistributions of source code must retain the above copyright 43 1.1 cgd * notice, this list of conditions and the following disclaimer. 44 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 cgd * notice, this list of conditions and the following disclaimer in the 46 1.1 cgd * documentation and/or other materials provided with the distribution. 47 1.117 agc * 3. Neither the name of the University nor the names of its contributors 48 1.1 cgd * may be used to endorse or promote products derived from this software 49 1.1 cgd * without specific prior written permission. 50 1.1 cgd * 51 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 1.1 cgd * SUCH DAMAGE. 62 1.1 cgd */ 63 1.1 cgd 64 1.38 mrg #include <sys/cdefs.h> 65 1.1 cgd #ifndef lint 66 1.161 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\ 67 1.161 lukem The Regents of the University of California. All rights reserved."); 68 1.1 cgd #endif /* not lint */ 69 1.1 cgd 70 1.1 cgd #ifndef lint 71 1.21 cgd #if 0 72 1.37 mrg static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; 73 1.21 cgd #else 74 1.262 skrll __RCSID("$NetBSD: vmstat.c,v 1.262 2025/02/16 10:56:31 skrll Exp $"); 75 1.21 cgd #endif 76 1.1 cgd #endif /* not lint */ 77 1.57 thorpej 78 1.57 thorpej #define __POOL_EXPOSE 79 1.228 christos #define __NAMECACHE_PRIVATE 80 1.1 cgd 81 1.1 cgd #include <sys/param.h> 82 1.174 christos #include <sys/types.h> 83 1.87 lukem #include <sys/mount.h> 84 1.87 lukem #include <sys/uio.h> 85 1.87 lukem 86 1.87 lukem #include <sys/buf.h> 87 1.146 yamt #include <sys/evcnt.h> 88 1.87 lukem #include <sys/ioctl.h> 89 1.87 lukem #include <sys/malloc.h> 90 1.109 thorpej #include <sys/mallocvar.h> 91 1.1 cgd #include <sys/namei.h> 92 1.87 lukem #include <sys/pool.h> 93 1.87 lukem #include <sys/proc.h> 94 1.64 perry #include <sys/sched.h> 95 1.87 lukem #include <sys/socket.h> 96 1.13 cgd #include <sys/sysctl.h> 97 1.87 lukem #include <sys/time.h> 98 1.171 christos #include <sys/queue.h> 99 1.181 mrg #include <sys/kernhist.h> 100 1.229 ad #include <sys/vnode.h> 101 1.229 ad #include <sys/vnode_impl.h> 102 1.258 ad #include <sys/uidinfo.h> 103 1.67 mrg 104 1.67 mrg #include <uvm/uvm_extern.h> 105 1.67 mrg #include <uvm/uvm_stat.h> 106 1.67 mrg 107 1.87 lukem #include <net/if.h> 108 1.87 lukem #include <netinet/in.h> 109 1.87 lukem #include <netinet/in_var.h> 110 1.87 lukem 111 1.87 lukem #include <ufs/ufs/inode.h> 112 1.87 lukem 113 1.87 lukem #include <nfs/rpcv2.h> 114 1.87 lukem #include <nfs/nfsproto.h> 115 1.87 lukem #include <nfs/nfsnode.h> 116 1.87 lukem 117 1.245 simonb #include <assert.h> 118 1.87 lukem #include <ctype.h> 119 1.45 thorpej #include <err.h> 120 1.87 lukem #include <errno.h> 121 1.55 kleink #include <fcntl.h> 122 1.87 lukem #include <kvm.h> 123 1.87 lukem #include <limits.h> 124 1.1 cgd #include <nlist.h> 125 1.87 lukem #undef n_hash 126 1.87 lukem #include <paths.h> 127 1.22 jtc #include <signal.h> 128 1.1 cgd #include <stdio.h> 129 1.87 lukem #include <stddef.h> 130 1.1 cgd #include <stdlib.h> 131 1.1 cgd #include <string.h> 132 1.87 lukem #include <time.h> 133 1.87 lukem #include <unistd.h> 134 1.104 mrg #include <util.h> 135 1.87 lukem 136 1.140 blymn #include "drvstats.h" 137 1.45 thorpej 138 1.90 lukem /* 139 1.174 christos * All this mess will go away once everything is converted. 140 1.174 christos */ 141 1.174 christos #ifdef __HAVE_CPU_DATA_FIRST 142 1.175 christos 143 1.175 christos # include <sys/cpu_data.h> 144 1.175 christos struct cpu_info { 145 1.174 christos struct cpu_data ci_data; 146 1.174 christos }; 147 1.174 christos #else 148 1.190 rmind # include <sys/cpu.h> 149 1.190 rmind #endif 150 1.175 christos 151 1.174 christos /* 152 1.90 lukem * General namelist 153 1.90 lukem */ 154 1.87 lukem struct nlist namelist[] = 155 1.87 lukem { 156 1.232 mrg #define X_HZ 0 157 1.153 christos { .n_name = "_hz" }, 158 1.232 mrg #define X_STATHZ 1 159 1.153 christos { .n_name = "_stathz" }, 160 1.232 mrg #define X_NCHSTATS 2 161 1.153 christos { .n_name = "_nchstats" }, 162 1.232 mrg #define X_ALLEVENTS 3 163 1.153 christos { .n_name = "_allevents" }, 164 1.232 mrg #define X_POOLHEAD 4 165 1.153 christos { .n_name = "_pool_head" }, 166 1.232 mrg #define X_UVMEXP 5 167 1.153 christos { .n_name = "_uvmexp" }, 168 1.232 mrg #define X_CPU_INFOS 6 169 1.232 mrg { .n_name = "_cpu_infos" }, 170 1.232 mrg #define X_NL_SIZE 7 171 1.232 mrg { .n_name = NULL }, 172 1.232 mrg }; 173 1.232 mrg 174 1.232 mrg /* 175 1.232 mrg * Namelist for time data. 176 1.232 mrg */ 177 1.232 mrg struct nlist timenl[] = 178 1.232 mrg { 179 1.232 mrg #define X_TIMEBASEBIN 0 180 1.232 mrg { .n_name = "_timebasebin" }, 181 1.232 mrg #define X_TIME_SECOND 1 182 1.153 christos { .n_name = "_time_second" }, 183 1.232 mrg #define X_TIME 2 184 1.153 christos { .n_name = "_time" }, 185 1.232 mrg #define X_TIMENL_SIZE 3 186 1.153 christos { .n_name = NULL }, 187 1.90 lukem }; 188 1.90 lukem 189 1.90 lukem /* 190 1.133 chs * Namelist for pre-evcnt interrupt counters. 191 1.133 chs */ 192 1.133 chs struct nlist intrnl[] = 193 1.133 chs { 194 1.133 chs #define X_INTRNAMES 0 195 1.153 christos { .n_name = "_intrnames" }, 196 1.133 chs #define X_EINTRNAMES 1 197 1.153 christos { .n_name = "_eintrnames" }, 198 1.133 chs #define X_INTRCNT 2 199 1.153 christos { .n_name = "_intrcnt" }, 200 1.133 chs #define X_EINTRCNT 3 201 1.153 christos { .n_name = "_eintrcnt" }, 202 1.133 chs #define X_INTRNL_SIZE 4 203 1.153 christos { .n_name = NULL }, 204 1.133 chs }; 205 1.133 chs 206 1.133 chs 207 1.133 chs /* 208 1.90 lukem * Namelist for hash statistics 209 1.90 lukem */ 210 1.90 lukem struct nlist hashnl[] = 211 1.90 lukem { 212 1.245 simonb #define X_BUFHASH 0 213 1.153 christos { .n_name = "_bufhash" }, 214 1.245 simonb #define X_BUFHASHTBL 1 215 1.153 christos { .n_name = "_bufhashtbl" }, 216 1.245 simonb #define X_UIHASH 2 217 1.153 christos { .n_name = "_uihash" }, 218 1.245 simonb #define X_UIHASHTBL 3 219 1.153 christos { .n_name = "_uihashtbl" }, 220 1.245 simonb #define X_IFADDRHASH 4 221 1.153 christos { .n_name = "_in_ifaddrhash" }, 222 1.245 simonb #define X_IFADDRHASHTBL 5 223 1.153 christos { .n_name = "_in_ifaddrhashtbl" }, 224 1.245 simonb #define X_VCACHEHASH 6 225 1.229 ad { .n_name = "_vcache_hashmask" }, 226 1.245 simonb #define X_VCACHETBL 7 227 1.229 ad { .n_name = "_vcache_hashtab" }, 228 1.245 simonb #define X_HASHNL_SIZE 8 /* must be last */ 229 1.153 christos { .n_name = NULL }, 230 1.90 lukem }; 231 1.87 lukem 232 1.90 lukem /* 233 1.181 mrg * Namelist for kernel histories 234 1.90 lukem */ 235 1.90 lukem struct nlist histnl[] = 236 1.90 lukem { 237 1.181 mrg { .n_name = "_kern_histories" }, 238 1.181 mrg #define X_KERN_HISTORIES 0 239 1.153 christos { .n_name = NULL }, 240 1.1 cgd }; 241 1.1 cgd 242 1.87 lukem 243 1.205 skrll #define KILO 1024 244 1.90 lukem 245 1.171 christos struct cpu_counter { 246 1.171 christos uint64_t nintr; 247 1.171 christos uint64_t nsyscall; 248 1.171 christos uint64_t nswtch; 249 1.171 christos uint64_t nfault; 250 1.171 christos uint64_t ntrap; 251 1.171 christos uint64_t nsoft; 252 1.171 christos } cpucounter, ocpucounter; 253 1.171 christos 254 1.196 joerg struct uvmexp_sysctl uvmexp, ouvmexp; 255 1.73 simonb int ndrives; 256 1.1 cgd 257 1.1 cgd int winlines = 20; 258 1.1 cgd 259 1.13 cgd kvm_t *kd; 260 1.13 cgd 261 1.174 christos 262 1.185 christos #define FORKSTAT 0x001 263 1.185 christos #define INTRSTAT 0x002 264 1.185 christos #define MEMSTAT 0x004 265 1.185 christos #define SUMSTAT 0x008 266 1.185 christos #define EVCNTSTAT 0x010 267 1.185 christos #define VMSTAT 0x020 268 1.185 christos #define HISTLIST 0x040 269 1.185 christos #define HISTDUMP 0x080 270 1.185 christos #define HASHSTAT 0x100 271 1.185 christos #define HASHLIST 0x200 272 1.185 christos #define VMTOTAL 0x400 273 1.185 christos #define POOLCACHESTAT 0x800 274 1.1 cgd 275 1.151 yamt /* 276 1.151 yamt * Print single word. `ovflow' is number of characters didn't fit 277 1.151 yamt * on the last word. `fmt' is a format string to print this word. 278 1.151 yamt * It must contain asterisk for field width. `width' is a width 279 1.151 yamt * occupied by this word. `fixed' is a number of constant chars in 280 1.151 yamt * `fmt'. `val' is a value to be printed using format string `fmt'. 281 1.151 yamt */ 282 1.151 yamt #define PRWORD(ovflw, fmt, width, fixed, val) do { \ 283 1.151 yamt (ovflw) += printf((fmt), \ 284 1.151 yamt (width) - (fixed) - (ovflw) > 0 ? \ 285 1.151 yamt (width) - (fixed) - (ovflw) : 0, \ 286 1.151 yamt (val)) - (width); \ 287 1.151 yamt if ((ovflw) < 0) \ 288 1.151 yamt (ovflw) = 0; \ 289 1.248 rillig } while (0) 290 1.151 yamt 291 1.151 yamt void cpustats(int *); 292 1.171 christos void cpucounters(struct cpu_counter *); 293 1.87 lukem void deref_kptr(const void *, void *, size_t, const char *); 294 1.151 yamt void drvstats(int *); 295 1.176 matt void doevcnt(int verbose, int type); 296 1.88 lukem void dohashstat(int, int, const char *); 297 1.245 simonb void dohashstat_sysctl(int, int, const char *); 298 1.73 simonb void dointr(int verbose); 299 1.126 simonb void dopool(int, int); 300 1.182 yamt void dopoolcache(int); 301 1.73 simonb void dosum(void); 302 1.103 mycroft void dovmstat(struct timespec *, int); 303 1.130 he void print_total_hdr(void); 304 1.130 he void dovmtotal(struct timespec *, int); 305 1.133 chs void kread(struct nlist *, int, void *, size_t); 306 1.147 kardel int kreadc(struct nlist *, int, void *, size_t); 307 1.73 simonb void needhdr(int); 308 1.176 matt void getnlist(int); 309 1.73 simonb long getuptime(void); 310 1.73 simonb void printhdr(void); 311 1.203 nakayama long pct(u_long, u_long); 312 1.183 joerg __dead static void usage(void); 313 1.73 simonb void doforkst(void); 314 1.73 simonb 315 1.73 simonb void hist_traverse(int, const char *); 316 1.210 pgoyette void hist_dodump(struct kern_history *); 317 1.210 pgoyette void hist_traverse_sysctl(int, const char *); 318 1.210 pgoyette void hist_dodump_sysctl(int[], unsigned int); 319 1.73 simonb 320 1.73 simonb char **choosedrives(char **); 321 1.38 mrg 322 1.29 thorpej /* Namelist and memory file names. */ 323 1.29 thorpej char *nlistf, *memf; 324 1.29 thorpej 325 1.47 mrg /* allow old usage [vmstat 1] */ 326 1.47 mrg #define BACKWARD_COMPATIBILITY 327 1.47 mrg 328 1.197 joerg static const int clockrate_mib[] = { CTL_KERN, KERN_CLOCKRATE }; 329 1.170 christos static const int vmmeter_mib[] = { CTL_VM, VM_METER }; 330 1.170 christos static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 }; 331 1.176 matt static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME }; 332 1.170 christos 333 1.252 rillig static int numdisks = 2; 334 1.250 mrg 335 1.38 mrg int 336 1.75 enami main(int argc, char *argv[]) 337 1.1 cgd { 338 1.126 simonb int c, todo, verbose, wide; 339 1.103 mycroft struct timespec interval; 340 1.1 cgd int reps; 341 1.88 lukem const char *histname, *hashname; 342 1.246 simonb char errbuf[_POSIX2_LINE_MAX]; 343 1.1 cgd 344 1.88 lukem histname = hashname = NULL; 345 1.13 cgd memf = nlistf = NULL; 346 1.126 simonb reps = todo = verbose = wide = 0; 347 1.103 mycroft interval.tv_sec = 0; 348 1.103 mycroft interval.tv_nsec = 0; 349 1.250 mrg while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:n:stu:UvWw:")) != -1) { 350 1.1 cgd switch (c) { 351 1.1 cgd case 'c': 352 1.1 cgd reps = atoi(optarg); 353 1.1 cgd break; 354 1.154 ad case 'C': 355 1.154 ad todo |= POOLCACHESTAT; 356 1.154 ad break; 357 1.66 cgd case 'e': 358 1.66 cgd todo |= EVCNTSTAT; 359 1.66 cgd break; 360 1.1 cgd case 'f': 361 1.1 cgd todo |= FORKSTAT; 362 1.1 cgd break; 363 1.45 thorpej case 'h': 364 1.88 lukem hashname = optarg; 365 1.88 lukem /* FALLTHROUGH */ 366 1.88 lukem case 'H': 367 1.87 lukem todo |= HASHSTAT; 368 1.45 thorpej break; 369 1.1 cgd case 'i': 370 1.1 cgd todo |= INTRSTAT; 371 1.1 cgd break; 372 1.45 thorpej case 'l': 373 1.45 thorpej todo |= HISTLIST; 374 1.45 thorpej break; 375 1.88 lukem case 'L': 376 1.88 lukem todo |= HASHLIST; 377 1.88 lukem break; 378 1.1 cgd case 'M': 379 1.13 cgd memf = optarg; 380 1.1 cgd break; 381 1.1 cgd case 'm': 382 1.1 cgd todo |= MEMSTAT; 383 1.1 cgd break; 384 1.1 cgd case 'N': 385 1.13 cgd nlistf = optarg; 386 1.1 cgd break; 387 1.250 mrg case 'n': 388 1.250 mrg numdisks = atoi(optarg); 389 1.250 mrg break; 390 1.1 cgd case 's': 391 1.1 cgd todo |= SUMSTAT; 392 1.1 cgd break; 393 1.130 he case 't': 394 1.130 he todo |= VMTOTAL; 395 1.130 he break; 396 1.87 lukem case 'u': 397 1.87 lukem histname = optarg; 398 1.87 lukem /* FALLTHROUGH */ 399 1.87 lukem case 'U': 400 1.87 lukem todo |= HISTDUMP; 401 1.87 lukem break; 402 1.66 cgd case 'v': 403 1.87 lukem verbose++; 404 1.66 cgd break; 405 1.126 simonb case 'W': 406 1.126 simonb wide++; 407 1.126 simonb break; 408 1.1 cgd case 'w': 409 1.103 mycroft interval.tv_sec = atol(optarg); 410 1.1 cgd break; 411 1.1 cgd case '?': 412 1.1 cgd default: 413 1.1 cgd usage(); 414 1.1 cgd } 415 1.1 cgd } 416 1.1 cgd argc -= optind; 417 1.1 cgd argv += optind; 418 1.1 cgd 419 1.1 cgd if (todo == 0) 420 1.1 cgd todo = VMSTAT; 421 1.1 cgd 422 1.246 simonb if (memf == NULL) { 423 1.246 simonb kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 424 1.246 simonb } else { 425 1.246 simonb kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 426 1.176 matt } 427 1.48 mrg 428 1.246 simonb if (kd == NULL) 429 1.246 simonb errx(EXIT_FAILURE, "%s", errbuf); 430 1.1 cgd 431 1.254 simonb if (memf != NULL) 432 1.254 simonb getnlist(todo); /* Only need this if a core is specified. */ 433 1.254 simonb 434 1.1 cgd if (todo & VMSTAT) { 435 1.1 cgd struct winsize winsize; 436 1.1 cgd 437 1.153 christos (void)drvinit(0);/* Initialize disk stats, no disks selected. */ 438 1.49 drochner 439 1.29 thorpej argv = choosedrives(argv); /* Select disks. */ 440 1.1 cgd winsize.ws_row = 0; 441 1.115 simonb (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize); 442 1.1 cgd if (winsize.ws_row > 0) 443 1.1 cgd winlines = winsize.ws_row; 444 1.1 cgd 445 1.1 cgd } 446 1.1 cgd 447 1.1 cgd #ifdef BACKWARD_COMPATIBILITY 448 1.1 cgd if (*argv) { 449 1.103 mycroft interval.tv_sec = atol(*argv); 450 1.1 cgd if (*++argv) 451 1.1 cgd reps = atoi(*argv); 452 1.1 cgd } 453 1.1 cgd #endif 454 1.1 cgd 455 1.103 mycroft if (interval.tv_sec) { 456 1.1 cgd if (!reps) 457 1.1 cgd reps = -1; 458 1.1 cgd } else if (reps) 459 1.103 mycroft interval.tv_sec = 1; 460 1.1 cgd 461 1.78 jhawk /* 462 1.78 jhawk * Statistics dumping is incompatible with the default 463 1.78 jhawk * VMSTAT/dovmstat() output. So perform the interval/reps handling 464 1.78 jhawk * for it here. 465 1.78 jhawk */ 466 1.130 he if ((todo & (VMSTAT|VMTOTAL)) == 0) { 467 1.99 enami for (;;) { 468 1.99 enami if (todo & (HISTLIST|HISTDUMP)) { 469 1.99 enami if ((todo & (HISTLIST|HISTDUMP)) == 470 1.99 enami (HISTLIST|HISTDUMP)) 471 1.99 enami errx(1, "you may list or dump," 472 1.99 enami " but not both!"); 473 1.210 pgoyette if (memf != NULL) 474 1.210 pgoyette hist_traverse(todo, histname); 475 1.210 pgoyette else 476 1.210 pgoyette hist_traverse_sysctl(todo, histname); 477 1.153 christos (void)putchar('\n'); 478 1.99 enami } 479 1.99 enami if (todo & FORKSTAT) { 480 1.99 enami doforkst(); 481 1.153 christos (void)putchar('\n'); 482 1.99 enami } 483 1.99 enami if (todo & MEMSTAT) { 484 1.126 simonb dopool(verbose, wide); 485 1.153 christos (void)putchar('\n'); 486 1.99 enami } 487 1.154 ad if (todo & POOLCACHESTAT) { 488 1.182 yamt dopoolcache(verbose); 489 1.154 ad (void)putchar('\n'); 490 1.154 ad } 491 1.99 enami if (todo & SUMSTAT) { 492 1.99 enami dosum(); 493 1.153 christos (void)putchar('\n'); 494 1.99 enami } 495 1.99 enami if (todo & INTRSTAT) { 496 1.99 enami dointr(verbose); 497 1.153 christos (void)putchar('\n'); 498 1.99 enami } 499 1.99 enami if (todo & EVCNTSTAT) { 500 1.176 matt doevcnt(verbose, EVCNT_TYPE_ANY); 501 1.153 christos (void)putchar('\n'); 502 1.99 enami } 503 1.99 enami if (todo & (HASHLIST|HASHSTAT)) { 504 1.99 enami if ((todo & (HASHLIST|HASHSTAT)) == 505 1.99 enami (HASHLIST|HASHSTAT)) 506 1.99 enami errx(1, "you may list or display," 507 1.99 enami " but not both!"); 508 1.99 enami dohashstat(verbose, todo, hashname); 509 1.153 christos (void)putchar('\n'); 510 1.99 enami } 511 1.101 sommerfe 512 1.164 dholland fflush(stdout); 513 1.101 sommerfe if (reps >= 0 && --reps <=0) 514 1.99 enami break; 515 1.153 christos (void)nanosleep(&interval, NULL); 516 1.87 lukem } 517 1.130 he } else { 518 1.130 he if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) { 519 1.130 he errx(1, "you may not both do vmstat and vmtotal"); 520 1.130 he } 521 1.130 he if (todo & VMSTAT) 522 1.130 he dovmstat(&interval, reps); 523 1.130 he if (todo & VMTOTAL) 524 1.130 he dovmtotal(&interval, reps); 525 1.130 he } 526 1.153 christos return 0; 527 1.1 cgd } 528 1.1 cgd 529 1.176 matt void 530 1.176 matt getnlist(int todo) 531 1.176 matt { 532 1.185 christos static int done = 0; 533 1.176 matt int c; 534 1.176 matt size_t i; 535 1.176 matt 536 1.246 simonb if ((c = kvm_nlist(kd, namelist)) != 0) { 537 1.246 simonb int doexit = 0; 538 1.246 simonb if (c == -1) 539 1.246 simonb errx(1, "kvm_nlist: %s %s", 540 1.246 simonb "namelist", kvm_geterr(kd)); 541 1.246 simonb for (i = 0; i < __arraycount(namelist)-1; i++) 542 1.246 simonb if (namelist[i].n_type == 0) { 543 1.246 simonb if (doexit++ == 0) 544 1.246 simonb (void)fprintf(stderr, 545 1.246 simonb "%s: undefined symbols:", 546 1.246 simonb getprogname()); 547 1.246 simonb (void)fprintf(stderr, " %s", 548 1.246 simonb namelist[i].n_name); 549 1.176 matt } 550 1.246 simonb if (doexit) { 551 1.246 simonb (void)fputc('\n', stderr); 552 1.246 simonb exit(1); 553 1.176 matt } 554 1.176 matt } 555 1.246 simonb 556 1.232 mrg if ((todo & (VMSTAT|INTRSTAT)) && !(done & (VMSTAT))) { 557 1.232 mrg done |= VMSTAT; 558 1.232 mrg if ((c = kvm_nlist(kd, timenl)) == -1 || c == X_TIMENL_SIZE) 559 1.232 mrg errx(1, "kvm_nlist: %s %s", "timenl", kvm_geterr(kd)); 560 1.232 mrg } 561 1.185 christos if ((todo & (SUMSTAT|INTRSTAT)) && !(done & (SUMSTAT|INTRSTAT))) { 562 1.185 christos done |= SUMSTAT|INTRSTAT; 563 1.176 matt (void) kvm_nlist(kd, intrnl); 564 1.176 matt } 565 1.185 christos if ((todo & (HASHLIST|HASHSTAT)) && !(done & (HASHLIST|HASHSTAT))) { 566 1.185 christos done |= HASHLIST|HASHSTAT; 567 1.176 matt if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE) 568 1.176 matt errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd)); 569 1.176 matt } 570 1.185 christos if ((todo & (HISTLIST|HISTDUMP)) && !(done & (HISTLIST|HISTDUMP))) { 571 1.185 christos done |= HISTLIST|HISTDUMP; 572 1.176 matt if (kvm_nlist(kd, histnl) == -1) 573 1.176 matt errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd)); 574 1.176 matt } 575 1.176 matt } 576 1.176 matt 577 1.1 cgd char ** 578 1.73 simonb choosedrives(char **argv) 579 1.1 cgd { 580 1.249 mrg size_t i, j, k; 581 1.1 cgd 582 1.1 cgd /* 583 1.1 cgd * Choose drives to be displayed. Priority goes to (in order) drives 584 1.1 cgd * supplied as arguments, default drives. If everything isn't filled 585 1.1 cgd * in and there are drives not taken care of, display the first few 586 1.1 cgd * that fit. 587 1.1 cgd */ 588 1.75 enami #define BACKWARD_COMPATIBILITY 589 1.1 cgd for (ndrives = 0; *argv; ++argv) { 590 1.1 cgd #ifdef BACKWARD_COMPATIBILITY 591 1.124 dsl if (isdigit((unsigned char)**argv)) 592 1.1 cgd break; 593 1.1 cgd #endif 594 1.140 blymn for (i = 0; i < ndrive; i++) { 595 1.1 cgd if (strcmp(dr_name[i], *argv)) 596 1.1 cgd continue; 597 1.140 blymn drv_select[i] = 1; 598 1.136 blymn ++ndrives; 599 1.136 blymn break; 600 1.136 blymn } 601 1.1 cgd } 602 1.249 mrg 603 1.249 mrg /* 604 1.249 mrg * Pick the most active drives. Must read the stats once before 605 1.249 mrg * sorting so that there is current IO data, before selecting 606 1.250 mrg * just the first 'numdisks' (default 2) drives. 607 1.249 mrg */ 608 1.249 mrg drvreadstats(); 609 1.250 mrg for (i = 0; i < ndrive && ndrives < numdisks; i++) { 610 1.249 mrg uint64_t high_bytes = 0, bytes; 611 1.249 mrg 612 1.249 mrg k = ndrive; 613 1.249 mrg for (j = 0; j < ndrive; j++) { 614 1.249 mrg if (drv_select[j]) 615 1.249 mrg continue; 616 1.249 mrg bytes = cur.rbytes[j] + cur.wbytes[j]; 617 1.249 mrg if (bytes > high_bytes) { 618 1.249 mrg high_bytes = bytes; 619 1.249 mrg k = j; 620 1.249 mrg } 621 1.249 mrg } 622 1.249 mrg if (k != ndrive) { 623 1.249 mrg drv_select[k] = 1; 624 1.249 mrg ++ndrives; 625 1.249 mrg } 626 1.1 cgd } 627 1.140 blymn 628 1.75 enami return (argv); 629 1.1 cgd } 630 1.1 cgd 631 1.1 cgd long 632 1.73 simonb getuptime(void) 633 1.1 cgd { 634 1.176 matt static struct timespec boottime; 635 1.176 matt struct timespec now; 636 1.149 kardel time_t uptime, nowsec; 637 1.1 cgd 638 1.176 matt if (memf == NULL) { 639 1.176 matt if (boottime.tv_sec == 0) { 640 1.176 matt size_t buflen = sizeof(boottime); 641 1.176 matt if (sysctl(boottime_mib, __arraycount(boottime_mib), 642 1.176 matt &boottime, &buflen, NULL, 0) == -1) 643 1.176 matt warn("Can't get boottime"); 644 1.176 matt } 645 1.176 matt clock_gettime(CLOCK_REALTIME, &now); 646 1.147 kardel } else { 647 1.231 thorpej if (boottime.tv_sec == 0) { 648 1.231 thorpej struct bintime bt; 649 1.231 thorpej 650 1.232 mrg kread(timenl, X_TIMEBASEBIN, &bt, sizeof(bt)); 651 1.231 thorpej bintime2timespec(&bt, &boottime); 652 1.231 thorpej } 653 1.232 mrg if (kreadc(timenl, X_TIME_SECOND, &nowsec, sizeof(nowsec))) { 654 1.176 matt /* 655 1.176 matt * XXX this assignment dance can be removed once 656 1.176 matt * timeval tv_sec is SUS mandated time_t 657 1.176 matt */ 658 1.176 matt now.tv_sec = nowsec; 659 1.176 matt now.tv_nsec = 0; 660 1.176 matt } else { 661 1.232 mrg kread(timenl, X_TIME, &now, sizeof(now)); 662 1.176 matt } 663 1.147 kardel } 664 1.145 kardel uptime = now.tv_sec - boottime.tv_sec; 665 1.87 lukem if (uptime <= 0 || uptime > 60*60*24*365*10) 666 1.87 lukem errx(1, "time makes no sense; namelist must be wrong."); 667 1.75 enami return (uptime); 668 1.1 cgd } 669 1.1 cgd 670 1.1 cgd int hz, hdrcnt; 671 1.1 cgd 672 1.1 cgd void 673 1.187 matt print_total_hdr(void) 674 1.130 he { 675 1.130 he 676 1.166 rmind (void)printf("procs memory\n"); 677 1.166 rmind (void)printf("ru dw pw sl"); 678 1.130 he (void)printf(" total-v active-v active-r"); 679 1.130 he (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n"); 680 1.130 he hdrcnt = winlines - 2; 681 1.130 he } 682 1.130 he 683 1.130 he void 684 1.130 he dovmtotal(struct timespec *interval, int reps) 685 1.130 he { 686 1.130 he struct vmtotal total; 687 1.130 he size_t size; 688 1.130 he 689 1.130 he (void)signal(SIGCONT, needhdr); 690 1.130 he 691 1.130 he for (hdrcnt = 1;;) { 692 1.130 he if (!--hdrcnt) 693 1.130 he print_total_hdr(); 694 1.130 he if (memf != NULL) { 695 1.170 christos warnx("Unable to get vmtotals from crash dump."); 696 1.153 christos (void)memset(&total, 0, sizeof(total)); 697 1.130 he } else { 698 1.130 he size = sizeof(total); 699 1.170 christos if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), 700 1.170 christos &total, &size, NULL, 0) == -1) { 701 1.170 christos warn("Can't get vmtotals"); 702 1.153 christos (void)memset(&total, 0, sizeof(total)); 703 1.130 he } 704 1.130 he } 705 1.153 christos (void)printf("%2d ", total.t_rq); 706 1.153 christos (void)printf("%2d ", total.t_dw); 707 1.153 christos (void)printf("%2d ", total.t_pw); 708 1.153 christos (void)printf("%2d ", total.t_sl); 709 1.153 christos 710 1.153 christos (void)printf("%9d ", total.t_vm); 711 1.153 christos (void)printf("%9d ", total.t_avm); 712 1.153 christos (void)printf("%9d ", total.t_arm); 713 1.153 christos (void)printf("%5d ", total.t_vmshr); 714 1.153 christos (void)printf("%6d ", total.t_avmshr); 715 1.153 christos (void)printf("%5d ", total.t_rmshr); 716 1.153 christos (void)printf("%6d ", total.t_armshr); 717 1.153 christos (void)printf("%5d", total.t_free); 718 1.130 he 719 1.153 christos (void)putchar('\n'); 720 1.130 he 721 1.130 he (void)fflush(stdout); 722 1.130 he if (reps >= 0 && --reps <= 0) 723 1.130 he break; 724 1.130 he 725 1.153 christos (void)nanosleep(interval, NULL); 726 1.130 he } 727 1.130 he } 728 1.130 he 729 1.130 he void 730 1.103 mycroft dovmstat(struct timespec *interval, int reps) 731 1.1 cgd { 732 1.1 cgd struct vmtotal total; 733 1.1 cgd time_t uptime, halfuptime; 734 1.17 cgd size_t size; 735 1.41 mrg int pagesize = getpagesize(); 736 1.151 yamt int ovflw; 737 1.1 cgd 738 1.1 cgd uptime = getuptime(); 739 1.1 cgd halfuptime = uptime / 2; 740 1.1 cgd (void)signal(SIGCONT, needhdr); 741 1.1 cgd 742 1.197 joerg if (memf != NULL) { 743 1.197 joerg if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) 744 1.197 joerg kread(namelist, X_STATHZ, &hz, sizeof(hz)); 745 1.197 joerg if (!hz) 746 1.197 joerg kread(namelist, X_HZ, &hz, sizeof(hz)); 747 1.197 joerg } else { 748 1.197 joerg struct clockinfo clockinfo; 749 1.197 joerg size = sizeof(clockinfo); 750 1.197 joerg if (sysctl(clockrate_mib, 2, &clockinfo, &size, NULL, 0) == -1) 751 1.197 joerg err(1, "sysctl kern.clockrate failed"); 752 1.197 joerg hz = clockinfo.stathz; 753 1.197 joerg if (!hz) 754 1.197 joerg hz = clockinfo.hz; 755 1.197 joerg } 756 1.1 cgd 757 1.1 cgd for (hdrcnt = 1;;) { 758 1.1 cgd if (!--hdrcnt) 759 1.1 cgd printhdr(); 760 1.29 thorpej /* Read new disk statistics */ 761 1.139 dsl cpureadstats(); 762 1.140 blymn drvreadstats(); 763 1.139 dsl tkreadstats(); 764 1.58 thorpej if (memf != NULL) { 765 1.196 joerg struct uvmexp uvmexp_kernel; 766 1.58 thorpej /* 767 1.58 thorpej * XXX Can't do this if we're reading a crash 768 1.58 thorpej * XXX dump because they're lazily-calculated. 769 1.58 thorpej */ 770 1.170 christos warnx("Unable to get vmtotals from crash dump."); 771 1.153 christos (void)memset(&total, 0, sizeof(total)); 772 1.196 joerg kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 773 1.196 joerg #define COPY(field) uvmexp.field = uvmexp_kernel.field 774 1.196 joerg COPY(pdreact); 775 1.196 joerg COPY(pageins); 776 1.196 joerg COPY(pgswapout); 777 1.196 joerg COPY(pdfreed); 778 1.196 joerg COPY(pdscans); 779 1.196 joerg #undef COPY 780 1.58 thorpej } else { 781 1.58 thorpej size = sizeof(total); 782 1.170 christos if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), 783 1.170 christos &total, &size, NULL, 0) == -1) { 784 1.170 christos warn("Can't get vmtotals"); 785 1.153 christos (void)memset(&total, 0, sizeof(total)); 786 1.58 thorpej } 787 1.196 joerg size = sizeof(uvmexp); 788 1.196 joerg if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 789 1.196 joerg &size, NULL, 0) == -1) 790 1.196 joerg warn("sysctl vm.uvmexp2 failed"); 791 1.13 cgd } 792 1.171 christos cpucounters(&cpucounter); 793 1.151 yamt ovflw = 0; 794 1.151 yamt PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1); 795 1.151 yamt PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw); 796 1.153 christos #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10)) 797 1.38 mrg #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */ 798 1.166 rmind PRWORD(ovflw, " %*ld", 9, 1, pgtok(total.t_avm)); 799 1.151 yamt PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free)); 800 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1, 801 1.171 christos rate(cpucounter.nfault - ocpucounter.nfault)); 802 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1, 803 1.151 yamt rate(uvmexp.pdreact - ouvmexp.pdreact)); 804 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1, 805 1.151 yamt rate(uvmexp.pageins - ouvmexp.pageins)); 806 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1, 807 1.44 mrg rate(uvmexp.pgswapout - ouvmexp.pgswapout)); 808 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1, 809 1.151 yamt rate(uvmexp.pdfreed - ouvmexp.pdfreed)); 810 1.151 yamt PRWORD(ovflw, " %*ld", 6, 2, 811 1.151 yamt rate(uvmexp.pdscans - ouvmexp.pdscans)); 812 1.151 yamt drvstats(&ovflw); 813 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1, 814 1.171 christos rate(cpucounter.nintr - ocpucounter.nintr)); 815 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1, 816 1.171 christos rate(cpucounter.nsyscall - ocpucounter.nsyscall)); 817 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1, 818 1.171 christos rate(cpucounter.nswtch - ocpucounter.nswtch)); 819 1.151 yamt cpustats(&ovflw); 820 1.153 christos (void)putchar('\n'); 821 1.42 mrg (void)fflush(stdout); 822 1.42 mrg if (reps >= 0 && --reps <= 0) 823 1.42 mrg break; 824 1.172 enami ouvmexp = uvmexp; 825 1.171 christos ocpucounter = cpucounter; 826 1.103 mycroft uptime = interval->tv_sec; 827 1.1 cgd /* 828 1.1 cgd * We round upward to avoid losing low-frequency events 829 1.1 cgd * (i.e., >= 1 per interval but < 1 per second). 830 1.1 cgd */ 831 1.33 thorpej halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2; 832 1.153 christos (void)nanosleep(interval, NULL); 833 1.1 cgd } 834 1.1 cgd } 835 1.1 cgd 836 1.38 mrg void 837 1.73 simonb printhdr(void) 838 1.1 cgd { 839 1.165 lukem size_t i; 840 1.1 cgd 841 1.104 mrg (void)printf(" procs memory page%*s", 23, ""); 842 1.29 thorpej if (ndrives > 0) 843 1.70 sommerfe (void)printf("%s %*sfaults cpu\n", 844 1.75 enami ((ndrives > 1) ? "disks" : "disk"), 845 1.75 enami ((ndrives > 1) ? ndrives * 3 - 4 : 0), ""); 846 1.1 cgd else 847 1.29 thorpej (void)printf("%*s faults cpu\n", 848 1.75 enami ndrives * 3, ""); 849 1.29 thorpej 850 1.166 rmind (void)printf(" r b avm fre flt re pi po fr sr "); 851 1.140 blymn for (i = 0; i < ndrive; i++) 852 1.140 blymn if (drv_select[i]) 853 1.1 cgd (void)printf("%c%c ", dr_name[i][0], 854 1.1 cgd dr_name[i][strlen(dr_name[i]) - 1]); 855 1.1 cgd (void)printf(" in sy cs us sy id\n"); 856 1.1 cgd hdrcnt = winlines - 2; 857 1.1 cgd } 858 1.1 cgd 859 1.1 cgd /* 860 1.1 cgd * Force a header to be prepended to the next output. 861 1.1 cgd */ 862 1.1 cgd void 863 1.153 christos /*ARGSUSED*/ 864 1.73 simonb needhdr(int dummy) 865 1.1 cgd { 866 1.1 cgd 867 1.1 cgd hdrcnt = 1; 868 1.1 cgd } 869 1.1 cgd 870 1.38 mrg long 871 1.203 nakayama pct(u_long top, u_long bot) 872 1.1 cgd { 873 1.13 cgd long ans; 874 1.13 cgd 875 1.1 cgd if (bot == 0) 876 1.75 enami return (0); 877 1.153 christos ans = (long)((quad_t)top * 100 / bot); 878 1.13 cgd return (ans); 879 1.1 cgd } 880 1.1 cgd 881 1.203 nakayama #define PCT(top, bot) (int)pct((u_long)(top), (u_long)(bot)) 882 1.1 cgd 883 1.1 cgd void 884 1.73 simonb dosum(void) 885 1.1 cgd { 886 1.206 dennis struct nchstats nch_stats; 887 1.194 joerg uint64_t nchtotal; 888 1.162 he size_t ssize; 889 1.162 he int active_kernel; 890 1.171 christos struct cpu_counter cc; 891 1.162 he 892 1.162 he /* 893 1.162 he * The "active" and "inactive" variables 894 1.162 he * are now estimated by the kernel and sadly 895 1.162 he * can not easily be dug out of a crash dump. 896 1.162 he */ 897 1.195 joerg ssize = sizeof(uvmexp); 898 1.195 joerg memset(&uvmexp, 0, ssize); 899 1.162 he active_kernel = (memf == NULL); 900 1.162 he if (active_kernel) { 901 1.162 he /* only on active kernel */ 902 1.195 joerg if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 903 1.170 christos &ssize, NULL, 0) == -1) 904 1.170 christos warn("sysctl vm.uvmexp2 failed"); 905 1.195 joerg } else { 906 1.195 joerg struct uvmexp uvmexp_kernel; 907 1.221 mrg struct pool pool, *pp = &pool; 908 1.222 mrg struct pool_allocator pa; 909 1.221 mrg TAILQ_HEAD(,pool) pool_head; 910 1.221 mrg void *addr; 911 1.222 mrg uint64_t bytes; 912 1.221 mrg 913 1.195 joerg kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 914 1.195 joerg #define COPY(field) uvmexp.field = uvmexp_kernel.field 915 1.195 joerg COPY(pagesize); 916 1.195 joerg COPY(ncolors); 917 1.195 joerg COPY(npages); 918 1.195 joerg COPY(free); 919 1.195 joerg COPY(paging); 920 1.195 joerg COPY(wired); 921 1.195 joerg COPY(reserve_pagedaemon); 922 1.195 joerg COPY(reserve_kernel); 923 1.195 joerg COPY(anonpages); 924 1.195 joerg COPY(filepages); 925 1.195 joerg COPY(execpages); 926 1.195 joerg COPY(freemin); 927 1.195 joerg COPY(freetarg); 928 1.195 joerg COPY(wiredmax); 929 1.195 joerg COPY(nswapdev); 930 1.195 joerg COPY(swpages); 931 1.195 joerg COPY(swpginuse); 932 1.195 joerg COPY(nswget); 933 1.195 joerg COPY(pageins); 934 1.195 joerg COPY(pdpageouts); 935 1.195 joerg COPY(pgswapin); 936 1.195 joerg COPY(pgswapout); 937 1.195 joerg COPY(forks); 938 1.195 joerg COPY(forks_ppwait); 939 1.195 joerg COPY(forks_sharevm); 940 1.195 joerg COPY(colorhit); 941 1.195 joerg COPY(colormiss); 942 1.195 joerg COPY(cpuhit); 943 1.195 joerg COPY(cpumiss); 944 1.195 joerg COPY(fltnoram); 945 1.195 joerg COPY(fltnoanon); 946 1.195 joerg COPY(fltpgwait); 947 1.195 joerg COPY(fltpgrele); 948 1.195 joerg COPY(fltrelck); 949 1.195 joerg COPY(fltrelckok); 950 1.195 joerg COPY(fltanget); 951 1.195 joerg COPY(fltanretry); 952 1.195 joerg COPY(fltamcopy); 953 1.195 joerg COPY(fltamcopy); 954 1.195 joerg COPY(fltnomap); 955 1.195 joerg COPY(fltlget); 956 1.195 joerg COPY(fltget); 957 1.195 joerg COPY(flt_anon); 958 1.195 joerg COPY(flt_acow); 959 1.195 joerg COPY(flt_obj); 960 1.195 joerg COPY(flt_prcopy); 961 1.195 joerg COPY(flt_przero); 962 1.195 joerg COPY(pdwoke); 963 1.195 joerg COPY(pdrevs); 964 1.195 joerg COPY(pdfreed); 965 1.195 joerg COPY(pdscans); 966 1.195 joerg COPY(pdanscan); 967 1.195 joerg COPY(pdobscan); 968 1.195 joerg COPY(pdreact); 969 1.195 joerg COPY(pdbusy); 970 1.195 joerg COPY(pdpending); 971 1.195 joerg COPY(pddeact); 972 1.221 mrg COPY(bootpages); 973 1.195 joerg #undef COPY 974 1.221 mrg kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); 975 1.221 mrg addr = TAILQ_FIRST(&pool_head); 976 1.222 mrg uvmexp.poolpages = 0; 977 1.221 mrg for (; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist)) { 978 1.221 mrg deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); 979 1.224 mrg deref_kptr(pp->pr_alloc, &pa, sizeof(pa), 980 1.224 mrg "pool allocator trashed"); 981 1.222 mrg bytes = pp->pr_npages * pa.pa_pagesz; 982 1.222 mrg if ((pp->pr_roflags & PR_RECURSIVE) != 0) 983 1.222 mrg bytes -= (pp->pr_nout * pp->pr_size); 984 1.222 mrg uvmexp.poolpages += bytes / uvmexp.pagesize; 985 1.221 mrg } 986 1.162 he } 987 1.1 cgd 988 1.41 mrg 989 1.195 joerg (void)printf("%9" PRIu64 " bytes per page\n", uvmexp.pagesize); 990 1.44 mrg 991 1.195 joerg (void)printf("%9" PRIu64 " page color%s\n", 992 1.81 thorpej uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s"); 993 1.81 thorpej 994 1.195 joerg (void)printf("%9" PRIu64 " pages managed\n", uvmexp.npages); 995 1.195 joerg (void)printf("%9" PRIu64 " pages free\n", uvmexp.free); 996 1.162 he if (active_kernel) { 997 1.195 joerg (void)printf("%9" PRIu64 " pages active\n", uvmexp.active); 998 1.195 joerg (void)printf("%9" PRIu64 " pages inactive\n", uvmexp.inactive); 999 1.162 he } 1000 1.195 joerg (void)printf("%9" PRIu64 " pages paging\n", uvmexp.paging); 1001 1.195 joerg (void)printf("%9" PRIu64 " pages wired\n", uvmexp.wired); 1002 1.195 joerg (void)printf("%9" PRIu64 " reserve pagedaemon pages\n", 1003 1.44 mrg uvmexp.reserve_pagedaemon); 1004 1.195 joerg (void)printf("%9" PRIu64 " reserve kernel pages\n", uvmexp.reserve_kernel); 1005 1.221 mrg (void)printf("%9" PRIu64 " boot kernel pages\n", uvmexp.bootpages); 1006 1.221 mrg (void)printf("%9" PRIu64 " kernel pool pages\n", uvmexp.poolpages); 1007 1.195 joerg (void)printf("%9" PRIu64 " anonymous pages\n", uvmexp.anonpages); 1008 1.195 joerg (void)printf("%9" PRIu64 " cached file pages\n", uvmexp.filepages); 1009 1.195 joerg (void)printf("%9" PRIu64 " cached executable pages\n", uvmexp.execpages); 1010 1.195 joerg 1011 1.195 joerg (void)printf("%9" PRIu64 " minimum free pages\n", uvmexp.freemin); 1012 1.195 joerg (void)printf("%9" PRIu64 " target free pages\n", uvmexp.freetarg); 1013 1.195 joerg (void)printf("%9" PRIu64 " maximum wired pages\n", uvmexp.wiredmax); 1014 1.195 joerg 1015 1.195 joerg (void)printf("%9" PRIu64 " swap devices\n", uvmexp.nswapdev); 1016 1.195 joerg (void)printf("%9" PRIu64 " swap pages\n", uvmexp.swpages); 1017 1.195 joerg (void)printf("%9" PRIu64 " swap pages in use\n", uvmexp.swpginuse); 1018 1.195 joerg (void)printf("%9" PRIu64 " swap allocations\n", uvmexp.nswget); 1019 1.44 mrg 1020 1.171 christos cpucounters(&cc); 1021 1.190 rmind 1022 1.171 christos (void)printf("%9" PRIu64 " total faults taken\n", cc.nfault); 1023 1.171 christos (void)printf("%9" PRIu64 " traps\n", cc.ntrap); 1024 1.171 christos (void)printf("%9" PRIu64 " device interrupts\n", cc.nintr); 1025 1.171 christos (void)printf("%9" PRIu64 " CPU context switches\n", cc.nswtch); 1026 1.171 christos (void)printf("%9" PRIu64 " software interrupts\n", cc.nsoft); 1027 1.171 christos (void)printf("%9" PRIu64 " system calls\n", cc.nsyscall); 1028 1.195 joerg (void)printf("%9" PRIu64 " pagein requests\n", uvmexp.pageins); 1029 1.195 joerg (void)printf("%9" PRIu64 " pageout requests\n", uvmexp.pdpageouts); 1030 1.195 joerg (void)printf("%9" PRIu64 " pages swapped in\n", uvmexp.pgswapin); 1031 1.195 joerg (void)printf("%9" PRIu64 " pages swapped out\n", uvmexp.pgswapout); 1032 1.195 joerg (void)printf("%9" PRIu64 " forks total\n", uvmexp.forks); 1033 1.195 joerg (void)printf("%9" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); 1034 1.195 joerg (void)printf("%9" PRIu64 " forks shared address space with parent\n", 1035 1.43 mrg uvmexp.forks_sharevm); 1036 1.195 joerg (void)printf("%9" PRIu64 " pagealloc desired color avail\n", 1037 1.79 thorpej uvmexp.colorhit); 1038 1.195 joerg (void)printf("%9" PRIu64 " pagealloc desired color not avail\n", 1039 1.79 thorpej uvmexp.colormiss); 1040 1.195 joerg (void)printf("%9" PRIu64 " pagealloc local cpu avail\n", 1041 1.159 ad uvmexp.cpuhit); 1042 1.195 joerg (void)printf("%9" PRIu64 " pagealloc local cpu not avail\n", 1043 1.159 ad uvmexp.cpumiss); 1044 1.44 mrg 1045 1.195 joerg (void)printf("%9" PRIu64 " faults with no memory\n", uvmexp.fltnoram); 1046 1.195 joerg (void)printf("%9" PRIu64 " faults with no anons\n", uvmexp.fltnoanon); 1047 1.195 joerg (void)printf("%9" PRIu64 " faults had to wait on pages\n", uvmexp.fltpgwait); 1048 1.195 joerg (void)printf("%9" PRIu64 " faults found released page\n", uvmexp.fltpgrele); 1049 1.195 joerg (void)printf("%9" PRIu64 " faults relock (%" PRIu64 " ok)\n", uvmexp.fltrelck, 1050 1.43 mrg uvmexp.fltrelckok); 1051 1.195 joerg (void)printf("%9" PRIu64 " anon page faults\n", uvmexp.fltanget); 1052 1.195 joerg (void)printf("%9" PRIu64 " anon retry faults\n", uvmexp.fltanretry); 1053 1.195 joerg (void)printf("%9" PRIu64 " amap copy faults\n", uvmexp.fltamcopy); 1054 1.195 joerg (void)printf("%9" PRIu64 " neighbour anon page faults\n", uvmexp.fltnamap); 1055 1.195 joerg (void)printf("%9" PRIu64 " neighbour object page faults\n", uvmexp.fltnomap); 1056 1.195 joerg (void)printf("%9" PRIu64 " locked pager get faults\n", uvmexp.fltlget); 1057 1.195 joerg (void)printf("%9" PRIu64 " unlocked pager get faults\n", uvmexp.fltget); 1058 1.195 joerg (void)printf("%9" PRIu64 " anon faults\n", uvmexp.flt_anon); 1059 1.195 joerg (void)printf("%9" PRIu64 " anon copy on write faults\n", uvmexp.flt_acow); 1060 1.195 joerg (void)printf("%9" PRIu64 " object faults\n", uvmexp.flt_obj); 1061 1.195 joerg (void)printf("%9" PRIu64 " promote copy faults\n", uvmexp.flt_prcopy); 1062 1.195 joerg (void)printf("%9" PRIu64 " promote zero fill faults\n", uvmexp.flt_przero); 1063 1.238 ad (void)printf("%9" PRIu64 " faults upgraded lock\n", 1064 1.238 ad uvmexp.fltup); 1065 1.238 ad (void)printf("%9" PRIu64 " faults couldn't upgrade lock\n", 1066 1.238 ad uvmexp.fltnoup); 1067 1.195 joerg 1068 1.195 joerg (void)printf("%9" PRIu64 " times daemon wokeup\n",uvmexp.pdwoke); 1069 1.195 joerg (void)printf("%9" PRIu64 " revolutions of the clock hand\n", uvmexp.pdrevs); 1070 1.195 joerg (void)printf("%9" PRIu64 " pages freed by daemon\n", uvmexp.pdfreed); 1071 1.195 joerg (void)printf("%9" PRIu64 " pages scanned by daemon\n", uvmexp.pdscans); 1072 1.195 joerg (void)printf("%9" PRIu64 " anonymous pages scanned by daemon\n", 1073 1.75 enami uvmexp.pdanscan); 1074 1.195 joerg (void)printf("%9" PRIu64 " object pages scanned by daemon\n", uvmexp.pdobscan); 1075 1.195 joerg (void)printf("%9" PRIu64 " pages reactivated\n", uvmexp.pdreact); 1076 1.195 joerg (void)printf("%9" PRIu64 " pages found busy by daemon\n", uvmexp.pdbusy); 1077 1.195 joerg (void)printf("%9" PRIu64 " total pending pageouts\n", uvmexp.pdpending); 1078 1.195 joerg (void)printf("%9" PRIu64 " pages deactivated\n", uvmexp.pddeact); 1079 1.240 ad (void)printf("%9" PRIu64 " per-cpu stats synced\n", uvmexp.countsyncall); 1080 1.235 ad (void)printf("%9" PRIu64 " anon pages possibly dirty\n", uvmexp.anonunknown); 1081 1.235 ad (void)printf("%9" PRIu64 " anon pages dirty\n", uvmexp.anondirty); 1082 1.235 ad (void)printf("%9" PRIu64 " anon pages clean\n", uvmexp.anonclean); 1083 1.235 ad (void)printf("%9" PRIu64 " file pages possibly dirty\n", uvmexp.fileunknown); 1084 1.235 ad (void)printf("%9" PRIu64 " file pages dirty\n", uvmexp.filedirty); 1085 1.235 ad (void)printf("%9" PRIu64 " file pages clean\n", uvmexp.fileclean); 1086 1.123 enami 1087 1.194 joerg if (active_kernel) { 1088 1.194 joerg ssize = sizeof(nch_stats); 1089 1.194 joerg if (sysctlbyname("vfs.namecache_stats", &nch_stats, &ssize, 1090 1.194 joerg NULL, 0)) { 1091 1.194 joerg warn("vfs.namecache_stats failed"); 1092 1.194 joerg memset(&nch_stats, 0, sizeof(nch_stats)); 1093 1.194 joerg } 1094 1.194 joerg } else { 1095 1.206 dennis kread(namelist, X_NCHSTATS, &nch_stats, sizeof(nch_stats)); 1096 1.194 joerg } 1097 1.194 joerg 1098 1.194 joerg nchtotal = nch_stats.ncs_goodhits + nch_stats.ncs_neghits + 1099 1.194 joerg nch_stats.ncs_badhits + nch_stats.ncs_falsehits + 1100 1.194 joerg nch_stats.ncs_miss + nch_stats.ncs_long; 1101 1.194 joerg (void)printf("%9" PRIu64 " total name lookups\n", nchtotal); 1102 1.194 joerg (void)printf("%9" PRIu64 " good hits\n", nch_stats.ncs_goodhits); 1103 1.194 joerg (void)printf("%9" PRIu64 " negative hits\n", nch_stats.ncs_neghits); 1104 1.194 joerg (void)printf("%9" PRIu64 " bad hits\n", nch_stats.ncs_badhits); 1105 1.194 joerg (void)printf("%9" PRIu64 " false hits\n", nch_stats.ncs_falsehits); 1106 1.194 joerg (void)printf("%9" PRIu64 " miss\n", nch_stats.ncs_miss); 1107 1.194 joerg (void)printf("%9" PRIu64 " too long\n", nch_stats.ncs_long); 1108 1.194 joerg (void)printf("%9" PRIu64 " pass2 hits\n", nch_stats.ncs_pass2); 1109 1.194 joerg (void)printf("%9" PRIu64 " 2passes\n", nch_stats.ncs_2passes); 1110 1.233 ad (void)printf("%9" PRIu64 " reverse hits\n", nch_stats.ncs_revhits); 1111 1.234 ad (void)printf("%9" PRIu64 " reverse miss\n", nch_stats.ncs_revmiss); 1112 1.237 ad (void)printf("%9" PRIu64 " access denied\n", nch_stats.ncs_denied); 1113 1.1 cgd (void)printf( 1114 1.1 cgd "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", 1115 1.194 joerg "", PCT(nch_stats.ncs_goodhits, nchtotal), 1116 1.194 joerg PCT(nch_stats.ncs_neghits, nchtotal), 1117 1.194 joerg PCT(nch_stats.ncs_pass2, nchtotal)); 1118 1.1 cgd (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", 1119 1.194 joerg PCT(nch_stats.ncs_badhits, nchtotal), 1120 1.194 joerg PCT(nch_stats.ncs_falsehits, nchtotal), 1121 1.194 joerg PCT(nch_stats.ncs_long, nchtotal)); 1122 1.1 cgd } 1123 1.1 cgd 1124 1.1 cgd void 1125 1.73 simonb doforkst(void) 1126 1.1 cgd { 1127 1.196 joerg if (memf != NULL) { 1128 1.196 joerg struct uvmexp uvmexp_kernel; 1129 1.196 joerg kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 1130 1.196 joerg #define COPY(field) uvmexp.field = uvmexp_kernel.field 1131 1.196 joerg COPY(forks); 1132 1.196 joerg COPY(forks_ppwait); 1133 1.196 joerg COPY(forks_sharevm); 1134 1.196 joerg #undef COPY 1135 1.196 joerg } else { 1136 1.196 joerg size_t size = sizeof(uvmexp); 1137 1.196 joerg if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 1138 1.196 joerg &size, NULL, 0) == -1) 1139 1.196 joerg warn("sysctl vm.uvmexp2 failed"); 1140 1.196 joerg } 1141 1.58 thorpej 1142 1.196 joerg (void)printf("%" PRIu64 " forks total\n", uvmexp.forks); 1143 1.196 joerg (void)printf("%" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); 1144 1.196 joerg (void)printf("%" PRIu64 " forks shared address space with parent\n", 1145 1.41 mrg uvmexp.forks_sharevm); 1146 1.1 cgd } 1147 1.1 cgd 1148 1.1 cgd void 1149 1.151 yamt drvstats(int *ovflwp) 1150 1.1 cgd { 1151 1.165 lukem size_t dn; 1152 1.217 mlelstv double dtime; 1153 1.151 yamt int ovflw = *ovflwp; 1154 1.1 cgd 1155 1.29 thorpej /* Calculate disk stat deltas. */ 1156 1.139 dsl cpuswap(); 1157 1.140 blymn drvswap(); 1158 1.139 dsl tkswap(); 1159 1.101 sommerfe 1160 1.140 blymn for (dn = 0; dn < ndrive; ++dn) { 1161 1.217 mlelstv /* elapsed time for disk stats */ 1162 1.218 mlelstv dtime = cur.cp_etime; 1163 1.218 mlelstv if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec) { 1164 1.218 mlelstv dtime = (double)cur.timestamp[dn].tv_sec + 1165 1.218 mlelstv ((double)cur.timestamp[dn].tv_usec / (double)1000000); 1166 1.218 mlelstv } 1167 1.217 mlelstv 1168 1.140 blymn if (!drv_select[dn]) 1169 1.151 yamt continue; 1170 1.151 yamt PRWORD(ovflw, " %*.0f", 3, 1, 1171 1.217 mlelstv (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); 1172 1.136 blymn } 1173 1.151 yamt *ovflwp = ovflw; 1174 1.136 blymn } 1175 1.136 blymn 1176 1.136 blymn void 1177 1.171 christos cpucounters(struct cpu_counter *cc) 1178 1.171 christos { 1179 1.198 joerg static struct cpu_info **cpu_infos; 1180 1.198 joerg static int initialised; 1181 1.198 joerg struct cpu_info **slot; 1182 1.198 joerg 1183 1.198 joerg if (memf == NULL) { 1184 1.198 joerg cc->nintr = uvmexp.intrs; 1185 1.198 joerg cc->nsyscall = uvmexp.syscalls; 1186 1.198 joerg cc->nswtch = uvmexp.swtch; 1187 1.198 joerg cc->nfault = uvmexp.faults; 1188 1.198 joerg cc->ntrap = uvmexp.traps; 1189 1.198 joerg cc->nsoft = uvmexp.softs; 1190 1.198 joerg return; 1191 1.198 joerg } 1192 1.198 joerg 1193 1.198 joerg if (!initialised) { 1194 1.198 joerg kread(namelist, X_CPU_INFOS, &cpu_infos, sizeof(cpu_infos)); 1195 1.198 joerg initialised = 1; 1196 1.198 joerg } 1197 1.198 joerg 1198 1.198 joerg slot = cpu_infos; 1199 1.190 rmind 1200 1.190 rmind memset(cc, 0, sizeof(*cc)); 1201 1.190 rmind 1202 1.190 rmind for (;;) { 1203 1.190 rmind struct cpu_info tci, *ci = NULL; 1204 1.190 rmind 1205 1.190 rmind deref_kptr(slot++, &ci, sizeof(ci), "CPU array trashed"); 1206 1.190 rmind if (!ci) { 1207 1.190 rmind break; 1208 1.190 rmind } 1209 1.190 rmind 1210 1.171 christos if ((size_t)kvm_read(kd, (u_long)ci, &tci, sizeof(tci)) 1211 1.171 christos != sizeof(tci)) { 1212 1.190 rmind warnx("Can't read cpu info from %p (%s)", 1213 1.190 rmind ci, kvm_geterr(kd)); 1214 1.190 rmind memset(cc, 0, sizeof(*cc)); 1215 1.190 rmind return; 1216 1.171 christos } 1217 1.171 christos cc->nintr += tci.ci_data.cpu_nintr; 1218 1.171 christos cc->nsyscall += tci.ci_data.cpu_nsyscall; 1219 1.171 christos cc->nswtch = tci.ci_data.cpu_nswtch; 1220 1.171 christos cc->nfault = tci.ci_data.cpu_nfault; 1221 1.171 christos cc->ntrap = tci.ci_data.cpu_ntrap; 1222 1.171 christos cc->nsoft = tci.ci_data.cpu_nsoft; 1223 1.171 christos } 1224 1.171 christos } 1225 1.171 christos 1226 1.171 christos void 1227 1.151 yamt cpustats(int *ovflwp) 1228 1.1 cgd { 1229 1.38 mrg int state; 1230 1.129 dsl double pcnt, total; 1231 1.120 dbj double stat_us, stat_sy, stat_id; 1232 1.151 yamt int ovflw = *ovflwp; 1233 1.1 cgd 1234 1.1 cgd total = 0; 1235 1.1 cgd for (state = 0; state < CPUSTATES; ++state) 1236 1.29 thorpej total += cur.cp_time[state]; 1237 1.1 cgd if (total) 1238 1.129 dsl pcnt = 100 / total; 1239 1.1 cgd else 1240 1.129 dsl pcnt = 0; 1241 1.129 dsl stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt; 1242 1.129 dsl stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt; 1243 1.129 dsl stat_id = cur.cp_time[CP_IDLE] * pcnt; 1244 1.151 yamt PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us); 1245 1.151 yamt PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1, 1246 1.151 yamt stat_sy); 1247 1.151 yamt PRWORD(ovflw, " %*.0f", 3, 1, stat_id); 1248 1.151 yamt *ovflwp = ovflw; 1249 1.1 cgd } 1250 1.1 cgd 1251 1.1 cgd void 1252 1.66 cgd dointr(int verbose) 1253 1.1 cgd { 1254 1.138 nonaka unsigned long *intrcnt, *ointrcnt; 1255 1.85 enami unsigned long long inttotal, uptime; 1256 1.38 mrg int nintr, inamlen; 1257 1.138 nonaka char *intrname, *ointrname; 1258 1.1 cgd 1259 1.244 simonb if (memf == NULL) { 1260 1.244 simonb doevcnt(verbose, EVCNT_TYPE_INTR); 1261 1.244 simonb return; 1262 1.244 simonb } 1263 1.244 simonb 1264 1.133 chs inttotal = 0; 1265 1.1 cgd uptime = getuptime(); 1266 1.133 chs nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value; 1267 1.133 chs inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value; 1268 1.133 chs if (nintr != 0 && inamlen != 0) { 1269 1.216 ryo (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate"); 1270 1.216 ryo 1271 1.138 nonaka ointrcnt = intrcnt = malloc((size_t)nintr); 1272 1.138 nonaka ointrname = intrname = malloc((size_t)inamlen); 1273 1.133 chs if (intrcnt == NULL || intrname == NULL) 1274 1.133 chs errx(1, "%s", ""); 1275 1.133 chs kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr); 1276 1.133 chs kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen); 1277 1.133 chs nintr /= sizeof(long); 1278 1.133 chs while (--nintr >= 0) { 1279 1.133 chs if (*intrcnt || verbose) 1280 1.133 chs (void)printf("%-34s %16llu %8llu\n", intrname, 1281 1.133 chs (unsigned long long)*intrcnt, 1282 1.133 chs (unsigned long long) 1283 1.133 chs (*intrcnt / uptime)); 1284 1.133 chs intrname += strlen(intrname) + 1; 1285 1.133 chs inttotal += *intrcnt++; 1286 1.133 chs } 1287 1.138 nonaka free(ointrcnt); 1288 1.138 nonaka free(ointrname); 1289 1.1 cgd } 1290 1.133 chs 1291 1.176 matt doevcnt(verbose, EVCNT_TYPE_INTR); 1292 1.66 cgd } 1293 1.66 cgd 1294 1.66 cgd void 1295 1.176 matt doevcnt(int verbose, int type) 1296 1.66 cgd { 1297 1.176 matt static const char * const evtypes [] = { "misc", "intr", "trap" }; 1298 1.176 matt uint64_t counttotal, uptime; 1299 1.66 cgd struct evcntlist allevents; 1300 1.66 cgd struct evcnt evcnt, *evptr; 1301 1.216 ryo size_t evlen_max, total_max, rate_max; 1302 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX]; 1303 1.66 cgd 1304 1.176 matt counttotal = 0; 1305 1.66 cgd uptime = getuptime(); 1306 1.176 matt 1307 1.261 skrll if (memf == NULL) { 1308 1.176 matt const int mib[4] = { CTL_KERN, KERN_EVCNT, type, 1309 1.176 matt verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO }; 1310 1.216 ryo size_t buflen0, buflen = 0; 1311 1.216 ryo void *buf0, *buf = NULL; 1312 1.176 matt const struct evcnt_sysctl *evs, *last_evs; 1313 1.176 matt for (;;) { 1314 1.176 matt size_t newlen; 1315 1.176 matt int error; 1316 1.176 matt if (buflen) 1317 1.176 matt buf = malloc(buflen); 1318 1.176 matt error = sysctl(mib, __arraycount(mib), 1319 1.176 matt buf, &newlen, NULL, 0); 1320 1.176 matt if (error) { 1321 1.193 joerg err(1, "kern.evcnt"); 1322 1.176 matt if (buf) 1323 1.176 matt free(buf); 1324 1.176 matt return; 1325 1.176 matt } 1326 1.176 matt if (newlen <= buflen) { 1327 1.176 matt buflen = newlen; 1328 1.176 matt break; 1329 1.176 matt } 1330 1.176 matt if (buf) 1331 1.176 matt free(buf); 1332 1.176 matt buflen = newlen; 1333 1.176 matt } 1334 1.216 ryo buflen0 = buflen; 1335 1.216 ryo evs = buf0 = buf; 1336 1.216 ryo last_evs = (void *)((char *)buf + buflen); 1337 1.216 ryo buflen /= sizeof(uint64_t); 1338 1.216 ryo /* calc columns */ 1339 1.216 ryo evlen_max = 0; 1340 1.216 ryo total_max = sizeof("total") - 1; 1341 1.216 ryo rate_max = sizeof("rate") - 1; 1342 1.216 ryo while (evs < last_evs 1343 1.216 ryo && buflen >= sizeof(*evs)/sizeof(uint64_t) 1344 1.216 ryo && buflen >= evs->ev_len) { 1345 1.216 ryo char cbuf[64]; 1346 1.216 ryo size_t len; 1347 1.216 ryo len = strlen(evs->ev_strings + evs->ev_grouplen + 1); 1348 1.216 ryo len += evs->ev_grouplen + 1; 1349 1.216 ryo if (evlen_max < len) 1350 1.216 ryo evlen_max= len; 1351 1.216 ryo len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, 1352 1.216 ryo evs->ev_count); 1353 1.216 ryo if (total_max < len) 1354 1.216 ryo total_max = len; 1355 1.216 ryo len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, 1356 1.216 ryo evs->ev_count / uptime); 1357 1.216 ryo if (rate_max < len) 1358 1.216 ryo rate_max = len; 1359 1.216 ryo buflen -= evs->ev_len; 1360 1.259 skrll counttotal += evs->ev_count; 1361 1.216 ryo evs = (const void *) 1362 1.216 ryo ((const uint64_t *)evs + evs->ev_len); 1363 1.216 ryo } 1364 1.259 skrll if (type != EVCNT_TYPE_ANY) { 1365 1.259 skrll char cbuf[64]; 1366 1.259 skrll size_t len; 1367 1.259 skrll 1368 1.259 skrll len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, 1369 1.259 skrll counttotal); 1370 1.259 skrll if (total_max < len) 1371 1.259 skrll total_max = len; 1372 1.259 skrll 1373 1.259 skrll len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, 1374 1.259 skrll counttotal / uptime); 1375 1.259 skrll if (rate_max < len) 1376 1.259 skrll rate_max = len; 1377 1.259 skrll } 1378 1.262 skrll const char *evdesc = type == EVCNT_TYPE_ANY ? 1379 1.262 skrll "event" : "interrupt"; 1380 1.262 skrll const char *typedesc = type == EVCNT_TYPE_ANY ? 1381 1.262 skrll " type" : ""; 1382 1.216 ryo 1383 1.262 skrll (void)printf("%-*s %*s %*s%s\n", 1384 1.262 skrll (int)evlen_max, evdesc, 1385 1.216 ryo (int)total_max, "total", 1386 1.216 ryo (int)rate_max, "rate", 1387 1.262 skrll typedesc); 1388 1.216 ryo 1389 1.216 ryo buflen = buflen0; 1390 1.216 ryo evs = buf0; 1391 1.176 matt last_evs = (void *)((char *)buf + buflen); 1392 1.176 matt buflen /= sizeof(uint64_t); 1393 1.176 matt while (evs < last_evs 1394 1.176 matt && buflen >= sizeof(*evs)/sizeof(uint64_t) 1395 1.176 matt && buflen >= evs->ev_len) { 1396 1.180 nakayama (void)printf(type == EVCNT_TYPE_ANY ? 1397 1.216 ryo "%s %s%*s %*"PRIu64" %*"PRIu64" %s\n" : 1398 1.216 ryo "%s %s%*s %*"PRIu64" %*"PRIu64"\n", 1399 1.176 matt evs->ev_strings, 1400 1.176 matt evs->ev_strings + evs->ev_grouplen + 1, 1401 1.216 ryo (int)evlen_max - (evs->ev_grouplen + 1 1402 1.216 ryo + evs->ev_namelen), "", 1403 1.216 ryo (int)total_max, evs->ev_count, 1404 1.216 ryo (int)rate_max, evs->ev_count / uptime, 1405 1.176 matt (evs->ev_type < __arraycount(evtypes) ? 1406 1.216 ryo evtypes[evs->ev_type] : "?")); 1407 1.176 matt buflen -= evs->ev_len; 1408 1.216 ryo evs = (const void *) 1409 1.216 ryo ((const uint64_t *)evs + evs->ev_len); 1410 1.176 matt } 1411 1.176 matt free(buf); 1412 1.176 matt if (type != EVCNT_TYPE_ANY) 1413 1.216 ryo (void)printf("%-*s %*"PRIu64" %*"PRIu64"\n", 1414 1.216 ryo (int)evlen_max, "Total", 1415 1.216 ryo (int)total_max, counttotal, 1416 1.216 ryo (int)rate_max, counttotal / uptime); 1417 1.176 matt return; 1418 1.261 skrll } 1419 1.176 matt 1420 1.216 ryo if (type == EVCNT_TYPE_ANY) 1421 1.216 ryo (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", 1422 1.216 ryo "type"); 1423 1.216 ryo 1424 1.133 chs kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents); 1425 1.133 chs evptr = TAILQ_FIRST(&allevents); 1426 1.66 cgd while (evptr) { 1427 1.87 lukem deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed"); 1428 1.32 cgd 1429 1.133 chs evptr = TAILQ_NEXT(&evcnt, ev_list); 1430 1.66 cgd if (evcnt.ev_count == 0 && !verbose) 1431 1.66 cgd continue; 1432 1.176 matt if (type != EVCNT_TYPE_ANY && evcnt.ev_type != type) 1433 1.176 matt continue; 1434 1.66 cgd 1435 1.153 christos deref_kptr(evcnt.ev_group, evgroup, 1436 1.153 christos (size_t)evcnt.ev_grouplen + 1, "event chain trashed"); 1437 1.153 christos deref_kptr(evcnt.ev_name, evname, 1438 1.153 christos (size_t)evcnt.ev_namelen + 1, "event chain trashed"); 1439 1.66 cgd 1440 1.180 nakayama (void)printf(type == EVCNT_TYPE_ANY ? 1441 1.180 nakayama "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" : 1442 1.180 nakayama "%s %s%*s %16"PRIu64" %8"PRIu64"\n", 1443 1.176 matt evgroup, evname, 1444 1.83 matt 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "", 1445 1.176 matt evcnt.ev_count, 1446 1.176 matt (evcnt.ev_count / uptime), 1447 1.176 matt (evcnt.ev_type < __arraycount(evtypes) ? 1448 1.86 enami evtypes[evcnt.ev_type] : "?")); 1449 1.176 matt 1450 1.180 nakayama counttotal += evcnt.ev_count; 1451 1.18 pk } 1452 1.176 matt if (type != EVCNT_TYPE_ANY) 1453 1.176 matt (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n", 1454 1.176 matt "Total", counttotal, counttotal / uptime); 1455 1.1 cgd } 1456 1.1 cgd 1457 1.200 joerg static void 1458 1.200 joerg dopool_sysctl(int verbose, int wide) 1459 1.200 joerg { 1460 1.200 joerg uint64_t total, inuse, this_total, this_inuse; 1461 1.200 joerg struct { 1462 1.200 joerg uint64_t pt_nget; 1463 1.200 joerg uint64_t pt_nfail; 1464 1.200 joerg uint64_t pt_nput; 1465 1.200 joerg uint64_t pt_nout; 1466 1.200 joerg uint64_t pt_nitems; 1467 1.200 joerg uint64_t pt_npagealloc; 1468 1.200 joerg uint64_t pt_npagefree; 1469 1.200 joerg uint64_t pt_npages; 1470 1.200 joerg } pool_totals; 1471 1.200 joerg size_t i, len; 1472 1.200 joerg int name_len, ovflw; 1473 1.200 joerg struct pool_sysctl *pp, *data; 1474 1.226 simonb char maxp[32]; 1475 1.200 joerg 1476 1.200 joerg data = asysctlbyname("kern.pool", &len); 1477 1.200 joerg if (data == NULL) 1478 1.225 sevan err(1, "failed to read kern.pool"); 1479 1.200 joerg 1480 1.202 joerg memset(&pool_totals, 0, sizeof pool_totals); 1481 1.200 joerg total = inuse = 0; 1482 1.200 joerg len /= sizeof(*data); 1483 1.200 joerg 1484 1.200 joerg (void)printf("Memory resource pool statistics\n"); 1485 1.200 joerg (void)printf( 1486 1.257 simonb "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%*s%s%s%s\n", 1487 1.200 joerg wide ? 16 : 11, "Name", 1488 1.257 simonb wide ? 9 : 5, "Size", 1489 1.253 simonb wide ? 13 : 9, "Requests", 1490 1.226 simonb wide ? 8 : 5, "Fail", 1491 1.253 simonb wide ? 13 : 9, "Releases", 1492 1.226 simonb wide ? " InUse" : "", 1493 1.226 simonb wide ? " Avail" : "", 1494 1.226 simonb wide ? 11 : 6, "Pgreq", 1495 1.226 simonb wide ? 11 : 6, "Pgrel", 1496 1.253 simonb wide ? 9 : 6, "Npage", 1497 1.257 simonb wide ? " PageSz" : "", 1498 1.253 simonb wide ? 8 : 6, "Hiwat", 1499 1.200 joerg "Minpg", 1500 1.253 simonb wide ? 9 : 6, "Maxpg", 1501 1.253 simonb wide ? 8 : 5, "Idle", 1502 1.236 simonb wide ? " Flags" : "", 1503 1.257 simonb wide ? " Util" : "", 1504 1.257 simonb wide ? " TotalKB" : ""); 1505 1.200 joerg 1506 1.200 joerg name_len = MIN((int)sizeof(pp->pr_wchan), wide ? 16 : 11); 1507 1.200 joerg for (i = 0; i < len; ++i) { 1508 1.200 joerg pp = &data[i]; 1509 1.200 joerg if (pp->pr_nget == 0 && !verbose) 1510 1.200 joerg continue; 1511 1.200 joerg if (pp->pr_maxpages == UINT_MAX) 1512 1.200 joerg (void)snprintf(maxp, sizeof(maxp), "inf"); 1513 1.200 joerg else 1514 1.200 joerg (void)snprintf(maxp, sizeof(maxp), "%" PRIu64, 1515 1.200 joerg pp->pr_maxpages); 1516 1.200 joerg ovflw = 0; 1517 1.200 joerg PRWORD(ovflw, "%-*s", name_len, 0, pp->pr_wchan); 1518 1.257 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 9 : 5, 1, pp->pr_size); 1519 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pp->pr_nget); 1520 1.200 joerg pool_totals.pt_nget += pp->pr_nget; 1521 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pp->pr_nfail); 1522 1.200 joerg pool_totals.pt_nfail += pp->pr_nfail; 1523 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pp->pr_nput); 1524 1.200 joerg pool_totals.pt_nput += pp->pr_nput; 1525 1.200 joerg if (wide) { 1526 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nout); 1527 1.200 joerg pool_totals.pt_nout += pp->pr_nout; 1528 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nitems); 1529 1.200 joerg pool_totals.pt_nitems += pp->pr_nitems; 1530 1.200 joerg } 1531 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagealloc); 1532 1.200 joerg pool_totals.pt_npagealloc += pp->pr_npagealloc; 1533 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagefree); 1534 1.200 joerg pool_totals.pt_npagefree += pp->pr_npagefree; 1535 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 9 : 6, 1, pp->pr_npages); 1536 1.200 joerg pool_totals.pt_npages += pp->pr_npages; 1537 1.200 joerg if (wide) 1538 1.257 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_pagesize); 1539 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pp->pr_hiwat); 1540 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_minpages); 1541 1.253 simonb PRWORD(ovflw, " %*s", wide ? 9 : 6, 1, maxp); 1542 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pp->pr_nidle); 1543 1.200 joerg if (wide) 1544 1.236 simonb PRWORD(ovflw, " 0x%0*" PRIx64, 6, 1, 1545 1.200 joerg pp->pr_flags); 1546 1.200 joerg 1547 1.200 joerg this_inuse = pp->pr_nout * pp->pr_size; 1548 1.200 joerg this_total = pp->pr_npages * pp->pr_pagesize; 1549 1.200 joerg if (pp->pr_flags & PR_RECURSIVE) { 1550 1.200 joerg /* 1551 1.200 joerg * Don't count in-use memory, since it's part 1552 1.200 joerg * of another pool and will be accounted for 1553 1.200 joerg * there. 1554 1.200 joerg */ 1555 1.200 joerg total += (this_total - this_inuse); 1556 1.200 joerg } else { 1557 1.200 joerg inuse += this_inuse; 1558 1.200 joerg total += this_total; 1559 1.200 joerg } 1560 1.200 joerg if (wide) { 1561 1.257 simonb if (this_total == 0) { 1562 1.200 joerg (void)printf(" ---"); 1563 1.257 simonb } else { 1564 1.257 simonb (void)printf(" %5.1f%% %10" PRIu64, 1565 1.257 simonb (100.0 * this_inuse) / this_total, 1566 1.257 simonb this_total / KILO); 1567 1.257 simonb } 1568 1.200 joerg } 1569 1.200 joerg (void)printf("\n"); 1570 1.200 joerg } 1571 1.226 simonb ovflw = 0; 1572 1.226 simonb PRWORD(ovflw, "%-*s", name_len, 0, "Totals"); 1573 1.257 simonb PRWORD(ovflw, " %*s", wide ? 9 : 5, 1, ""); 1574 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pool_totals.pt_nget); 1575 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); 1576 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pool_totals.pt_nput); 1577 1.200 joerg if (wide) { 1578 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); 1579 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); 1580 1.200 joerg } 1581 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); 1582 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); 1583 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 9 : 6, 1, pool_totals.pt_npages); 1584 1.226 simonb (void)printf("\n"); 1585 1.200 joerg 1586 1.200 joerg inuse /= KILO; 1587 1.200 joerg total /= KILO; 1588 1.200 joerg (void)printf( 1589 1.201 joerg "\nIn use %" PRIu64 "K, " 1590 1.201 joerg "total allocated %" PRIu64 "K; utilization %.1f%%\n", 1591 1.200 joerg inuse, total, (100.0 * inuse) / total); 1592 1.200 joerg 1593 1.200 joerg free(data); 1594 1.200 joerg } 1595 1.200 joerg 1596 1.51 pk void 1597 1.126 simonb dopool(int verbose, int wide) 1598 1.51 pk { 1599 1.69 enami int first, ovflw; 1600 1.87 lukem void *addr; 1601 1.255 simonb uint64_t total, inuse, this_total, this_inuse; 1602 1.189 mrg struct { 1603 1.189 mrg uint64_t pt_nget; 1604 1.189 mrg uint64_t pt_nfail; 1605 1.189 mrg uint64_t pt_nput; 1606 1.189 mrg uint64_t pt_nout; 1607 1.189 mrg uint64_t pt_nitems; 1608 1.189 mrg uint64_t pt_npagealloc; 1609 1.189 mrg uint64_t pt_npagefree; 1610 1.189 mrg uint64_t pt_npages; 1611 1.189 mrg } pool_totals; 1612 1.157 ad TAILQ_HEAD(,pool) pool_head; 1613 1.51 pk struct pool pool, *pp = &pool; 1614 1.98 christos struct pool_allocator pa; 1615 1.226 simonb char maxp[32], name[32]; 1616 1.51 pk 1617 1.247 rillig if (memf == NULL) { 1618 1.247 rillig dopool_sysctl(verbose, wide); 1619 1.247 rillig return; 1620 1.247 rillig } 1621 1.200 joerg 1622 1.189 mrg memset(&pool_totals, 0, sizeof pool_totals); 1623 1.133 chs kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); 1624 1.157 ad addr = TAILQ_FIRST(&pool_head); 1625 1.51 pk 1626 1.126 simonb total = inuse = 0; 1627 1.126 simonb 1628 1.157 ad for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { 1629 1.87 lukem deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); 1630 1.98 christos deref_kptr(pp->pr_alloc, &pa, sizeof(pa), 1631 1.125 dsainty "pool allocator trashed"); 1632 1.87 lukem deref_kptr(pp->pr_wchan, name, sizeof(name), 1633 1.98 christos "pool wait channel trashed"); 1634 1.87 lukem name[sizeof(name)-1] = '\0'; 1635 1.51 pk 1636 1.51 pk if (first) { 1637 1.51 pk (void)printf("Memory resource pool statistics\n"); 1638 1.51 pk (void)printf( 1639 1.257 simonb "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%*s%s%s%s\n", 1640 1.126 simonb wide ? 16 : 11, "Name", 1641 1.257 simonb wide ? 9 : 5, "Size", 1642 1.253 simonb wide ? 13 : 9, "Requests", 1643 1.226 simonb wide ? 8 : 5, "Fail", 1644 1.253 simonb wide ? 13 : 9, "Releases", 1645 1.226 simonb wide ? " InUse" : "", 1646 1.226 simonb wide ? " Avail" : "", 1647 1.226 simonb wide ? 11 : 6, "Pgreq", 1648 1.226 simonb wide ? 11 : 6, "Pgrel", 1649 1.253 simonb wide ? 9 : 6, "Npage", 1650 1.257 simonb wide ? " PageSz" : "", 1651 1.253 simonb wide ? 8 : 6, "Hiwat", 1652 1.75 enami "Minpg", 1653 1.253 simonb wide ? 9 : 6, "Maxpg", 1654 1.253 simonb wide ? 8 : 5, "Idle", 1655 1.236 simonb wide ? " Flags" : "", 1656 1.257 simonb wide ? " Util" : "", 1657 1.257 simonb wide ? " TotalKB" : ""); 1658 1.51 pk first = 0; 1659 1.51 pk } 1660 1.113 dsl if (pp->pr_nget == 0 && !verbose) 1661 1.113 dsl continue; 1662 1.51 pk if (pp->pr_maxpages == UINT_MAX) 1663 1.153 christos (void)snprintf(maxp, sizeof(maxp), "inf"); 1664 1.51 pk else 1665 1.153 christos (void)snprintf(maxp, sizeof(maxp), "%u", 1666 1.153 christos pp->pr_maxpages); 1667 1.69 enami ovflw = 0; 1668 1.126 simonb PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name); 1669 1.257 simonb PRWORD(ovflw, " %*u", wide ? 9 : 5, 1, pp->pr_size); 1670 1.253 simonb PRWORD(ovflw, " %*lu", wide ? 13 : 9, 1, pp->pr_nget); 1671 1.189 mrg pool_totals.pt_nget += pp->pr_nget; 1672 1.226 simonb PRWORD(ovflw, " %*lu", wide ? 8 : 5, 1, pp->pr_nfail); 1673 1.189 mrg pool_totals.pt_nfail += pp->pr_nfail; 1674 1.253 simonb PRWORD(ovflw, " %*lu", wide ? 13 : 9, 1, pp->pr_nput); 1675 1.189 mrg pool_totals.pt_nput += pp->pr_nput; 1676 1.189 mrg if (wide) { 1677 1.226 simonb PRWORD(ovflw, " %*u", 9, 1, pp->pr_nout); 1678 1.189 mrg pool_totals.pt_nout += pp->pr_nout; 1679 1.226 simonb PRWORD(ovflw, " %*u", 9, 1, pp->pr_nitems); 1680 1.189 mrg pool_totals.pt_nitems += pp->pr_nitems; 1681 1.189 mrg } 1682 1.226 simonb PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagealloc); 1683 1.189 mrg pool_totals.pt_npagealloc += pp->pr_npagealloc; 1684 1.226 simonb PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagefree); 1685 1.189 mrg pool_totals.pt_npagefree += pp->pr_npagefree; 1686 1.253 simonb PRWORD(ovflw, " %*u", wide ? 9 : 6, 1, pp->pr_npages); 1687 1.189 mrg pool_totals.pt_npages += pp->pr_npages; 1688 1.126 simonb if (wide) 1689 1.257 simonb PRWORD(ovflw, " %*u", 9, 1, pa.pa_pagesz); 1690 1.253 simonb PRWORD(ovflw, " %*u", wide ? 8 : 6, 1, pp->pr_hiwat); 1691 1.126 simonb PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages); 1692 1.253 simonb PRWORD(ovflw, " %*s", wide ? 9 : 6, 1, maxp); 1693 1.253 simonb PRWORD(ovflw, " %*lu", wide ? 8 : 5, 1, pp->pr_nidle); 1694 1.126 simonb if (wide) 1695 1.236 simonb PRWORD(ovflw, " 0x%0*x", 6, 1, 1696 1.126 simonb pp->pr_flags | pp->pr_roflags); 1697 1.51 pk 1698 1.255 simonb this_inuse = (uint64_t)pp->pr_nout * pp->pr_size; 1699 1.255 simonb this_total = (uint64_t)pp->pr_npages * pa.pa_pagesz; 1700 1.84 bjh21 if (pp->pr_roflags & PR_RECURSIVE) { 1701 1.84 bjh21 /* 1702 1.84 bjh21 * Don't count in-use memory, since it's part 1703 1.84 bjh21 * of another pool and will be accounted for 1704 1.84 bjh21 * there. 1705 1.84 bjh21 */ 1706 1.126 simonb total += (this_total - this_inuse); 1707 1.84 bjh21 } else { 1708 1.126 simonb inuse += this_inuse; 1709 1.126 simonb total += this_total; 1710 1.84 bjh21 } 1711 1.126 simonb if (wide) { 1712 1.257 simonb if (this_total == 0) { 1713 1.153 christos (void)printf(" ---"); 1714 1.257 simonb } else { 1715 1.257 simonb (void)printf(" %5.1f%% %10" PRIu64, 1716 1.257 simonb (100.0 * this_inuse) / this_total, 1717 1.257 simonb this_total / KILO); 1718 1.257 simonb } 1719 1.126 simonb } 1720 1.153 christos (void)printf("\n"); 1721 1.51 pk } 1722 1.226 simonb ovflw = 0; 1723 1.226 simonb PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, "Totals"); 1724 1.257 simonb PRWORD(ovflw, " %*s", wide ? 9 : 5, 1, ""); 1725 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pool_totals.pt_nget); 1726 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); 1727 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 13 : 9, 1, pool_totals.pt_nput); 1728 1.226 simonb if (wide) { 1729 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); 1730 1.226 simonb PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); 1731 1.226 simonb } 1732 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); 1733 1.226 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); 1734 1.253 simonb PRWORD(ovflw, " %*" PRIu64, wide ? 9 : 6, 1, pool_totals.pt_npages); 1735 1.226 simonb (void)printf("\n"); 1736 1.51 pk 1737 1.152 christos inuse /= KILO; 1738 1.152 christos total /= KILO; 1739 1.153 christos (void)printf( 1740 1.255 simonb "\nIn use %" PRIu64 "K, " 1741 1.255 simonb "total allocated %" PRIu64 "K; utilization %.1f%%\n", 1742 1.126 simonb inuse, total, (100.0 * inuse) / total); 1743 1.1 cgd } 1744 1.96 enami 1745 1.200 joerg static void 1746 1.200 joerg dopoolcache_sysctl(int verbose) 1747 1.200 joerg { 1748 1.200 joerg struct pool_sysctl *data, *pp; 1749 1.200 joerg size_t i, len; 1750 1.200 joerg bool first = true; 1751 1.200 joerg int ovflw; 1752 1.200 joerg uint64_t tot; 1753 1.208 christos double p; 1754 1.200 joerg 1755 1.200 joerg data = asysctlbyname("kern.pool", &len); 1756 1.200 joerg if (data == NULL) 1757 1.225 sevan err(1, "failed to read kern.pool"); 1758 1.200 joerg len /= sizeof(*data); 1759 1.200 joerg 1760 1.200 joerg for (i = 0; i < len; ++i) { 1761 1.200 joerg pp = &data[i]; 1762 1.200 joerg if (pp->pr_cache_meta_size == 0) 1763 1.200 joerg continue; 1764 1.200 joerg 1765 1.200 joerg if (pp->pr_cache_nmiss_global == 0 && !verbose) 1766 1.200 joerg continue; 1767 1.200 joerg 1768 1.200 joerg if (first) { 1769 1.200 joerg (void)printf("Pool cache statistics.\n"); 1770 1.200 joerg (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", 1771 1.200 joerg 12, "Name", 1772 1.200 joerg 6, "Spin", 1773 1.200 joerg 6, "GrpSz", 1774 1.200 joerg 5, "Full", 1775 1.200 joerg 5, "Emty", 1776 1.200 joerg 10, "PoolLayer", 1777 1.200 joerg 11, "CacheLayer", 1778 1.200 joerg 6, "Hit%", 1779 1.200 joerg 12, "CpuLayer", 1780 1.200 joerg 6, "Hit%" 1781 1.200 joerg ); 1782 1.200 joerg first = false; 1783 1.200 joerg } 1784 1.200 joerg 1785 1.200 joerg ovflw = 0; 1786 1.200 joerg PRWORD(ovflw, "%-*s", MIN((int)sizeof(pp->pr_wchan), 13), 1, 1787 1.200 joerg pp->pr_wchan); 1788 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_ncontended); 1789 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_meta_size); 1790 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nfull); 1791 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nempty); 1792 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 10, 1, pp->pr_cache_nmiss_global); 1793 1.200 joerg 1794 1.200 joerg tot = pp->pr_cache_nhit_global + pp->pr_cache_nmiss_global; 1795 1.200 joerg p = pp->pr_cache_nhit_global * 100.0 / tot; 1796 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 11, 1, tot); 1797 1.200 joerg PRWORD(ovflw, " %*.1f", 6, 1, p); 1798 1.200 joerg 1799 1.200 joerg tot = pp->pr_cache_nhit_pcpu + pp->pr_cache_nmiss_pcpu; 1800 1.200 joerg p = pp->pr_cache_nhit_pcpu * 100.0 / tot; 1801 1.200 joerg PRWORD(ovflw, " %*" PRIu64, 12, 1, tot); 1802 1.200 joerg PRWORD(ovflw, " %*.1f", 6, 1, p); 1803 1.200 joerg printf("\n"); 1804 1.200 joerg } 1805 1.200 joerg } 1806 1.200 joerg 1807 1.96 enami void 1808 1.182 yamt dopoolcache(int verbose) 1809 1.96 enami { 1810 1.96 enami struct pool_cache pool_cache, *pc = &pool_cache; 1811 1.154 ad pool_cache_cpu_t cache_cpu, *cc = &cache_cpu; 1812 1.157 ad TAILQ_HEAD(,pool) pool_head; 1813 1.154 ad struct pool pool, *pp = &pool; 1814 1.154 ad char name[32]; 1815 1.241 ad uint64_t cpuhit, cpumiss, pchit, pcmiss, contended, tot; 1816 1.241 ad uint32_t nfull; 1817 1.154 ad void *addr; 1818 1.165 lukem int first, ovflw; 1819 1.165 lukem size_t i; 1820 1.154 ad double p; 1821 1.96 enami 1822 1.247 rillig if (memf == NULL) { 1823 1.247 rillig dopoolcache_sysctl(verbose); 1824 1.247 rillig return; 1825 1.247 rillig } 1826 1.200 joerg 1827 1.154 ad kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); 1828 1.157 ad addr = TAILQ_FIRST(&pool_head); 1829 1.96 enami 1830 1.157 ad for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { 1831 1.154 ad deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); 1832 1.154 ad if (pp->pr_cache == NULL) 1833 1.96 enami continue; 1834 1.154 ad deref_kptr(pp->pr_wchan, name, sizeof(name), 1835 1.154 ad "pool wait channel trashed"); 1836 1.154 ad deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed"); 1837 1.154 ad name[sizeof(name)-1] = '\0'; 1838 1.154 ad 1839 1.154 ad cpuhit = 0; 1840 1.154 ad cpumiss = 0; 1841 1.241 ad pcmiss = 0; 1842 1.241 ad contended = 0; 1843 1.241 ad nfull = 0; 1844 1.184 jym for (i = 0; i < __arraycount(pc->pc_cpus); i++) { 1845 1.154 ad if ((addr = pc->pc_cpus[i]) == NULL) 1846 1.154 ad continue; 1847 1.154 ad deref_kptr(addr, cc, sizeof(*cc), 1848 1.154 ad "pool cache cpu trashed"); 1849 1.154 ad cpuhit += cc->cc_hits; 1850 1.154 ad cpumiss += cc->cc_misses; 1851 1.241 ad pcmiss += cc->cc_pcmisses; 1852 1.241 ad nfull += cc->cc_nfull; 1853 1.241 ad contended += cc->cc_contended; 1854 1.137 chs } 1855 1.241 ad pchit = cpumiss - pcmiss; 1856 1.241 ad 1857 1.241 ad if (pcmiss == 0 && !verbose) 1858 1.241 ad continue; 1859 1.154 ad 1860 1.154 ad if (first) { 1861 1.154 ad (void)printf("Pool cache statistics.\n"); 1862 1.156 ad (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", 1863 1.154 ad 12, "Name", 1864 1.154 ad 6, "Spin", 1865 1.156 ad 6, "GrpSz", 1866 1.156 ad 5, "Full", 1867 1.156 ad 5, "Emty", 1868 1.156 ad 10, "PoolLayer", 1869 1.156 ad 11, "CacheLayer", 1870 1.154 ad 6, "Hit%", 1871 1.154 ad 12, "CpuLayer", 1872 1.154 ad 6, "Hit%" 1873 1.154 ad ); 1874 1.154 ad first = 0; 1875 1.96 enami } 1876 1.154 ad 1877 1.154 ad ovflw = 0; 1878 1.154 ad PRWORD(ovflw, "%-*s", 13, 1, name); 1879 1.241 ad PRWORD(ovflw, " %*llu", 6, 1, (long long)contended); 1880 1.156 ad PRWORD(ovflw, " %*u", 6, 1, pc->pc_pcgsize); 1881 1.241 ad PRWORD(ovflw, " %*u", 5, 1, nfull); 1882 1.241 ad PRWORD(ovflw, " %*u", 5, 1, 0); 1883 1.241 ad PRWORD(ovflw, " %*llu", 10, 1, (long long)pcmiss); 1884 1.154 ad 1885 1.241 ad tot = pchit + pcmiss; 1886 1.241 ad p = pchit * 100.0 / (tot); 1887 1.156 ad PRWORD(ovflw, " %*llu", 11, 1, (long long)tot); 1888 1.154 ad PRWORD(ovflw, " %*.1f", 6, 1, p); 1889 1.154 ad 1890 1.154 ad tot = cpuhit + cpumiss; 1891 1.154 ad p = cpuhit * 100.0 / (tot); 1892 1.154 ad PRWORD(ovflw, " %*llu", 12, 1, (long long)tot); 1893 1.154 ad PRWORD(ovflw, " %*.1f", 6, 1, p); 1894 1.154 ad printf("\n"); 1895 1.96 enami } 1896 1.96 enami } 1897 1.90 lukem 1898 1.87 lukem enum hashtype { /* from <sys/systm.h> */ 1899 1.87 lukem HASH_LIST, 1900 1.229 ad HASH_SLIST, 1901 1.229 ad HASH_TAILQ, 1902 1.229 ad HASH_PSLIST 1903 1.87 lukem }; 1904 1.87 lukem 1905 1.87 lukem struct kernel_hash { 1906 1.90 lukem const char * description; /* description */ 1907 1.90 lukem int hashsize; /* nlist index for hash size */ 1908 1.90 lukem int hashtbl; /* nlist index for hash table */ 1909 1.90 lukem enum hashtype type; /* type of hash table */ 1910 1.101 sommerfe size_t offset; /* offset of {LIST,TAILQ}_NEXT */ 1911 1.87 lukem } khashes[] = 1912 1.87 lukem { 1913 1.87 lukem { 1914 1.90 lukem "buffer hash", 1915 1.90 lukem X_BUFHASH, X_BUFHASHTBL, 1916 1.90 lukem HASH_LIST, offsetof(struct buf, b_hash) 1917 1.90 lukem }, { 1918 1.90 lukem "ipv4 address -> interface hash", 1919 1.87 lukem X_IFADDRHASH, X_IFADDRHASHTBL, 1920 1.87 lukem HASH_LIST, offsetof(struct in_ifaddr, ia_hash), 1921 1.90 lukem }, { 1922 1.90 lukem "user info (uid -> used processes) hash", 1923 1.90 lukem X_UIHASH, X_UIHASHTBL, 1924 1.258 ad HASH_SLIST, offsetof(struct uidinfo, ui_hash), 1925 1.90 lukem }, { 1926 1.229 ad "vnode cache hash", 1927 1.237 ad X_VCACHEHASH, X_VCACHETBL, 1928 1.229 ad HASH_SLIST, offsetof(struct vnode_impl, vi_hash), 1929 1.229 ad }, { 1930 1.90 lukem NULL, -1, -1, 0, 0, 1931 1.87 lukem } 1932 1.87 lukem }; 1933 1.87 lukem 1934 1.87 lukem void 1935 1.88 lukem dohashstat(int verbose, int todo, const char *hashname) 1936 1.101 sommerfe { 1937 1.87 lukem LIST_HEAD(, generic) *hashtbl_list; 1938 1.229 ad SLIST_HEAD(, generic) *hashtbl_slist; 1939 1.87 lukem TAILQ_HEAD(, generic) *hashtbl_tailq; 1940 1.87 lukem struct kernel_hash *curhash; 1941 1.118 itojun void *hashaddr, *hashbuf, *nhashbuf, *nextaddr; 1942 1.87 lukem size_t elemsize, hashbufsize, thissize; 1943 1.165 lukem u_long hashsize, i; 1944 1.165 lukem int used, items, chain, maxchain; 1945 1.87 lukem 1946 1.247 rillig if (memf == NULL) { 1947 1.247 rillig dohashstat_sysctl(verbose, todo, hashname); 1948 1.247 rillig return; 1949 1.247 rillig } 1950 1.245 simonb 1951 1.87 lukem hashbuf = NULL; 1952 1.87 lukem hashbufsize = 0; 1953 1.88 lukem 1954 1.88 lukem if (todo & HASHLIST) { 1955 1.153 christos (void)printf("Supported hashes:\n"); 1956 1.90 lukem for (curhash = khashes; curhash->description; curhash++) { 1957 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 || 1958 1.90 lukem hashnl[curhash->hashtbl].n_value == 0) 1959 1.90 lukem continue; 1960 1.153 christos (void)printf("\t%-16s%s\n", 1961 1.90 lukem hashnl[curhash->hashsize].n_name + 1, 1962 1.90 lukem curhash->description); 1963 1.88 lukem } 1964 1.88 lukem return; 1965 1.88 lukem } 1966 1.88 lukem 1967 1.88 lukem if (hashname != NULL) { 1968 1.90 lukem for (curhash = khashes; curhash->description; curhash++) { 1969 1.90 lukem if (strcmp(hashnl[curhash->hashsize].n_name + 1, 1970 1.90 lukem hashname) == 0 && 1971 1.101 sommerfe hashnl[curhash->hashsize].n_value != 0 && 1972 1.90 lukem hashnl[curhash->hashtbl].n_value != 0) 1973 1.88 lukem break; 1974 1.88 lukem } 1975 1.90 lukem if (curhash->description == NULL) { 1976 1.90 lukem warnx("%s: no such hash", hashname); 1977 1.90 lukem return; 1978 1.90 lukem } 1979 1.88 lukem } 1980 1.88 lukem 1981 1.153 christos (void)printf( 1982 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n" 1983 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n", 1984 1.88 lukem "", "total", "used", "util", "num", "average", "maximum", 1985 1.88 lukem "hash table", "buckets", "buckets", "%", "items", "chain", 1986 1.88 lukem "chain"); 1987 1.87 lukem 1988 1.90 lukem for (curhash = khashes; curhash->description; curhash++) { 1989 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 || 1990 1.90 lukem hashnl[curhash->hashtbl].n_value == 0) 1991 1.90 lukem continue; 1992 1.88 lukem if (hashname != NULL && 1993 1.90 lukem strcmp(hashnl[curhash->hashsize].n_name + 1, hashname)) 1994 1.88 lukem continue; 1995 1.243 simonb switch (curhash->type) { 1996 1.243 simonb case HASH_LIST: 1997 1.243 simonb elemsize = sizeof(*hashtbl_list); 1998 1.243 simonb break; 1999 1.243 simonb case HASH_SLIST: 2000 1.243 simonb elemsize = sizeof(*hashtbl_slist); 2001 1.243 simonb break; 2002 1.243 simonb case HASH_TAILQ: 2003 1.243 simonb elemsize = sizeof(*hashtbl_tailq); 2004 1.243 simonb break; 2005 1.243 simonb default: 2006 1.243 simonb /* shouldn't get here */ 2007 1.243 simonb continue; 2008 1.243 simonb } 2009 1.90 lukem deref_kptr((void *)hashnl[curhash->hashsize].n_value, 2010 1.90 lukem &hashsize, sizeof(hashsize), 2011 1.90 lukem hashnl[curhash->hashsize].n_name); 2012 1.87 lukem hashsize++; 2013 1.90 lukem deref_kptr((void *)hashnl[curhash->hashtbl].n_value, 2014 1.90 lukem &hashaddr, sizeof(hashaddr), 2015 1.90 lukem hashnl[curhash->hashtbl].n_name); 2016 1.87 lukem if (verbose) 2017 1.153 christos (void)printf( 2018 1.153 christos "%s %lu, %s %p, offset %ld, elemsize %llu\n", 2019 1.90 lukem hashnl[curhash->hashsize].n_name + 1, hashsize, 2020 1.90 lukem hashnl[curhash->hashtbl].n_name + 1, hashaddr, 2021 1.101 sommerfe (long)curhash->offset, 2022 1.91 jmc (unsigned long long)elemsize); 2023 1.87 lukem thissize = hashsize * elemsize; 2024 1.144 christos if (hashbuf == NULL || thissize > hashbufsize) { 2025 1.118 itojun if ((nhashbuf = realloc(hashbuf, thissize)) == NULL) 2026 1.101 sommerfe errx(1, "malloc hashbuf %llu", 2027 1.91 jmc (unsigned long long)hashbufsize); 2028 1.118 itojun hashbuf = nhashbuf; 2029 1.118 itojun hashbufsize = thissize; 2030 1.87 lukem } 2031 1.87 lukem deref_kptr(hashaddr, hashbuf, thissize, 2032 1.90 lukem hashnl[curhash->hashtbl].n_name); 2033 1.87 lukem used = 0; 2034 1.87 lukem items = maxchain = 0; 2035 1.135 lukem if (curhash->type == HASH_LIST) { 2036 1.87 lukem hashtbl_list = hashbuf; 2037 1.229 ad hashtbl_slist = NULL; 2038 1.229 ad hashtbl_tailq = NULL; 2039 1.229 ad } else if (curhash->type == HASH_SLIST) { 2040 1.229 ad hashtbl_list = NULL; 2041 1.229 ad hashtbl_slist = hashbuf; 2042 1.135 lukem hashtbl_tailq = NULL; 2043 1.135 lukem } else { 2044 1.135 lukem hashtbl_list = NULL; 2045 1.229 ad hashtbl_slist = NULL; 2046 1.87 lukem hashtbl_tailq = hashbuf; 2047 1.135 lukem } 2048 1.87 lukem for (i = 0; i < hashsize; i++) { 2049 1.87 lukem if (curhash->type == HASH_LIST) 2050 1.87 lukem nextaddr = LIST_FIRST(&hashtbl_list[i]); 2051 1.229 ad else if (curhash->type == HASH_SLIST) 2052 1.229 ad nextaddr = SLIST_FIRST(&hashtbl_slist[i]); 2053 1.87 lukem else 2054 1.87 lukem nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]); 2055 1.87 lukem if (nextaddr == NULL) 2056 1.87 lukem continue; 2057 1.87 lukem if (verbose) 2058 1.165 lukem (void)printf("%5lu: %p\n", i, nextaddr); 2059 1.87 lukem used++; 2060 1.87 lukem chain = 0; 2061 1.87 lukem do { 2062 1.87 lukem chain++; 2063 1.87 lukem deref_kptr((char *)nextaddr + curhash->offset, 2064 1.87 lukem &nextaddr, sizeof(void *), 2065 1.87 lukem "hash chain corrupted"); 2066 1.87 lukem if (verbose > 1) 2067 1.153 christos (void)printf("got nextaddr as %p\n", 2068 1.87 lukem nextaddr); 2069 1.87 lukem } while (nextaddr != NULL); 2070 1.87 lukem items += chain; 2071 1.87 lukem if (verbose && chain > 1) 2072 1.153 christos (void)printf("\tchain = %d\n", chain); 2073 1.87 lukem if (chain > maxchain) 2074 1.87 lukem maxchain = chain; 2075 1.87 lukem } 2076 1.153 christos (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n", 2077 1.90 lukem hashnl[curhash->hashsize].n_name + 1, 2078 1.87 lukem hashsize, used, used * 100.0 / hashsize, 2079 1.93 lukem items, used ? (double)items / used : 0.0, maxchain); 2080 1.87 lukem } 2081 1.87 lukem } 2082 1.87 lukem 2083 1.245 simonb void 2084 1.245 simonb dohashstat_sysctl(int verbose, int todo, const char *hashname) 2085 1.245 simonb { 2086 1.245 simonb struct hashstat_sysctl hash, *data, *hs; 2087 1.245 simonb int mib[3]; 2088 1.245 simonb int error; 2089 1.245 simonb size_t i, len, miblen; 2090 1.245 simonb 2091 1.245 simonb 2092 1.245 simonb miblen = __arraycount(mib); 2093 1.245 simonb error = sysctlnametomib("kern.hashstat", mib, &miblen); 2094 1.245 simonb if (error) 2095 1.245 simonb err(EXIT_FAILURE, "nametomib kern.hashstat failed"); 2096 1.245 simonb assert(miblen < 3); 2097 1.245 simonb 2098 1.245 simonb if (todo & HASHLIST) { 2099 1.245 simonb mib[miblen] = CTL_DESCRIBE; 2100 1.245 simonb miblen++; 2101 1.245 simonb }; 2102 1.245 simonb 2103 1.245 simonb if (hashname) { 2104 1.245 simonb mib[miblen] = CTL_QUERY; 2105 1.245 simonb miblen++; 2106 1.245 simonb memset(&hash, 0, sizeof(hash)); 2107 1.245 simonb strlcpy(hash.hash_name, hashname, sizeof(hash.hash_name)); 2108 1.245 simonb len = sizeof(hash); 2109 1.245 simonb error = sysctl(mib, miblen, &hash, &len, &hash, len); 2110 1.245 simonb if (error == ENOENT) { 2111 1.245 simonb err(1, "hash '%s' not found", hashname); 2112 1.245 simonb return; 2113 1.245 simonb } else if (error) { 2114 1.245 simonb err(1, "sysctl kern.hashstat query failed"); 2115 1.245 simonb return; 2116 1.245 simonb } 2117 1.245 simonb 2118 1.245 simonb data = &hash; 2119 1.245 simonb len = 1; 2120 1.245 simonb } else { 2121 1.245 simonb data = asysctl(mib, miblen, &len); 2122 1.245 simonb if (data == NULL) 2123 1.245 simonb err(1, "failed to read kern.hashstat"); 2124 1.245 simonb len /= sizeof(*data); 2125 1.245 simonb } 2126 1.245 simonb 2127 1.245 simonb if (todo & HASHLIST) { 2128 1.245 simonb printf("Supported hashes:\n"); 2129 1.245 simonb for (i = 0, hs = data; i < len; i++, hs++) { 2130 1.245 simonb printf("\t%-16s%s\n", hs->hash_name, hs->hash_desc); 2131 1.245 simonb } 2132 1.245 simonb } else { 2133 1.245 simonb printf("%-16s %8s %8s %8s %8s %8s %8s\n" 2134 1.245 simonb "%-16s %8s %8s %8s %8s %8s %8s\n", 2135 1.245 simonb "", "total", "used", "util", "num", "average", "maximum", 2136 1.245 simonb "hash table", "buckets", "buckets", "%", "items", "chain", 2137 1.245 simonb "chain"); 2138 1.245 simonb for (i = 0, hs = data; i < len; i++, hs++) { 2139 1.245 simonb printf("%-16s %8"PRId64" %8"PRId64" %8.2f %8"PRId64 2140 1.245 simonb " %8.2f %8"PRId64"\n", 2141 1.245 simonb hs->hash_name, hs->hash_size, hs->hash_used, 2142 1.245 simonb hs->hash_used * 100.0 / hs->hash_size, hs->hash_items, 2143 1.245 simonb hs->hash_used ? (double)hs->hash_items / hs->hash_used : 0.0, 2144 1.245 simonb hs->hash_maxchain); 2145 1.245 simonb } 2146 1.245 simonb } 2147 1.245 simonb 2148 1.245 simonb if (!hashname && (data != NULL)) 2149 1.245 simonb free(data); 2150 1.245 simonb } 2151 1.245 simonb 2152 1.1 cgd /* 2153 1.230 msaitoh * kreadc like kread but returns 1 if successful, 0 otherwise 2154 1.147 kardel */ 2155 1.147 kardel int 2156 1.147 kardel kreadc(struct nlist *nl, int nlx, void *addr, size_t size) 2157 1.147 kardel { 2158 1.147 kardel const char *sym; 2159 1.147 kardel 2160 1.147 kardel sym = nl[nlx].n_name; 2161 1.147 kardel if (*sym == '_') 2162 1.147 kardel ++sym; 2163 1.147 kardel if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) 2164 1.147 kardel return 0; 2165 1.147 kardel deref_kptr((void *)nl[nlx].n_value, addr, size, sym); 2166 1.147 kardel return 1; 2167 1.147 kardel } 2168 1.147 kardel 2169 1.147 kardel /* 2170 1.90 lukem * kread reads something from the kernel, given its nlist index in namelist[]. 2171 1.1 cgd */ 2172 1.1 cgd void 2173 1.133 chs kread(struct nlist *nl, int nlx, void *addr, size_t size) 2174 1.1 cgd { 2175 1.50 mycroft const char *sym; 2176 1.1 cgd 2177 1.133 chs sym = nl[nlx].n_name; 2178 1.87 lukem if (*sym == '_') 2179 1.87 lukem ++sym; 2180 1.133 chs if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) 2181 1.87 lukem errx(1, "symbol %s not defined", sym); 2182 1.133 chs deref_kptr((void *)nl[nlx].n_value, addr, size, sym); 2183 1.87 lukem } 2184 1.87 lukem 2185 1.87 lukem /* 2186 1.101 sommerfe * Dereference the kernel pointer `kptr' and fill in the local copy 2187 1.87 lukem * pointed to by `ptr'. The storage space must be pre-allocated, 2188 1.87 lukem * and the size of the copy passed in `len'. 2189 1.87 lukem */ 2190 1.87 lukem void 2191 1.87 lukem deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg) 2192 1.87 lukem { 2193 1.87 lukem 2194 1.87 lukem if (*msg == '_') 2195 1.87 lukem msg++; 2196 1.165 lukem if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) 2197 1.87 lukem errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd)); 2198 1.1 cgd } 2199 1.1 cgd 2200 1.45 thorpej /* 2201 1.181 mrg * Traverse the kernel history buffers, performing the requested action. 2202 1.45 thorpej * 2203 1.45 thorpej * Note, we assume that if we're not listing, we're dumping. 2204 1.45 thorpej */ 2205 1.45 thorpej void 2206 1.73 simonb hist_traverse(int todo, const char *histname) 2207 1.45 thorpej { 2208 1.210 pgoyette struct kern_history_head histhead; 2209 1.210 pgoyette struct kern_history hist, *histkva; 2210 1.210 pgoyette char *name = NULL; 2211 1.210 pgoyette size_t namelen = 0; 2212 1.210 pgoyette 2213 1.210 pgoyette if (histnl[0].n_value == 0) { 2214 1.210 pgoyette warnx("kernel history is not compiled into the kernel."); 2215 1.210 pgoyette return; 2216 1.210 pgoyette } 2217 1.210 pgoyette 2218 1.210 pgoyette deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead, 2219 1.210 pgoyette sizeof(histhead), histnl[X_KERN_HISTORIES].n_name); 2220 1.210 pgoyette 2221 1.210 pgoyette if (histhead.lh_first == NULL) { 2222 1.210 pgoyette warnx("No active kernel history logs."); 2223 1.210 pgoyette return; 2224 1.210 pgoyette } 2225 1.210 pgoyette 2226 1.210 pgoyette if (todo & HISTLIST) 2227 1.210 pgoyette (void)printf("Active kernel histories:"); 2228 1.210 pgoyette 2229 1.210 pgoyette for (histkva = LIST_FIRST(&histhead); histkva != NULL; 2230 1.210 pgoyette histkva = LIST_NEXT(&hist, list)) { 2231 1.210 pgoyette deref_kptr(histkva, &hist, sizeof(hist), "histkva"); 2232 1.210 pgoyette if (name == NULL || hist.namelen > namelen) { 2233 1.210 pgoyette if (name != NULL) 2234 1.210 pgoyette free(name); 2235 1.210 pgoyette namelen = hist.namelen; 2236 1.210 pgoyette if ((name = malloc(namelen + 1)) == NULL) 2237 1.210 pgoyette err(1, "malloc history name"); 2238 1.210 pgoyette } 2239 1.210 pgoyette 2240 1.210 pgoyette deref_kptr(hist.name, name, namelen, "history name"); 2241 1.210 pgoyette name[namelen] = '\0'; 2242 1.210 pgoyette if (todo & HISTLIST) 2243 1.210 pgoyette (void)printf(" %s", name); 2244 1.210 pgoyette else { 2245 1.210 pgoyette /* 2246 1.210 pgoyette * If we're dumping all histories, do it, else 2247 1.210 pgoyette * check to see if this is the one we want. 2248 1.210 pgoyette */ 2249 1.210 pgoyette if (histname == NULL || strcmp(histname, name) == 0) { 2250 1.210 pgoyette if (histname == NULL) 2251 1.210 pgoyette (void)printf( 2252 1.210 pgoyette "\nkernel history `%s':\n", name); 2253 1.210 pgoyette hist_dodump(&hist); 2254 1.210 pgoyette } 2255 1.210 pgoyette } 2256 1.210 pgoyette } 2257 1.210 pgoyette 2258 1.210 pgoyette if (todo & HISTLIST) 2259 1.210 pgoyette (void)putchar('\n'); 2260 1.210 pgoyette 2261 1.210 pgoyette if (name != NULL) 2262 1.210 pgoyette free(name); 2263 1.210 pgoyette } 2264 1.210 pgoyette 2265 1.210 pgoyette /* 2266 1.210 pgoyette * Actually dump the history buffer at the specified KVA. 2267 1.210 pgoyette */ 2268 1.210 pgoyette void 2269 1.210 pgoyette hist_dodump(struct kern_history *histp) 2270 1.210 pgoyette { 2271 1.210 pgoyette struct kern_history_ent *histents, *e; 2272 1.215 pgoyette struct timeval tv; 2273 1.210 pgoyette size_t histsize; 2274 1.210 pgoyette char *fmt = NULL, *fn = NULL; 2275 1.210 pgoyette size_t fmtlen = 0, fnlen = 0; 2276 1.210 pgoyette unsigned i; 2277 1.210 pgoyette 2278 1.210 pgoyette histsize = sizeof(struct kern_history_ent) * histp->n; 2279 1.210 pgoyette 2280 1.210 pgoyette if ((histents = malloc(histsize)) == NULL) 2281 1.210 pgoyette err(1, "malloc history entries"); 2282 1.210 pgoyette 2283 1.210 pgoyette (void)memset(histents, 0, histsize); 2284 1.210 pgoyette 2285 1.211 pgoyette (void)printf("%"PRIu32" entries, next is %"PRIu32"\n", 2286 1.211 pgoyette histp->n, histp->f); 2287 1.211 pgoyette 2288 1.210 pgoyette deref_kptr(histp->e, histents, histsize, "history entries"); 2289 1.210 pgoyette i = histp->f; 2290 1.210 pgoyette do { 2291 1.210 pgoyette e = &histents[i]; 2292 1.210 pgoyette if (e->fmt != NULL) { 2293 1.210 pgoyette if (fmt == NULL || e->fmtlen > fmtlen) { 2294 1.227 mrg free(fmt); 2295 1.210 pgoyette fmtlen = e->fmtlen; 2296 1.210 pgoyette if ((fmt = malloc(fmtlen + 1)) == NULL) 2297 1.210 pgoyette err(1, "malloc printf format"); 2298 1.210 pgoyette } 2299 1.210 pgoyette if (fn == NULL || e->fnlen > fnlen) { 2300 1.227 mrg free(fn); 2301 1.210 pgoyette fnlen = e->fnlen; 2302 1.210 pgoyette if ((fn = malloc(fnlen + 1)) == NULL) 2303 1.210 pgoyette err(1, "malloc function name"); 2304 1.210 pgoyette } 2305 1.210 pgoyette 2306 1.210 pgoyette deref_kptr(e->fmt, fmt, fmtlen, "printf format"); 2307 1.210 pgoyette fmt[fmtlen] = '\0'; 2308 1.227 mrg for (unsigned z = 0; z < fmtlen - 1; z++) { 2309 1.227 mrg if (fmt[z] == '%' && fmt[z+1] == 's') 2310 1.227 mrg fmt[z+1] = 'p'; 2311 1.227 mrg } 2312 1.210 pgoyette 2313 1.210 pgoyette deref_kptr(e->fn, fn, fnlen, "function name"); 2314 1.210 pgoyette fn[fnlen] = '\0'; 2315 1.210 pgoyette 2316 1.215 pgoyette bintime2timeval(&e->bt, &tv); 2317 1.215 pgoyette (void)printf("%06ld.%06ld ", (long int)tv.tv_sec, 2318 1.215 pgoyette (long int)tv.tv_usec); 2319 1.256 simonb (void)printf("%s#%" PRId32 "@%" PRId32 ": ", 2320 1.219 pgoyette fn, e->call, e->cpunum); 2321 1.210 pgoyette (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]); 2322 1.210 pgoyette (void)putchar('\n'); 2323 1.210 pgoyette } 2324 1.210 pgoyette i = (i + 1) % histp->n; 2325 1.210 pgoyette } while (i != histp->f); 2326 1.210 pgoyette 2327 1.210 pgoyette free(histents); 2328 1.227 mrg free(fmt); 2329 1.227 mrg free(fn); 2330 1.210 pgoyette } 2331 1.210 pgoyette 2332 1.210 pgoyette void 2333 1.210 pgoyette hist_traverse_sysctl(int todo, const char *histname) 2334 1.210 pgoyette { 2335 1.209 pgoyette int error; 2336 1.209 pgoyette int mib[4]; 2337 1.209 pgoyette unsigned int i; 2338 1.209 pgoyette size_t len, miblen; 2339 1.209 pgoyette struct sysctlnode query, histnode[32]; 2340 1.209 pgoyette 2341 1.209 pgoyette /* retrieve names of available histories */ 2342 1.209 pgoyette miblen = __arraycount(mib); 2343 1.209 pgoyette error = sysctlnametomib("kern.hist", mib, &miblen); 2344 1.209 pgoyette if (error != 0) { 2345 1.214 pgoyette if (errno == ENOENT) { 2346 1.214 pgoyette warnx("kernel history is not compiled into the kernel."); 2347 1.214 pgoyette return; 2348 1.214 pgoyette } else 2349 1.245 simonb err(EXIT_FAILURE, "nametomib kern.hist failed"); 2350 1.209 pgoyette } 2351 1.260 skrll 2352 1.209 pgoyette /* get the list of nodenames below kern.hist */ 2353 1.209 pgoyette mib[2] = CTL_QUERY; 2354 1.209 pgoyette memset(&query, 0, sizeof(query)); 2355 1.209 pgoyette query.sysctl_flags = SYSCTL_VERSION; 2356 1.209 pgoyette len = sizeof(histnode); 2357 1.209 pgoyette error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query)); 2358 1.209 pgoyette if (error != 0) { 2359 1.209 pgoyette err(1, "query failed"); 2360 1.209 pgoyette return; 2361 1.209 pgoyette } 2362 1.209 pgoyette if (len == 0) { 2363 1.210 pgoyette warnx("No active kernel history logs."); 2364 1.210 pgoyette return; 2365 1.210 pgoyette } 2366 1.260 skrll 2367 1.209 pgoyette len = len / sizeof(histnode[0]); /* get # of entries returned */ 2368 1.209 pgoyette 2369 1.210 pgoyette if (todo & HISTLIST) 2370 1.210 pgoyette (void)printf("Active kernel histories:"); 2371 1.260 skrll 2372 1.209 pgoyette for (i = 0; i < len; i++) { 2373 1.210 pgoyette if (todo & HISTLIST) 2374 1.209 pgoyette (void)printf(" %s", histnode[i].sysctl_name); 2375 1.210 pgoyette else { 2376 1.210 pgoyette /* 2377 1.210 pgoyette * If we're dumping all histories, do it, else 2378 1.210 pgoyette * check to see if this is the one we want. 2379 1.210 pgoyette */ 2380 1.209 pgoyette if (histname == NULL || 2381 1.209 pgoyette strcmp(histname, histnode[i].sysctl_name) == 0) { 2382 1.210 pgoyette if (histname == NULL) 2383 1.210 pgoyette (void)printf( 2384 1.209 pgoyette "\nkernel history `%s':\n", 2385 1.209 pgoyette histnode[i].sysctl_name); 2386 1.209 pgoyette mib[2] = histnode[i].sysctl_num; 2387 1.209 pgoyette mib[3] = CTL_EOL; 2388 1.210 pgoyette hist_dodump_sysctl(mib, 4); 2389 1.210 pgoyette } 2390 1.210 pgoyette } 2391 1.210 pgoyette } 2392 1.260 skrll 2393 1.210 pgoyette if (todo & HISTLIST) 2394 1.210 pgoyette (void)putchar('\n'); 2395 1.219 pgoyette else if (mib[2] == CTL_QUERY) 2396 1.219 pgoyette warnx("history %s not found", histname); 2397 1.210 pgoyette } 2398 1.260 skrll 2399 1.210 pgoyette /* 2400 1.210 pgoyette * Actually dump the history buffer at the specified KVA. 2401 1.210 pgoyette */ 2402 1.221 mrg void 2403 1.210 pgoyette hist_dodump_sysctl(int mib[], unsigned int miblen) 2404 1.221 mrg { 2405 1.209 pgoyette struct sysctl_history *hist; 2406 1.215 pgoyette struct timeval tv; 2407 1.209 pgoyette struct sysctl_history_event *e; 2408 1.210 pgoyette size_t histsize; 2409 1.209 pgoyette char *strp; 2410 1.210 pgoyette unsigned i; 2411 1.45 thorpej char *fmt = NULL, *fn = NULL; 2412 1.260 skrll 2413 1.209 pgoyette hist = NULL; 2414 1.209 pgoyette histsize = 0; 2415 1.210 pgoyette do { 2416 1.209 pgoyette errno = 0; 2417 1.209 pgoyette if (sysctl(mib, miblen, hist, &histsize, NULL, 0) == 0) 2418 1.209 pgoyette break; 2419 1.209 pgoyette if (errno != ENOMEM) 2420 1.209 pgoyette break; 2421 1.209 pgoyette if ((hist = realloc(hist, histsize)) == NULL) 2422 1.209 pgoyette errx(1, "realloc history buffer"); 2423 1.209 pgoyette } while (errno == ENOMEM); 2424 1.209 pgoyette if (errno != 0) 2425 1.209 pgoyette err(1, "sysctl failed"); 2426 1.260 skrll 2427 1.219 pgoyette strp = (char *)(&hist->sh_events[hist->sh_numentries]); 2428 1.260 skrll 2429 1.209 pgoyette (void)printf("%"PRIu32" entries, next is %"PRIu32"\n", 2430 1.219 pgoyette hist->sh_numentries, 2431 1.219 pgoyette hist->sh_nextfree); 2432 1.260 skrll 2433 1.219 pgoyette i = hist->sh_nextfree; 2434 1.45 thorpej 2435 1.45 thorpej do { 2436 1.209 pgoyette e = &hist->sh_events[i]; 2437 1.209 pgoyette if (e->she_fmtoffset != 0) { 2438 1.209 pgoyette fmt = &strp[e->she_fmtoffset]; 2439 1.227 mrg size_t fmtlen = strlen(fmt); 2440 1.227 mrg for (unsigned z = 0; z < fmtlen - 1; z++) { 2441 1.227 mrg if (fmt[z] == '%' && fmt[z+1] == 's') 2442 1.227 mrg fmt[z+1] = 'p'; 2443 1.227 mrg } 2444 1.209 pgoyette fn = &strp[e->she_funcoffset]; 2445 1.215 pgoyette bintime2timeval(&e->she_bintime, &tv); 2446 1.219 pgoyette (void)printf("%06ld.%06ld %s#%"PRIu32"@%"PRIu32": ", 2447 1.215 pgoyette (long int)tv.tv_sec, (long int)tv.tv_usec, 2448 1.213 pgoyette fn, e->she_callnumber, e->she_cpunum); 2449 1.209 pgoyette (void)printf(fmt, e->she_values[0], e->she_values[1], 2450 1.209 pgoyette e->she_values[2], e->she_values[3]); 2451 1.210 pgoyette (void)putchar('\n'); 2452 1.210 pgoyette } 2453 1.219 pgoyette i = (i + 1) % hist->sh_numentries; 2454 1.219 pgoyette } while (i != hist->sh_nextfree); 2455 1.260 skrll 2456 1.209 pgoyette free(hist); 2457 1.210 pgoyette } 2458 1.45 thorpej 2459 1.183 joerg static void 2460 1.73 simonb usage(void) 2461 1.1 cgd { 2462 1.47 mrg 2463 1.1 cgd (void)fprintf(stderr, 2464 1.250 mrg "usage: %s [-CefHiLlmstUvW] [-c count] [-h hashname]\n" 2465 1.251 wiz "\t\t[-M core] [-N system] [-n diskcount] [-u histname]\n" 2466 1.250 mrg "[-w wait] [disks]\n", 2467 1.250 mrg getprogname()); 2468 1.1 cgd exit(1); 2469 1.1 cgd } 2470