• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* profil.c -- win32 profil.c equivalent
2 
3    Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
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 #ifndef WIN32_LEAN_AND_MEAN
17 #define WIN32_LEAN_AND_MEAN
18 #endif
19 #include <windows.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <errno.h>
23 #include <math.h>
24 #include "profil.h"
25 
26 #define SLEEPTIME (1000 / PROF_HZ)
27 
28 /* global profinfo for profil() call */
29 static struct profinfo prof;
30 
31 /* Get the pc for thread THR */
32 
33 static size_t
get_thrpc(HANDLE thr)34 get_thrpc (HANDLE thr)
35 {
36   CONTEXT ctx;
37   size_t pc;
38   int res;
39 
40   res = SuspendThread (thr);
41   if (res == -1)
42     return (size_t) - 1;
43   ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
44   pc = (size_t) - 1;
45   if (GetThreadContext (thr, &ctx)) {
46 #if defined(_AMD64_) || defined(__x86_64__)
47     pc = ctx.Rip;
48 #elif defined(_ARM_) || defined(__arm__)
49     pc = ctx.Pc;
50 #elif defined(_X86_) || defined(__i386__)
51     pc = ctx.Eip;
52 #endif
53   }
54   ResumeThread (thr);
55   return pc;
56 }
57 
58 /* Display cell of profile buffer */
59 #if 0
60 static void
61 print_prof (struct profinfo *p)
62 {
63   printf ("profthr %x\ttarget thr %x\n", p->profthr, p->targthr);
64   printf ("pc: %x - %x\n", p->lowpc, p->highpc);
65   printf ("scale: %x\n", p->scale);
66   return;
67 }
68 #endif
69 
70 /* Everytime we wake up use the main thread pc to hash into the cell in the
71    profile buffer ARG. */
72 
73 static void CALLBACK profthr_func (LPVOID);
74 
75 static void CALLBACK
profthr_func(LPVOID arg)76 profthr_func (LPVOID arg)
77 {
78   struct profinfo *p = (struct profinfo *) arg;
79   size_t pc, idx;
80 
81   for (;;)
82     {
83       pc = (size_t) get_thrpc (p->targthr);
84       if (pc >= p->lowpc && pc < p->highpc)
85 	{
86 	  idx = PROFIDX (pc, p->lowpc, p->scale);
87 	  p->counter[idx]++;
88 	}
89 #if 0
90       print_prof (p);
91 #endif
92       /* Check quit condition, WAIT_OBJECT_0 or WAIT_TIMEOUT */
93       if (WaitForSingleObject (p->quitevt, SLEEPTIME) == WAIT_OBJECT_0)
94 	return;
95     }
96 }
97 
98 /* Stop profiling to the profiling buffer pointed to by P. */
99 
100 static int
profile_off(struct profinfo * p)101 profile_off (struct profinfo *p)
102 {
103   if (p->profthr)
104     {
105       SignalObjectAndWait (p->quitevt, p->profthr, INFINITE, FALSE);
106       CloseHandle (p->quitevt);
107       CloseHandle (p->profthr);
108     }
109   if (p->targthr)
110     CloseHandle (p->targthr);
111   return 0;
112 }
113 
114 /* Create a timer thread and pass it a pointer P to the profiling buffer. */
115 
116 static int
profile_on(struct profinfo * p)117 profile_on (struct profinfo *p)
118 {
119   DWORD thrid;
120 
121   /* get handle for this thread */
122   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
123 			GetCurrentProcess (), &p->targthr, 0, FALSE,
124 			DUPLICATE_SAME_ACCESS))
125     {
126       errno = ESRCH;
127       return -1;
128     }
129 
130   p->quitevt = CreateEvent (NULL, TRUE, FALSE, NULL);
131 
132   if (!p->quitevt)
133     {
134       CloseHandle (p->quitevt);
135       p->targthr = 0;
136       errno = EAGAIN;
137       return -1;
138     }
139 
140   p->profthr = CreateThread (0, 0, (DWORD (WINAPI *)(LPVOID)) profthr_func,
141                              (void *) p, 0, &thrid);
142 
143   if (!p->profthr)
144     {
145       CloseHandle (p->targthr);
146       CloseHandle (p->quitevt);
147       p->targthr = 0;
148       errno = EAGAIN;
149       return -1;
150     }
151 
152   /* Set profiler thread priority to highest to be sure that it gets the
153      processor as soon it request it (i.e. when the Sleep terminate) to get
154      the next data out of the profile. */
155 
156   SetThreadPriority (p->profthr, THREAD_PRIORITY_TIME_CRITICAL);
157 
158   return 0;
159 }
160 
161 /*
162  * start or stop profiling
163  *
164  * profiling goes into the SAMPLES buffer of size SIZE (which is treated
165  * as an array of u_shorts of size size/2)
166  *
167  * each bin represents a range of pc addresses from OFFSET.  The number
168  * of pc addresses in a bin depends on SCALE.  (A scale of 65536 maps
169  * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
170  * a scale of 1 maps each bin to 128k addreses).  Scale may be 1 - 65536,
171  * or zero to turn off profiling
172  */
173 int
profile_ctl(struct profinfo * p,char * samples,size_t size,size_t offset,u_int scale)174 profile_ctl (struct profinfo * p, char *samples, size_t size,
175 	     size_t offset, u_int scale)
176 {
177   size_t maxbin;
178 
179   if (scale > 65536)
180     {
181       errno = EINVAL;
182       return -1;
183     }
184 
185   profile_off (p);
186   if (scale)
187     {
188       memset (samples, 0, size);
189       memset (p, 0, sizeof *p);
190       maxbin = size >> 1;
191       prof.counter = (u_short *) samples;
192       prof.lowpc = offset;
193       prof.highpc = PROFADDR (maxbin, offset, scale);
194       prof.scale = scale;
195 
196       return profile_on (p);
197     }
198   return 0;
199 }
200 
201 /* Equivalent to unix profil()
202    Every SLEEPTIME interval, the user's program counter (PC) is examined:
203    offset is subtracted and the result is multiplied by scale.
204    The word pointed to by this address is incremented.  Buf is unused. */
205 
206 int
profil(char * samples,size_t size,size_t offset,u_int scale)207 profil (char *samples, size_t size, size_t offset, u_int scale)
208 {
209   return profile_ctl (&prof, samples, size, offset, scale);
210 }
211 
212