nfsstat.c revision 1.20 1 /* $NetBSD: nfsstat.c,v 1.20 2006/12/27 21:53:58 dogcow Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
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.
21 *
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.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\n\
38 The Regents of the University of California. All rights reserved.\n");
39 #endif /* not lint */
40
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.20 2006/12/27 21:53:58 dogcow Exp $");
46 #endif
47 #endif /* not lint */
48
49 #include <sys/param.h>
50 #include <sys/mount.h>
51 #include <sys/sysctl.h>
52
53 #include <nfs/rpcv2.h>
54 #include <nfs/nfsproto.h>
55 #include <nfs/nfs.h>
56
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>
70
71 struct nlist nl[] = {
72 #define N_NFSSTAT 0
73 { "_nfsstats" },
74 { "" },
75 };
76
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"},
96 };
97
98 #define NSHORTPROC (sizeof(shortprocs)/sizeof(shortprocs[0]))
99
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));
107
108 kvm_t *kd;
109 int printall, clientinfo, serverinfo;
110 u_long nfsstataddr;
111
112 int
113 main(argc, argv)
114 int argc;
115 char **argv;
116 {
117 u_int interval;
118 int ch;
119 char *memf, *nlistf;
120 char errbuf[_POSIX2_LINE_MAX];
121
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();
147 }
148 argc -= optind;
149 argv += optind;
150
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;
159 }
160 }
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);
166
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;
172 }
173
174 if (interval)
175 sidewaysintpr(interval);
176 else
177 intpr();
178 exit(0);
179 }
180
181 void
182 getstats(ns)
183 struct nfsstats *ns;
184 {
185 size_t size;
186 int mib[3];
187
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;
196
197 size = sizeof(*ns);
198 if (sysctl(mib, 3, ns, &size, NULL, 0) == -1)
199 err(1, "sysctl(NFS_NFSSTATS) failed");
200 }
201 }
202
203 /*
204 * Print a description of the nfs stats.
205 */
206 void
207 intpr()
208 {
209 struct nfsstats nfsstats;
210 int64_t total;
211 int i;
212
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)
216
217 getstats(&nfsstats);
218
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");
226
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 %14s %14s %14s\n",
264 "pathconf", "commit", "getlease", "vacated", "evicted");
265 printf("%10d %2d%% %10d %2d%%\n",
266 RPCSTAT(nfsstats.rpccnt[NFSPROC_PATHCONF]),
267 RPCSTAT(nfsstats.rpccnt[NFSPROC_COMMIT]));
268 printf("%10s\n", "noop");
269 printf("%10d %2d%%\n",
270 RPCSTAT(nfsstats.rpccnt[NFSPROC_NOOP]));
271
272 printf("RPC Info:\n");
273 printf("%10s %14s %14s %14s %14s\n",
274 "timeout", "invalid", "unexpected", "retries", "requests");
275 printf("%10d %14d %14d %14d %14d\n",
276 nfsstats.rpctimeouts,
277 nfsstats.rpcinvalid,
278 nfsstats.rpcunexpected,
279 nfsstats.rpcretries,
280 nfsstats.rpcrequests);
281
282 printf("Cache Info:\n");
283 printf("%10s %14s %14s %14s %14s\n",
284 "attrcache", "lookupcache", "read", "write", "readlink");
285 printf(
286 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
287 NUMPCT(nfsstats.attrcache_hits,
288 nfsstats.attrcache_misses),
289 NUMPCT(nfsstats.lookupcache_hits,
290 nfsstats.lookupcache_misses),
291 NUMPCT(nfsstats.biocache_reads - nfsstats.read_bios,
292 nfsstats.read_bios),
293 NUMPCT(nfsstats.biocache_writes - nfsstats.write_bios,
294 nfsstats.write_bios),
295 NUMPCT(nfsstats.biocache_readlinks - nfsstats.readlink_bios,
296 nfsstats.readlink_bios));
297 printf("%10s %14s\n",
298 "readdir", "direofcache");
299 printf("%10d %2d%% %10d %2d%%\n",
300 NUMPCT(nfsstats.biocache_readdirs - nfsstats.readdir_bios,
301 nfsstats.readdir_bios),
302 NUMPCT(nfsstats.direofcache_hits,
303 nfsstats.direofcache_misses));
304 }
305
306 if (printall || (clientinfo && serverinfo))
307 printf("\n");
308
309 if (printall || serverinfo) {
310 total = 0;
311 for (i = 0; i < NFS_NPROCS; i++)
312 total += nfsstats.srvrpccnt[i];
313 printf("Server Info:\n");
314 printf("RPC Counts: (%lld call%s)\n", (long long)total,
315 total == 1 ? "" : "s");
316
317 printf("%10s %14s %14s %14s %14s\n",
318 "null", "getattr", "setattr", "lookup", "access");
319 printf(
320 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
321 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NULL]),
322 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_GETATTR]),
323 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SETATTR]),
324 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LOOKUP]),
325 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_ACCESS]));
326 printf("%10s %14s %14s %14s %14s\n",
327 "readlink", "read", "write", "create", "mkdir");
328 printf(
329 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
330 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READLINK]),
331 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READ]),
332 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_WRITE]),
333 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_CREATE]),
334 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKDIR]));
335 printf("%10s %14s %14s %14s %14s\n",
336 "symlink", "mknod", "remove", "rmdir", "rename");
337 printf(
338 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
339 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SYMLINK]),
340 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKNOD]),
341 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_REMOVE]),
342 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RMDIR]),
343 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RENAME]));
344 printf("%10s %14s %14s %14s %14s\n",
345 "link", "readdir", "readdirplus", "fsstat", "fsinfo");
346 printf(
347 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n",
348 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LINK]),
349 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIR]),
350 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]),
351 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSSTAT]),
352 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSINFO]));
353 printf("%10s %14s %14s %14s %14s\n",
354 "pathconf", "commit", "getlease", "vacated", "evicted");
355 printf("%10d %2d%% %10d %2d%%\n",
356 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_PATHCONF]),
357 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_COMMIT]));
358 printf("%10s\n", "noop");
359 printf("%10d %2d%%\n",
360 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NOOP]));
361
362 printf("Server Errors:\n");
363 printf("%10s %14s\n",
364 "RPC errors", "faults");
365 printf("%10d %14d\n",
366 nfsstats.srvrpc_errs,
367 nfsstats.srv_errs);
368 printf("Server Cache Stats:\n");
369 printf("%10s %14s %14s %14s\n",
370 "inprogress", "idem", "non-idem", "misses");
371 printf("%10d %14d %14d %14d\n",
372 nfsstats.srvcache_inproghits,
373 nfsstats.srvcache_idemdonehits,
374 nfsstats.srvcache_nonidemdonehits,
375 nfsstats.srvcache_misses);
376 printf("Server Write Gathering:\n");
377 printf("%10s %14s %14s\n",
378 "writes", "write RPC", "OPs saved");
379 printf("%10d %14d %14d %2d%%\n",
380 nfsstats.srvvop_writes,
381 nfsstats.srvrpccnt[NFSPROC_WRITE],
382 NUMPCT(
383 nfsstats.srvrpccnt[NFSPROC_WRITE]-nfsstats.srvvop_writes,
384 nfsstats.srvrpccnt[NFSPROC_WRITE]));
385 }
386 }
387
388 u_char signalled; /* set if alarm goes off "early" */
389
390 /*
391 * Print a running summary of nfs statistics.
392 * Repeat display every interval seconds, showing statistics
393 * collected over that interval. Assumes that interval is non-zero.
394 * First line printed at top of screen is always cumulative.
395 */
396 void
397 sidewaysintpr(interval)
398 u_int interval;
399 {
400 struct nfsstats nfsstats;
401 int hdrcnt, oldmask;
402 struct stats {
403 int client[NSHORTPROC];
404 int server[NSHORTPROC];
405 } current, last;
406
407 (void)signal(SIGALRM, catchalarm);
408 signalled = 0;
409 (void)alarm(interval);
410 memset(&last, 0, sizeof(last));
411
412 for (hdrcnt = 1;;) {
413 int i;
414
415 if (!--hdrcnt) {
416 printhdr();
417 hdrcnt = 20;
418 }
419 getstats(&nfsstats);
420 memset(¤t, 0, sizeof(current));
421 for (i = 0; i < NSHORTPROC; i++) {
422 int mask = shortprocs[i].mask;
423 int idx;
424
425 while ((idx = ffs(mask)) != 0) {
426 idx--;
427 mask &= ~(1 << idx);
428 current.client[i] += nfsstats.rpccnt[idx];
429 current.server[i] += nfsstats.srvrpccnt[idx];
430 }
431 }
432
433 if (printall || clientinfo) {
434 printf("Client:");
435 for (i = 0; i < NSHORTPROC; i++)
436 printf(" %7d",
437 current.client[i] - last.client[i]);
438 printf("\n");
439 }
440 if (printall || serverinfo) {
441 printf("Server:");
442 for (i = 0; i < NSHORTPROC; i++)
443 printf(" %7d",
444 current.server[i] - last.server[i]);
445 printf("\n");
446 }
447 memcpy(&last, ¤t, sizeof(last));
448 fflush(stdout);
449 oldmask = sigblock(sigmask(SIGALRM));
450 if (!signalled)
451 sigpause(0);
452 sigsetmask(oldmask);
453 signalled = 0;
454 (void)alarm(interval);
455 }
456 /*NOTREACHED*/
457 }
458
459 void
460 printhdr()
461 {
462 int i;
463
464 printf(" ");
465 for (i = 0; i < NSHORTPROC; i++)
466 printf("%7.7s ", shortprocs[i].name);
467 printf("\n");
468 fflush(stdout);
469 }
470
471 /*
472 * Called if an interval expires before sidewaysintpr has completed a loop.
473 * Sets a flag to not wait for the alarm.
474 */
475 void
476 catchalarm(dummy)
477 int dummy;
478 {
479
480 signalled = 1;
481 }
482
483 void
484 usage()
485 {
486
487 (void)fprintf(stderr,
488 "usage: nfsstat [-cs] [-M core] [-N system] [-w interval]\n");
489 exit(1);
490 }
491