Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!labrea!navajo!rokicki
From: rokicki@navajo.STANFORD.EDU (Tomas Rokicki)
Newsgroups: comp.sys.amiga
Subject: profiler (4/5) p2.c
Message-ID: <1248@navajo.STANFORD.EDU>
Date: Tue, 23-Dec-86 14:25:42 EST
Article-I.D.: navajo.1248
Posted: Tue Dec 23 14:25:42 1986
Date-Received: Wed, 24-Dec-86 00:00:03 EST
Organization: Stanford University
Lines: 465
---cut here---
/*
* (C) 1986 Radical Eye Software. This code may be used and distributed
* freely, so long as this notice stays in it and the banner messages
* are unchanged except for the version notices. Written by Tomas Rokicki
* on December 19 through December 21 1986.
*
* This is the second part of the profiler. It resides in memory,
* and handles the traps from the execution of the .exe file.
*
* ***This is a dangerous program!!!*** Do not run the patched
* executable while this program is not running. Do not exit this
* program while the patched executable is running. Do not choose
* the `initialize' gadget when this program is running.
*
* Currently, this program does not work for programs which are invoked
* from the workbench, because the glue routine for Exit() does not
* start with a link, so it's not trapped. This will require a patch
* in p1. Setjmp/Longjmp also will throw it off. But it should be
* useful anyway.
*
* Usage: p2 filename [memsize]
*
* Reads filename.pdt (the profiler data file)
*
* Writes filename.mon (the monitor output data)
*/
#include "stdio.h"
#include "exec/memory.h"
#include "intuition/intuition.h"
/*
* Globals (yuck).
*/
long memsize = 20000 ;
FILE *f ;
char filename[255] ;
long old_trap_vector ;
long tick_val = 0 ;
int max_rout ;
char *filearg ;
struct IntuitionBase *IntuitionBase ;
struct GfxBase *GfxBase ;
/*
* We have to disable ^C interrupts.
*/
extern int Enable_Abort ;
/*
* Note that the following two structures are also used in
* p2a.asm; when changing them, also change the ones
* there. Or better yet, put them into an include file.
* (I didn't because you need two include files, one for C and
* one for assembly, and I'm too lazy.)
*/
struct rout_stat {
short recursion_count ;
short data_offset ;
long invoke_count ;
long self ;
long children ;
} ;
struct tstruct {
short running ;
char *tick_add ;
char *dat_add ;
char *stack ;
char *stack_top ;
char *stack_bot ;
short error ;
char *debug_ptr ;
} trap_glob ;
struct rout_stat *big_arr ;
extern int_rout(), trap_rout() ;
/*
* External routines.
*/
char *strcpy(), *strcat() ;
char *AllocMem() ;
char *OpenLibrary() ;
struct Window *OpenWindow() ;
long atol() ;
struct IntuiMessage *GetMsg() ;
char *malloc() ;
/*
* Startup installs the interrupt and the trap code.
*/
startup() {
/*
* Find the address of the vector.
*/
register long *t = (long *)((*(long *)4)+0x94) ;
register int *dest ;
/*
* Make sure we can allocate the trap.
*/
if (AllocTrap(3L) != 3)
error("! couldn't allocate trap #3") ;
/*
* Set up the global pointers.
*/
trap_glob.tick_add = (char *)&tick_val ;
trap_glob.dat_add = (char *)big_arr ;
/*
* We subtract 4 because we use the zeros at the end as
* a guard zone.
*/
trap_glob.stack = (char *)big_arr + memsize - 4 ;
trap_glob.stack_top = (char *)big_arr + memsize - 4 ;
trap_glob.stack_bot = (char *)(big_arr + max_rout + 1) ;
/*
* Debug; take this out!
*
{
long i ;
trap_glob.debug_ptr = (char *)big_arr + memsize ;
for (i=0; i 3)
error("! usage: p2 filename [memsize]") ;
filearg = argv[1] ;
if ((f = fopen(strcat(strcpy(filename,filearg),".pdt"), "r"))==NULL)
error("! couldn't open .pdt file") ;
if (argc > 2)
memsize = atol(argv[2]) ;
if ((memsize & 3) != 0 || memsize < 1000 || memsize > 500000)
error("! let's be reasonable in our memory size") ;
get_data() ;
startup() ;
gadgets() ;
cleanup() ;
write_summary() ;
/*
* Free the memory.
*/
if (big_arr != NULL)
FreeMem(big_arr, memsize) ;
exit(0) ;
}
/*
* We need a set of routines to deal with the names. They add the names
* to the dynamic list, and free them on exit. Note that this wastes
* on the average 19 bytes per name.
*/
struct namestruct {
struct namestruct *next ;
int number ;
char name[1] ;
} *globnames = NULL ;
/*
* Addname() adds a name to our global list.
*/
addname(s, n)
char *s ;
int n ;
{
register struct namestruct *p = (struct namestruct *)
malloc(sizeof(struct namestruct)+strlen(s)) ;
if (p==NULL)
error("! couldn't allocate name struct\n") ;
p->next = globnames ;
globnames = p ;
p->number = n ;
strcpy(p->name, s) ;
}
/*
* Name() looks up a name in our global list.
*/
char *name(n)
int n ;
{
register struct namestruct *p ;
for (p=globnames; p!=NULL; p = p->next)
if (p->number == n)
return(p->name) ;
return("") ;
}
/*
* Get_data() reads in the data from the .pdt file and initializes
* the arrays.
*/
get_data() {
int num, offset ;
char name[255] ;
/*
* The (*2) is there for debugging.
*/
big_arr = (struct rout_stat *)AllocMem(memsize/* * 2*/, MEMF_CLEAR) ;
if (big_arr == NULL)
error("! couldn't allocate memory") ;
while (fscanf(f, "%d %s %d", &num, name, &offset)==3) {
if (num > max_rout) {
max_rout = num ;
if (max_rout * (long) sizeof(struct rout_stat) > memsize)
error("! increase mem_size") ;
}
addname(name, num) ;
big_arr[num].data_offset = offset ;
}
fclose(f) ;
}
/*
* Here are the window and gadget structure definitions.
*/
short borders[] = { 0, 0,
100, 0,
100, 11,
0, 11,
0, 0 } ;
struct Border b1 = {
0, 0,
1, 0, JAM1,
5,
borders,
NULL
} ;
struct IntuiText it1 = {
1, 0,
JAM1,
10, 2,
NULL,
(UBYTE *)"Initialize",
NULL,
} ;
struct Gadget g1 = {
NULL,
60, 16,
100, 11,
GADGHCOMP,
RELVERIFY,
BOOLGADGET,
(APTR)&b1,
NULL,
&it1,
0,
NULL,
'i',
NULL
} ;
struct IntuiText it2 = {
1, 0,
JAM1,
26, 2,
NULL,
(UBYTE *)"Finish",
NULL,
} ;
struct Gadget g2 = {
&g1,
60, 32,
100, 11,
GADGHCOMP,
RELVERIFY,
BOOLGADGET,
(APTR)&b1,
NULL,
&it2,
0,
NULL,
'f',
NULL
} ;
struct NewWindow p2window =
{
400, 20,
220, 50,
-1, -1,
GADGETUP,
WINDOWDEPTH | WINDOWDRAG | SMART_REFRESH,
&g2,
NULL,
(UBYTE *)"Radical Eye Software",
NULL,
NULL,
0, 0,
0, 0,
WBENCHSCREEN
} ;
/*
* Gadgets does the fun stuff. It opens a small window with two
* gadgets, a `initialize' and a `write_data' gadget.
*/
gadgets() {
struct Window *mywindow = NULL ;
struct IntuiMessage *im ;
char gadg = ' ' ;
int i ;
if ((IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 0L))==NULL)
error("! couldn't open intuition") ;
if ((GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library", 0L))==NULL)
error("! couldn't open graphics") ;
if ((mywindow = OpenWindow(&p2window))==NULL)
error("! couldn't open window") ;
while (gadg != 'f') {
Wait(1L << mywindow->UserPort->mp_SigBit) ;
while (im = GetMsg(mywindow->UserPort)) {
if (im->Class == GADGETUP)
gadg = ((struct Gadget *)(im->IAddress))->GadgetID ;
else
gadg = ' ' ;
ReplyMsg(im) ;
}
/*
* For now, we turn this off, because _exit() calls close().
* We are just going to have to trust the user.
*
if (i=trap_glob.running) {
DisplayBeep(mywindow->WScreen) ;
printf("Last routine called: %d\n", i) ;
gadg = ' ' ;
} else */ {
if (gadg == 'i') {
initialize() ;
} else if (gadg == 'f') {
break ;
}
}
}
CloseWindow(mywindow) ;
}
/*
* The initialize() routine sets all of the counts back to zero.
* The program had better not be running at this point!
*/
initialize() {
register int i ;
register struct rout_stat *p ;
for (i=0, p=big_arr; i<=max_rout; i++, p++) {
p->recursion_count = 0 ;
p->invoke_count = 0 ;
p->self = 0 ;
p->children = 0 ;
}
trap_glob.error = 0 ;
}
/*
* The write_summary() simply writes the data in the structure
* to a file; it is recovered by p3.
*/
#define fix(i) (p->invoke_count==0?0.0:i*0.065169336/p->invoke_count)
write_summary() {
register int i, j ;
register struct rout_stat *p ;
int *sort_ptrs ;
int t ;
long s ;
if ((f = fopen(strcat(strcpy(filename,filearg),".mon"), "w"))==NULL)
error("! couldn't open .mon file") ;
if ((sort_ptrs = (int *)AllocMem(((long)max_rout+1)*2, 0L))==NULL)
error("! couldn't allocate pointers file") ;
/*
* We use a bubble sort to sort the array.
*/
s = 0 ;
for (i=0; i<=max_rout; i++) {
sort_ptrs[i] = i ;
s += big_arr[i].self ;
}
if (s != 0) {
for (i=max_rout; i>0; i--)
for (j=0; jinvoke_count, fix(p->self), (100.0*p->self)/s,
fix(p->children), (100.0*p->children)/s, name(sort_ptrs[i])) ;
}
}
if (trap_glob.error != 0)
printf("Error no %d in trace.\n", trap_glob.error) ;
/*
* This is debug code! Remove me!
*
{
int *t ;
for (i=0, t=(int *)((char *)big_arr + memsize); *t != -1; i++, t++)
fprintf(f, "%04x\n", *t) ;
}
*/
FreeMem(sort_ptrs, ((long)max_rout+1)*2) ;
}
/*
* error() prints an error message and exits if it was fatal.
*/
error(s)
char *s ;
{
printf("%s\n", s) ;
if (*s=='!') {
if (big_arr != NULL)
FreeMem(big_arr, memsize) ;
exit(1) ;
}
}
---cut here---