xref: /csrg-svn/old/prof/prof.c (revision 12892)
1*12892Ssam #ifndef lint
2*12892Ssam static	char *sccsid = "@(#)prof.c	4.1 (Berkeley) 06/02/83";
3*12892Ssam #endif
4*12892Ssam /*
5*12892Ssam  * prof
6*12892Ssam  */
7*12892Ssam #include <stdio.h>
8*12892Ssam #include <sys/types.h>
9*12892Ssam #include <sys/stat.h>
10*12892Ssam #include <a.out.h>
11*12892Ssam 
12*12892Ssam typedef	short UNIT;		/* unit of profiling */
13*12892Ssam #define	A_OUTNAME	"a.out"
14*12892Ssam #define	MON_OUTNAME	"mon.out"
15*12892Ssam #define	MON_SUMNAME	"mon.sum"
16*12892Ssam 
17*12892Ssam /*
18*12892Ssam  * The symbol table;
19*12892Ssam  * for each external in the specified file we gather
20*12892Ssam  * its address, the number of calls and compute its share of cpu time.
21*12892Ssam  */
22*12892Ssam struct nl {
23*12892Ssam 	char	*name;
24*12892Ssam 	unsigned value;
25*12892Ssam 	float	time;
26*12892Ssam 	long	ncall;
27*12892Ssam } *nl;
28*12892Ssam int	nname;
29*12892Ssam struct	nl *np;
30*12892Ssam struct	nl *npe;
31*12892Ssam 
32*12892Ssam /*
33*12892Ssam  * The header on the mon.out file.
34*12892Ssam  * Mon.out consists of one of these headers, an array of ncount
35*12892Ssam  * cnt structures (as below) and then an array of samples
36*12892Ssam  * representing the discretized program counter values.
37*12892Ssam  */
38*12892Ssam struct hdr {
39*12892Ssam 	UNIT	*lowpc, *highpc;
40*12892Ssam 	int	ncount;
41*12892Ssam } h;
42*12892Ssam 
43*12892Ssam /*
44*12892Ssam  * Each counter has an address and a number of calls.
45*12892Ssam  */
46*12892Ssam struct cnt {
47*12892Ssam 	unsigned cvalue;
48*12892Ssam 	long	cncall;
49*12892Ssam } *cbuf;
50*12892Ssam 
51*12892Ssam /*
52*12892Ssam  * Each discretized pc sample has
53*12892Ssam  * a count of the number of samples in its range
54*12892Ssam  */
55*12892Ssam unsigned UNIT	*samples;
56*12892Ssam 
57*12892Ssam FILE	*pfile, *nfile;
58*12892Ssam 
59*12892Ssam unsigned lowpc, highpc;		/* range profiled */
60*12892Ssam double	ransca, ranoff;		/* scaling for blowing up plots */
61*12892Ssam unsigned sampbytes;		/* number of bytes of samples */
62*12892Ssam int	nsamples;		/* number of samples */
63*12892Ssam double	totime;			/* total time for all routines */
64*12892Ssam double	maxtime;		/* maximum time of any routine (for plot) */
65*12892Ssam double	scale;			/* scale factor converting samples to pc
66*12892Ssam 				   values: each sample covers scale bytes */
67*12892Ssam char	*strtab;		/* string table in core */
68*12892Ssam off_t	ssiz;			/* size of the string table */
69*12892Ssam struct	exec xbuf;		/* exec header of a.out */
70*12892Ssam 
71*12892Ssam int	aflg;
72*12892Ssam int	nflg;
73*12892Ssam int	vflg;
74*12892Ssam int	lflg;
75*12892Ssam int	zflg;
76*12892Ssam int	sflag;
77*12892Ssam 
78*12892Ssam char	*namfil;
79*12892Ssam 
80*12892Ssam int	timcmp(), valcmp(), cntcmp();
81*12892Ssam 
82*12892Ssam main(argc, argv)
83*12892Ssam 	char **argv;
84*12892Ssam {
85*12892Ssam 	int lowpct, highpct;
86*12892Ssam 
87*12892Ssam 	/*
88*12892Ssam 	 * Use highpct and lowpc as percentages, temporarily
89*12892Ssam 	 * for graphing options involving blow-up
90*12892Ssam 	 */
91*12892Ssam 	lowpct = -1;
92*12892Ssam 	highpct = -1;
93*12892Ssam 	argv++;
94*12892Ssam 	while ( *argv != 0 && **argv == '-' ) {
95*12892Ssam 		*argv += 1;
96*12892Ssam 		if (**argv == 'l')
97*12892Ssam 			lflg++;
98*12892Ssam 		else if (**argv == 'a')
99*12892Ssam 			aflg++;
100*12892Ssam 		else if (**argv == 'n')
101*12892Ssam 			nflg++;
102*12892Ssam 		else if (**argv == 'z')
103*12892Ssam 			zflg++;
104*12892Ssam 		else if (**argv == 'v')
105*12892Ssam 			vflg++;
106*12892Ssam 		else if ( **argv == 's' )
107*12892Ssam 			sflag++;
108*12892Ssam 		else if (**argv >= '0' && **argv <= '9') {
109*12892Ssam 			int i = atoi(*argv);
110*12892Ssam 			if (lowpct == -1)
111*12892Ssam 				lowpct = i;
112*12892Ssam 			else
113*12892Ssam 				highpct = i;
114*12892Ssam 		}
115*12892Ssam 		argv++;
116*12892Ssam 	}
117*12892Ssam 	if ( *argv != 0 ) {
118*12892Ssam 		namfil = *argv;
119*12892Ssam 		argv++;
120*12892Ssam 	} else {
121*12892Ssam 		namfil = A_OUTNAME;
122*12892Ssam 	}
123*12892Ssam 	if (lowpct >= 100)
124*12892Ssam 		lowpct = 0;
125*12892Ssam 	if (highpct <= lowpct || highpct > 100)
126*12892Ssam 		highpct = 100;
127*12892Ssam 	ransca = 100./(highpct-lowpct);
128*12892Ssam 	ranoff = 2040. + 40.8*lowpc*ransca;
129*12892Ssam 		/*
130*12892Ssam 		 *	get information about a.out file.
131*12892Ssam 		 */
132*12892Ssam 	getnfile();
133*12892Ssam 		/*
134*12892Ssam 		 *	get information about mon.out file(s).
135*12892Ssam 		 */
136*12892Ssam 	if ( *argv == 0 ) {
137*12892Ssam 		getpfile( MON_OUTNAME );
138*12892Ssam 	} else {
139*12892Ssam 		do {
140*12892Ssam 			getpfile( *argv );
141*12892Ssam 			argv++;
142*12892Ssam 		} while ( *argv != 0 );
143*12892Ssam 	}
144*12892Ssam 	asgnsamples();		/* assign samples to procedures */
145*12892Ssam #ifdef plot
146*12892Ssam 	if (vflg)
147*12892Ssam 		plotprof();	/* a plotted or ... */
148*12892Ssam 	else
149*12892Ssam #endif
150*12892Ssam 		printprof();	/* a printed profile */
151*12892Ssam 	if ( sflag != 0 ) {
152*12892Ssam 		putprof();
153*12892Ssam 	}
154*12892Ssam 	done();
155*12892Ssam }
156*12892Ssam 
157*12892Ssam printprof()
158*12892Ssam {
159*12892Ssam 	double time, actime;
160*12892Ssam 
161*12892Ssam 	actime = 0;
162*12892Ssam 	printf(" %%time  cumsecs  #call  ms/call  name\n");
163*12892Ssam 	if (!lflg)
164*12892Ssam 		qsort(nl, nname, sizeof(struct nl), timcmp);
165*12892Ssam 	for (np = nl; np<npe-1; np++) {
166*12892Ssam 		if (zflg == 0 && np->time == 0 && np->ncall == 0)
167*12892Ssam 			continue;
168*12892Ssam 		time = np->time/totime;
169*12892Ssam 		actime += np->time;
170*12892Ssam 		printf("%6.1f%9.2f", 100*time, actime/60);
171*12892Ssam 		if (np->ncall != 0)
172*12892Ssam 			printf("%7ld %8.2f",
173*12892Ssam 			    np->ncall, np->time/(np->ncall*.06));
174*12892Ssam 		else
175*12892Ssam 			printf("%7.7s %8.8s", "", "");
176*12892Ssam 		printf("  %s\n", np->name);
177*12892Ssam 	}
178*12892Ssam }
179*12892Ssam 
180*12892Ssam /*
181*12892Ssam  * Set up string and symbol tables from a.out.
182*12892Ssam  * On return symbol table is sorted by value.
183*12892Ssam  */
184*12892Ssam getnfile()
185*12892Ssam {
186*12892Ssam 
187*12892Ssam 	nfile = fopen(namfil,"r");
188*12892Ssam 	if (nfile == NULL) {
189*12892Ssam 		perror(namfil);
190*12892Ssam 		done();
191*12892Ssam 	}
192*12892Ssam 	fread(&xbuf, 1, sizeof(xbuf), nfile);
193*12892Ssam 	if (N_BADMAG(xbuf)) {
194*12892Ssam 		fprintf(stderr, "%s: bad format\n", namfil);
195*12892Ssam 		done();
196*12892Ssam 	}
197*12892Ssam 	getstrtab();
198*12892Ssam 	getsymtab();
199*12892Ssam 	qsort(nl, nname, sizeof(struct nl), valcmp);
200*12892Ssam }
201*12892Ssam 
202*12892Ssam getstrtab()
203*12892Ssam {
204*12892Ssam 
205*12892Ssam 	fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0);
206*12892Ssam 	if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
207*12892Ssam 		fprintf(stderr, "%s: no string table (old format?)\n", namfil);
208*12892Ssam 		done();
209*12892Ssam 	}
210*12892Ssam 	strtab = (char *)calloc(ssiz, 1);
211*12892Ssam 	if (strtab == NULL) {
212*12892Ssam 		fprintf(stderr, "%s: no room for %d bytes of string table",
213*12892Ssam 		    namfil, ssiz);
214*12892Ssam 		done();
215*12892Ssam 	}
216*12892Ssam 	if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
217*12892Ssam 		fprintf(stderr, "%s: error reading string table\n", namfil);
218*12892Ssam 		done();
219*12892Ssam 	}
220*12892Ssam }
221*12892Ssam 
222*12892Ssam /*
223*12892Ssam  * Read in symbol table
224*12892Ssam  */
225*12892Ssam getsymtab()
226*12892Ssam {
227*12892Ssam 	register int i;
228*12892Ssam 
229*12892Ssam 	/* pass1 - count symbols */
230*12892Ssam 	fseek(nfile, N_SYMOFF(xbuf), 0);
231*12892Ssam 	nname = 0;
232*12892Ssam 	for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
233*12892Ssam 		struct nlist nbuf;
234*12892Ssam 		fread(&nbuf, sizeof(nbuf), 1, nfile);
235*12892Ssam 		if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
236*12892Ssam 			continue;
237*12892Ssam 		if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
238*12892Ssam 			continue;
239*12892Ssam 		nname++;
240*12892Ssam 	}
241*12892Ssam 	if (nname == 0) {
242*12892Ssam 		fprintf(stderr, "%s: no symbols\n", namfil);
243*12892Ssam 		done();
244*12892Ssam 	}
245*12892Ssam 	nl = (struct nl *)calloc((nname+1), sizeof (struct nl));
246*12892Ssam 	if (nl == 0) {
247*12892Ssam 		fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
248*12892Ssam 		    (nname+1) * sizeof (struct nlist));
249*12892Ssam 		done();
250*12892Ssam 	}
251*12892Ssam 
252*12892Ssam 	/* pass2 - read symbols */
253*12892Ssam 	fseek(nfile, N_SYMOFF(xbuf), 0);
254*12892Ssam 	npe = nl;
255*12892Ssam 	nname = 0;
256*12892Ssam 	for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
257*12892Ssam 		struct nlist nbuf;
258*12892Ssam 		fread(&nbuf, sizeof(nbuf), 1, nfile);
259*12892Ssam 		if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
260*12892Ssam 			continue;
261*12892Ssam 		if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
262*12892Ssam 			continue;
263*12892Ssam 		npe->value = nbuf.n_value/sizeof(UNIT);
264*12892Ssam 		npe->name = strtab+nbuf.n_un.n_strx;
265*12892Ssam 		npe++;
266*12892Ssam 		nname++;
267*12892Ssam 	}
268*12892Ssam 	npe->value = -1;
269*12892Ssam 	npe++;
270*12892Ssam }
271*12892Ssam 
272*12892Ssam /*
273*12892Ssam  * information from a mon.out file is in two parts:
274*12892Ssam  * the counters of how many times each procedure was called,
275*12892Ssam  * if it was called at all;
276*12892Ssam  * and an array of sampling hits within pc ranges.
277*12892Ssam  * the counters must be dealt with on a file-by-file basis,
278*12892Ssam  * since which procedures are represented may vary.
279*12892Ssam  * the samples ranges are fixed, but must be summed across
280*12892Ssam  * files, and then distributed among procedures, because
281*12892Ssam  * of the wierd way the plotting is done.
282*12892Ssam  */
283*12892Ssam getpfile(filename)
284*12892Ssam 	char *filename;
285*12892Ssam {
286*12892Ssam 
287*12892Ssam 	openpfile(filename);
288*12892Ssam 	readcntrs();
289*12892Ssam 	asgncntrs();		/* assign counts to procedures */
290*12892Ssam 	readsamples();
291*12892Ssam 	closepfile();
292*12892Ssam }
293*12892Ssam 
294*12892Ssam openpfile(filename)
295*12892Ssam 	char *filename;
296*12892Ssam {
297*12892Ssam 	struct stat stb;
298*12892Ssam 
299*12892Ssam 	if((pfile = fopen(filename, "r")) == NULL) {
300*12892Ssam 		perror(filename);
301*12892Ssam 		done();
302*12892Ssam 	}
303*12892Ssam 	fstat(fileno(pfile), &stb);
304*12892Ssam 	fread(&h, sizeof(struct hdr), 1, pfile);
305*12892Ssam 	lowpc = h.lowpc - (UNIT *)0;
306*12892Ssam 	highpc = h.highpc - (UNIT *)0;
307*12892Ssam 	sampbytes =
308*12892Ssam 	    stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt);
309*12892Ssam 	nsamples = sampbytes / sizeof (unsigned UNIT);
310*12892Ssam }
311*12892Ssam 
312*12892Ssam closepfile()
313*12892Ssam {
314*12892Ssam 
315*12892Ssam 	fclose(pfile);
316*12892Ssam 	free(cbuf);
317*12892Ssam }
318*12892Ssam 
319*12892Ssam readcntrs()
320*12892Ssam {
321*12892Ssam 	struct cnt *kp;
322*12892Ssam 
323*12892Ssam 	cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt));
324*12892Ssam 	if (cbuf == 0) {
325*12892Ssam 		fprintf(stderr, "prof: No room for %d bytes of count buffer\n",
326*12892Ssam 		    (h.ncount+1) * sizeof (struct cnt));
327*12892Ssam 		exit(1);
328*12892Ssam 	}
329*12892Ssam 	fread(cbuf, sizeof(struct cnt), h.ncount, pfile);
330*12892Ssam 	/* eliminate zero counters and scale counter pc values */
331*12892Ssam 	if (h.ncount) {
332*12892Ssam 		kp = &cbuf[h.ncount - 1];
333*12892Ssam 		for (;;) {
334*12892Ssam 			if (kp->cvalue==0) {
335*12892Ssam 				h.ncount=kp-cbuf;
336*12892Ssam 				++kp;
337*12892Ssam 				break;
338*12892Ssam 			}
339*12892Ssam 			if (kp == cbuf) {
340*12892Ssam 				h.ncount = 0;
341*12892Ssam 				break;
342*12892Ssam 			}
343*12892Ssam 			--kp;
344*12892Ssam 		}
345*12892Ssam 		for (; --kp>=cbuf; )
346*12892Ssam 			kp->cvalue /= sizeof(UNIT);
347*12892Ssam 	}
348*12892Ssam 	/* sort counters */
349*12892Ssam 	qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp);
350*12892Ssam }
351*12892Ssam 
352*12892Ssam /*
353*12892Ssam  * Assign counters to the procedures to which they belong
354*12892Ssam  */
355*12892Ssam asgncntrs()
356*12892Ssam {
357*12892Ssam 	register int i;
358*12892Ssam 	struct cnt *kp;
359*12892Ssam 
360*12892Ssam 	kp = &cbuf[h.ncount-1];
361*12892Ssam 	np = npe;
362*12892Ssam 	while (--np>=nl) {
363*12892Ssam 		if (kp<cbuf || np->value > kp->cvalue)
364*12892Ssam 			continue;
365*12892Ssam 			/* skip ``static'' functions */
366*12892Ssam 		while (kp >= cbuf && kp->cvalue > np->value + 11)
367*12892Ssam 			--kp;
368*12892Ssam 		if (kp->cvalue >= np->value) {
369*12892Ssam 			np->ncall += kp->cncall;
370*12892Ssam 			--kp;
371*12892Ssam 		}
372*12892Ssam 	}
373*12892Ssam }
374*12892Ssam 
375*12892Ssam readsamples()
376*12892Ssam {
377*12892Ssam 	register i;
378*12892Ssam 	unsigned UNIT	sample;
379*12892Ssam 	int totalt;
380*12892Ssam 
381*12892Ssam 	if (samples == 0) {
382*12892Ssam 		samples = (unsigned UNIT *)
383*12892Ssam 		    calloc(sampbytes, sizeof (unsigned UNIT));
384*12892Ssam 		if (samples == 0) {
385*12892Ssam 			printf("prof: No room for %d sample pc's\n",
386*12892Ssam 			    sampbytes / sizeof (unsigned UNIT));
387*12892Ssam 			done();
388*12892Ssam 		}
389*12892Ssam 	}
390*12892Ssam 	for (i = 0; ; i++) {
391*12892Ssam 		fread(&sample, sizeof (unsigned UNIT), 1, pfile);
392*12892Ssam 		if (feof(pfile))
393*12892Ssam 			break;
394*12892Ssam 		samples[i] += sample;
395*12892Ssam 		totalt += sample;
396*12892Ssam 	}
397*12892Ssam 	if (i != nsamples) {
398*12892Ssam 		fprintf(stderr,
399*12892Ssam 		    "prof: unexpected EOF after reading %d/%d samples\n",
400*12892Ssam 			--i, nsamples);
401*12892Ssam 		done();
402*12892Ssam 	}
403*12892Ssam }
404*12892Ssam 
405*12892Ssam /*
406*12892Ssam  * Assign samples to the procedures to which they belong.
407*12892Ssam  */
408*12892Ssam asgnsamples()
409*12892Ssam {
410*12892Ssam 	register j;
411*12892Ssam 	unsigned UNIT	ccnt;
412*12892Ssam 	double time;
413*12892Ssam 	unsigned pcl, pch;
414*12892Ssam 	register int i;
415*12892Ssam 	int overlap;
416*12892Ssam 
417*12892Ssam 	/* read samples and assign to namelist symbols */
418*12892Ssam 	scale = highpc - lowpc;
419*12892Ssam 	scale /= nsamples;
420*12892Ssam 	for (i=0; i < nsamples; i++) {
421*12892Ssam 		ccnt = samples[i];
422*12892Ssam 		if (ccnt == 0)
423*12892Ssam 			continue;
424*12892Ssam 		pcl = lowpc + scale*i;
425*12892Ssam 		pch = lowpc + scale*(i+1);
426*12892Ssam 		time = ccnt;
427*12892Ssam 		totime += time;
428*12892Ssam 		if(time > maxtime)
429*12892Ssam 			maxtime = time;
430*12892Ssam 		for (j=0; j<nname; j++) {
431*12892Ssam 			if (pch < nl[j].value)
432*12892Ssam 				break;
433*12892Ssam 			if (pcl >= nl[j+1].value)
434*12892Ssam 				continue;
435*12892Ssam 			overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value));
436*12892Ssam 			if (overlap>0)
437*12892Ssam 				nl[j].time += overlap*time/scale;
438*12892Ssam 		}
439*12892Ssam 	}
440*12892Ssam 	if (totime==0.0) {
441*12892Ssam 		fprintf(stderr, "No time accumulated\n");
442*12892Ssam /*
443*12892Ssam 		done();
444*12892Ssam  */
445*12892Ssam 		totime=1.0;
446*12892Ssam 	}
447*12892Ssam }
448*12892Ssam 
449*12892Ssam /*
450*12892Ssam  * dump what you have out to a mon.out style file.
451*12892Ssam  */
452*12892Ssam putprof()
453*12892Ssam {
454*12892Ssam 	FILE *sfile;
455*12892Ssam 	struct nl *np;
456*12892Ssam 	struct cnt kp;
457*12892Ssam 	int i;
458*12892Ssam 
459*12892Ssam 	sfile = fopen(MON_SUMNAME, "w");
460*12892Ssam 	if (sfile == NULL) {
461*12892Ssam 		perror(MON_SUMNAME);
462*12892Ssam 		done();
463*12892Ssam 	}
464*12892Ssam 	/*
465*12892Ssam 	 * build a new header.
466*12892Ssam 	 * h.lowpc and h.highpc are already fine.
467*12892Ssam 	 * fix h.ncount to count non-zero calls,
468*12892Ssam 	 * and the one zero call which marks the end.
469*12892Ssam 	 */
470*12892Ssam 	h.ncount = 0;
471*12892Ssam 	for (np = nl; np < npe-1 ; np++)
472*12892Ssam 		if (np->ncall > 0)
473*12892Ssam 			h.ncount++;
474*12892Ssam 	h.ncount++;
475*12892Ssam 	fwrite(&h, sizeof (struct hdr), 1, sfile);
476*12892Ssam 	for (np = nl; np < npe-1; np++) {
477*12892Ssam 		if (np->ncall > 0) {
478*12892Ssam 			kp.cvalue = np->value * sizeof (unsigned UNIT);
479*12892Ssam 			kp.cncall = np->ncall;
480*12892Ssam 			fwrite(&kp, sizeof (struct cnt), 1, sfile);
481*12892Ssam 		}
482*12892Ssam 	}
483*12892Ssam 	kp.cvalue = 0;
484*12892Ssam 	kp.cncall = 0;
485*12892Ssam 	fwrite(&kp, sizeof (struct cnt), 1, sfile);
486*12892Ssam 	fwrite(samples, sizeof (unsigned UNIT), nsamples, sfile);
487*12892Ssam 	fclose(sfile);
488*12892Ssam }
489*12892Ssam 
490*12892Ssam min(a, b)
491*12892Ssam {
492*12892Ssam 	if (a<b)
493*12892Ssam 		return(a);
494*12892Ssam 	return(b);
495*12892Ssam }
496*12892Ssam 
497*12892Ssam max(a, b)
498*12892Ssam {
499*12892Ssam 	if (a>b)
500*12892Ssam 		return(a);
501*12892Ssam 	return(b);
502*12892Ssam }
503*12892Ssam 
504*12892Ssam valcmp(p1, p2)
505*12892Ssam 	struct nl *p1, *p2;
506*12892Ssam {
507*12892Ssam 
508*12892Ssam 	return(p1->value - p2->value);
509*12892Ssam }
510*12892Ssam 
511*12892Ssam timcmp(p1, p2)
512*12892Ssam 	struct nl *p1, *p2;
513*12892Ssam {
514*12892Ssam 	float d;
515*12892Ssam 
516*12892Ssam 	if (nflg && p2->ncall != p1->ncall)
517*12892Ssam 		return (p2->ncall - p1->ncall);
518*12892Ssam 	d = p2->time - p1->time;
519*12892Ssam 	if (d > 0.0)
520*12892Ssam 		return(1);
521*12892Ssam 	if (d < 0.0)
522*12892Ssam 		return(-1);
523*12892Ssam 	return(strcmp(p1->name,p2->name));
524*12892Ssam }
525*12892Ssam 
526*12892Ssam cntcmp(p1, p2)
527*12892Ssam 	struct cnt *p1, *p2;
528*12892Ssam {
529*12892Ssam 
530*12892Ssam 	return(p1->cvalue - p2->cvalue);
531*12892Ssam }
532*12892Ssam 
533*12892Ssam done()
534*12892Ssam {
535*12892Ssam 
536*12892Ssam #ifdef plot
537*12892Ssam 	if(vflg) {
538*12892Ssam 		point(0, -2040);
539*12892Ssam 		closepl();
540*12892Ssam 	}
541*12892Ssam #endif
542*12892Ssam 	exit(0);
543*12892Ssam }
544*12892Ssam 
545*12892Ssam #ifdef plot
546*12892Ssam plotprof()
547*12892Ssam {
548*12892Ssam 	double time, lastx, lasty, lastsx;
549*12892Ssam 	register i;
550*12892Ssam 
551*12892Ssam 	openpl();
552*12892Ssam 	erase();
553*12892Ssam 	space(-2048, -2048, 2048, 2048);
554*12892Ssam 	line(-2040, -2040, -2040, 2040);
555*12892Ssam 	line(0, 2040, 0, -2040);
556*12892Ssam 	for(i=0; i<11; i++)
557*12892Ssam 		line(-2040, 2040-i*408, 0, 2040-i*408);
558*12892Ssam 	lastx = 0.;
559*12892Ssam 	lasty = ranoff;
560*12892Ssam 	scale = (4080.*ransca)/(sampbytes/sizeof(UNIT));
561*12892Ssam 	lastsx = 0.0;
562*12892Ssam 	for(i = 0; i < nsamples; i++) {
563*12892Ssam 		unsigned UNIT ccnt;
564*12892Ssam 		double tx, ty;
565*12892Ssam 		ccnt = samples[i];
566*12892Ssam 		time = ccnt;
567*12892Ssam 		tx = lastsx;
568*12892Ssam 		ty = lasty;
569*12892Ssam 		lastsx -= 2000.*time/totime;
570*12892Ssam 		lasty -= scale;
571*12892Ssam 		if(lasty >= -2040. && ty <= 2040.) {
572*12892Ssam 			line((int)tx, (int)ty, (int)lastsx, (int)lasty);
573*12892Ssam 			if (ccnt!=0 || lastx!=0.0) {
574*12892Ssam 				tx = lastx;
575*12892Ssam 				lastx = -time*2000./maxtime;
576*12892Ssam 				ty += scale/2;
577*12892Ssam 				line(0, (int)ty, (int)tx, (int)ty);
578*12892Ssam 			}
579*12892Ssam 		}
580*12892Ssam 	}
581*12892Ssam 	scale = (4080.*ransca)/(highpc-lowpc);
582*12892Ssam 	lastx = 50.;
583*12892Ssam 	for(np = nl; np<npe;  np++) {
584*12892Ssam 		if(np->value < lowpc)
585*12892Ssam 			continue;
586*12892Ssam 		if(np->value >= highpc)
587*12892Ssam 			continue;
588*12892Ssam 		time = np->time/totime;
589*12892Ssam 		lasty = ranoff - (np->value - lowpc)*scale;
590*12892Ssam 		if(lasty >= -2040. && lasty <= 2040.) {
591*12892Ssam 			char bufl[BUFSIZ], *namp;
592*12892Ssam 			register j;
593*12892Ssam 			line(0, (int)lasty, 50, (int)lasty);
594*12892Ssam 			line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty);
595*12892Ssam 			move((int)(lastx+30), (int)(lasty+10));
596*12892Ssam 			sprintf(bufl, "%s", np->name + (np->name[0] == '_'));
597*12892Ssam 			label(bufl);
598*12892Ssam 		}
599*12892Ssam 		lastx += 500.;
600*12892Ssam 		if(lastx > 2000.)
601*12892Ssam 			lastx = 50.;
602*12892Ssam 	}
603*12892Ssam }
604*12892Ssam #endif
605