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 file[128]; 54 55 if(argc != 2) 56 error(0, "usage: tprof pid"); 57 /* 58 * Read symbol table 59 */ 60 sprint(file, "/proc/%s/text", argv[1]); 61 fd = open(file, OREAD); 62 if(fd < 0) 63 error(1, file); 64 65 if (!crackhdr(fd, &f)) 66 error(1, "read text header"); 67 if (f.type == FNONE) 68 error(0, "text file not an a.out"); 69 machbytype(f.type); 70 if (syminit(fd, &f) < 0) 71 error(1, "syminit"); 72 close(fd); 73 /* 74 * Read timing data 75 */ 76 sprint(file, "/proc/%s/profile", argv[1]); 77 fd = open(file, OREAD); 78 if(fd < 0) 79 error(1, file); 80 d = dirfstat(fd); 81 if(d == nil) 82 error(1, "stat"); 83 n = d->length/sizeof(data[0]); 84 if(n < 2) 85 error(0, "data file too short"); 86 data = malloc(d->length); 87 if(data == 0) 88 error(1, "malloc"); 89 if(read(fd, data, d->length) < 0) 90 error(1, "text read"); 91 close(fd); 92 93 for(i=0; i<n; i++) 94 data[i] = machdata->swal(data[i]); 95 96 delta = data[0]-data[1]; 97 print("total: %ld\n", data[0]); 98 if(data[0] == 0) 99 exits(0); 100 if (!textsym(&s, 0)) 101 error(0, "no text symbols"); 102 tbase = s.value & ~(mach->pgsize-1); /* align down to page */ 103 print("TEXT %.8lux\n", tbase); 104 /* 105 * Accumulate counts for each function 106 */ 107 cp = 0; 108 k = 0; 109 for (i = 0, j = (s.value-tbase)/PCRES+2; j < n; i++) { 110 name = s.name; /* save name */ 111 if (!textsym(&s, i)) /* get next symbol */ 112 break; 113 sum = 0; 114 while (j < n && j*PCRES < s.value-tbase) 115 sum += data[j++]; 116 if (sum) { 117 cp = realloc(cp, (k+1)*sizeof(struct COUNTER)); 118 if (cp == 0) 119 error(1, "realloc"); 120 cp[k].name = name; 121 cp[k].time = sum; 122 k++; 123 } 124 } 125 if (!k) 126 error(0, "no counts"); 127 cp[k].time = 0; /* "etext" can take no time */ 128 /* 129 * Sort by time and print 130 */ 131 qsort(cp, k, sizeof(struct COUNTER), compar); 132 Binit(&outbuf, 1, OWRITE); 133 Bprint(&outbuf, " ms %% sym\n"); 134 while(--k>=0) 135 Bprint(&outbuf, "%6ld\t%3ld.%ld\t%s\n", 136 cp[k].time, 137 100*cp[k].time/delta, 138 (1000*cp[k].time/delta)%10, 139 cp[k].name); 140 exits(0); 141 } 142