/* Orion Lawlor's Short UNIX Examples, olawlor@acm.org 2003/10/03

Shows how to use the "profil" syscall.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memset */
#include <sys/types.h>
#include <unistd.h> /* for profil syscall */
#include <execinfo.h> /* for backtrace (GNU glibc header) */

/* This is the starting address of the code to measure */
size_t offset=(size_t)0x08000000u;

/* This is the number of bytes to measure from offset */
size_t bufsize=(size_t)0x00100000u;

typedef unsigned short profil_pc_t;


/* Little demo program to time */
int foo;
void do_adds(void) {
	int i;
	for (i=0;i<100*1000*1000;i++) {
		foo=foo+(1+i);
	}
}
void do_divides(void) {
	int i;
	for (i=0;i<100*1000*1000;i++) {
		foo=foo/(1+i);
	}
}
void code_under_test(void) {
	do_adds();
	do_divides();
}

int main() {
	profil_pc_t *buf;
	
	printf("Will profile code from %p to %p\n",
		(void *)offset, (void *)(offset+bufsize));
	/* Turn on profiling */
	buf=(profil_pc_t *)malloc(sizeof(profil_pc_t)*bufsize);
	memset(buf,0,sizeof(profil_pc_t)*bufsize);
	profil(buf,bufsize,offset,65536*2);
	
	code_under_test();
	
	/* Turn off profiling */
	profil(0,0,0,0);
	
	/* Analyze profile buffer */
	{
		size_t i;
		long int total=0;
		for (i=0;i<bufsize;i++) total+=buf[i];
		printf("Total of %d profile hits (%.3f%% error)\n",
			(int)total, 100.0/(1+total));
		for (i=0;i<bufsize;i++) 
		if (buf[i]!=0) {
			void *ptr=(void *)(offset+i);
			char **names=backtrace_symbols(&ptr,1);
			printf(" %.3f%% at pc %p: %s\n",
				100.0*buf[i]/total, ptr, names[0]);
			free(names);
		}
	}
	
	free(buf);
	
	return 0;
}

/*<@>
<@> ******** Program output: ********
<@> Will profile code from 0x8000000 to 0x8100000
<@> Total of 0 profile hits (100.000% error)
<@> */
