2 * iostats - Gather file system information
13 void (*fcalls[])(Fsrpc*) =
35 fprint(2, "usage: iostats [-d] [-f debugfile] cmds [args ...]\n");
40 main(int argc, char **argv)
50 float brpsec, bwpsec, bppsec;
51 int type, cpid, fspid, n;
71 create(dbfile, OWRITE, 0666);
77 switch(cpid = fork()) {
82 if(getwd(buf, sizeof(buf)) == 0)
83 fatal("no working directory");
85 rfork(RFENVG|RFNAMEG|RFNOTEG);
86 if(mount(p[0], -1, "/", MREPL, "") < 0)
89 bind("#c/pid", "/dev/pid", MREPL);
90 bind("#e", "/env", MREPL|MCREATE);
95 open("/fd/1", OWRITE);
96 open("/fd/2", OWRITE);
106 switch(fspid = fork()) {
108 while(cpid != waitpid())
110 postnote(PNPROC, fspid, DONESTR);
111 while(fspid != waitpid())
120 /* Allocate work queues in shared memory */
122 Workq = malloc(sizeof(Fsrpc)*Nr_workbufs);
123 stats = malloc(sizeof(Stats));
124 fhash = mallocz(sizeof(Fid*)*FHASHSIZE, 1);
126 if(Workq == 0 || fhash == 0 || stats == 0)
127 fatal("no initial memory");
129 memset(Workq, 0, sizeof(Fsrpc)*Nr_workbufs);
130 memset(stats, 0, sizeof(Stats));
132 stats->rpc[Tversion].name = "version";
133 stats->rpc[Tauth].name = "auth";
134 stats->rpc[Tflush].name = "flush";
135 stats->rpc[Tattach].name = "attach";
136 stats->rpc[Twalk].name = "walk";
137 stats->rpc[Topen].name = "open";
138 stats->rpc[Tcreate].name = "create";
139 stats->rpc[Tclunk].name = "clunk";
140 stats->rpc[Tread].name = "read";
141 stats->rpc[Twrite].name = "write";
142 stats->rpc[Tremove].name = "remove";
143 stats->rpc[Tstat].name = "stat";
144 stats->rpc[Twstat].name = "wstat";
146 for(n = 0; n < Maxrpc; n++)
147 stats->rpc[n].lo = 10000000000LL;
149 fmtinstall('M', dirmodefmt);
150 fmtinstall('D', dirfmt);
151 fmtinstall('F', fcallfmt);
158 DEBUG(2, "statfs: %s\n", buf);
165 fatal("Out of service buffers");
167 n = read9pmsg(p[1], r->buf, sizeof(r->buf));
171 fatal("read server");
173 if(convM2S(r->buf, n, &r->work) == 0)
174 fatal("format error");
179 DEBUG(2, "%F\n", &r->work);
182 rpc = &stats->rpc[type];
188 /* Clear away the slave children */
189 for(m = Proclist; m; m = m->next)
190 postnote(PNPROC, m->pid, "kill");
192 rpc = &stats->rpc[Tread];
193 brpsec = (float)stats->totread / (((float)rpc->time/1e9)+.000001);
195 rpc = &stats->rpc[Twrite];
196 bwpsec = (float)stats->totwrite / (((float)rpc->time/1e9)+.000001);
199 for(n = 0; n < Maxrpc; n++) {
200 rpc = &stats->rpc[n];
206 bppsec = (float)stats->nproto / ((ttime/1e9)+.000001);
208 fprint(2, "\nread %lud bytes, %g Kb/sec\n", stats->totread, brpsec/1024.0);
209 fprint(2, "write %lud bytes, %g Kb/sec\n", stats->totwrite, bwpsec/1024.0);
210 fprint(2, "protocol %lud bytes, %g Kb/sec\n", stats->nproto, bppsec/1024.0);
211 fprint(2, "rpc %lud count\n\n", stats->nrpc);
213 fprint(2, "%-10s %5s %5s %5s %5s %5s T R\n",
214 "Message", "Count", "Low", "High", "Time", "Averg");
216 for(n = 0; n < Maxrpc; n++) {
217 rpc = &stats->rpc[n];
220 fprint(2, "%-10s %5lud %5llud %5llud %5llud %5llud ms %8lud %8lud bytes\n",
226 rpc->time/1000000/rpc->count,
231 for(n = 0; n < FHASHSIZE; n++)
232 for(fid = fhash[n]; fid; fid = fid->next)
233 if(fid->nread || fid->nwrite)
238 fprint(2, "\nOpens Reads (bytes) Writes (bytes) File\n");
239 for(fr = frhead; fr; fr = fr->next) {
242 if(strcmp(s, "/fd/0") == 0)
245 if(strcmp(s, "/fd/1") == 0)
248 if(strcmp(s, "/fd/2") == 0)
254 fprint(2, "%5lud %8lud %8lud %8lud %8lud %s\n", fr->opens, fr->nread, fr->bread,
255 fr->nwrite, fr->bwrite, s);
262 reply(Fcall *r, Fcall *t, char *err)
264 uchar data[IOHDRSZ+Maxfdata];
274 t->type = r->type + 1;
276 DEBUG(2, "\t%F\n", t);
278 n = convS2M(t, data, sizeof data);
279 if(write(p[1], data, n)!=n)
280 fatal("mount write");
282 stats->rpc[t->type-1].bout += n;
290 for(f = fidhash(nr); f; f = f->next)
303 for(f = *l; f; f = f->next) {
323 for(new = *l; new; new = new->next)
328 fidfree = mallocz(sizeof(Fid) * Fidchunk, 1);
330 fatal("out of memory");
332 for(i = 0; i < Fidchunk-1; i++)
333 fidfree[i].next = &fidfree[i+1];
335 fidfree[Fidchunk-1].next = 0;
341 memset(new, 0, sizeof(Fid));
361 for(look = 0; look < Nr_workbufs; look++) {
362 if(++ap == Nr_workbufs)
364 if(Workq[ap].busy == 0)
368 if(look == Nr_workbufs)
369 fatal("No more work buffers");
374 wb->flushtag = NOTAG;
381 strcatalloc(char *p, char *n)
385 v = realloc(p, strlen(p)+strlen(n)+1);
393 file(File *parent, char *name)
399 DEBUG(2, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
401 for(f = parent->child; f; f = f->childlist)
402 if(strcmp(name, f->name) == 0)
405 if(f != nil && !f->inval)
407 makepath(buf, parent, name);
417 new = malloc(sizeof(File));
421 memset(new, 0, sizeof(File));
422 new->name = strdup(name);
424 fatal("can't strdup");
425 new->qid.type = dir->qid.type;
426 new->qid.vers = dir->qid.vers;
427 new->qid.path = ++qid;
429 new->parent = parent;
430 new->childlist = parent->child;
442 root = malloc(sizeof(File));
446 memset(root, 0, sizeof(File));
447 root->name = strdup("/");
448 if(root->name == nil)
449 fatal("can't strdup");
450 dir = dirstat(root->name);
454 root->qid.type = dir->qid.type;
455 root->qid.vers = dir->qid.vers;
456 root->qid.path = ++qid;
461 makepath(char *as, File *p, char *name)
468 for(i = 1; i < 100 && p; i++, p = p->parent){
470 if(strcmp(p->name, "/") == 0)
471 seg[i] = ""; /* will insert slash later */
476 for(c = seg[i]; *c; c++)
483 if(as == s) /* empty string is root */
492 fprint(2, "iostats: %s: %r\n", s);
494 /* Clear away the slave children */
495 for(m = Proclist; m; m = m->next)
496 postnote(PNPROC, m->pid, "exit");
502 rdenv(char *v, char **end)
507 if((fd = open(v, OREAD)) == -1)
510 if(d == nil || (buf = malloc(d->length + 1)) == nil)
513 n = read(fd, buf, n);
527 char Defaultpath[] = ".\0/bin";
529 runprog(char *argv[])
534 path = rdenv("/env/path", &ep);
537 ep = path+sizeof(Defaultpath);
539 for(p = path; p < ep; p += strlen(p)+1){
540 snprint(arg0, sizeof arg0, "%s/%s", p, argv[0]);
547 catcher(void *a, char *msg)
550 if(strcmp(msg, DONESTR) == 0) {
554 if(strcmp(msg, "exit") == 0)
567 makepath(p, f->f, "");
569 for(fr = frhead; fr; fr = fr->next) {
570 if(strcmp(fr->op, p) == 0) {
571 fr->nread += f->nread;
572 fr->nwrite += f->nwrite;
573 fr->bread += f->bread;
574 fr->bwrite += f->bwrite;
580 fr = malloc(sizeof(Frec));
581 if(fr == 0 || (fr->op = strdup(p)) == 0)
584 fr->nread = f->nread;
585 fr->nwrite = f->nwrite;
586 fr->bread = f->bread;
587 fr->bwrite = f->bwrite;