1 /* $NetBSD: nfsstat.c,v 1.22 2008/07/21 14:19:24 lukem Exp $ */
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
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
35 #include <sys/cdefs.h>
37 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\
38 The Regents of the University of California. All rights reserved.");
43 static char sccsid
[] = "from: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93";
45 __RCSID("$NetBSD: nfsstat.c,v 1.22 2008/07/21 14:19:24 lukem Exp $");
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>
73 { "_nfsstats", 0, 0, 0, 0 },
77 #define MASK(a) (1 << NFSPROC_##a)
79 (MASK(GETATTR) | MASK(SETATTR) | MASK(LOOKUP) | MASK(READ) | \
80 MASK(WRITE) | MASK(RENAME)| MASK(ACCESS) | MASK(READDIR) | \
82 #define OTHERMASK (((1 << NFS_NPROCS) - 1) & ~ALLMASK)
83 const struct shortprocs
{
87 {MASK(GETATTR
), "Getattr"},
88 {MASK(SETATTR
), "Setattr"},
89 {MASK(LOOKUP
), "Lookup"},
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));
109 int printall
, clientinfo
, serverinfo
;
120 char errbuf
[_POSIX2_LINE_MAX
];
123 memf
= nlistf
= NULL
;
125 while ((ch
= getopt(argc
, argv
, "M:N:w:cs")) != -1)
134 interval
= atoi(optarg
);
151 #define BACKWARD_COMPATIBILITY
152 #ifdef BACKWARD_COMPATIBILITY
154 interval
= atoi(*argv
);
162 if (nlistf
|| memf
) {
163 if ((kd
= kvm_openfiles(nlistf
, memf
, NULL
, O_RDONLY
, errbuf
))
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
;
175 sidewaysintpr(interval
);
189 if (kvm_read(kd
, (u_long
)nfsstataddr
, ns
, sizeof(*ns
))
191 errx(1, "kvm_read failed");
194 mib
[1] = 2; /* XXX from CTL_VFS_NAMES in <sys/mount.h> */
195 mib
[2] = NFS_NFSSTATS
;
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.
209 struct nfsstats nfsstats
;
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)
219 if (printall
|| clientinfo
) {
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");
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");
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");
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");
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
,
275 nfsstats
.rpcunexpected
,
277 nfsstats
.rpcrequests
);
279 printf("Cache Info:\n");
280 printf("%10s %14s %14s %14s %14s\n",
281 "attrcache", "lookupcache", "read", "write", "readlink");
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
,
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
))
306 if (printall
|| serverinfo
) {
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");
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");
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");
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");
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
,
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
],
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.
391 sidewaysintpr(interval
)
394 struct nfsstats nfsstats
;
397 int client
[NSHORTPROC
];
398 int server
[NSHORTPROC
];
401 (void)signal(SIGALRM
, catchalarm
);
403 (void)alarm(interval
);
404 memset(&last
, 0, sizeof(last
));
414 memset(¤t
, 0, sizeof(current
));
415 for (i
= 0; i
< NSHORTPROC
; i
++) {
416 int mask
= shortprocs
[i
].mask
;
419 while ((idx
= ffs(mask
)) != 0) {
422 current
.client
[i
] += nfsstats
.rpccnt
[idx
];
423 current
.server
[i
] += nfsstats
.srvrpccnt
[idx
];
427 if (printall
|| clientinfo
) {
429 for (i
= 0; i
< NSHORTPROC
; i
++)
431 current
.client
[i
] - last
.client
[i
]);
434 if (printall
|| serverinfo
) {
436 for (i
= 0; i
< NSHORTPROC
; i
++)
438 current
.server
[i
] - last
.server
[i
]);
441 memcpy(&last
, ¤t
, sizeof(last
));
443 oldmask
= sigblock(sigmask(SIGALRM
));
448 (void)alarm(interval
);
459 for (i
= 0; i
< NSHORTPROC
; i
++)
460 printf("%7.7s ", shortprocs
[i
].name
);
466 * Called if an interval expires before sidewaysintpr has completed a loop.
467 * Sets a flag to not wait for the alarm.
481 (void)fprintf(stderr
,
482 "usage: nfsstat [-cs] [-M core] [-N system] [-w interval]\n");