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. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 /*- 33 * Copyright (c) 2004, 2008, 2009 Silicon Graphics International Corp. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions, and the following disclaimer, 41 * without modification. 42 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 43 * substantially similar to the "NO WARRANTY" disclaimer below 44 * ("Disclaimer") and any redistribution must be conditioned upon 45 * including a substantially similar Disclaimer requirement for further 46 * binary redistribution. 47 * 48 * NO WARRANTY 49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 57 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 58 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 * POSSIBILITY OF SUCH DAMAGES. 60 */ 61 62 63 #include <sys/param.h> 64 #include <sys/module.h> 65 #include <sys/mount.h> 66 #include <sys/time.h> 67 #include <sys/sysctl.h> 68 #include <nfs/nfssvc.h> 69 70 #include <fs/nfs/nfsproto.h> 71 #include <fs/nfs/nfsport.h> 72 73 #include <signal.h> 74 #include <fcntl.h> 75 #include <ctype.h> 76 #include <errno.h> 77 #include <limits.h> 78 #include <nlist.h> 79 #include <unistd.h> 80 #include <stdio.h> 81 #include <stdint.h> 82 #include <stdlib.h> 83 #include <string.h> 84 #include <paths.h> 85 #include <devstat.h> 86 #include <err.h> 87 88 #include <libxo/xo.h> 89 90 static int widemode = 0; 91 static int zflag = 0; 92 static int printtitle = 1; 93 static struct nfsstatsv1 ext_nfsstats; 94 static int extra_output = 0; 95 96 static void intpr(int, int); 97 static void printhdr(int, int, int); 98 static void usage(void) __dead2; 99 static char *sperc1(int, int); 100 static char *sperc2(int, int); 101 static void exp_intpr(int, int, int); 102 static void exp_sidewaysintpr(u_int, int, int, int); 103 static void compute_new_stats(struct nfsstatsv1 *cur_stats, 104 struct nfsstatsv1 *prev_stats, int curop, long double etime, 105 long double *mbsec, long double *kb_per_transfer, 106 long double *transfers_per_second, long double *ms_per_transfer, 107 uint64_t *queue_len, long double *busy_pct); 108 109 #define DELTA(field) (nfsstats.field - lastst.field) 110 111 #define STAT_TYPE_READ 0 112 #define STAT_TYPE_WRITE 1 113 #define STAT_TYPE_COMMIT 2 114 #define NUM_STAT_TYPES 3 115 116 struct stattypes { 117 int stat_type; 118 int nfs_type; 119 }; 120 static struct stattypes statstruct[] = { 121 {STAT_TYPE_READ, NFSV4OP_READ}, 122 {STAT_TYPE_WRITE, NFSV4OP_WRITE}, 123 {STAT_TYPE_COMMIT, NFSV4OP_COMMIT} 124 }; 125 126 #define STAT_TYPE_TO_NFS(stat_type) statstruct[stat_type].nfs_type 127 128 #define NFSSTAT_XO_VERSION "1" 129 130 int 131 main(int argc, char **argv) 132 { 133 u_int interval; 134 int clientOnly = -1; 135 int serverOnly = -1; 136 int newStats = 0; 137 int ch; 138 int mntlen, i; 139 char buf[1024]; 140 struct statfs *mntbuf; 141 struct nfscl_dumpmntopts dumpmntopts; 142 143 interval = 0; 144 145 argc = xo_parse_args(argc, argv); 146 if (argc < 0) 147 exit(1); 148 149 xo_set_version(NFSSTAT_XO_VERSION); 150 151 while ((ch = getopt(argc, argv, "cdEesWM:mN:w:zq")) != -1) 152 switch(ch) { 153 case 'M': 154 printf("*** -M option deprecated, ignored\n\n"); 155 break; 156 case 'm': 157 /* Display mount options for NFS mount points. */ 158 mntlen = getmntinfo(&mntbuf, MNT_NOWAIT); 159 for (i = 0; i < mntlen; i++) { 160 if (strcmp(mntbuf->f_fstypename, "nfs") == 0) { 161 dumpmntopts.ndmnt_fname = 162 mntbuf->f_mntonname; 163 dumpmntopts.ndmnt_buf = buf; 164 dumpmntopts.ndmnt_blen = sizeof(buf); 165 if (nfssvc(NFSSVC_DUMPMNTOPTS, 166 &dumpmntopts) >= 0) 167 printf("%s on %s\n%s\n", 168 mntbuf->f_mntfromname, 169 mntbuf->f_mntonname, buf); 170 else if (errno == EPERM) 171 errx(1, "Only privileged users" 172 " can use the -m option"); 173 } 174 mntbuf++; 175 } 176 exit(0); 177 case 'N': 178 printf("*** -N option deprecated, ignored\n\n"); 179 break; 180 case 'W': 181 widemode = 1; 182 break; 183 case 'w': 184 interval = atoi(optarg); 185 break; 186 case 'c': 187 clientOnly = 1; 188 if (serverOnly < 0) 189 serverOnly = 0; 190 break; 191 case 'd': 192 newStats = 1; 193 if (interval == 0) 194 interval = 1; 195 break; 196 case 's': 197 serverOnly = 1; 198 if (clientOnly < 0) 199 clientOnly = 0; 200 break; 201 case 'z': 202 zflag = 1; 203 break; 204 case 'E': 205 if (extra_output != 0) 206 xo_err(1, "-e and -E are mutually exclusive"); 207 extra_output = 2; 208 break; 209 case 'e': 210 if (extra_output != 0) 211 xo_err(1, "-e and -E are mutually exclusive"); 212 extra_output = 1; 213 break; 214 case 'q': 215 printtitle = 0; 216 break; 217 case '?': 218 default: 219 usage(); 220 } 221 argc -= optind; 222 argv += optind; 223 224 #define BACKWARD_COMPATIBILITY 225 #ifdef BACKWARD_COMPATIBILITY 226 if (*argv) 227 interval = atoi(*argv); 228 #endif 229 if (modfind("nfscommon") < 0) 230 xo_err(1, "NFS client/server not loaded"); 231 232 if (interval) { 233 exp_sidewaysintpr(interval, clientOnly, serverOnly, 234 newStats); 235 } else { 236 xo_open_container("nfsstat"); 237 if (extra_output != 0) 238 exp_intpr(clientOnly, serverOnly, extra_output - 1); 239 else 240 intpr(clientOnly, serverOnly); 241 xo_close_container("nfsstat"); 242 } 243 244 xo_finish(); 245 exit(0); 246 } 247 248 /* 249 * Print a description of the nfs stats. 250 */ 251 static void 252 intpr(int clientOnly, int serverOnly) 253 { 254 int nfssvc_flag; 255 256 nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT; 257 if (zflag != 0) { 258 if (clientOnly != 0) 259 nfssvc_flag |= NFSSVC_ZEROCLTSTATS; 260 if (serverOnly != 0) 261 nfssvc_flag |= NFSSVC_ZEROSRVSTATS; 262 } 263 ext_nfsstats.vers = NFSSTATS_V1; 264 if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0) 265 xo_err(1, "Can't get stats"); 266 if (clientOnly) { 267 xo_open_container("clientstats"); 268 269 if (printtitle) 270 xo_emit("{T:Client Info:\n"); 271 272 xo_open_container("operations"); 273 if (printtitle) 274 xo_emit("{T:Rpc Counts:}\n"); 275 276 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}" 277 "{T:Lookup/%13.13s}{T:Readlink/%13.13s}" 278 "{T:Read/%13.13s}{T:Write/%13.13s}" 279 "{T:Create/%13.13s}{T:Remove/%13.13s}\n"); 280 xo_emit("{:getattr/%13ju}{:setattr/%13ju}" 281 "{:lookup/%13ju}{:readlink/%13ju}" 282 "{:read/%13ju}{:write/%13ju}" 283 "{:create/%13ju}{:remove/%13ju}\n", 284 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR], 285 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR], 286 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP], 287 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK], 288 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ], 289 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE], 290 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE], 291 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]); 292 293 xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}" 294 "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}" 295 "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}" 296 "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n"); 297 xo_emit("{:rename/%13ju}{:link/%13ju}" 298 "{:symlink/%13ju}{:mkdir/%13ju}" 299 "{:rmdir/%13ju}{:readdir/%13ju}" 300 "{:rdirplus/%13ju}{:access/%13ju}\n", 301 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME], 302 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK], 303 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK], 304 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR], 305 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR], 306 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR], 307 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS], 308 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]); 309 310 xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}" 311 "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}" 312 "{T:Commit/%13.13s}\n"); 313 xo_emit("{:mknod/%13ju}{:fsstat/%13ju}" 314 "{:fsinfo/%13ju}{:pathconf/%13ju}" 315 "{:commit/%13ju}\n", 316 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD], 317 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT], 318 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO], 319 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF], 320 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT]); 321 322 xo_close_container("operations"); 323 324 xo_open_container("rpcs"); 325 if (printtitle) 326 xo_emit("{T:Rpc Info:}\n"); 327 328 xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}" 329 "{T:X Replies/%13.13s}{T:Retries/%13.13s}" 330 "{T:Requests/%13.13s}\n"); 331 xo_emit("{:timedout/%13ju}{:invalid/%13ju}" 332 "{:xreplies/%13ju}{:retries/%13ju}" 333 "{:requests/%13ju}\n", 334 (uintmax_t)ext_nfsstats.rpctimeouts, 335 (uintmax_t)ext_nfsstats.rpcinvalid, 336 (uintmax_t)ext_nfsstats.rpcunexpected, 337 (uintmax_t)ext_nfsstats.rpcretries, 338 (uintmax_t)ext_nfsstats.rpcrequests); 339 xo_close_container("rpcs"); 340 341 xo_open_container("cache"); 342 if (printtitle) 343 xo_emit("{T:Cache Info:}\n"); 344 345 xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}" 346 "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}" 347 "{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}" 348 "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n"); 349 xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}" 350 "{:lkuphits/%13ju}{:lkupmisses/%13ju}" 351 "{:biorhits/%13ju}{:biormisses/%13ju}" 352 "{:biowhits/%13ju}{:biowmisses/%13ju}\n", 353 (uintmax_t)ext_nfsstats.attrcache_hits, 354 (uintmax_t)ext_nfsstats.attrcache_misses, 355 (uintmax_t)ext_nfsstats.lookupcache_hits, 356 (uintmax_t)ext_nfsstats.lookupcache_misses, 357 (uintmax_t)(ext_nfsstats.biocache_reads - 358 ext_nfsstats.read_bios), 359 (uintmax_t)ext_nfsstats.read_bios, 360 (uintmax_t)(ext_nfsstats.biocache_writes - 361 ext_nfsstats.write_bios), 362 (uintmax_t)ext_nfsstats.write_bios); 363 364 xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}" 365 "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}" 366 "{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}" 367 "{T:Accs Hits/%13.13s}{T:Accs Misses/%13.13s}\n"); 368 xo_emit("{:biosrlhits/%13ju}{:biorlmisses/%13ju}" 369 "{:biodhits/%13ju}{:biodmisses/%13ju}" 370 "{:direhits/%13ju}{:diremisses/%13ju}" 371 "{:accshits/%13ju}{:accsmisses/%13ju}\n", 372 (uintmax_t)(ext_nfsstats.biocache_readlinks - 373 ext_nfsstats.readlink_bios), 374 (uintmax_t)ext_nfsstats.readlink_bios, 375 (uintmax_t)(ext_nfsstats.biocache_readdirs - 376 ext_nfsstats.readdir_bios), 377 (uintmax_t)ext_nfsstats.readdir_bios, 378 (uintmax_t)ext_nfsstats.direofcache_hits, 379 (uintmax_t)ext_nfsstats.direofcache_misses, 380 (uintmax_t)ext_nfsstats.accesscache_hits, 381 (uintmax_t)ext_nfsstats.accesscache_misses); 382 383 xo_close_container("cache"); 384 385 xo_close_container("clientstats"); 386 } 387 if (serverOnly) { 388 xo_open_container("serverstats"); 389 390 if (printtitle) 391 xo_emit("{T:Server Info:}\n"); 392 xo_open_container("operations"); 393 394 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}" 395 "{T:Lookup/%13.13s}{T:Readlink/%13.13s}" 396 "{T:Read/%13.13s}{T:Write/%13.13s}" 397 "{T:Create/%13.13s}{T:Remove/%13.13s}\n"); 398 xo_emit("{:getattr/%13ju}{:setattr/%13ju}" 399 "{:lookup/%13ju}{:readlink/%13ju}" 400 "{:read/%13ju}{:write/%13ju}" 401 "{:create/%13ju}{:remove/%13ju}\n", 402 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR], 403 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR], 404 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP], 405 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK], 406 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ], 407 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 408 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE], 409 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]); 410 411 xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}" 412 "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}" 413 "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}" 414 "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n"); 415 xo_emit("{:rename/%13ju}{:link/%13ju}" 416 "{:symlink/%13ju}{:mkdir/%13ju}" 417 "{:rmdir/%13ju}{:readdir/%13ju}" 418 "{:rdirplus/%13ju}{:access/%13ju}\n", 419 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME], 420 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK], 421 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK], 422 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR], 423 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR], 424 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR], 425 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS], 426 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]); 427 428 xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}" 429 "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}" 430 "{T:Commit/%13.13s}\n"); 431 xo_emit("{:mknod/%13ju}{:fsstat/%13ju}" 432 "{:fsinfo/%13ju}{:pathconf/%13ju}" 433 "{:commit/%13ju}\n", 434 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD], 435 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT], 436 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO], 437 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF], 438 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]); 439 440 xo_close_container("operations"); 441 442 xo_open_container("server"); 443 444 if (printtitle) 445 xo_emit("{T:Server Write Gathering:/%13.13s}\n"); 446 447 xo_emit("{T:WriteOps/%13.13s}{T:WriteRPC/%13.13s}" 448 "{T:Opsaved/%13.13s}\n"); 449 xo_emit("{:writeops/%13ju}{:writerpc/%13ju}" 450 "{:opsaved/%13ju}\n", 451 /* 452 * The new client doesn't do write gathering. It was 453 * only useful for NFSv2. 454 */ 455 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 456 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0); 457 458 xo_close_container("server"); 459 460 xo_open_container("cache"); 461 if (printtitle) 462 xo_emit("{T:Server Cache Stats:/%13.13s}\n"); 463 xo_emit("{T:Inprog/%13.13s}" 464 "{T:Non-Idem/%13.13s}{T:Misses/%13.13s}\n"); 465 xo_emit("{:inprog/%13ju}{:nonidem/%13ju}{:misses/%13ju}\n", 466 (uintmax_t)ext_nfsstats.srvcache_inproghits, 467 (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits, 468 (uintmax_t)ext_nfsstats.srvcache_misses); 469 xo_close_container("cache"); 470 471 xo_close_container("serverstats"); 472 } 473 } 474 475 static void 476 printhdr(int clientOnly, int serverOnly, int newStats) 477 { 478 479 if (newStats) { 480 printf(" [%s Read %s] [%s Write %s] " 481 "%s[=========== Total ============]\n" 482 " KB/t tps MB/s%s KB/t tps MB/s%s " 483 "%sKB/t tps MB/s ms ql %%b", 484 widemode ? "========" : "=====", 485 widemode ? "========" : "=====", 486 widemode ? "========" : "=====", 487 widemode ? "=======" : "====", 488 widemode ? "[Commit ] " : "", 489 widemode ? " ms" : "", 490 widemode ? " ms" : "", 491 widemode ? "tps ms " : ""); 492 } else { 493 printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s", 494 ((serverOnly && clientOnly) ? " " : " "), 495 "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename", 496 "Access", "Rddir"); 497 if (widemode && clientOnly) { 498 printf(" Attr Lkup BioR BioW Accs BioD"); 499 } 500 } 501 printf("\n"); 502 fflush(stdout); 503 } 504 505 static void 506 usage(void) 507 { 508 (void)fprintf(stderr, 509 "usage: nfsstat [-cdEemqszW] [-w wait]\n"); 510 exit(1); 511 } 512 513 static char SPBuf[64][8]; 514 static int SPIndex; 515 516 static char * 517 sperc1(int hits, int misses) 518 { 519 char *p = SPBuf[SPIndex]; 520 521 if (hits + misses) { 522 sprintf(p, "%3d%%", 523 (int)(char)((quad_t)hits * 100 / (hits + misses))); 524 } else { 525 sprintf(p, " -"); 526 } 527 SPIndex = (SPIndex + 1) & 63; 528 return(p); 529 } 530 531 static char * 532 sperc2(int ttl, int misses) 533 { 534 char *p = SPBuf[SPIndex]; 535 536 if (ttl) { 537 sprintf(p, "%3d%%", 538 (int)(char)((quad_t)(ttl - misses) * 100 / ttl)); 539 } else { 540 sprintf(p, " -"); 541 } 542 SPIndex = (SPIndex + 1) & 63; 543 return(p); 544 } 545 546 #define DELTA_T(field) \ 547 devstat_compute_etime(&cur_stats->field, \ 548 (prev_stats ? &prev_stats->field : NULL)) 549 550 /* 551 * XXX KDM mostly copied from ctlstat. We should commonize the code (and 552 * the devstat code) somehow. 553 */ 554 static void 555 compute_new_stats(struct nfsstatsv1 *cur_stats, 556 struct nfsstatsv1 *prev_stats, int curop, 557 long double etime, long double *mbsec, 558 long double *kb_per_transfer, 559 long double *transfers_per_second, 560 long double *ms_per_transfer, uint64_t *queue_len, 561 long double *busy_pct) 562 { 563 uint64_t total_bytes = 0, total_operations = 0; 564 struct bintime total_time_bt; 565 struct timespec total_time_ts; 566 567 bzero(&total_time_bt, sizeof(total_time_bt)); 568 bzero(&total_time_ts, sizeof(total_time_ts)); 569 570 total_bytes = cur_stats->srvbytes[curop]; 571 total_operations = cur_stats->srvops[curop]; 572 if (prev_stats != NULL) { 573 total_bytes -= prev_stats->srvbytes[curop]; 574 total_operations -= prev_stats->srvops[curop]; 575 } 576 577 *mbsec = total_bytes; 578 *mbsec /= 1024 * 1024; 579 if (etime > 0.0) { 580 *busy_pct = DELTA_T(busytime); 581 if (*busy_pct < 0) 582 *busy_pct = 0; 583 *busy_pct /= etime; 584 *busy_pct *= 100; 585 if (*busy_pct < 0) 586 *busy_pct = 0; 587 *mbsec /= etime; 588 } else { 589 *busy_pct = 0; 590 *mbsec = 0; 591 } 592 *kb_per_transfer = total_bytes; 593 *kb_per_transfer /= 1024; 594 if (total_operations > 0) 595 *kb_per_transfer /= total_operations; 596 else 597 *kb_per_transfer = 0; 598 if (etime > 0.0) { 599 *transfers_per_second = total_operations; 600 *transfers_per_second /= etime; 601 } else { 602 *transfers_per_second = 0.0; 603 } 604 605 if (total_operations > 0) { 606 *ms_per_transfer = DELTA_T(srvduration[curop]); 607 *ms_per_transfer /= total_operations; 608 *ms_per_transfer *= 1000; 609 } else 610 *ms_per_transfer = 0.0; 611 612 *queue_len = cur_stats->srvstartcnt - cur_stats->srvdonecnt; 613 } 614 615 /* 616 * Print a description of the nfs stats for the client/server, 617 * including NFSv4.1. 618 */ 619 static void 620 exp_intpr(int clientOnly, int serverOnly, int nfs41) 621 { 622 int nfssvc_flag; 623 624 xo_open_container("nfsv4"); 625 626 nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT; 627 if (zflag != 0) { 628 if (clientOnly != 0) 629 nfssvc_flag |= NFSSVC_ZEROCLTSTATS; 630 if (serverOnly != 0) 631 nfssvc_flag |= NFSSVC_ZEROSRVSTATS; 632 } 633 ext_nfsstats.vers = NFSSTATS_V1; 634 if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0) 635 xo_err(1, "Can't get stats"); 636 if (clientOnly != 0) { 637 xo_open_container("clientstats"); 638 639 xo_open_container("operations"); 640 if (printtitle) { 641 xo_emit("{T:Client Info:}\n"); 642 xo_emit("{T:RPC Counts:}\n"); 643 } 644 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}" 645 "{T:Lookup/%13.13s}{T:Readlink/%13.13s}" 646 "{T:Read/%13.13s}{T:Write/%13.13s}\n"); 647 xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}" 648 "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n", 649 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR], 650 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR], 651 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP], 652 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK], 653 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ], 654 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE]); 655 xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}" 656 "{T:Rename/%13.13s}{T:Link/%13.13s}" 657 "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n"); 658 xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}" 659 "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n", 660 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE], 661 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE], 662 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME], 663 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK], 664 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK], 665 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR]); 666 xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}" 667 "{T:RdirPlus/%13.13s}{T:Access/%13.13s}" 668 "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n"); 669 xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}" 670 "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n", 671 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR], 672 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR], 673 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS], 674 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS], 675 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD], 676 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT]); 677 xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}" 678 "{T:Commit/%13.13s}{T:SetClId/%13.13s}" 679 "{T:SetClIdCf/%13.13s}{T:Lock/%13.13s}\n"); 680 xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}" 681 "{:setclientid/%13ju}{:setclientidcf/%13ju}{:lock/%13ju}\n", 682 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO], 683 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF], 684 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT], 685 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID], 686 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM], 687 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]); 688 xo_emit("{T:LockT/%13.13s}{T:LockU/%13.13s}" 689 "{T:Open/%13.13s}{T:OpenCfr/%13.13s}\n"); 690 xo_emit("{:lockt/%13ju}{:locku/%13ju}" 691 "{:open/%13ju}{:opencfr/%13ju}\n", 692 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT], 693 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU], 694 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN], 695 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]); 696 697 if (nfs41) { 698 xo_open_container("nfsv41"); 699 700 xo_emit("{T:OpenDownGr/%13.13s}{T:Close/%13.13s}\n"); 701 xo_emit("{:opendowngr/%13ju}{:close/%13ju}\n", 702 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENDOWNGRADE], 703 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CLOSE]); 704 705 xo_emit("{T:RelLckOwn/%13.13s}{T:FreeStateID/%13.13s}" 706 "{T:PutRootFH/%13.13s}{T:DelegRet/%13.13s}" 707 "{T:GetAcl/%13.13s}{T:SetAcl/%13.13s}\n"); 708 xo_emit("{:rellckown/%13ju}{:freestateid/%13ju}" 709 "{:putrootfh/%13ju}{:delegret/%13ju}" 710 "{:getacl/%13ju}{:setacl/%13ju}\n", 711 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RELEASELCKOWN], 712 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FREESTATEID], 713 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PUTROOTFH], 714 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DELEGRETURN], 715 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETACL], 716 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETACL]); 717 718 xo_emit("{T:ExchangeId/%13.13s}{T:CreateSess/%13.13s}" 719 "{T:DestroySess/%13.13s}{T:DestroyClId/%13.13s}" 720 "{T:LayoutGet/%13.13s}{T:GetDevInfo/%13.13s}\n"); 721 xo_emit("{:exchangeid/%13ju}{:createsess/%13ju}" 722 "{:destroysess/%13ju}{:destroyclid/%13ju}" 723 "{:layoutget/%13ju}{:getdevinfo/%13ju}\n", 724 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_EXCHANGEID], 725 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATESESSION], 726 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYSESSION], 727 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYCLIENT], 728 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTGET], 729 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETDEVICEINFO]); 730 731 xo_emit("{T:LayoutCommit/%13.13s}{T:LayoutReturn/%13.13s}" 732 "{T:ReclaimCompl/%13.13s}{T:ReadDataS/%13.13s}" 733 "{T:WriteDataS/%13.13s}{T:CommitDataS/%13.13s}\n"); 734 xo_emit("{:layoutcomit/%13ju}{:layoutreturn/%13ju}" 735 "{:reclaimcompl/%13ju}{:readdatas/%13ju}" 736 "{:writedatas/%13ju}{:commitdatas/%13ju}\n", 737 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTCOMMIT], 738 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTRETURN], 739 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RECLAIMCOMPL], 740 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDS], 741 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITEDS], 742 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMITDS]); 743 744 xo_emit("{T:OpenLayout/%13.13s}{T:CreateLayout/%13.13s}" 745 "{T:BindConnSess/%13.13s}{T:LookupOpen/%13.13s}" 746 "{T:AppendWrite/%13.13s}\n"); 747 xo_emit("{:openlayout/%13ju}{:createlayout/%13ju}" 748 "{:bindconnsess/%13ju}{:lookupopen/%13ju}" 749 "{:appendwrite/%13ju}\n", 750 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENLAYGET], 751 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATELAYGET], 752 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_BINDCONNTOSESS], 753 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUPOPEN], 754 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_APPENDWRITE]); 755 756 xo_close_container("nfsv41"); 757 758 xo_open_container("nfsv42"); 759 760 xo_emit("{T:IOAdvise/%13.13s}{T:Allocate/%13.13s}" 761 "{T:Copy/%13.13s}{T:Seek/%13.13s}" 762 "{T:SeekDataS/%13.13s}{T:GetExtattr/%13.13s}\n"); 763 xo_emit("{:ioadvise/%13ju}{:allocate/%13ju}" 764 "{:copy/%13ju}{:seek/%13ju}" 765 "{:seekdatas/%13ju}{:getextattr/%13ju}\n", 766 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_IOADVISE], 767 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ALLOCATE], 768 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COPY], 769 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SEEK], 770 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SEEKDS], 771 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETEXTATTR]); 772 773 xo_emit("{T:SetExtattr/%13.13s}{T:RmExtattr/%13.13s}" 774 "{T:ListExtattr/%13.13s}{T:Deallocate/%13.13s}" 775 "{T:LayoutError/%13.13s}\n"); 776 xo_emit("{:setextattr/%13ju}{:rmextattr/%13ju}" 777 "{:listextattr/%13ju}{:deallocate/%13ju}" 778 "{:layouterror/%13ju}\n", 779 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETEXTATTR], 780 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMEXTATTR], 781 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LISTEXTATTR], 782 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DEALLOCATE], 783 (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTERROR]); 784 785 xo_close_container("nfsv42"); 786 } 787 xo_close_container("operations"); 788 789 if (printtitle) 790 xo_emit("{T:Client:}\n"); 791 xo_open_container("client"); 792 xo_emit("{T:OpenOwner/%13.13s}{T:Opens/%13.13s}" 793 "{T:LockOwner/%13.13s}{T:Locks/%13.13s}" 794 "{T:Delegs/%13.13s}{T:LocalOwn/%13.13s}\n"); 795 xo_emit("{:openowner/%13ju}{:opens/%13ju}" 796 "{:lockowner/%13ju}{:locks/%13ju}" 797 "{:delegs/%13ju}{:localown/%13ju}\n", 798 (uintmax_t)ext_nfsstats.clopenowners, 799 (uintmax_t)ext_nfsstats.clopens, 800 (uintmax_t)ext_nfsstats.cllockowners, 801 (uintmax_t)ext_nfsstats.cllocks, 802 (uintmax_t)ext_nfsstats.cldelegates, 803 (uintmax_t)ext_nfsstats.cllocalopenowners); 804 805 xo_emit("{T:LocalOpen/%13.13s}{T:LocalLown/%13.13s}" 806 "{T:LocalLock/%13.13s}{T:Layouts/%13.13s}\n"); 807 xo_emit("{:localopen/%13ju}{:locallown/%13ju}" 808 "{:locallock/%13ju}{:layouts/%13ju}\n", 809 (uintmax_t)ext_nfsstats.cllocalopens, 810 (uintmax_t)ext_nfsstats.cllocallockowners, 811 (uintmax_t)ext_nfsstats.cllocallocks, 812 (uintmax_t)ext_nfsstats.cllayouts); 813 xo_close_container("client"); 814 815 xo_open_container("rpc"); 816 if (printtitle) 817 xo_emit("{T:Rpc Info:}\n"); 818 xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}" 819 "{T:X Replies/%13.13s}{T:Retries/%13.13s}" 820 "{T:Requests/%13.13s}\n"); 821 xo_emit("{:timedout/%13ju}{:invalid/%13ju}" 822 "{:xreplies/%13ju}{:retries/%13ju}" 823 "{:requests/%13ju}\n", 824 (uintmax_t)ext_nfsstats.rpctimeouts, 825 (uintmax_t)ext_nfsstats.rpcinvalid, 826 (uintmax_t)ext_nfsstats.rpcunexpected, 827 (uintmax_t)ext_nfsstats.rpcretries, 828 (uintmax_t)ext_nfsstats.rpcrequests); 829 xo_close_container("rpc"); 830 831 xo_open_container("cache"); 832 if (printtitle) 833 xo_emit("{T:Cache Info:}\n"); 834 xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}" 835 "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}\n"); 836 xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}" 837 "{:lkuphits/%13ju}{:lkupmisses/%13ju}\n", 838 (uintmax_t)ext_nfsstats.attrcache_hits, 839 (uintmax_t)ext_nfsstats.attrcache_misses, 840 (uintmax_t)ext_nfsstats.lookupcache_hits, 841 (uintmax_t)ext_nfsstats.lookupcache_misses); 842 843 xo_emit("{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}" 844 "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n"); 845 xo_emit("{:biorhits/%13ju}{:biormisses/%13ju}" 846 "{:biowhits/%13ju}{:biowmisses/%13ju}\n", 847 (uintmax_t)(ext_nfsstats.biocache_reads - 848 ext_nfsstats.read_bios), 849 (uintmax_t)ext_nfsstats.read_bios, 850 (uintmax_t)(ext_nfsstats.biocache_writes - 851 ext_nfsstats.write_bios), 852 (uintmax_t)ext_nfsstats.write_bios); 853 854 xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}" 855 "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}\n"); 856 xo_emit("{:biorlhits/%13ju}{:biorlmisses/%13ju}" 857 "{:biodhits/%13ju}{:biodmisses/%13ju}\n", 858 (uintmax_t)(ext_nfsstats.biocache_readlinks - 859 ext_nfsstats.readlink_bios), 860 (uintmax_t)ext_nfsstats.readlink_bios, 861 (uintmax_t)(ext_nfsstats.biocache_readdirs - 862 ext_nfsstats.readdir_bios), 863 (uintmax_t)ext_nfsstats.readdir_bios); 864 865 xo_emit("{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}\n"); 866 xo_emit("{:direhits/%13ju}{:diremisses/%13ju}\n", 867 (uintmax_t)ext_nfsstats.direofcache_hits, 868 (uintmax_t)ext_nfsstats.direofcache_misses); 869 xo_open_container("cache"); 870 871 xo_close_container("clientstats"); 872 } 873 if (serverOnly != 0) { 874 xo_open_container("serverstats"); 875 876 xo_open_container("operations"); 877 if (printtitle) 878 xo_emit("{T:Server Info:}\n"); 879 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}" 880 "{T:Lookup/%13.13s}{T:Readlink/%13.13s}" 881 "{T:Read/%13.13s}{T:Write/%13.13s}\n"); 882 xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}" 883 "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n", 884 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR], 885 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR], 886 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP], 887 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK], 888 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ], 889 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE]); 890 xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}" 891 "{T:Rename/%13.13s}{T:Link/%13.13s}" 892 "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n"); 893 xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}" 894 "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n", 895 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE], 896 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE], 897 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME], 898 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK], 899 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK], 900 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR]); 901 xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}" 902 "{T:RdirPlus/%13.13s}{T:Access/%13.13s}" 903 "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n"); 904 xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}" 905 "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n", 906 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR], 907 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR], 908 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS], 909 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS], 910 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD], 911 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT]); 912 xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}" 913 "{T:Commit/%13.13s}{T:LookupP/%13.13s}" 914 "{T:SetClId/%13.13s}{T:SetClIdCf/%13.13s}\n"); 915 xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}" 916 "{:lookupp/%13ju}{:setclientid/%13ju}{:setclientidcfrm/%13ju}\n", 917 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO], 918 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF], 919 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT], 920 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP], 921 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID], 922 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]); 923 xo_emit("{T:Open/%13.13s}{T:OpenAttr/%13.13s}" 924 "{T:OpenDwnGr/%13.13s}{T:OpenCfrm/%13.13s}" 925 "{T:DelePurge/%13.13s}{T:DelRet/%13.13s}\n"); 926 xo_emit("{:open/%13ju}{:openattr/%13ju}{:opendwgr/%13ju}" 927 "{:opencfrm/%13ju}{:delepurge/%13ju}{:delreg/%13ju}\n", 928 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN], 929 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR], 930 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE], 931 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM], 932 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE], 933 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN]); 934 xo_emit("{T:GetFH/%13.13s}{T:Lock/%13.13s}" 935 "{T:LockT/%13.13s}{T:LockU/%13.13s}" 936 "{T:Close/%13.13s}{T:Verify/%13.13s}\n"); 937 xo_emit("{:getfh/%13ju}{:lock/%13ju}{:lockt/%13ju}" 938 "{:locku/%13ju}{:close/%13ju}{:verify/%13ju}\n", 939 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH], 940 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK], 941 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT], 942 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU], 943 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE], 944 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY]); 945 xo_emit("{T:NVerify/%13.13s}{T:PutFH/%13.13s}" 946 "{T:PutPubFH/%13.13s}{T:PutRootFH/%13.13s}" 947 "{T:Renew/%13.13s}{T:RestoreFH/%13.13s}\n"); 948 xo_emit("{:nverify/%13ju}{:putfh/%13ju}{:putpubfh/%13ju}" 949 "{:putrootfh/%13ju}{:renew/%13ju}{:restore/%13ju}\n", 950 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY], 951 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH], 952 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH], 953 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH], 954 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW], 955 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH]); 956 xo_emit("{T:SaveFH/%13.13s}{T:Secinfo/%13.13s}" 957 "{T:RelLockOwn/%13.13s}{T:V4Create/%13.13s}\n"); 958 xo_emit("{:savefh/%13ju}{:secinfo/%13ju}{:rellockown/%13ju}" 959 "{:v4create/%13ju}\n", 960 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH], 961 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO], 962 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN], 963 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]); 964 if (nfs41) { 965 xo_open_container("nfsv41"); 966 xo_emit("{T:BackChannelCtrl/%13.13s}{T:BindConnToSess/%13.13s}" 967 "{T:ExchangeID/%13.13s}{T:CreateSess/%13.13s}" 968 "{T:DestroySess/%13.13s}{T:FreeStateID/%13.13s}\n"); 969 xo_emit("{:backchannelctrl/%13ju}{:bindconntosess/%13ju}" 970 "{:exchangeid/%13ju}{:createsess/%13ju}" 971 "{:destroysess/%13ju}{:freestateid/%13ju}\n", 972 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BACKCHANNELCTL], 973 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BINDCONNTOSESS], 974 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_EXCHANGEID], 975 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATESESSION], 976 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYSESSION], 977 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FREESTATEID]), 978 979 xo_emit("{T:GetDirDeleg/%13.13s}{T:GetDevInfo/%13.13s}" 980 "{T:GetDevList/%13.13s}{T:layoutCommit/%13.13s}" 981 "{T:LayoutGet/%13.13s}{T:LayoutReturn/%13.13s}\n"); 982 xo_emit("{:getdirdeleg/%13ju}{:getdevinfo/%13ju}" 983 "{:getdevlist/%13ju}{:layoutcommit/%13ju}" 984 "{:layoutget/%13ju}{:layoutreturn/%13ju}\n", 985 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDIRDELEG], 986 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVINFO], 987 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVLIST], 988 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTCOMMIT], 989 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTGET], 990 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTRETURN]); 991 992 xo_emit("{T:SecInfNoName/%13.13s}{T:Sequence/%13.13s}" 993 "{T:SetSSV/%13.13s}{T:TestStateID/%13.13s}" 994 "{T:WantDeleg/%13.13s}{T:DestroyClId/%13.13s}\n"); 995 xo_emit("{:secinfnoname/%13ju}{:sequence/%13ju}" 996 "{:setssv/%13ju}{:teststateid/%13ju}{:wantdeleg/%13ju}" 997 "{:destroyclid/%13ju}\n", 998 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFONONAME], 999 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEQUENCE], 1000 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETSSV], 1001 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_TESTSTATEID], 1002 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WANTDELEG], 1003 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYCLIENTID]); 1004 1005 xo_emit("{T:ReclaimCompl/%13.13s}\n"); 1006 xo_emit("{:reclaimcompl/%13ju}\n", 1007 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RECLAIMCOMPL]); 1008 1009 xo_close_container("nfsv41"); 1010 1011 xo_open_container("nfsv42"); 1012 1013 xo_emit("{T:Allocate/%13.13s}{T:Copy/%13.13s}" 1014 "{T:CopyNotify/%13.13s}{T:Deallocate/%13.13s}" 1015 "{T:IOAdvise/%13.13s}{T:LayoutError/%13.13s}\n"); 1016 xo_emit("{:allocate/%13ju}{:copy/%13ju}" 1017 "{:copynotify/%13ju}{:deallocate/%13ju}" 1018 "{:ioadvise/%13ju}{:layouterror/%13ju}\n", 1019 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ALLOCATE], 1020 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COPY], 1021 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COPYNOTIFY], 1022 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DEALLOCATE], 1023 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_IOADVISE], 1024 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTERROR]); 1025 1026 xo_emit("{T:LayoutStats/%13.13s}{T:OffloadCncl/%13.13s}" 1027 "{T:OffloadStat/%13.13s}{T:ReadPlus/%13.13s}" 1028 "{T:Seek/%13.13s}{T:WriteSame/%13.13s}\n"); 1029 xo_emit("{:layoutstats/%13ju}{:offloadcncl/%13ju}" 1030 "{:offloadstat/%13ju}{:readplus/%13ju}" 1031 "{:seek/%13ju}{:writesame/%13ju}\n", 1032 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTSTATS], 1033 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OFFLOADCANCEL], 1034 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OFFLOADSTATUS], 1035 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READPLUS], 1036 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEEK], 1037 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITESAME]); 1038 1039 xo_emit("{T:Clone/%13.13s}{T:GetExtattr/%13.13s}" 1040 "{T:SetExtattr/%13.13s}{T:ListExtattr/%13.13s}" 1041 "{T:RmExtattr/%13.13s}\n"); 1042 xo_emit("{:clone/%13ju}{:getextattr/%13ju}" 1043 "{:setextattr/%13ju}{:listextattr/%13ju}" 1044 "{:rmextattr/%13ju}\n", 1045 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLONE], 1046 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETXATTR], 1047 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETXATTR], 1048 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LISTXATTRS], 1049 (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVEXATTR]); 1050 1051 xo_close_container("nfsv42"); 1052 } 1053 1054 xo_close_container("operations"); 1055 1056 if (printtitle) 1057 xo_emit("{T:Server:}\n"); 1058 xo_open_container("server"); 1059 xo_emit("{T:Clients/%13.13s}{T:OpenOwner/%13.13s}" 1060 "{T:Opens/%13.13s}{T:LockOwner/%13.13s}{T:Locks/%13.13s}" 1061 "{T:Delegs/%13.13s}\n"); 1062 xo_emit("{:clients/%13ju}{:openowner/%13ju}{:opens/%13ju}" 1063 "{:lockowner/%13ju}{:locks/%13ju}{:delegs/%13ju}\n", 1064 (uintmax_t)ext_nfsstats.srvclients, 1065 (uintmax_t)ext_nfsstats.srvopenowners, 1066 (uintmax_t)ext_nfsstats.srvopens, 1067 (uintmax_t)ext_nfsstats.srvlockowners, 1068 (uintmax_t)ext_nfsstats.srvlocks, 1069 (uintmax_t)ext_nfsstats.srvdelegates); 1070 xo_emit("{T:Layouts/%13.13s}\n"); 1071 xo_emit("{:layouts/%13ju}\n", 1072 (uintmax_t)ext_nfsstats.srvlayouts); 1073 xo_close_container("server"); 1074 1075 if (printtitle) 1076 xo_emit("{T:Server Cache Stats:}\n"); 1077 xo_open_container("cache"); 1078 xo_emit("{T:Inprog/%13.13s}" 1079 "{T:Non-idem/%13.13s}{T:Misses/%13.13s}" 1080 "{T:CacheSize/%13.13s}{T:TCPPeak/%13.13s}\n"); 1081 xo_emit("{:inprog/%13ju}{:nonidem/%13ju}" 1082 "{:misses/%13ju}{:cachesize/%13ju}{:tcppeak/%13ju}\n", 1083 (uintmax_t)ext_nfsstats.srvcache_inproghits, 1084 (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits, 1085 (uintmax_t)ext_nfsstats.srvcache_misses, 1086 (uintmax_t)ext_nfsstats.srvcache_size, 1087 (uintmax_t)ext_nfsstats.srvcache_tcppeak); 1088 xo_close_container("cache"); 1089 1090 xo_close_container("serverstats"); 1091 } 1092 1093 xo_close_container("nfsv4"); 1094 } 1095 1096 static void 1097 compute_totals(struct nfsstatsv1 *total_stats, struct nfsstatsv1 *cur_stats) 1098 { 1099 int i; 1100 1101 bzero(total_stats, sizeof(*total_stats)); 1102 for (i = 0; i < (NFSV42_NOPS + NFSV4OP_FAKENOPS); i++) { 1103 total_stats->srvbytes[0] += cur_stats->srvbytes[i]; 1104 total_stats->srvops[0] += cur_stats->srvops[i]; 1105 bintime_add(&total_stats->srvduration[0], 1106 &cur_stats->srvduration[i]); 1107 total_stats->srvrpccnt[i] = cur_stats->srvrpccnt[i]; 1108 } 1109 total_stats->srvstartcnt = cur_stats->srvstartcnt; 1110 total_stats->srvdonecnt = cur_stats->srvdonecnt; 1111 total_stats->busytime = cur_stats->busytime; 1112 1113 } 1114 1115 /* 1116 * Print a running summary of nfs statistics for the experimental client and/or 1117 * server. 1118 * Repeat display every interval seconds, showing statistics 1119 * collected over that interval. Assumes that interval is non-zero. 1120 * First line printed at top of screen is always cumulative. 1121 */ 1122 static void 1123 exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly, 1124 int newStats) 1125 { 1126 struct nfsstatsv1 nfsstats, lastst, *ext_nfsstatsp; 1127 struct nfsstatsv1 curtotal, lasttotal; 1128 struct timespec ts, lastts; 1129 int hdrcnt = 1; 1130 1131 ext_nfsstatsp = &lastst; 1132 ext_nfsstatsp->vers = NFSSTATS_V1; 1133 if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) < 0) 1134 err(1, "Can't get stats"); 1135 clock_gettime(CLOCK_MONOTONIC, &lastts); 1136 compute_totals(&lasttotal, ext_nfsstatsp); 1137 sleep(interval); 1138 1139 for (;;) { 1140 ext_nfsstatsp = &nfsstats; 1141 ext_nfsstatsp->vers = NFSSTATS_V1; 1142 if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) 1143 < 0) 1144 err(1, "Can't get stats"); 1145 clock_gettime(CLOCK_MONOTONIC, &ts); 1146 1147 if (--hdrcnt == 0) { 1148 printhdr(clientOnly, serverOnly, newStats); 1149 if (newStats) 1150 hdrcnt = 20; 1151 else if (clientOnly && serverOnly) 1152 hdrcnt = 10; 1153 else 1154 hdrcnt = 20; 1155 } 1156 if (clientOnly && newStats == 0) { 1157 printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju", 1158 ((clientOnly && serverOnly) ? "Client:" : ""), 1159 (uintmax_t)DELTA(rpccnt[NFSPROC_GETATTR]), 1160 (uintmax_t)DELTA(rpccnt[NFSPROC_LOOKUP]), 1161 (uintmax_t)DELTA(rpccnt[NFSPROC_READLINK]), 1162 (uintmax_t)DELTA(rpccnt[NFSPROC_READ]), 1163 (uintmax_t)DELTA(rpccnt[NFSPROC_WRITE]), 1164 (uintmax_t)DELTA(rpccnt[NFSPROC_RENAME]), 1165 (uintmax_t)DELTA(rpccnt[NFSPROC_ACCESS]), 1166 (uintmax_t)(DELTA(rpccnt[NFSPROC_READDIR]) + 1167 DELTA(rpccnt[NFSPROC_READDIRPLUS])) 1168 ); 1169 if (widemode) { 1170 printf(" %s %s %s %s %s %s", 1171 sperc1(DELTA(attrcache_hits), 1172 DELTA(attrcache_misses)), 1173 sperc1(DELTA(lookupcache_hits), 1174 DELTA(lookupcache_misses)), 1175 sperc2(DELTA(biocache_reads), 1176 DELTA(read_bios)), 1177 sperc2(DELTA(biocache_writes), 1178 DELTA(write_bios)), 1179 sperc1(DELTA(accesscache_hits), 1180 DELTA(accesscache_misses)), 1181 sperc2(DELTA(biocache_readdirs), 1182 DELTA(readdir_bios)) 1183 ); 1184 } 1185 printf("\n"); 1186 } 1187 1188 if (serverOnly && newStats) { 1189 long double cur_secs, last_secs, etime; 1190 long double mbsec; 1191 long double kb_per_transfer; 1192 long double transfers_per_second; 1193 long double ms_per_transfer; 1194 uint64_t queue_len; 1195 long double busy_pct; 1196 int i; 1197 1198 cur_secs = ts.tv_sec + 1199 ((long double)ts.tv_nsec / 1000000000); 1200 last_secs = lastts.tv_sec + 1201 ((long double)lastts.tv_nsec / 1000000000); 1202 etime = cur_secs - last_secs; 1203 1204 compute_totals(&curtotal, &nfsstats); 1205 1206 for (i = 0; i < NUM_STAT_TYPES; i++) { 1207 compute_new_stats(&nfsstats, &lastst, 1208 STAT_TYPE_TO_NFS(i), etime, &mbsec, 1209 &kb_per_transfer, 1210 &transfers_per_second, 1211 &ms_per_transfer, &queue_len, 1212 &busy_pct); 1213 1214 if (i == STAT_TYPE_COMMIT) { 1215 if (widemode == 0) 1216 continue; 1217 1218 printf("%2.0Lf %7.2Lf ", 1219 transfers_per_second, 1220 ms_per_transfer); 1221 } else { 1222 printf("%5.2Lf %5.0Lf %7.2Lf ", 1223 kb_per_transfer, 1224 transfers_per_second, mbsec); 1225 if (widemode) 1226 printf("%5.2Lf ", 1227 ms_per_transfer); 1228 } 1229 } 1230 1231 compute_new_stats(&curtotal, &lasttotal, 0, etime, 1232 &mbsec, &kb_per_transfer, &transfers_per_second, 1233 &ms_per_transfer, &queue_len, &busy_pct); 1234 1235 printf("%5.2Lf %5.0Lf %7.2Lf %5.2Lf %3ju %3.0Lf\n", 1236 kb_per_transfer, transfers_per_second, mbsec, 1237 ms_per_transfer, queue_len, busy_pct); 1238 } else if (serverOnly) { 1239 printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju", 1240 ((clientOnly && serverOnly) ? "Server:" : ""), 1241 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_GETATTR]), 1242 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_LOOKUP]), 1243 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_READLINK]), 1244 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_READ]), 1245 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_WRITE]), 1246 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_RENAME]), 1247 (uintmax_t)DELTA(srvrpccnt[NFSV4OP_ACCESS]), 1248 (uintmax_t)(DELTA(srvrpccnt[NFSV4OP_READDIR]) + 1249 DELTA(srvrpccnt[NFSV4OP_READDIRPLUS]))); 1250 printf("\n"); 1251 } 1252 bcopy(&nfsstats, &lastst, sizeof(lastst)); 1253 bcopy(&curtotal, &lasttotal, sizeof(lasttotal)); 1254 lastts = ts; 1255 fflush(stdout); 1256 sleep(interval); 1257 } 1258 /*NOTREACHED*/ 1259 } 1260