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 >
Text File  |  1988-12-19  |  14KB  |  454 lines

  1. /*
  2.         HEADER:                CUG000.00;
  3.         TITLE:                Amiga Monitor source code file;
  4.         DATE:                09/07/88;
  5.         VERSION:        1.0;
  6.         FILENAME:        MONITOR.C;
  7.         SEE-ALSO:        MONITOR.H;
  8.         AUTHORS:        Steve Roggenkamp
  9. */
  10. /*
  11.    monitor.c -- monitor a process, demonstrating interprocess communications
  12.                 and other such things.  Written for the Amiga running
  13.                 AmigaDOS.
  14.  
  15.    Steve Roggenkamp
  16.    5394 Winetavern Lane
  17.    Dublin, OH  43017
  18.    (614)792-8236
  19.    
  20.    9 / 6 / 88
  21. */
  22.  
  23. #include <stdio.h>
  24. #include "monitor.h"
  25.  
  26. #ifdef DEBUG
  27. #define DBG( x )
  28. #else
  29. #define DBG( x )
  30. #endif
  31.  
  32. #define SAMPLE_RATE  20000  /* sample rate in microseconds 
  33.                               this rate is 50 samples per second */
  34.  
  35. #define STACKSIZE    1000L  /* size of task stack */
  36.  
  37. #define MONITOR_TASK "monitor"  /* monitor task name */
  38.  
  39. #define SIG_PORT     (1 << reply->mp_SigBit)
  40.  
  41. APTR                AllocMem();
  42. void                DeleteTimer( );
  43. struct timerequest *CreateTimer( );
  44. struct Task        *FindTask();
  45. struct Task        *thistask;           /* monitored task */
  46. struct Task        *montask;            /* monitoring task */
  47.  
  48. extern long        mon_tabsize; /* size of mon_tbl in # of entries */
  49. extern mon_table   mon_tbl[];   /* table containing function information */
  50. static ULONG       mon_total;   /* number of times the task is sampled */
  51. static mon_table **mon_tptr;    /* sorted array of pointers to mon_tbl */
  52.  
  53. long time_delay = SAMPLE_RATE;    /* time delay in usec */
  54.  
  55. long
  56. mon_cmp_addr( x, y )             /* compare mon_table function addresses */
  57.     register mon_table *x, *y;   /* entries in mon_table to compare */
  58. {
  59.     return ( (long) y->func - (long) x->func);
  60.     }
  61.     
  62. long
  63. mon_cmp_name( x, y )             /* compare mon_table function names */
  64.     register mon_table *x, *y;   /* entries in mon_table to compare */
  65. {
  66.     return ( strcmp( y->name, x->name ));
  67.     }
  68.         
  69. long
  70. mon_cmp_count( x, y )            /* compare mon_table function names */
  71.     register mon_table *x, *y;   /* entries in mon_table to compare */
  72. {
  73.     return ( x->count - y->count );
  74.     }
  75.         
  76. struct timerequest *
  77. mon_create_timer( mon_tr )         /* create a timer */
  78.     struct timerequest **mon_tr;   /* time request */
  79. {
  80.     LONG  error;     /* error */
  81.     ULONG sigmask;   /* signal mask */
  82.     
  83.     struct MsgPort     *timerport;    /* message port for the timer */
  84.     static struct timeval tv;         /* time delay structure */
  85.     
  86.     timerport = CreatePort( 0L, 0L );   /* get a message port for timer */
  87.     if ( timerport == NULL )
  88.         {
  89.         return( NULL );
  90.         }
  91.     *mon_tr = (struct timerequest *)
  92.              CreateExtIO( timerport, sizeof( struct timerequest ));
  93.     if ( *mon_tr == NULL )
  94.         {
  95.         mon_delete_timer( *mon_tr );
  96.         return( NULL );
  97.         }
  98.     error = OpenDevice( TIMERNAME, UNIT_VBLANK, *mon_tr, 0L );
  99.     if ( error != 0L )
  100.         {
  101.         mon_delete_timer( *mon_tr );
  102.         return( NULL );
  103.         }
  104.     tv.tv_secs  = 0;                    /* set the time delay we want */
  105.     tv.tv_micro = time_delay;
  106.     (*mon_tr)->tr_time = tv;
  107.     (*mon_tr)->tr_node.io_Command = TR_ADDREQUEST;
  108.     
  109.     return( *mon_tr );
  110.     }
  111.     
  112. void
  113. mon_delete_timer( tr )           /* delete the timer we created above */
  114.     struct timerequest *tr;      /* timer to delete */
  115. {
  116.     struct MsgPort  *tp;         /* timer message port */
  117.     
  118.     Forbid();                    /* disable multi-tasking so we don't */
  119.     if ( tr != NULL )            /* mess up some system data structs  */
  120.         {
  121.         tp = tr->tr_node.io_Message.mn_ReplyPort;
  122.         CloseDevice( tr );                             /* close the timer */
  123.         DeleteExtIO( tr, sizeof( struct timerequest ));
  124.         if ( tp != 0L )
  125.             {
  126.             DeletePort( tp );                  /* get rid of message port */
  127.             }
  128.         }
  129.     Permit();                    /* enable multi-tasking again */
  130.     }
  131.  
  132. mon_table *
  133. mon_get_func( pc )            /* return a pointer to the function pc is in */
  134.     register void (*pc)();                /* program counter */
  135. {
  136.     long               lo, hi; /* low and high offsets into mon_table array */
  137.     register long      mid;    /* offset to the middle of the table */
  138.     register mon_table **mp;    /* pointer to middle of the lo - hi range */
  139.  
  140.     lo = 1;                /* don't look at entry 0, it's the system calls */
  141.     hi = mon_tabsize-1;    /* point to the last entry into the table */
  142.     
  143.     /*
  144.        first, check to see if the program counter is contained within
  145.        the monitor function table.  If it is not, then just return the
  146.        pointer to the beginning of the table.
  147.      */
  148.     if ( pc < mon_tptr[hi]->func && pc > mon_tptr[1]->func )
  149.         {
  150.         while ( hi >= lo )           /* use a binary search for speed */
  151.             {
  152.             mid = ( hi + lo ) / 2;
  153.             mp = mon_tptr + mid;
  154.             if ( pc < (*mp)->func )
  155.                 {
  156.                 hi = mid-1;
  157.                 }
  158.             else if ( pc > (*(mp+1))->func )
  159.                 {
  160.                 lo = mid+1;
  161.                 }
  162.             else
  163.                 {
  164.                 return ( *mp );  /* found a function */
  165.                 break;
  166.                 }
  167.             }
  168.         }
  169.     return ( *mon_tptr );   /* didn't find a func, return a pointer to */
  170.     }                       /* the "system" call entry */
  171.  
  172. long
  173. mon_init()               /* initialize the monitor task */
  174. {
  175.     register long i;     /* loop counter */
  176.     register long pri;   /* old task priority */
  177.  
  178.     /*
  179.      * first, make up an array of pointers to the function table.  This
  180.      * new array will be used for sorting and searching.  By using an
  181.      * array of pointers, we don't have to copy much information and
  182.      * things run much faster.
  183.      */
  184.     mon_tptr = (mon_table **) AllocMem( mon_tabsize * sizeof( mon_table * ),
  185.                                         MEMF_PUBLIC | MEMF_CLEAR );
  186.     for ( i = 0; i < mon_tabsize; i++ )
  187.         {
  188.         *(mon_tptr + i) = mon_tbl + i;
  189.         }
  190.                                                  
  191.     mon_sort_table( mon_cmp_addr );    /* sort the table by function addr */
  192.     Forbid();                          /* turn off multi-tasking to access */
  193.     thistask = FindTask( 0L );         /* system data structures */
  194.     if ( thistask == NULL )
  195.         {
  196.         Permit();
  197.         exit( 1 );
  198.         }
  199.     /*
  200.      *           task name,   priority, task entry pt, task stack size */
  201.     CreateTask( MONITOR_TASK,    5L,      mon_task,       STACKSIZE );
  202.     Permit();                          /* turn multi-tasking back on */
  203.     DBG( printf( "starting monitoring\n" ); )
  204.     return ( 0L );
  205.     }
  206.     
  207. void
  208. mon_print()    /* print monitor results */
  209. {
  210.     register long i;       /* loop counter */
  211.     register long cnt;     /* count for individual functions */
  212.     
  213.     printf( "%-20s %6s %4s\n", "function", "count", "pct" );
  214.     for ( i = 0; i < mon_tabsize; i++ )
  215.         {
  216.         cnt = (*(mon_tptr+i))->count;
  217.         printf("%-20s %6ld %4ld\n", (*(mon_tptr+i))->name,
  218.                                     cnt,
  219.                                     100*cnt/mon_total );
  220.         }
  221.     printf( "\n%-20s %6ld\n\n", "total count", mon_total );
  222.     }
  223.  
  224. void
  225. mon_sample()                  /* samples the monitored process */
  226. {
  227.     register mon_table   *tp;     /* pointer to function table */
  228.     register APTR         pc;     /* stack pointer */
  229.  
  230.     Forbid();                             /* turn off multi-tasking */
  231.     pc = (APTR) *(thistask->tc_SPReg);    /* get the program counter */
  232.     Permit();                             /* turn on multi-tasking */
  233.     tp = mon_get_func( (void (*)()) pc ); /* find the current function */
  234.     tp->count++;                          /* increment its count */
  235.     mon_total++;
  236.     }
  237.  
  238. void
  239. mon_sort_table( cmp )          /* sort the function table */
  240.     long (*cmp)();             /* pointer to comparison function */
  241. {
  242.     mon_table_qsort( mon_tptr+1, mon_tptr+mon_tabsize-1, cmp );
  243.     }
  244.  
  245. void
  246. mon_table_qsort( lo, hi, cmp )     /* quicksort the function table */
  247.     mon_table **lo, **hi;          /* table pointers */
  248.     long      (*cmp)();            /* comparison function */
  249. {
  250.     register mon_table   **i, **j; /* temporary pointers */
  251.     register mon_table    *t;      /* partition */
  252.     register mon_table    *w;      /* swap temporary */
  253.     
  254.     i = lo; j = hi;
  255.     t = *(lo + (hi-lo)/2);
  256.     do
  257.         {
  258.         while ( (*cmp)( *i, t ) > 0 ) i++;
  259.         while ( (*cmp)( *j, t ) < 0 ) j--;
  260.         if ( i <= j )
  261.             {
  262.             w = *i;  *i = *j; *j = w; i++; j--;
  263.             }
  264.         } while ( i < j );
  265.     if ( lo < j ) mon_table_qsort( lo, j, cmp );
  266.     if ( i < hi ) mon_table_qsort( i, hi, cmp );
  267.     }
  268.  
  269. void
  270. mon_task()               /* the monitor task */
  271. {
  272.     struct timerequest *mon_tr;  /* timer request struct pointer */
  273.     register ULONG               signals; /* signals sent to task */
  274.     register struct MsgPort     *reply;   /* message reply port */
  275.  
  276.     geta4();                 /* MUST CALL 1st thing in a created task */
  277.                              /* when using the AZTEC-C compiler */
  278.     if ( (mon_tr = mon_create_timer( &mon_tr )) != NULL ) 
  279.         {
  280.         reply = mon_tr->tr_node.io_Message.mn_ReplyPort;
  281.         do
  282.             {
  283.             SendIO( mon_tr );     /* start things off */
  284.             do                    /* wait until timer goes off or the */
  285.                                   /* monitor should be terminated */
  286.                 signals = Wait( SIGBREAKF_CTRL_C | SIG_PORT );
  287.             while ( (signals & SIG_PORT ) != 0 &&
  288.                      CheckIO( mon_tr ) == 0 );
  289.             if ( CheckIO( mon_tr ) == 0 )   /* if timer isn't done abort */
  290.                 AbortIO( mon_tr );
  291.             if ( (signals & SIG_PORT) != 0 )  /* if timer went off, sample */
  292.                 mon_sample();
  293.             } while ( (signals & SIGBREAKF_CTRL_C ) == 0 );
  294.         mon_delete_timer( mon_tr );   /* terminating, so delete timer */
  295.         }
  296.     }
  297.  
  298. void
  299. mon_terminate()        /* terminate the monitor */
  300. {
  301.     register long i;    /* loop counter */
  302.     struct Task   *mt;  /* monitor task */
  303.     register long pri;  /* monitored task priority */
  304.  
  305.     /* get the message signal and delete the exception */
  306.  
  307.     do
  308.         {
  309.         Forbid();                       /* disable multi-tasking */
  310.         mt = FindTask( MONITOR_TASK );  /* find monitor task */
  311.         if ( mt )
  312.             {
  313.             Signal( mt, SIGBREAKF_CTRL_C );   /* blow it away */
  314.             Delay( 10 );                      /* wait for things to happen */
  315.             }
  316.         Permit();                       /* enable multi-tasking again */
  317.         } while ( mt != NULL );
  318.  
  319.     /*
  320.      * sort the table first by count and print it, then sort by name
  321.      * and print it.
  322.      */
  323.     mon_table_qsort( mon_tptr, mon_tptr+mon_tabsize-1, mon_cmp_count );
  324.     mon_print();
  325.     mon_table_qsort( mon_tptr, mon_tptr+mon_tabsize-1, mon_cmp_name );
  326.     mon_print();
  327.  
  328.     /*
  329.      * free the space allocated for the function table
  330.      */
  331.     FreeMem( mon_tptr, mon_tabsize * sizeof( mon_table * ) );
  332.     }
  333.  
  334. #if 0
  335.  
  336. /*
  337.    the following function is not used anywhere in the system; however, I
  338.    used it in the beginning to see what was going on with the stack.  It's
  339.    included here for your personal enjoyment and edification.
  340.    
  341.    usage:
  342.    
  343.         a = b + c;     <- in funca
  344.         mon_trace();
  345.         .
  346.         .
  347.         .
  348.    result:
  349.         funca     called by funcb
  350.         funcb     called by foo
  351.         foo       called by main
  352.         main      the main function!
  353. */
  354. void
  355. mon_trace()      /* print a trace of the stack */
  356.     {
  357.     long   *fp;          /* frame pointer */
  358.     void (*pc)();        /* program counter */
  359.     mon_table *func;     /* function name */
  360.     
  361.     fp = (long *) &fp + STACKDIR;   /* set frame pointer to current frame */
  362.     pc = (void (*)()) *(fp + STACKDIR);    /* get the program counter */
  363.     while ( (func = mon_get_func( pc )) != *mon_tptr )
  364.         {
  365.         printf( "%-16s %lx\n", func->name, pc );
  366.         if ( func->func == main ) 
  367.             break;
  368.         fp = (int *) *fp;       /* set the frame pointer to the next one */
  369.         pc = (void (*)()) *(fp + STACKDIR ); 
  370.         }
  371.     }
  372. #endif
  373.  
  374. #ifdef TEST_MONITOR
  375.  
  376. #define NWORD         150  /* default # of words to dump */
  377.  
  378. void system(){}            /* used when the pc is outside the program */
  379.  
  380. int funca(), funcb(), funcc();
  381.  
  382. mon_table mon_tbl[] = {
  383.     MON_NAME( system ),
  384.     MON_NAME( main ),
  385.     MON_NAME( dumpstack ),
  386.     MON_NAME( funca ),
  387.     MON_NAME( funcc ),
  388.     MON_NAME( funcb ),
  389.     MON_NAME( mon_trace )
  390.     };
  391.  
  392. long mon_tabsize = sizeof( mon_tbl ) / sizeof( mon_table );
  393.  
  394. void
  395. main( argc, argv )
  396.     int argc;
  397.     char **argv;
  398.     {
  399.     int  i;
  400.  
  401.     if ( mon_init() != 0L )
  402.         {
  403.         printf( "initialization problems\n" );
  404.         exit( 1 );
  405.         }
  406.     dumpstack();
  407.     mon_terminate();
  408.     }
  409.  
  410. void
  411. dumpstack()
  412.     {
  413.     static long loc = 0;    /* location of i in original call */
  414.            long *ps;        /* stack pointer */
  415.            long i;          /* loop counter */
  416.     
  417.     if ( !loc )          /* is this the first call to dumpstack */
  418.         {
  419.         loc = (int) &i;     /* save temp location in loc */
  420.         dumpstack();
  421.         }
  422.     else
  423.         {
  424.         mon_trace( );
  425.         for ( i = 0; i < 1000; i++ )  funca();
  426.         ps = &i;
  427.         for ( i = 0; i < nword; i++ )
  428.             {
  429.             printf( "%lx:  %lx\n", ps, *ps );
  430.             ps += STACKDIR;
  431.             }
  432.         }
  433.     }
  434.  
  435. funca()
  436.     {
  437.     funcb();
  438.     }
  439.  
  440. funcb()
  441.     {
  442.     funcc();
  443.     }
  444.  
  445. funcc()
  446.     {
  447.     static long i;
  448.     
  449.     i++;
  450.     printf( "print:  %d\n", i );
  451.     }
  452.  
  453. #endif
  454.