-
Notifications
You must be signed in to change notification settings - Fork 253
/
Copy pathprofil.cpp
159 lines (136 loc) · 4.04 KB
/
profil.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* Low-level statistical profiling support function. Mostly POSIX.1 version.
Copyright (C) 1996-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef __circle__
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <stdint.h>
#include <libc-internal.h>
#include <sigsetops.h>
#else
#include <profile/glibc_compat.h>
#include <circle/exceptionstub.h>
#include <circle/timer.h>
#include <stdint.h>
#endif
//#ifndef SIGPROF
#ifndef __circle__
#include <gmon/profil.c>
#else
static u_short *samples;
static size_t nsamples;
static size_t pc_offset;
static u_int pc_scale;
static inline void
profil_count (uintptr_t pc)
{
size_t i = (pc - pc_offset) / 2;
if (sizeof (unsigned long long int) > sizeof (size_t))
i = (unsigned long long int) i * pc_scale / 65536;
else
i = i / 65536 * pc_scale + i % 65536 * pc_scale / 65536;
if (i < nsamples)
++samples[i];
}
/* Get the machine-dependent definition of `__profil_counter', the signal
handler for SIGPROF. It calls `profil_count' (above) with the PC of the
interrupted code. */
#ifndef __circle__
#include "profil-counter.h"
#else
void __profil_counter (void)
{
if (samples != NULL)
profil_count (IRQReturnAddress);
}
#endif
/* Enable statistical profiling, writing samples of the PC into at most
SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling
is enabled, the system examines the user PC and increments
SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536]. If SCALE is zero,
disable profiling. Returns zero on success, -1 on error. */
int
__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
{
#ifndef __circle__
struct sigaction act;
struct itimerval timer;
#if !IS_IN (rtld)
static struct sigaction oact;
static struct itimerval otimer;
# define oact_ptr &oact
# define otimer_ptr &otimer
if (sample_buffer == NULL)
{
/* Disable profiling. */
if (samples == NULL)
/* Wasn't turned on. */
return 0;
if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0)
return -1;
samples = NULL;
return __sigaction (SIGPROF, &oact, NULL);
}
if (samples)
{
/* Was already turned on. Restore old timer and signal handler
first. */
if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0
|| __sigaction (SIGPROF, &oact, NULL) < 0)
return -1;
}
#else
/* In ld.so profiling should never be disabled once it runs. */
//assert (sample_buffer != NULL);
# define oact_ptr NULL
# define otimer_ptr NULL
#endif
#else
if (sample_buffer == NULL)
{
/* Disable profiling. */
samples = NULL;
return 0;
}
#endif
samples = sample_buffer;
nsamples = size / sizeof *samples;
pc_offset = offset;
pc_scale = scale;
#ifndef __circle__
#ifdef SA_SIGINFO
act.sa_sigaction = __profil_counter;
act.sa_flags = SA_SIGINFO;
#else
act.sa_handler = __profil_counter;
act.sa_flags = 0;
#endif
act.sa_flags |= SA_RESTART;
__sigfillset (&act.sa_mask);
if (__sigaction (SIGPROF, &act, oact_ptr) < 0)
return -1;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 1000000 / __profile_frequency ();
timer.it_interval = timer.it_value;
return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
#else
CTimer::Get ()->RegisterPeriodicHandler (__profil_counter);
return 0;
#endif
}
weak_alias (__profil, profil)
#endif