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---