1 /* profil.c -- win32 profil.c equivalent
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 * This file is taken from Cygwin distribution. Please keep it in sync.
11 * The differences should be within __MINGW32__ guard.
14 #ifndef WIN32_LEAN_AND_MEAN
15 #define WIN32_LEAN_AND_MEAN
19 #include <sys/cygwin.h>
20 #include <sys/types.h>
25 #define SLEEPTIME (1000 / PROF_HZ)
27 /* global profinfo for profil() call */
28 static struct profinfo prof
;
30 /* Get the pc for thread THR */
33 get_thrpc (HANDLE thr
)
39 res
= SuspendThread (thr
);
42 ctx
.ContextFlags
= CONTEXT_CONTROL
| CONTEXT_INTEGER
;
44 if (GetThreadContext (thr
, &ctx
)) {
48 #error unimplemented for this target
55 /* Display cell of profile buffer */
58 print_prof (struct profinfo
*p
)
60 printf ("profthr %x\ttarget thr %x\n", p
->profthr
, p
->targthr
);
61 printf ("pc: %x - %x\n", p
->lowpc
, p
->highpc
);
62 printf ("scale: %x\n", p
->scale
);
67 /* Every time we wake up sample the main thread's pc to hash into the cell
68 in the profile buffer ARG. Then all other pthreads' pc's are sampled. */
71 profthr_byhandle (HANDLE thr
)
75 /* Sample the pc of the thread indicated by thr; bail if anything amiss. */
76 if (thr
== INVALID_HANDLE_VALUE
)
82 /* Code assumes there's only one profinfo in play: the static prof above. */
83 if (pc
>= prof
.lowpc
&& pc
< prof
.highpc
)
85 size_t idx
= PROFIDX (pc
, prof
.lowpc
, prof
.scale
);
91 profthr_func (LPVOID arg
)
93 struct profinfo
*p
= (struct profinfo
*) arg
;
97 /* Record profiling sample for main thread. */
98 profthr_byhandle (p
->targthr
);
100 /* Record profiling samples for other pthreads, if any. */
101 cygwin_internal (CW_CYGHEAP_PROFTHR_ALL
, profthr_byhandle
);
106 /* Check quit condition, WAIT_OBJECT_0 or WAIT_TIMEOUT */
107 if (WaitForSingleObject (p
->quitevt
, SLEEPTIME
) == WAIT_OBJECT_0
)
112 /* Stop profiling to the profiling buffer pointed to by P. */
115 profile_off (struct profinfo
*p
)
119 SignalObjectAndWait (p
->quitevt
, p
->profthr
, INFINITE
, FALSE
);
120 CloseHandle (p
->quitevt
);
121 CloseHandle (p
->profthr
);
124 CloseHandle (p
->targthr
);
129 /* Create a timer thread and pass it a pointer P to the profiling buffer. */
132 profile_on (struct profinfo
*p
)
136 /* get handle for this thread */
137 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
138 GetCurrentProcess (), &p
->targthr
, 0, FALSE
,
139 DUPLICATE_SAME_ACCESS
))
146 p
->quitevt
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
150 CloseHandle (p
->targthr
);
156 p
->profthr
= CreateThread (0, 0, (DWORD (*)(LPVOID
)) profthr_func
,
157 (void *) p
, 0, &thrid
);
161 CloseHandle (p
->targthr
);
162 CloseHandle (p
->quitevt
);
168 /* Set profiler thread priority to highest to be sure that it gets the
169 processor as soon it requests it (i.e. when the Sleep terminates) to get
170 the next data sample as quickly as possible. */
172 SetThreadPriority (p
->profthr
, THREAD_PRIORITY_TIME_CRITICAL
);
178 * Restart profiling in child after fork.
180 * The profiling control info in prof needs to be selectively updated.
181 * Items counter, lowpc, highpc, and scale are correct as-is. But items
182 * targthr, profthr, and quitevt need updating because these copied HANDLE
183 * values are only valid in parent process. We also zero out the sample
184 * buffer so that samples aren't double-counted if multiple gmon.out files
185 * are aggregated. We calculate buffer's size from other data in prof.
190 /* Bail if this was a fork after profiling turned off or was never on. */
194 /* Figure out how big the sample buffer is and zero it out. */
195 size_t size
= PROFIDX (prof
.highpc
, prof
.lowpc
, prof
.scale
) << 1;
196 memset ((char *) prof
.counter
, 0, size
);
198 /* Replace stale HANDLEs in prof and create profiling thread. */
203 * Start or stop profiling.
205 * Profiling data goes into the SAMPLES buffer of size SIZE (which is treated
206 * as an array of uint16_t of size SIZE/2).
208 * Each bin represents a range of pc addresses from OFFSET. The number
209 * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps
210 * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
211 * a scale of 1 maps each bin to 128k addreses). Scale may be 1 - 65536,
212 * or zero to turn off profiling.
215 profile_ctl (struct profinfo
* p
, char *samples
, size_t size
,
216 size_t offset
, uint32_t scale
)
229 memset (samples
, 0, size
);
230 memset (p
, 0, sizeof *p
);
232 prof
.counter
= (uint16_t *) samples
;
234 prof
.highpc
= PROFADDR (maxbin
, offset
, scale
);
237 /* Set up callback to restart profiling in child after fork. */
238 pthread_atfork (NULL
, NULL
, profile_child
);
240 return profile_on (p
);
245 /* Equivalent to unix profil()
246 Every SLEEPTIME interval, the user's program counter (PC) is examined:
247 offset is subtracted and the result is multiplied by scale.
248 The word pointed to by this address is incremented. Buf is unused. */
251 profil (char *samples
, size_t size
, size_t offset
, uint32_t scale
)
253 return profile_ctl (&prof
, samples
, size
, offset
, scale
);