#ifndef lint static char sccsid[] = "@(#)nfsstat.c 1.2 88/05/17 4.0NFSSRC Copyr 1988 Sun Micro"; #endif /* * Copyright (c) 1984 by Sun Microsystems, Inc. */ /* * nfsstat: Network File System statistics */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include # include /* * client side rpc statistics * NOTE: These data structures must match the kernel ones in nfs_stat.h! */ struct rcstat { int rccalls; int rcbadcalls; int rcretrans; int rcbadxids; int rctimeouts; int rcwaits; int rcnewcreds; int rcbadverfs; } rcstat; /* * client side nfs statistics */ struct clstat { int nclsleeps; /* client handle waits */ int nclgets; /* client handle gets */ int ncalls; /* client requests */ int nbadcalls; /* rpc failures */ int reqs[32]; /* count of each request */ } clstat, clstat3; /* * Server side rpc statistics */ struct rsstat { int rscalls; int rsbadcalls; int rsnullrecv; int rsbadlen; int rsxdrcall; int rsduphits; /* duplicate request cache hits */ int rsdupage; /* average age of recycled cache entries */ } rsstat; /* * server side nfs statistics */ struct svstat { int ncalls; /* number of calls received */ int nbadcalls; /* calls that failed */ int reqs[32]; /* count for each request */ } svstat, svstat3; static int ccode = 1; /* SGI doesn't separate these two */ static int scode = 1; /* Identify server and client code present */ static int Interval = 1; /* seconds for below */ static int Cflag = 0; /* Continuous stat display */ static int gotstats = 0; static void disp(int); static void getstats(void); static void putstats(void); static void cr_print(int); static void sr_print(int); static void cn_print(int); static void cn_print3(int); static void sn_print(int); static void sn_print3(int); static void req_print(u_int *, u_int, char **, int); static void usage(void); main(argc, argv) char *argv[]; { int cflag = 0; /* client stats */ int sflag = 0; /* server stats */ int nflag = 0; /* nfs stats */ int rflag = 0; /* rpc stats */ int zflag = 0; /* zero stats after printing */ int c; opterr = 0; while ((c = getopt(argc, argv, "Ccnrsz")) != EOF) switch (c) { case 'C': Cflag++; break; case 'c': cflag++; break; case 'n': nflag++; break; case 'r': rflag++; break; case 's': sflag++; break; case 'z': if (getuid()) { fprintf(stderr, "Must be root for z flag\n"); exit(1); } zflag++; break; default: usage(); } if (optind < argc) { Interval = atoi(argv[optind]); if (Interval > 0) optind++; } if (optind < argc) usage(); if (Cflag) disp(sflag ? 1 : 0); getstats(); if (sflag && (!scode)) { fprintf(stderr,"nfsstat: kernel is not configured with the server nfs and rpc code.\n"); } if ((sflag || (!sflag && !cflag)) && scode) { if (rflag || (!rflag && !nflag)) { sr_print(zflag); } if (nflag || (!rflag && !nflag)) { sn_print(zflag); sn_print3(zflag); } } if (cflag && (!ccode)) { fprintf(stderr,"nfsstat: kernel is not configured with the client nfs and rpc code.\n"); } if ((cflag || (!sflag && !cflag)) && ccode) { if (rflag || (!rflag && !nflag)) { cr_print(zflag); } if (nflag || (!rflag && !nflag)) { cn_print(zflag); cn_print3(zflag); } } if (zflag) { putstats(); } exit(0); } static void getstats() { gotstats++; if (ccode) { if (sysmp(MP_SAGET, MPSA_RCSTAT, &rcstat, sizeof(rcstat)) == -1) { fprintf(stderr,"can't read rcstat\n"); exit(1); } if (sysmp(MP_SAGET, MPSA_CLSTAT, &clstat, sizeof(clstat)) == -1) { fprintf(stderr,"can't read clstat\n"); exit(1); } if (sysmp(MP_SAGET, MPSA_CLSTAT3, &clstat3, sizeof(clstat)) == -1) { fprintf(stderr,"can't read clstat3\n"); exit(1); } } if (scode) { if (sysmp(MP_SAGET, MPSA_RSSTAT, &rsstat, sizeof(rsstat)) == -1) { fprintf(stderr,"can't read rsstat\n"); exit(1); } if (sysmp(MP_SAGET, MPSA_SVSTAT, &svstat, sizeof(svstat)) == -1) { fprintf(stderr,"can't read svstat\n"); exit(1); } if (sysmp(MP_SAGET, MPSA_SVSTAT3, &svstat3, sizeof(svstat)) == -1) { fprintf(stderr,"can't read svstat3\n"); exit(1); } } } static void putstats() { if (sysmp(MP_CLEARNFSSTAT) == -1) { fprintf(stderr,"can't clear nfsstat\n"); exit(1); } } static void cr_print(zflag) int zflag; { fprintf(stdout, "\nClient RPC:\n"); fprintf(stdout, "calls badcalls retrans badxid timeout wait newcred badversions\n"); fprintf(stdout, "%-11d%-11d%-11d%-11d%-11d%-11d%-11d%-11d\n", rcstat.rccalls, rcstat.rcbadcalls, rcstat.rcretrans, rcstat.rcbadxids, rcstat.rctimeouts, rcstat.rcwaits, rcstat.rcnewcreds, rcstat.rcbadverfs); if (zflag) { bzero(&rcstat, sizeof rcstat); } } static void sr_print(zflag) int zflag; { fprintf(stdout, "\nServer RPC:\n"); fprintf(stdout, "calls badcalls nullrecv badlen xdrcall duphits dupage\n"); fprintf(stdout, "%-11d%-11d%-11d%-11d%-11d%-11d%-8.2f\n", rsstat.rscalls, rsstat.rsbadcalls, rsstat.rsnullrecv, rsstat.rsbadlen, rsstat.rsxdrcall, rsstat.rsduphits, rsstat.rsdupage/(HZ*1.0)); if (zflag) { bzero(&rsstat, sizeof rsstat); } } #define RFS_NPROC 18 char *nfsstr[RFS_NPROC] = { "null", "getattr", "setattr", "root", "lookup", "readlink", "read", "wrcache", "write", "create", "remove", "rename", "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat" }; #define RFS3_NPROC 22 char *nfs3str[RFS3_NPROC] = { "null", "getattr", "setattr", "lookup", "access", "readlink", "read", "write", "create", "mkdir", "symlink", "mknod", "remove", "rmdir", "rename", "link", "readdir", "readdir+", "fsstat", "fsinfo", "pathconf", "commit" }; static void cn_print(zflag) int zflag; { int i; fprintf(stdout, "\nClient NFS V2:\n"); fprintf(stdout, "%-13s%-13s%-13s%-13s\n", "calls", "badcalls", "nclget", "nclsleep"); fprintf(stdout, "%-13d%-13d%-13d%-13d\n", clstat.ncalls, clstat.nbadcalls, clstat.nclgets, clstat.nclsleeps); req_print((int *)clstat.reqs, clstat.ncalls, &nfsstr[0], RFS_NPROC); if (zflag) { bzero(&clstat, sizeof clstat); } } static void cn_print3(zflag) int zflag; { int i; fprintf(stdout, "\nClient NFS V3:\n"); fprintf(stdout, "%-13s%-13s%-13s%-13s\n", "calls", "badcalls", "nclget", "nclsleep"); fprintf(stdout, "%-13d%-13d%-13d%-13d\n", clstat3.ncalls, clstat3.nbadcalls, clstat3.nclgets, clstat3.nclsleeps); req_print((int *)clstat3.reqs, clstat3.ncalls, &nfs3str[0], RFS3_NPROC); if (zflag) { bzero(&clstat3, sizeof clstat); } } static void sn_print3(zflag) int zflag; { fprintf(stdout, "\nServer NFS V3:\n"); fprintf(stdout, "%-13s%-13s\n", "calls", "badcalls"); fprintf(stdout, "%-13d%-13d\n", svstat3.ncalls, svstat3.nbadcalls); req_print((int *)svstat3.reqs, svstat3.ncalls, &nfs3str[0], RFS3_NPROC); if (zflag) { bzero(&svstat3, sizeof svstat); } } static void sn_print(zflag) int zflag; { fprintf(stdout, "\nServer NFS V2:\n"); fprintf(stdout, "%-13s%-13s\n", "calls", "badcalls"); fprintf(stdout, "%-13d%-13d\n", svstat.ncalls, svstat.nbadcalls); req_print((int *)svstat.reqs, svstat.ncalls, &nfsstr[0], RFS_NPROC); if (zflag) { bzero(&svstat, sizeof svstat); } } static void req_print(req, tot, str, len) int *req; int tot; char **str; int len; { int i, j, p; char fixlen[128]; for (i=0; i<=len / 6; i++) { for (j=i*6; j 1) printw("%-11d%-11d%-11d%-11d%-11d%-11d%-8.2f", DSP(rsstat.rscalls - rsp->rscalls), DSP(rsstat.rsbadcalls - rsp->rsbadcalls), DSP(rsstat.rsnullrecv - rsp->rsnullrecv), DSP(rsstat.rsbadlen - rsp->rsbadlen), DSP(rsstat.rsxdrcall - rsp->rsxdrcall), DSP(rsstat.rsduphits - rsp->rsduphits), rsstat.rsdupage/(HZ*1.0)); y++; y++; /* skip a blank line */ PL("Server NFS V3:"); PL("calls badcalls"); move(y,x); if (gotstats > 1) printw("%-13d%-13d", DSP(svstat3.ncalls - svp->ncalls), DSP(svstat3.nbadcalls - svp->nbadcalls)); y++; req = (int *)svstat3.reqs; zreq = (int *)(svp->reqs); tot = svstat3.ncalls - svp->ncalls; for (i = 0; i <= RFS3_NPROC / 6; i++) { if (Cfirst) { move(y,x); for (j = i*6; j < min(i*6+6, RFS3_NPROC); j++) { printw("%-13s", nfs3str[j]); } } y++; move(y,x); for (j = i*6; j < min(i*6+6, RFS3_NPROC); j++) { char fixlen[128]; int curreq = req[j] - zreq[j]; int p; if (gotstats <= 1) break; if (tot) { p = ((double)curreq*100)/tot; } else { p = 0; } sprintf(fixlen, "%d %2d%% ", DSP(curreq), p); printw("%-13s", fixlen); } y++; } drsstat = rsstat; dsvstat3 = svstat3; } static void spr_server(int cmd, register int y, char *tmb) { register int i, j; register int x = 0; register int *req, *zreq; register int tot; register struct rsstat *rsp; register struct svstat *svp; if (cmode == DELTA) { rsp = &drsstat; svp = &dsvstat; } else { rsp = &zrsstat; svp = &zsvstat; } move(0,0); printw(" %d: Server %.26s %s",cmd,hostname,tmb); y++; PL("Server RPC:"); PL("calls badcalls nullrecv badlen xdrcall duphits dupage"); move(y,x); if (gotstats > 1) printw("%-11d%-11d%-11d%-11d%-11d%-11d%-8.2f", DSP(rsstat.rscalls - rsp->rscalls), DSP(rsstat.rsbadcalls - rsp->rsbadcalls), DSP(rsstat.rsnullrecv - rsp->rsnullrecv), DSP(rsstat.rsbadlen - rsp->rsbadlen), DSP(rsstat.rsxdrcall - rsp->rsxdrcall), DSP(rsstat.rsduphits - rsp->rsduphits), rsstat.rsdupage/(HZ*1.0)); y++; y++; /* skip a blank line */ PL("Server NFS V2:"); PL("calls badcalls"); move(y,x); if (gotstats > 1) printw("%-13d%-13d", DSP(svstat.ncalls - svp->ncalls), DSP(svstat.nbadcalls - svp->nbadcalls)); y++; req = (int *)svstat.reqs; zreq = (int *)(svp->reqs); tot = svstat.ncalls - svp->ncalls; for (i = 0; i <= RFS_NPROC / 6; i++) { if (Cfirst) { move(y,x); for (j = i*6; j < min(i*6+6, RFS_NPROC); j++) { printw("%-13s", nfsstr[j]); } } y++; move(y,x); for (j = i*6; j < min(i*6+6, RFS_NPROC); j++) { char fixlen[128]; int curreq = req[j] - zreq[j]; int p; if (gotstats <= 1) break; if (tot) { p = ((double)curreq*100)/tot; } else { p = 0; } sprintf(fixlen, "%d %2d%% ", DSP(curreq), p); printw("%-13s", fixlen); } y++; } drsstat = rsstat; dsvstat = svstat; } static struct rcstat zrcstat, drcstat; static struct clstat zclstat, dclstat; static struct clstat zclstat3, dclstat3; static void initclient(int initall) { if (initall) { bzero(&drcstat, sizeof(drcstat)); bzero(&dclstat, sizeof(dclstat)); bzero(&dclstat3, sizeof(dclstat3)); } bzero(&zrcstat, sizeof(zrcstat)); bzero(&zclstat, sizeof(zclstat)); bzero(&zclstat3, sizeof(zclstat3)); } static void zeroclient() { zrcstat = drcstat; zclstat = dclstat; zclstat3 = dclstat3; } static void _spr_client(int cmd, register int y, char *tmb, char *legend, struct rcstat *rcp, struct clstat *clp, struct clstat *cls, char **str, int strcnt) { register int i, j; register int x = 0; register int *req, *zreq; register int tot; move(0,0); printw(" %d: Client %.26s %s",cmd,hostname,tmb);y++; PL("Client RPC:"); PL("calls badcalls retrans badxid timeout wait newcred"); move(y,x); if (gotstats > 1) printw("%-11d%-11d%-11d%-11d%-11d%-11d%-11d\n", DSP(rcstat.rccalls - rcp->rccalls), DSP(rcstat.rcbadcalls - rcp->rcbadcalls), DSP(rcstat.rcretrans - rcp->rcretrans), DSP(rcstat.rcbadxids - rcp->rcbadxids), DSP(rcstat.rctimeouts - rcp->rctimeouts), DSP(rcstat.rcwaits - rcp->rcwaits), DSP(rcstat.rcnewcreds - rcp->rcnewcreds)); y++; y++; /* skip a blank line */ PL(legend); PL("calls badcalls nclget nclsleep"); move(y,x); if (gotstats > 1) printw("%-13d%-13d%-13d%-13d", DSP(cls->ncalls - clp->ncalls), DSP(cls->nbadcalls - clp->nbadcalls), DSP(cls->nclgets - clp->nclgets), DSP(cls->nclsleeps - clp->nclsleeps)); y++; req = (int *)cls->reqs; zreq = (int *)(clp->reqs); tot = cls->ncalls - clp->ncalls; for (i = 0; i <= strcnt / 6; i++) { if (Cfirst) { move(y,x); for (j = i*6; j < min(i*6+6, strcnt); j++) { printw("%-13s", str[j]); } } y++; move(y,x); for (j = i*6; j < min(i*6+6, strcnt); j++) { char fixlen[128]; int curreq = req[j] - zreq[j]; int p; if (gotstats <= 1) break; if (tot) { p = ((double)curreq*100)/tot; } else { p = 0; } sprintf(fixlen, "%d %2d%% ", DSP(curreq), p); printw("%-13s", fixlen); } y++; } } static void spr_client(int cmd, register int y, char *tmb) { register struct rcstat *rcp; register struct clstat *clp; if (cmode == DELTA) { rcp = &drcstat; clp = &dclstat; } else { rcp = &zrcstat; clp = &zclstat; } _spr_client(cmd, y, tmb, "Client NFS:", rcp, clp, &clstat, &nfsstr[0], RFS_NPROC); drcstat = rcstat; dclstat = clstat; } static void spr_client3(int cmd, register int y, char *tmb) { register struct rcstat *rcp; register struct clstat *clp; if (cmode == DELTA) { rcp = &drcstat; clp = &dclstat3; } else { rcp = &zrcstat; clp = &zclstat3; } _spr_client(cmd, y, tmb, "Client NFS3:", rcp, clp, &clstat3, &nfs3str[0], RFS3_NPROC); drcstat = rcstat; dclstat3 = clstat3; } #define NUMFUNCS 4 static void (*sprfuncs[NUMFUNCS])(int, int, char *) = { spr_client, spr_server, spr_client3, spr_server3, }; static void (*sprinitfuncs[NUMFUNCS])(int) = { initclient, initserver, initclient, initserver, }; static void (*sprzerofuncs[NUMFUNCS])() = { zeroclient, zeroserver, zeroclient, zeroserver, }; const char min_cmd_num = '1'; const char max_cmd_num = '1' + NUMFUNCS - 1; /* * Print a description of the station. */ static void disp(int scmd) { time_t now; char tmb[26]; struct timeval wait; fd_set rmask; struct termio tb; int c, n; int intrchar; /* user's interrupt character */ int suspchar; /* job control character */ static char dtitle[] = "D: Delta/second"; static char rtitle[] = "R: Normal mode"; static char ztitle0[] = "Z: Delta -- %b %d %T"; static char ztitle[] = "Z: Delta -- MMM DD HH:MM:SS"; cmode = DELTA; (void) gethostname(hostname, sizeof(hostname)); for (n = 0; n < NUMFUNCS; n++) sprinitfuncs[n](1); initscr(); raw(); noecho(); keypad(stdscr, TRUE); leaveok(stdscr, FALSE); move(0, 0); (void) ioctl(0, TCGETA, &tb); intrchar = tb.c_cc[VINTR]; suspchar = tb.c_cc[VSUSP]; FD_ZERO(&rmask); while (1) { if (Cfirst) clear(); getstats(); now = time(0); cftime(tmb,"%b %e %T", &now); sprfuncs[scmd](scmd+1, 1, tmb); if (Cfirst) { standout(); move(BOS, 0); printw( "1: Client[V2] 2: Server[V2] 3: Client[V3] 4: Server[V3] DZR:mode"); standend(); switch (cmode) { case DELTA: move(0, 80-sizeof(dtitle)); printw(dtitle); break; case ZERO: move(0, 80-sizeof(ztitle)); printw(ztitle); break; case NORM: move(0, 80-sizeof(rtitle)); printw(rtitle); break; } } move(0, 0); refresh(); Cfirst = 0; FD_SET(0, &rmask); wait.tv_sec = Interval; wait.tv_usec = 0; n = select(1, &rmask, NULL, NULL, &wait); if (n < 0) { fail("select: %s", strerror(errno)); break; } else if (n == 1) { c = getch(); if (c == intrchar || c == 'q' || c == 'Q') { quit(0); break; } else if (c == suspchar) { reset_shell_mode(); kill(getpid(), SIGTSTP); reset_prog_mode(); } else if (c == 'z' || c == 'Z') { now = time(0); cftime(ztitle,ztitle0,&now); for (n = 0; n < NUMFUNCS; n++) sprzerofuncs[n](); cmode = ZERO; } else if (c == 'r' || c == 'R') { for (n = 0; n < NUMFUNCS; n++) sprinitfuncs[n](0); cmode = NORM; } else if (c == 'd' || c == 'D') { cmode = DELTA; } else if ((c >= min_cmd_num) && (c <= max_cmd_num)) { scmd = c - '1'; } Cfirst = 1; } } }