/* Copyright (c)1994-2000 Begemot Computer Associates. All rights reserved.
 * See the file COPYRIGHT for details of redistribution and use. */

/*
 * Count how many times each instruction was executed. This helps in
 * finding which instructions should be optimized.
 */
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <string.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAVE_GETOPT_H
#  include <getopt.h>
# endif

# include <begemot.h>
# include "cdefs.h"
# include "util.h"

RCSID("$Id: aprof.c 476 2001-07-09 08:09:10Z hbb $")

struct cnt {
	u_long	cnt;
	u_int	op;
};

struct cnt a[0x10000];
u_int cnt[0x10000];
int dflag, sflag;

int	comp(const void *, const void *);

unsigned long long ccc;

static void usage(void) DEAD_FUNC;

static char usgtxt[] =
"Usage: aprof [-hds] file\n"
"Options:\n"
"	-s		collapse single address commands\n"
"	-d		collapse double address commands\n"
"	-h		print this info\n";

int
main(int argc, char *argv[])
{
	int opt, fd, i;
	struct stat sbuf;

	set_argv0(argv[0]);
	while((opt = getopt(argc, argv, "hsd")) != EOF)
		switch(opt) {

		  case 's':
			sflag++;
			break;

		  case 'd':
			dflag++;
			break;

		  case 'h':
			usage();
		}
	argc -= optind;
	argv += optind;

	if(argc != 1)
		usage();

	if((fd = open(argv[0], O_RDWR)) < 0)
		panic("Cannot open %s: %s\n", argv[0], strerror(errno));

	if(fstat(fd, &sbuf) < 0)
		panic("Cannot stat %s: %s\n", argv[0], strerror(errno));

	if(sbuf.st_size != sizeof(cnt))
		panic("%s has wrong size, probably not an aprof file\n",
					argv[0]);

	if(read(fd, cnt, sizeof(cnt)) != sizeof(cnt))
		panic("read %s: %s", argv[0], strerror(errno));

	for(i = 0; i < 0x10000; i++) {
		a[i].op = i;
		ccc += cnt[i];
		if((i & 070000) == 0 && !(i & 04000) && i >= 0400)
			a[i & ~0377].cnt += cnt[i]; 	/* BRANCH */
		else if((i & 0177000) == 077000)
			a[i & ~077].cnt += cnt[i];	/* SOB */
		else if((i & 0177000) == 0104000)
			a[i & ~0377].cnt += cnt[i];	/* TRAP/EMT */
		else if((i & 0177700) == 06400)
			a[i & ~077].cnt += cnt[i];	/* MARK */
		else if((i & 070000) != 0 && (i & 070000) != 070000) {
			if(dflag)
				a[i & 0170000].cnt += cnt[i];
			else
				a[i].cnt = cnt[i];
		} else if((i & 070000) == 0 && (i & 07777) > 05000) {
			if(sflag)
				a[i & ~077].cnt += cnt[i];
			else
				a[i].cnt = cnt[i];
		} else
			a[i].cnt = cnt[i];
	}

	qsort(a, 0x10000, sizeof(struct cnt), comp);

	for(i = 0; i < 0x10000; i++) {
		if(a[i].cnt == 0)
			break;
		printf("%06o %11lu %f\n", a[i].op, a[i].cnt,
			(100.0 * a[i].cnt) / ccc);
	}
	return 0;
}

static void
usage()
{
	fprintf(stderr, usgtxt);
	exit(1);
}

int	
comp(const void *p1, const void *p2)
{
	const struct cnt *a1 = p1;
	const struct cnt *a2 = p2;

	return a2->cnt - a1->cnt;
}
