~mingw-w64/mingw-w64/experimental

« back to all changes in this revision

Viewing changes to ros-privexp/mingw-w64-crt/profile/profil.c

  • Committer: NightStrike
  • Date: 2010-08-11 22:20:57 UTC
  • Revision ID: svn-v4:4407c894-4637-0410-b4f5-ada5f102cad1:experimental:3266
Branch for adding option for supporting ros

Show diffs side-by-side

added added

removed removed

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