home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_07_02
/
v7n2078a.txt
< prev
next >
Wrap
Text File
|
1988-12-19
|
14KB
|
454 lines
/*
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