nfsstat.c revision 306632
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
64static 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
71static char sccsid[] = "@(#)nfsstat.c	8.2 (Berkeley) 3/31/95";
72#endif
73static const char rcsid[] =
74  "$FreeBSD: stable/11/usr.bin/nfsstat/nfsstat.c 306632 2016-10-03 12:02:45Z rmacklem $";
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
104static int widemode = 0;
105static int zflag = 0;
106static int printtitle = 1;
107static struct nfsstatsv1 ext_nfsstats;
108static int extra_output = 0;
109
110static void intpr(int, int);
111static void printhdr(int, int, int);
112static void usage(void);
113static char *sperc1(int, int);
114static char *sperc2(int, int);
115static void exp_intpr(int, int);
116static void exp_sidewaysintpr(u_int, int, int, int);
117static 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
130struct stattypes {
131	int stat_type;
132	int nfs_type;
133};
134static 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
142int
143main(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 */
250static void
251intpr(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
402static void
403printhdr(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
432static void
433usage(void)
434{
435	(void)fprintf(stderr,
436	    "usage: nfsstat [-cdemszW] [-M core] [-N system] [-w wait]\n");
437	exit(1);
438}
439
440static char SPBuf[64][8];
441static int SPIndex;
442
443static char *
444sperc1(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
458static char *
459sperc2(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 */
481static void
482compute_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 */
545static void
546exp_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
798static void
799compute_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 */
824static void
825exp_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