xref: /freebsd/usr.bin/nfsstat/nfsstat.c (revision ca987d4641cdcd7f27e153db17c5bf064934faf5)
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 #ifndef lint
64 static const char copyright[] =
65 "@(#) Copyright (c) 1983, 1989, 1993\n\
66 	The Regents of the University of California.  All rights reserved.\n";
67 #endif /* not lint */
68 
69 #ifndef lint
70 #if 0
71 static char sccsid[] = "@(#)nfsstat.c	8.2 (Berkeley) 3/31/95";
72 #endif
73 static const char rcsid[] =
74   "$FreeBSD$";
75 #endif /* not lint */
76 
77 #include <sys/param.h>
78 #include <sys/module.h>
79 #include <sys/mount.h>
80 #include <sys/time.h>
81 #include <sys/sysctl.h>
82 #include <nfs/nfsproto.h>
83 #include <nfsclient/nfs.h>
84 #include <nfsserver/nfs.h>
85 #include <nfs/nfssvc.h>
86 
87 #include <fs/nfs/nfsport.h>
88 
89 #include <signal.h>
90 #include <fcntl.h>
91 #include <ctype.h>
92 #include <errno.h>
93 #include <limits.h>
94 #include <nlist.h>
95 #include <unistd.h>
96 #include <stdio.h>
97 #include <stdint.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #include <paths.h>
101 #include <devstat.h>
102 #include <err.h>
103 
104 static int widemode = 0;
105 static int zflag = 0;
106 static int printtitle = 1;
107 static struct nfsstatsv1 ext_nfsstats;
108 static int extra_output = 0;
109 
110 static void intpr(int, int);
111 static void printhdr(int, int, int);
112 static void usage(void);
113 static char *sperc1(int, int);
114 static char *sperc2(int, int);
115 static void exp_intpr(int, int);
116 static void exp41_intpr(int, int);
117 static void exp_sidewaysintpr(u_int, int, int, int);
118 static void compute_new_stats(struct nfsstatsv1 *cur_stats,
119     struct nfsstatsv1 *prev_stats, int curop, long double etime,
120     long double *mbsec, long double *kb_per_transfer,
121     long double *transfers_per_second, long double *ms_per_transfer,
122     uint64_t *queue_len, long double *busy_pct);
123 
124 #define DELTA(field)	(nfsstats.field - lastst.field)
125 
126 #define	STAT_TYPE_READ		0
127 #define	STAT_TYPE_WRITE		1
128 #define	STAT_TYPE_COMMIT	2
129 #define	NUM_STAT_TYPES		3
130 
131 struct stattypes {
132 	int stat_type;
133 	int nfs_type;
134 };
135 static struct stattypes statstruct[] = {
136 	{STAT_TYPE_READ, NFSV4OP_READ},
137 	{STAT_TYPE_WRITE, NFSV4OP_WRITE},
138 	{STAT_TYPE_COMMIT, NFSV4OP_COMMIT}
139 };
140 
141 #define	STAT_TYPE_TO_NFS(stat_type)	statstruct[stat_type].nfs_type
142 
143 int
144 main(int argc, char **argv)
145 {
146 	u_int interval;
147 	int clientOnly = -1;
148 	int serverOnly = -1;
149 	int newStats = 0;
150 	int ch;
151 	char *memf, *nlistf;
152 	int mntlen, i;
153 	char buf[1024];
154 	struct statfs *mntbuf;
155 	struct nfscl_dumpmntopts dumpmntopts;
156 
157 	interval = 0;
158 	memf = nlistf = NULL;
159 	while ((ch = getopt(argc, argv, "cdEesWM:mN:w:z")) != -1)
160 		switch(ch) {
161 		case 'M':
162 			memf = optarg;
163 			break;
164 		case 'm':
165 			/* Display mount options for NFS mount points. */
166 			mntlen = getmntinfo(&mntbuf, MNT_NOWAIT);
167 			for (i = 0; i < mntlen; i++) {
168 				if (strcmp(mntbuf->f_fstypename, "nfs") == 0) {
169 					dumpmntopts.ndmnt_fname =
170 					    mntbuf->f_mntonname;
171 					dumpmntopts.ndmnt_buf = buf;
172 					dumpmntopts.ndmnt_blen = sizeof(buf);
173 					if (nfssvc(NFSSVC_DUMPMNTOPTS,
174 					    &dumpmntopts) >= 0)
175 						printf("%s on %s\n%s\n",
176 						    mntbuf->f_mntfromname,
177 						    mntbuf->f_mntonname, buf);
178 					else if (errno == EPERM)
179 						errx(1, "Only priviledged users"
180 						    " can use the -m option");
181 				}
182 				mntbuf++;
183 			}
184 			exit(0);
185 		case 'N':
186 			nlistf = optarg;
187 			break;
188 		case 'W':
189 			widemode = 1;
190 			break;
191 		case 'w':
192 			interval = atoi(optarg);
193 			break;
194 		case 'c':
195 			clientOnly = 1;
196 			if (serverOnly < 0)
197 				serverOnly = 0;
198 			break;
199 		case 'd':
200 			newStats = 1;
201 			if (interval == 0)
202 				interval = 1;
203 			break;
204 		case 's':
205 			serverOnly = 1;
206 			if (clientOnly < 0)
207 				clientOnly = 0;
208 			break;
209 		case 'z':
210 			zflag = 1;
211 			break;
212 		case 'E':
213 			if (extra_output != 0)
214 				errx(1, "-e and -E are mutually exclusive");
215 			extra_output = 2;
216 			break;
217 		case 'e':
218 			if (extra_output != 0)
219 				errx(1, "-e and -E are mutually exclusive");
220 			extra_output = 1;
221 			break;
222 		case '?':
223 		default:
224 			usage();
225 		}
226 	argc -= optind;
227 	argv += optind;
228 
229 #define	BACKWARD_COMPATIBILITY
230 #ifdef	BACKWARD_COMPATIBILITY
231 	if (*argv) {
232 		interval = atoi(*argv);
233 		if (*++argv) {
234 			nlistf = *argv;
235 			if (*++argv)
236 				memf = *argv;
237 		}
238 	}
239 #endif
240 	if (modfind("nfscommon") < 0)
241 		errx(1, "NFS client/server not loaded");
242 
243 	if (interval) {
244 		exp_sidewaysintpr(interval, clientOnly, serverOnly,
245 		    newStats);
246 	} else {
247 		if (extra_output == 2)
248 			exp41_intpr(clientOnly, serverOnly);
249 		else if (extra_output == 1)
250 			exp_intpr(clientOnly, serverOnly);
251 		else
252 			intpr(clientOnly, serverOnly);
253 	}
254 	exit(0);
255 }
256 
257 /*
258  * Print a description of the nfs stats.
259  */
260 static void
261 intpr(int clientOnly, int serverOnly)
262 {
263 	int nfssvc_flag;
264 
265 	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
266 	if (zflag != 0) {
267 		if (clientOnly != 0)
268 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
269 		if (serverOnly != 0)
270 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
271 	}
272 	ext_nfsstats.vers = NFSSTATS_V1;
273 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
274 		err(1, "Can't get stats");
275 	if (clientOnly) {
276 		printf("Client Info:\n");
277 		printf("Rpc Counts:\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("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
282 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
283 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
284 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
285 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
286 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
287 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
288 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
289 			(uintmax_t)ext_nfsstats.rpccnt[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("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
294 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
295 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
296 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
297 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
298 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
299 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
300 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
301 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
302 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
303 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
304 		printf("%9ju %9ju %9ju %9ju %9ju\n",
305 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
306 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
307 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
308 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
309 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
310 		printf("Rpc Info:\n");
311 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
312 			"TimedOut", "Invalid", "X Replies", "Retries",
313 			"Requests");
314 		printf("%9ju %9ju %9ju %9ju %9ju\n",
315 			(uintmax_t)ext_nfsstats.rpctimeouts,
316 			(uintmax_t)ext_nfsstats.rpcinvalid,
317 			(uintmax_t)ext_nfsstats.rpcunexpected,
318 			(uintmax_t)ext_nfsstats.rpcretries,
319 			(uintmax_t)ext_nfsstats.rpcrequests);
320 		printf("Cache Info:\n");
321 		printf("%9.9s %9.9s %9.9s %9.9s",
322 			"Attr Hits", "Misses", "Lkup Hits", "Misses");
323 		printf(" %9.9s %9.9s %9.9s %9.9s\n",
324 			"BioR Hits", "Misses", "BioW Hits", "Misses");
325 		printf("%9ju %9ju %9ju %9ju",
326 			(uintmax_t)ext_nfsstats.attrcache_hits,
327 			(uintmax_t)ext_nfsstats.attrcache_misses,
328 			(uintmax_t)ext_nfsstats.lookupcache_hits,
329 			(uintmax_t)ext_nfsstats.lookupcache_misses);
330 		printf(" %9ju %9ju %9ju %9ju\n",
331 			(uintmax_t)(ext_nfsstats.biocache_reads -
332 			ext_nfsstats.read_bios),
333 			(uintmax_t)ext_nfsstats.read_bios,
334 			(uintmax_t)(ext_nfsstats.biocache_writes -
335 			ext_nfsstats.write_bios),
336 			(uintmax_t)ext_nfsstats.write_bios);
337 		printf("%9.9s %9.9s %9.9s %9.9s",
338 			"BioRLHits", "Misses", "BioD Hits", "Misses");
339 		printf(" %9.9s %9.9s %9.9s %9.9s\n", "DirE Hits", "Misses", "Accs Hits", "Misses");
340 		printf("%9ju %9ju %9ju %9ju",
341 			(uintmax_t)(ext_nfsstats.biocache_readlinks -
342 			ext_nfsstats.readlink_bios),
343 			(uintmax_t)ext_nfsstats.readlink_bios,
344 			(uintmax_t)(ext_nfsstats.biocache_readdirs -
345 			ext_nfsstats.readdir_bios),
346 			(uintmax_t)ext_nfsstats.readdir_bios);
347 		printf(" %9ju %9ju %9ju %9ju\n",
348 			(uintmax_t)ext_nfsstats.direofcache_hits,
349 			(uintmax_t)ext_nfsstats.direofcache_misses,
350 			(uintmax_t)ext_nfsstats.accesscache_hits,
351 			(uintmax_t)ext_nfsstats.accesscache_misses);
352 	}
353 	if (serverOnly) {
354 		printf("\nServer Info:\n");
355 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
356 			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
357 			"Write", "Create", "Remove");
358 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
359 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
360 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
361 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
362 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
363 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
364 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
365 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
366 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
367 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
368 			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
369 			"Readdir", "RdirPlus", "Access");
370 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
371 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
372 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
373 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
374 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
375 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
376 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
377 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
378 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
379 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
380 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
381 		printf("%9ju %9ju %9ju %9ju %9ju\n",
382 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
383 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
384 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
385 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
386 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
387 		printf("Server Ret-Failed\n");
388 		printf("%17ju\n", (uintmax_t)ext_nfsstats.srvrpc_errs);
389 		printf("Server Faults\n");
390 		printf("%13ju\n", (uintmax_t)ext_nfsstats.srv_errs);
391 		printf("Server Cache Stats:\n");
392 		printf("%9.9s %9.9s %9.9s %9.9s\n",
393 			"Inprog", "Idem", "Non-idem", "Misses");
394 		printf("%9ju %9ju %9ju %9ju\n",
395 			(uintmax_t)ext_nfsstats.srvcache_inproghits,
396 			(uintmax_t)ext_nfsstats.srvcache_idemdonehits,
397 			(uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
398 			(uintmax_t)ext_nfsstats.srvcache_misses);
399 		printf("Server Write Gathering:\n");
400 		printf("%9.9s %9.9s %9.9s\n",
401 			"WriteOps", "WriteRPC", "Opsaved");
402 		/*
403 		 * The new client doesn't do write gathering. It was
404 		 * only useful for NFSv2.
405 		 */
406 		printf("%9ju %9ju %9d\n",
407 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
408 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
409 	}
410 }
411 
412 static void
413 printhdr(int clientOnly, int serverOnly, int newStats)
414 {
415 
416 	if (newStats) {
417 		printf(" [%s Read %s]  [%s Write %s]  "
418 		    "%s[=========== Total ============]\n"
419 		    " KB/t   tps    MB/s%s  KB/t   tps    MB/s%s  "
420 		    "%sKB/t   tps    MB/s    ms  ql  %%b",
421 		    widemode ? "========" : "=====",
422 		    widemode ? "========" : "=====",
423 		    widemode ? "========" : "=====",
424 		    widemode ? "======="  : "====",
425 		    widemode ? "[Commit ]  " : "",
426 		    widemode ? "    ms" : "",
427 		    widemode ? "    ms" : "",
428 		    widemode ? "tps    ms  " : "");
429 	} else {
430 		printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
431 		    ((serverOnly && clientOnly) ? "        " : " "),
432 		    "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename",
433 		    "Access", "Rddir");
434 		if (widemode && clientOnly) {
435 			printf(" Attr Lkup BioR BioW Accs BioD");
436 		}
437 	}
438 	printf("\n");
439 	fflush(stdout);
440 }
441 
442 static void
443 usage(void)
444 {
445 	(void)fprintf(stderr,
446 	    "usage: nfsstat [-cdemszW] [-M core] [-N system] [-w wait]\n");
447 	exit(1);
448 }
449 
450 static char SPBuf[64][8];
451 static int SPIndex;
452 
453 static char *
454 sperc1(int hits, int misses)
455 {
456 	char *p = SPBuf[SPIndex];
457 
458 	if (hits + misses) {
459 		sprintf(p, "%3d%%",
460 		    (int)(char)((quad_t)hits * 100 / (hits + misses)));
461 	} else {
462 		sprintf(p, "   -");
463 	}
464 	SPIndex = (SPIndex + 1) & 63;
465 	return(p);
466 }
467 
468 static char *
469 sperc2(int ttl, int misses)
470 {
471 	char *p = SPBuf[SPIndex];
472 
473 	if (ttl) {
474 		sprintf(p, "%3d%%",
475 		    (int)(char)((quad_t)(ttl - misses) * 100 / ttl));
476 	} else {
477 		sprintf(p, "   -");
478 	}
479 	SPIndex = (SPIndex + 1) & 63;
480 	return(p);
481 }
482 
483 #define DELTA_T(field)					\
484 	devstat_compute_etime(&cur_stats->field,	\
485 	(prev_stats ? &prev_stats->field : NULL))
486 
487 /*
488  * XXX KDM mostly copied from ctlstat.  We should commonize the code (and
489  * the devstat code) somehow.
490  */
491 static void
492 compute_new_stats(struct nfsstatsv1 *cur_stats,
493 		  struct nfsstatsv1 *prev_stats, int curop,
494 		  long double etime, long double *mbsec,
495 		  long double *kb_per_transfer,
496 		  long double *transfers_per_second,
497 		  long double *ms_per_transfer, uint64_t *queue_len,
498 		  long double *busy_pct)
499 {
500 	uint64_t total_bytes = 0, total_operations = 0;
501 	struct bintime total_time_bt;
502 	struct timespec total_time_ts;
503 
504 	bzero(&total_time_bt, sizeof(total_time_bt));
505 	bzero(&total_time_ts, sizeof(total_time_ts));
506 
507 	total_bytes = cur_stats->srvbytes[curop];
508 	total_operations = cur_stats->srvops[curop];
509 	if (prev_stats != NULL) {
510 		total_bytes -= prev_stats->srvbytes[curop];
511 		total_operations -= prev_stats->srvops[curop];
512 	}
513 
514 	*mbsec = total_bytes;
515 	*mbsec /= 1024 * 1024;
516 	if (etime > 0.0) {
517 		*busy_pct = DELTA_T(busytime);
518 		if (*busy_pct < 0)
519 			*busy_pct = 0;
520 		*busy_pct /= etime;
521 		*busy_pct *= 100;
522 		if (*busy_pct < 0)
523 			*busy_pct = 0;
524 		*mbsec /= etime;
525 	} else {
526 		*busy_pct = 0;
527 		*mbsec = 0;
528 	}
529 	*kb_per_transfer = total_bytes;
530 	*kb_per_transfer /= 1024;
531 	if (total_operations > 0)
532 		*kb_per_transfer /= total_operations;
533 	else
534 		*kb_per_transfer = 0;
535 	if (etime > 0.0) {
536 		*transfers_per_second = total_operations;
537 		*transfers_per_second /= etime;
538 	} else {
539 		*transfers_per_second = 0.0;
540 	}
541 
542 	if (total_operations > 0) {
543 		*ms_per_transfer = DELTA_T(srvduration[curop]);
544 		*ms_per_transfer /= total_operations;
545 		*ms_per_transfer *= 1000;
546 	} else
547 		*ms_per_transfer = 0.0;
548 
549 	*queue_len = cur_stats->srvstartcnt - cur_stats->srvdonecnt;
550 }
551 
552 /*
553  * Print a description of the nfs stats for the experimental client/server.
554  */
555 static void
556 exp_intpr(int clientOnly, int serverOnly)
557 {
558 	int nfssvc_flag;
559 
560 	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
561 	if (zflag != 0) {
562 		if (clientOnly != 0)
563 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
564 		if (serverOnly != 0)
565 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
566 	}
567 	ext_nfsstats.vers = NFSSTATS_V1;
568 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
569 		err(1, "Can't get stats");
570 	if (clientOnly != 0) {
571 		if (printtitle) {
572 			printf("Client Info:\n");
573 			printf("Rpc Counts:\n");
574 			printf(
575 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
576 			    , "Getattr", "Setattr", "Lookup", "Readlink",
577 			    "Read", "Write", "Create", "Remove");
578 		}
579 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
580 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
581 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
582 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
583 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
584 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
585 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
586 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
587 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
588 		if (printtitle)
589 			printf(
590 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
591 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
592 			    "Readdir", "RdirPlus", "Access");
593 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
594 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
595 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
596 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
597 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
598 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
599 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
600 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
601 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
602 		if (printtitle)
603 			printf(
604 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
605 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
606 			    "Commit", "SetClId", "SetClIdCf", "Lock");
607 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
608 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
609 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
610 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
611 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
612 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
613 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
614 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
615 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
616 		if (printtitle)
617 			printf("%9.9s %9.9s %9.9s %9.9s\n",
618 			    "LockT", "LockU", "Open", "OpenCfr");
619 		printf("%9ju %9ju %9ju %9ju\n",
620 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
621 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
622 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
623 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);
624 		if (printtitle)
625 			printf(
626 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
627 			    , "OpenOwner", "Opens", "LockOwner",
628 			    "Locks", "Delegs", "LocalOwn",
629 			    "LocalOpen", "LocalLOwn");
630 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
631 		    (uintmax_t)ext_nfsstats.clopenowners,
632 		    (uintmax_t)ext_nfsstats.clopens,
633 		    (uintmax_t)ext_nfsstats.cllockowners,
634 		    (uintmax_t)ext_nfsstats.cllocks,
635 		    (uintmax_t)ext_nfsstats.cldelegates,
636 		    (uintmax_t)ext_nfsstats.cllocalopenowners,
637 		    (uintmax_t)ext_nfsstats.cllocalopens,
638 		    (uintmax_t)ext_nfsstats.cllocallockowners);
639 		if (printtitle)
640 			printf("%9.9s\n", "LocalLock");
641 		printf("%9ju\n", (uintmax_t)ext_nfsstats.cllocallocks);
642 		if (printtitle) {
643 			printf("Rpc Info:\n");
644 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
645 			    "TimedOut", "Invalid", "X Replies", "Retries",
646 			    "Requests");
647 		}
648 		printf("%9ju %9ju %9ju %9ju %9ju\n",
649 		    (uintmax_t)ext_nfsstats.rpctimeouts,
650 		    (uintmax_t)ext_nfsstats.rpcinvalid,
651 		    (uintmax_t)ext_nfsstats.rpcunexpected,
652 		    (uintmax_t)ext_nfsstats.rpcretries,
653 		    (uintmax_t)ext_nfsstats.rpcrequests);
654 		if (printtitle) {
655 			printf("Cache Info:\n");
656 			printf("%9.9s %9.9s %9.9s %9.9s",
657 			    "Attr Hits", "Misses", "Lkup Hits", "Misses");
658 			printf(" %9.9s %9.9s %9.9s %9.9s\n",
659 			    "BioR Hits", "Misses", "BioW Hits", "Misses");
660 		}
661 		printf("%9ju %9ju %9ju %9ju",
662 		    (uintmax_t)ext_nfsstats.attrcache_hits,
663 		    (uintmax_t)ext_nfsstats.attrcache_misses,
664 		    (uintmax_t)ext_nfsstats.lookupcache_hits,
665 		    (uintmax_t)ext_nfsstats.lookupcache_misses);
666 		printf(" %9ju %9ju %9ju %9ju\n",
667 		    (uintmax_t)(ext_nfsstats.biocache_reads -
668 		    ext_nfsstats.read_bios),
669 		    (uintmax_t)ext_nfsstats.read_bios,
670 		    (uintmax_t)(ext_nfsstats.biocache_writes -
671 		    ext_nfsstats.write_bios),
672 		    (uintmax_t)ext_nfsstats.write_bios);
673 		if (printtitle) {
674 			printf("%9.9s %9.9s %9.9s %9.9s",
675 			    "BioRLHits", "Misses", "BioD Hits", "Misses");
676 			printf(" %9.9s %9.9s\n", "DirE Hits", "Misses");
677 		}
678 		printf("%9ju %9ju %9ju %9ju",
679 		    (uintmax_t)(ext_nfsstats.biocache_readlinks -
680 		    ext_nfsstats.readlink_bios),
681 		    (uintmax_t)ext_nfsstats.readlink_bios,
682 		    (uintmax_t)(ext_nfsstats.biocache_readdirs -
683 		    ext_nfsstats.readdir_bios),
684 		    (uintmax_t)ext_nfsstats.readdir_bios);
685 		printf(" %9ju %9ju\n",
686 		    (uintmax_t)ext_nfsstats.direofcache_hits,
687 		    (uintmax_t)ext_nfsstats.direofcache_misses);
688 	}
689 	if (serverOnly != 0) {
690 		if (printtitle) {
691 			printf("\nServer Info:\n");
692 			printf(
693 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
694 			    , "Getattr", "Setattr", "Lookup", "Readlink",
695 			    "Read", "Write", "Create", "Remove");
696 		}
697 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
698 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
699 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
700 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
701 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
702 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
703 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
704 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
705 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
706 		if (printtitle)
707 			printf(
708 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
709 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
710 			    "Readdir", "RdirPlus", "Access");
711 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
712 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
713 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
714 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
715 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
716 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
717 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
718 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
719 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
720 		if (printtitle)
721 			printf(
722 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
723 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
724 			    "Commit", "LookupP", "SetClId", "SetClIdCf");
725 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
726 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
727 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
728 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
729 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
730 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
731 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
732 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
733 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
734 		if (printtitle)
735 			printf(
736 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
737 			    , "Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
738 			    "DelePurge", "DeleRet", "GetFH", "Lock");
739 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
740 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
741 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
742 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
743 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
744 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
745 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN],
746 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
747 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK]);
748 		if (printtitle)
749 			printf(
750 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
751 			    , "LockT", "LockU", "Close", "Verify", "NVerify",
752 			    "PutFH", "PutPubFH", "PutRootFH");
753 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
754 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
755 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
756 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
757 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY],
758 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
759 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
760 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
761 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH]);
762 		if (printtitle)
763 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
764 			    "Renew", "RestoreFH", "SaveFH", "Secinfo",
765 			    "RelLckOwn", "V4Create");
766 		printf("%9ju %9ju %9ju %9ju %9ju %9ju\n",
767 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
768 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH],
769 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
770 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
771 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
772 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
773 		if (printtitle) {
774 			printf("Server:\n");
775 			printf("%9.9s %9.9s %9.9s\n",
776 			    "Retfailed", "Faults", "Clients");
777 		}
778 		printf("%9ju %9ju %9ju\n",
779 		    (uintmax_t)ext_nfsstats.srv_errs,
780 		    (uintmax_t)ext_nfsstats.srvrpc_errs,
781 		    (uintmax_t)ext_nfsstats.srvclients);
782 		if (printtitle)
783 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s \n",
784 			    "OpenOwner", "Opens", "LockOwner",
785 			    "Locks", "Delegs");
786 		printf("%9ju %9ju %9ju %9ju %9ju \n",
787 		    (uintmax_t)ext_nfsstats.srvopenowners,
788 		    (uintmax_t)ext_nfsstats.srvopens,
789 		    (uintmax_t)ext_nfsstats.srvlockowners,
790 		    (uintmax_t)ext_nfsstats.srvlocks,
791 		    (uintmax_t)ext_nfsstats.srvdelegates);
792 		if (printtitle) {
793 			printf("Server Cache Stats:\n");
794 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
795 			    "Inprog", "Idem", "Non-idem", "Misses",
796 			    "CacheSize", "TCPPeak");
797 		}
798 		printf("%9ju %9ju %9ju %9ju %9ju %9ju\n",
799 		    (uintmax_t)ext_nfsstats.srvcache_inproghits,
800 		    (uintmax_t)ext_nfsstats.srvcache_idemdonehits,
801 		    (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
802 		    (uintmax_t)ext_nfsstats.srvcache_misses,
803 		    (uintmax_t)ext_nfsstats.srvcache_size,
804 		    (uintmax_t)ext_nfsstats.srvcache_tcppeak);
805 	}
806 }
807 
808 /*
809  * Print a description of the nfs stats for the client/server,
810  * including NFSv4.1.
811  */
812 static void
813 exp41_intpr(int clientOnly, int serverOnly)
814 {
815 	int nfssvc_flag;
816 
817 	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
818 	if (zflag != 0) {
819 		if (clientOnly != 0)
820 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
821 		if (serverOnly != 0)
822 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
823 	}
824 	ext_nfsstats.vers = NFSSTATS_V1;
825 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
826 		err(1, "Can't get stats");
827 	if (clientOnly != 0) {
828 		if (printtitle) {
829 			printf("Client Info:\n");
830 			printf("RPC Counts:\n");
831 			printf(
832 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
833 			    "Getattr", "Setattr", "Lookup", "Readlink", "Read",
834 			    "Write");
835 		}
836 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
837 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
838 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
839 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
840 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
841 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
842 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE]);
843 		if (printtitle)
844 			printf(
845 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
846 			    "Create", "Remove", "Rename", "Link", "Symlink",
847 			    "Mkdir");
848 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
849 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
850 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE],
851 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
852 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
853 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
854 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR]);
855 		if (printtitle)
856 			printf(
857 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
858 			    "Rmdir", "Readdir", "RdirPlus", "Access", "Mknod",
859 			    "Fsstat");
860 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
861 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
862 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
863 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
864 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS],
865 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
866 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT]);
867 		if (printtitle)
868 			printf(
869 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
870 			    "Fsinfo", "PathConf", "Commit", "SetClId",
871 			    "SetClIdCf", "Lock");
872 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
873 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
874 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
875 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
876 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
877 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
878 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
879 		if (printtitle)
880 			printf(
881 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
882 			    "LockT", "LockU", "Open", "OpenCfr", "OpenDownGr",
883 			    "Close");
884 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
885 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
886 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
887 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
888 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM],
889 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENDOWNGRADE],
890 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CLOSE]);
891 		if (printtitle)
892 			printf(
893 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
894 			    "RelLckOwn", "FreeStateID", "PutRootFH", "DelegRet",
895 			    "GetACL", "SetACL");
896 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
897 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RELEASELCKOWN],
898 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FREESTATEID],
899 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PUTROOTFH],
900 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DELEGRETURN],
901 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETACL],
902 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETACL]);
903 		if (printtitle)
904 			printf(
905 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
906 			    "ExchangeID", "CreateSess", "DestroySess",
907 			    "DestroyClId", "LayoutGet", "GetDevInfo");
908 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
909 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_EXCHANGEID],
910 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATESESSION],
911 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYSESSION],
912 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYCLIENT],
913 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTGET],
914 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETDEVICEINFO]);
915 		if (printtitle)
916 			printf(
917 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
918 			    "LayoutCommit", "LayoutReturn", "ReclaimCompl",
919 			    "ReadDataS", "WriteDataS", "CommitDataS");
920 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
921 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTCOMMIT],
922 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTRETURN],
923 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RECLAIMCOMPL],
924 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDS],
925 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITEDS],
926 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMITDS]);
927 		if (printtitle)
928 			printf(
929 			    "%12.12s %12.12s\n",
930 			    "OpenLayout", "CreateLayout");
931 		printf("%12ju %12ju\n",
932 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENLAYGET],
933 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATELAYGET]);
934 		if (printtitle)
935 			printf(
936 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
937 			    "OpenOwner", "Opens", "LockOwner", "Locks",
938 			    "Delegs", "LocalOwn");
939 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
940 		    (uintmax_t)ext_nfsstats.clopenowners,
941 		    (uintmax_t)ext_nfsstats.clopens,
942 		    (uintmax_t)ext_nfsstats.cllockowners,
943 		    (uintmax_t)ext_nfsstats.cllocks,
944 		    (uintmax_t)ext_nfsstats.cldelegates,
945 		    (uintmax_t)ext_nfsstats.cllocalopenowners);
946 		if (printtitle)
947 			printf("%12.12s %12.12s %12.12s\n",
948 			    "LocalOpen", "LocalLOwn", "LocalLock");
949 		printf("%12ju %12ju %12ju\n",
950 		    (uintmax_t)ext_nfsstats.cllocalopens,
951 		    (uintmax_t)ext_nfsstats.cllocallockowners,
952 		    (uintmax_t)ext_nfsstats.cllocallocks);
953 		if (printtitle) {
954 			printf("Rpc Info:\n");
955 			printf("%12.12s %12.12s %12.12s %12.12s %12.12s\n",
956 			    "TimedOut", "Invalid", "X Replies", "Retries",
957 			    "Requests");
958 		}
959 		printf("%12ju %12ju %12ju %12ju %12ju\n",
960 		    (uintmax_t)ext_nfsstats.rpctimeouts,
961 		    (uintmax_t)ext_nfsstats.rpcinvalid,
962 		    (uintmax_t)ext_nfsstats.rpcunexpected,
963 		    (uintmax_t)ext_nfsstats.rpcretries,
964 		    (uintmax_t)ext_nfsstats.rpcrequests);
965 		if (printtitle) {
966 			printf("Cache Info:\n");
967 			printf("%12.12s %12.12s %12.12s %12.12s\n",
968 			    "Attr Hits", "Misses", "Lkup Hits", "Misses");
969 		}
970 		printf("%12ju %12ju %12ju %12ju\n",
971 		    (uintmax_t)ext_nfsstats.attrcache_hits,
972 		    (uintmax_t)ext_nfsstats.attrcache_misses,
973 		    (uintmax_t)ext_nfsstats.lookupcache_hits,
974 		    (uintmax_t)ext_nfsstats.lookupcache_misses);
975 		if (printtitle)
976 			printf("%12.12s %12.12s %12.12s %12.12s\n",
977 			    "BioR Hits", "Misses", "BioW Hits", "Misses");
978 		printf("%12ju %12ju %12ju %12ju\n",
979 		    (uintmax_t)(ext_nfsstats.biocache_reads -
980 		    ext_nfsstats.read_bios),
981 		    (uintmax_t)ext_nfsstats.read_bios,
982 		    (uintmax_t)(ext_nfsstats.biocache_writes -
983 		    ext_nfsstats.write_bios),
984 		    (uintmax_t)ext_nfsstats.write_bios);
985 		if (printtitle)
986 			printf("%12.12s %12.12s %12.12s %12.12s\n",
987 			    "BioRLHits", "Misses", "BioD Hits", "Misses");
988 		printf("%12ju %12ju %12ju %12ju\n",
989 		    (uintmax_t)(ext_nfsstats.biocache_readlinks -
990 		    ext_nfsstats.readlink_bios),
991 		    (uintmax_t)ext_nfsstats.readlink_bios,
992 		    (uintmax_t)(ext_nfsstats.biocache_readdirs -
993 		    ext_nfsstats.readdir_bios),
994 		    (uintmax_t)ext_nfsstats.readdir_bios);
995 		if (printtitle)
996 			printf("%12.12s %12.12s\n", "DirE Hits", "Misses");
997 		printf("%12ju %12ju\n",
998 		    (uintmax_t)ext_nfsstats.direofcache_hits,
999 		    (uintmax_t)ext_nfsstats.direofcache_misses);
1000 	}
1001 	if (serverOnly != 0) {
1002 		if (printtitle) {
1003 			printf("\nServer Info:\n");
1004 			printf(
1005 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1006 			    "Getattr", "Setattr", "Lookup", "Readlink",
1007 			    "Read", "Write");
1008 		}
1009 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1010 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
1011 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
1012 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
1013 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
1014 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
1015 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE]);
1016 		if (printtitle)
1017 			printf(
1018 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1019 			    "Create", "Remove", "Rename", "Link", "Symlink",
1020 			    "Mkdir");
1021 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1022 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
1023 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE],
1024 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
1025 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
1026 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
1027 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR]);
1028 		if (printtitle)
1029 			printf(
1030 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1031 			    "Rmdir", "Readdir", "RdirPlus", "Access", "Mknod",
1032 			    "Fsstat");
1033 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1034 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
1035 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
1036 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
1037 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS],
1038 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
1039 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT]);
1040 		if (printtitle)
1041 			printf(
1042 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1043 			    "Fsinfo", "PathConf", "Commit", "LookupP",
1044 			    "SetClId", "SetClIdCf");
1045 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1046 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
1047 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
1048 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
1049 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
1050 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
1051 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
1052 		if (printtitle)
1053 			printf(
1054 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1055 			    "Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
1056 			    "DelePurge", "DeleRet");
1057 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1058 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
1059 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
1060 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
1061 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
1062 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
1063 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN]);
1064 		if (printtitle)
1065 			printf(
1066 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1067 			    "GetFH", "Lock", "LockT", "LockU", "Close",
1068 			    "Verify");
1069 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1070 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
1071 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK],
1072 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
1073 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
1074 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
1075 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY]);
1076 		if (printtitle)
1077 			printf(
1078 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1079 			    "NVerify", "PutFH", "PutPubFH", "PutRootFH",
1080 			    "Renew", "RestoreFH");
1081 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1082 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
1083 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
1084 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
1085 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH],
1086 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
1087 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH]);
1088 		if (printtitle)
1089 			printf(
1090 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1091 			    "SaveFH", "Secinfo", "RelLckOwn", "V4Create",
1092 			    "BackChannelCtrl", "BindConnToSess");
1093 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1094 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
1095 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
1096 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
1097 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
1098 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BACKCHANNELCTL],
1099 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BINDCONNTOSESS]);
1100 		if (printtitle)
1101 			printf(
1102 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1103 			    "ExchangeID", "CreateSess", "DestroySess",
1104 			    "FreeStateID", "GetDirDeleg", "GetDevInfo");
1105 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1106 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_EXCHANGEID],
1107 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATESESSION],
1108 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYSESSION],
1109 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FREESTATEID],
1110 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDIRDELEG],
1111 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVINFO]);
1112 		if (printtitle)
1113 			printf(
1114 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1115 			    "GetDevList", "LayoutCommit", "LayoutGet",
1116 			    "LayoutReturn", "SecInfNoName", "Sequence");
1117 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1118 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVLIST],
1119 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTCOMMIT],
1120 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTGET],
1121 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTRETURN],
1122 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFONONAME],
1123 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEQUENCE]);
1124 		if (printtitle)
1125 			printf(
1126 			    "%12.12s %12.12s %12.12s %12.12s %12.12s\n",
1127 			    "SetSSV", "TestStateID", "WantDeleg",
1128 			    "DestroyClID", "ReclaimCompl");
1129 		printf("%12ju %12ju %12ju %12ju %12ju\n",
1130 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETSSV],
1131 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_TESTSTATEID],
1132 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WANTDELEG],
1133 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYCLIENTID],
1134 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RECLAIMCOMPL]);
1135 		if (printtitle) {
1136 			printf("Server:\n");
1137 			printf("%12.12s %12.12s %12.12s\n",
1138 			    "Retfailed", "Faults", "Clients");
1139 		}
1140 		printf("%12ju %12ju %12ju\n",
1141 		    (uintmax_t)ext_nfsstats.srv_errs,
1142 		    (uintmax_t)ext_nfsstats.srvrpc_errs,
1143 		    (uintmax_t)ext_nfsstats.srvclients);
1144 		if (printtitle)
1145 			printf("%12.12s %12.12s %12.12s %12.12s %12.12s\n",
1146 			    "OpenOwner", "Opens", "LockOwner",
1147 			    "Locks", "Delegs");
1148 		printf("%12ju %12ju %12ju %12ju %12ju\n",
1149 		    (uintmax_t)ext_nfsstats.srvopenowners,
1150 		    (uintmax_t)ext_nfsstats.srvopens,
1151 		    (uintmax_t)ext_nfsstats.srvlockowners,
1152 		    (uintmax_t)ext_nfsstats.srvlocks,
1153 		    (uintmax_t)ext_nfsstats.srvdelegates);
1154 		if (printtitle) {
1155 			printf("Server Cache Stats:\n");
1156 			printf(
1157 			    "%12.12s %12.12s %12.12s %12.12s %12.12s %12.12s\n",
1158 			    "Inprog", "Idem", "Non-idem", "Misses",
1159 			    "CacheSize", "TCPPeak");
1160 		}
1161 		printf("%12ju %12ju %12ju %12ju %12ju %12ju\n",
1162 		    (uintmax_t)ext_nfsstats.srvcache_inproghits,
1163 		    (uintmax_t)ext_nfsstats.srvcache_idemdonehits,
1164 		    (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
1165 		    (uintmax_t)ext_nfsstats.srvcache_misses,
1166 		    (uintmax_t)ext_nfsstats.srvcache_size,
1167 		    (uintmax_t)ext_nfsstats.srvcache_tcppeak);
1168 	}
1169 }
1170 
1171 static void
1172 compute_totals(struct nfsstatsv1 *total_stats, struct nfsstatsv1 *cur_stats)
1173 {
1174 	int i;
1175 
1176 	bzero(total_stats, sizeof(*total_stats));
1177 	for (i = 0; i < (NFSV42_NOPS + NFSV4OP_FAKENOPS); i++) {
1178 		total_stats->srvbytes[0] += cur_stats->srvbytes[i];
1179 		total_stats->srvops[0] += cur_stats->srvops[i];
1180 		bintime_add(&total_stats->srvduration[0],
1181 			    &cur_stats->srvduration[i]);
1182 		total_stats->srvrpccnt[i] = cur_stats->srvrpccnt[i];
1183 	}
1184 	total_stats->srvstartcnt = cur_stats->srvstartcnt;
1185 	total_stats->srvdonecnt = cur_stats->srvdonecnt;
1186 	total_stats->busytime = cur_stats->busytime;
1187 
1188 }
1189 
1190 /*
1191  * Print a running summary of nfs statistics for the experimental client and/or
1192  * server.
1193  * Repeat display every interval seconds, showing statistics
1194  * collected over that interval.  Assumes that interval is non-zero.
1195  * First line printed at top of screen is always cumulative.
1196  */
1197 static void
1198 exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly,
1199     int newStats)
1200 {
1201 	struct nfsstatsv1 nfsstats, lastst, *ext_nfsstatsp;
1202 	struct nfsstatsv1 curtotal, lasttotal;
1203 	struct timespec ts, lastts;
1204 	int hdrcnt = 1;
1205 
1206 	ext_nfsstatsp = &lastst;
1207 	ext_nfsstatsp->vers = NFSSTATS_V1;
1208 	if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) < 0)
1209 		err(1, "Can't get stats");
1210 	clock_gettime(CLOCK_MONOTONIC, &lastts);
1211 	compute_totals(&lasttotal, ext_nfsstatsp);
1212 	sleep(interval);
1213 
1214 	for (;;) {
1215 		ext_nfsstatsp = &nfsstats;
1216 		ext_nfsstatsp->vers = NFSSTATS_V1;
1217 		if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp)
1218 		    < 0)
1219 			err(1, "Can't get stats");
1220 		clock_gettime(CLOCK_MONOTONIC, &ts);
1221 
1222 		if (--hdrcnt == 0) {
1223 			printhdr(clientOnly, serverOnly, newStats);
1224 			if (newStats)
1225 				hdrcnt = 20;
1226 			else if (clientOnly && serverOnly)
1227 				hdrcnt = 10;
1228 			else
1229 				hdrcnt = 20;
1230 		}
1231 		if (clientOnly && newStats == 0) {
1232 		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
1233 			((clientOnly && serverOnly) ? "Client:" : ""),
1234 			(uintmax_t)DELTA(rpccnt[NFSPROC_GETATTR]),
1235 			(uintmax_t)DELTA(rpccnt[NFSPROC_LOOKUP]),
1236 			(uintmax_t)DELTA(rpccnt[NFSPROC_READLINK]),
1237 			(uintmax_t)DELTA(rpccnt[NFSPROC_READ]),
1238 			(uintmax_t)DELTA(rpccnt[NFSPROC_WRITE]),
1239 			(uintmax_t)DELTA(rpccnt[NFSPROC_RENAME]),
1240 			(uintmax_t)DELTA(rpccnt[NFSPROC_ACCESS]),
1241 			(uintmax_t)(DELTA(rpccnt[NFSPROC_READDIR]) +
1242 			DELTA(rpccnt[NFSPROC_READDIRPLUS]))
1243 		    );
1244 		    if (widemode) {
1245 			    printf(" %s %s %s %s %s %s",
1246 				sperc1(DELTA(attrcache_hits),
1247 				    DELTA(attrcache_misses)),
1248 				sperc1(DELTA(lookupcache_hits),
1249 				    DELTA(lookupcache_misses)),
1250 				sperc2(DELTA(biocache_reads),
1251 				    DELTA(read_bios)),
1252 				sperc2(DELTA(biocache_writes),
1253 				    DELTA(write_bios)),
1254 				sperc1(DELTA(accesscache_hits),
1255 				    DELTA(accesscache_misses)),
1256 				sperc2(DELTA(biocache_readdirs),
1257 				    DELTA(readdir_bios))
1258 			    );
1259 		    }
1260 		    printf("\n");
1261 		}
1262 
1263 		if (serverOnly && newStats) {
1264 			long double cur_secs, last_secs, etime;
1265 			long double mbsec;
1266 			long double kb_per_transfer;
1267 			long double transfers_per_second;
1268 			long double ms_per_transfer;
1269 			uint64_t queue_len;
1270 			long double busy_pct;
1271 			int i;
1272 
1273 			cur_secs = ts.tv_sec +
1274 			    ((long double)ts.tv_nsec / 1000000000);
1275 			last_secs = lastts.tv_sec +
1276 			    ((long double)lastts.tv_nsec / 1000000000);
1277 			etime = cur_secs - last_secs;
1278 
1279 			compute_totals(&curtotal, &nfsstats);
1280 
1281 			for (i = 0; i < NUM_STAT_TYPES; i++) {
1282 				compute_new_stats(&nfsstats, &lastst,
1283 				    STAT_TYPE_TO_NFS(i), etime, &mbsec,
1284 				    &kb_per_transfer,
1285 				    &transfers_per_second,
1286 				    &ms_per_transfer, &queue_len,
1287 				    &busy_pct);
1288 
1289 				if (i == STAT_TYPE_COMMIT) {
1290 					if (widemode == 0)
1291 						continue;
1292 
1293 					printf("%2.0Lf %7.2Lf ",
1294 					    transfers_per_second,
1295 					    ms_per_transfer);
1296 				} else {
1297 					printf("%5.2Lf %5.0Lf %7.2Lf ",
1298 					    kb_per_transfer,
1299 					    transfers_per_second, mbsec);
1300 					if (widemode)
1301 						printf("%5.2Lf ",
1302 						    ms_per_transfer);
1303 				}
1304 			}
1305 
1306 			compute_new_stats(&curtotal, &lasttotal, 0, etime,
1307 			    &mbsec, &kb_per_transfer, &transfers_per_second,
1308 			    &ms_per_transfer, &queue_len, &busy_pct);
1309 
1310 			printf("%5.2Lf %5.0Lf %7.2Lf %5.2Lf %3ju %3.0Lf\n",
1311 			    kb_per_transfer, transfers_per_second, mbsec,
1312 			    ms_per_transfer, queue_len, busy_pct);
1313 		} else if (serverOnly) {
1314 		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
1315 			((clientOnly && serverOnly) ? "Server:" : ""),
1316 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_GETATTR]),
1317 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_LOOKUP]),
1318 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READLINK]),
1319 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READ]),
1320 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_WRITE]),
1321 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_RENAME]),
1322 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_ACCESS]),
1323 			(uintmax_t)(DELTA(srvrpccnt[NFSV4OP_READDIR]) +
1324 			DELTA(srvrpccnt[NFSV4OP_READDIRPLUS])));
1325 		    printf("\n");
1326 		}
1327 		bcopy(&nfsstats, &lastst, sizeof(lastst));
1328 		bcopy(&curtotal, &lasttotal, sizeof(lasttotal));
1329 		lastts = ts;
1330 		fflush(stdout);
1331 		sleep(interval);
1332 	}
1333 	/*NOTREACHED*/
1334 }
1335