174a4d8c2SCharles.Forsyth #include <lib9.h>
274a4d8c2SCharles.Forsyth #include <bio.h>
374a4d8c2SCharles.Forsyth #include <mach.h>
474a4d8c2SCharles.Forsyth
574a4d8c2SCharles.Forsyth enum {
674a4d8c2SCharles.Forsyth SpecialTotalTicks,
774a4d8c2SCharles.Forsyth SpecialOutsideTicks,
874a4d8c2SCharles.Forsyth SpecialMicroSecondsPerTick,
974a4d8c2SCharles.Forsyth SpecialSamples,
1074a4d8c2SCharles.Forsyth SpecialSampleSize,
1174a4d8c2SCharles.Forsyth SpecialSampleLogBucketSize,
1274a4d8c2SCharles.Forsyth SpecialMax
1374a4d8c2SCharles.Forsyth };
1474a4d8c2SCharles.Forsyth
1574a4d8c2SCharles.Forsyth int pcres = 8;
1674a4d8c2SCharles.Forsyth ulong uspertick;
1774a4d8c2SCharles.Forsyth
1874a4d8c2SCharles.Forsyth struct COUNTER
1974a4d8c2SCharles.Forsyth {
2074a4d8c2SCharles.Forsyth char *name; /* function name */
2174a4d8c2SCharles.Forsyth ulong time; /* ticks spent there */
2274a4d8c2SCharles.Forsyth };
2374a4d8c2SCharles.Forsyth
2474a4d8c2SCharles.Forsyth void
error(int perr,char * s)2574a4d8c2SCharles.Forsyth error(int perr, char *s)
2674a4d8c2SCharles.Forsyth {
2774a4d8c2SCharles.Forsyth fprint(2, "kprof: %s", s);
2874a4d8c2SCharles.Forsyth if(perr)
2974a4d8c2SCharles.Forsyth fprint(2, ": %r\n");
3074a4d8c2SCharles.Forsyth else
3174a4d8c2SCharles.Forsyth fprint(2, "\n");
3274a4d8c2SCharles.Forsyth exits(s);
3374a4d8c2SCharles.Forsyth }
3474a4d8c2SCharles.Forsyth
3574a4d8c2SCharles.Forsyth int
compar(void * va,void * vb)3674a4d8c2SCharles.Forsyth compar(void *va, void *vb)
3774a4d8c2SCharles.Forsyth {
3874a4d8c2SCharles.Forsyth struct COUNTER *a, *b;
3974a4d8c2SCharles.Forsyth
4074a4d8c2SCharles.Forsyth a = (struct COUNTER *)va;
4174a4d8c2SCharles.Forsyth b = (struct COUNTER *)vb;
4274a4d8c2SCharles.Forsyth if(a->time < b->time)
4374a4d8c2SCharles.Forsyth return -1;
4474a4d8c2SCharles.Forsyth if(a->time == b->time)
4574a4d8c2SCharles.Forsyth return 0;
4674a4d8c2SCharles.Forsyth return 1;
4774a4d8c2SCharles.Forsyth }
4874a4d8c2SCharles.Forsyth
4974a4d8c2SCharles.Forsyth ulong
tickstoms(ulong ticks)5074a4d8c2SCharles.Forsyth tickstoms(ulong ticks)
5174a4d8c2SCharles.Forsyth {
5274a4d8c2SCharles.Forsyth return ((vlong)ticks * uspertick) / 1000;
5374a4d8c2SCharles.Forsyth }
5474a4d8c2SCharles.Forsyth
5574a4d8c2SCharles.Forsyth void
main(int argc,char * argv[])5674a4d8c2SCharles.Forsyth main(int argc, char *argv[])
5774a4d8c2SCharles.Forsyth {
5874a4d8c2SCharles.Forsyth int fd;
5974a4d8c2SCharles.Forsyth long i, j, k, n;
6074a4d8c2SCharles.Forsyth Dir *d;
6174a4d8c2SCharles.Forsyth char *name;
6274a4d8c2SCharles.Forsyth ulong *data;
6374a4d8c2SCharles.Forsyth ulong tbase, sum;
6474a4d8c2SCharles.Forsyth long delta;
6574a4d8c2SCharles.Forsyth Symbol s;
6674a4d8c2SCharles.Forsyth Biobuf outbuf;
6774a4d8c2SCharles.Forsyth Fhdr f;
6874a4d8c2SCharles.Forsyth struct COUNTER *cp;
6974a4d8c2SCharles.Forsyth
7074a4d8c2SCharles.Forsyth if(argc != 3)
7174a4d8c2SCharles.Forsyth error(0, "usage: kprof text data");
7274a4d8c2SCharles.Forsyth /*
7374a4d8c2SCharles.Forsyth * Read symbol table
7474a4d8c2SCharles.Forsyth */
7574a4d8c2SCharles.Forsyth fd = open(argv[1], OREAD);
7674a4d8c2SCharles.Forsyth if(fd < 0)
7774a4d8c2SCharles.Forsyth error(1, argv[1]);
7874a4d8c2SCharles.Forsyth if (!crackhdr(fd, &f))
7974a4d8c2SCharles.Forsyth error(1, "read text header");
8074a4d8c2SCharles.Forsyth if (f.type == FNONE)
8174a4d8c2SCharles.Forsyth error(0, "text file not an a.out");
8274a4d8c2SCharles.Forsyth if (syminit(fd, &f) < 0)
8374a4d8c2SCharles.Forsyth error(1, "syminit");
8474a4d8c2SCharles.Forsyth close(fd);
8574a4d8c2SCharles.Forsyth /*
8674a4d8c2SCharles.Forsyth * Read timing data
8774a4d8c2SCharles.Forsyth */
8874a4d8c2SCharles.Forsyth fd = open(argv[2], OREAD);
8974a4d8c2SCharles.Forsyth if(fd < 0)
9074a4d8c2SCharles.Forsyth error(1, argv[2]);
9174a4d8c2SCharles.Forsyth if((d = dirfstat(fd)) == nil)
9274a4d8c2SCharles.Forsyth error(1, "stat");
9374a4d8c2SCharles.Forsyth n = d->length/sizeof(data[0]);
9474a4d8c2SCharles.Forsyth if(n < 2)
9574a4d8c2SCharles.Forsyth error(0, "data file too short");
9674a4d8c2SCharles.Forsyth data = malloc(d->length);
9774a4d8c2SCharles.Forsyth if(data == 0)
9874a4d8c2SCharles.Forsyth error(1, "malloc");
9974a4d8c2SCharles.Forsyth if(read(fd, data, d->length) < 0)
10074a4d8c2SCharles.Forsyth error(1, "text read");
10174a4d8c2SCharles.Forsyth close(fd);
10274a4d8c2SCharles.Forsyth free(d);
10374a4d8c2SCharles.Forsyth for(i=0; i<n; i++)
10474a4d8c2SCharles.Forsyth data[i] = beswal(data[i]);
10574a4d8c2SCharles.Forsyth pcres = 1 << data[SpecialSampleLogBucketSize];
10674a4d8c2SCharles.Forsyth uspertick = data[SpecialMicroSecondsPerTick];
10774a4d8c2SCharles.Forsyth if (data[SpecialSampleSize] != sizeof(data[0]))
10874a4d8c2SCharles.Forsyth error(0, "only sample size 4 supported\n");
10974a4d8c2SCharles.Forsyth delta = data[SpecialTotalTicks] - data[SpecialOutsideTicks];
11074a4d8c2SCharles.Forsyth print("total: %lud in kernel text: %lud outside kernel text: %lud\n",
11174a4d8c2SCharles.Forsyth data[0], delta, data[1]);
11274a4d8c2SCharles.Forsyth if(data[0] == 0)
11374a4d8c2SCharles.Forsyth exits(0);
11474a4d8c2SCharles.Forsyth if (!textsym(&s, 0))
11574a4d8c2SCharles.Forsyth error(0, "no text symbols");
11674a4d8c2SCharles.Forsyth tbase = s.value & ~(mach->pgsize-1); /* align down to page */
11774a4d8c2SCharles.Forsyth print("KTZERO %.8lux\n", tbase);
11874a4d8c2SCharles.Forsyth /*
11974a4d8c2SCharles.Forsyth * Accumulate counts for each function
12074a4d8c2SCharles.Forsyth */
12174a4d8c2SCharles.Forsyth cp = 0;
12274a4d8c2SCharles.Forsyth k = 0;
12374a4d8c2SCharles.Forsyth for (i = 0, j = (s.value-tbase)/pcres+SpecialMax; j < n; i++) {
12474a4d8c2SCharles.Forsyth name = s.name; /* save name */
12574a4d8c2SCharles.Forsyth if (!textsym(&s, i)) /* get next symbol */
12674a4d8c2SCharles.Forsyth break;
12774a4d8c2SCharles.Forsyth sum = 0;
12874a4d8c2SCharles.Forsyth while (j < n && j*pcres < s.value-tbase)
12974a4d8c2SCharles.Forsyth sum += data[j++];
13074a4d8c2SCharles.Forsyth if (sum) {
13174a4d8c2SCharles.Forsyth cp = realloc(cp, (k+1)*sizeof(struct COUNTER));
13274a4d8c2SCharles.Forsyth if (cp == 0)
13374a4d8c2SCharles.Forsyth error(1, "realloc");
13474a4d8c2SCharles.Forsyth cp[k].name = name;
13574a4d8c2SCharles.Forsyth cp[k].time = sum;
13674a4d8c2SCharles.Forsyth k++;
13774a4d8c2SCharles.Forsyth }
13874a4d8c2SCharles.Forsyth }
13974a4d8c2SCharles.Forsyth if (!k)
14074a4d8c2SCharles.Forsyth error(0, "no counts");
14174a4d8c2SCharles.Forsyth cp[k].time = 0; /* "etext" can take no time */
14274a4d8c2SCharles.Forsyth /*
14374a4d8c2SCharles.Forsyth * Sort by time and print
14474a4d8c2SCharles.Forsyth */
14574a4d8c2SCharles.Forsyth qsort(cp, k, sizeof(struct COUNTER), compar);
14674a4d8c2SCharles.Forsyth Binit(&outbuf, 1, OWRITE);
14774a4d8c2SCharles.Forsyth Bprint(&outbuf, "ms %% sym\n");
14874a4d8c2SCharles.Forsyth while(--k>=0)
149*ce8e0d60Sforsyth Bprint(&outbuf, "%lud\t%3lud.%ld\t%s\n",
15074a4d8c2SCharles.Forsyth tickstoms(cp[k].time),
15174a4d8c2SCharles.Forsyth 100*cp[k].time/delta,
15274a4d8c2SCharles.Forsyth (1000*cp[k].time/delta)%10,
15374a4d8c2SCharles.Forsyth cp[k].name);
15474a4d8c2SCharles.Forsyth exits(0);
15574a4d8c2SCharles.Forsyth }
156