#include #include #include #include typedef struct Data Data; typedef struct Pc Pc; typedef struct Acc Acc; struct Data { ushort down; ushort right; ulong pc; ulong count; ulong time; }; struct Pc { Pc *next; ulong pc; }; struct Acc { char *name; ulong pc; ulong ms; ulong calls; }; Data* data; Acc* acc; ulong ms; long nsym; long ndata; int dflag; int rflag; Biobuf bout; int tabstop = 4; void syms(char*); void datas(char*); void graph(int, ulong, Pc*); void plot(void); char* name(ulong); void indent(int); char* defaout(void); void main(int argc, char *argv[]) { char *s; s = getenv("tabstop"); if(s!=nil && atoi(s)>0) tabstop = atoi(s); ARGBEGIN{ case 'd': dflag = 1; break; case 'r': rflag = 1; break; default: fprint(2, "usage: prof [-dr] [8.out] [prof.out]\n"); exits("usage"); }ARGEND Binit(&bout, 1, OWRITE); if(argc > 0) syms(argv[0]); else syms(defaout()); if(argc > 1) datas(argv[1]); else datas("prof.out"); if(ndata){ if(dflag) graph(0, data[0].down, 0); else plot(); } exits(0); } void swapdata(Data *dp) { dp->down = beswab(dp->down); dp->right = beswab(dp->right); dp->pc = beswal(dp->pc); dp->count = beswal(dp->count); dp->time = beswal(dp->time); } int acmp(void *va, void *vb) { Acc *a, *b; ulong ua, ub; a = va; b = vb; ua = a->ms; ub = b->ms; if(ua > ub) return 1; if(ua < ub) return -1; return 0; } void syms(char *cout) { Fhdr f; int fd; if((fd = open(cout, 0)) < 0){ perror(cout); exits("open"); } if (!crackhdr(fd, &f)) { fprint(2, "can't read text file header\n"); exits("read"); } if (f.type == FNONE) { fprint(2, "text file not an a.out\n"); exits("file type"); } if (syminit(fd, &f) < 0) { fprint(2, "syminit: %r\n"); exits("syms"); } close(fd); } void datas(char *dout) { int fd; Dir *d; int i; if((fd = open(dout, 0)) < 0){ perror(dout); exits("open"); } d = dirfstat(fd); if(d == nil){ perror(dout); exits("stat"); } ndata = d->length/sizeof(data[0]); data = malloc(ndata*sizeof(Data)); if(data == 0){ fprint(2, "prof: can't malloc data\n"); exits("data malloc"); } if(read(fd, data, d->length) != d->length){ fprint(2, "prof: can't read data file\n"); exits("data read"); } free(d); close(fd); for (i = 0; i < ndata; i++) swapdata(data+i); } char* name(ulong pc) { Symbol s; static char buf[16]; if (findsym(pc, CTEXT, &s)) return(s.name); sprint(buf, "#%lux", pc); return buf; } void graph(int ind, ulong i, Pc *pc) { long time, count, prgm; Pc lpc; if(i >= ndata){ fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata); return; } count = data[i].count; time = data[i].time; prgm = data[i].pc; if(time < 0) time += data[0].time; if(data[i].right != 0xFFFF) graph(ind, data[i].right, pc); indent(ind); if(count == 1) Bprint(&bout, "%s:%lud\n", name(prgm), time); else Bprint(&bout, "%s:%lud/%lud\n", name(prgm), time, count); if(data[i].down == 0xFFFF) return; lpc.next = pc; lpc.pc = prgm; if(!rflag){ while(pc){ if(pc->pc == prgm){ indent(ind+1); Bprint(&bout, "...\n"); return; } pc = pc->next; } } graph(ind+1, data[i].down, &lpc); } /* * assume acc is ordered by increasing text address. */ long symind(ulong pc) { int top, bot, mid; bot = 0; top = nsym; for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { if (pc < acc[mid].pc) top = mid; else if (mid != nsym-1 && pc >= acc[mid+1].pc) bot = mid; else return mid; } return -1; } ulong sum(ulong i) { long j, dtime, time; if(i >= ndata){ fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata); return 0; } time = data[i].time; if(time < 0) time += data[0].time; dtime = 0; if(data[i].down != 0xFFFF) dtime = sum(data[i].down); j = symind(data[i].pc); if (j >= 0) { acc[j].ms += time - dtime; ms += time - dtime; acc[j].calls += data[i].count; } if(data[i].right == 0xFFFF) return time; return time + sum(data[i].right); } void plot(void) { Symbol s; for (nsym = 0; textsym(&s, nsym); nsym++) { acc = realloc(acc, (nsym+1)*sizeof(Acc)); if(acc == 0){ fprint(2, "prof: malloc fail\n"); exits("acc malloc"); } acc[nsym].name = s.name; acc[nsym].pc = s.value; acc[nsym].calls = acc[nsym].ms = 0; } sum(data[0].down); qsort(acc, nsym, sizeof(Acc), acmp); Bprint(&bout, " %% Time\tCalls\tName\n"); if(ms == 0) ms = 1; while (--nsym >= 0) { if(acc[nsym].calls) Bprint(&bout, "%4.1f%8.3f %8lud\t%s\n", (100.0*acc[nsym].ms)/ms, acc[nsym].ms/1000.0, acc[nsym].calls, acc[nsym].name); } } void indent(int ind) { int j; j = 2*ind; while(j >= tabstop){ Bwrite(&bout, ".\t", 2); j -= tabstop; } if(j) Bwrite(&bout, ". ", j); } char* trans[] = { "386", "8.out", "68020", "2.out", "alpha", "7.out", "arm", "5.out", "mips", "v.out", "power", "q.out", "sparc", "k.out", "spim", "0.out", 0,0 }; char* defaout(void) { char *p; int i; p = getenv("objtype"); if(p) for(i=0; trans[i]; i+=2) if(strcmp(p, trans[i]) == 0) return trans[i+1]; return trans[1]; }