1 // 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.
5 #include "src/sampler.h"
7 #if V8_OS_POSIX && !V8_OS_CYGWIN
16 #if !V8_OS_QNX && !V8_OS_NACL
17 #include <sys/syscall.h> // NOLINT
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
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
39 #elif V8_OS_WIN || V8_OS_CYGWIN
41 #include "src/base/win32-headers.h"
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"
52 #include "src/simulator.h"
53 #include "src/v8threads.h"
54 #include "src/vm-state-inl.h"
57 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
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
64 // See http://code.google.com/p/android/issues/detail?id=34784
68 typedef struct sigcontext mcontext_t;
70 typedef struct ucontext {
72 struct ucontext* uc_link;
74 mcontext_t uc_mcontext;
75 // Other fields are not used by V8, don't define them here.
78 #elif defined(__aarch64__)
80 typedef struct sigcontext mcontext_t;
82 typedef struct ucontext {
84 struct ucontext *uc_link;
86 mcontext_t uc_mcontext;
87 // Other fields are not used by V8, don't define them here.
90 #elif defined(__mips__)
91 // MIPS version of sigcontext, for Android bionic.
113 typedef struct ucontext {
115 struct ucontext* uc_link;
117 mcontext_t uc_mcontext;
118 // Other fields are not used by V8, don't define them here.
121 #elif defined(__i386__)
122 // x86 version for Android.
130 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
131 typedef struct ucontext {
133 struct ucontext* uc_link;
135 mcontext_t uc_mcontext;
136 // Other fields are not used by V8, don't define them here.
138 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
140 #elif defined(__x86_64__)
141 // x64 version for Android.
145 uint64_t __reserved1[8];
148 typedef struct ucontext {
150 struct ucontext *uc_link;
152 mcontext_t uc_mcontext;
153 // Other fields are not used by V8, don't define them here.
155 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
158 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
166 class PlatformDataCommon : public Malloced {
168 PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
169 ThreadId profiled_thread_id() { return profiled_thread_id_; }
172 ~PlatformDataCommon() {}
175 ThreadId profiled_thread_id_;
180 #if defined(USE_SIGNALS)
182 class Sampler::PlatformData : public PlatformDataCommon {
184 PlatformData() : vm_tid_(pthread_self()) {}
185 pthread_t vm_tid() const { return vm_tid_; }
191 #elif V8_OS_WIN || V8_OS_CYGWIN
193 // ----------------------------------------------------------------------------
194 // Win32 profiler support. On Cygwin we use the same sampler implementation as
197 class Sampler::PlatformData : public PlatformDataCommon {
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.
205 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
206 THREAD_SUSPEND_RESUME |
207 THREAD_QUERY_INFORMATION,
209 GetCurrentThreadId())) {}
212 if (profiled_thread_ != NULL) {
213 CloseHandle(profiled_thread_);
214 profiled_thread_ = NULL;
218 HANDLE profiled_thread() { return profiled_thread_; }
221 HANDLE profiled_thread_;
226 #if defined(USE_SIMULATOR)
227 class SimulatorHelper {
229 inline bool Init(Sampler* sampler, Isolate* isolate) {
230 simulator_ = isolate->thread_local_top()->simulator_;
231 // Check if there is active simulator.
232 return simulator_ != NULL;
235 inline void FillRegisters(RegisterState* state) {
236 #if V8_TARGET_ARCH_ARM
237 state->pc = reinterpret_cast<Address>(simulator_->get_pc());
238 state->sp = reinterpret_cast<Address>(simulator_->get_register(
240 state->fp = reinterpret_cast<Address>(simulator_->get_register(
242 #elif V8_TARGET_ARCH_ARM64
243 if (simulator_->sp() == 0 || simulator_->fp() == 0) {
244 // It possible that the simulator is interrupted while it is updating
245 // the sp or fp register. ARM64 simulator does this in two steps:
246 // first setting it to zero and then setting it to the new value.
247 // Bailout if sp/fp doesn't contain the new value.
250 state->pc = reinterpret_cast<Address>(simulator_->pc());
251 state->sp = reinterpret_cast<Address>(simulator_->sp());
252 state->fp = reinterpret_cast<Address>(simulator_->fp());
253 #elif V8_TARGET_ARCH_MIPS
254 state->pc = reinterpret_cast<Address>(simulator_->get_pc());
255 state->sp = reinterpret_cast<Address>(simulator_->get_register(
257 state->fp = reinterpret_cast<Address>(simulator_->get_register(
259 #elif V8_TARGET_ARCH_MIPS64
260 state->pc = reinterpret_cast<Address>(simulator_->get_pc());
261 state->sp = reinterpret_cast<Address>(simulator_->get_register(
263 state->fp = reinterpret_cast<Address>(simulator_->get_register(
269 Simulator* simulator_;
271 #endif // USE_SIMULATOR
274 #if defined(USE_SIGNALS)
276 class SignalHandler : public AllStatic {
278 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
279 static void TearDown() { delete mutex_; mutex_ = NULL; }
281 static void IncreaseSamplerCount() {
282 base::LockGuard<base::Mutex> lock_guard(mutex_);
283 if (++client_count_ == 1) Install();
286 static void DecreaseSamplerCount() {
287 base::LockGuard<base::Mutex> lock_guard(mutex_);
288 if (--client_count_ == 0) Restore();
291 static bool Installed() {
292 return signal_handler_installed_;
296 static void Install() {
299 sa.sa_sigaction = &HandleProfilerSignal;
300 sigemptyset(&sa.sa_mask);
302 sa.sa_flags = SA_SIGINFO;
304 sa.sa_flags = SA_RESTART | SA_SIGINFO;
306 signal_handler_installed_ =
307 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
311 static void Restore() {
313 if (signal_handler_installed_) {
314 sigaction(SIGPROF, &old_signal_handler_, 0);
315 signal_handler_installed_ = false;
321 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
323 // Protects the process wide state below.
324 static base::Mutex* mutex_;
325 static int client_count_;
326 static bool signal_handler_installed_;
327 static struct sigaction old_signal_handler_;
331 base::Mutex* SignalHandler::mutex_ = NULL;
332 int SignalHandler::client_count_ = 0;
333 struct sigaction SignalHandler::old_signal_handler_;
334 bool SignalHandler::signal_handler_installed_ = false;
337 // As Native Client does not support signal handling, profiling is disabled.
339 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
342 if (signal != SIGPROF) return;
343 Isolate* isolate = Isolate::UnsafeCurrent();
344 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
345 // We require a fully initialized and entered isolate.
348 if (v8::Locker::IsActive() &&
349 !isolate->thread_manager()->IsLockedByCurrentThread()) {
353 Sampler* sampler = isolate->logger()->sampler();
354 if (sampler == NULL) return;
358 #if defined(USE_SIMULATOR)
359 SimulatorHelper helper;
360 if (!helper.Init(sampler, isolate)) return;
361 helper.FillRegisters(&state);
362 // It possible that the simulator is interrupted while it is updating
363 // the sp or fp register. ARM64 simulator does this in two steps:
364 // first setting it to zero and then setting it to the new value.
365 // Bailout if sp/fp doesn't contain the new value.
366 if (state.sp == 0 || state.fp == 0) return;
368 // Extracting the sample from the context is extremely machine dependent.
369 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
371 mcontext_t& mcontext = ucontext->uc_mcontext;
374 #if V8_HOST_ARCH_IA32
375 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
376 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
377 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
378 #elif V8_HOST_ARCH_X64
379 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
380 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
381 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
382 #elif V8_HOST_ARCH_ARM
383 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
384 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
385 // Old GLibc ARM versions used a gregs[] array to access the register
386 // values from mcontext_t.
387 state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
388 state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
389 state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
391 state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
392 state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
393 state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
394 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
395 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
396 #elif V8_HOST_ARCH_ARM64
397 state.pc = reinterpret_cast<Address>(mcontext.pc);
398 state.sp = reinterpret_cast<Address>(mcontext.sp);
399 // FP is an alias for x29.
400 state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
401 #elif V8_HOST_ARCH_MIPS
402 state.pc = reinterpret_cast<Address>(mcontext.pc);
403 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
404 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
405 #elif V8_HOST_ARCH_MIPS64
406 state.pc = reinterpret_cast<Address>(mcontext.pc);
407 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
408 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
409 #endif // V8_HOST_ARCH_*
413 state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
414 state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
415 state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
416 #else // !__DARWIN_UNIX03
417 state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
418 state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
419 state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
420 #endif // __DARWIN_UNIX03
421 #elif V8_HOST_ARCH_IA32
423 state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
424 state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
425 state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
426 #else // !__DARWIN_UNIX03
427 state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
428 state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
429 state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
430 #endif // __DARWIN_UNIX03
431 #endif // V8_HOST_ARCH_IA32
433 #if V8_HOST_ARCH_IA32
434 state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
435 state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
436 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
437 #elif V8_HOST_ARCH_X64
438 state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
439 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
440 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
441 #elif V8_HOST_ARCH_ARM
442 state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
443 state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
444 state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
445 #endif // V8_HOST_ARCH_*
447 #if V8_HOST_ARCH_IA32
448 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
449 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
450 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
451 #elif V8_HOST_ARCH_X64
452 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
453 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
454 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
455 #endif // V8_HOST_ARCH_*
457 #if V8_HOST_ARCH_IA32
458 state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
459 state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
460 state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
461 #elif V8_HOST_ARCH_X64
462 state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
463 state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
464 state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
465 #endif // V8_HOST_ARCH_*
467 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
468 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
469 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
471 #if V8_HOST_ARCH_IA32
472 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
473 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
474 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
475 #elif V8_HOST_ARCH_ARM
476 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
477 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
478 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
479 #endif // V8_HOST_ARCH_*
481 #endif // USE_SIMULATOR
482 sampler->SampleStack(state);
489 class SamplerThread : public base::Thread {
491 static const int kSamplerThreadStackSize = 64 * KB;
493 explicit SamplerThread(int interval)
494 : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
495 interval_(interval) {}
497 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
498 static void TearDown() { delete mutex_; mutex_ = NULL; }
500 static void AddActiveSampler(Sampler* sampler) {
501 bool need_to_start = false;
502 base::LockGuard<base::Mutex> lock_guard(mutex_);
503 if (instance_ == NULL) {
504 // Start a thread that will send SIGPROF signal to VM threads,
505 // when CPU profiling will be enabled.
506 instance_ = new SamplerThread(sampler->interval());
507 need_to_start = true;
510 DCHECK(sampler->IsActive());
511 DCHECK(!instance_->active_samplers_.Contains(sampler));
512 DCHECK(instance_->interval_ == sampler->interval());
513 instance_->active_samplers_.Add(sampler);
515 if (need_to_start) instance_->StartSynchronously();
518 static void RemoveActiveSampler(Sampler* sampler) {
519 SamplerThread* instance_to_remove = NULL;
521 base::LockGuard<base::Mutex> lock_guard(mutex_);
523 DCHECK(sampler->IsActive());
524 bool removed = instance_->active_samplers_.RemoveElement(sampler);
528 // We cannot delete the instance immediately as we need to Join() the
529 // thread but we are holding mutex_ and the thread may try to acquire it.
530 if (instance_->active_samplers_.is_empty()) {
531 instance_to_remove = instance_;
536 if (!instance_to_remove) return;
537 instance_to_remove->Join();
538 delete instance_to_remove;
541 // Implement Thread::Run().
545 base::LockGuard<base::Mutex> lock_guard(mutex_);
546 if (active_samplers_.is_empty()) break;
547 // When CPU profiling is enabled both JavaScript and C++ code is
548 // profiled. We must not suspend.
549 for (int i = 0; i < active_samplers_.length(); ++i) {
550 Sampler* sampler = active_samplers_.at(i);
551 if (!sampler->isolate()->IsInitialized()) continue;
552 if (!sampler->IsProfiling()) continue;
556 base::OS::Sleep(interval_);
561 // Protects the process wide state below.
562 static base::Mutex* mutex_;
563 static SamplerThread* instance_;
566 List<Sampler*> active_samplers_;
568 DISALLOW_COPY_AND_ASSIGN(SamplerThread);
572 base::Mutex* SamplerThread::mutex_ = NULL;
573 SamplerThread* SamplerThread::instance_ = NULL;
577 // StackTracer implementation
579 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
580 const RegisterState& regs) {
581 DCHECK(isolate->IsInitialized());
582 timestamp = base::TimeTicks::HighResolutionNow();
584 state = isolate->current_vm_state();
586 // Avoid collecting traces while doing GC.
587 if (state == GC) return;
589 Address js_entry_sp = isolate->js_entry_sp();
590 if (js_entry_sp == 0) {
591 // Not executing JS now.
595 ExternalCallbackScope* scope = isolate->external_callback_scope();
596 Address handler = Isolate::handler(isolate->thread_local_top());
597 // If there is a handler on top of the external callback scope then
598 // we have already entrered JavaScript again and the external callback
599 // is not the top function.
600 if (scope && scope->scope_address() < handler) {
601 external_callback = scope->callback();
602 has_external_callback = true;
604 // Sample potential return address value for frameless invocation of
605 // stubs (we'll figure out later, if this value makes sense).
606 tos = Memory::Address_at(regs.sp);
607 has_external_callback = false;
610 SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
611 top_frame_type = it.top_frame_type();
613 while (!it.done() && i < TickSample::kMaxFramesCount) {
614 stack[i++] = it.frame()->pc();
621 void Sampler::SetUp() {
622 #if defined(USE_SIGNALS)
623 SignalHandler::SetUp();
625 SamplerThread::SetUp();
629 void Sampler::TearDown() {
630 SamplerThread::TearDown();
631 #if defined(USE_SIGNALS)
632 SignalHandler::TearDown();
637 Sampler::Sampler(Isolate* isolate, int interval)
641 has_processing_thread_(false),
643 is_counting_samples_(false),
644 js_and_external_sample_count_(0) {
645 data_ = new PlatformData;
649 Sampler::~Sampler() {
655 void Sampler::Start() {
658 SamplerThread::AddActiveSampler(this);
662 void Sampler::Stop() {
664 SamplerThread::RemoveActiveSampler(this);
669 void Sampler::IncreaseProfilingDepth() {
670 base::NoBarrier_AtomicIncrement(&profiling_, 1);
671 #if defined(USE_SIGNALS)
672 SignalHandler::IncreaseSamplerCount();
677 void Sampler::DecreaseProfilingDepth() {
678 #if defined(USE_SIGNALS)
679 SignalHandler::DecreaseSamplerCount();
681 base::NoBarrier_AtomicIncrement(&profiling_, -1);
685 void Sampler::SampleStack(const RegisterState& state) {
686 TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
687 TickSample sample_obj;
688 if (sample == NULL) sample = &sample_obj;
689 sample->Init(isolate_, state);
690 if (is_counting_samples_) {
691 if (sample->state == JS || sample->state == EXTERNAL) {
692 ++js_and_external_sample_count_;
696 if (sample != &sample_obj) {
697 isolate_->cpu_profiler()->FinishTickSample();
702 #if defined(USE_SIGNALS)
704 void Sampler::DoSample() {
705 if (!SignalHandler::Installed()) return;
706 pthread_kill(platform_data()->vm_tid(), SIGPROF);
709 #elif V8_OS_WIN || V8_OS_CYGWIN
711 void Sampler::DoSample() {
712 HANDLE profiled_thread = platform_data()->profiled_thread();
713 if (profiled_thread == NULL) return;
715 #if defined(USE_SIMULATOR)
716 SimulatorHelper helper;
717 if (!helper.Init(this, isolate())) return;
720 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
721 if (SuspendThread(profiled_thread) == kSuspendFailed) return;
723 // Context used for sampling the register state of the profiled thread.
725 memset(&context, 0, sizeof(context));
726 context.ContextFlags = CONTEXT_FULL;
727 if (GetThreadContext(profiled_thread, &context) != 0) {
729 #if defined(USE_SIMULATOR)
730 helper.FillRegisters(&state);
733 state.pc = reinterpret_cast<Address>(context.Rip);
734 state.sp = reinterpret_cast<Address>(context.Rsp);
735 state.fp = reinterpret_cast<Address>(context.Rbp);
737 state.pc = reinterpret_cast<Address>(context.Eip);
738 state.sp = reinterpret_cast<Address>(context.Esp);
739 state.fp = reinterpret_cast<Address>(context.Ebp);
741 #endif // USE_SIMULATOR
744 ResumeThread(profiled_thread);
747 #endif // USE_SIGNALS
750 } } // namespace v8::internal