xref: /inferno-os/utils/kprof/kprof.c (revision ce8e0d607a2bec33fcaac7237d0b5535e5b152a1)
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