diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/prof.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/prof.c')
-rwxr-xr-x | sys/src/cmd/prof.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/sys/src/cmd/prof.c b/sys/src/cmd/prof.c new file mode 100755 index 000000000..0e8806cef --- /dev/null +++ b/sys/src/cmd/prof.c @@ -0,0 +1,360 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +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; +int verbose; + +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 && strtol(s,0,0)>0) + tabstop = strtol(s,0,0); + ARGBEGIN{ + case 'v': + verbose = 1; + break; + 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); + snprint(buf, sizeof(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; + int k; + static indent; + + if(i >= ndata){ + fprint(2, "prof: index out of range %ld [max %ld]\n", i, ndata); + return 0; + } + j = symind(data[i].pc); + time = data[i].time; + if(time < 0) + time += data[0].time; + if (verbose){ + for(k = 0; k < indent; k++) + print(" "); + print("%lud: %ld/%lud", i, data[i].time, data[i].count); + if (j >= 0) + print(" %s\n", acc[j].name); + else + print(" 0x%lux\n", data[i].pc); + } + dtime = 0; + if(data[i].down != 0xFFFF){ + indent++; + dtime = sum(data[i].down); + indent--; + } + 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 Calls Name\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", + "amd64", "6.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]; +} |