123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- /*
- * iostats - Gather file system information
- */
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #define Extern
- #include "statfs.h"
- void runprog(char**);
- void (*fcalls[])(Fsrpc*) =
- {
- [Tversion] Xversion,
- [Tauth] Xauth,
- [Tflush] Xflush,
- [Tattach] Xattach,
- [Twalk] Xwalk,
- [Topen] slave,
- [Tcreate] Xcreate,
- [Tclunk] Xclunk,
- [Tread] slave,
- [Twrite] slave,
- [Tremove] Xremove,
- [Tstat] Xstat,
- [Twstat] Xwstat,
- };
- int p[2];
- void
- usage(void)
- {
- fprint(2, "usage: iostats [-d] [-f debugfile] cmds [args ...]\n");
- exits("usage");
- }
- void
- main(int argc, char **argv)
- {
- Fsrpc *r;
- Rpc *rpc;
- Proc *m;
- Frec *fr;
- Fid *fid;
- ulong ttime;
- char *dbfile, *s;
- char buf[128];
- float brpsec, bwpsec, bppsec;
- int type, cpid, fspid, n;
- dbfile = DEBUGFILE;
- ARGBEGIN{
- case 'd':
- dbg++;
- break;
- case 'f':
- dbfile = ARGF();
- break;
- default:
- usage();
- }ARGEND
- if(argc == 0)
- usage();
- if(dbg) {
- close(2);
- create(dbfile, OWRITE, 0666);
- }
- if(pipe(p) < 0)
- fatal("pipe");
- switch(cpid = fork()) {
- case -1:
- fatal("fork");
- case 0:
- close(p[1]);
- if(getwd(buf, sizeof(buf)) == 0)
- fatal("no working directory");
- rfork(RFENVG|RFNAMEG|RFNOTEG);
- if(mount(p[0], -1, "/", MREPL, "") < 0)
- fatal("mount /");
- bind("#c/pid", "/dev/pid", MREPL);
- bind("#e", "/env", MREPL|MCREATE);
- close(0);
- close(1);
- close(2);
- open("/fd/0", OREAD);
- open("/fd/1", OWRITE);
- open("/fd/2", OWRITE);
- if(chdir(buf) < 0)
- fatal("chdir");
- runprog(argv);
- default:
- close(p[0]);
- }
- switch(fspid = fork()) {
- default:
- while(cpid != waitpid())
- ;
- postnote(PNPROC, fspid, DONESTR);
- while(fspid != waitpid())
- ;
- exits(0);
- case -1:
- fatal("fork");
- case 0:
- break;
- }
- /* Allocate work queues in shared memory */
- malloc(Dsegpad);
- Workq = malloc(sizeof(Fsrpc)*Nr_workbufs);
- stats = malloc(sizeof(Stats));
- fhash = mallocz(sizeof(Fid*)*FHASHSIZE, 1);
- if(Workq == 0 || fhash == 0 || stats == 0)
- fatal("no initial memory");
- memset(Workq, 0, sizeof(Fsrpc)*Nr_workbufs);
- memset(stats, 0, sizeof(Stats));
- stats->rpc[Tversion].name = "version";
- stats->rpc[Tauth].name = "auth";
- stats->rpc[Tflush].name = "flush";
- stats->rpc[Tattach].name = "attach";
- stats->rpc[Twalk].name = "walk";
- stats->rpc[Topen].name = "open";
- stats->rpc[Tcreate].name = "create";
- stats->rpc[Tclunk].name = "clunk";
- stats->rpc[Tread].name = "read";
- stats->rpc[Twrite].name = "write";
- stats->rpc[Tremove].name = "remove";
- stats->rpc[Tstat].name = "stat";
- stats->rpc[Twstat].name = "wstat";
- for(n = 0; n < Maxrpc; n++)
- stats->rpc[n].lo = 10000000000LL;
- fmtinstall('F', fcallfmt);
- if(chdir("/") < 0)
- fatal("chdir");
- initroot();
- DEBUG(2, "statfs: %s\n", buf);
- notify(catcher);
- for(;;) {
- r = getsbuf();
- if(r == 0)
- fatal("Out of service buffers");
- n = read9pmsg(p[1], r->buf, sizeof(r->buf));
- if(done)
- break;
- if(n < 0)
- fatal("read server");
- if(convM2S(r->buf, n, &r->work) == 0)
- fatal("format error");
- stats->nrpc++;
- stats->nproto += n;
- if(r->work.fid < 0)
- fatal("fid out of range");
- DEBUG(2, "%F\n", &r->work);
- type = r->work.type;
- rpc = &stats->rpc[type];
- rpc->count++;
- rpc->bin += n;
- (fcalls[type])(r);
- }
- /* Clear away the slave children */
- for(m = Proclist; m; m = m->next)
- postnote(PNPROC, m->pid, "kill");
- rpc = &stats->rpc[Tread];
- brpsec = (float)stats->totread / (((float)rpc->time/1e9)+.000001);
- rpc = &stats->rpc[Twrite];
- bwpsec = (float)stats->totwrite / (((float)rpc->time/1e9)+.000001);
- ttime = 0;
- for(n = 0; n < Maxrpc; n++) {
- rpc = &stats->rpc[n];
- if(rpc->count == 0)
- continue;
- ttime += rpc->time;
- }
- bppsec = (float)stats->nproto / ((ttime/1e9)+.000001);
- fprint(2, "\nread %lud bytes, %g Kb/sec\n", stats->totread, brpsec/1024.0);
- fprint(2, "write %lud bytes, %g Kb/sec\n", stats->totwrite, bwpsec/1024.0);
- fprint(2, "protocol %lud bytes, %g Kb/sec\n", stats->nproto, bppsec/1024.0);
- fprint(2, "rpc %lud count\n\n", stats->nrpc);
- fprint(2, "%-10s %5s %5s %5s %5s %5s T R\n",
- "Message", "Count", "Low", "High", "Time", "Averg");
- for(n = 0; n < Maxrpc; n++) {
- rpc = &stats->rpc[n];
- if(rpc->count == 0)
- continue;
- fprint(2, "%-10s %5lud %5llud %5llud %5llud %5llud ms %8lud %8lud bytes\n",
- rpc->name,
- rpc->count,
- rpc->lo/1000000,
- rpc->hi/1000000,
- rpc->time/1000000,
- rpc->time/1000000/rpc->count,
- rpc->bin,
- rpc->bout);
- }
- for(n = 0; n < FHASHSIZE; n++)
- for(fid = fhash[n]; fid; fid = fid->next)
- if(fid->nread || fid->nwrite)
- fidreport(fid);
- if(frhead == 0)
- exits(0);
- fprint(2, "\nOpens Reads (bytes) Writes (bytes) File\n");
- for(fr = frhead; fr; fr = fr->next) {
- s = fr->op;
- if(*s) {
- if(strcmp(s, "/fd/0") == 0)
- s = "(stdin)";
- else
- if(strcmp(s, "/fd/1") == 0)
- s = "(stdout)";
- else
- if(strcmp(s, "/fd/2") == 0)
- s = "(stderr)";
- }
- else
- s = "/.";
- fprint(2, "%5lud %8lud %8lud %8lud %8lud %s\n", fr->opens, fr->nread, fr->bread,
- fr->nwrite, fr->bwrite, s);
- }
- exits(0);
- }
- void
- reply(Fcall *r, Fcall *t, char *err)
- {
- uchar data[IOHDRSZ+Maxfdata];
- int n;
- t->tag = r->tag;
- t->fid = r->fid;
- if(err) {
- t->type = Rerror;
- t->ename = err;
- }
- else
- t->type = r->type + 1;
- DEBUG(2, "\t%F\n", t);
- n = convS2M(t, data, sizeof data);
- if(write(p[1], data, n)!=n)
- fatal("mount write");
- stats->nproto += n;
- stats->rpc[t->type-1].bout += n;
- }
- Fid *
- getfid(int nr)
- {
- Fid *f;
- for(f = fidhash(nr); f; f = f->next)
- if(f->nr == nr)
- return f;
- return 0;
- }
- int
- freefid(int nr)
- {
- Fid *f, **l;
- l = &fidhash(nr);
- for(f = *l; f; f = f->next) {
- if(f->nr == nr) {
- *l = f->next;
- f->next = fidfree;
- fidfree = f;
- return 1;
- }
- l = &f->next;
- }
- return 0;
- }
- Fid *
- newfid(int nr)
- {
- Fid *new, **l;
- int i;
- l = &fidhash(nr);
- for(new = *l; new; new = new->next)
- if(new->nr == nr)
- return 0;
- if(fidfree == 0) {
- fidfree = mallocz(sizeof(Fid) * Fidchunk, 1);
- if(fidfree == 0)
- fatal("out of memory");
- for(i = 0; i < Fidchunk-1; i++)
- fidfree[i].next = &fidfree[i+1];
- fidfree[Fidchunk-1].next = 0;
- }
- new = fidfree;
- fidfree = new->next;
- memset(new, 0, sizeof(Fid));
- new->next = *l;
- *l = new;
- new->nr = nr;
- new->fid = -1;
- new->nread = 0;
- new->nwrite = 0;
- new->bread = 0;
- new->bwrite = 0;
- return new;
- }
- Fsrpc *
- getsbuf(void)
- {
- static int ap;
- int look;
- Fsrpc *wb;
- for(look = 0; look < Nr_workbufs; look++) {
- if(++ap == Nr_workbufs)
- ap = 0;
- if(Workq[ap].busy == 0)
- break;
- }
- if(look == Nr_workbufs)
- fatal("No more work buffers");
- wb = &Workq[ap];
- wb->pid = 0;
- wb->canint = 0;
- wb->flushtag = NOTAG;
- wb->busy = 1;
- return wb;
- }
- char *
- strcatalloc(char *p, char *n)
- {
- char *v;
- v = realloc(p, strlen(p)+strlen(n)+1);
- if(v == 0)
- fatal("no memory");
- strcat(v, n);
- return v;
- }
- File *
- file(File *parent, char *name)
- {
- char buf[128];
- File *f, *new;
- Dir *dir;
- DEBUG(2, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
- for(f = parent->child; f; f = f->childlist)
- if(strcmp(name, f->name) == 0)
- break;
- if(f != nil && !f->inval)
- return f;
- makepath(buf, parent, name);
- dir = dirstat(buf);
- if(dir == nil)
- return 0;
- if(f != nil){
- free(dir);
- f->inval = 0;
- return f;
- }
- new = malloc(sizeof(File));
- if(new == 0)
- fatal("no memory");
- memset(new, 0, sizeof(File));
- new->name = strdup(name);
- if(new->name == nil)
- fatal("can't strdup");
- new->qid.type = dir->qid.type;
- new->qid.vers = dir->qid.vers;
- new->qid.path = ++qid;
- new->parent = parent;
- new->childlist = parent->child;
- parent->child = new;
- free(dir);
- return new;
- }
- void
- initroot(void)
- {
- Dir *dir;
- root = malloc(sizeof(File));
- if(root == 0)
- fatal("no memory");
- memset(root, 0, sizeof(File));
- root->name = strdup("/");
- if(root->name == nil)
- fatal("can't strdup");
- dir = dirstat(root->name);
- if(dir == nil)
- fatal("root stat");
- root->qid.type = dir->qid.type;
- root->qid.vers = dir->qid.vers;
- root->qid.path = ++qid;
- free(dir);
- }
- void
- makepath(char *as, File *p, char *name)
- {
- char *c, *seg[100];
- int i;
- char *s;
- seg[0] = name;
- for(i = 1; i < 100 && p; i++, p = p->parent){
- seg[i] = p->name;
- if(strcmp(p->name, "/") == 0)
- seg[i] = ""; /* will insert slash later */
- }
- s = as;
- while(i--) {
- for(c = seg[i]; *c; c++)
- *s++ = *c;
- *s++ = '/';
- }
- while(s[-1] == '/')
- s--;
- *s = '\0';
- if(as == s) /* empty string is root */
- strcpy(as, "/");
- }
- void
- fatal(char *s)
- {
- Proc *m;
- fprint(2, "iostats: %s: %r\n", s);
- /* Clear away the slave children */
- for(m = Proclist; m; m = m->next)
- postnote(PNPROC, m->pid, "exit");
- exits("fatal");
- }
- void
- runprog(char *argv[])
- {
- char arg0[128];
- exec(argv[0], argv);
- if (*argv[0] != '/' && strncmp(argv[0],"./",2) != 0) {
- sprint(arg0, "/bin/%s", argv[0]);
- exec(arg0, argv);
- }
- fatal("exec");
- }
- void
- catcher(void *a, char *msg)
- {
- USED(a);
- if(strcmp(msg, DONESTR) == 0) {
- done = 1;
- noted(NCONT);
- }
- if(strcmp(msg, "exit") == 0)
- exits("exit");
- noted(NDFLT);
- }
- void
- fidreport(Fid *f)
- {
- char *p, path[128];
- Frec *fr;
- p = path;
- makepath(p, f->f, "");
- for(fr = frhead; fr; fr = fr->next) {
- if(strcmp(fr->op, p) == 0) {
- fr->nread += f->nread;
- fr->nwrite += f->nwrite;
- fr->bread += f->bread;
- fr->bwrite += f->bwrite;
- fr->opens++;
- return;
- }
- }
- fr = malloc(sizeof(Frec));
- if(fr == 0 || (fr->op = strdup(p)) == 0)
- fatal("no memory");
- fr->nread = f->nread;
- fr->nwrite = f->nwrite;
- fr->bread = f->bread;
- fr->bwrite = f->bwrite;
- fr->opens = 1;
- if(frhead == 0) {
- frhead = fr;
- frtail = fr;
- }
- else {
- frtail->next = fr;
- frtail = fr;
- }
- fr->next = 0;
- }
|