1 1.25 christos /* $NetBSD: nfsstat.c,v 1.25 2014/04/24 18:40:35 christos Exp $ */ 2 1.7 thorpej 3 1.1 cgd /* 4 1.5 mycroft * Copyright (c) 1983, 1989, 1993 5 1.5 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.18 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.9 lukem #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.22 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\ 38 1.22 lukem The Regents of the University of California. All rights reserved."); 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.7 thorpej #if 0 43 1.7 thorpej static char sccsid[] = "from: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93"; 44 1.7 thorpej #else 45 1.25 christos __RCSID("$NetBSD: nfsstat.c,v 1.25 2014/04/24 18:40:35 christos Exp $"); 46 1.7 thorpej #endif 47 1.1 cgd #endif /* not lint */ 48 1.1 cgd 49 1.1 cgd #include <sys/param.h> 50 1.1 cgd #include <sys/mount.h> 51 1.6 fvdl #include <sys/sysctl.h> 52 1.8 explorer 53 1.6 fvdl #include <nfs/rpcv2.h> 54 1.6 fvdl #include <nfs/nfsproto.h> 55 1.1 cgd #include <nfs/nfs.h> 56 1.8 explorer 57 1.1 cgd #include <ctype.h> 58 1.8 explorer #include <err.h> 59 1.1 cgd #include <errno.h> 60 1.8 explorer #include <fcntl.h> 61 1.5 mycroft #include <kvm.h> 62 1.8 explorer #include <limits.h> 63 1.1 cgd #include <nlist.h> 64 1.8 explorer #include <paths.h> 65 1.8 explorer #include <signal.h> 66 1.8 explorer #include <stdlib.h> 67 1.1 cgd #include <stdio.h> 68 1.1 cgd #include <string.h> 69 1.8 explorer #include <unistd.h> 70 1.1 cgd 71 1.24 joerg static struct nlist nl[] = { 72 1.1 cgd #define N_NFSSTAT 0 73 1.23 lukem { "_nfsstats", 0, 0, 0, 0 }, 74 1.23 lukem { "", 0, 0, 0, 0 }, 75 1.1 cgd }; 76 1.16 simonb 77 1.19 yamt #define MASK(a) (1 << NFSPROC_##a) 78 1.19 yamt #define ALLMASK \ 79 1.19 yamt (MASK(GETATTR) | MASK(SETATTR) | MASK(LOOKUP) | MASK(READ) | \ 80 1.19 yamt MASK(WRITE) | MASK(RENAME)| MASK(ACCESS) | MASK(READDIR) | \ 81 1.19 yamt MASK(READDIRPLUS)) 82 1.19 yamt #define OTHERMASK (((1 << NFS_NPROCS) - 1) & ~ALLMASK) 83 1.24 joerg static const struct shortprocs { 84 1.19 yamt int mask; 85 1.19 yamt const char *name; 86 1.19 yamt } shortprocs[] = { 87 1.19 yamt {MASK(GETATTR), "Getattr"}, 88 1.19 yamt {MASK(SETATTR), "Setattr"}, 89 1.19 yamt {MASK(LOOKUP), "Lookup"}, 90 1.19 yamt {MASK(READ), "Read"}, 91 1.19 yamt {MASK(WRITE), "Write"}, 92 1.19 yamt {MASK(RENAME), "Rename"}, 93 1.19 yamt {MASK(ACCESS), "Access"}, 94 1.19 yamt {MASK(READDIR) | MASK(READDIRPLUS), "Readdir"}, 95 1.19 yamt {OTHERMASK, "Others"}, 96 1.19 yamt }; 97 1.19 yamt 98 1.19 yamt #define NSHORTPROC (sizeof(shortprocs)/sizeof(shortprocs[0])) 99 1.1 cgd 100 1.24 joerg static void catchalarm(int); 101 1.24 joerg static void getstats(struct nfsstats *); 102 1.24 joerg static void intpr(void); 103 1.24 joerg static void printhdr(void); 104 1.24 joerg __dead static void sidewaysintpr(u_int); 105 1.24 joerg __dead static void usage(void); 106 1.24 joerg 107 1.24 joerg static kvm_t *kd; 108 1.24 joerg static int printall, clientinfo, serverinfo; 109 1.24 joerg static u_long nfsstataddr; 110 1.10 hubertf 111 1.9 lukem int 112 1.24 joerg main(int argc, char **argv) 113 1.1 cgd { 114 1.1 cgd u_int interval; 115 1.1 cgd int ch; 116 1.5 mycroft char *memf, *nlistf; 117 1.8 explorer char errbuf[_POSIX2_LINE_MAX]; 118 1.1 cgd 119 1.1 cgd interval = 0; 120 1.5 mycroft memf = nlistf = NULL; 121 1.10 hubertf printall = 1; 122 1.10 hubertf while ((ch = getopt(argc, argv, "M:N:w:cs")) != -1) 123 1.1 cgd switch(ch) { 124 1.1 cgd case 'M': 125 1.5 mycroft memf = optarg; 126 1.1 cgd break; 127 1.1 cgd case 'N': 128 1.5 mycroft nlistf = optarg; 129 1.1 cgd break; 130 1.1 cgd case 'w': 131 1.1 cgd interval = atoi(optarg); 132 1.1 cgd break; 133 1.10 hubertf case 's': 134 1.10 hubertf serverinfo = 1; 135 1.10 hubertf printall = 0; 136 1.10 hubertf break; 137 1.10 hubertf case 'c': 138 1.10 hubertf clientinfo = 1; 139 1.10 hubertf printall = 0; 140 1.10 hubertf break; 141 1.1 cgd case '?': 142 1.1 cgd default: 143 1.1 cgd usage(); 144 1.1 cgd } 145 1.1 cgd argc -= optind; 146 1.1 cgd argv += optind; 147 1.1 cgd 148 1.1 cgd #define BACKWARD_COMPATIBILITY 149 1.1 cgd #ifdef BACKWARD_COMPATIBILITY 150 1.1 cgd if (*argv) { 151 1.5 mycroft interval = atoi(*argv); 152 1.1 cgd if (*++argv) { 153 1.5 mycroft nlistf = *argv; 154 1.5 mycroft if (*++argv) 155 1.5 mycroft memf = *argv; 156 1.1 cgd } 157 1.1 cgd } 158 1.1 cgd #endif 159 1.16 simonb if (nlistf || memf) { 160 1.16 simonb if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) 161 1.16 simonb == 0) 162 1.16 simonb errx(1, "kvm_openfiles: %s", errbuf); 163 1.16 simonb 164 1.16 simonb if (kvm_nlist(kd, nl) != 0) 165 1.16 simonb errx(1, "kvm_nlist: can't get names"); 166 1.16 simonb nfsstataddr = nl[N_NFSSTAT].n_value; 167 1.16 simonb } else { 168 1.16 simonb kd = NULL; 169 1.16 simonb } 170 1.1 cgd 171 1.1 cgd if (interval) 172 1.16 simonb sidewaysintpr(interval); 173 1.1 cgd else 174 1.16 simonb intpr(); 175 1.1 cgd exit(0); 176 1.1 cgd } 177 1.1 cgd 178 1.24 joerg static void 179 1.24 joerg getstats(struct nfsstats *ns) 180 1.16 simonb { 181 1.16 simonb size_t size; 182 1.16 simonb int mib[3]; 183 1.16 simonb 184 1.16 simonb if (kd) { 185 1.16 simonb if (kvm_read(kd, (u_long)nfsstataddr, ns, sizeof(*ns)) 186 1.16 simonb != sizeof(*ns)) 187 1.16 simonb errx(1, "kvm_read failed"); 188 1.16 simonb } else { 189 1.16 simonb mib[0] = CTL_VFS; 190 1.16 simonb mib[1] = 2; /* XXX from CTL_VFS_NAMES in <sys/mount.h> */ 191 1.16 simonb mib[2] = NFS_NFSSTATS; 192 1.16 simonb 193 1.16 simonb size = sizeof(*ns); 194 1.16 simonb if (sysctl(mib, 3, ns, &size, NULL, 0) == -1) 195 1.16 simonb err(1, "sysctl(NFS_NFSSTATS) failed"); 196 1.16 simonb } 197 1.16 simonb } 198 1.16 simonb 199 1.1 cgd /* 200 1.5 mycroft * Print a description of the nfs stats. 201 1.1 cgd */ 202 1.24 joerg static void 203 1.24 joerg intpr(void) 204 1.1 cgd { 205 1.1 cgd struct nfsstats nfsstats; 206 1.25 christos uint64_t total; 207 1.17 lukem int i; 208 1.17 lukem 209 1.17 lukem #define PCT(x,y) ((y) == 0 ? 0 : (int)((int64_t)(x) * 100 / (y))) 210 1.17 lukem #define NUMPCT(x,y) (x), PCT(x, (x)+(y)) 211 1.17 lukem #define RPCSTAT(x) (x), PCT(x, total) 212 1.1 cgd 213 1.16 simonb getstats(&nfsstats); 214 1.17 lukem 215 1.13 mrg if (printall || clientinfo) { 216 1.17 lukem total = 0; 217 1.17 lukem for (i = 0; i < NFS_NPROCS; i++) 218 1.17 lukem total += nfsstats.rpccnt[i]; 219 1.13 mrg printf("Client Info:\n"); 220 1.25 christos printf("RPC Counts: (%" PRIu64 " call%s)\n", total, 221 1.17 lukem total == 1 ? "" : "s"); 222 1.17 lukem 223 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 224 1.17 lukem "null", "getattr", "setattr", "lookup", "access"); 225 1.17 lukem printf( 226 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 227 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_NULL]), 228 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_GETATTR]), 229 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_SETATTR]), 230 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_LOOKUP]), 231 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_ACCESS])); 232 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 233 1.17 lukem "readlink", "read", "write", "create", "mkdir"); 234 1.17 lukem printf( 235 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 236 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_READLINK]), 237 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_READ]), 238 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_WRITE]), 239 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_CREATE]), 240 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_MKDIR])); 241 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 242 1.17 lukem "symlink", "mknod", "remove", "rmdir", "rename"); 243 1.17 lukem printf( 244 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 245 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_SYMLINK]), 246 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_MKNOD]), 247 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_REMOVE]), 248 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_RMDIR]), 249 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_RENAME])); 250 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 251 1.17 lukem "link", "readdir", "readdirplus", "fsstat", "fsinfo"); 252 1.17 lukem printf( 253 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 254 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_LINK]), 255 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIR]), 256 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIRPLUS]), 257 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_FSSTAT]), 258 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_FSINFO])); 259 1.21 yamt printf("%10s %14s\n", 260 1.21 yamt "pathconf", "commit"); 261 1.25 christos printf("%10u %2u%% %10u %2u%%\n", 262 1.17 lukem RPCSTAT(nfsstats.rpccnt[NFSPROC_PATHCONF]), 263 1.20 dogcow RPCSTAT(nfsstats.rpccnt[NFSPROC_COMMIT])); 264 1.17 lukem 265 1.17 lukem printf("RPC Info:\n"); 266 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 267 1.17 lukem "timeout", "invalid", "unexpected", "retries", "requests"); 268 1.25 christos printf("%10u %14u %14u %14u %14u\n", 269 1.13 mrg nfsstats.rpctimeouts, 270 1.13 mrg nfsstats.rpcinvalid, 271 1.13 mrg nfsstats.rpcunexpected, 272 1.13 mrg nfsstats.rpcretries, 273 1.13 mrg nfsstats.rpcrequests); 274 1.17 lukem 275 1.13 mrg printf("Cache Info:\n"); 276 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 277 1.17 lukem "attrcache", "lookupcache", "read", "write", "readlink"); 278 1.17 lukem printf( 279 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 280 1.17 lukem NUMPCT(nfsstats.attrcache_hits, 281 1.17 lukem nfsstats.attrcache_misses), 282 1.17 lukem NUMPCT(nfsstats.lookupcache_hits, 283 1.17 lukem nfsstats.lookupcache_misses), 284 1.17 lukem NUMPCT(nfsstats.biocache_reads - nfsstats.read_bios, 285 1.17 lukem nfsstats.read_bios), 286 1.17 lukem NUMPCT(nfsstats.biocache_writes - nfsstats.write_bios, 287 1.17 lukem nfsstats.write_bios), 288 1.17 lukem NUMPCT(nfsstats.biocache_readlinks - nfsstats.readlink_bios, 289 1.17 lukem nfsstats.readlink_bios)); 290 1.17 lukem printf("%10s %14s\n", 291 1.17 lukem "readdir", "direofcache"); 292 1.25 christos printf("%10u %2u%% %10u %2u%%\n", 293 1.17 lukem NUMPCT(nfsstats.biocache_readdirs - nfsstats.readdir_bios, 294 1.17 lukem nfsstats.readdir_bios), 295 1.17 lukem NUMPCT(nfsstats.direofcache_hits, 296 1.17 lukem nfsstats.direofcache_misses)); 297 1.10 hubertf } 298 1.17 lukem 299 1.17 lukem if (printall || (clientinfo && serverinfo)) 300 1.13 mrg printf("\n"); 301 1.17 lukem 302 1.17 lukem if (printall || serverinfo) { 303 1.17 lukem total = 0; 304 1.17 lukem for (i = 0; i < NFS_NPROCS; i++) 305 1.17 lukem total += nfsstats.srvrpccnt[i]; 306 1.13 mrg printf("Server Info:\n"); 307 1.25 christos printf("RPC Counts: (%" PRIu64 " call%s)\n", total, 308 1.17 lukem total == 1 ? "" : "s"); 309 1.17 lukem 310 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 311 1.17 lukem "null", "getattr", "setattr", "lookup", "access"); 312 1.17 lukem printf( 313 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 314 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NULL]), 315 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_GETATTR]), 316 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SETATTR]), 317 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LOOKUP]), 318 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_ACCESS])); 319 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 320 1.17 lukem "readlink", "read", "write", "create", "mkdir"); 321 1.17 lukem printf( 322 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 323 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READLINK]), 324 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READ]), 325 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_WRITE]), 326 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_CREATE]), 327 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKDIR])); 328 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 329 1.17 lukem "symlink", "mknod", "remove", "rmdir", "rename"); 330 1.17 lukem printf( 331 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 332 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SYMLINK]), 333 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKNOD]), 334 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_REMOVE]), 335 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RMDIR]), 336 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RENAME])); 337 1.17 lukem printf("%10s %14s %14s %14s %14s\n", 338 1.17 lukem "link", "readdir", "readdirplus", "fsstat", "fsinfo"); 339 1.17 lukem printf( 340 1.25 christos "%10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%% %10u %2u%%\n", 341 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LINK]), 342 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIR]), 343 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]), 344 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSSTAT]), 345 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSINFO])); 346 1.21 yamt printf("%10s %14s\n", 347 1.21 yamt "pathconf", "commit"); 348 1.25 christos printf("%10u %2u%% %10u %2u%%\n", 349 1.17 lukem RPCSTAT(nfsstats.srvrpccnt[NFSPROC_PATHCONF]), 350 1.20 dogcow RPCSTAT(nfsstats.srvrpccnt[NFSPROC_COMMIT])); 351 1.17 lukem 352 1.17 lukem printf("Server Errors:\n"); 353 1.17 lukem printf("%10s %14s\n", 354 1.17 lukem "RPC errors", "faults"); 355 1.25 christos printf("%10u %14u\n", 356 1.17 lukem nfsstats.srvrpc_errs, 357 1.17 lukem nfsstats.srv_errs); 358 1.13 mrg printf("Server Cache Stats:\n"); 359 1.17 lukem printf("%10s %14s %14s %14s\n", 360 1.17 lukem "inprogress", "idem", "non-idem", "misses"); 361 1.25 christos printf("%10u %14u %14u %14u\n", 362 1.13 mrg nfsstats.srvcache_inproghits, 363 1.13 mrg nfsstats.srvcache_idemdonehits, 364 1.13 mrg nfsstats.srvcache_nonidemdonehits, 365 1.13 mrg nfsstats.srvcache_misses); 366 1.13 mrg printf("Server Write Gathering:\n"); 367 1.17 lukem printf("%10s %14s %14s\n", 368 1.17 lukem "writes", "write RPC", "OPs saved"); 369 1.25 christos printf("%10u %14u %14u %2u%%\n", 370 1.13 mrg nfsstats.srvvop_writes, 371 1.13 mrg nfsstats.srvrpccnt[NFSPROC_WRITE], 372 1.17 lukem NUMPCT( 373 1.17 lukem nfsstats.srvrpccnt[NFSPROC_WRITE]-nfsstats.srvvop_writes, 374 1.17 lukem nfsstats.srvrpccnt[NFSPROC_WRITE])); 375 1.10 hubertf } 376 1.1 cgd } 377 1.1 cgd 378 1.24 joerg static u_char signalled; /* set if alarm goes off "early" */ 379 1.1 cgd 380 1.1 cgd /* 381 1.1 cgd * Print a running summary of nfs statistics. 382 1.1 cgd * Repeat display every interval seconds, showing statistics 383 1.1 cgd * collected over that interval. Assumes that interval is non-zero. 384 1.1 cgd * First line printed at top of screen is always cumulative. 385 1.1 cgd */ 386 1.24 joerg static void 387 1.24 joerg sidewaysintpr(u_int interval) 388 1.1 cgd { 389 1.19 yamt struct nfsstats nfsstats; 390 1.1 cgd int hdrcnt, oldmask; 391 1.19 yamt struct stats { 392 1.19 yamt int client[NSHORTPROC]; 393 1.19 yamt int server[NSHORTPROC]; 394 1.19 yamt } current, last; 395 1.1 cgd 396 1.1 cgd (void)signal(SIGALRM, catchalarm); 397 1.1 cgd signalled = 0; 398 1.1 cgd (void)alarm(interval); 399 1.19 yamt memset(&last, 0, sizeof(last)); 400 1.1 cgd 401 1.1 cgd for (hdrcnt = 1;;) { 402 1.23 lukem size_t i; 403 1.19 yamt 404 1.1 cgd if (!--hdrcnt) { 405 1.1 cgd printhdr(); 406 1.1 cgd hdrcnt = 20; 407 1.1 cgd } 408 1.16 simonb getstats(&nfsstats); 409 1.19 yamt memset(¤t, 0, sizeof(current)); 410 1.19 yamt for (i = 0; i < NSHORTPROC; i++) { 411 1.19 yamt int mask = shortprocs[i].mask; 412 1.19 yamt int idx; 413 1.19 yamt 414 1.19 yamt while ((idx = ffs(mask)) != 0) { 415 1.19 yamt idx--; 416 1.19 yamt mask &= ~(1 << idx); 417 1.19 yamt current.client[i] += nfsstats.rpccnt[idx]; 418 1.19 yamt current.server[i] += nfsstats.srvrpccnt[idx]; 419 1.19 yamt } 420 1.19 yamt } 421 1.19 yamt 422 1.19 yamt if (printall || clientinfo) { 423 1.19 yamt printf("Client:"); 424 1.19 yamt for (i = 0; i < NSHORTPROC; i++) 425 1.25 christos printf(" %7u", 426 1.19 yamt current.client[i] - last.client[i]); 427 1.19 yamt printf("\n"); 428 1.19 yamt } 429 1.19 yamt if (printall || serverinfo) { 430 1.19 yamt printf("Server:"); 431 1.19 yamt for (i = 0; i < NSHORTPROC; i++) 432 1.25 christos printf(" %7u", 433 1.19 yamt current.server[i] - last.server[i]); 434 1.19 yamt printf("\n"); 435 1.19 yamt } 436 1.19 yamt memcpy(&last, ¤t, sizeof(last)); 437 1.1 cgd fflush(stdout); 438 1.1 cgd oldmask = sigblock(sigmask(SIGALRM)); 439 1.1 cgd if (!signalled) 440 1.1 cgd sigpause(0); 441 1.1 cgd sigsetmask(oldmask); 442 1.1 cgd signalled = 0; 443 1.1 cgd (void)alarm(interval); 444 1.1 cgd } 445 1.1 cgd /*NOTREACHED*/ 446 1.1 cgd } 447 1.1 cgd 448 1.24 joerg static void 449 1.24 joerg printhdr(void) 450 1.1 cgd { 451 1.23 lukem size_t i; 452 1.13 mrg 453 1.19 yamt printf(" "); 454 1.19 yamt for (i = 0; i < NSHORTPROC; i++) 455 1.19 yamt printf("%7.7s ", shortprocs[i].name); 456 1.19 yamt printf("\n"); 457 1.1 cgd fflush(stdout); 458 1.1 cgd } 459 1.1 cgd 460 1.1 cgd /* 461 1.1 cgd * Called if an interval expires before sidewaysintpr has completed a loop. 462 1.1 cgd * Sets a flag to not wait for the alarm. 463 1.1 cgd */ 464 1.24 joerg static void 465 1.24 joerg catchalarm(int dummy) 466 1.1 cgd { 467 1.13 mrg 468 1.1 cgd signalled = 1; 469 1.1 cgd } 470 1.1 cgd 471 1.24 joerg static void 472 1.24 joerg usage(void) 473 1.1 cgd { 474 1.13 mrg 475 1.1 cgd (void)fprintf(stderr, 476 1.25 christos "Usage: %s [-cs] [-M core] [-N system] [-w interval]\n", 477 1.25 christos getprogname()); 478 1.1 cgd exit(1); 479 1.1 cgd } 480