]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/nfsstat/nfsstat.c
zfs: merge openzfs/zfs@797f55ef1
[FreeBSD/FreeBSD.git] / usr.bin / nfsstat / nfsstat.c
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  * 3. 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
64 static 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
71 static char sccsid[] = "@(#)nfsstat.c   8.2 (Berkeley) 3/31/95";
72 #endif
73 #endif /* not lint */
74
75 #include <sys/param.h>
76 #include <sys/module.h>
77 #include <sys/mount.h>
78 #include <sys/time.h>
79 #include <sys/sysctl.h>
80 #include <nfs/nfssvc.h>
81
82 #include <fs/nfs/nfsproto.h>
83 #include <fs/nfs/nfsport.h>
84
85 #include <signal.h>
86 #include <fcntl.h>
87 #include <ctype.h>
88 #include <errno.h>
89 #include <limits.h>
90 #include <nlist.h>
91 #include <unistd.h>
92 #include <stdio.h>
93 #include <stdint.h>
94 #include <stdlib.h>
95 #include <string.h>
96 #include <paths.h>
97 #include <devstat.h>
98 #include <err.h>
99
100 #include <libxo/xo.h>
101
102 static int widemode = 0;
103 static int zflag = 0;
104 static int printtitle = 1;
105 static struct nfsstatsv1 ext_nfsstats;
106 static int extra_output = 0;
107
108 static void intpr(int, int);
109 static void printhdr(int, int, int);
110 static void usage(void) __dead2;
111 static char *sperc1(int, int);
112 static char *sperc2(int, int);
113 static void exp_intpr(int, int, int);
114 static void exp_sidewaysintpr(u_int, int, int, int);
115 static void compute_new_stats(struct nfsstatsv1 *cur_stats,
116     struct nfsstatsv1 *prev_stats, int curop, long double etime,
117     long double *mbsec, long double *kb_per_transfer,
118     long double *transfers_per_second, long double *ms_per_transfer,
119     uint64_t *queue_len, long double *busy_pct);
120
121 #define DELTA(field)    (nfsstats.field - lastst.field)
122
123 #define STAT_TYPE_READ          0
124 #define STAT_TYPE_WRITE         1
125 #define STAT_TYPE_COMMIT        2
126 #define NUM_STAT_TYPES          3
127
128 struct stattypes {
129         int stat_type;
130         int nfs_type;
131 };
132 static struct stattypes statstruct[] = {
133         {STAT_TYPE_READ, NFSV4OP_READ},
134         {STAT_TYPE_WRITE, NFSV4OP_WRITE},
135         {STAT_TYPE_COMMIT, NFSV4OP_COMMIT}
136 };
137
138 #define STAT_TYPE_TO_NFS(stat_type)     statstruct[stat_type].nfs_type
139
140 #define NFSSTAT_XO_VERSION      "1"
141
142 int
143 main(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         int mntlen, i;
151         char buf[1024];
152         struct statfs *mntbuf;
153         struct nfscl_dumpmntopts dumpmntopts;
154
155         interval = 0;
156
157         argc = xo_parse_args(argc, argv);
158         if (argc < 0)
159                 exit(1);
160
161         xo_set_version(NFSSTAT_XO_VERSION);
162
163         while ((ch = getopt(argc, argv, "cdEesWM:mN:w:zq")) != -1)
164                 switch(ch) {
165                 case 'M':
166                         printf("*** -M option deprecated, ignored\n\n");
167                         break;
168                 case 'm':
169                         /* Display mount options for NFS mount points. */
170                         mntlen = getmntinfo(&mntbuf, MNT_NOWAIT);
171                         for (i = 0; i < mntlen; i++) {
172                                 if (strcmp(mntbuf->f_fstypename, "nfs") == 0) {
173                                         dumpmntopts.ndmnt_fname =
174                                             mntbuf->f_mntonname;
175                                         dumpmntopts.ndmnt_buf = buf;
176                                         dumpmntopts.ndmnt_blen = sizeof(buf);
177                                         if (nfssvc(NFSSVC_DUMPMNTOPTS,
178                                             &dumpmntopts) >= 0)
179                                                 printf("%s on %s\n%s\n",
180                                                     mntbuf->f_mntfromname,
181                                                     mntbuf->f_mntonname, buf);
182                                         else if (errno == EPERM)
183                                                 errx(1, "Only privileged users"
184                                                     " can use the -m option");
185                                 }
186                                 mntbuf++;
187                         }
188                         exit(0);
189                 case 'N':
190                         printf("*** -N option deprecated, ignored\n\n");
191                         break;
192                 case 'W':
193                         widemode = 1;
194                         break;
195                 case 'w':
196                         interval = atoi(optarg);
197                         break;
198                 case 'c':
199                         clientOnly = 1;
200                         if (serverOnly < 0)
201                                 serverOnly = 0;
202                         break;
203                 case 'd':
204                         newStats = 1;
205                         if (interval == 0)
206                                 interval = 1;
207                         break;
208                 case 's':
209                         serverOnly = 1;
210                         if (clientOnly < 0)
211                                 clientOnly = 0;
212                         break;
213                 case 'z':
214                         zflag = 1;
215                         break;
216                 case 'E':
217                         if (extra_output != 0)
218                                 xo_err(1, "-e and -E are mutually exclusive");
219                         extra_output = 2;
220                         break;
221                 case 'e':
222                         if (extra_output != 0)
223                                 xo_err(1, "-e and -E are mutually exclusive");
224                         extra_output = 1;
225                         break;
226                 case 'q':
227                         printtitle = 0;
228                         break;
229                 case '?':
230                 default:
231                         usage();
232                 }
233         argc -= optind;
234         argv += optind;
235
236 #define BACKWARD_COMPATIBILITY
237 #ifdef  BACKWARD_COMPATIBILITY
238         if (*argv)
239                 interval = atoi(*argv);
240 #endif
241         if (modfind("nfscommon") < 0)
242                 xo_err(1, "NFS client/server not loaded");
243
244         if (interval) {
245                 exp_sidewaysintpr(interval, clientOnly, serverOnly,
246                     newStats);
247         } else {
248                 xo_open_container("nfsstat");
249                 if (extra_output != 0)
250                         exp_intpr(clientOnly, serverOnly, extra_output - 1);
251                 else
252                         intpr(clientOnly, serverOnly);
253                 xo_close_container("nfsstat");
254         }
255
256         xo_finish();
257         exit(0);
258 }
259
260 /*
261  * Print a description of the nfs stats.
262  */
263 static void
264 intpr(int clientOnly, int serverOnly)
265 {
266         int nfssvc_flag;
267
268         nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
269         if (zflag != 0) {
270                 if (clientOnly != 0)
271                         nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
272                 if (serverOnly != 0)
273                         nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
274         }
275         ext_nfsstats.vers = NFSSTATS_V1;
276         if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
277                 xo_err(1, "Can't get stats");
278         if (clientOnly) {
279                 xo_open_container("clientstats");
280
281                 if (printtitle)
282                         xo_emit("{T:Client Info:\n");
283
284                 xo_open_container("operations");
285                 xo_emit("{T:Rpc Counts:}\n");
286
287                 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
288                     "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
289                     "{T:Read/%13.13s}{T:Write/%13.13s}"
290                   "{T:Create/%13.13s}{T:Remove/%13.13s}\n");
291                 xo_emit("{:getattr/%13ju}{:setattr/%13ju}"
292                     "{:lookup/%13ju}{:readlink/%13ju}"
293                     "{:read/%13ju}{:write/%13ju}"
294                     "{:create/%13ju}{:remove/%13ju}\n",
295                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
296                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
297                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
298                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
299                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
300                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
301                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
302                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
303
304                 xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}"
305                     "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}"
306                     "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
307                   "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n");
308                 xo_emit("{:rename/%13ju}{:link/%13ju}"
309                     "{:symlink/%13ju}{:mkdir/%13ju}"
310                     "{:rmdir/%13ju}{:readdir/%13ju}"
311                     "{:rdirplus/%13ju}{:access/%13ju}\n",
312                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
313                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
314                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
315                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
316                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
317                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
318                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
319                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
320
321                 xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}"
322                     "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}"
323                     "{T:Commit/%13.13s}\n");
324                 xo_emit("{:mknod/%13ju}{:fsstat/%13ju}"
325                     "{:fsinfo/%13ju}{:pathconf/%13ju}"
326                     "{:commit/%13ju}\n",
327                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
328                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
329                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
330                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
331                         (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
332
333                 xo_close_container("operations");
334
335                 xo_open_container("rpcs");
336                 xo_emit("{T:Rpc Info:}\n");
337
338                 xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}"
339                     "{T:X Replies/%13.13s}{T:Retries/%13.13s}"
340                     "{T:Requests/%13.13s}\n");
341                 xo_emit("{:timedout/%13ju}{:invalid/%13ju}"
342                     "{:xreplies/%13ju}{:retries/%13ju}"
343                     "{:requests/%13ju}\n",
344                         (uintmax_t)ext_nfsstats.rpctimeouts,
345                         (uintmax_t)ext_nfsstats.rpcinvalid,
346                         (uintmax_t)ext_nfsstats.rpcunexpected,
347                         (uintmax_t)ext_nfsstats.rpcretries,
348                         (uintmax_t)ext_nfsstats.rpcrequests);
349                 xo_close_container("rpcs");
350
351                 xo_open_container("cache");
352                 xo_emit("{T:Cache Info:}\n");
353
354                 xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}"
355                     "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}"
356                     "{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}"
357                     "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n");
358                 xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}"
359                     "{:lkuphits/%13ju}{:lkupmisses/%13ju}"
360                     "{:biorhits/%13ju}{:biormisses/%13ju}"
361                     "{:biowhits/%13ju}{:biowmisses/%13ju}\n",
362                     (uintmax_t)ext_nfsstats.attrcache_hits,
363                     (uintmax_t)ext_nfsstats.attrcache_misses,
364                     (uintmax_t)ext_nfsstats.lookupcache_hits,
365                     (uintmax_t)ext_nfsstats.lookupcache_misses,
366                     (uintmax_t)(ext_nfsstats.biocache_reads -
367                     ext_nfsstats.read_bios),
368                     (uintmax_t)ext_nfsstats.read_bios,
369                     (uintmax_t)(ext_nfsstats.biocache_writes -
370                     ext_nfsstats.write_bios),
371                     (uintmax_t)ext_nfsstats.write_bios);
372
373                 xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}"
374                     "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}"
375                     "{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}"
376                     "{T:Accs Hits/%13.13s}{T:Accs Misses/%13.13s}\n");
377                 xo_emit("{:biosrlhits/%13ju}{:biorlmisses/%13ju}"
378                     "{:biodhits/%13ju}{:biodmisses/%13ju}"
379                     "{:direhits/%13ju}{:diremisses/%13ju}"
380                     "{:accshits/%13ju}{:accsmisses/%13ju}\n",
381                     (uintmax_t)(ext_nfsstats.biocache_readlinks -
382                     ext_nfsstats.readlink_bios),
383                     (uintmax_t)ext_nfsstats.readlink_bios,
384                     (uintmax_t)(ext_nfsstats.biocache_readdirs -
385                     ext_nfsstats.readdir_bios),
386                     (uintmax_t)ext_nfsstats.readdir_bios,
387                     (uintmax_t)ext_nfsstats.direofcache_hits,
388                     (uintmax_t)ext_nfsstats.direofcache_misses,
389                     (uintmax_t)ext_nfsstats.accesscache_hits,
390                     (uintmax_t)ext_nfsstats.accesscache_misses);
391
392                 xo_close_container("cache");
393
394                 xo_close_container("clientstats");
395         }
396         if (serverOnly) {
397                 xo_open_container("serverstats");
398
399                 xo_emit("{T:Server Info:}\n");
400                 xo_open_container("operations");
401
402                 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
403                     "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
404                     "{T:Read/%13.13s}{T:Write/%13.13s}"
405                     "{T:Create/%13.13s}{T:Remove/%13.13s}\n");
406                 xo_emit("{:getattr/%13ju}{:setattr/%13ju}"
407                     "{:lookup/%13ju}{:readlink/%13ju}"
408                     "{:read/%13ju}{:write/%13ju}"
409                     "{:create/%13ju}{:remove/%13ju}\n",
410                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
411                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
412                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
413                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
414                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
415                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
416                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
417                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
418
419                 xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}"
420                     "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}"
421                     "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
422                     "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n");
423                 xo_emit("{:rename/%13ju}{:link/%13ju}"
424                     "{:symlink/%13ju}{:mkdir/%13ju}"
425                     "{:rmdir/%13ju}{:readdir/%13ju}"
426                     "{:rdirplus/%13ju}{:access/%13ju}\n",
427                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
428                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
429                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
430                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
431                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
432                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
433                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
434                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
435
436                 xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}"
437                     "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}"
438                     "{T:Commit/%13.13s}\n");
439                 xo_emit("{:mknod/%13ju}{:fsstat/%13ju}"
440                     "{:fsinfo/%13ju}{:pathconf/%13ju}"
441                     "{:commit/%13ju}\n",
442                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
443                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
444                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
445                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
446                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
447
448                 xo_close_container("operations");
449
450                 xo_open_container("server");
451
452                 xo_emit("{T:Server Write Gathering:/%13.13s}\n");
453
454                 xo_emit("{T:WriteOps/%13.13s}{T:WriteRPC/%13.13s}"
455                     "{T:Opsaved/%13.13s}\n");
456                 xo_emit("{:writeops/%13ju}{:writerpc/%13ju}"
457                     "{:opsaved/%13ju}\n",
458                 /*
459                  * The new client doesn't do write gathering. It was
460                  * only useful for NFSv2.
461                  */
462                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
463                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
464
465                 xo_close_container("server");
466
467                 xo_open_container("cache");
468                 xo_emit("{T:Server Cache Stats:/%13.13s}\n");
469                 xo_emit("{T:Inprog/%13.13s}"
470                     "{T:Non-Idem/%13.13s}{T:Misses/%13.13s}\n");
471                 xo_emit("{:inprog/%13ju}{:nonidem/%13ju}{:misses/%13ju}\n",
472                         (uintmax_t)ext_nfsstats.srvcache_inproghits,
473                         (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
474                         (uintmax_t)ext_nfsstats.srvcache_misses);
475                 xo_close_container("cache");
476
477                 xo_close_container("serverstats");
478         }
479 }
480
481 static void
482 printhdr(int clientOnly, int serverOnly, int newStats)
483 {
484
485         if (newStats) {
486                 printf(" [%s Read %s]  [%s Write %s]  "
487                     "%s[=========== Total ============]\n"
488                     " KB/t   tps    MB/s%s  KB/t   tps    MB/s%s  "
489                     "%sKB/t   tps    MB/s    ms  ql  %%b",
490                     widemode ? "========" : "=====",
491                     widemode ? "========" : "=====",
492                     widemode ? "========" : "=====",
493                     widemode ? "======="  : "====",
494                     widemode ? "[Commit ]  " : "",
495                     widemode ? "    ms" : "",
496                     widemode ? "    ms" : "",
497                     widemode ? "tps    ms  " : "");
498         } else {
499                 printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
500                     ((serverOnly && clientOnly) ? "        " : " "),
501                     "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename",
502                     "Access", "Rddir");
503                 if (widemode && clientOnly) {
504                         printf(" Attr Lkup BioR BioW Accs BioD");
505                 }
506         }
507         printf("\n");
508         fflush(stdout);
509 }
510
511 static void
512 usage(void)
513 {
514         (void)fprintf(stderr,
515             "usage: nfsstat [-cdemszW] [-w wait]\n");
516         exit(1);
517 }
518
519 static char SPBuf[64][8];
520 static int SPIndex;
521
522 static char * 
523 sperc1(int hits, int misses)
524 {
525         char *p = SPBuf[SPIndex];
526
527         if (hits + misses) {
528                 sprintf(p, "%3d%%", 
529                     (int)(char)((quad_t)hits * 100 / (hits + misses)));
530         } else {
531                 sprintf(p, "   -");
532         }
533         SPIndex = (SPIndex + 1) & 63;
534         return(p);
535 }
536
537 static char * 
538 sperc2(int ttl, int misses)
539 {
540         char *p = SPBuf[SPIndex];
541
542         if (ttl) {
543                 sprintf(p, "%3d%%",
544                     (int)(char)((quad_t)(ttl - misses) * 100 / ttl));
545         } else {
546                 sprintf(p, "   -");
547         }
548         SPIndex = (SPIndex + 1) & 63;
549         return(p);
550 }
551
552 #define DELTA_T(field)                                  \
553         devstat_compute_etime(&cur_stats->field,        \
554         (prev_stats ? &prev_stats->field : NULL))
555
556 /*
557  * XXX KDM mostly copied from ctlstat.  We should commonize the code (and
558  * the devstat code) somehow.
559  */
560 static void
561 compute_new_stats(struct nfsstatsv1 *cur_stats,
562                   struct nfsstatsv1 *prev_stats, int curop,
563                   long double etime, long double *mbsec,
564                   long double *kb_per_transfer,
565                   long double *transfers_per_second,
566                   long double *ms_per_transfer, uint64_t *queue_len,
567                   long double *busy_pct)
568 {
569         uint64_t total_bytes = 0, total_operations = 0;
570         struct bintime total_time_bt;
571         struct timespec total_time_ts;
572
573         bzero(&total_time_bt, sizeof(total_time_bt));
574         bzero(&total_time_ts, sizeof(total_time_ts));
575
576         total_bytes = cur_stats->srvbytes[curop];
577         total_operations = cur_stats->srvops[curop];
578         if (prev_stats != NULL) {
579                 total_bytes -= prev_stats->srvbytes[curop];
580                 total_operations -= prev_stats->srvops[curop];
581         }
582
583         *mbsec = total_bytes;
584         *mbsec /= 1024 * 1024;
585         if (etime > 0.0) {
586                 *busy_pct = DELTA_T(busytime);
587                 if (*busy_pct < 0)
588                         *busy_pct = 0;
589                 *busy_pct /= etime;
590                 *busy_pct *= 100;
591                 if (*busy_pct < 0)
592                         *busy_pct = 0;
593                 *mbsec /= etime;
594         } else {
595                 *busy_pct = 0;
596                 *mbsec = 0;
597         }
598         *kb_per_transfer = total_bytes;
599         *kb_per_transfer /= 1024;
600         if (total_operations > 0)
601                 *kb_per_transfer /= total_operations;
602         else
603                 *kb_per_transfer = 0;
604         if (etime > 0.0) {
605                 *transfers_per_second = total_operations;
606                 *transfers_per_second /= etime;
607         } else {
608                 *transfers_per_second = 0.0;
609         }
610                         
611         if (total_operations > 0) {
612                 *ms_per_transfer = DELTA_T(srvduration[curop]);
613                 *ms_per_transfer /= total_operations;
614                 *ms_per_transfer *= 1000;
615         } else
616                 *ms_per_transfer = 0.0;
617
618         *queue_len = cur_stats->srvstartcnt - cur_stats->srvdonecnt;
619 }
620
621 /*
622  * Print a description of the nfs stats for the client/server,
623  * including NFSv4.1.
624  */
625 static void
626 exp_intpr(int clientOnly, int serverOnly, int nfs41)
627 {
628         int nfssvc_flag;
629
630         xo_open_container("nfsv4");
631
632         nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
633         if (zflag != 0) {
634                 if (clientOnly != 0)
635                         nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
636                 if (serverOnly != 0)
637                         nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
638         }
639         ext_nfsstats.vers = NFSSTATS_V1;
640         if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
641                 xo_err(1, "Can't get stats");
642         if (clientOnly != 0) {
643                 xo_open_container("clientstats");
644
645                 xo_open_container("operations");
646                 if (printtitle) {
647                         xo_emit("{T:Client Info:}\n");
648                         xo_emit("{T:RPC Counts:}\n");
649                 }
650                 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
651                     "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
652                     "{T:Read/%13.13s}{T:Write/%13.13s}\n");
653                 xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}"
654                     "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n",
655                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
656                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
657                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
658                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
659                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
660                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE]);
661                 xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}"
662                     "{T:Rename/%13.13s}{T:Link/%13.13s}"
663                     "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n");
664                 xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}"
665                   "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n",
666                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
667                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE],
668                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
669                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
670                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
671                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR]);
672                 xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
673                     "{T:RdirPlus/%13.13s}{T:Access/%13.13s}"
674                     "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n");
675                 xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}"
676                     "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n",
677                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
678                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
679                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
680                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS],
681                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
682                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT]);
683                 xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}"
684                     "{T:Commit/%13.13s}{T:SetClId/%13.13s}"
685                     "{T:SetClIdCf/%13.13s}{T:Lock/%13.13s}\n");
686                 xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}"
687                     "{:setclientid/%13ju}{:setclientidcf/%13ju}{:lock/%13ju}\n",
688                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
689                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
690                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
691                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
692                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
693                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
694                 xo_emit("{T:LockT/%13.13s}{T:LockU/%13.13s}"
695                     "{T:Open/%13.13s}{T:OpenCfr/%13.13s}\n");
696                 xo_emit("{:lockt/%13ju}{:locku/%13ju}"
697                     "{:open/%13ju}{:opencfr/%13ju}\n",
698                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
699                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
700                     (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
701                   (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);
702
703                 if (nfs41) {
704                         xo_open_container("nfsv41");
705
706                         xo_emit("{T:OpenDownGr/%13.13s}{T:Close/%13.13s}\n");
707                         xo_emit("{:opendowngr/%13ju}{:close/%13ju}\n",
708                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENDOWNGRADE],
709                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CLOSE]);
710
711                         xo_emit("{T:RelLckOwn/%13.13s}{T:FreeStateID/%13.13s}"
712                             "{T:PutRootFH/%13.13s}{T:DelegRet/%13.13s}"
713                             "{T:GetAcl/%13.13s}{T:SetAcl/%13.13s}\n");
714                         xo_emit("{:rellckown/%13ju}{:freestateid/%13ju}"
715                             "{:putrootfh/%13ju}{:delegret/%13ju}"
716                             "{:getacl/%13ju}{:setacl/%13ju}\n",
717                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RELEASELCKOWN],
718                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FREESTATEID],
719                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PUTROOTFH],
720                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DELEGRETURN],
721                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETACL],
722                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETACL]);
723
724                         xo_emit("{T:ExchangeId/%13.13s}{T:CreateSess/%13.13s}"
725                             "{T:DestroySess/%13.13s}{T:DestroyClId/%13.13s}"
726                             "{T:LayoutGet/%13.13s}{T:GetDevInfo/%13.13s}\n");
727                         xo_emit("{:exchangeid/%13ju}{:createsess/%13ju}"
728                             "{:destroysess/%13ju}{:destroyclid/%13ju}"
729                             "{:layoutget/%13ju}{:getdevinfo/%13ju}\n",
730                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_EXCHANGEID],
731                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATESESSION],
732                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYSESSION],
733                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYCLIENT],
734                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTGET],
735                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETDEVICEINFO]);
736
737                         xo_emit("{T:LayoutCommit/%13.13s}{T:LayoutReturn/%13.13s}"
738                             "{T:ReclaimCompl/%13.13s}{T:ReadDataS/%13.13s}"
739                             "{T:WriteDataS/%13.13s}{T:CommitDataS/%13.13s}\n");
740                         xo_emit("{:layoutcomit/%13ju}{:layoutreturn/%13ju}"
741                             "{:reclaimcompl/%13ju}{:readdatas/%13ju}"
742                             "{:writedatas/%13ju}{:commitdatas/%13ju}\n",
743                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTCOMMIT],
744                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTRETURN],
745                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RECLAIMCOMPL],
746                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDS],
747                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITEDS],
748                           (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMITDS]);
749
750                         xo_emit("{T:OpenLayout/%13.13s}{T:CreateLayout/%13.13s}"
751                             "{T:BindConnSess/%13.13s}{T:LookupOpen/%13.13s}"
752                             "{T:AppendWrite/%13.13s}\n");
753                         xo_emit("{:openlayout/%13ju}{:createlayout/%13ju}"
754                             "{:bindconnsess/%13ju}{:lookupopen/%13ju}"
755                             "{:appendwrite/%13ju}\n",
756                          (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENLAYGET],
757                          (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATELAYGET],
758                          (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_BINDCONNTOSESS],
759                          (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUPOPEN],
760                          (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_APPENDWRITE]);
761
762                         xo_close_container("nfsv41");
763
764                         xo_open_container("nfsv42");
765
766                         xo_emit("{T:IOAdvise/%13.13s}{T:Allocate/%13.13s}"
767                             "{T:Copy/%13.13s}{T:Seek/%13.13s}"
768                             "{T:SeekDataS/%13.13s}{T:GetExtattr/%13.13s}\n");
769                         xo_emit("{:ioadvise/%13ju}{:allocate/%13ju}"
770                             "{:copy/%13ju}{:seek/%13ju}"
771                             "{:seekdatas/%13ju}{:getextattr/%13ju}\n",
772                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_IOADVISE],
773                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ALLOCATE],
774                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COPY],
775                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SEEK],
776                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SEEKDS],
777                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETEXTATTR]);
778
779                         xo_emit("{T:SetExtattr/%13.13s}{T:RmExtattr/%13.13s}"
780                             "{T:ListExtattr/%13.13s}{T:Deallocate/%13.13s}"
781                             "{T:LayoutError/%13.13s}\n");
782                         xo_emit("{:setextattr/%13ju}{:rmextattr/%13ju}"
783                             "{:listextattr/%13ju}{:deallocate/%13ju}"
784                             "{:layouterror/%13ju}\n",
785                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETEXTATTR],
786                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMEXTATTR],
787                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LISTEXTATTR],
788                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DEALLOCATE],
789                             (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTERROR]);
790
791                         xo_close_container("nfsv42");
792                 }
793                 xo_close_container("operations");
794
795                 if (printtitle)
796                         xo_emit("{T:Client:}\n");
797                 xo_open_container("client");
798                 xo_emit("{T:OpenOwner/%13.13s}{T:Opens/%13.13s}"
799                     "{T:LockOwner/%13.13s}{T:Locks/%13.13s}"
800                     "{T:Delegs/%13.13s}{T:LocalOwn/%13.13s}\n");
801                 xo_emit("{:openowner/%13ju}{:opens/%13ju}"
802                     "{:lockowner/%13ju}{:locks/%13ju}"
803                     "{:delegs/%13ju}{:localown/%13ju}\n",
804                     (uintmax_t)ext_nfsstats.clopenowners,
805                     (uintmax_t)ext_nfsstats.clopens,
806                     (uintmax_t)ext_nfsstats.cllockowners,
807                     (uintmax_t)ext_nfsstats.cllocks,
808                     (uintmax_t)ext_nfsstats.cldelegates,
809                     (uintmax_t)ext_nfsstats.cllocalopenowners);
810
811                 xo_emit("{T:LocalOpen/%13.13s}{T:LocalLown/%13.13s}"
812                     "{T:LocalLock/%13.13s}{T:Layouts/%13.13s}\n");
813                 xo_emit("{:localopen/%13ju}{:locallown/%13ju}"
814                     "{:locallock/%13ju}{:layouts/%13ju}\n",
815                     (uintmax_t)ext_nfsstats.cllocalopens,
816                     (uintmax_t)ext_nfsstats.cllocallockowners,
817                     (uintmax_t)ext_nfsstats.cllocallocks,
818                     (uintmax_t)ext_nfsstats.cllayouts);
819                 xo_close_container("client");
820
821                 xo_open_container("rpc");
822                 if (printtitle)
823                         xo_emit("{T:Rpc Info:}\n");
824                 xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}"
825                     "{T:X Replies/%13.13s}{T:Retries/%13.13s}"
826                     "{T:Requests/%13.13s}\n");
827                 xo_emit("{:timedout/%13ju}{:invalid/%13ju}"
828                     "{:xreplies/%13ju}{:retries/%13ju}"
829                     "{:requests/%13ju}\n",
830                     (uintmax_t)ext_nfsstats.rpctimeouts,
831                     (uintmax_t)ext_nfsstats.rpcinvalid,
832                     (uintmax_t)ext_nfsstats.rpcunexpected,
833                     (uintmax_t)ext_nfsstats.rpcretries,
834                     (uintmax_t)ext_nfsstats.rpcrequests);
835                 xo_close_container("rpc");
836
837                 xo_open_container("cache");
838                 if (printtitle)
839                         xo_emit("{T:Cache Info:}\n");
840                 xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}"
841                     "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}\n");
842                 xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}"
843                     "{:lkuphits/%13ju}{:lkupmisses/%13ju}\n",
844                     (uintmax_t)ext_nfsstats.attrcache_hits,
845                     (uintmax_t)ext_nfsstats.attrcache_misses,
846                     (uintmax_t)ext_nfsstats.lookupcache_hits,
847                     (uintmax_t)ext_nfsstats.lookupcache_misses);
848
849                 xo_emit("{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}"
850                     "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n");
851                 xo_emit("{:biorhits/%13ju}{:biormisses/%13ju}"
852                     "{:biowhits/%13ju}{:biowmisses/%13ju}\n",
853                     (uintmax_t)(ext_nfsstats.biocache_reads -
854                     ext_nfsstats.read_bios),
855                     (uintmax_t)ext_nfsstats.read_bios,
856                     (uintmax_t)(ext_nfsstats.biocache_writes -
857                     ext_nfsstats.write_bios),
858                     (uintmax_t)ext_nfsstats.write_bios);
859
860                 xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}"
861                     "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}\n");
862                 xo_emit("{:biorlhits/%13ju}{:biorlmisses/%13ju}"
863                     "{:biodhits/%13ju}{:biodmisses/%13ju}\n",
864                     (uintmax_t)(ext_nfsstats.biocache_readlinks -
865                     ext_nfsstats.readlink_bios),
866                     (uintmax_t)ext_nfsstats.readlink_bios,
867                     (uintmax_t)(ext_nfsstats.biocache_readdirs -
868                     ext_nfsstats.readdir_bios),
869                     (uintmax_t)ext_nfsstats.readdir_bios);
870
871                 xo_emit("{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}\n");
872                 xo_emit("{:direhits/%13ju}{:diremisses/%13ju}\n",
873                     (uintmax_t)ext_nfsstats.direofcache_hits,
874                     (uintmax_t)ext_nfsstats.direofcache_misses);
875                 xo_open_container("cache");
876
877                 xo_close_container("clientstats");
878         }
879         if (serverOnly != 0) {
880                 xo_open_container("serverstats");
881
882                 xo_open_container("operations");
883                 if (printtitle)
884                         xo_emit("{T:Server Info:}\n");
885                 xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
886                     "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
887                     "{T:Read/%13.13s}{T:Write/%13.13s}\n");
888                 xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}"
889                     "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n",
890                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
891                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
892                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
893                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
894                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
895                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE]);
896                 xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}"
897                     "{T:Rename/%13.13s}{T:Link/%13.13s}"
898                     "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n");
899                 xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}"
900                     "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n",
901                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
902                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE],
903                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
904                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
905                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
906                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR]);
907                 xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
908                     "{T:RdirPlus/%13.13s}{T:Access/%13.13s}"
909                     "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n");
910                 xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}"
911                     "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n",
912                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
913                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
914                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
915                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS],
916                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
917                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT]);
918                 xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}"
919                     "{T:Commit/%13.13s}{T:LookupP/%13.13s}"
920                     "{T:SetClId/%13.13s}{T:SetClIdCf/%13.13s}\n");
921                 xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}"
922                     "{:lookupp/%13ju}{:setclientid/%13ju}{:setclientidcfrm/%13ju}\n",
923                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
924                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
925                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
926                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
927                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
928                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
929                 xo_emit("{T:Open/%13.13s}{T:OpenAttr/%13.13s}"
930                     "{T:OpenDwnGr/%13.13s}{T:OpenCfrm/%13.13s}"
931                     "{T:DelePurge/%13.13s}{T:DelRet/%13.13s}\n");
932                 xo_emit("{:open/%13ju}{:openattr/%13ju}{:opendwgr/%13ju}"
933                     "{:opencfrm/%13ju}{:delepurge/%13ju}{:delreg/%13ju}\n",
934                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
935                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
936                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
937                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
938                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
939                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN]);
940                 xo_emit("{T:GetFH/%13.13s}{T:Lock/%13.13s}"
941                     "{T:LockT/%13.13s}{T:LockU/%13.13s}"
942                     "{T:Close/%13.13s}{T:Verify/%13.13s}\n");
943                 xo_emit("{:getfh/%13ju}{:lock/%13ju}{:lockt/%13ju}"
944                     "{:locku/%13ju}{:close/%13ju}{:verify/%13ju}\n",
945                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
946                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK],
947                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
948                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
949                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
950                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY]);
951                 xo_emit("{T:NVerify/%13.13s}{T:PutFH/%13.13s}"
952                     "{T:PutPubFH/%13.13s}{T:PutRootFH/%13.13s}"
953                     "{T:Renew/%13.13s}{T:RestoreFH/%13.13s}\n");
954                 xo_emit("{:nverify/%13ju}{:putfh/%13ju}{:putpubfh/%13ju}"
955                     "{:putrootfh/%13ju}{:renew/%13ju}{:restore/%13ju}\n",
956                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
957                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
958                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
959                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH],
960                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
961                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH]);
962                 xo_emit("{T:SaveFH/%13.13s}{T:Secinfo/%13.13s}"
963                     "{T:RelLockOwn/%13.13s}{T:V4Create/%13.13s}\n");
964                 xo_emit("{:savefh/%13ju}{:secinfo/%13ju}{:rellockown/%13ju}"
965                     "{:v4create/%13ju}\n",
966                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
967                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
968                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
969                     (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
970                 if (nfs41) {
971                         xo_open_container("nfsv41");
972                         xo_emit("{T:BackChannelCtrl/%13.13s}{T:BindConnToSess/%13.13s}"
973                             "{T:ExchangeID/%13.13s}{T:CreateSess/%13.13s}"
974                             "{T:DestroySess/%13.13s}{T:FreeStateID/%13.13s}\n");
975                         xo_emit("{:backchannelctrl/%13ju}{:bindconntosess/%13ju}"
976                             "{:exchangeid/%13ju}{:createsess/%13ju}"
977                             "{:destroysess/%13ju}{:freestateid/%13ju}\n",
978                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BACKCHANNELCTL],
979                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BINDCONNTOSESS],
980                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_EXCHANGEID],
981                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATESESSION],
982                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYSESSION],
983                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FREESTATEID]),
984
985                         xo_emit("{T:GetDirDeleg/%13.13s}{T:GetDevInfo/%13.13s}"
986                             "{T:GetDevList/%13.13s}{T:layoutCommit/%13.13s}"
987                             "{T:LayoutGet/%13.13s}{T:LayoutReturn/%13.13s}\n");
988                         xo_emit("{:getdirdeleg/%13ju}{:getdevinfo/%13ju}"
989                             "{:getdevlist/%13ju}{:layoutcommit/%13ju}"
990                             "{:layoutget/%13ju}{:layoutreturn/%13ju}\n",
991                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDIRDELEG],
992                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVINFO],
993                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVLIST],
994                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTCOMMIT],
995                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTGET],
996                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTRETURN]);
997
998                         xo_emit("{T:SecInfNoName/%13.13s}{T:Sequence/%13.13s}"
999                             "{T:SetSSV/%13.13s}{T:TestStateID/%13.13s}"
1000                             "{T:WantDeleg/%13.13s}{T:DestroyClId/%13.13s}\n");
1001                         xo_emit("{:secinfnoname/%13ju}{:sequence/%13ju}"
1002                             "{:setssv/%13ju}{:teststateid/%13ju}{:wantdeleg/%13ju}"
1003                             "{:destroyclid/%13ju}\n",
1004                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFONONAME],
1005                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEQUENCE],
1006                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETSSV],
1007                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_TESTSTATEID],
1008                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WANTDELEG],
1009                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYCLIENTID]);
1010
1011                         xo_emit("{T:ReclaimCompl/%13.13s}\n");
1012                         xo_emit("{:reclaimcompl/%13ju}\n",
1013                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RECLAIMCOMPL]);
1014
1015                         xo_close_container("nfsv41");
1016
1017                         xo_open_container("nfsv42");
1018
1019                         xo_emit("{T:Allocate/%13.13s}{T:Copy/%13.13s}"
1020                             "{T:CopyNotify/%13.13s}{T:Deallocate/%13.13s}"
1021                             "{T:IOAdvise/%13.13s}{T:LayoutError/%13.13s}\n");
1022                         xo_emit("{:allocate/%13ju}{:copy/%13ju}"
1023                             "{:copynotify/%13ju}{:deallocate/%13ju}"
1024                             "{:ioadvise/%13ju}{:layouterror/%13ju}\n",
1025                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ALLOCATE],
1026                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COPY],
1027                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COPYNOTIFY],
1028                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DEALLOCATE],
1029                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_IOADVISE],
1030                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTERROR]);
1031
1032                         xo_emit("{T:LayoutStats/%13.13s}{T:OffloadCncl/%13.13s}"
1033                             "{T:OffloadStat/%13.13s}{T:ReadPlus/%13.13s}"
1034                             "{T:Seek/%13.13s}{T:WriteSame/%13.13s}\n");
1035                         xo_emit("{:layoutstats/%13ju}{:offloadcncl/%13ju}"
1036                             "{:offloadstat/%13ju}{:readplus/%13ju}"
1037                             "{:seek/%13ju}{:writesame/%13ju}\n",
1038                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTSTATS],
1039                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OFFLOADCANCEL],
1040                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OFFLOADSTATUS],
1041                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READPLUS],
1042                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEEK],
1043                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITESAME]);
1044
1045                         xo_emit("{T:Clone/%13.13s}{T:GetExtattr/%13.13s}"
1046                             "{T:SetExtattr/%13.13s}{T:ListExtattr/%13.13s}"
1047                             "{T:RmExtattr/%13.13s}\n");
1048                         xo_emit("{:clone/%13ju}{:getextattr/%13ju}"
1049                             "{:setextattr/%13ju}{:listextattr/%13ju}"
1050                             "{:rmextattr/%13ju}\n",
1051                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLONE],
1052                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETXATTR],
1053                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETXATTR],
1054                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LISTXATTRS],
1055                             (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVEXATTR]);
1056
1057                         xo_close_container("nfsv42");
1058                 }
1059
1060                 xo_close_container("operations");
1061
1062                 if (printtitle)
1063                         xo_emit("{T:Server:}\n");
1064                 xo_open_container("server");
1065                 xo_emit("{T:Clients/%13.13s}{T:OpenOwner/%13.13s}"
1066                     "{T:Opens/%13.13s}{T:LockOwner/%13.13s}{T:Locks/%13.13s}"
1067                     "{T:Delegs/%13.13s}\n");
1068                 xo_emit("{:clients/%13ju}{:openowner/%13ju}{:opens/%13ju}"
1069                     "{:lockowner/%13ju}{:locks/%13ju}{:delegs/%13ju}\n",
1070                     (uintmax_t)ext_nfsstats.srvclients,
1071                     (uintmax_t)ext_nfsstats.srvopenowners,
1072                     (uintmax_t)ext_nfsstats.srvopens,
1073                     (uintmax_t)ext_nfsstats.srvlockowners,
1074                     (uintmax_t)ext_nfsstats.srvlocks,
1075                     (uintmax_t)ext_nfsstats.srvdelegates);
1076                 xo_emit("{T:Layouts/%13.13s}\n");
1077                 xo_emit("{:layouts/%13ju}\n",
1078                     (uintmax_t)ext_nfsstats.srvlayouts);
1079                 xo_close_container("server");
1080
1081                 if (printtitle)
1082                         xo_emit("{T:Server Cache Stats:}\n");
1083                 xo_open_container("cache");
1084                 xo_emit("{T:Inprog/%13.13s}"
1085                     "{T:Non-idem/%13.13s}{T:Misses/%13.13s}"
1086                     "{T:CacheSize/%13.13s}{T:TCPPeak/%13.13s}\n");
1087                 xo_emit("{:inprog/%13ju}{:nonidem/%13ju}"
1088                     "{:misses/%13ju}{:cachesize/%13ju}{:tcppeak/%13ju}\n",
1089                     (uintmax_t)ext_nfsstats.srvcache_inproghits,
1090                     (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
1091                     (uintmax_t)ext_nfsstats.srvcache_misses,
1092                     (uintmax_t)ext_nfsstats.srvcache_size,
1093                     (uintmax_t)ext_nfsstats.srvcache_tcppeak);
1094                 xo_close_container("cache");
1095
1096                 xo_close_container("serverstats");
1097         }
1098
1099         xo_close_container("nfsv4");
1100 }
1101
1102 static void
1103 compute_totals(struct nfsstatsv1 *total_stats, struct nfsstatsv1 *cur_stats)
1104 {
1105         int i;
1106
1107         bzero(total_stats, sizeof(*total_stats));
1108         for (i = 0; i < (NFSV42_NOPS + NFSV4OP_FAKENOPS); i++) {
1109                 total_stats->srvbytes[0] += cur_stats->srvbytes[i];
1110                 total_stats->srvops[0] += cur_stats->srvops[i];
1111                 bintime_add(&total_stats->srvduration[0],
1112                             &cur_stats->srvduration[i]);
1113                 total_stats->srvrpccnt[i] = cur_stats->srvrpccnt[i];
1114         }
1115         total_stats->srvstartcnt = cur_stats->srvstartcnt;
1116         total_stats->srvdonecnt = cur_stats->srvdonecnt;
1117         total_stats->busytime = cur_stats->busytime;
1118
1119 }
1120
1121 /*
1122  * Print a running summary of nfs statistics for the experimental client and/or
1123  * server.
1124  * Repeat display every interval seconds, showing statistics
1125  * collected over that interval.  Assumes that interval is non-zero.
1126  * First line printed at top of screen is always cumulative.
1127  */
1128 static void
1129 exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly,
1130     int newStats)
1131 {
1132         struct nfsstatsv1 nfsstats, lastst, *ext_nfsstatsp;
1133         struct nfsstatsv1 curtotal, lasttotal;
1134         struct timespec ts, lastts;
1135         int hdrcnt = 1;
1136
1137         ext_nfsstatsp = &lastst;
1138         ext_nfsstatsp->vers = NFSSTATS_V1;
1139         if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) < 0)
1140                 err(1, "Can't get stats");
1141         clock_gettime(CLOCK_MONOTONIC, &lastts);
1142         compute_totals(&lasttotal, ext_nfsstatsp);
1143         sleep(interval);
1144
1145         for (;;) {
1146                 ext_nfsstatsp = &nfsstats;
1147                 ext_nfsstatsp->vers = NFSSTATS_V1;
1148                 if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp)
1149                     < 0)
1150                         err(1, "Can't get stats");
1151                 clock_gettime(CLOCK_MONOTONIC, &ts);
1152
1153                 if (--hdrcnt == 0) {
1154                         printhdr(clientOnly, serverOnly, newStats);
1155                         if (newStats)
1156                                 hdrcnt = 20;
1157                         else if (clientOnly && serverOnly)
1158                                 hdrcnt = 10;
1159                         else
1160                                 hdrcnt = 20;
1161                 }
1162                 if (clientOnly && newStats == 0) {
1163                     printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
1164                         ((clientOnly && serverOnly) ? "Client:" : ""),
1165                         (uintmax_t)DELTA(rpccnt[NFSPROC_GETATTR]),
1166                         (uintmax_t)DELTA(rpccnt[NFSPROC_LOOKUP]),
1167                         (uintmax_t)DELTA(rpccnt[NFSPROC_READLINK]),
1168                         (uintmax_t)DELTA(rpccnt[NFSPROC_READ]),
1169                         (uintmax_t)DELTA(rpccnt[NFSPROC_WRITE]),
1170                         (uintmax_t)DELTA(rpccnt[NFSPROC_RENAME]),
1171                         (uintmax_t)DELTA(rpccnt[NFSPROC_ACCESS]),
1172                         (uintmax_t)(DELTA(rpccnt[NFSPROC_READDIR]) +
1173                         DELTA(rpccnt[NFSPROC_READDIRPLUS]))
1174                     );
1175                     if (widemode) {
1176                             printf(" %s %s %s %s %s %s",
1177                                 sperc1(DELTA(attrcache_hits),
1178                                     DELTA(attrcache_misses)),
1179                                 sperc1(DELTA(lookupcache_hits), 
1180                                     DELTA(lookupcache_misses)),
1181                                 sperc2(DELTA(biocache_reads),
1182                                     DELTA(read_bios)),
1183                                 sperc2(DELTA(biocache_writes),
1184                                     DELTA(write_bios)),
1185                                 sperc1(DELTA(accesscache_hits),
1186                                     DELTA(accesscache_misses)),
1187                                 sperc2(DELTA(biocache_readdirs),
1188                                     DELTA(readdir_bios))
1189                             );
1190                     }
1191                     printf("\n");
1192                 }
1193
1194                 if (serverOnly && newStats) {
1195                         long double cur_secs, last_secs, etime;
1196                         long double mbsec;
1197                         long double kb_per_transfer;
1198                         long double transfers_per_second;
1199                         long double ms_per_transfer;
1200                         uint64_t queue_len;
1201                         long double busy_pct;
1202                         int i;
1203
1204                         cur_secs = ts.tv_sec +
1205                             ((long double)ts.tv_nsec / 1000000000);
1206                         last_secs = lastts.tv_sec +
1207                             ((long double)lastts.tv_nsec / 1000000000);
1208                         etime = cur_secs - last_secs;
1209
1210                         compute_totals(&curtotal, &nfsstats);
1211
1212                         for (i = 0; i < NUM_STAT_TYPES; i++) {
1213                                 compute_new_stats(&nfsstats, &lastst,
1214                                     STAT_TYPE_TO_NFS(i), etime, &mbsec,
1215                                     &kb_per_transfer,
1216                                     &transfers_per_second,
1217                                     &ms_per_transfer, &queue_len,
1218                                     &busy_pct);
1219
1220                                 if (i == STAT_TYPE_COMMIT) {
1221                                         if (widemode == 0)
1222                                                 continue;
1223
1224                                         printf("%2.0Lf %7.2Lf ",
1225                                             transfers_per_second,
1226                                             ms_per_transfer);
1227                                 } else {
1228                                         printf("%5.2Lf %5.0Lf %7.2Lf ",
1229                                             kb_per_transfer,
1230                                             transfers_per_second, mbsec);
1231                                         if (widemode)
1232                                                 printf("%5.2Lf ",
1233                                                     ms_per_transfer);
1234                                 }
1235                         }
1236
1237                         compute_new_stats(&curtotal, &lasttotal, 0, etime,
1238                             &mbsec, &kb_per_transfer, &transfers_per_second,
1239                             &ms_per_transfer, &queue_len, &busy_pct);
1240
1241                         printf("%5.2Lf %5.0Lf %7.2Lf %5.2Lf %3ju %3.0Lf\n",
1242                             kb_per_transfer, transfers_per_second, mbsec,
1243                             ms_per_transfer, queue_len, busy_pct);
1244                 } else if (serverOnly) {
1245                     printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
1246                         ((clientOnly && serverOnly) ? "Server:" : ""),
1247                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_GETATTR]),
1248                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_LOOKUP]),
1249                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_READLINK]),
1250                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_READ]),
1251                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_WRITE]),
1252                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_RENAME]),
1253                         (uintmax_t)DELTA(srvrpccnt[NFSV4OP_ACCESS]),
1254                         (uintmax_t)(DELTA(srvrpccnt[NFSV4OP_READDIR]) +
1255                         DELTA(srvrpccnt[NFSV4OP_READDIRPLUS])));
1256                     printf("\n");
1257                 }
1258                 bcopy(&nfsstats, &lastst, sizeof(lastst));
1259                 bcopy(&curtotal, &lasttotal, sizeof(lasttotal));
1260                 lastts = ts;
1261                 fflush(stdout);
1262                 sleep(interval);
1263         }
1264         /*NOTREACHED*/
1265 }