home *** CD-ROM | disk | FTP | other *** search
- /*
- HEADER: CUG000.00;
- TITLE: Amiga Monitor source code file;
- DATE: 09/07/88;
- VERSION: 1.0;
- FILENAME: MONITOR.C;
- SEE-ALSO: MONITOR.H;
- AUTHORS: Steve Roggenkamp
- */
- /*
- monitor.c -- monitor a process, demonstrating interprocess communications
- and other such things. Written for the Amiga running
- AmigaDOS.
-
- Steve Roggenkamp
- 5394 Winetavern Lane
- Dublin, OH 43017
- (614)792-8236
-
- 9 / 6 / 88
- */
-
- #include <stdio.h>
- #include "monitor.h"
-
- #ifdef DEBUG
- #define DBG( x )
- #else
- #define DBG( x )
- #endif
-
- #define SAMPLE_RATE 20000 /* sample rate in microseconds
- this rate is 50 samples per second */
-
- #define STACKSIZE 1000L /* size of task stack */
-
- #define MONITOR_TASK "monitor" /* monitor task name */
-
- #define SIG_PORT (1 << reply->mp_SigBit)
-
- APTR AllocMem();
- void DeleteTimer( );
- struct timerequest *CreateTimer( );
- struct Task *FindTask();
- struct Task *thistask; /* monitored task */
- struct Task *montask; /* monitoring task */
-
- extern long mon_tabsize; /* size of mon_tbl in # of entries */
- extern mon_table mon_tbl[]; /* table containing function information */
- static ULONG mon_total; /* number of times the task is sampled */
- static mon_table **mon_tptr; /* sorted array of pointers to mon_tbl */
-
- long time_delay = SAMPLE_RATE; /* time delay in usec */
-
- long
- mon_cmp_addr( x, y ) /* compare mon_table function addresses */
- register mon_table *x, *y; /* entries in mon_table to compare */
- {
- return ( (long) y->func - (long) x->func);
- }
-
- long
- mon_cmp_name( x, y ) /* compare mon_table function names */
- register mon_table *x, *y; /* entries in mon_table to compare */
- {
- return ( strcmp( y->name, x->name ));
- }
-
- long
- mon_cmp_count( x, y ) /* compare mon_table function names */
- register mon_table *x, *y; /* entries in mon_table to compare */
- {
- return ( x->count - y->count );
- }
-
- struct timerequest *
- mon_create_timer( mon_tr ) /* create a timer */
- struct timerequest **mon_tr; /* time request */
- {
- LONG error; /* error */
- ULONG sigmask; /* signal mask */
-
- struct MsgPort *timerport; /* message port for the timer */
- static struct timeval tv; /* time delay structure */
-
- timerport = CreatePort( 0L, 0L ); /* get a message port for timer */
- if ( timerport == NULL )
- {
- return( NULL );
- }
- *mon_tr = (struct timerequest *)
- CreateExtIO( timerport, sizeof( struct timerequest ));
- if ( *mon_tr == NULL )
- {
- mon_delete_timer( *mon_tr );
- return( NULL );
- }
- error = OpenDevice( TIMERNAME, UNIT_VBLANK, *mon_tr, 0L );
- if ( error != 0L )
- {
- mon_delete_timer( *mon_tr );
- return( NULL );
- }
- tv.tv_secs = 0; /* set the time delay we want */
- tv.tv_micro = time_delay;
- (*mon_tr)->tr_time = tv;
- (*mon_tr)->tr_node.io_Command = TR_ADDREQUEST;
-
- return( *mon_tr );
- }
-
- void
- mon_delete_timer( tr ) /* delete the timer we created above */
- struct timerequest *tr; /* timer to delete */
- {
- struct MsgPort *tp; /* timer message port */
-
- Forbid(); /* disable multi-tasking so we don't */
- if ( tr != NULL ) /* mess up some system data structs */
- {
- tp = tr->tr_node.io_Message.mn_ReplyPort;
- CloseDevice( tr ); /* close the timer */
- DeleteExtIO( tr, sizeof( struct timerequest ));
- if ( tp != 0L )
- {
- DeletePort( tp ); /* get rid of message port */
- }
- }
- Permit(); /* enable multi-tasking again */
- }
-
- mon_table *
- mon_get_func( pc ) /* return a pointer to the function pc is in */
- register void (*pc)(); /* program counter */
- {
- long lo, hi; /* low and high offsets into mon_table array */
- register long mid; /* offset to the middle of the table */
- register mon_table **mp; /* pointer to middle of the lo - hi range */
-
- lo = 1; /* don't look at entry 0, it's the system calls */
- hi = mon_tabsize-1; /* point to the last entry into the table */
-
- /*
- first, check to see if the program counter is contained within
- the monitor function table. If it is not, then just return the
- pointer to the beginning of the table.
- */
- if ( pc < mon_tptr[hi]->func && pc > mon_tptr[1]->func )
- {
- while ( hi >= lo ) /* use a binary search for speed */
- {
- mid = ( hi + lo ) / 2;
- mp = mon_tptr + mid;
- if ( pc < (*mp)->func )
- {
- hi = mid-1;
- }
- else if ( pc > (*(mp+1))->func )
- {
- lo = mid+1;
- }
- else
- {
- return ( *mp ); /* found a function */
- break;
- }
- }
- }
- return ( *mon_tptr ); /* didn't find a func, return a pointer to */
- } /* the "system" call entry */
-
- long
- mon_init() /* initialize the monitor task */
- {
- register long i; /* loop counter */
- register long pri; /* old task priority */
-
- /*
- * first, make up an array of pointers to the function table. This
- * new array will be used for sorting and searching. By using an
- * array of pointers, we don't have to copy much information and
- * things run much faster.
- */
- mon_tptr = (mon_table **) AllocMem( mon_tabsize * sizeof( mon_table * ),
- MEMF_PUBLIC | MEMF_CLEAR );
- for ( i = 0; i < mon_tabsize; i++ )
- {
- *(mon_tptr + i) = mon_tbl + i;
- }
-
- mon_sort_table( mon_cmp_addr ); /* sort the table by function addr */
- Forbid(); /* turn off multi-tasking to access */
- thistask = FindTask( 0L ); /* system data structures */
- if ( thistask == NULL )
- {
- Permit();
- exit( 1 );
- }
- /*
- * task name, priority, task entry pt, task stack size */
- CreateTask( MONITOR_TASK, 5L, mon_task, STACKSIZE );
- Permit(); /* turn multi-tasking back on */
- DBG( printf( "starting monitoring\n" ); )
- return ( 0L );
- }
-
- void
- mon_print() /* print monitor results */
- {
- register long i; /* loop counter */
- register long cnt; /* count for individual functions */
-
- printf( "%-20s %6s %4s\n", "function", "count", "pct" );
- for ( i = 0; i < mon_tabsize; i++ )
- {
- cnt = (*(mon_tptr+i))->count;
- printf("%-20s %6ld %4ld\n", (*(mon_tptr+i))->name,
- cnt,
- 100*cnt/mon_total );
- }
- printf( "\n%-20s %6ld\n\n", "total count", mon_total );
- }
-
- void
- mon_sample() /* samples the monitored process */
- {
- register mon_table *tp; /* pointer to function table */
- register APTR pc; /* stack pointer */
-
- Forbid(); /* turn off multi-tasking */
- pc = (APTR) *(thistask->tc_SPReg); /* get the program counter */
- Permit(); /* turn on multi-tasking */
- tp = mon_get_func( (void (*)()) pc ); /* find the current function */
- tp->count++; /* increment its count */
- mon_total++;
- }
-
- void
- mon_sort_table( cmp ) /* sort the function table */
- long (*cmp)(); /* pointer to comparison function */
- {
- mon_table_qsort( mon_tptr+1, mon_tptr+mon_tabsize-1, cmp );
- }
-
- void
- mon_table_qsort( lo, hi, cmp ) /* quicksort the function table */
- mon_table **lo, **hi; /* table pointers */
- long (*cmp)(); /* comparison function */
- {
- register mon_table **i, **j; /* temporary pointers */
- register mon_table *t; /* partition */
- register mon_table *w; /* swap temporary */
-
- i = lo; j = hi;
- t = *(lo + (hi-lo)/2);
- do
- {
- while ( (*cmp)( *i, t ) > 0 ) i++;
- while ( (*cmp)( *j, t ) < 0 ) j--;
- if ( i <= j )
- {
- w = *i; *i = *j; *j = w; i++; j--;
- }
- } while ( i < j );
- if ( lo < j ) mon_table_qsort( lo, j, cmp );
- if ( i < hi ) mon_table_qsort( i, hi, cmp );
- }
-
- void
- mon_task() /* the monitor task */
- {
- struct timerequest *mon_tr; /* timer request struct pointer */
- register ULONG signals; /* signals sent to task */
- register struct MsgPort *reply; /* message reply port */
-
- geta4(); /* MUST CALL 1st thing in a created task */
- /* when using the AZTEC-C compiler */
- if ( (mon_tr = mon_create_timer( &mon_tr )) != NULL )
- {
- reply = mon_tr->tr_node.io_Message.mn_ReplyPort;
- do
- {
- SendIO( mon_tr ); /* start things off */
- do /* wait until timer goes off or the */
- /* monitor should be terminated */
- signals = Wait( SIGBREAKF_CTRL_C | SIG_PORT );
- while ( (signals & SIG_PORT ) != 0 &&
- CheckIO( mon_tr ) == 0 );
- if ( CheckIO( mon_tr ) == 0 ) /* if timer isn't done abort */
- AbortIO( mon_tr );
- if ( (signals & SIG_PORT) != 0 ) /* if timer went off, sample */
- mon_sample();
- } while ( (signals & SIGBREAKF_CTRL_C ) == 0 );
- mon_delete_timer( mon_tr ); /* terminating, so delete timer */
- }
- }
-
- void
- mon_terminate() /* terminate the monitor */
- {
- register long i; /* loop counter */
- struct Task *mt; /* monitor task */
- register long pri; /* monitored task priority */
-
- /* get the message signal and delete the exception */
-
- do
- {
- Forbid(); /* disable multi-tasking */
- mt = FindTask( MONITOR_TASK ); /* find monitor task */
- if ( mt )
- {
- Signal( mt, SIGBREAKF_CTRL_C ); /* blow it away */
- Delay( 10 ); /* wait for things to happen */
- }
- Permit(); /* enable multi-tasking again */
- } while ( mt != NULL );
-
- /*
- * sort the table first by count and print it, then sort by name
- * and print it.
- */
- mon_table_qsort( mon_tptr, mon_tptr+mon_tabsize-1, mon_cmp_count );
- mon_print();
- mon_table_qsort( mon_tptr, mon_tptr+mon_tabsize-1, mon_cmp_name );
- mon_print();
-
- /*
- * free the space allocated for the function table
- */
- FreeMem( mon_tptr, mon_tabsize * sizeof( mon_table * ) );
- }
-
- #if 0
-
- /*
- the following function is not used anywhere in the system; however, I
- used it in the beginning to see what was going on with the stack. It's
- included here for your personal enjoyment and edification.
-
- usage:
-
- a = b + c; <- in funca
- mon_trace();
- .
- .
- .
- result:
- funca called by funcb
- funcb called by foo
- foo called by main
- main the main function!
- */
- void
- mon_trace() /* print a trace of the stack */
- {
- long *fp; /* frame pointer */
- void (*pc)(); /* program counter */
- mon_table *func; /* function name */
-
- fp = (long *) &fp + STACKDIR; /* set frame pointer to current frame */
- pc = (void (*)()) *(fp + STACKDIR); /* get the program counter */
- while ( (func = mon_get_func( pc )) != *mon_tptr )
- {
- printf( "%-16s %lx\n", func->name, pc );
- if ( func->func == main )
- break;
- fp = (int *) *fp; /* set the frame pointer to the next one */
- pc = (void (*)()) *(fp + STACKDIR );
- }
- }
- #endif
-
- #ifdef TEST_MONITOR
-
- #define NWORD 150 /* default # of words to dump */
-
- void system(){} /* used when the pc is outside the program */
-
- int funca(), funcb(), funcc();
-
- mon_table mon_tbl[] = {
- MON_NAME( system ),
- MON_NAME( main ),
- MON_NAME( dumpstack ),
- MON_NAME( funca ),
- MON_NAME( funcc ),
- MON_NAME( funcb ),
- MON_NAME( mon_trace )
- };
-
- long mon_tabsize = sizeof( mon_tbl ) / sizeof( mon_table );
-
- void
- main( argc, argv )
- int argc;
- char **argv;
- {
- int i;
-
- if ( mon_init() != 0L )
- {
- printf( "initialization problems\n" );
- exit( 1 );
- }
- dumpstack();
- mon_terminate();
- }
-
- void
- dumpstack()
- {
- static long loc = 0; /* location of i in original call */
- long *ps; /* stack pointer */
- long i; /* loop counter */
-
- if ( !loc ) /* is this the first call to dumpstack */
- {
- loc = (int) &i; /* save temp location in loc */
- dumpstack();
- }
- else
- {
- mon_trace( );
- for ( i = 0; i < 1000; i++ ) funca();
- ps = &i;
- for ( i = 0; i < nword; i++ )
- {
- printf( "%lx: %lx\n", ps, *ps );
- ps += STACKDIR;
- }
- }
- }
-
- funca()
- {
- funcb();
- }
-
- funcb()
- {
- funcc();
- }
-
- funcc()
- {
- static long i;
-
- i++;
- printf( "print: %d\n", i );
- }
-
- #endif
-