1 : // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : /*
6 : # vim: sw=2
7 : */
8 : #include <stdio.h>
9 :
10 : #include <pthread.h>
11 : #include <semaphore.h>
12 : #include <signal.h>
13 : #include <sys/time.h>
14 : #include <sys/resource.h>
15 : #include <sys/syscall.h>
16 : #include <sys/types.h>
17 : #include <stdlib.h>
18 : #ifdef ANDROID
19 : #include <android/log.h>
20 : #else
21 : #define __android_log_print(a, ...)
22 : #endif
23 : // Ubuntu Dapper requires memory pages to be marked as
24 : // executable. Otherwise, OS raises an exception when executing code
25 : // in that page.
26 : #include <sys/types.h> // mmap & munmap
27 : #include <sys/mman.h> // mmap & munmap
28 : #include <sys/stat.h> // open
29 : #include <fcntl.h> // open
30 : #include <unistd.h> // sysconf
31 : #ifdef __GLIBC__
32 : #include <execinfo.h> // backtrace, backtrace_symbols
33 : #endif // def __GLIBC__
34 : #include <strings.h> // index
35 : #include <errno.h>
36 : #include <stdarg.h>
37 : #include "platform.h"
38 :
39 : #include <string.h>
40 : #include <stdio.h>
41 :
42 : #define SIGNAL_SAVE_PROFILE SIGUSR2
43 :
44 : #if defined(__GLIBC__)
45 : // glibc doesn't implement gettid(2).
46 : #include <sys/syscall.h>
47 0 : pid_t gettid()
48 : {
49 0 : return (pid_t) syscall(SYS_gettid);
50 : }
51 : #endif
52 :
53 : static Sampler* sActiveSampler = NULL;
54 :
55 :
56 : #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
57 : // Android runs a fairly new Linux kernel, so signal info is there,
58 : // but the C library doesn't have the structs defined.
59 :
60 : struct sigcontext {
61 : uint32_t trap_no;
62 : uint32_t error_code;
63 : uint32_t oldmask;
64 : uint32_t gregs[16];
65 : uint32_t arm_cpsr;
66 : uint32_t fault_address;
67 : };
68 : typedef uint32_t __sigset_t;
69 : typedef struct sigcontext mcontext_t;
70 : typedef struct ucontext {
71 : uint32_t uc_flags;
72 : struct ucontext* uc_link;
73 : stack_t uc_stack;
74 : mcontext_t uc_mcontext;
75 : __sigset_t uc_sigmask;
76 : } ucontext_t;
77 : enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
78 :
79 : #endif
80 :
81 0 : static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context) {
82 0 : sActiveSampler->RequestSave();
83 0 : }
84 :
85 : #ifdef ANDROID
86 : #define V8_HOST_ARCH_ARM 1
87 : #define SYS_gettid __NR_gettid
88 : #define SYS_tgkill __NR_tgkill
89 : #else
90 : #define V8_HOST_ARCH_X64 1
91 : #endif
92 0 : static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
93 0 : if (!sActiveSampler)
94 0 : return;
95 :
96 0 : TickSample sample_obj;
97 0 : TickSample* sample = &sample_obj;
98 0 : sample->pc = 0;
99 :
100 : #ifdef ENABLE_SPS_LEAF_DATA
101 : // If profiling, we extract the current pc and sp.
102 : if (sActiveSampler->IsProfiling()) {
103 : // Extracting the sample from the context is extremely machine dependent.
104 : ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
105 : mcontext_t& mcontext = ucontext->uc_mcontext;
106 : #if V8_HOST_ARCH_IA32
107 : sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
108 : sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
109 : sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
110 : #elif V8_HOST_ARCH_X64
111 : sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
112 : sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
113 : sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
114 : #elif V8_HOST_ARCH_ARM
115 : // An undefined macro evaluates to 0, so this applies to Android's Bionic also.
116 : #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
117 : sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
118 : sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
119 : sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
120 : #else
121 : sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
122 : sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
123 : sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
124 : #endif
125 : #elif V8_HOST_ARCH_MIPS
126 : // Implement this on MIPS.
127 : UNIMPLEMENTED();
128 : #endif
129 : }
130 : #endif
131 0 : sample->timestamp = mozilla::TimeStamp::Now();
132 :
133 0 : sActiveSampler->Tick(sample);
134 : }
135 :
136 : #ifndef XP_MACOSX
137 0 : void tgkill(pid_t tgid, pid_t tid, int signalno) {
138 0 : syscall(SYS_tgkill, tgid, tid, signalno);
139 0 : }
140 : #endif
141 :
142 : class Sampler::PlatformData : public Malloced {
143 : public:
144 0 : explicit PlatformData(Sampler* sampler)
145 : : sampler_(sampler),
146 : signal_handler_installed_(false),
147 0 : vm_tgid_(getpid()),
148 : #ifndef XP_MACOSX
149 0 : vm_tid_(gettid()),
150 : #endif
151 0 : signal_sender_launched_(false)
152 : #ifdef XP_MACOSX
153 : , signal_receiver_(pthread_self())
154 : #endif
155 : {
156 0 : }
157 :
158 0 : void SignalSender() {
159 0 : while (sampler_->IsActive()) {
160 0 : sampler_->HandleSaveRequest();
161 :
162 : #ifdef XP_MACOSX
163 : pthread_kill(signal_receiver_, SIGPROF);
164 : #else
165 : // Glibc doesn't provide a wrapper for tgkill(2).
166 0 : tgkill(vm_tgid_, vm_tid_, SIGPROF);
167 : #endif
168 : // Convert ms to us and subtract 100 us to compensate delays
169 : // occuring during signal delivery.
170 :
171 : // TODO measure and confirm this.
172 0 : const useconds_t interval = sampler_->interval_ * 1000 - 100;
173 : //int result = usleep(interval);
174 0 : usleep(interval);
175 : // sometimes usleep is defined as returning void
176 0 : int result = 0;
177 : #ifdef DEBUG
178 0 : if (result != 0 && errno != EINTR) {
179 0 : LOG("SignalSender usleep error");
180 0 : ASSERT(result == 0 || errno == EINTR);
181 : }
182 : #endif
183 0 : mozilla::unused << result;
184 : }
185 0 : }
186 :
187 : Sampler* sampler_;
188 : bool signal_handler_installed_;
189 : struct sigaction old_sigprof_signal_handler_;
190 : struct sigaction old_sigsave_signal_handler_;
191 : pid_t vm_tgid_;
192 : pid_t vm_tid_;
193 : bool signal_sender_launched_;
194 : pthread_t signal_sender_thread_;
195 : #ifdef XP_MACOSX
196 : pthread_t signal_receiver_;
197 : #endif
198 : };
199 :
200 :
201 0 : static void* SenderEntry(void* arg) {
202 : Sampler::PlatformData* data =
203 0 : reinterpret_cast<Sampler::PlatformData*>(arg);
204 0 : data->SignalSender();
205 0 : return 0;
206 : }
207 :
208 :
209 0 : Sampler::Sampler(int interval, bool profiling)
210 : : interval_(interval),
211 : profiling_(profiling),
212 0 : active_(false) {
213 0 : data_ = new PlatformData(this);
214 0 : }
215 :
216 0 : Sampler::~Sampler() {
217 0 : ASSERT(!data_->signal_sender_launched_);
218 0 : delete data_;
219 0 : }
220 :
221 :
222 0 : void Sampler::Start() {
223 0 : LOG("Sampler Started");
224 0 : if (sActiveSampler != NULL) return;
225 :
226 : // Request profiling signals.
227 0 : LOG("Request signal");
228 : struct sigaction sa;
229 0 : sa.sa_sigaction = ProfilerSignalHandler;
230 0 : sigemptyset(&sa.sa_mask);
231 0 : sa.sa_flags = SA_RESTART | SA_SIGINFO;
232 0 : if (sigaction(SIGPROF, &sa, &data_->old_sigprof_signal_handler_) != 0) {
233 0 : LOG("Error installing signal");
234 0 : return;
235 : }
236 :
237 : // Request save profile signals
238 : struct sigaction sa2;
239 0 : sa2.sa_sigaction = ProfilerSaveSignalHandler;
240 0 : sigemptyset(&sa2.sa_mask);
241 0 : sa2.sa_flags = SA_RESTART | SA_SIGINFO;
242 0 : if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &data_->old_sigsave_signal_handler_) != 0) {
243 0 : LOG("Error installing start signal");
244 0 : return;
245 : }
246 0 : LOG("Signal installed");
247 0 : data_->signal_handler_installed_ = true;
248 :
249 : // Start a thread that sends SIGPROF signal to VM thread.
250 : // Sending the signal ourselves instead of relying on itimer provides
251 : // much better accuracy.
252 0 : SetActive(true);
253 0 : if (pthread_create(
254 0 : &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
255 0 : data_->signal_sender_launched_ = true;
256 : }
257 0 : LOG("Profiler thread started");
258 :
259 : // Set this sampler as the active sampler.
260 0 : sActiveSampler = this;
261 : }
262 :
263 :
264 0 : void Sampler::Stop() {
265 0 : SetActive(false);
266 :
267 : // Wait for signal sender termination (it will exit after setting
268 : // active_ to false).
269 0 : if (data_->signal_sender_launched_) {
270 0 : pthread_join(data_->signal_sender_thread_, NULL);
271 0 : data_->signal_sender_launched_ = false;
272 : }
273 :
274 : // Restore old signal handler
275 0 : if (data_->signal_handler_installed_) {
276 0 : sigaction(SIGPROF, &data_->old_sigsave_signal_handler_, 0);
277 0 : sigaction(SIGPROF, &data_->old_sigprof_signal_handler_, 0);
278 0 : data_->signal_handler_installed_ = false;
279 : }
280 :
281 : // This sampler is no longer the active sampler.
282 0 : sActiveSampler = NULL;
283 0 : }
284 :
|