home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / crt0 / mcount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-01  |  4.4 KB  |  194 lines

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. #include <libc/stubs.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <setjmp.h>
  9. #include <sys/time.h>
  10. #include <sys/exceptn.h>
  11. #include <sys/mono.h>
  12.  
  13. /* header of a GPROF type file
  14. */
  15. typedef struct {
  16.   long low;
  17.   long high;
  18.   long nbytes;
  19. } header;
  20.  
  21. /* entry of a GPROF type file
  22. */
  23. typedef struct {
  24.     unsigned long from;
  25.     unsigned long to;
  26.     unsigned long count;
  27. } MTABE;
  28.  
  29. /* internal form - sizeof(MTAB) is 4096 for efficiency
  30. */
  31. typedef struct MTAB {
  32.   MTABE calls[341];
  33.   struct MTAB *prev;
  34. } MTAB;
  35.  
  36. static header h;
  37. static short *histogram;
  38. static int mcount_skip = 1;
  39. static int histlen;
  40. static MTAB *mtab=0;
  41.  
  42. extern int etext;
  43.  
  44. /* called by functions.  Use the pointer it provides to cache
  45. ** the last used MTABE, so that repeated calls to/from the same
  46. ** pair works quickly - no lookup.
  47. */
  48. void mcount(int _to);
  49. void mcount(int _to)
  50. {
  51.   MTAB *m;
  52.   int i;
  53.   int to;
  54.   int ebp;
  55.   int from;
  56.   int mtabi;
  57.   MTABE **cache;
  58.  
  59.   if (&_to < &etext)
  60.     *(int *)(-1) = 0; /* fault! */
  61.  
  62.   mcount_skip = 1;
  63.   asm("movl %%edx,%0" : "=g" (cache)); /* obtain the cached pointer */
  64.   to = *((&_to)-1) - 12;
  65.   ebp = *((&_to)-2); /* glean the caller's return address from the stack */
  66.   from = ((int *)ebp)[1];
  67.   _mono_printf("from %08x  to %08x\r\n", from, to);
  68.   if (*cache && ((*cache)->from == from) && ((*cache)->to == to))
  69.   {
  70.     /* cache paid off - works quickly */
  71.     (*cache)->count++;
  72.     mcount_skip = 0;
  73.     return;
  74.   }
  75.  
  76.   /* no cache hit - search all mtab tables for a match, or an empty slot */
  77.   mtabi = -1;
  78.   for (m=mtab; m; m=m->prev)
  79.   {
  80.     for (i=0; i<341; i++)
  81.     {
  82.       if (m->calls[i].from == 0)
  83.       {
  84.         /* empty slot - end of table */
  85.         mtabi = i;
  86.         break;
  87.       }
  88.       if ((m->calls[i].from == from) &&
  89.           (m->calls[i].to == to))
  90.         {
  91.           /* found a match - bump count and return */
  92.           m->calls[i].count ++;
  93.           *cache = m->calls + i;
  94.           mcount_skip = 0;
  95.           return;
  96.         }
  97.     }
  98.   }
  99.   if (mtabi != -1)
  100.   {
  101.     /* found an empty - fill it in */
  102.     mtab->calls[mtabi].from = from;
  103.     mtab->calls[mtabi].to = to;
  104.     mtab->calls[mtabi].count = 1;
  105.     *cache = mtab->calls + mtabi;
  106.     mcount_skip = 0;
  107.     return;
  108.   }
  109.   /* lob off another page of memory and initialize the new table */
  110.   m = (MTAB *)sbrk(sizeof(MTAB));
  111.   memset(m, 0, sizeof(MTAB));
  112.   m->prev = mtab;
  113.   mtab = m;
  114.   m->calls[0].from = from;
  115.   m->calls[0].to = to;
  116.   m->calls[0].count = 1;
  117.   *cache = m->calls;
  118.   mcount_skip = 0;
  119. }
  120.  
  121. /* this is called during program exit (installed by atexit). */
  122. static void
  123. mcount_write(void)
  124. {
  125.   MTAB *m;
  126.   int i, f;
  127.   struct itimerval new_values;
  128.  
  129.   mcount_skip = 1;
  130.  
  131.   /* disable timer */
  132.   new_values.it_value.tv_usec = new_values.it_interval.tv_usec = 0;   
  133.   new_values.it_value.tv_sec = new_values.it_interval.tv_sec = 0;
  134.   setitimer(ITIMER_PROF, &new_values, NULL);
  135.  
  136.   f = open("gmon.out", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
  137.   write(f, &h, sizeof(header));
  138.   write(f, histogram, histlen);
  139.   for (m=mtab; m; m=m->prev)
  140.   {
  141.     for (i=0; i<341; i++)
  142.       if (m->calls[i].from == 0)
  143.         break;
  144.     write(f, m->calls, i*12);
  145.   }
  146.   close(f);
  147. }
  148.  
  149. extern unsigned start __asm__ ("start");
  150. #define START (unsigned)&start
  151. extern int etext;
  152.  
  153. /* ARGSUSED */
  154. static void
  155. mcount_tick(int _x)
  156. {
  157.   unsigned bin;
  158.   
  159.   if(!mcount_skip) {
  160.     bin = __djgpp_exception_state->__eip;
  161.     if(bin >= START && bin <= (unsigned)&etext) {
  162.       bin = (bin - START) / 4;    /* 4 EIP's per bin */
  163.       histogram[bin]++;
  164.     }
  165.   }
  166. }
  167.  
  168. /* this is called to initialize profiling before the program starts */
  169. void _mcount_init(void);
  170. void
  171. _mcount_init(void)
  172. {
  173.   struct itimerval new_values;
  174.  
  175.   h.low = START;
  176.   h.high = (int)&etext;
  177.   histlen = (h.high-h.low)/4*sizeof(short);
  178.   h.nbytes = sizeof(header) + histlen;
  179.   histogram = (short *)sbrk(histlen);
  180.   memset(histogram, 0, histlen);
  181.   atexit(mcount_write);
  182.  
  183.   /* here, do whatever it takes to initialize the timer interrupt */
  184.   signal(SIGPROF, mcount_tick);
  185.  
  186.   /* 18.2 tics per second */
  187.   new_values.it_value.tv_usec = new_values.it_interval.tv_usec = 5494;
  188.   new_values.it_value.tv_sec = new_values.it_interval.tv_sec = 0;
  189.  
  190.   setitimer(ITIMER_PROF, &new_values, NULL);
  191.  
  192.   mcount_skip = 0;
  193. }
  194.