xref: /original-bsd/old/prof/prof.c (revision ccda3464)
16d829f4eSsam #ifndef lint
2*ccda3464Sbostic static	char *sccsid = "@(#)prof.c	4.5 (Berkeley) 07/22/88";
36d829f4eSsam #endif
46d829f4eSsam /*
56d829f4eSsam  * prof
66d829f4eSsam  */
76d829f4eSsam #include <stdio.h>
86d829f4eSsam #include <sys/types.h>
96d829f4eSsam #include <sys/stat.h>
106d829f4eSsam #include <a.out.h>
11850218e9Smckusick #include <sys/time.h>
126d829f4eSsam 
13*ccda3464Sbostic typedef	unsigned short UNIT;		/* unit of profiling */
143f355a35Ssam #define	PCFUDGE		11
156d829f4eSsam #define	A_OUTNAME	"a.out"
166d829f4eSsam #define	MON_OUTNAME	"mon.out"
176d829f4eSsam #define	MON_SUMNAME	"mon.sum"
186d829f4eSsam 
196d829f4eSsam /*
206d829f4eSsam  * The symbol table;
216d829f4eSsam  * for each external in the specified file we gather
226d829f4eSsam  * its address, the number of calls and compute its share of cpu time.
236d829f4eSsam  */
246d829f4eSsam struct nl {
256d829f4eSsam 	char	*name;
266d829f4eSsam 	unsigned value;
276d829f4eSsam 	float	time;
286d829f4eSsam 	long	ncall;
296d829f4eSsam } *nl;
306d829f4eSsam int	nname;
316d829f4eSsam struct	nl *np;
326d829f4eSsam struct	nl *npe;
336d829f4eSsam 
346d829f4eSsam /*
356d829f4eSsam  * The header on the mon.out file.
366d829f4eSsam  * Mon.out consists of one of these headers, an array of ncount
376d829f4eSsam  * cnt structures (as below) and then an array of samples
386d829f4eSsam  * representing the discretized program counter values.
396d829f4eSsam  */
406d829f4eSsam struct hdr {
416d829f4eSsam 	UNIT	*lowpc, *highpc;
426d829f4eSsam 	int	ncount;
436d829f4eSsam } h;
446d829f4eSsam 
456d829f4eSsam /*
466d829f4eSsam  * Each counter has an address and a number of calls.
476d829f4eSsam  */
486d829f4eSsam struct cnt {
496d829f4eSsam 	unsigned cvalue;
506d829f4eSsam 	long	cncall;
516d829f4eSsam } *cbuf;
526d829f4eSsam 
536d829f4eSsam /*
546d829f4eSsam  * Each discretized pc sample has
556d829f4eSsam  * a count of the number of samples in its range
566d829f4eSsam  */
57*ccda3464Sbostic UNIT	*samples;
586d829f4eSsam 
596d829f4eSsam FILE	*pfile, *nfile;
606d829f4eSsam 
616d829f4eSsam unsigned lowpc, highpc;		/* range profiled */
626d829f4eSsam double	ransca, ranoff;		/* scaling for blowing up plots */
636d829f4eSsam unsigned sampbytes;		/* number of bytes of samples */
646d829f4eSsam int	nsamples;		/* number of samples */
656d829f4eSsam double	totime;			/* total time for all routines */
666d829f4eSsam double	maxtime;		/* maximum time of any routine (for plot) */
676d829f4eSsam double	scale;			/* scale factor converting samples to pc
686d829f4eSsam 				   values: each sample covers scale bytes */
696d829f4eSsam char	*strtab;		/* string table in core */
706d829f4eSsam off_t	ssiz;			/* size of the string table */
716d829f4eSsam struct	exec xbuf;		/* exec header of a.out */
726d829f4eSsam 
736d829f4eSsam int	aflg;
746d829f4eSsam int	nflg;
756d829f4eSsam int	vflg;
766d829f4eSsam int	lflg;
776d829f4eSsam int	zflg;
786d829f4eSsam int	sflag;
796d829f4eSsam 
806d829f4eSsam char	*namfil;
816d829f4eSsam 
826d829f4eSsam int	timcmp(), valcmp(), cntcmp();
836d829f4eSsam 
main(argc,argv)846d829f4eSsam main(argc, argv)
856d829f4eSsam 	char **argv;
866d829f4eSsam {
876d829f4eSsam 	int lowpct, highpct;
886d829f4eSsam 
896d829f4eSsam 	/*
906d829f4eSsam 	 * Use highpct and lowpc as percentages, temporarily
916d829f4eSsam 	 * for graphing options involving blow-up
926d829f4eSsam 	 */
936d829f4eSsam 	lowpct = -1;
946d829f4eSsam 	highpct = -1;
956d829f4eSsam 	argv++;
966d829f4eSsam 	while ( *argv != 0 && **argv == '-' ) {
976d829f4eSsam 		*argv += 1;
986d829f4eSsam 		if (**argv == 'l')
996d829f4eSsam 			lflg++;
1006d829f4eSsam 		else if (**argv == 'a')
1016d829f4eSsam 			aflg++;
1026d829f4eSsam 		else if (**argv == 'n')
1036d829f4eSsam 			nflg++;
1046d829f4eSsam 		else if (**argv == 'z')
1056d829f4eSsam 			zflg++;
1066d829f4eSsam 		else if (**argv == 'v')
1076d829f4eSsam 			vflg++;
1086d829f4eSsam 		else if ( **argv == 's' )
1096d829f4eSsam 			sflag++;
1106d829f4eSsam 		else if (**argv >= '0' && **argv <= '9') {
1116d829f4eSsam 			int i = atoi(*argv);
1126d829f4eSsam 			if (lowpct == -1)
1136d829f4eSsam 				lowpct = i;
1146d829f4eSsam 			else
1156d829f4eSsam 				highpct = i;
1166d829f4eSsam 		}
1176d829f4eSsam 		argv++;
1186d829f4eSsam 	}
1196d829f4eSsam 	if ( *argv != 0 ) {
1206d829f4eSsam 		namfil = *argv;
1216d829f4eSsam 		argv++;
1226d829f4eSsam 	} else {
1236d829f4eSsam 		namfil = A_OUTNAME;
1246d829f4eSsam 	}
1256d829f4eSsam 	if (lowpct >= 100)
1266d829f4eSsam 		lowpct = 0;
1276d829f4eSsam 	if (highpct <= lowpct || highpct > 100)
1286d829f4eSsam 		highpct = 100;
1296d829f4eSsam 	ransca = 100./(highpct-lowpct);
1306d829f4eSsam 	ranoff = 2040. + 40.8*lowpc*ransca;
1316d829f4eSsam 		/*
1326d829f4eSsam 		 *	get information about a.out file.
1336d829f4eSsam 		 */
1346d829f4eSsam 	getnfile();
1356d829f4eSsam 		/*
1366d829f4eSsam 		 *	get information about mon.out file(s).
1376d829f4eSsam 		 */
1386d829f4eSsam 	if ( *argv == 0 ) {
1396d829f4eSsam 		getpfile( MON_OUTNAME );
1406d829f4eSsam 	} else {
1416d829f4eSsam 		do {
1426d829f4eSsam 			getpfile( *argv );
1436d829f4eSsam 			argv++;
1446d829f4eSsam 		} while ( *argv != 0 );
1456d829f4eSsam 	}
1466d829f4eSsam 	asgnsamples();		/* assign samples to procedures */
1476d829f4eSsam #ifdef plot
1486d829f4eSsam 	if (vflg)
1496d829f4eSsam 		plotprof();	/* a plotted or ... */
1506d829f4eSsam 	else
1516d829f4eSsam #endif
1526d829f4eSsam 		printprof();	/* a printed profile */
1536d829f4eSsam 	if ( sflag != 0 ) {
1546d829f4eSsam 		putprof();
1556d829f4eSsam 	}
1566d829f4eSsam 	done();
1576d829f4eSsam }
1586d829f4eSsam 
printprof()1596d829f4eSsam printprof()
1606d829f4eSsam {
161850218e9Smckusick 	double time, actime, hz;
1626d829f4eSsam 
1636d829f4eSsam 	actime = 0;
164850218e9Smckusick 	hz = hertz();
1656d829f4eSsam 	printf(" %%time  cumsecs  #call  ms/call  name\n");
1666d829f4eSsam 	if (!lflg)
1676d829f4eSsam 		qsort(nl, nname, sizeof(struct nl), timcmp);
1686d829f4eSsam 	for (np = nl; np<npe-1; np++) {
1696d829f4eSsam 		if (zflg == 0 && np->time == 0 && np->ncall == 0)
1706d829f4eSsam 			continue;
1716d829f4eSsam 		time = np->time/totime;
1726d829f4eSsam 		actime += np->time;
173850218e9Smckusick 		printf("%6.1f%9.2f", 100*time, actime/hz);
1746d829f4eSsam 		if (np->ncall != 0)
1756d829f4eSsam 			printf("%7ld %8.2f",
176850218e9Smckusick 			    np->ncall, (np->time*1000/hz)/np->ncall);
1776d829f4eSsam 		else
1786d829f4eSsam 			printf("%7.7s %8.8s", "", "");
1796d829f4eSsam 		printf("  %s\n", np->name);
1806d829f4eSsam 	}
1816d829f4eSsam }
1826d829f4eSsam 
1836d829f4eSsam /*
1846d829f4eSsam  * Set up string and symbol tables from a.out.
1856d829f4eSsam  * On return symbol table is sorted by value.
1866d829f4eSsam  */
getnfile()1876d829f4eSsam getnfile()
1886d829f4eSsam {
1896d829f4eSsam 
1906d829f4eSsam 	nfile = fopen(namfil,"r");
1916d829f4eSsam 	if (nfile == NULL) {
1926d829f4eSsam 		perror(namfil);
1936d829f4eSsam 		done();
1946d829f4eSsam 	}
1956d829f4eSsam 	fread(&xbuf, 1, sizeof(xbuf), nfile);
1966d829f4eSsam 	if (N_BADMAG(xbuf)) {
1976d829f4eSsam 		fprintf(stderr, "%s: bad format\n", namfil);
1986d829f4eSsam 		done();
1996d829f4eSsam 	}
2006d829f4eSsam 	getstrtab();
2016d829f4eSsam 	getsymtab();
2026d829f4eSsam 	qsort(nl, nname, sizeof(struct nl), valcmp);
2036d829f4eSsam }
2046d829f4eSsam 
getstrtab()2056d829f4eSsam getstrtab()
2066d829f4eSsam {
2076d829f4eSsam 
2086d829f4eSsam 	fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0);
2096d829f4eSsam 	if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
2106d829f4eSsam 		fprintf(stderr, "%s: no string table (old format?)\n", namfil);
2116d829f4eSsam 		done();
2126d829f4eSsam 	}
2136d829f4eSsam 	strtab = (char *)calloc(ssiz, 1);
2146d829f4eSsam 	if (strtab == NULL) {
2156d829f4eSsam 		fprintf(stderr, "%s: no room for %d bytes of string table",
2166d829f4eSsam 		    namfil, ssiz);
2176d829f4eSsam 		done();
2186d829f4eSsam 	}
2196d829f4eSsam 	if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
2206d829f4eSsam 		fprintf(stderr, "%s: error reading string table\n", namfil);
2216d829f4eSsam 		done();
2226d829f4eSsam 	}
2236d829f4eSsam }
2246d829f4eSsam 
2256d829f4eSsam /*
2266d829f4eSsam  * Read in symbol table
2276d829f4eSsam  */
getsymtab()2286d829f4eSsam getsymtab()
2296d829f4eSsam {
2306d829f4eSsam 	register int i;
2316d829f4eSsam 
2326d829f4eSsam 	/* pass1 - count symbols */
2336d829f4eSsam 	fseek(nfile, N_SYMOFF(xbuf), 0);
2346d829f4eSsam 	nname = 0;
2356d829f4eSsam 	for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2366d829f4eSsam 		struct nlist nbuf;
2376d829f4eSsam 		fread(&nbuf, sizeof(nbuf), 1, nfile);
2386d829f4eSsam 		if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
2396d829f4eSsam 			continue;
2406d829f4eSsam 		if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
2416d829f4eSsam 			continue;
2426d829f4eSsam 		nname++;
2436d829f4eSsam 	}
2446d829f4eSsam 	if (nname == 0) {
2456d829f4eSsam 		fprintf(stderr, "%s: no symbols\n", namfil);
2466d829f4eSsam 		done();
2476d829f4eSsam 	}
2486d829f4eSsam 	nl = (struct nl *)calloc((nname+1), sizeof (struct nl));
2496d829f4eSsam 	if (nl == 0) {
2506d829f4eSsam 		fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
2516d829f4eSsam 		    (nname+1) * sizeof (struct nlist));
2526d829f4eSsam 		done();
2536d829f4eSsam 	}
2546d829f4eSsam 
2556d829f4eSsam 	/* pass2 - read symbols */
2566d829f4eSsam 	fseek(nfile, N_SYMOFF(xbuf), 0);
2576d829f4eSsam 	npe = nl;
2586d829f4eSsam 	nname = 0;
2596d829f4eSsam 	for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
2606d829f4eSsam 		struct nlist nbuf;
2616d829f4eSsam 		fread(&nbuf, sizeof(nbuf), 1, nfile);
2626d829f4eSsam 		if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
2636d829f4eSsam 			continue;
2646d829f4eSsam 		if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
2656d829f4eSsam 			continue;
2666d829f4eSsam 		npe->value = nbuf.n_value/sizeof(UNIT);
2676d829f4eSsam 		npe->name = strtab+nbuf.n_un.n_strx;
2686d829f4eSsam 		npe++;
2696d829f4eSsam 		nname++;
2706d829f4eSsam 	}
2716d829f4eSsam 	npe->value = -1;
2726d829f4eSsam 	npe++;
2736d829f4eSsam }
2746d829f4eSsam 
2756d829f4eSsam /*
2766d829f4eSsam  * information from a mon.out file is in two parts:
2776d829f4eSsam  * the counters of how many times each procedure was called,
2786d829f4eSsam  * if it was called at all;
2796d829f4eSsam  * and an array of sampling hits within pc ranges.
2806d829f4eSsam  * the counters must be dealt with on a file-by-file basis,
2816d829f4eSsam  * since which procedures are represented may vary.
2826d829f4eSsam  * the samples ranges are fixed, but must be summed across
2836d829f4eSsam  * files, and then distributed among procedures, because
2846d829f4eSsam  * of the wierd way the plotting is done.
2856d829f4eSsam  */
getpfile(filename)2866d829f4eSsam getpfile(filename)
2876d829f4eSsam 	char *filename;
2886d829f4eSsam {
2896d829f4eSsam 
2906d829f4eSsam 	openpfile(filename);
2916d829f4eSsam 	readcntrs();
2926d829f4eSsam 	asgncntrs();		/* assign counts to procedures */
2936d829f4eSsam 	readsamples();
2946d829f4eSsam 	closepfile();
2956d829f4eSsam }
2966d829f4eSsam 
openpfile(filename)2976d829f4eSsam openpfile(filename)
2986d829f4eSsam 	char *filename;
2996d829f4eSsam {
3006d829f4eSsam 	struct stat stb;
3016d829f4eSsam 
3026d829f4eSsam 	if((pfile = fopen(filename, "r")) == NULL) {
3036d829f4eSsam 		perror(filename);
3046d829f4eSsam 		done();
3056d829f4eSsam 	}
3066d829f4eSsam 	fstat(fileno(pfile), &stb);
3076d829f4eSsam 	fread(&h, sizeof(struct hdr), 1, pfile);
3086d829f4eSsam 	lowpc = h.lowpc - (UNIT *)0;
3096d829f4eSsam 	highpc = h.highpc - (UNIT *)0;
3106d829f4eSsam 	sampbytes =
3116d829f4eSsam 	    stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt);
312*ccda3464Sbostic 	nsamples = sampbytes / sizeof (UNIT);
3136d829f4eSsam }
3146d829f4eSsam 
closepfile()3156d829f4eSsam closepfile()
3166d829f4eSsam {
3176d829f4eSsam 
3186d829f4eSsam 	fclose(pfile);
3196d829f4eSsam 	free(cbuf);
3206d829f4eSsam }
3216d829f4eSsam 
readcntrs()3226d829f4eSsam readcntrs()
3236d829f4eSsam {
3246d829f4eSsam 	struct cnt *kp;
3256d829f4eSsam 
3266d829f4eSsam 	cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt));
3276d829f4eSsam 	if (cbuf == 0) {
3286d829f4eSsam 		fprintf(stderr, "prof: No room for %d bytes of count buffer\n",
3296d829f4eSsam 		    (h.ncount+1) * sizeof (struct cnt));
3306d829f4eSsam 		exit(1);
3316d829f4eSsam 	}
3326d829f4eSsam 	fread(cbuf, sizeof(struct cnt), h.ncount, pfile);
3336d829f4eSsam 	/* eliminate zero counters and scale counter pc values */
3346d829f4eSsam 	if (h.ncount) {
3356d829f4eSsam 		kp = &cbuf[h.ncount - 1];
3366d829f4eSsam 		for (;;) {
3376d829f4eSsam 			if (kp->cvalue==0) {
3386d829f4eSsam 				h.ncount=kp-cbuf;
3396d829f4eSsam 				++kp;
3406d829f4eSsam 				break;
3416d829f4eSsam 			}
3426d829f4eSsam 			if (kp == cbuf) {
3436d829f4eSsam 				h.ncount = 0;
3446d829f4eSsam 				break;
3456d829f4eSsam 			}
3466d829f4eSsam 			--kp;
3476d829f4eSsam 		}
3486d829f4eSsam 		for (; --kp>=cbuf; )
3496d829f4eSsam 			kp->cvalue /= sizeof(UNIT);
3506d829f4eSsam 	}
3516d829f4eSsam 	/* sort counters */
3526d829f4eSsam 	qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp);
3536d829f4eSsam }
3546d829f4eSsam 
3556d829f4eSsam /*
3566d829f4eSsam  * Assign counters to the procedures to which they belong
3576d829f4eSsam  */
asgncntrs()3586d829f4eSsam asgncntrs()
3596d829f4eSsam {
3606d829f4eSsam 	register int i;
3616d829f4eSsam 	struct cnt *kp;
3626d829f4eSsam 
3636d829f4eSsam 	kp = &cbuf[h.ncount-1];
3646d829f4eSsam 	np = npe;
3656d829f4eSsam 	while (--np>=nl) {
3666d829f4eSsam 		if (kp<cbuf || np->value > kp->cvalue)
3676d829f4eSsam 			continue;
3686d829f4eSsam 			/* skip ``static'' functions */
3693f355a35Ssam 		while (kp >= cbuf && kp->cvalue > np->value + PCFUDGE)
3706d829f4eSsam 			--kp;
3716d829f4eSsam 		if (kp->cvalue >= np->value) {
3726d829f4eSsam 			np->ncall += kp->cncall;
3736d829f4eSsam 			--kp;
3746d829f4eSsam 		}
3756d829f4eSsam 	}
3766d829f4eSsam }
3776d829f4eSsam 
readsamples()3786d829f4eSsam readsamples()
3796d829f4eSsam {
3806d829f4eSsam 	register i;
381*ccda3464Sbostic 	UNIT	sample;
3826d829f4eSsam 	int totalt;
3836d829f4eSsam 
3846d829f4eSsam 	if (samples == 0) {
385*ccda3464Sbostic 		samples = (UNIT *)
386*ccda3464Sbostic 		    calloc(sampbytes, sizeof (UNIT));
3876d829f4eSsam 		if (samples == 0) {
3886d829f4eSsam 			printf("prof: No room for %d sample pc's\n",
389*ccda3464Sbostic 			    sampbytes / sizeof (UNIT));
3906d829f4eSsam 			done();
3916d829f4eSsam 		}
3926d829f4eSsam 	}
3936d829f4eSsam 	for (i = 0; ; i++) {
394*ccda3464Sbostic 		fread(&sample, sizeof (UNIT), 1, pfile);
3956d829f4eSsam 		if (feof(pfile))
3966d829f4eSsam 			break;
3976d829f4eSsam 		samples[i] += sample;
3986d829f4eSsam 		totalt += sample;
3996d829f4eSsam 	}
4006d829f4eSsam 	if (i != nsamples) {
4016d829f4eSsam 		fprintf(stderr,
4026d829f4eSsam 		    "prof: unexpected EOF after reading %d/%d samples\n",
4036d829f4eSsam 			--i, nsamples);
4046d829f4eSsam 		done();
4056d829f4eSsam 	}
4066d829f4eSsam }
4076d829f4eSsam 
4086d829f4eSsam /*
4096d829f4eSsam  * Assign samples to the procedures to which they belong.
4106d829f4eSsam  */
asgnsamples()4116d829f4eSsam asgnsamples()
4126d829f4eSsam {
4136d829f4eSsam 	register j;
414*ccda3464Sbostic 	UNIT	ccnt;
4156d829f4eSsam 	double time;
4166d829f4eSsam 	unsigned pcl, pch;
4176d829f4eSsam 	register int i;
4186d829f4eSsam 	int overlap;
4196d829f4eSsam 
4206d829f4eSsam 	/* read samples and assign to namelist symbols */
4216d829f4eSsam 	scale = highpc - lowpc;
4226d829f4eSsam 	scale /= nsamples;
4236d829f4eSsam 	for (i=0; i < nsamples; i++) {
4246d829f4eSsam 		ccnt = samples[i];
4256d829f4eSsam 		if (ccnt == 0)
4266d829f4eSsam 			continue;
4276d829f4eSsam 		pcl = lowpc + scale*i;
4286d829f4eSsam 		pch = lowpc + scale*(i+1);
4296d829f4eSsam 		time = ccnt;
4306d829f4eSsam 		totime += time;
4316d829f4eSsam 		if(time > maxtime)
4326d829f4eSsam 			maxtime = time;
4336d829f4eSsam 		for (j=0; j<nname; j++) {
4346d829f4eSsam 			if (pch < nl[j].value)
4356d829f4eSsam 				break;
4366d829f4eSsam 			if (pcl >= nl[j+1].value)
4376d829f4eSsam 				continue;
4386d829f4eSsam 			overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value));
4396d829f4eSsam 			if (overlap>0)
4406d829f4eSsam 				nl[j].time += overlap*time/scale;
4416d829f4eSsam 		}
4426d829f4eSsam 	}
4436d829f4eSsam 	if (totime==0.0) {
4446d829f4eSsam 		fprintf(stderr, "No time accumulated\n");
4456d829f4eSsam /*
4466d829f4eSsam 		done();
4476d829f4eSsam  */
4486d829f4eSsam 		totime=1.0;
4496d829f4eSsam 	}
4506d829f4eSsam }
4516d829f4eSsam 
4526d829f4eSsam /*
4536d829f4eSsam  * dump what you have out to a mon.out style file.
4546d829f4eSsam  */
putprof()4556d829f4eSsam putprof()
4566d829f4eSsam {
4576d829f4eSsam 	FILE *sfile;
4586d829f4eSsam 	struct nl *np;
4596d829f4eSsam 	struct cnt kp;
4606d829f4eSsam 	int i;
4616d829f4eSsam 
4626d829f4eSsam 	sfile = fopen(MON_SUMNAME, "w");
4636d829f4eSsam 	if (sfile == NULL) {
4646d829f4eSsam 		perror(MON_SUMNAME);
4656d829f4eSsam 		done();
4666d829f4eSsam 	}
4676d829f4eSsam 	/*
4686d829f4eSsam 	 * build a new header.
4696d829f4eSsam 	 * h.lowpc and h.highpc are already fine.
4706d829f4eSsam 	 * fix h.ncount to count non-zero calls,
4716d829f4eSsam 	 * and the one zero call which marks the end.
4726d829f4eSsam 	 */
4736d829f4eSsam 	h.ncount = 0;
4746d829f4eSsam 	for (np = nl; np < npe-1 ; np++)
4756d829f4eSsam 		if (np->ncall > 0)
4766d829f4eSsam 			h.ncount++;
4776d829f4eSsam 	h.ncount++;
4786d829f4eSsam 	fwrite(&h, sizeof (struct hdr), 1, sfile);
4796d829f4eSsam 	for (np = nl; np < npe-1; np++) {
4806d829f4eSsam 		if (np->ncall > 0) {
481*ccda3464Sbostic 			kp.cvalue = np->value * sizeof (UNIT);
4826d829f4eSsam 			kp.cncall = np->ncall;
4836d829f4eSsam 			fwrite(&kp, sizeof (struct cnt), 1, sfile);
4846d829f4eSsam 		}
4856d829f4eSsam 	}
4866d829f4eSsam 	kp.cvalue = 0;
4876d829f4eSsam 	kp.cncall = 0;
4886d829f4eSsam 	fwrite(&kp, sizeof (struct cnt), 1, sfile);
489*ccda3464Sbostic 	fwrite(samples, sizeof (UNIT), nsamples, sfile);
4906d829f4eSsam 	fclose(sfile);
4916d829f4eSsam }
4926d829f4eSsam 
493850218e9Smckusick /*
494850218e9Smckusick  *	discover the tick frequency of the machine
495850218e9Smckusick  *	if something goes wrong, we return 1.
496850218e9Smckusick  */
hertz()497850218e9Smckusick hertz()
498850218e9Smckusick {
499850218e9Smckusick 	struct itimerval tim;
500850218e9Smckusick 
501850218e9Smckusick 	tim.it_interval.tv_sec = 0;
502850218e9Smckusick 	tim.it_interval.tv_usec = 1;
503850218e9Smckusick 	tim.it_value.tv_sec = 0;
504850218e9Smckusick 	tim.it_value.tv_usec = 0;
505850218e9Smckusick 	setitimer(ITIMER_REAL, &tim, 0);
506850218e9Smckusick 	setitimer(ITIMER_REAL, 0, &tim);
507850218e9Smckusick 	if (tim.it_interval.tv_usec < 1)
508850218e9Smckusick 		return (1);
509850218e9Smckusick 	return (1000000 / tim.it_interval.tv_usec);
510850218e9Smckusick }
511850218e9Smckusick 
min(a,b)5126d829f4eSsam min(a, b)
5136d829f4eSsam {
5146d829f4eSsam 	if (a<b)
5156d829f4eSsam 		return(a);
5166d829f4eSsam 	return(b);
5176d829f4eSsam }
5186d829f4eSsam 
max(a,b)5196d829f4eSsam max(a, b)
5206d829f4eSsam {
5216d829f4eSsam 	if (a>b)
5226d829f4eSsam 		return(a);
5236d829f4eSsam 	return(b);
5246d829f4eSsam }
5256d829f4eSsam 
5266d829f4eSsam valcmp(p1, p2)
5276d829f4eSsam 	struct nl *p1, *p2;
5286d829f4eSsam {
5296d829f4eSsam 
5306d829f4eSsam 	return(p1->value - p2->value);
5316d829f4eSsam }
5326d829f4eSsam 
5336d829f4eSsam timcmp(p1, p2)
5346d829f4eSsam 	struct nl *p1, *p2;
5356d829f4eSsam {
5366d829f4eSsam 	float d;
5376d829f4eSsam 
5386d829f4eSsam 	if (nflg && p2->ncall != p1->ncall)
5396d829f4eSsam 		return (p2->ncall - p1->ncall);
5406d829f4eSsam 	d = p2->time - p1->time;
5416d829f4eSsam 	if (d > 0.0)
5426d829f4eSsam 		return(1);
5436d829f4eSsam 	if (d < 0.0)
5446d829f4eSsam 		return(-1);
5456d829f4eSsam 	return(strcmp(p1->name,p2->name));
5466d829f4eSsam }
5476d829f4eSsam 
5486d829f4eSsam cntcmp(p1, p2)
5496d829f4eSsam 	struct cnt *p1, *p2;
5506d829f4eSsam {
5516d829f4eSsam 
5526d829f4eSsam 	return(p1->cvalue - p2->cvalue);
5536d829f4eSsam }
5546d829f4eSsam 
done()5556d829f4eSsam done()
5566d829f4eSsam {
5576d829f4eSsam 
5586d829f4eSsam #ifdef plot
5596d829f4eSsam 	if(vflg) {
5606d829f4eSsam 		point(0, -2040);
5616d829f4eSsam 		closepl();
5626d829f4eSsam 	}
5636d829f4eSsam #endif
5646d829f4eSsam 	exit(0);
5656d829f4eSsam }
5666d829f4eSsam 
5676d829f4eSsam #ifdef plot
plotprof()5686d829f4eSsam plotprof()
5696d829f4eSsam {
5706d829f4eSsam 	double time, lastx, lasty, lastsx;
5716d829f4eSsam 	register i;
5726d829f4eSsam 
5736d829f4eSsam 	openpl();
5746d829f4eSsam 	erase();
5756d829f4eSsam 	space(-2048, -2048, 2048, 2048);
5766d829f4eSsam 	line(-2040, -2040, -2040, 2040);
5776d829f4eSsam 	line(0, 2040, 0, -2040);
5786d829f4eSsam 	for(i=0; i<11; i++)
5796d829f4eSsam 		line(-2040, 2040-i*408, 0, 2040-i*408);
5806d829f4eSsam 	lastx = 0.;
5816d829f4eSsam 	lasty = ranoff;
5826d829f4eSsam 	scale = (4080.*ransca)/(sampbytes/sizeof(UNIT));
5836d829f4eSsam 	lastsx = 0.0;
5846d829f4eSsam 	for(i = 0; i < nsamples; i++) {
585*ccda3464Sbostic 		UNIT ccnt;
5866d829f4eSsam 		double tx, ty;
5876d829f4eSsam 		ccnt = samples[i];
5886d829f4eSsam 		time = ccnt;
5896d829f4eSsam 		tx = lastsx;
5906d829f4eSsam 		ty = lasty;
5916d829f4eSsam 		lastsx -= 2000.*time/totime;
5926d829f4eSsam 		lasty -= scale;
5936d829f4eSsam 		if(lasty >= -2040. && ty <= 2040.) {
5946d829f4eSsam 			line((int)tx, (int)ty, (int)lastsx, (int)lasty);
5956d829f4eSsam 			if (ccnt!=0 || lastx!=0.0) {
5966d829f4eSsam 				tx = lastx;
5976d829f4eSsam 				lastx = -time*2000./maxtime;
5986d829f4eSsam 				ty += scale/2;
5996d829f4eSsam 				line(0, (int)ty, (int)tx, (int)ty);
6006d829f4eSsam 			}
6016d829f4eSsam 		}
6026d829f4eSsam 	}
6036d829f4eSsam 	scale = (4080.*ransca)/(highpc-lowpc);
6046d829f4eSsam 	lastx = 50.;
6056d829f4eSsam 	for(np = nl; np<npe;  np++) {
6066d829f4eSsam 		if(np->value < lowpc)
6076d829f4eSsam 			continue;
6086d829f4eSsam 		if(np->value >= highpc)
6096d829f4eSsam 			continue;
610c899282bSroot 		if(zflg == 0 && np->time == 0 && np->ncall == 0)
611c899282bSroot 			continue;
6126d829f4eSsam 		time = np->time/totime;
6136d829f4eSsam 		lasty = ranoff - (np->value - lowpc)*scale;
6146d829f4eSsam 		if(lasty >= -2040. && lasty <= 2040.) {
6156d829f4eSsam 			char bufl[BUFSIZ], *namp;
6166d829f4eSsam 			register j;
6176d829f4eSsam 			line(0, (int)lasty, 50, (int)lasty);
6186d829f4eSsam 			line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty);
6196d829f4eSsam 			move((int)(lastx+30), (int)(lasty+10));
6206d829f4eSsam 			sprintf(bufl, "%s", np->name + (np->name[0] == '_'));
6216d829f4eSsam 			label(bufl);
6226d829f4eSsam 		}
6236d829f4eSsam 		lastx += 500.;
6246d829f4eSsam 		if(lastx > 2000.)
6256d829f4eSsam 			lastx = 50.;
6266d829f4eSsam 	}
6276d829f4eSsam }
6286d829f4eSsam #endif
629