home *** CD-ROM | disk | FTP | other *** search
/ Programming Win32 Under the API / ProgrammingWin32UnderTheApiPatVillani.iso / src / mingw-runtime-19991107 / mingw / profile / profil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-04  |  3.9 KB  |  179 lines

  1. /* profil.c -- win32 profil.c equivalent
  2.  
  3.    Copyright 1998 Cygnus Solutions.
  4.  
  5.    This file is part of Cygwin.
  6.  
  7.    This software is a copyrighted work licensed under the terms of the
  8.    Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
  9.    details. */
  10.  
  11. /*
  12.  * This file is taken from Cygwin distribution. Please keep it in sync.
  13.  * The differences should be within __MINGW32__ guard.
  14.  */
  15.  
  16. #include <windows.h>
  17. #include <stdio.h>
  18. #include <sys/types.h>
  19. #include <errno.h>
  20. #include <math.h>
  21.  
  22. #include <profil.h>
  23.  
  24. #define SLEEPTIME (1000 / PROF_HZ)
  25.  
  26. /* global profinfo for profil() call */
  27. static struct profinfo prof;
  28.  
  29. /* Get the pc for thread THR */
  30.  
  31. static u_long
  32. get_thrpc (HANDLE thr)
  33. {
  34.   CONTEXT ctx;
  35.   u_long pc;
  36.   int res;
  37.  
  38.   res = SuspendThread (thr);
  39.   if (res == -1)
  40.     return (u_long) - 1;
  41.   ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  42.   pc = (u_long) - 1;
  43.   if (GetThreadContext (thr, &ctx))
  44.     pc = ctx.Eip;
  45.   ResumeThread (thr);
  46.   return pc;
  47. }
  48.  
  49. /* Display cell of profile buffer */
  50. #if 0
  51. static void
  52. print_prof (struct profinfo *p)
  53. {
  54.   printf ("profthr %x\ttarget thr %x\n", p->profthr, p->targthr);
  55.   printf ("pc: %x - %x\n", p->lowpc, p->highpc);
  56.   printf ("scale: %x\n", p->scale);
  57.   return;
  58. }
  59. #endif
  60.  
  61. /* Everytime we wake up use the main thread pc to hash into the cell in the 
  62.    profile buffer ARG. */
  63.  
  64. static DWORD CALLBACK
  65. profthr_func (LPVOID arg)
  66. {
  67.   struct profinfo *p = (struct profinfo *) arg;
  68.   u_long pc, idx;
  69.  
  70.   for (;;)
  71.     {
  72.       pc = (u_long) get_thrpc (p->targthr);
  73.       if (pc >= p->lowpc && pc < p->highpc)
  74.     {
  75.       idx = PROFIDX (pc, p->lowpc, p->scale);
  76.       p->counter[idx]++;
  77.     }
  78. #if 0
  79.       print_prof (p);
  80. #endif
  81.       Sleep (SLEEPTIME);
  82.     }
  83.   return 0;
  84. }
  85.  
  86. /* Stop profiling to the profiling buffer pointed to by P. */
  87.  
  88. static int
  89. profile_off (struct profinfo *p)
  90. {
  91.   if (p->profthr)
  92.     {
  93.       TerminateThread (p->profthr, 0);
  94.       CloseHandle (p->profthr);
  95.     }
  96.   if (p->targthr)
  97.     CloseHandle (p->targthr);
  98.   return 0;
  99. }
  100.  
  101. /* Create a timer thread and pass it a pointer P to the profiling buffer. */
  102.  
  103. static int
  104. profile_on (struct profinfo *p)
  105. {
  106.   DWORD thrid;
  107.  
  108.   /* get handle for this thread */
  109.   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
  110.             GetCurrentProcess (), &p->targthr, 0, FALSE,
  111.             DUPLICATE_SAME_ACCESS))
  112.     {
  113.       errno = ESRCH;
  114.       return -1;
  115.     }
  116.  
  117.   p->profthr = CreateThread (0, 0, profthr_func, (void *) p, 0, &thrid);
  118.   if (!p->profthr)
  119.     {
  120.       CloseHandle (p->targthr);
  121.       p->targthr = 0;
  122.       errno = EAGAIN;
  123.       return -1;
  124.     }
  125.   return 0;
  126. }
  127.  
  128. /*
  129.  * start or stop profiling
  130.  *
  131.  * profiling goes into the SAMPLES buffer of size SIZE (which is treated
  132.  * as an array of u_shorts of size size/2)
  133.  * 
  134.  * each bin represents a range of pc addresses from OFFSET.  The number
  135.  * of pc addresses in a bin depends on SCALE.  (A scale of 65536 maps
  136.  * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
  137.  * a scale of 1 maps each bin to 128k addreses).  Scale may be 1 - 65536,
  138.  * or zero to turn off profiling
  139.  */
  140. int
  141. profile_ctl (struct profinfo * p, char *samples, size_t size,
  142.          u_long offset, u_int scale)
  143. {
  144.   u_long maxbin;
  145.  
  146.   if (scale > 65536)
  147.     {
  148.       errno = EINVAL;
  149.       return -1;
  150.     }
  151.  
  152.   profile_off (p);
  153.   if (scale)
  154.     {
  155.       memset (samples, 0, size);
  156.       memset (p, 0, sizeof *p);
  157.       maxbin = size >> 1;
  158.       prof.counter = (u_short *) samples;
  159.       prof.lowpc = offset;
  160.       prof.highpc = PROFADDR (maxbin, offset, scale);
  161.       prof.scale = scale;
  162.  
  163.       return profile_on (p);
  164.     }
  165.   return 0;
  166. }
  167.  
  168. /* Equivalent to unix profil() 
  169.    Every SLEEPTIME interval, the user's program counter (PC) is examined: 
  170.    offset is subtracted and the result is multiplied by scale.  
  171.    The word pointed to by this address is incremented.  Buf is unused. */
  172.  
  173. int
  174. profil (char *samples, size_t size, u_long offset, u_int scale)
  175. {
  176.   return profile_ctl (&prof, samples, size, offset, scale);
  177. }
  178.  
  179.