xref: /netbsd-src/usr.bin/nfsstat/nfsstat.c (revision 9bbbeef3e775d28b69288e321d93938c1bb90424)
1*9bbbeef3Schristos /*	$NetBSD: nfsstat.c,v 1.25 2014/04/24 18:40:35 christos Exp $	*/
2c5f7cf3aSthorpej 
361f28255Scgd /*
4b6109a20Smycroft  * Copyright (c) 1983, 1989, 1993
5b6109a20Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * This code is derived from software contributed to Berkeley by
861f28255Scgd  * Rick Macklem at The University of Guelph.
961f28255Scgd  *
1061f28255Scgd  * Redistribution and use in source and binary forms, with or without
1161f28255Scgd  * modification, are permitted provided that the following conditions
1261f28255Scgd  * are met:
1361f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1561f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1761f28255Scgd  *    documentation and/or other materials provided with the distribution.
1889aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd  *    may be used to endorse or promote products derived from this software
2061f28255Scgd  *    without specific prior written permission.
2161f28255Scgd  *
2261f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd  * SUCH DAMAGE.
3361f28255Scgd  */
3461f28255Scgd 
350ef9bf00Slukem #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
3798e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\
3898e5374cSlukem  The Regents of the University of California.  All rights reserved.");
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #ifndef lint
42c5f7cf3aSthorpej #if 0
43c5f7cf3aSthorpej static char sccsid[] = "from: @(#)nfsstat.c	8.1 (Berkeley) 6/6/93";
44c5f7cf3aSthorpej #else
45*9bbbeef3Schristos __RCSID("$NetBSD: nfsstat.c,v 1.25 2014/04/24 18:40:35 christos Exp $");
46c5f7cf3aSthorpej #endif
4761f28255Scgd #endif /* not lint */
4861f28255Scgd 
4961f28255Scgd #include <sys/param.h>
5061f28255Scgd #include <sys/mount.h>
51aa58cf93Sfvdl #include <sys/sysctl.h>
525c1fdae7Sexplorer 
53aa58cf93Sfvdl #include <nfs/rpcv2.h>
54aa58cf93Sfvdl #include <nfs/nfsproto.h>
5561f28255Scgd #include <nfs/nfs.h>
565c1fdae7Sexplorer 
5761f28255Scgd #include <ctype.h>
58aa58cf93Sfvdl #include <err.h>
595c1fdae7Sexplorer #include <errno.h>
605c1fdae7Sexplorer #include <fcntl.h>
615c1fdae7Sexplorer #include <kvm.h>
625c1fdae7Sexplorer #include <limits.h>
635c1fdae7Sexplorer #include <nlist.h>
645c1fdae7Sexplorer #include <paths.h>
655c1fdae7Sexplorer #include <signal.h>
665c1fdae7Sexplorer #include <stdlib.h>
675c1fdae7Sexplorer #include <stdio.h>
685c1fdae7Sexplorer #include <string.h>
695c1fdae7Sexplorer #include <unistd.h>
7061f28255Scgd 
71a2f897e7Sjoerg static struct nlist nl[] = {
7261f28255Scgd #define	N_NFSSTAT	0
73fc99e5eaSlukem 	{ "_nfsstats", 0, 0, 0, 0 },
74fc99e5eaSlukem 	{ "", 0, 0, 0, 0 },
7561f28255Scgd };
7654736c47Ssimonb 
77d25d8e4dSyamt #define	MASK(a)	(1 << NFSPROC_##a)
78d25d8e4dSyamt #define ALLMASK								\
79d25d8e4dSyamt 	(MASK(GETATTR) | MASK(SETATTR) | MASK(LOOKUP) | MASK(READ) |	\
80d25d8e4dSyamt 	MASK(WRITE) | MASK(RENAME)| MASK(ACCESS) | MASK(READDIR) |	\
81d25d8e4dSyamt 	MASK(READDIRPLUS))
82d25d8e4dSyamt #define	OTHERMASK	(((1 << NFS_NPROCS) - 1) & ~ALLMASK)
83a2f897e7Sjoerg static const struct shortprocs {
84d25d8e4dSyamt 	int mask;
85d25d8e4dSyamt 	const char *name;
86d25d8e4dSyamt } shortprocs[] = {
87d25d8e4dSyamt 	{MASK(GETATTR),	"Getattr"},
88d25d8e4dSyamt 	{MASK(SETATTR),	"Setattr"},
89d25d8e4dSyamt 	{MASK(LOOKUP),	"Lookup"},
90d25d8e4dSyamt 	{MASK(READ),	"Read"},
91d25d8e4dSyamt 	{MASK(WRITE),	"Write"},
92d25d8e4dSyamt 	{MASK(RENAME),	"Rename"},
93d25d8e4dSyamt 	{MASK(ACCESS),	"Access"},
94d25d8e4dSyamt 	{MASK(READDIR) | MASK(READDIRPLUS), "Readdir"},
95d25d8e4dSyamt 	{OTHERMASK, "Others"},
96d25d8e4dSyamt };
97d25d8e4dSyamt 
98d25d8e4dSyamt #define	NSHORTPROC	(sizeof(shortprocs)/sizeof(shortprocs[0]))
9961f28255Scgd 
100a2f897e7Sjoerg static void	catchalarm(int);
101a2f897e7Sjoerg static void	getstats(struct nfsstats *);
102a2f897e7Sjoerg static void	intpr(void);
103a2f897e7Sjoerg static void	printhdr(void);
104a2f897e7Sjoerg __dead static void	sidewaysintpr(u_int);
105a2f897e7Sjoerg __dead static void	usage(void);
10661f28255Scgd 
107a2f897e7Sjoerg static kvm_t  *kd;
108a2f897e7Sjoerg static int     printall, clientinfo, serverinfo;
109a2f897e7Sjoerg static u_long	nfsstataddr;
110b5232219Shubertf 
1110ef9bf00Slukem int
main(int argc,char ** argv)112a2f897e7Sjoerg main(int argc, char **argv)
11361f28255Scgd {
11461f28255Scgd 	u_int interval;
11561f28255Scgd 	int ch;
116b6109a20Smycroft 	char *memf, *nlistf;
1175c1fdae7Sexplorer 	char errbuf[_POSIX2_LINE_MAX];
11861f28255Scgd 
11961f28255Scgd 	interval = 0;
120b6109a20Smycroft 	memf = nlistf = NULL;
121b5232219Shubertf 	printall = 1;
122b5232219Shubertf 	while ((ch = getopt(argc, argv, "M:N:w:cs")) != -1)
12361f28255Scgd 		switch(ch) {
12461f28255Scgd 		case 'M':
125b6109a20Smycroft 			memf = optarg;
12661f28255Scgd 			break;
12761f28255Scgd 		case 'N':
128b6109a20Smycroft 			nlistf = optarg;
12961f28255Scgd 			break;
13061f28255Scgd 		case 'w':
13161f28255Scgd 			interval = atoi(optarg);
13261f28255Scgd 			break;
133b5232219Shubertf 		case 's':
134b5232219Shubertf 		        serverinfo = 1;
135b5232219Shubertf 			printall = 0;
136b5232219Shubertf 			break;
137b5232219Shubertf 		case 'c':
138b5232219Shubertf 		        clientinfo = 1;
139b5232219Shubertf 			printall = 0;
140b5232219Shubertf 			break;
14161f28255Scgd 		case '?':
14261f28255Scgd 		default:
14361f28255Scgd 			usage();
14461f28255Scgd 		}
14561f28255Scgd 	argc -= optind;
14661f28255Scgd 	argv += optind;
14761f28255Scgd 
14861f28255Scgd #define	BACKWARD_COMPATIBILITY
14961f28255Scgd #ifdef	BACKWARD_COMPATIBILITY
15061f28255Scgd 	if (*argv) {
151b6109a20Smycroft 		interval = atoi(*argv);
15261f28255Scgd 		if (*++argv) {
153b6109a20Smycroft 			nlistf = *argv;
154b6109a20Smycroft 			if (*++argv)
155b6109a20Smycroft 				memf = *argv;
15661f28255Scgd 		}
15761f28255Scgd 	}
15861f28255Scgd #endif
15954736c47Ssimonb 	if (nlistf || memf) {
16054736c47Ssimonb 		if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf))
16154736c47Ssimonb 		    == 0)
1620ef9bf00Slukem 			errx(1, "kvm_openfiles: %s", errbuf);
16380efe80bSmrg 
1640ef9bf00Slukem 		if (kvm_nlist(kd, nl) != 0)
1650ef9bf00Slukem 			errx(1, "kvm_nlist: can't get names");
16654736c47Ssimonb 		nfsstataddr = nl[N_NFSSTAT].n_value;
16754736c47Ssimonb 	} else {
16854736c47Ssimonb 		kd = NULL;
16954736c47Ssimonb 	}
17061f28255Scgd 
17161f28255Scgd 	if (interval)
17254736c47Ssimonb 		sidewaysintpr(interval);
17361f28255Scgd 	else
17454736c47Ssimonb 		intpr();
17561f28255Scgd 	exit(0);
17661f28255Scgd }
17761f28255Scgd 
178a2f897e7Sjoerg static void
getstats(struct nfsstats * ns)179a2f897e7Sjoerg getstats(struct nfsstats *ns)
18054736c47Ssimonb {
18154736c47Ssimonb 	size_t size;
18254736c47Ssimonb 	int mib[3];
18354736c47Ssimonb 
18454736c47Ssimonb 	if (kd) {
18554736c47Ssimonb 		if (kvm_read(kd, (u_long)nfsstataddr, ns, sizeof(*ns))
18654736c47Ssimonb 		    != sizeof(*ns))
18754736c47Ssimonb 			errx(1, "kvm_read failed");
18854736c47Ssimonb 	} else {
18954736c47Ssimonb 		mib[0] = CTL_VFS;
19054736c47Ssimonb 		mib[1] = 2;	/* XXX from CTL_VFS_NAMES in <sys/mount.h> */
19154736c47Ssimonb 		mib[2] = NFS_NFSSTATS;
19254736c47Ssimonb 
19354736c47Ssimonb 		size = sizeof(*ns);
19454736c47Ssimonb 		if (sysctl(mib, 3, ns, &size, NULL, 0) == -1)
19554736c47Ssimonb 			err(1, "sysctl(NFS_NFSSTATS) failed");
19654736c47Ssimonb 	}
19754736c47Ssimonb }
19854736c47Ssimonb 
19961f28255Scgd /*
200b6109a20Smycroft  * Print a description of the nfs stats.
20161f28255Scgd  */
202a2f897e7Sjoerg static void
intpr(void)203a2f897e7Sjoerg intpr(void)
20461f28255Scgd {
20561f28255Scgd 	struct nfsstats nfsstats;
206*9bbbeef3Schristos 	uint64_t	total;
2078073bda8Slukem 	int	i;
2088073bda8Slukem 
2098073bda8Slukem #define PCT(x,y)	((y) == 0 ? 0 : (int)((int64_t)(x) * 100 / (y)))
2108073bda8Slukem #define NUMPCT(x,y)	(x), PCT(x, (x)+(y))
2118073bda8Slukem #define	RPCSTAT(x)	(x), PCT(x, total)
21261f28255Scgd 
21354736c47Ssimonb 	getstats(&nfsstats);
2148073bda8Slukem 
215b5232219Shubertf 	if (printall || clientinfo) {
2168073bda8Slukem 		total = 0;
2178073bda8Slukem 		for (i = 0; i < NFS_NPROCS; i++)
2188073bda8Slukem 			total += nfsstats.rpccnt[i];
21961f28255Scgd 		printf("Client Info:\n");
220*9bbbeef3Schristos 		printf("RPC Counts: (%" PRIu64 " call%s)\n", total,
2218073bda8Slukem 		    total == 1 ? "" : "s");
2228073bda8Slukem 
2238073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2248073bda8Slukem 		    "null", "getattr", "setattr", "lookup", "access");
2258073bda8Slukem 		printf(
226*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
2278073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_NULL]),
2288073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_GETATTR]),
2298073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_SETATTR]),
2308073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_LOOKUP]),
2318073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_ACCESS]));
2328073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2338073bda8Slukem 		    "readlink", "read", "write", "create", "mkdir");
2348073bda8Slukem 		printf(
235*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
2368073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_READLINK]),
2378073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_READ]),
2388073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_WRITE]),
2398073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_CREATE]),
2408073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_MKDIR]));
2418073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2428073bda8Slukem 		    "symlink", "mknod", "remove", "rmdir", "rename");
2438073bda8Slukem 		printf(
244*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
2458073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_SYMLINK]),
2468073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_MKNOD]),
2478073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_REMOVE]),
2488073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_RMDIR]),
2498073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_RENAME]));
2508073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2518073bda8Slukem 		    "link", "readdir", "readdirplus", "fsstat", "fsinfo");
2528073bda8Slukem 		printf(
253*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
2548073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_LINK]),
2558073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIR]),
2568073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIRPLUS]),
2578073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_FSSTAT]),
2588073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_FSINFO]));
259a67f31f4Syamt 		printf("%10s  %14s\n",
260a67f31f4Syamt 		    "pathconf", "commit");
261*9bbbeef3Schristos 		printf("%10u %2u%%  %10u %2u%%\n",
2628073bda8Slukem 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_PATHCONF]),
263d7e50df6Sdogcow 		    RPCSTAT(nfsstats.rpccnt[NFSPROC_COMMIT]));
2648073bda8Slukem 
2658073bda8Slukem 		printf("RPC Info:\n");
2668073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2678073bda8Slukem 		    "timeout", "invalid", "unexpected", "retries", "requests");
268*9bbbeef3Schristos 		printf("%10u  %14u  %14u  %14u  %14u\n",
26961f28255Scgd 		    nfsstats.rpctimeouts,
27061f28255Scgd 		    nfsstats.rpcinvalid,
27161f28255Scgd 		    nfsstats.rpcunexpected,
27261f28255Scgd 		    nfsstats.rpcretries,
27361f28255Scgd 		    nfsstats.rpcrequests);
2748073bda8Slukem 
27561f28255Scgd 		printf("Cache Info:\n");
2768073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
2778073bda8Slukem 		    "attrcache", "lookupcache", "read", "write", "readlink");
2788073bda8Slukem 		printf(
279*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
2808073bda8Slukem 		    NUMPCT(nfsstats.attrcache_hits,
2818073bda8Slukem 			nfsstats.attrcache_misses),
2828073bda8Slukem 		    NUMPCT(nfsstats.lookupcache_hits,
2838073bda8Slukem 			nfsstats.lookupcache_misses),
2848073bda8Slukem 		    NUMPCT(nfsstats.biocache_reads - nfsstats.read_bios,
2858073bda8Slukem 			nfsstats.read_bios),
2868073bda8Slukem 		    NUMPCT(nfsstats.biocache_writes - nfsstats.write_bios,
2878073bda8Slukem 			nfsstats.write_bios),
2888073bda8Slukem 		    NUMPCT(nfsstats.biocache_readlinks - nfsstats.readlink_bios,
2898073bda8Slukem 			nfsstats.readlink_bios));
2908073bda8Slukem 		printf("%10s  %14s\n",
2918073bda8Slukem 		    "readdir", "direofcache");
292*9bbbeef3Schristos 		printf("%10u %2u%%  %10u %2u%%\n",
2938073bda8Slukem 		    NUMPCT(nfsstats.biocache_readdirs - nfsstats.readdir_bios,
2948073bda8Slukem 			nfsstats.readdir_bios),
2958073bda8Slukem 		    NUMPCT(nfsstats.direofcache_hits,
2968073bda8Slukem 			nfsstats.direofcache_misses));
297b5232219Shubertf 	}
2988073bda8Slukem 
2998073bda8Slukem 	if (printall || (clientinfo && serverinfo))
300b5232219Shubertf 		printf("\n");
3018073bda8Slukem 
302b5232219Shubertf 	if (printall || serverinfo) {
3038073bda8Slukem 		total = 0;
3048073bda8Slukem 		for (i = 0; i < NFS_NPROCS; i++)
3058073bda8Slukem 			total += nfsstats.srvrpccnt[i];
306b5232219Shubertf 		printf("Server Info:\n");
307*9bbbeef3Schristos 		printf("RPC Counts: (%" PRIu64 " call%s)\n", total,
3088073bda8Slukem 		    total == 1 ? "" : "s");
3098073bda8Slukem 
3108073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
3118073bda8Slukem 		    "null", "getattr", "setattr", "lookup", "access");
3128073bda8Slukem 		printf(
313*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
3148073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NULL]),
3158073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_GETATTR]),
3168073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SETATTR]),
3178073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LOOKUP]),
3188073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_ACCESS]));
3198073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
3208073bda8Slukem 		    "readlink", "read", "write", "create", "mkdir");
3218073bda8Slukem 		printf(
322*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
3238073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READLINK]),
3248073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READ]),
3258073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_WRITE]),
3268073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_CREATE]),
3278073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKDIR]));
3288073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
3298073bda8Slukem 		    "symlink", "mknod", "remove", "rmdir", "rename");
3308073bda8Slukem 		printf(
331*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
3328073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SYMLINK]),
3338073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKNOD]),
3348073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_REMOVE]),
3358073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RMDIR]),
3368073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RENAME]));
3378073bda8Slukem 		printf("%10s  %14s  %14s  %14s  %14s\n",
3388073bda8Slukem 		    "link", "readdir", "readdirplus", "fsstat", "fsinfo");
3398073bda8Slukem 		printf(
340*9bbbeef3Schristos 	    "%10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%  %10u %2u%%\n",
3418073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LINK]),
3428073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIR]),
3438073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]),
3448073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSSTAT]),
3458073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSINFO]));
346a67f31f4Syamt 		printf("%10s  %14s\n",
347a67f31f4Syamt 		    "pathconf", "commit");
348*9bbbeef3Schristos 		printf("%10u %2u%%  %10u %2u%%\n",
3498073bda8Slukem 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_PATHCONF]),
350d7e50df6Sdogcow 		    RPCSTAT(nfsstats.srvrpccnt[NFSPROC_COMMIT]));
3518073bda8Slukem 
3528073bda8Slukem 		printf("Server Errors:\n");
3538073bda8Slukem 		printf("%10s  %14s\n",
3548073bda8Slukem 		    "RPC errors", "faults");
355*9bbbeef3Schristos 		printf("%10u  %14u\n",
3568073bda8Slukem 		    nfsstats.srvrpc_errs,
3578073bda8Slukem 		    nfsstats.srv_errs);
35861f28255Scgd 		printf("Server Cache Stats:\n");
3598073bda8Slukem 		printf("%10s  %14s  %14s  %14s\n",
3608073bda8Slukem 		    "inprogress", "idem", "non-idem", "misses");
361*9bbbeef3Schristos 		printf("%10u  %14u  %14u  %14u\n",
36261f28255Scgd 		    nfsstats.srvcache_inproghits,
36361f28255Scgd 		    nfsstats.srvcache_idemdonehits,
36461f28255Scgd 		    nfsstats.srvcache_nonidemdonehits,
36561f28255Scgd 		    nfsstats.srvcache_misses);
366aa58cf93Sfvdl 		printf("Server Write Gathering:\n");
3678073bda8Slukem 		printf("%10s  %14s  %14s\n",
3688073bda8Slukem 		    "writes", "write RPC", "OPs saved");
369*9bbbeef3Schristos 		printf("%10u  %14u  %14u %2u%%\n",
370aa58cf93Sfvdl 		    nfsstats.srvvop_writes,
371aa58cf93Sfvdl 		    nfsstats.srvrpccnt[NFSPROC_WRITE],
3728073bda8Slukem 		    NUMPCT(
3738073bda8Slukem 		      nfsstats.srvrpccnt[NFSPROC_WRITE]-nfsstats.srvvop_writes,
3748073bda8Slukem 		      nfsstats.srvrpccnt[NFSPROC_WRITE]));
37561f28255Scgd 	}
376b5232219Shubertf }
37761f28255Scgd 
378a2f897e7Sjoerg static u_char	signalled;			/* set if alarm goes off "early" */
37961f28255Scgd 
38061f28255Scgd /*
38161f28255Scgd  * Print a running summary of nfs statistics.
38261f28255Scgd  * Repeat display every interval seconds, showing statistics
38361f28255Scgd  * collected over that interval.  Assumes that interval is non-zero.
38461f28255Scgd  * First line printed at top of screen is always cumulative.
38561f28255Scgd  */
386a2f897e7Sjoerg static void
sidewaysintpr(u_int interval)387a2f897e7Sjoerg sidewaysintpr(u_int interval)
38861f28255Scgd {
389d25d8e4dSyamt 	struct nfsstats nfsstats;
39061f28255Scgd 	int hdrcnt, oldmask;
391d25d8e4dSyamt 	struct stats {
392d25d8e4dSyamt 		int client[NSHORTPROC];
393d25d8e4dSyamt 		int server[NSHORTPROC];
394d25d8e4dSyamt 	} current, last;
39561f28255Scgd 
39661f28255Scgd 	(void)signal(SIGALRM, catchalarm);
39761f28255Scgd 	signalled = 0;
39861f28255Scgd 	(void)alarm(interval);
399d25d8e4dSyamt 	memset(&last, 0, sizeof(last));
40061f28255Scgd 
40161f28255Scgd 	for (hdrcnt = 1;;) {
402fc99e5eaSlukem 		size_t i;
403d25d8e4dSyamt 
40461f28255Scgd 		if (!--hdrcnt) {
40561f28255Scgd 			printhdr();
40661f28255Scgd 			hdrcnt = 20;
40761f28255Scgd 		}
40854736c47Ssimonb 		getstats(&nfsstats);
409d25d8e4dSyamt 		memset(&current, 0, sizeof(current));
410d25d8e4dSyamt 		for (i = 0; i < NSHORTPROC; i++) {
411d25d8e4dSyamt 			int mask = shortprocs[i].mask;
412d25d8e4dSyamt 			int idx;
413d25d8e4dSyamt 
414d25d8e4dSyamt 			while ((idx = ffs(mask)) != 0) {
415d25d8e4dSyamt 				idx--;
416d25d8e4dSyamt 				mask &= ~(1 << idx);
417d25d8e4dSyamt 				current.client[i] += nfsstats.rpccnt[idx];
418d25d8e4dSyamt 				current.server[i] += nfsstats.srvrpccnt[idx];
419d25d8e4dSyamt 			}
420d25d8e4dSyamt 		}
421d25d8e4dSyamt 
422d25d8e4dSyamt 		if (printall || clientinfo) {
423d25d8e4dSyamt 			printf("Client:");
424d25d8e4dSyamt 			for (i = 0; i < NSHORTPROC; i++)
425*9bbbeef3Schristos 				printf(" %7u",
426d25d8e4dSyamt 				    current.client[i] - last.client[i]);
427d25d8e4dSyamt 			printf("\n");
428d25d8e4dSyamt 		}
429d25d8e4dSyamt 		if (printall || serverinfo) {
430d25d8e4dSyamt 			printf("Server:");
431d25d8e4dSyamt 			for (i = 0; i < NSHORTPROC; i++)
432*9bbbeef3Schristos 				printf(" %7u",
433d25d8e4dSyamt 				    current.server[i] - last.server[i]);
434d25d8e4dSyamt 			printf("\n");
435d25d8e4dSyamt 		}
436d25d8e4dSyamt 		memcpy(&last, &current, sizeof(last));
43761f28255Scgd 		fflush(stdout);
43861f28255Scgd 		oldmask = sigblock(sigmask(SIGALRM));
43961f28255Scgd 		if (!signalled)
44061f28255Scgd 			sigpause(0);
44161f28255Scgd 		sigsetmask(oldmask);
44261f28255Scgd 		signalled = 0;
44361f28255Scgd 		(void)alarm(interval);
44461f28255Scgd 	}
44561f28255Scgd 	/*NOTREACHED*/
44661f28255Scgd }
44761f28255Scgd 
448a2f897e7Sjoerg static void
printhdr(void)449a2f897e7Sjoerg printhdr(void)
45061f28255Scgd {
451fc99e5eaSlukem 	size_t i;
452d717877cSmrg 
453d25d8e4dSyamt 	printf("        ");
454d25d8e4dSyamt 	for (i = 0; i < NSHORTPROC; i++)
455d25d8e4dSyamt 		printf("%7.7s ", shortprocs[i].name);
456d25d8e4dSyamt 	printf("\n");
45761f28255Scgd 	fflush(stdout);
45861f28255Scgd }
45961f28255Scgd 
46061f28255Scgd /*
46161f28255Scgd  * Called if an interval expires before sidewaysintpr has completed a loop.
46261f28255Scgd  * Sets a flag to not wait for the alarm.
46361f28255Scgd  */
464a2f897e7Sjoerg static void
catchalarm(int dummy)465a2f897e7Sjoerg catchalarm(int dummy)
46661f28255Scgd {
467d717877cSmrg 
46861f28255Scgd 	signalled = 1;
46961f28255Scgd }
47061f28255Scgd 
471a2f897e7Sjoerg static void
usage(void)472a2f897e7Sjoerg usage(void)
47361f28255Scgd {
474d717877cSmrg 
47561f28255Scgd 	(void)fprintf(stderr,
476*9bbbeef3Schristos 	      "Usage: %s [-cs] [-M core] [-N system] [-w interval]\n",
477*9bbbeef3Schristos 	      getprogname());
47861f28255Scgd 	exit(1);
47961f28255Scgd }
480