nfsstat.c revision 74655
1/* 2 * Copyright (c) 1983, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright (c) 1983, 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)nfsstat.c 8.2 (Berkeley) 3/31/95"; 46#endif 47static const char rcsid[] = 48 "$FreeBSD: head/usr.bin/nfsstat/nfsstat.c 74655 2001-03-22 17:39:57Z tmm $"; 49#endif /* not lint */ 50 51#include <sys/param.h> 52#include <sys/mount.h> 53#include <sys/time.h> 54#include <sys/sysctl.h> 55#include <nfs/rpcv2.h> 56#include <nfs/nfsproto.h> 57#include <nfs/nfs.h> 58#include <signal.h> 59#include <fcntl.h> 60#include <ctype.h> 61#include <errno.h> 62#include <kvm.h> 63#include <nlist.h> 64#include <unistd.h> 65#include <stdio.h> 66#include <stdlib.h> 67#include <string.h> 68#include <paths.h> 69#include <err.h> 70 71struct nlist nl[] = { 72#define N_NFSSTAT 0 73 { "_nfsstats" }, 74 "", 75}; 76kvm_t *kd; 77 78static int deadkernel = 0; 79static int widemode = 0; 80 81void intpr __P((int, int)); 82void printhdr __P((int, int)); 83void sidewaysintpr __P((u_int, int, int)); 84void usage __P((void)); 85char *sperc1 __P((int, int)); 86char *sperc2 __P((int, int)); 87 88#define DELTA(field) (nfsstats.field - lastst.field) 89 90main(argc, argv) 91 int argc; 92 char **argv; 93{ 94 u_int interval; 95 int clientOnly = -1; 96 int serverOnly = -1; 97 int ch; 98 char *memf, *nlistf; 99 char errbuf[80]; 100 101 interval = 0; 102 memf = nlistf = NULL; 103 while ((ch = getopt(argc, argv, "csWM:N:w:")) != -1) 104 switch(ch) { 105 case 'M': 106 memf = optarg; 107 break; 108 case 'N': 109 nlistf = optarg; 110 break; 111 case 'W': 112 widemode = 1; 113 break; 114 case 'w': 115 interval = atoi(optarg); 116 break; 117 case 'c': 118 clientOnly = 1; 119 if (serverOnly < 0) 120 serverOnly = 0; 121 break; 122 case 's': 123 serverOnly = 1; 124 if (clientOnly < 0) 125 clientOnly = 0; 126 break; 127 case '?': 128 default: 129 usage(); 130 } 131 argc -= optind; 132 argv += optind; 133 134#define BACKWARD_COMPATIBILITY 135#ifdef BACKWARD_COMPATIBILITY 136 if (*argv) { 137 interval = atoi(*argv); 138 if (*++argv) { 139 nlistf = *argv; 140 if (*++argv) 141 memf = *argv; 142 } 143 } 144#endif 145 if (nlistf != NULL || memf != NULL) { 146 deadkernel = 1; 147 148 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 149 errbuf)) == 0) { 150 errx(1, "kvm_openfiles: %s", errbuf); 151 } 152 if (kvm_nlist(kd, nl) != 0) { 153 errx(1, "kvm_nlist: can't get names"); 154 } 155 } 156 157 if (interval) 158 sidewaysintpr(interval, clientOnly, serverOnly); 159 else 160 intpr(clientOnly, serverOnly); 161 exit(0); 162} 163 164/* 165 * Read the nfs stats using sysctl(3) for live kernels, or kvm_read 166 * for dead ones. 167 */ 168void 169readstats(stp) 170 struct nfsstats *stp; 171{ 172 if(deadkernel) { 173 if(kvm_read(kd, (u_long)nl[N_NFSSTAT].n_value, stp, 174 sizeof *stp) < 0) { 175 err(1, "kvm_read"); 176 } 177 } else { 178 int name[3]; 179 size_t buflen = sizeof *stp; 180 struct vfsconf vfc; 181 182 if (getvfsbyname("nfs", &vfc) < 0) 183 err(1, "getvfsbyname: NFS not compiled into kernel"); 184 name[0] = CTL_VFS; 185 name[1] = vfc.vfc_typenum; 186 name[2] = NFS_NFSSTATS; 187 if (sysctl(name, 3, stp, &buflen, (void *)0, (size_t)0) < 0) { 188 err(1, "sysctl"); 189 } 190 } 191} 192 193/* 194 * Print a description of the nfs stats. 195 */ 196void 197intpr(int clientOnly, int serverOnly) 198{ 199 struct nfsstats nfsstats; 200 201 readstats(&nfsstats); 202 203 if (clientOnly) { 204 printf("Client Info:\n"); 205 printf("Rpc Counts:\n"); 206 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 207 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 208 "Write", "Create", "Remove"); 209 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 210 nfsstats.rpccnt[NFSPROC_GETATTR], 211 nfsstats.rpccnt[NFSPROC_SETATTR], 212 nfsstats.rpccnt[NFSPROC_LOOKUP], 213 nfsstats.rpccnt[NFSPROC_READLINK], 214 nfsstats.rpccnt[NFSPROC_READ], 215 nfsstats.rpccnt[NFSPROC_WRITE], 216 nfsstats.rpccnt[NFSPROC_CREATE], 217 nfsstats.rpccnt[NFSPROC_REMOVE]); 218 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 219 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 220 "Readdir", "RdirPlus", "Access"); 221 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 222 nfsstats.rpccnt[NFSPROC_RENAME], 223 nfsstats.rpccnt[NFSPROC_LINK], 224 nfsstats.rpccnt[NFSPROC_SYMLINK], 225 nfsstats.rpccnt[NFSPROC_MKDIR], 226 nfsstats.rpccnt[NFSPROC_RMDIR], 227 nfsstats.rpccnt[NFSPROC_READDIR], 228 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 229 nfsstats.rpccnt[NFSPROC_ACCESS]); 230 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 231 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 232 "GLease", "Vacate", "Evict"); 233 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 234 nfsstats.rpccnt[NFSPROC_MKNOD], 235 nfsstats.rpccnt[NFSPROC_FSSTAT], 236 nfsstats.rpccnt[NFSPROC_FSINFO], 237 nfsstats.rpccnt[NFSPROC_PATHCONF], 238 nfsstats.rpccnt[NFSPROC_COMMIT], 239 nfsstats.rpccnt[NQNFSPROC_GETLEASE], 240 nfsstats.rpccnt[NQNFSPROC_VACATED], 241 nfsstats.rpccnt[NQNFSPROC_EVICTED]); 242 printf("Rpc Info:\n"); 243 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 244 "TimedOut", "Invalid", "X Replies", "Retries", 245 "Requests"); 246 printf("%9d %9d %9d %9d %9d\n", 247 nfsstats.rpctimeouts, 248 nfsstats.rpcinvalid, 249 nfsstats.rpcunexpected, 250 nfsstats.rpcretries, 251 nfsstats.rpcrequests); 252 printf("Cache Info:\n"); 253 printf("%9.9s %9.9s %9.9s %9.9s", 254 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 255 printf(" %9.9s %9.9s %9.9s %9.9s\n", 256 "BioR Hits", "Misses", "BioW Hits", "Misses"); 257 printf("%9d %9d %9d %9d", 258 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 259 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 260 printf(" %9d %9d %9d %9d\n", 261 nfsstats.biocache_reads-nfsstats.read_bios, 262 nfsstats.read_bios, 263 nfsstats.biocache_writes-nfsstats.write_bios, 264 nfsstats.write_bios); 265 printf("%9.9s %9.9s %9.9s %9.9s", 266 "BioRLHits", "Misses", "BioD Hits", "Misses"); 267 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 268 printf("%9d %9d %9d %9d", 269 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 270 nfsstats.readlink_bios, 271 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 272 nfsstats.readdir_bios); 273 printf(" %9d %9d\n", 274 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 275 } 276 if (serverOnly) { 277 printf("\nServer Info:\n"); 278 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 279 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 280 "Write", "Create", "Remove"); 281 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 282 nfsstats.srvrpccnt[NFSPROC_GETATTR], 283 nfsstats.srvrpccnt[NFSPROC_SETATTR], 284 nfsstats.srvrpccnt[NFSPROC_LOOKUP], 285 nfsstats.srvrpccnt[NFSPROC_READLINK], 286 nfsstats.srvrpccnt[NFSPROC_READ], 287 nfsstats.srvrpccnt[NFSPROC_WRITE], 288 nfsstats.srvrpccnt[NFSPROC_CREATE], 289 nfsstats.srvrpccnt[NFSPROC_REMOVE]); 290 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 291 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 292 "Readdir", "RdirPlus", "Access"); 293 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 294 nfsstats.srvrpccnt[NFSPROC_RENAME], 295 nfsstats.srvrpccnt[NFSPROC_LINK], 296 nfsstats.srvrpccnt[NFSPROC_SYMLINK], 297 nfsstats.srvrpccnt[NFSPROC_MKDIR], 298 nfsstats.srvrpccnt[NFSPROC_RMDIR], 299 nfsstats.srvrpccnt[NFSPROC_READDIR], 300 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS], 301 nfsstats.srvrpccnt[NFSPROC_ACCESS]); 302 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 303 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 304 "GLease", "Vacate", "Evict"); 305 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 306 nfsstats.srvrpccnt[NFSPROC_MKNOD], 307 nfsstats.srvrpccnt[NFSPROC_FSSTAT], 308 nfsstats.srvrpccnt[NFSPROC_FSINFO], 309 nfsstats.srvrpccnt[NFSPROC_PATHCONF], 310 nfsstats.srvrpccnt[NFSPROC_COMMIT], 311 nfsstats.srvrpccnt[NQNFSPROC_GETLEASE], 312 nfsstats.srvrpccnt[NQNFSPROC_VACATED], 313 nfsstats.srvrpccnt[NQNFSPROC_EVICTED]); 314 printf("Server Ret-Failed\n"); 315 printf("%17d\n", nfsstats.srvrpc_errs); 316 printf("Server Faults\n"); 317 printf("%13d\n", nfsstats.srv_errs); 318 printf("Server Cache Stats:\n"); 319 printf("%9.9s %9.9s %9.9s %9.9s\n", 320 "Inprog", "Idem", "Non-idem", "Misses"); 321 printf("%9d %9d %9d %9d\n", 322 nfsstats.srvcache_inproghits, 323 nfsstats.srvcache_idemdonehits, 324 nfsstats.srvcache_nonidemdonehits, 325 nfsstats.srvcache_misses); 326 printf("Server Lease Stats:\n"); 327 printf("%9.9s %9.9s %9.9s\n", 328 "Leases", "PeakL", "GLeases"); 329 printf("%9d %9d %9d\n", 330 nfsstats.srvnqnfs_leases, 331 nfsstats.srvnqnfs_maxleases, 332 nfsstats.srvnqnfs_getleases); 333 printf("Server Write Gathering:\n"); 334 printf("%9.9s %9.9s %9.9s\n", 335 "WriteOps", "WriteRPC", "Opsaved"); 336 printf("%9d %9d %9d\n", 337 nfsstats.srvvop_writes, 338 nfsstats.srvrpccnt[NFSPROC_WRITE], 339 nfsstats.srvrpccnt[NFSPROC_WRITE] - 340 nfsstats.srvvop_writes); 341 } 342} 343 344u_char signalled; /* set if alarm goes off "early" */ 345 346/* 347 * Print a running summary of nfs statistics. 348 * Repeat display every interval seconds, showing statistics 349 * collected over that interval. Assumes that interval is non-zero. 350 * First line printed at top of screen is always cumulative. 351 */ 352void 353sidewaysintpr(u_int interval, int clientOnly, int serverOnly) 354{ 355 struct nfsstats nfsstats, lastst; 356 int hdrcnt = 1; 357 358 readstats(&lastst); 359 sleep(interval); 360 361 for (;;) { 362 readstats(&nfsstats); 363 364 if (--hdrcnt == 0) { 365 printhdr(clientOnly, serverOnly); 366 if (clientOnly && serverOnly) 367 hdrcnt = 10; 368 else 369 hdrcnt = 20; 370 } 371 if (clientOnly) { 372 printf("%s %6d %6d %6d %6d %6d %6d %6d %6d", 373 ((clientOnly && serverOnly) ? "Client:" : ""), 374 DELTA(attrcache_hits) + DELTA(attrcache_misses), 375 DELTA(lookupcache_hits) + DELTA(lookupcache_misses), 376 DELTA(biocache_readlinks), 377 DELTA(biocache_reads), 378 DELTA(biocache_writes), 379 nfsstats.rpccnt[NFSPROC_RENAME]-lastst.rpccnt[NFSPROC_RENAME], 380 DELTA(accesscache_hits) + DELTA(accesscache_misses), 381 DELTA(biocache_readdirs) 382 ); 383 if (widemode) { 384 printf(" %s %s %s %s %s %s", 385 sperc1(DELTA(attrcache_hits), 386 DELTA(attrcache_misses)), 387 sperc1(DELTA(lookupcache_hits), 388 DELTA(lookupcache_misses)), 389 sperc2(DELTA(biocache_reads), 390 DELTA(read_bios)), 391 sperc2(DELTA(biocache_writes), 392 DELTA(write_bios)), 393 sperc1(DELTA(accesscache_hits), 394 DELTA(accesscache_misses)), 395 sperc2(DELTA(biocache_readdirs), 396 DELTA(readdir_bios)) 397 ); 398 } 399 printf("\n"); 400 } 401 if (serverOnly) { 402 printf("%s %6d %6d %6d %6d %6d %6d %6d %6d", 403 ((clientOnly && serverOnly) ? "Server:" : ""), 404 nfsstats.srvrpccnt[NFSPROC_GETATTR]-lastst.srvrpccnt[NFSPROC_GETATTR], 405 nfsstats.srvrpccnt[NFSPROC_LOOKUP]-lastst.srvrpccnt[NFSPROC_LOOKUP], 406 nfsstats.srvrpccnt[NFSPROC_READLINK]-lastst.srvrpccnt[NFSPROC_READLINK], 407 nfsstats.srvrpccnt[NFSPROC_READ]-lastst.srvrpccnt[NFSPROC_READ], 408 nfsstats.srvrpccnt[NFSPROC_WRITE]-lastst.srvrpccnt[NFSPROC_WRITE], 409 nfsstats.srvrpccnt[NFSPROC_RENAME]-lastst.srvrpccnt[NFSPROC_RENAME], 410 nfsstats.srvrpccnt[NFSPROC_ACCESS]-lastst.srvrpccnt[NFSPROC_ACCESS], 411 (nfsstats.srvrpccnt[NFSPROC_READDIR]-lastst.srvrpccnt[NFSPROC_READDIR]) 412 +(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 413 printf("\n"); 414 } 415 lastst = nfsstats; 416 fflush(stdout); 417 sleep(interval); 418 } 419 /*NOTREACHED*/ 420} 421 422void 423printhdr(int clientOnly, int serverOnly) 424{ 425 printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s", 426 ((serverOnly && clientOnly) ? " " : " "), 427 "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename", 428 "Access", "Rddir"); 429 if (widemode && clientOnly) { 430 printf(" Attr Lkup BioR BioW Accs BioD"); 431 } 432 printf("\n"); 433 fflush(stdout); 434} 435 436void 437usage() 438{ 439 (void)fprintf(stderr, 440 "usage: nfsstat [-csW] [-M core] [-N system] [-w interval]\n"); 441 exit(1); 442} 443 444static char SPBuf[64][8]; 445static int SPIndex; 446 447char * 448sperc1(int hits, int misses) 449{ 450 char *p = SPBuf[SPIndex]; 451 452 if (hits + misses) { 453 sprintf(p, "%3d%%", 454 (int)(char)((quad_t)hits * 100 / (hits + misses))); 455 } else { 456 sprintf(p, " -"); 457 } 458 SPIndex = (SPIndex + 1) & 63; 459 return(p); 460} 461 462char * 463sperc2(int ttl, int misses) 464{ 465 char *p = SPBuf[SPIndex]; 466 467 if (ttl) { 468 sprintf(p, "%3d%%", 469 (int)(char)((quad_t)(ttl - misses) * 100 / ttl)); 470 } else { 471 sprintf(p, " -"); 472 } 473 SPIndex = (SPIndex + 1) & 63; 474 return(p); 475} 476 477