|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 9173 (0x23d5) Types: TextFile Notes: UNIX file Names: »prof.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─ ⟦this⟧ »cmd/prof.c«
/* * Prof interprets the mon.out files produced by monitor(3) and hence by * the cc(1) option -p. The usage is as follows: * prof [-a] [-b] [-c] [-s] [l.out_file [mon.out_file]] * The -a option indicates that all symbols should be used (as opposed to * only external symbols). The -b option indicates that we should print * all bin information (to detect hot spots). The -c option indicates * that all call information should be printed. The -s option asks for stack * depth information. */ #include <stdio.h> #include <l.out.h> #include <const.h> #include <canon.h> #include "mon.h" /* * Note that in setting PSCALE, one must guard against overflow. * Examine putdata carefully before changeing these constants. * Also note that certain divisibility properties are assumed * there reguarding PSCALE and HZ. */ #define PSCALE ((long)100) /* pc count scale factor */ #define SWIDTH 10 /* default symbol widht */ #define EOS '\0' /* string terminator */ #define REL 1 /* relative position for fseek */ #define TRUE (0 == 0) #define FALSE (0 != 0) typedef struct symbol { char name[NCPLN]; vaddr_t addr; long pcount, /* pc count, scaled by PSCALE */ ccount; /* number of times routine called */ } symbol; char *lout = "l.out", *monout = "mon.out"; symbol **dict; /* NULL terminated list of symbols */ int dsize, /* number of symbols */ allsyms = FALSE, /* iff we use all symbols */ bindmp = FALSE, /* iff we should dump bin info */ calldmp = FALSE; /* iff we should dump call info */ int stkdmp = FALSE; /* iff we should dump low stack mark */ long tticks, /* total number of clock ticks */ tcalls; /* total number of calls */ vaddr_t lowpc; /* lowest pc profiled */ unsigned scale; /* mon.out scale factor over 2 */ vaddr_t stksz; /* Stack size */ main(argc, argv) int argc; register char *argv[]; { register char *cp, ch; for (cp=*++argv; cp != NULL && *cp++ == '-'; cp=*++argv) while ((ch=*cp++) != EOS) switch (ch) { case 'a': allsyms = TRUE; break; case 'b': bindmp = TRUE; break; case 'c': calldmp = TRUE; break; case 's': stkdmp = TRUE; break; default: usage(); } if (*argv != NULL) lout = *argv++; if (*argv != NULL) monout = *argv++; if (*argv != NULL) usage(); getsyms(); getdata(); if (stkdmp) printf("%u bytes stack used\n", stksz); if (! bindmp && ! calldmp) putdata(); return(0); } die(str) char *str; { fprintf(stderr, "%r\n", &str); exit(1); } usage() { die("Usage: prof [-a] [-b] [-c] [-s] [l.out_file [mon.out_file]]"); } /* * Getsyms reads in the symbols from an l.out file and sets dict to * an array of them, in sorted order. */ getsyms() { FILE *fp; long skip; struct ldheader hdr; int cmpsym(); fp = fopen(lout, "r"); if (fp == NULL) die("Can't open %s", lout); if (fread(&hdr, sizeof hdr, 1, fp) != 1 || hdr.l_magic != L_MAGIC) die("%s not l.out file", lout); cansize(hdr.l_ssize[L_SHRI]); cansize(hdr.l_ssize[L_PRVI]); cansize(hdr.l_ssize[L_SHRD]); cansize(hdr.l_ssize[L_PRVD]); cansize(hdr.l_ssize[L_DEBUG]); cansize(hdr.l_ssize[L_SYM]); skip = hdr.l_ssize[L_SHRI] + hdr.l_ssize[L_PRVI] + hdr.l_ssize[L_SHRD] + hdr.l_ssize[L_PRVD] + hdr.l_ssize[L_DEBUG]; fseek(fp, skip, REL); readsy((int)(hdr.l_ssize[L_SYM]/sizeof (struct ldsym)), fp); qsort(dict, dsize, sizeof *dict, cmpsym); fclose(fp); } /* * Cmpsym compares the two symbols `sp1' and `sp2', and returns an * int corresponding to the relative order of the address fields. */ cmpsym(sp1, sp2) symbol **sp1, **sp2; { register vaddr_t adr1, adr2; adr1 = (*sp1)->addr; adr2 = (*sp2)->addr; if (adr1 > adr2) return (1); else if (adr1 == adr2) return (0); else return (-1); } /* * Readsy reads in nsyms ldsyms from the FILE fp. It sets dict to * an array of the resulting symbols. */ readsy(nsyms, fp) register int nsyms; FILE *fp; { register symbol **dpp, *dp; struct ldsym lsym; char *alloc(); dict = dpp = (symbol **)alloc((nsyms + 1) * sizeof *dpp); while (--nsyms >= 0) { if (fread(&lsym, sizeof lsym, 1, fp) != 1) die("Unexpected end of file on %s", lout); if ((lsym.ls_type & ~L_GLOBAL) > L_BSSI) continue; if ((lsym.ls_type & L_GLOBAL) == 0 && ! allsyms) continue; dp = (symbol *)alloc(sizeof *dp); strncpy(dp->name, lsym.ls_id, NCPLN); dp->addr = lsym.ls_addr; dp->pcount = dp->ccount = 0; *dpp++ = dp; } *dpp = NULL; dsize = dpp - dict; dict = (symbol *)realloc(dict, (dpp + 1 - dict) * sizeof *dpp); } /* * Alloc is simply an interface to malloc which exits if there is no * room. */ char * alloc(size) unsigned size; { char *result; result = (char *)malloc(size); if (result == NULL) die("Out of space"); return (result); } /* * Getdata reads in the mon.out file and puts the information into * the dictionary. */ getdata() { FILE *fp; struct m_hdr hdr; fp = fopen(monout, "r"); if (fp == NULL) die("Can't open %s", monout); if (fread(&hdr, sizeof hdr, 1, fp) != 1) die("%s not mon.out file", monout); scale = hdr.m_scale/2; lowpc = hdr.m_lowpc; stksz = hdr.m_hisp - hdr.m_lowsp; if (calldmp || ! bindmp) getcdata(fp, hdr.m_nfuncs); else fseek(fp, hdr.m_nfuncs * (long)sizeof (struct m_func), REL); if (bindmp || ! calldmp) getpdata(fp, hdr.m_nbins); } /* * Getcdata reads in the function call information from the mon.out file. */ getcdata(fp, nfnc) FILE *fp; register unsigned nfnc; { register symbol **dpp, *dp; struct m_func buf; while (nfnc-- != 0) { if (fread(&buf, sizeof buf, 1, fp) != 1) die("unexpected end of file on %s", monout); for (dpp=dict; (dp=*++dpp) != NULL && dp->addr <= buf.m_addr;) ; if (calldmp) printf("%4ld %*.*s+%u\n", buf.m_ncalls, SWIDTH, NCPLN, dpp[-1]->name, buf.m_addr - dpp[-1]->addr); tcalls += buf.m_ncalls; dpp[-1]->ccount += buf.m_ncalls; } } /* * Getpdata reads in the profileing data and increments the corresponding * symbols pcount fields. * Note that the global scale must contain the mon.out scale divided * by 2. */ getpdata(fp, nbins) FILE *fp; unsigned nbins; { register symbol **dpp; vaddr_t high, low; int highr, inc, incr; short tick; symbol **credit(); high = lowpc; highr = 0; inc = ((long)1<<16) / scale; incr = ((long)1<<16) % scale; if (incr != 0) { ++inc; incr -= scale; } for (dpp=dict; nbins > 0; --nbins) { low = high; high += inc; highr += incr; if (-highr >= scale) { --high; highr += scale; } if (fread(&tick, sizeof tick, 1, fp) != 1) die("Unexpected end of file on %s\n", monout); if (tick == 0) continue; tticks += tick; dpp = credit(tick, low, high, dpp); } } symbol ** credit(tick, low, high, dpp) int tick; vaddr_t low, high; symbol **dpp; { register unsigned overlap; register symbol *cur, *nxt; unsigned binlen; binlen = high - low; nxt = *dpp; if (nxt == NULL || nxt->addr >= high) { if (bindmp) printf("%3d %06o %06o\n", tick, low, high-1); return(dpp); } do { cur = nxt; nxt = *++dpp; } while (nxt != NULL && nxt->addr <= low); if (bindmp) printf("%3d %*.*s+%-4u ", tick, SWIDTH, NCPLN, cur->name, low - cur->addr); do { if (nxt != NULL && nxt->addr < high) overlap = nxt->addr; else overlap = high; if (cur->addr > low) overlap -= cur->addr; else overlap -= low; cur->pcount += (PSCALE*overlap*tick + binlen/2) / binlen; cur = nxt; nxt = *++dpp; } while (cur != NULL && cur->addr < high); dpp -= 2; if (bindmp) printf("%*.*s+%u\n", SWIDTH, NCPLN, dpp[0]->name, high - 1 - dpp[0]->addr); return (dpp); } /* * Putdata prints out the results which have been tabulated in the * dictionary. */ putdata() { register symbol **dpp, *dp; int cmpdata(); char *centi(); qsort(dict, dsize, sizeof *dict, cmpdata); for (dpp=dict; (dp=*dpp++) != NULL;) { if (dp->pcount == 0 && dp->ccount == 0) continue; printf("%-*.*s", SWIDTH, NCPLN, dp->name); centi(dp->pcount, (PSCALE * tticks)/100, 2); putchar('%'); if (dp->ccount != 0) { printf(" %7ld ", dp->ccount); centi((1000*dp->pcount) / (PSCALE*10), (HZ*dp->ccount) / 10, 3); } putchar('\n'); } } /* * Cmpdata compares the data in the dictionary entries `sp1' * and `sp2'. It returns an int which reflects which entry should * be listed first. If the value is positive, `sp2' should occur * first. If it is zero, it makes no difference. If it is negative, * `sp1' should occur first. */ cmpdata(sp1, sp2) symbol **sp1, **sp2; { register symbol *adr1, *adr2; long rel; adr1 = *sp1; adr2 = *sp2; rel = adr2->pcount - adr1->pcount; if (rel == 0) rel = adr2->ccount - adr1->ccount; if (rel > 0) return (1); else if (rel < 0) return (-1); else return (strncmp(adr1->name, adr2->name, NCPLN)); } /* * Centi prints out on standard output `num' / `den' to two places, with * atleast `width' places to the left of the decimal point. */ char * centi(num, den, width) long num, den; int width; { long cv; cv = (num*100 + den/2) / den; printf("%*ld.%02d", width, cv/100, (int)(cv%100)); }