OSDN Git Service

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