1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 6 #define PCRES 8 7 8 struct COUNTER 9 { 10 char *name; /* function name */ 11 long time; /* ticks spent there */ 12 }; 13 14 void 15 error(int perr, char *s) 16 { 17 fprint(2, "tprof: %s", s); 18 if(perr){ 19 fprint(2, ": "); 20 perror(0); 21 }else 22 fprint(2, "\n"); 23 exits(s); 24 } 25 26 int 27 compar(void *va, void *vb) 28 { 29 struct COUNTER *a, *b; 30 31 a = va; 32 b = vb; 33 if(a->time < b->time) 34 return -1; 35 if(a->time == b->time) 36 return 0; 37 return 1; 38 } 39 void 40 main(int argc, char *argv[]) 41 { 42 int fd; 43 long i, j, k, n; 44 Dir *d; 45 char *name; 46 ulong *data; 47 ulong tbase, sum; 48 long delta; 49 Symbol s; 50 Biobuf outbuf; 51 Fhdr f; 52 struct COUNTER *cp; 53 char filebuf[128], *file; 54 55 if(argc != 2 && argc != 3) 56 error(0, "usage: tprof pid [binary]"); 57 /* 58 * Read symbol table 59 */ 60 if(argc == 2){ 61 file = filebuf; 62 snprint(filebuf, sizeof filebuf, "/proc/%s/text", argv[1]); 63 }else 64 file = argv[2]; 65 66 fd = open(file, OREAD); 67 if(fd < 0) 68 error(1, file); 69 70 if (!crackhdr(fd, &f)) 71 error(1, "read text header"); 72 if (f.type == FNONE) 73 error(0, "text file not an a.out"); 74 machbytype(f.type); 75 if (syminit(fd, &f) < 0) 76 error(1, "syminit"); 77 close(fd); 78 /* 79 * Read timing data 80 */ 81 file = smprint("/proc/%s/profile", argv[1]); 82 fd = open(file, OREAD); 83 if(fd < 0) 84 error(1, file); 85 free(file); 86 d = dirfstat(fd); 87 if(d == nil) 88 error(1, "stat"); 89 n = d->length/sizeof(data[0]); 90 if(n < 2) 91 error(0, "data file too short"); 92 data = malloc(d->length); 93 if(data == 0) 94 error(1, "malloc"); 95 if(read(fd, data, d->length) < 0) 96 error(1, "text read"); 97 close(fd); 98 99 for(i=0; i<n; i++) 100 data[i] = machdata->swal(data[i]); 101 102 delta = data[0]-data[1]; 103 print("total: %ld\n", data[0]); 104 if(data[0] == 0) 105 exits(0); 106 if (!textsym(&s, 0)) 107 error(0, "no text symbols"); 108 tbase = s.value & ~(mach->pgsize-1); /* align down to page */ 109 print("TEXT %.8lux\n", tbase); 110 /* 111 * Accumulate counts for each function 112 */ 113 cp = 0; 114 k = 0; 115 for (i = 0, j = (s.value-tbase)/PCRES+2; j < n; i++) { 116 name = s.name; /* save name */ 117 if (!textsym(&s, i)) /* get next symbol */ 118 break; 119 sum = 0; 120 while (j < n && j*PCRES < s.value-tbase) 121 sum += data[j++]; 122 if (sum) { 123 cp = realloc(cp, (k+1)*sizeof(struct COUNTER)); 124 if (cp == 0) 125 error(1, "realloc"); 126 cp[k].name = name; 127 cp[k].time = sum; 128 k++; 129 } 130 } 131 if (!k) 132 error(0, "no counts"); 133 cp[k].time = 0; /* "etext" can take no time */ 134 /* 135 * Sort by time and print 136 */ 137 qsort(cp, k, sizeof(struct COUNTER), compar); 138 Binit(&outbuf, 1, OWRITE); 139 Bprint(&outbuf, " ms %% sym\n"); 140 while(--k>=0) 141 Bprint(&outbuf, "%6ld\t%3lld.%lld\t%s\n", 142 cp[k].time, 143 100LL*cp[k].time/delta, 144 (1000LL*cp[k].time/delta)%10, 145 cp[k].name); 146 exits(0); 147 } 148