xref: /freebsd/usr.bin/nfsstat/nfsstat.c (revision 97549c34ecaf74580941fdc9c5bd1050e4b1f6ce)
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  * 4. 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 exp_sidewaysintpr(u_int, int, int, int);
117 static void compute_new_stats(struct nfsstatsv1 *cur_stats,
118     struct nfsstatsv1 *prev_stats, int curop, long double etime,
119     long double *mbsec, long double *kb_per_transfer,
120     long double *transfers_per_second, long double *ms_per_transfer,
121     uint64_t *queue_len, long double *busy_pct);
122 
123 #define DELTA(field)	(nfsstats.field - lastst.field)
124 
125 #define	STAT_TYPE_READ		0
126 #define	STAT_TYPE_WRITE		1
127 #define	STAT_TYPE_COMMIT	2
128 #define	NUM_STAT_TYPES		3
129 
130 struct stattypes {
131 	int stat_type;
132 	int nfs_type;
133 };
134 static struct stattypes statstruct[] = {
135 	{STAT_TYPE_READ, NFSV4OP_READ},
136 	{STAT_TYPE_WRITE, NFSV4OP_WRITE},
137 	{STAT_TYPE_COMMIT, NFSV4OP_COMMIT}
138 };
139 
140 #define	STAT_TYPE_TO_NFS(stat_type)	statstruct[stat_type].nfs_type
141 
142 int
143 main(int argc, char **argv)
144 {
145 	u_int interval;
146 	int clientOnly = -1;
147 	int serverOnly = -1;
148 	int newStats = 0;
149 	int ch;
150 	char *memf, *nlistf;
151 	int mntlen, i;
152 	char buf[1024];
153 	struct statfs *mntbuf;
154 	struct nfscl_dumpmntopts dumpmntopts;
155 
156 	interval = 0;
157 	memf = nlistf = NULL;
158 	while ((ch = getopt(argc, argv, "cdesWM:mN:w:z")) != -1)
159 		switch(ch) {
160 		case 'M':
161 			memf = optarg;
162 			break;
163 		case 'm':
164 			/* Display mount options for NFS mount points. */
165 			mntlen = getmntinfo(&mntbuf, MNT_NOWAIT);
166 			for (i = 0; i < mntlen; i++) {
167 				if (strcmp(mntbuf->f_fstypename, "nfs") == 0) {
168 					dumpmntopts.ndmnt_fname =
169 					    mntbuf->f_mntonname;
170 					dumpmntopts.ndmnt_buf = buf;
171 					dumpmntopts.ndmnt_blen = sizeof(buf);
172 					if (nfssvc(NFSSVC_DUMPMNTOPTS,
173 					    &dumpmntopts) >= 0)
174 						printf("%s on %s\n%s\n",
175 						    mntbuf->f_mntfromname,
176 						    mntbuf->f_mntonname, buf);
177 					else if (errno == EPERM)
178 						errx(1, "Only priviledged users"
179 						    " can use the -m option");
180 				}
181 				mntbuf++;
182 			}
183 			exit(0);
184 		case 'N':
185 			nlistf = optarg;
186 			break;
187 		case 'W':
188 			widemode = 1;
189 			break;
190 		case 'w':
191 			interval = atoi(optarg);
192 			break;
193 		case 'c':
194 			clientOnly = 1;
195 			if (serverOnly < 0)
196 				serverOnly = 0;
197 			break;
198 		case 'd':
199 			newStats = 1;
200 			if (interval == 0)
201 				interval = 1;
202 			break;
203 		case 's':
204 			serverOnly = 1;
205 			if (clientOnly < 0)
206 				clientOnly = 0;
207 			break;
208 		case 'z':
209 			zflag = 1;
210 			break;
211 		case 'e':
212 			extra_output = 1;
213 			break;
214 		case '?':
215 		default:
216 			usage();
217 		}
218 	argc -= optind;
219 	argv += optind;
220 
221 #define	BACKWARD_COMPATIBILITY
222 #ifdef	BACKWARD_COMPATIBILITY
223 	if (*argv) {
224 		interval = atoi(*argv);
225 		if (*++argv) {
226 			nlistf = *argv;
227 			if (*++argv)
228 				memf = *argv;
229 		}
230 	}
231 #endif
232 	if (modfind("nfscommon") < 0)
233 		errx(1, "NFS client/server not loaded");
234 
235 	if (interval) {
236 		exp_sidewaysintpr(interval, clientOnly, serverOnly,
237 		    newStats);
238 	} else {
239 		if (extra_output != 0)
240 			exp_intpr(clientOnly, serverOnly);
241 		else
242 			intpr(clientOnly, serverOnly);
243 	}
244 	exit(0);
245 }
246 
247 /*
248  * Print a description of the nfs stats.
249  */
250 static void
251 intpr(int clientOnly, int serverOnly)
252 {
253 	int nfssvc_flag;
254 
255 	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
256 	if (zflag != 0) {
257 		if (clientOnly != 0)
258 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
259 		if (serverOnly != 0)
260 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
261 	}
262 	ext_nfsstats.vers = NFSSTATS_V1;
263 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
264 		err(1, "Can't get stats");
265 	if (clientOnly) {
266 		printf("Client Info:\n");
267 		printf("Rpc Counts:\n");
268 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
269 			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
270 			"Write", "Create", "Remove");
271 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
272 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
273 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
274 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
275 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
276 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
277 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
278 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
279 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
280 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
281 			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
282 			"Readdir", "RdirPlus", "Access");
283 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
284 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
285 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
286 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
287 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
288 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
289 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
290 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
291 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
292 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
293 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
294 		printf("%9ju %9ju %9ju %9ju %9ju\n",
295 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
296 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
297 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
298 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
299 			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
300 		printf("Rpc Info:\n");
301 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
302 			"TimedOut", "Invalid", "X Replies", "Retries",
303 			"Requests");
304 		printf("%9ju %9ju %9ju %9ju %9ju\n",
305 			(uintmax_t)ext_nfsstats.rpctimeouts,
306 			(uintmax_t)ext_nfsstats.rpcinvalid,
307 			(uintmax_t)ext_nfsstats.rpcunexpected,
308 			(uintmax_t)ext_nfsstats.rpcretries,
309 			(uintmax_t)ext_nfsstats.rpcrequests);
310 		printf("Cache Info:\n");
311 		printf("%9.9s %9.9s %9.9s %9.9s",
312 			"Attr Hits", "Misses", "Lkup Hits", "Misses");
313 		printf(" %9.9s %9.9s %9.9s %9.9s\n",
314 			"BioR Hits", "Misses", "BioW Hits", "Misses");
315 		printf("%9ju %9ju %9ju %9ju",
316 			(uintmax_t)ext_nfsstats.attrcache_hits,
317 			(uintmax_t)ext_nfsstats.attrcache_misses,
318 			(uintmax_t)ext_nfsstats.lookupcache_hits,
319 			(uintmax_t)ext_nfsstats.lookupcache_misses);
320 		printf(" %9ju %9ju %9ju %9ju\n",
321 			(uintmax_t)(ext_nfsstats.biocache_reads -
322 			ext_nfsstats.read_bios),
323 			(uintmax_t)ext_nfsstats.read_bios,
324 			(uintmax_t)(ext_nfsstats.biocache_writes -
325 			ext_nfsstats.write_bios),
326 			(uintmax_t)ext_nfsstats.write_bios);
327 		printf("%9.9s %9.9s %9.9s %9.9s",
328 			"BioRLHits", "Misses", "BioD Hits", "Misses");
329 		printf(" %9.9s %9.9s %9.9s %9.9s\n", "DirE Hits", "Misses", "Accs Hits", "Misses");
330 		printf("%9ju %9ju %9ju %9ju",
331 			(uintmax_t)(ext_nfsstats.biocache_readlinks -
332 			ext_nfsstats.readlink_bios),
333 			(uintmax_t)ext_nfsstats.readlink_bios,
334 			(uintmax_t)(ext_nfsstats.biocache_readdirs -
335 			ext_nfsstats.readdir_bios),
336 			(uintmax_t)ext_nfsstats.readdir_bios);
337 		printf(" %9ju %9ju %9ju %9ju\n",
338 			(uintmax_t)ext_nfsstats.direofcache_hits,
339 			(uintmax_t)ext_nfsstats.direofcache_misses,
340 			(uintmax_t)ext_nfsstats.accesscache_hits,
341 			(uintmax_t)ext_nfsstats.accesscache_misses);
342 	}
343 	if (serverOnly) {
344 		printf("\nServer Info:\n");
345 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
346 			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
347 			"Write", "Create", "Remove");
348 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
349 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
350 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
351 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
352 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
353 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
354 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
355 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
356 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
357 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
358 			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
359 			"Readdir", "RdirPlus", "Access");
360 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
361 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
362 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
363 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
364 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
365 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
366 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
367 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
368 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
369 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
370 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
371 		printf("%9ju %9ju %9ju %9ju %9ju\n",
372 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
373 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
374 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
375 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
376 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
377 		printf("Server Ret-Failed\n");
378 		printf("%17ju\n", (uintmax_t)ext_nfsstats.srvrpc_errs);
379 		printf("Server Faults\n");
380 		printf("%13ju\n", (uintmax_t)ext_nfsstats.srv_errs);
381 		printf("Server Cache Stats:\n");
382 		printf("%9.9s %9.9s %9.9s %9.9s\n",
383 			"Inprog", "Idem", "Non-idem", "Misses");
384 		printf("%9ju %9ju %9ju %9ju\n",
385 			(uintmax_t)ext_nfsstats.srvcache_inproghits,
386 			(uintmax_t)ext_nfsstats.srvcache_idemdonehits,
387 			(uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
388 			(uintmax_t)ext_nfsstats.srvcache_misses);
389 		printf("Server Write Gathering:\n");
390 		printf("%9.9s %9.9s %9.9s\n",
391 			"WriteOps", "WriteRPC", "Opsaved");
392 		/*
393 		 * The new client doesn't do write gathering. It was
394 		 * only useful for NFSv2.
395 		 */
396 		printf("%9ju %9ju %9d\n",
397 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
398 			(uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
399 	}
400 }
401 
402 static void
403 printhdr(int clientOnly, int serverOnly, int newStats)
404 {
405 
406 	if (newStats) {
407 		printf(" [%s Read %s]  [%s Write %s]  "
408 		    "%s[=========== Total ============]\n"
409 		    " KB/t   tps    MB/s%s  KB/t   tps    MB/s%s  "
410 		    "%sKB/t   tps    MB/s    ms  ql  %%b",
411 		    widemode ? "========" : "=====",
412 		    widemode ? "========" : "=====",
413 		    widemode ? "========" : "=====",
414 		    widemode ? "======="  : "====",
415 		    widemode ? "[Commit ]  " : "",
416 		    widemode ? "    ms" : "",
417 		    widemode ? "    ms" : "",
418 		    widemode ? "tps    ms  " : "");
419 	} else {
420 		printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
421 		    ((serverOnly && clientOnly) ? "        " : " "),
422 		    "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename",
423 		    "Access", "Rddir");
424 		if (widemode && clientOnly) {
425 			printf(" Attr Lkup BioR BioW Accs BioD");
426 		}
427 	}
428 	printf("\n");
429 	fflush(stdout);
430 }
431 
432 static void
433 usage(void)
434 {
435 	(void)fprintf(stderr,
436 	    "usage: nfsstat [-cdemszW] [-M core] [-N system] [-w wait]\n");
437 	exit(1);
438 }
439 
440 static char SPBuf[64][8];
441 static int SPIndex;
442 
443 static char *
444 sperc1(int hits, int misses)
445 {
446 	char *p = SPBuf[SPIndex];
447 
448 	if (hits + misses) {
449 		sprintf(p, "%3d%%",
450 		    (int)(char)((quad_t)hits * 100 / (hits + misses)));
451 	} else {
452 		sprintf(p, "   -");
453 	}
454 	SPIndex = (SPIndex + 1) & 63;
455 	return(p);
456 }
457 
458 static char *
459 sperc2(int ttl, int misses)
460 {
461 	char *p = SPBuf[SPIndex];
462 
463 	if (ttl) {
464 		sprintf(p, "%3d%%",
465 		    (int)(char)((quad_t)(ttl - misses) * 100 / ttl));
466 	} else {
467 		sprintf(p, "   -");
468 	}
469 	SPIndex = (SPIndex + 1) & 63;
470 	return(p);
471 }
472 
473 #define DELTA_T(field)					\
474 	devstat_compute_etime(&cur_stats->field,	\
475 	(prev_stats ? &prev_stats->field : NULL))
476 
477 /*
478  * XXX KDM mostly copied from ctlstat.  We should commonize the code (and
479  * the devstat code) somehow.
480  */
481 static void
482 compute_new_stats(struct nfsstatsv1 *cur_stats,
483 		  struct nfsstatsv1 *prev_stats, int curop,
484 		  long double etime, long double *mbsec,
485 		  long double *kb_per_transfer,
486 		  long double *transfers_per_second,
487 		  long double *ms_per_transfer, uint64_t *queue_len,
488 		  long double *busy_pct)
489 {
490 	uint64_t total_bytes = 0, total_operations = 0;
491 	struct bintime total_time_bt;
492 	struct timespec total_time_ts;
493 
494 	bzero(&total_time_bt, sizeof(total_time_bt));
495 	bzero(&total_time_ts, sizeof(total_time_ts));
496 
497 	total_bytes = cur_stats->srvbytes[curop];
498 	total_operations = cur_stats->srvops[curop];
499 	if (prev_stats != NULL) {
500 		total_bytes -= prev_stats->srvbytes[curop];
501 		total_operations -= prev_stats->srvops[curop];
502 	}
503 
504 	*mbsec = total_bytes;
505 	*mbsec /= 1024 * 1024;
506 	if (etime > 0.0) {
507 		*busy_pct = DELTA_T(busytime);
508 		if (*busy_pct < 0)
509 			*busy_pct = 0;
510 		*busy_pct /= etime;
511 		*busy_pct *= 100;
512 		if (*busy_pct < 0)
513 			*busy_pct = 0;
514 		*mbsec /= etime;
515 	} else {
516 		*busy_pct = 0;
517 		*mbsec = 0;
518 	}
519 	*kb_per_transfer = total_bytes;
520 	*kb_per_transfer /= 1024;
521 	if (total_operations > 0)
522 		*kb_per_transfer /= total_operations;
523 	else
524 		*kb_per_transfer = 0;
525 	if (etime > 0.0) {
526 		*transfers_per_second = total_operations;
527 		*transfers_per_second /= etime;
528 	} else {
529 		*transfers_per_second = 0.0;
530 	}
531 
532 	if (total_operations > 0) {
533 		*ms_per_transfer = DELTA_T(srvduration[curop]);
534 		*ms_per_transfer /= total_operations;
535 		*ms_per_transfer *= 1000;
536 	} else
537 		*ms_per_transfer = 0.0;
538 
539 	*queue_len = cur_stats->srvstartcnt - cur_stats->srvdonecnt;
540 }
541 
542 /*
543  * Print a description of the nfs stats for the experimental client/server.
544  */
545 static void
546 exp_intpr(int clientOnly, int serverOnly)
547 {
548 	int nfssvc_flag;
549 
550 	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
551 	if (zflag != 0) {
552 		if (clientOnly != 0)
553 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
554 		if (serverOnly != 0)
555 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
556 	}
557 	ext_nfsstats.vers = NFSSTATS_V1;
558 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
559 		err(1, "Can't get stats");
560 	if (clientOnly != 0) {
561 		if (printtitle) {
562 			printf("Client Info:\n");
563 			printf("Rpc Counts:\n");
564 			printf(
565 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
566 			    , "Getattr", "Setattr", "Lookup", "Readlink",
567 			    "Read", "Write", "Create", "Remove");
568 		}
569 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
570 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
571 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
572 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
573 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
574 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
575 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
576 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
577 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
578 		if (printtitle)
579 			printf(
580 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
581 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
582 			    "Readdir", "RdirPlus", "Access");
583 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
584 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
585 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
586 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
587 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
588 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
589 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
590 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
591 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
592 		if (printtitle)
593 			printf(
594 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
595 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
596 			    "Commit", "SetClId", "SetClIdCf", "Lock");
597 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
598 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
599 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
600 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
601 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
602 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
603 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
604 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
605 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
606 		if (printtitle)
607 			printf("%9.9s %9.9s %9.9s %9.9s\n",
608 			    "LockT", "LockU", "Open", "OpenCfr");
609 		printf("%9ju %9ju %9ju %9ju\n",
610 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
611 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
612 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
613 		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);
614 		if (printtitle)
615 			printf(
616 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
617 			    , "OpenOwner", "Opens", "LockOwner",
618 			    "Locks", "Delegs", "LocalOwn",
619 			    "LocalOpen", "LocalLOwn");
620 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
621 		    (uintmax_t)ext_nfsstats.clopenowners,
622 		    (uintmax_t)ext_nfsstats.clopens,
623 		    (uintmax_t)ext_nfsstats.cllockowners,
624 		    (uintmax_t)ext_nfsstats.cllocks,
625 		    (uintmax_t)ext_nfsstats.cldelegates,
626 		    (uintmax_t)ext_nfsstats.cllocalopenowners,
627 		    (uintmax_t)ext_nfsstats.cllocalopens,
628 		    (uintmax_t)ext_nfsstats.cllocallockowners);
629 		if (printtitle)
630 			printf("%9.9s\n", "LocalLock");
631 		printf("%9ju\n", (uintmax_t)ext_nfsstats.cllocallocks);
632 		if (printtitle) {
633 			printf("Rpc Info:\n");
634 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
635 			    "TimedOut", "Invalid", "X Replies", "Retries",
636 			    "Requests");
637 		}
638 		printf("%9ju %9ju %9ju %9ju %9ju\n",
639 		    (uintmax_t)ext_nfsstats.rpctimeouts,
640 		    (uintmax_t)ext_nfsstats.rpcinvalid,
641 		    (uintmax_t)ext_nfsstats.rpcunexpected,
642 		    (uintmax_t)ext_nfsstats.rpcretries,
643 		    (uintmax_t)ext_nfsstats.rpcrequests);
644 		if (printtitle) {
645 			printf("Cache Info:\n");
646 			printf("%9.9s %9.9s %9.9s %9.9s",
647 			    "Attr Hits", "Misses", "Lkup Hits", "Misses");
648 			printf(" %9.9s %9.9s %9.9s %9.9s\n",
649 			    "BioR Hits", "Misses", "BioW Hits", "Misses");
650 		}
651 		printf("%9ju %9ju %9ju %9ju",
652 		    (uintmax_t)ext_nfsstats.attrcache_hits,
653 		    (uintmax_t)ext_nfsstats.attrcache_misses,
654 		    (uintmax_t)ext_nfsstats.lookupcache_hits,
655 		    (uintmax_t)ext_nfsstats.lookupcache_misses);
656 		printf(" %9ju %9ju %9ju %9ju\n",
657 		    (uintmax_t)(ext_nfsstats.biocache_reads -
658 		    ext_nfsstats.read_bios),
659 		    (uintmax_t)ext_nfsstats.read_bios,
660 		    (uintmax_t)(ext_nfsstats.biocache_writes -
661 		    ext_nfsstats.write_bios),
662 		    (uintmax_t)ext_nfsstats.write_bios);
663 		if (printtitle) {
664 			printf("%9.9s %9.9s %9.9s %9.9s",
665 			    "BioRLHits", "Misses", "BioD Hits", "Misses");
666 			printf(" %9.9s %9.9s\n", "DirE Hits", "Misses");
667 		}
668 		printf("%9ju %9ju %9ju %9ju",
669 		    (uintmax_t)(ext_nfsstats.biocache_readlinks -
670 		    ext_nfsstats.readlink_bios),
671 		    (uintmax_t)ext_nfsstats.readlink_bios,
672 		    (uintmax_t)(ext_nfsstats.biocache_readdirs -
673 		    ext_nfsstats.readdir_bios),
674 		    (uintmax_t)ext_nfsstats.readdir_bios);
675 		printf(" %9ju %9ju\n",
676 		    (uintmax_t)ext_nfsstats.direofcache_hits,
677 		    (uintmax_t)ext_nfsstats.direofcache_misses);
678 	}
679 	if (serverOnly != 0) {
680 		if (printtitle) {
681 			printf("\nServer Info:\n");
682 			printf(
683 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
684 			    , "Getattr", "Setattr", "Lookup", "Readlink",
685 			    "Read", "Write", "Create", "Remove");
686 		}
687 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
688 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
689 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
690 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
691 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
692 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
693 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
694 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
695 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
696 		if (printtitle)
697 			printf(
698 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
699 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
700 			    "Readdir", "RdirPlus", "Access");
701 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
702 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
703 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
704 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
705 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
706 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
707 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
708 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
709 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
710 		if (printtitle)
711 			printf(
712 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
713 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
714 			    "Commit", "LookupP", "SetClId", "SetClIdCf");
715 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
716 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
717 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
718 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
719 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
720 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
721 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
722 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
723 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
724 		if (printtitle)
725 			printf(
726 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
727 			    , "Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
728 			    "DelePurge", "DeleRet", "GetFH", "Lock");
729 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
730 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
731 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
732 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
733 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
734 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
735 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN],
736 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
737 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK]);
738 		if (printtitle)
739 			printf(
740 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
741 			    , "LockT", "LockU", "Close", "Verify", "NVerify",
742 			    "PutFH", "PutPubFH", "PutRootFH");
743 		printf("%9ju %9ju %9ju %9ju %9ju %9ju %9ju %9ju\n",
744 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
745 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
746 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
747 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY],
748 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
749 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
750 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
751 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH]);
752 		if (printtitle)
753 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
754 			    "Renew", "RestoreFH", "SaveFH", "Secinfo",
755 			    "RelLckOwn", "V4Create");
756 		printf("%9ju %9ju %9ju %9ju %9ju %9ju\n",
757 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
758 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH],
759 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
760 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
761 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
762 		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
763 		if (printtitle) {
764 			printf("Server:\n");
765 			printf("%9.9s %9.9s %9.9s\n",
766 			    "Retfailed", "Faults", "Clients");
767 		}
768 		printf("%9ju %9ju %9ju\n",
769 		    (uintmax_t)ext_nfsstats.srv_errs,
770 		    (uintmax_t)ext_nfsstats.srvrpc_errs,
771 		    (uintmax_t)ext_nfsstats.srvclients);
772 		if (printtitle)
773 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s \n",
774 			    "OpenOwner", "Opens", "LockOwner",
775 			    "Locks", "Delegs");
776 		printf("%9ju %9ju %9ju %9ju %9ju \n",
777 		    (uintmax_t)ext_nfsstats.srvopenowners,
778 		    (uintmax_t)ext_nfsstats.srvopens,
779 		    (uintmax_t)ext_nfsstats.srvlockowners,
780 		    (uintmax_t)ext_nfsstats.srvlocks,
781 		    (uintmax_t)ext_nfsstats.srvdelegates);
782 		if (printtitle) {
783 			printf("Server Cache Stats:\n");
784 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
785 			    "Inprog", "Idem", "Non-idem", "Misses",
786 			    "CacheSize", "TCPPeak");
787 		}
788 		printf("%9ju %9ju %9ju %9ju %9ju %9ju\n",
789 		    (uintmax_t)ext_nfsstats.srvcache_inproghits,
790 		    (uintmax_t)ext_nfsstats.srvcache_idemdonehits,
791 		    (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
792 		    (uintmax_t)ext_nfsstats.srvcache_misses,
793 		    (uintmax_t)ext_nfsstats.srvcache_size,
794 		    (uintmax_t)ext_nfsstats.srvcache_tcppeak);
795 	}
796 }
797 
798 static void
799 compute_totals(struct nfsstatsv1 *total_stats, struct nfsstatsv1 *cur_stats)
800 {
801 	int i;
802 
803 	bzero(total_stats, sizeof(*total_stats));
804 	for (i = 0; i < (NFSV42_NOPS + NFSV4OP_FAKENOPS); i++) {
805 		total_stats->srvbytes[0] += cur_stats->srvbytes[i];
806 		total_stats->srvops[0] += cur_stats->srvops[i];
807 		bintime_add(&total_stats->srvduration[0],
808 			    &cur_stats->srvduration[i]);
809 		total_stats->srvrpccnt[i] = cur_stats->srvrpccnt[i];
810 	}
811 	total_stats->srvstartcnt = cur_stats->srvstartcnt;
812 	total_stats->srvdonecnt = cur_stats->srvdonecnt;
813 	total_stats->busytime = cur_stats->busytime;
814 
815 }
816 
817 /*
818  * Print a running summary of nfs statistics for the experimental client and/or
819  * server.
820  * Repeat display every interval seconds, showing statistics
821  * collected over that interval.  Assumes that interval is non-zero.
822  * First line printed at top of screen is always cumulative.
823  */
824 static void
825 exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly,
826     int newStats)
827 {
828 	struct nfsstatsv1 nfsstats, lastst, *ext_nfsstatsp;
829 	struct nfsstatsv1 curtotal, lasttotal;
830 	struct timespec ts, lastts;
831 	int hdrcnt = 1;
832 
833 	ext_nfsstatsp = &lastst;
834 	ext_nfsstatsp->vers = NFSSTATS_V1;
835 	if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) < 0)
836 		err(1, "Can't get stats");
837 	clock_gettime(CLOCK_MONOTONIC, &lastts);
838 	compute_totals(&lasttotal, ext_nfsstatsp);
839 	sleep(interval);
840 
841 	for (;;) {
842 		ext_nfsstatsp = &nfsstats;
843 		ext_nfsstatsp->vers = NFSSTATS_V1;
844 		if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp)
845 		    < 0)
846 			err(1, "Can't get stats");
847 		clock_gettime(CLOCK_MONOTONIC, &ts);
848 
849 		if (--hdrcnt == 0) {
850 			printhdr(clientOnly, serverOnly, newStats);
851 			if (newStats)
852 				hdrcnt = 20;
853 			else if (clientOnly && serverOnly)
854 				hdrcnt = 10;
855 			else
856 				hdrcnt = 20;
857 		}
858 		if (clientOnly && newStats == 0) {
859 		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
860 			((clientOnly && serverOnly) ? "Client:" : ""),
861 			(uintmax_t)DELTA(rpccnt[NFSPROC_GETATTR]),
862 			(uintmax_t)DELTA(rpccnt[NFSPROC_LOOKUP]),
863 			(uintmax_t)DELTA(rpccnt[NFSPROC_READLINK]),
864 			(uintmax_t)DELTA(rpccnt[NFSPROC_READ]),
865 			(uintmax_t)DELTA(rpccnt[NFSPROC_WRITE]),
866 			(uintmax_t)DELTA(rpccnt[NFSPROC_RENAME]),
867 			(uintmax_t)DELTA(rpccnt[NFSPROC_ACCESS]),
868 			(uintmax_t)(DELTA(rpccnt[NFSPROC_READDIR]) +
869 			DELTA(rpccnt[NFSPROC_READDIRPLUS]))
870 		    );
871 		    if (widemode) {
872 			    printf(" %s %s %s %s %s %s",
873 				sperc1(DELTA(attrcache_hits),
874 				    DELTA(attrcache_misses)),
875 				sperc1(DELTA(lookupcache_hits),
876 				    DELTA(lookupcache_misses)),
877 				sperc2(DELTA(biocache_reads),
878 				    DELTA(read_bios)),
879 				sperc2(DELTA(biocache_writes),
880 				    DELTA(write_bios)),
881 				sperc1(DELTA(accesscache_hits),
882 				    DELTA(accesscache_misses)),
883 				sperc2(DELTA(biocache_readdirs),
884 				    DELTA(readdir_bios))
885 			    );
886 		    }
887 		    printf("\n");
888 		}
889 
890 		if (serverOnly && newStats) {
891 			long double cur_secs, last_secs, etime;
892 			long double mbsec;
893 			long double kb_per_transfer;
894 			long double transfers_per_second;
895 			long double ms_per_transfer;
896 			uint64_t queue_len;
897 			long double busy_pct;
898 			int i;
899 
900 			cur_secs = ts.tv_sec +
901 			    ((long double)ts.tv_nsec / 1000000000);
902 			last_secs = lastts.tv_sec +
903 			    ((long double)lastts.tv_nsec / 1000000000);
904 			etime = cur_secs - last_secs;
905 
906 			compute_totals(&curtotal, &nfsstats);
907 
908 			for (i = 0; i < NUM_STAT_TYPES; i++) {
909 				compute_new_stats(&nfsstats, &lastst,
910 				    STAT_TYPE_TO_NFS(i), etime, &mbsec,
911 				    &kb_per_transfer,
912 				    &transfers_per_second,
913 				    &ms_per_transfer, &queue_len,
914 				    &busy_pct);
915 
916 				if (i == STAT_TYPE_COMMIT) {
917 					if (widemode == 0)
918 						continue;
919 
920 					printf("%2.0Lf %7.2Lf ",
921 					    transfers_per_second,
922 					    ms_per_transfer);
923 				} else {
924 					printf("%5.2Lf %5.0Lf %7.2Lf ",
925 					    kb_per_transfer,
926 					    transfers_per_second, mbsec);
927 					if (widemode)
928 						printf("%5.2Lf ",
929 						    ms_per_transfer);
930 				}
931 			}
932 
933 			compute_new_stats(&curtotal, &lasttotal, 0, etime,
934 			    &mbsec, &kb_per_transfer, &transfers_per_second,
935 			    &ms_per_transfer, &queue_len, &busy_pct);
936 
937 			printf("%5.2Lf %5.0Lf %7.2Lf %5.2Lf %3ju %3.0Lf\n",
938 			    kb_per_transfer, transfers_per_second, mbsec,
939 			    ms_per_transfer, queue_len, busy_pct);
940 		} else if (serverOnly) {
941 		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
942 			((clientOnly && serverOnly) ? "Server:" : ""),
943 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_GETATTR]),
944 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_LOOKUP]),
945 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READLINK]),
946 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READ]),
947 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_WRITE]),
948 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_RENAME]),
949 			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_ACCESS]),
950 			(uintmax_t)(DELTA(srvrpccnt[NFSV4OP_READDIR]) +
951 			DELTA(srvrpccnt[NFSV4OP_READDIRPLUS])));
952 		    printf("\n");
953 		}
954 		bcopy(&nfsstats, &lastst, sizeof(lastst));
955 		bcopy(&curtotal, &lasttotal, sizeof(lasttotal));
956 		lastts = ts;
957 		fflush(stdout);
958 		sleep(interval);
959 	}
960 	/*NOTREACHED*/
961 }
962