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