|
|
researchv10 Norman
#include "sys/types.h"
#include "sys/stat.h"
#include "a.out.h"
/* it wouldn't be better to get this out of sys/param.h */
#define HZ 60
typedef unsigned short Prof; /* what the counts are stored in! */
/* a mon.out consists of a phdr, cnt structs pcnt, and the rest are
Profs of pc clicks */
struct phdr {
char *lopc, *hipc; /* void *? */
int cnt;
};
struct phdr hsv;
struct pcnt {
char * value;
long calls;
};
char flags[128];
char *xfile, *file;
struct nlist *names;
char *strings, *pbuf;
Prof *accum;
int accumsz;
typedef struct {
char *loc;
char *name;
long calls;
long clicks;
unsigned char type;
} sym;
int nsym;
sym *syms, nilsym;
long lopct, hipct; /* plot stuff */
double rscale, roffset;
main(argc, argv)
char **argv;
{ int c;
extern int optind;
extern char **optarg;
char *p;
while((c = getopt(argc, argv, "alnsvz")) != -1)
switch(c) {
case 'l': case 'n': case 's': case 'z':
flags[c] = 1;
continue;
case 'v':
flags['v'] = 1;
p = argv[optind];
if(*p != '-' || p[1] > '9' || p[1] < '0')
continue;
lopct = atoi(p+1);
p = argv[++optind];
if(*p != '-' || p[1] > '9' || p[1] < '0')
continue;
hipct = atoi(p+1);
optind++;
continue;
case '?':
fatal("usage: %s -[alnsz] files\n", argv[0]);
}
if(optind < argc)
xfile = argv[optind++];
else
xfile = "a.out";
readsyms();
if(optind >= argc)
doit("mon.out");
else
for(; optind < argc; optind++)
doit(argv[optind]);
output();
exit(0);
}
doit(s)
char *s;
{ struct stat stb;
int fd;
file = s;
fd = open(s, 0);
if(fd < 0)
fatal("couldn't open %s\n", s);
fstat(fd, &stb);
pbuf = (char *) malloc(stb.st_size);
if(pbuf == 0)
fatal("couldn't alloc %d bytes for %s\n", stb.st_size, s);
if(read(fd, pbuf, stb.st_size) != stb.st_size)
fatal("read of %s failed\n", s);
if(stb.st_size <= sizeof(struct phdr))
fatal("%s not a mon.out\n");
close(fd);
addcalls();
addclicks(stb.st_size);
free(pbuf);
}
addclicks(top)
{ int i, n, cnt, j;
char *x;
Prof *p;
struct phdr *h;
double scale; /* the kernel uses 16 bit fractions */
h = (struct phdr *)pbuf;
n = ((struct phdr *)pbuf)->cnt;
p = (Prof *) (pbuf + sizeof(struct phdr) + n * sizeof(struct pcnt));
top -= sizeof(struct phdr) + n * sizeof(struct pcnt);
cnt = top/sizeof(Prof); /* number of counters */
if(flags['s'] && !accumsz) {
accum = (Prof *) malloc(cnt*sizeof(Prof));
(void) memset(accum, 0, cnt*sizeof(Prof));
accumsz = cnt;
hsv = *h;
} /* we assume h is fixed across the files */
scale = (h->hipc-h->lopc)/(double)cnt;
/* in mcrt0.s it's 8 */
for(j = i = 0; i < cnt; i++) {
x = (char *)(h->lopc + (int)(scale*i));
while(j < nsym && syms[j+1].loc < x)
j++;
if(j > nsym)
fatal("cnts out of range %s\n", file);
syms[j].clicks += p[i];
}
if(flags['s'])
for(i = 0; i < accumsz; i++) {
n = accum[i] + p[i];
accum[i] = n;
if(n != accum[i]) {
mesg("overflow in accumulating counts, -s ignored\n");
flags['s'] = 0;
return;
}
}
}
addcalls()
{ int n, i;
struct pcnt *p;
p = (struct pcnt *)(pbuf + sizeof(struct phdr));
n = ((struct phdr *)pbuf)->cnt;
for(i = 0; i < n; i++, p++)
addcall(p->value, p->calls);
}
addcall(x, n)
char *x;
{ int i;
for(i = 0; i < nsym && syms[i+1].loc < x; i++)
;
if(i >= nsym) {
mesg("cntr out of range (%s), ignored\n", file);
return;
}
if(syms[i+1].loc == x)
syms[i+1].calls += n;
else
syms[i].calls += n;
}
symnum(a, b)
register sym *a, *b;
{
return(a->loc - b->loc);
}
readsyms()
{ int fd, n, i, j;
struct exec x;
struct stat stb;
struct nlist *np;
fd = open(xfile, 0);
if(fd < 0)
fatal("couldn't read %s\n", xfile);
if(read(fd, (char *)&x, sizeof(x)) != sizeof(x))
fatal("can't read header of %s\n", xfile);
if(!x.a_syms)
fatal("%s has no symbol table\n", xfile);
/* read the symbol table in */
lseek(fd, N_SYMOFF(x), 0);
names = (struct nlist *) malloc(x.a_syms);
read(fd, (char *)names, x.a_syms);
nsym = N_STROFF(x) - N_SYMOFF(x);
nsym /= sizeof(struct nlist); /* over estimated */
/* read the wretched strings in */
lseek(fd, N_STROFF(x), 0);
fstat(fd, &stb);
n = stb.st_size - N_STROFF(x);
strings = (char *) malloc(n);
if(read(fd, strings, n) != n)
fatal("couldn't read string table from %s (%d)\n", xfile, n);
/* copy the text symbols into the symbol table */
syms = (sym *) malloc(nsym * sizeof(sym));
for(i = 0, np = names; np < names + nsym; np++) {
if((np->n_type & N_TYPE) != N_TEXT)
continue;
if(np->n_type & N_STAB)
continue;
syms[i] = nilsym;
syms[i].type = np->n_type;
syms[i].loc = (char *)np->n_value;
syms[i].name = strings + np->n_un.n_strx;
i++;
}
nsym = i;
qsort((char *)syms, nsym, sizeof(sym), symnum);
/* now decide which of the ones with the same loc we like */
for(i = 0; i < nsym; i = j) {
for(j = i+1; j < nsym; j++)
if(syms[i].loc != syms[j].loc)
break;
choose(i, j);
}
/* and squash it down */
for(i = j = 0; i < nsym; i++)
if(syms[i].type)
syms[j++] = syms[i];
nsym = j;
syms[nsym].loc = (char *)0x8fffffff; /* a very big end */
close(fd);
}
/* the expert system */
choose(i, j)
{ int n;
if(j-i <= 1)
return;
/* if there is an external text one, take it */
for(n = i; n < j; n++)
if(syms[n].type & N_EXT)
goto found;
/* if there is one that starts with _, take it */
for(n = i; n < j; n++)
if(syms[n].name[0] == '_')
goto found;
/* if there is one without a . in it, take it */
for(n = i; n < j; n++)
if(!strchr(syms[n].name, '.'))
goto found;
/* first must be right, or at least ok */
n = i;
found:
for(; i < j; i++)
if(i != n)
syms[i].type = 0;
}
char ebuf[256];
mesg(s, a, b, c, d, e, f)
char *s;
{
sprintf(ebuf, s, a, b, c, d, e, f);
write(2, ebuf, strlen(ebuf));
}
fatal(s, a, b, c, d, e, f)
char *s;
{
mesg(s, a, b, c, d, e, f);
exit(1);
}
symcalls(a, b)
register sym *a, *b;
{
return(b->calls - a->calls);
}
symcnt(a, b)
register sym *a, *b;
{
return(b->clicks - a->clicks); /* largest first */
}
output()
{ int i, tot, fd;
double x, y;
if(flags['v']) {
plotout();
return;
}
for(tot = i = 0; i < nsym; i++)
tot += syms[i].clicks;
if(tot == 0)
tot = 1;
if(flags['n'])
qsort((char *)syms, nsym, sizeof(sym), symcalls);
else if(!flags['l'])
qsort((char *)syms, nsym, sizeof(sym), symcnt);
printf(" %% Time\tCalls\tName\n");
for(i = 0; i < nsym; i++) {
if(!syms[i].calls && !syms[i].clicks && !flags['z'])
continue;
x = syms[i].clicks;
x /= HZ;
y = syms[i].clicks/(double)tot;
printf("%4.1f%8.3f %8d\t%s\n", (y*100), x, syms[i].calls,
syms[i].name);
}
if(!flags['s'])
return;
fd = creat("mon.sum", 0666);
if(fd < 0)
fatal("can't create mon.sum\n");
hsv.cnt = nsym;
if(write(fd, (char *)&hsv, sizeof(hsv)) != sizeof(hsv))
fatal("write failed\n");
for(i = 0; i < nsym; i++) { /* this is very inefficient */
write(fd, (char *)&syms[i].loc, 4); /* 4! */
write(fd, (char *)&syms[i].calls, 4);
}
if(write(fd, (char *)accum, accumsz*sizeof(Prof)) != accumsz*sizeof(Prof))
fatal("write failed\n");
close(fd);
}
/* most of this is witchcraft */
plotout()
{ int i;
/* double lastx, lasty;
if(lopct >= 100 || lopct < 0)
lopct = 0;
if(hipct > 100 || hipct <= 0)
hipct = 100;
rscale = 100./(hipct-lopct);
roffset = 2040.+40.8*lopct*rscale;
openpl();
erase();
range(-2048, -2048, 2048, 2048);
line(-2040, -2040, -2040, 2040);
for(i = 0; i < 11; i++)
line(-2040, 2040-i*408, 0, 2040-i*408);
*/
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.