summaryrefslogtreecommitdiff
path: root/sys/src/cmd/prof.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/prof.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/prof.c')
-rwxr-xr-xsys/src/cmd/prof.c360
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];
+}