Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.bin / nfsstat / nfsstat.c
blob514d199e78143e55d81dca2658a192191b7b8bd3
1 /* $NetBSD: nfsstat.c,v 1.22 2008/07/21 14:19:24 lukem Exp $ */
3 /*
4 * Copyright (c) 1983, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\
38 The Regents of the University of California. All rights reserved.");
39 #endif /* not lint */
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "from: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93";
44 #else
45 __RCSID("$NetBSD: nfsstat.c,v 1.22 2008/07/21 14:19:24 lukem Exp $");
46 #endif
47 #endif /* not lint */
49 #include <sys/param.h>
50 #include <sys/mount.h>
51 #include <sys/sysctl.h>
53 #include <nfs/rpcv2.h>
54 #include <nfs/nfsproto.h>
55 #include <nfs/nfs.h>
57 #include <ctype.h>
58 #include <err.h>
59 #include <errno.h>
60 #include <fcntl.h>
61 #include <kvm.h>
62 #include <limits.h>
63 #include <nlist.h>
64 #include <paths.h>
65 #include <signal.h>
66 #include <stdlib.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
71 struct nlist nl[] = {
72 #define N_NFSSTAT 0
73 { "_nfsstats", 0, 0, 0, 0 },
74 { "", 0, 0, 0, 0 },
77 #define MASK(a) (1 << NFSPROC_##a)
78 #define ALLMASK \
79 (MASK(GETATTR) | MASK(SETATTR) | MASK(LOOKUP) | MASK(READ) | \
80 MASK(WRITE) | MASK(RENAME)| MASK(ACCESS) | MASK(READDIR) | \
81 MASK(READDIRPLUS))
82 #define OTHERMASK (((1 << NFS_NPROCS) - 1) & ~ALLMASK)
83 const struct shortprocs {
84 int mask;
85 const char *name;
86 } shortprocs[] = {
87 {MASK(GETATTR), "Getattr"},
88 {MASK(SETATTR), "Setattr"},
89 {MASK(LOOKUP), "Lookup"},
90 {MASK(READ), "Read"},
91 {MASK(WRITE), "Write"},
92 {MASK(RENAME), "Rename"},
93 {MASK(ACCESS), "Access"},
94 {MASK(READDIR) | MASK(READDIRPLUS), "Readdir"},
95 {OTHERMASK, "Others"},
98 #define NSHORTPROC (sizeof(shortprocs)/sizeof(shortprocs[0]))
100 void catchalarm __P((int));
101 void getstats __P((struct nfsstats *));
102 void intpr __P((void));
103 int main __P((int, char **));
104 void printhdr __P((void));
105 void sidewaysintpr __P((u_int));
106 void usage __P((void));
108 kvm_t *kd;
109 int printall, clientinfo, serverinfo;
110 u_long nfsstataddr;
113 main(argc, argv)
114 int argc;
115 char **argv;
117 u_int interval;
118 int ch;
119 char *memf, *nlistf;
120 char errbuf[_POSIX2_LINE_MAX];
122 interval = 0;
123 memf = nlistf = NULL;
124 printall = 1;
125 while ((ch = getopt(argc, argv, "M:N:w:cs")) != -1)
126 switch(ch) {
127 case 'M':
128 memf = optarg;
129 break;
130 case 'N':
131 nlistf = optarg;
132 break;
133 case 'w':
134 interval = atoi(optarg);
135 break;
136 case 's':
137 serverinfo = 1;
138 printall = 0;
139 break;
140 case 'c':
141 clientinfo = 1;
142 printall = 0;
143 break;
144 case '?':
145 default:
146 usage();
148 argc -= optind;
149 argv += optind;
151 #define BACKWARD_COMPATIBILITY
152 #ifdef BACKWARD_COMPATIBILITY
153 if (*argv) {
154 interval = atoi(*argv);
155 if (*++argv) {
156 nlistf = *argv;
157 if (*++argv)
158 memf = *argv;
161 #endif
162 if (nlistf || memf) {
163 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf))
164 == 0)
165 errx(1, "kvm_openfiles: %s", errbuf);
167 if (kvm_nlist(kd, nl) != 0)
168 errx(1, "kvm_nlist: can't get names");
169 nfsstataddr = nl[N_NFSSTAT].n_value;
170 } else {
171 kd = NULL;
174 if (interval)
175 sidewaysintpr(interval);
176 else
177 intpr();
178 exit(0);
181 void
182 getstats(ns)
183 struct nfsstats *ns;
185 size_t size;
186 int mib[3];
188 if (kd) {
189 if (kvm_read(kd, (u_long)nfsstataddr, ns, sizeof(*ns))
190 != sizeof(*ns))
191 errx(1, "kvm_read failed");
192 } else {
193 mib[0] = CTL_VFS;
194 mib[1] = 2; /* XXX from CTL_VFS_NAMES in <sys/mount.h> */
195 mib[2] = NFS_NFSSTATS;
197 size = sizeof(*ns);
198 if (sysctl(mib, 3, ns, &size, NULL, 0) == -1)
199 err(1, "sysctl(NFS_NFSSTATS) failed");
204 * Print a description of the nfs stats.
206 void
207 intpr()
209 struct nfsstats nfsstats;
210 int64_t total;
211 int i;
213 #define PCT(x,y) ((y) == 0 ? 0 : (int)((int64_t)(x) * 100 / (y)))
214 #define NUMPCT(x,y) (x), PCT(x, (x)+(y))
215 #define RPCSTAT(x) (x), PCT(x, total)
217 getstats(&nfsstats);
219 if (printall || clientinfo) {
220 total = 0;
221 for (i = 0; i < NFS_NPROCS; i++)
222 total += nfsstats.rpccnt[i];
223 printf("Client Info:\n");
224 printf("RPC Counts: (%lld call%s)\n", (long long)total,
225 total == 1 ? "" : "s");
227 printf("%10s %14s %14s %14s %14s\n",
228 "null", "getattr", "setattr", "lookup", "access");
229 printf(
230 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
231 RPCSTAT(nfsstats.rpccnt[NFSPROC_NULL]),
232 RPCSTAT(nfsstats.rpccnt[NFSPROC_GETATTR]),
233 RPCSTAT(nfsstats.rpccnt[NFSPROC_SETATTR]),
234 RPCSTAT(nfsstats.rpccnt[NFSPROC_LOOKUP]),
235 RPCSTAT(nfsstats.rpccnt[NFSPROC_ACCESS]));
236 printf("%10s %14s %14s %14s %14s\n",
237 "readlink", "read", "write", "create", "mkdir");
238 printf(
239 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
240 RPCSTAT(nfsstats.rpccnt[NFSPROC_READLINK]),
241 RPCSTAT(nfsstats.rpccnt[NFSPROC_READ]),
242 RPCSTAT(nfsstats.rpccnt[NFSPROC_WRITE]),
243 RPCSTAT(nfsstats.rpccnt[NFSPROC_CREATE]),
244 RPCSTAT(nfsstats.rpccnt[NFSPROC_MKDIR]));
245 printf("%10s %14s %14s %14s %14s\n",
246 "symlink", "mknod", "remove", "rmdir", "rename");
247 printf(
248 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
249 RPCSTAT(nfsstats.rpccnt[NFSPROC_SYMLINK]),
250 RPCSTAT(nfsstats.rpccnt[NFSPROC_MKNOD]),
251 RPCSTAT(nfsstats.rpccnt[NFSPROC_REMOVE]),
252 RPCSTAT(nfsstats.rpccnt[NFSPROC_RMDIR]),
253 RPCSTAT(nfsstats.rpccnt[NFSPROC_RENAME]));
254 printf("%10s %14s %14s %14s %14s\n",
255 "link", "readdir", "readdirplus", "fsstat", "fsinfo");
256 printf(
257 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
258 RPCSTAT(nfsstats.rpccnt[NFSPROC_LINK]),
259 RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIR]),
260 RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIRPLUS]),
261 RPCSTAT(nfsstats.rpccnt[NFSPROC_FSSTAT]),
262 RPCSTAT(nfsstats.rpccnt[NFSPROC_FSINFO]));
263 printf("%10s %14s\n",
264 "pathconf", "commit");
265 printf("%10d %2d%% %10d %2d%%\n",
266 RPCSTAT(nfsstats.rpccnt[NFSPROC_PATHCONF]),
267 RPCSTAT(nfsstats.rpccnt[NFSPROC_COMMIT]));
269 printf("RPC Info:\n");
270 printf("%10s %14s %14s %14s %14s\n",
271 "timeout", "invalid", "unexpected", "retries", "requests");
272 printf("%10d %14d %14d %14d %14d\n",
273 nfsstats.rpctimeouts,
274 nfsstats.rpcinvalid,
275 nfsstats.rpcunexpected,
276 nfsstats.rpcretries,
277 nfsstats.rpcrequests);
279 printf("Cache Info:\n");
280 printf("%10s %14s %14s %14s %14s\n",
281 "attrcache", "lookupcache", "read", "write", "readlink");
282 printf(
283 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
284 NUMPCT(nfsstats.attrcache_hits,
285 nfsstats.attrcache_misses),
286 NUMPCT(nfsstats.lookupcache_hits,
287 nfsstats.lookupcache_misses),
288 NUMPCT(nfsstats.biocache_reads - nfsstats.read_bios,
289 nfsstats.read_bios),
290 NUMPCT(nfsstats.biocache_writes - nfsstats.write_bios,
291 nfsstats.write_bios),
292 NUMPCT(nfsstats.biocache_readlinks - nfsstats.readlink_bios,
293 nfsstats.readlink_bios));
294 printf("%10s %14s\n",
295 "readdir", "direofcache");
296 printf("%10d %2d%% %10d %2d%%\n",
297 NUMPCT(nfsstats.biocache_readdirs - nfsstats.readdir_bios,
298 nfsstats.readdir_bios),
299 NUMPCT(nfsstats.direofcache_hits,
300 nfsstats.direofcache_misses));
303 if (printall || (clientinfo && serverinfo))
304 printf("\n");
306 if (printall || serverinfo) {
307 total = 0;
308 for (i = 0; i < NFS_NPROCS; i++)
309 total += nfsstats.srvrpccnt[i];
310 printf("Server Info:\n");
311 printf("RPC Counts: (%lld call%s)\n", (long long)total,
312 total == 1 ? "" : "s");
314 printf("%10s %14s %14s %14s %14s\n",
315 "null", "getattr", "setattr", "lookup", "access");
316 printf(
317 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
318 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NULL]),
319 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_GETATTR]),
320 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SETATTR]),
321 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LOOKUP]),
322 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_ACCESS]));
323 printf("%10s %14s %14s %14s %14s\n",
324 "readlink", "read", "write", "create", "mkdir");
325 printf(
326 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
327 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READLINK]),
328 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READ]),
329 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_WRITE]),
330 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_CREATE]),
331 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKDIR]));
332 printf("%10s %14s %14s %14s %14s\n",
333 "symlink", "mknod", "remove", "rmdir", "rename");
334 printf(
335 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
336 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SYMLINK]),
337 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKNOD]),
338 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_REMOVE]),
339 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RMDIR]),
340 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RENAME]));
341 printf("%10s %14s %14s %14s %14s\n",
342 "link", "readdir", "readdirplus", "fsstat", "fsinfo");
343 printf(
344 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
345 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LINK]),
346 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIR]),
347 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]),
348 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSSTAT]),
349 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSINFO]));
350 printf("%10s %14s\n",
351 "pathconf", "commit");
352 printf("%10d %2d%% %10d %2d%%\n",
353 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_PATHCONF]),
354 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_COMMIT]));
356 printf("Server Errors:\n");
357 printf("%10s %14s\n",
358 "RPC errors", "faults");
359 printf("%10d %14d\n",
360 nfsstats.srvrpc_errs,
361 nfsstats.srv_errs);
362 printf("Server Cache Stats:\n");
363 printf("%10s %14s %14s %14s\n",
364 "inprogress", "idem", "non-idem", "misses");
365 printf("%10d %14d %14d %14d\n",
366 nfsstats.srvcache_inproghits,
367 nfsstats.srvcache_idemdonehits,
368 nfsstats.srvcache_nonidemdonehits,
369 nfsstats.srvcache_misses);
370 printf("Server Write Gathering:\n");
371 printf("%10s %14s %14s\n",
372 "writes", "write RPC", "OPs saved");
373 printf("%10d %14d %14d %2d%%\n",
374 nfsstats.srvvop_writes,
375 nfsstats.srvrpccnt[NFSPROC_WRITE],
376 NUMPCT(
377 nfsstats.srvrpccnt[NFSPROC_WRITE]-nfsstats.srvvop_writes,
378 nfsstats.srvrpccnt[NFSPROC_WRITE]));
382 u_char signalled; /* set if alarm goes off "early" */
385 * Print a running summary of nfs statistics.
386 * Repeat display every interval seconds, showing statistics
387 * collected over that interval. Assumes that interval is non-zero.
388 * First line printed at top of screen is always cumulative.
390 void
391 sidewaysintpr(interval)
392 u_int interval;
394 struct nfsstats nfsstats;
395 int hdrcnt, oldmask;
396 struct stats {
397 int client[NSHORTPROC];
398 int server[NSHORTPROC];
399 } current, last;
401 (void)signal(SIGALRM, catchalarm);
402 signalled = 0;
403 (void)alarm(interval);
404 memset(&last, 0, sizeof(last));
406 for (hdrcnt = 1;;) {
407 size_t i;
409 if (!--hdrcnt) {
410 printhdr();
411 hdrcnt = 20;
413 getstats(&nfsstats);
414 memset(&current, 0, sizeof(current));
415 for (i = 0; i < NSHORTPROC; i++) {
416 int mask = shortprocs[i].mask;
417 int idx;
419 while ((idx = ffs(mask)) != 0) {
420 idx--;
421 mask &= ~(1 << idx);
422 current.client[i] += nfsstats.rpccnt[idx];
423 current.server[i] += nfsstats.srvrpccnt[idx];
427 if (printall || clientinfo) {
428 printf("Client:");
429 for (i = 0; i < NSHORTPROC; i++)
430 printf(" %7d",
431 current.client[i] - last.client[i]);
432 printf("\n");
434 if (printall || serverinfo) {
435 printf("Server:");
436 for (i = 0; i < NSHORTPROC; i++)
437 printf(" %7d",
438 current.server[i] - last.server[i]);
439 printf("\n");
441 memcpy(&last, &current, sizeof(last));
442 fflush(stdout);
443 oldmask = sigblock(sigmask(SIGALRM));
444 if (!signalled)
445 sigpause(0);
446 sigsetmask(oldmask);
447 signalled = 0;
448 (void)alarm(interval);
450 /*NOTREACHED*/
453 void
454 printhdr()
456 size_t i;
458 printf(" ");
459 for (i = 0; i < NSHORTPROC; i++)
460 printf("%7.7s ", shortprocs[i].name);
461 printf("\n");
462 fflush(stdout);
466 * Called if an interval expires before sidewaysintpr has completed a loop.
467 * Sets a flag to not wait for the alarm.
469 void
470 catchalarm(dummy)
471 int dummy;
474 signalled = 1;
477 void
478 usage()
481 (void)fprintf(stderr,
482 "usage: nfsstat [-cs] [-M core] [-N system] [-w interval]\n");
483 exit(1);