blob: 760df807088d1eb6223056c53c3c5d13bc2c4474 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project 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#include "src/sampler.h"
6
7#if V8_OS_POSIX && !V8_OS_CYGWIN
8
9#define USE_SIGNALS
10
11#include <errno.h>
12#include <pthread.h>
13#include <signal.h>
14#include <sys/time.h>
15
16#if !V8_OS_QNX && !V8_OS_NACL
17#include <sys/syscall.h> // NOLINT
18#endif
19
20#if V8_OS_MACOSX
21#include <mach/mach.h>
22// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
23// and is a typedef for struct sigcontext. There is no uc_mcontext.
24#elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \
25 !V8_OS_OPENBSD && !V8_OS_NACL
26#include <ucontext.h>
27#endif
28
29#include <unistd.h>
30
31// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
32// Old versions of the C library <signal.h> didn't define the type.
33#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
34 (defined(__arm__) || defined(__aarch64__)) && \
35 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
36#include <asm/sigcontext.h> // NOLINT
37#endif
38
39#elif V8_OS_WIN || V8_OS_CYGWIN
40
41#include "src/base/win32-headers.h"
42
43#endif
44
45#include "src/v8.h"
46
47#include "src/base/platform/platform.h"
48#include "src/cpu-profiler-inl.h"
49#include "src/flags.h"
50#include "src/frames-inl.h"
51#include "src/log.h"
52#include "src/simulator.h"
53#include "src/v8threads.h"
54#include "src/vm-state-inl.h"
55
56
57#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
58
59// Not all versions of Android's C library provide ucontext_t.
60// Detect this and provide custom but compatible definitions. Note that these
61// follow the GLibc naming convention to access register values from
62// mcontext_t.
63//
64// See http://code.google.com/p/android/issues/detail?id=34784
65
66#if defined(__arm__)
67
68typedef struct sigcontext mcontext_t;
69
70typedef struct ucontext {
71 uint32_t uc_flags;
72 struct ucontext* uc_link;
73 stack_t uc_stack;
74 mcontext_t uc_mcontext;
75 // Other fields are not used by V8, don't define them here.
76} ucontext_t;
77
78#elif defined(__aarch64__)
79
80typedef struct sigcontext mcontext_t;
81
82typedef struct ucontext {
83 uint64_t uc_flags;
84 struct ucontext *uc_link;
85 stack_t uc_stack;
86 mcontext_t uc_mcontext;
87 // Other fields are not used by V8, don't define them here.
88} ucontext_t;
89
90#elif defined(__mips__)
91// MIPS version of sigcontext, for Android bionic.
92typedef struct {
93 uint32_t regmask;
94 uint32_t status;
95 uint64_t pc;
96 uint64_t gregs[32];
97 uint64_t fpregs[32];
98 uint32_t acx;
99 uint32_t fpc_csr;
100 uint32_t fpc_eir;
101 uint32_t used_math;
102 uint32_t dsp;
103 uint64_t mdhi;
104 uint64_t mdlo;
105 uint32_t hi1;
106 uint32_t lo1;
107 uint32_t hi2;
108 uint32_t lo2;
109 uint32_t hi3;
110 uint32_t lo3;
111} mcontext_t;
112
113typedef struct ucontext {
114 uint32_t uc_flags;
115 struct ucontext* uc_link;
116 stack_t uc_stack;
117 mcontext_t uc_mcontext;
118 // Other fields are not used by V8, don't define them here.
119} ucontext_t;
120
121#elif defined(__i386__)
122// x86 version for Android.
123typedef struct {
124 uint32_t gregs[19];
125 void* fpregs;
126 uint32_t oldmask;
127 uint32_t cr2;
128} mcontext_t;
129
130typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
131typedef struct ucontext {
132 uint32_t uc_flags;
133 struct ucontext* uc_link;
134 stack_t uc_stack;
135 mcontext_t uc_mcontext;
136 // Other fields are not used by V8, don't define them here.
137} ucontext_t;
138enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
139
140#elif defined(__x86_64__)
141// x64 version for Android.
142typedef struct {
143 uint64_t gregs[23];
144 void* fpregs;
145 uint64_t __reserved1[8];
146} mcontext_t;
147
148typedef struct ucontext {
149 uint64_t uc_flags;
150 struct ucontext *uc_link;
151 stack_t uc_stack;
152 mcontext_t uc_mcontext;
153 // Other fields are not used by V8, don't define them here.
154} ucontext_t;
155enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
156#endif
157
158#endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
159
160
161namespace v8 {
162namespace internal {
163
164namespace {
165
166class PlatformDataCommon : public Malloced {
167 public:
168 PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
169 ThreadId profiled_thread_id() { return profiled_thread_id_; }
170
171 protected:
172 ~PlatformDataCommon() {}
173
174 private:
175 ThreadId profiled_thread_id_;
176};
177
178} // namespace
179
180#if defined(USE_SIGNALS)
181
182class Sampler::PlatformData : public PlatformDataCommon {
183 public:
184 PlatformData() : vm_tid_(pthread_self()) {}
185 pthread_t vm_tid() const { return vm_tid_; }
186
187 private:
188 pthread_t vm_tid_;
189};
190
191#elif V8_OS_WIN || V8_OS_CYGWIN
192
193// ----------------------------------------------------------------------------
194// Win32 profiler support. On Cygwin we use the same sampler implementation as
195// on Win32.
196
197class Sampler::PlatformData : public PlatformDataCommon {
198 public:
199 // Get a handle to the calling thread. This is the thread that we are
200 // going to profile. We need to make a copy of the handle because we are
201 // going to use it in the sampler thread. Using GetThreadHandle() will
202 // not work in this case. We're using OpenThread because DuplicateHandle
203 // for some reason doesn't work in Chrome's sandbox.
204 PlatformData()
205 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
206 THREAD_SUSPEND_RESUME |
207 THREAD_QUERY_INFORMATION,
208 false,
209 GetCurrentThreadId())) {}
210
211 ~PlatformData() {
212 if (profiled_thread_ != NULL) {
213 CloseHandle(profiled_thread_);
214 profiled_thread_ = NULL;
215 }
216 }
217
218 HANDLE profiled_thread() { return profiled_thread_; }
219
220 private:
221 HANDLE profiled_thread_;
222};
223#endif
224
225
226#if defined(USE_SIMULATOR)
227class SimulatorHelper {
228 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229 inline bool Init(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 simulator_ = isolate->thread_local_top()->simulator_;
231 // Check if there is active simulator.
232 return simulator_ != NULL;
233 }
234
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235 inline void FillRegisters(v8::RegisterState* state) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236#if V8_TARGET_ARCH_ARM
237 state->pc = reinterpret_cast<Address>(simulator_->get_pc());
238 state->sp = reinterpret_cast<Address>(simulator_->get_register(
239 Simulator::sp));
240 state->fp = reinterpret_cast<Address>(simulator_->get_register(
241 Simulator::r11));
242#elif V8_TARGET_ARCH_ARM64
243 if (simulator_->sp() == 0 || simulator_->fp() == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400244 // It's possible that the simulator is interrupted while it is updating
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 // the sp or fp register. ARM64 simulator does this in two steps:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 // first setting it to zero and then setting it to a new value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 // Bailout if sp/fp doesn't contain the new value.
248 return;
249 }
250 state->pc = reinterpret_cast<Address>(simulator_->pc());
251 state->sp = reinterpret_cast<Address>(simulator_->sp());
252 state->fp = reinterpret_cast<Address>(simulator_->fp());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254 state->pc = reinterpret_cast<Address>(simulator_->get_pc());
255 state->sp = reinterpret_cast<Address>(simulator_->get_register(
256 Simulator::sp));
257 state->fp = reinterpret_cast<Address>(simulator_->get_register(
258 Simulator::fp));
259#endif
260 }
261
262 private:
263 Simulator* simulator_;
264};
265#endif // USE_SIMULATOR
266
267
268#if defined(USE_SIGNALS)
269
270class SignalHandler : public AllStatic {
271 public:
272 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
273 static void TearDown() { delete mutex_; mutex_ = NULL; }
274
275 static void IncreaseSamplerCount() {
276 base::LockGuard<base::Mutex> lock_guard(mutex_);
277 if (++client_count_ == 1) Install();
278 }
279
280 static void DecreaseSamplerCount() {
281 base::LockGuard<base::Mutex> lock_guard(mutex_);
282 if (--client_count_ == 0) Restore();
283 }
284
285 static bool Installed() {
286 return signal_handler_installed_;
287 }
288
289 private:
290 static void Install() {
291#if !V8_OS_NACL
292 struct sigaction sa;
293 sa.sa_sigaction = &HandleProfilerSignal;
294 sigemptyset(&sa.sa_mask);
295#if V8_OS_QNX
296 sa.sa_flags = SA_SIGINFO;
297#else
298 sa.sa_flags = SA_RESTART | SA_SIGINFO;
299#endif
300 signal_handler_installed_ =
301 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
302#endif
303 }
304
305 static void Restore() {
306#if !V8_OS_NACL
307 if (signal_handler_installed_) {
308 sigaction(SIGPROF, &old_signal_handler_, 0);
309 signal_handler_installed_ = false;
310 }
311#endif
312 }
313
314#if !V8_OS_NACL
315 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
316#endif
317 // Protects the process wide state below.
318 static base::Mutex* mutex_;
319 static int client_count_;
320 static bool signal_handler_installed_;
321 static struct sigaction old_signal_handler_;
322};
323
324
325base::Mutex* SignalHandler::mutex_ = NULL;
326int SignalHandler::client_count_ = 0;
327struct sigaction SignalHandler::old_signal_handler_;
328bool SignalHandler::signal_handler_installed_ = false;
329
330
331// As Native Client does not support signal handling, profiling is disabled.
332#if !V8_OS_NACL
333void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
334 void* context) {
335 USE(info);
336 if (signal != SIGPROF) return;
337 Isolate* isolate = Isolate::UnsafeCurrent();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338 if (isolate == NULL || !isolate->IsInUse()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 // We require a fully initialized and entered isolate.
340 return;
341 }
342 if (v8::Locker::IsActive() &&
343 !isolate->thread_manager()->IsLockedByCurrentThread()) {
344 return;
345 }
346
347 Sampler* sampler = isolate->logger()->sampler();
348 if (sampler == NULL) return;
349
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350 v8::RegisterState state;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000351
352#if defined(USE_SIMULATOR)
353 SimulatorHelper helper;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400354 if (!helper.Init(isolate)) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000355 helper.FillRegisters(&state);
356 // It possible that the simulator is interrupted while it is updating
357 // the sp or fp register. ARM64 simulator does this in two steps:
358 // first setting it to zero and then setting it to the new value.
359 // Bailout if sp/fp doesn't contain the new value.
360 if (state.sp == 0 || state.fp == 0) return;
361#else
362 // Extracting the sample from the context is extremely machine dependent.
363 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
364#if !V8_OS_OPENBSD
365 mcontext_t& mcontext = ucontext->uc_mcontext;
366#endif
367#if V8_OS_LINUX
368#if V8_HOST_ARCH_IA32
369 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
370 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
371 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
372#elif V8_HOST_ARCH_X64
373 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
374 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
375 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
376#elif V8_HOST_ARCH_ARM
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400377#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000378 // Old GLibc ARM versions used a gregs[] array to access the register
379 // values from mcontext_t.
380 state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
381 state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
382 state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
383#else
384 state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
385 state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
386 state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400387#endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388#elif V8_HOST_ARCH_ARM64
389 state.pc = reinterpret_cast<Address>(mcontext.pc);
390 state.sp = reinterpret_cast<Address>(mcontext.sp);
391 // FP is an alias for x29.
392 state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
393#elif V8_HOST_ARCH_MIPS
394 state.pc = reinterpret_cast<Address>(mcontext.pc);
395 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
396 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
397#elif V8_HOST_ARCH_MIPS64
398 state.pc = reinterpret_cast<Address>(mcontext.pc);
399 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
400 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
401#endif // V8_HOST_ARCH_*
402#elif V8_OS_MACOSX
403#if V8_HOST_ARCH_X64
404#if __DARWIN_UNIX03
405 state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
406 state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
407 state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
408#else // !__DARWIN_UNIX03
409 state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
410 state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
411 state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
412#endif // __DARWIN_UNIX03
413#elif V8_HOST_ARCH_IA32
414#if __DARWIN_UNIX03
415 state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
416 state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
417 state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
418#else // !__DARWIN_UNIX03
419 state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
420 state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
421 state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
422#endif // __DARWIN_UNIX03
423#endif // V8_HOST_ARCH_IA32
424#elif V8_OS_FREEBSD
425#if V8_HOST_ARCH_IA32
426 state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
427 state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
428 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
429#elif V8_HOST_ARCH_X64
430 state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
431 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
432 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
433#elif V8_HOST_ARCH_ARM
434 state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
435 state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
436 state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
437#endif // V8_HOST_ARCH_*
438#elif V8_OS_NETBSD
439#if V8_HOST_ARCH_IA32
440 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
441 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
442 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
443#elif V8_HOST_ARCH_X64
444 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
445 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
446 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
447#endif // V8_HOST_ARCH_*
448#elif V8_OS_OPENBSD
449#if V8_HOST_ARCH_IA32
450 state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
451 state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
452 state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
453#elif V8_HOST_ARCH_X64
454 state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
455 state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
456 state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
457#endif // V8_HOST_ARCH_*
458#elif V8_OS_SOLARIS
459 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
460 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
461 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
462#elif V8_OS_QNX
463#if V8_HOST_ARCH_IA32
464 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
465 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
466 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
467#elif V8_HOST_ARCH_ARM
468 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
469 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
470 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
471#endif // V8_HOST_ARCH_*
472#endif // V8_OS_QNX
473#endif // USE_SIMULATOR
474 sampler->SampleStack(state);
475}
476#endif // V8_OS_NACL
477
478#endif
479
480
481class SamplerThread : public base::Thread {
482 public:
483 static const int kSamplerThreadStackSize = 64 * KB;
484
485 explicit SamplerThread(int interval)
486 : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
487 interval_(interval) {}
488
489 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
490 static void TearDown() { delete mutex_; mutex_ = NULL; }
491
492 static void AddActiveSampler(Sampler* sampler) {
493 bool need_to_start = false;
494 base::LockGuard<base::Mutex> lock_guard(mutex_);
495 if (instance_ == NULL) {
496 // Start a thread that will send SIGPROF signal to VM threads,
497 // when CPU profiling will be enabled.
498 instance_ = new SamplerThread(sampler->interval());
499 need_to_start = true;
500 }
501
502 DCHECK(sampler->IsActive());
503 DCHECK(!instance_->active_samplers_.Contains(sampler));
504 DCHECK(instance_->interval_ == sampler->interval());
505 instance_->active_samplers_.Add(sampler);
506
507 if (need_to_start) instance_->StartSynchronously();
508 }
509
510 static void RemoveActiveSampler(Sampler* sampler) {
511 SamplerThread* instance_to_remove = NULL;
512 {
513 base::LockGuard<base::Mutex> lock_guard(mutex_);
514
515 DCHECK(sampler->IsActive());
516 bool removed = instance_->active_samplers_.RemoveElement(sampler);
517 DCHECK(removed);
518 USE(removed);
519
520 // We cannot delete the instance immediately as we need to Join() the
521 // thread but we are holding mutex_ and the thread may try to acquire it.
522 if (instance_->active_samplers_.is_empty()) {
523 instance_to_remove = instance_;
524 instance_ = NULL;
525 }
526 }
527
528 if (!instance_to_remove) return;
529 instance_to_remove->Join();
530 delete instance_to_remove;
531 }
532
533 // Implement Thread::Run().
534 virtual void Run() {
535 while (true) {
536 {
537 base::LockGuard<base::Mutex> lock_guard(mutex_);
538 if (active_samplers_.is_empty()) break;
539 // When CPU profiling is enabled both JavaScript and C++ code is
540 // profiled. We must not suspend.
541 for (int i = 0; i < active_samplers_.length(); ++i) {
542 Sampler* sampler = active_samplers_.at(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 if (!sampler->IsProfiling()) continue;
544 sampler->DoSample();
545 }
546 }
547 base::OS::Sleep(interval_);
548 }
549 }
550
551 private:
552 // Protects the process wide state below.
553 static base::Mutex* mutex_;
554 static SamplerThread* instance_;
555
556 const int interval_;
557 List<Sampler*> active_samplers_;
558
559 DISALLOW_COPY_AND_ASSIGN(SamplerThread);
560};
561
562
563base::Mutex* SamplerThread::mutex_ = NULL;
564SamplerThread* SamplerThread::instance_ = NULL;
565
566
567//
568// StackTracer implementation
569//
570DISABLE_ASAN void TickSample::Init(Isolate* isolate,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571 const v8::RegisterState& regs,
572 RecordCEntryFrame record_c_entry_frame) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 timestamp = base::TimeTicks::HighResolutionNow();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400574 pc = reinterpret_cast<Address>(regs.pc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 state = isolate->current_vm_state();
576
577 // Avoid collecting traces while doing GC.
578 if (state == GC) return;
579
580 Address js_entry_sp = isolate->js_entry_sp();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400581 if (js_entry_sp == 0) return; // Not executing JS now.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582
583 ExternalCallbackScope* scope = isolate->external_callback_scope();
584 Address handler = Isolate::handler(isolate->thread_local_top());
585 // If there is a handler on top of the external callback scope then
586 // we have already entrered JavaScript again and the external callback
587 // is not the top function.
588 if (scope && scope->scope_address() < handler) {
589 external_callback = scope->callback();
590 has_external_callback = true;
591 } else {
592 // Sample potential return address value for frameless invocation of
593 // stubs (we'll figure out later, if this value makes sense).
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400594 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 has_external_callback = false;
596 }
597
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400598 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
599 reinterpret_cast<Address>(regs.sp), js_entry_sp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 top_frame_type = it.top_frame_type();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400601
602 SampleInfo info;
603 GetStackSample(isolate, regs, record_c_entry_frame,
604 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
605 frames_count = static_cast<unsigned>(info.frames_count);
606}
607
608
609void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
610 RecordCEntryFrame record_c_entry_frame,
611 void** frames, size_t frames_limit,
612 v8::SampleInfo* sample_info) {
613 sample_info->frames_count = 0;
614 sample_info->vm_state = isolate->current_vm_state();
615 if (sample_info->vm_state == GC) return;
616
617 Address js_entry_sp = isolate->js_entry_sp();
618 if (js_entry_sp == 0) return; // Not executing JS now.
619
620 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
621 reinterpret_cast<Address>(regs.sp), js_entry_sp);
622 size_t i = 0;
623 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
624 it.top_frame_type() == StackFrame::EXIT) {
625 frames[i++] = isolate->c_function();
626 }
627 while (!it.done() && i < frames_limit) {
628 frames[i++] = it.frame()->pc();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 it.Advance();
630 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400631 sample_info->frames_count = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632}
633
634
635void Sampler::SetUp() {
636#if defined(USE_SIGNALS)
637 SignalHandler::SetUp();
638#endif
639 SamplerThread::SetUp();
640}
641
642
643void Sampler::TearDown() {
644 SamplerThread::TearDown();
645#if defined(USE_SIGNALS)
646 SignalHandler::TearDown();
647#endif
648}
649
650
651Sampler::Sampler(Isolate* isolate, int interval)
652 : isolate_(isolate),
653 interval_(interval),
654 profiling_(false),
655 has_processing_thread_(false),
656 active_(false),
657 is_counting_samples_(false),
658 js_and_external_sample_count_(0) {
659 data_ = new PlatformData;
660}
661
662
663Sampler::~Sampler() {
664 DCHECK(!IsActive());
665 delete data_;
666}
667
668
669void Sampler::Start() {
670 DCHECK(!IsActive());
671 SetActive(true);
672 SamplerThread::AddActiveSampler(this);
673}
674
675
676void Sampler::Stop() {
677 DCHECK(IsActive());
678 SamplerThread::RemoveActiveSampler(this);
679 SetActive(false);
680}
681
682
683void Sampler::IncreaseProfilingDepth() {
684 base::NoBarrier_AtomicIncrement(&profiling_, 1);
685#if defined(USE_SIGNALS)
686 SignalHandler::IncreaseSamplerCount();
687#endif
688}
689
690
691void Sampler::DecreaseProfilingDepth() {
692#if defined(USE_SIGNALS)
693 SignalHandler::DecreaseSamplerCount();
694#endif
695 base::NoBarrier_AtomicIncrement(&profiling_, -1);
696}
697
698
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400699void Sampler::SampleStack(const v8::RegisterState& state) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700 TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
701 TickSample sample_obj;
702 if (sample == NULL) sample = &sample_obj;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400703 sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000704 if (is_counting_samples_) {
705 if (sample->state == JS || sample->state == EXTERNAL) {
706 ++js_and_external_sample_count_;
707 }
708 }
709 Tick(sample);
710 if (sample != &sample_obj) {
711 isolate_->cpu_profiler()->FinishTickSample();
712 }
713}
714
715
716#if defined(USE_SIGNALS)
717
718void Sampler::DoSample() {
719 if (!SignalHandler::Installed()) return;
720 pthread_kill(platform_data()->vm_tid(), SIGPROF);
721}
722
723#elif V8_OS_WIN || V8_OS_CYGWIN
724
725void Sampler::DoSample() {
726 HANDLE profiled_thread = platform_data()->profiled_thread();
727 if (profiled_thread == NULL) return;
728
729#if defined(USE_SIMULATOR)
730 SimulatorHelper helper;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731 if (!helper.Init(isolate())) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732#endif
733
734 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
735 if (SuspendThread(profiled_thread) == kSuspendFailed) return;
736
737 // Context used for sampling the register state of the profiled thread.
738 CONTEXT context;
739 memset(&context, 0, sizeof(context));
740 context.ContextFlags = CONTEXT_FULL;
741 if (GetThreadContext(profiled_thread, &context) != 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400742 v8::RegisterState state;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743#if defined(USE_SIMULATOR)
744 helper.FillRegisters(&state);
745#else
746#if V8_HOST_ARCH_X64
747 state.pc = reinterpret_cast<Address>(context.Rip);
748 state.sp = reinterpret_cast<Address>(context.Rsp);
749 state.fp = reinterpret_cast<Address>(context.Rbp);
750#else
751 state.pc = reinterpret_cast<Address>(context.Eip);
752 state.sp = reinterpret_cast<Address>(context.Esp);
753 state.fp = reinterpret_cast<Address>(context.Ebp);
754#endif
755#endif // USE_SIMULATOR
756 SampleStack(state);
757 }
758 ResumeThread(profiled_thread);
759}
760
761#endif // USE_SIGNALS
762
763
764} } // namespace v8::internal