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