Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / profil.c
blob30b37244afcd70cf88d3c00ab12be21558694178
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
7 details. */
9 /*
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
16 #endif
17 #include <windows.h>
18 #include <stdio.h>
19 #include <sys/cygwin.h>
20 #include <sys/types.h>
21 #include <errno.h>
22 #include <pthread.h>
23 #include "profil.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 */
32 static size_t
33 get_thrpc (HANDLE thr)
35 CONTEXT ctx;
36 size_t pc;
37 int res;
39 res = SuspendThread (thr);
40 if (res == -1)
41 return (size_t) - 1;
42 ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
43 pc = (size_t) - 1;
44 if (GetThreadContext (thr, &ctx)) {
45 #ifdef __x86_64__
46 pc = ctx.Rip;
47 #else
48 #error unimplemented for this target
49 #endif
51 ResumeThread (thr);
52 return pc;
55 /* Display cell of profile buffer */
56 #if 0
57 static void
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);
63 return;
65 #endif
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. */
70 static void
71 profthr_byhandle (HANDLE thr)
73 size_t pc;
75 /* Sample the pc of the thread indicated by thr; bail if anything amiss. */
76 if (thr == INVALID_HANDLE_VALUE)
77 return;
78 pc = get_thrpc (thr);
79 if (pc == -1)
80 return;
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);
86 prof.counter[idx]++;
90 static void CALLBACK
91 profthr_func (LPVOID arg)
93 struct profinfo *p = (struct profinfo *) arg;
95 for (;;)
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);
103 #if 0
104 print_prof (p);
105 #endif
106 /* Check quit condition, WAIT_OBJECT_0 or WAIT_TIMEOUT */
107 if (WaitForSingleObject (p->quitevt, SLEEPTIME) == WAIT_OBJECT_0)
108 return;
112 /* Stop profiling to the profiling buffer pointed to by P. */
114 static int
115 profile_off (struct profinfo *p)
117 if (p->profthr)
119 SignalObjectAndWait (p->quitevt, p->profthr, INFINITE, FALSE);
120 CloseHandle (p->quitevt);
121 CloseHandle (p->profthr);
123 if (p->targthr)
124 CloseHandle (p->targthr);
125 p->targthr = 0;
126 return 0;
129 /* Create a timer thread and pass it a pointer P to the profiling buffer. */
131 static int
132 profile_on (struct profinfo *p)
134 DWORD thrid;
136 /* get handle for this thread */
137 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
138 GetCurrentProcess (), &p->targthr, 0, FALSE,
139 DUPLICATE_SAME_ACCESS))
141 p->targthr = 0;
142 errno = ESRCH;
143 return -1;
146 p->quitevt = CreateEvent (NULL, TRUE, FALSE, NULL);
148 if (!p->quitevt)
150 CloseHandle (p->targthr);
151 p->targthr = 0;
152 errno = EAGAIN;
153 return -1;
156 p->profthr = CreateThread (0, 0, (DWORD (*)(LPVOID)) profthr_func,
157 (void *) p, 0, &thrid);
159 if (!p->profthr)
161 CloseHandle (p->targthr);
162 CloseHandle (p->quitevt);
163 p->targthr = 0;
164 errno = EAGAIN;
165 return -1;
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);
174 return 0;
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.
187 static void
188 profile_child (void)
190 /* Bail if this was a fork after profiling turned off or was never on. */
191 if (!prof.targthr)
192 return;
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. */
199 profile_on (&prof);
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)
218 size_t maxbin;
220 if (scale > 65536)
222 errno = EINVAL;
223 return -1;
226 profile_off (p);
227 if (scale)
229 memset (samples, 0, size);
230 memset (p, 0, sizeof *p);
231 maxbin = size >> 1;
232 prof.counter = (uint16_t *) samples;
233 prof.lowpc = offset;
234 prof.highpc = PROFADDR (maxbin, offset, scale);
235 prof.scale = scale;
237 /* Set up callback to restart profiling in child after fork. */
238 pthread_atfork (NULL, NULL, profile_child);
240 return profile_on (p);
242 return 0;
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);