/* * (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) ; } }