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. 4 5#include "src/profiler/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 && !V8_OS_AIX 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/base/platform/platform.h" 46#include "src/flags.h" 47#include "src/frames-inl.h" 48#include "src/log.h" 49#include "src/profiler/cpu-profiler-inl.h" 50#include "src/simulator.h" 51#include "src/v8threads.h" 52#include "src/vm-state-inl.h" 53 54 55#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 56 57// Not all versions of Android's C library provide ucontext_t. 58// Detect this and provide custom but compatible definitions. Note that these 59// follow the GLibc naming convention to access register values from 60// mcontext_t. 61// 62// See http://code.google.com/p/android/issues/detail?id=34784 63 64#if defined(__arm__) 65 66typedef struct sigcontext mcontext_t; 67 68typedef struct ucontext { 69 uint32_t uc_flags; 70 struct ucontext* uc_link; 71 stack_t uc_stack; 72 mcontext_t uc_mcontext; 73 // Other fields are not used by V8, don't define them here. 74} ucontext_t; 75 76#elif defined(__aarch64__) 77 78typedef struct sigcontext mcontext_t; 79 80typedef struct ucontext { 81 uint64_t uc_flags; 82 struct ucontext *uc_link; 83 stack_t uc_stack; 84 mcontext_t uc_mcontext; 85 // Other fields are not used by V8, don't define them here. 86} ucontext_t; 87 88#elif defined(__mips__) 89// MIPS version of sigcontext, for Android bionic. 90typedef struct { 91 uint32_t regmask; 92 uint32_t status; 93 uint64_t pc; 94 uint64_t gregs[32]; 95 uint64_t fpregs[32]; 96 uint32_t acx; 97 uint32_t fpc_csr; 98 uint32_t fpc_eir; 99 uint32_t used_math; 100 uint32_t dsp; 101 uint64_t mdhi; 102 uint64_t mdlo; 103 uint32_t hi1; 104 uint32_t lo1; 105 uint32_t hi2; 106 uint32_t lo2; 107 uint32_t hi3; 108 uint32_t lo3; 109} mcontext_t; 110 111typedef struct ucontext { 112 uint32_t uc_flags; 113 struct ucontext* uc_link; 114 stack_t uc_stack; 115 mcontext_t uc_mcontext; 116 // Other fields are not used by V8, don't define them here. 117} ucontext_t; 118 119#elif defined(__i386__) 120// x86 version for Android. 121typedef struct { 122 uint32_t gregs[19]; 123 void* fpregs; 124 uint32_t oldmask; 125 uint32_t cr2; 126} mcontext_t; 127 128typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks 129typedef struct ucontext { 130 uint32_t uc_flags; 131 struct ucontext* uc_link; 132 stack_t uc_stack; 133 mcontext_t uc_mcontext; 134 // Other fields are not used by V8, don't define them here. 135} ucontext_t; 136enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; 137 138#elif defined(__x86_64__) 139// x64 version for Android. 140typedef struct { 141 uint64_t gregs[23]; 142 void* fpregs; 143 uint64_t __reserved1[8]; 144} mcontext_t; 145 146typedef struct ucontext { 147 uint64_t uc_flags; 148 struct ucontext *uc_link; 149 stack_t uc_stack; 150 mcontext_t uc_mcontext; 151 // Other fields are not used by V8, don't define them here. 152} ucontext_t; 153enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; 154#endif 155 156#endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 157 158 159namespace v8 { 160namespace internal { 161 162namespace { 163 164class PlatformDataCommon : public Malloced { 165 public: 166 PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {} 167 ThreadId profiled_thread_id() { return profiled_thread_id_; } 168 169 protected: 170 ~PlatformDataCommon() {} 171 172 private: 173 ThreadId profiled_thread_id_; 174}; 175 176 177bool IsSamePage(byte* ptr1, byte* ptr2) { 178 const uint32_t kPageSize = 4096; 179 uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); 180 return (reinterpret_cast<uintptr_t>(ptr1) & mask) == 181 (reinterpret_cast<uintptr_t>(ptr2) & mask); 182} 183 184 185// Check if the code at specified address could potentially be a 186// frame setup code. 187bool IsNoFrameRegion(Address address) { 188 struct Pattern { 189 int bytes_count; 190 byte bytes[8]; 191 int offsets[4]; 192 }; 193 byte* pc = reinterpret_cast<byte*>(address); 194 static Pattern patterns[] = { 195#if V8_HOST_ARCH_IA32 196 // push %ebp 197 // mov %esp,%ebp 198 {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, 199 // pop %ebp 200 // ret N 201 {2, {0x5d, 0xc2}, {0, 1, -1}}, 202 // pop %ebp 203 // ret 204 {2, {0x5d, 0xc3}, {0, 1, -1}}, 205#elif V8_HOST_ARCH_X64 206 // pushq %rbp 207 // movq %rsp,%rbp 208 {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}}, 209 // popq %rbp 210 // ret N 211 {2, {0x5d, 0xc2}, {0, 1, -1}}, 212 // popq %rbp 213 // ret 214 {2, {0x5d, 0xc3}, {0, 1, -1}}, 215#endif 216 {0, {}, {}} 217 }; 218 for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) { 219 for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) { 220 int offset = *offset_ptr; 221 if (!offset || IsSamePage(pc, pc - offset)) { 222 MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count); 223 if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count)) 224 return true; 225 } else { 226 // It is not safe to examine bytes on another page as it might not be 227 // allocated thus causing a SEGFAULT. 228 // Check the pattern part that's on the same page and 229 // pessimistically assume it could be the entire pattern match. 230 MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset); 231 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) 232 return true; 233 } 234 } 235 } 236 return false; 237} 238 239} // namespace 240 241#if defined(USE_SIGNALS) 242 243class Sampler::PlatformData : public PlatformDataCommon { 244 public: 245 PlatformData() : vm_tid_(pthread_self()) {} 246 pthread_t vm_tid() const { return vm_tid_; } 247 248 private: 249 pthread_t vm_tid_; 250}; 251 252#elif V8_OS_WIN || V8_OS_CYGWIN 253 254// ---------------------------------------------------------------------------- 255// Win32 profiler support. On Cygwin we use the same sampler implementation as 256// on Win32. 257 258class Sampler::PlatformData : public PlatformDataCommon { 259 public: 260 // Get a handle to the calling thread. This is the thread that we are 261 // going to profile. We need to make a copy of the handle because we are 262 // going to use it in the sampler thread. Using GetThreadHandle() will 263 // not work in this case. We're using OpenThread because DuplicateHandle 264 // for some reason doesn't work in Chrome's sandbox. 265 PlatformData() 266 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | 267 THREAD_SUSPEND_RESUME | 268 THREAD_QUERY_INFORMATION, 269 false, 270 GetCurrentThreadId())) {} 271 272 ~PlatformData() { 273 if (profiled_thread_ != NULL) { 274 CloseHandle(profiled_thread_); 275 profiled_thread_ = NULL; 276 } 277 } 278 279 HANDLE profiled_thread() { return profiled_thread_; } 280 281 private: 282 HANDLE profiled_thread_; 283}; 284#endif 285 286 287#if defined(USE_SIMULATOR) 288class SimulatorHelper { 289 public: 290 inline bool Init(Isolate* isolate) { 291 simulator_ = isolate->thread_local_top()->simulator_; 292 // Check if there is active simulator. 293 return simulator_ != NULL; 294 } 295 296 inline void FillRegisters(v8::RegisterState* state) { 297#if V8_TARGET_ARCH_ARM 298 if (!simulator_->has_bad_pc()) { 299 state->pc = reinterpret_cast<Address>(simulator_->get_pc()); 300 } 301 state->sp = reinterpret_cast<Address>(simulator_->get_register( 302 Simulator::sp)); 303 state->fp = reinterpret_cast<Address>(simulator_->get_register( 304 Simulator::r11)); 305#elif V8_TARGET_ARCH_ARM64 306 if (simulator_->sp() == 0 || simulator_->fp() == 0) { 307 // It's possible that the simulator is interrupted while it is updating 308 // the sp or fp register. ARM64 simulator does this in two steps: 309 // first setting it to zero and then setting it to a new value. 310 // Bailout if sp/fp doesn't contain the new value. 311 // 312 // FIXME: The above doesn't really solve the issue. 313 // If a 64-bit target is executed on a 32-bit host even the final 314 // write is non-atomic, so it might obtain a half of the result. 315 // Moreover as long as the register set code uses memcpy (as of now), 316 // it is not guaranteed to be atomic even when both host and target 317 // are of same bitness. 318 return; 319 } 320 state->pc = reinterpret_cast<Address>(simulator_->pc()); 321 state->sp = reinterpret_cast<Address>(simulator_->sp()); 322 state->fp = reinterpret_cast<Address>(simulator_->fp()); 323#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 324 if (!simulator_->has_bad_pc()) { 325 state->pc = reinterpret_cast<Address>(simulator_->get_pc()); 326 } 327 state->sp = reinterpret_cast<Address>(simulator_->get_register( 328 Simulator::sp)); 329 state->fp = reinterpret_cast<Address>(simulator_->get_register( 330 Simulator::fp)); 331#elif V8_TARGET_ARCH_PPC 332 if (!simulator_->has_bad_pc()) { 333 state->pc = reinterpret_cast<Address>(simulator_->get_pc()); 334 } 335 state->sp = 336 reinterpret_cast<Address>(simulator_->get_register(Simulator::sp)); 337 state->fp = 338 reinterpret_cast<Address>(simulator_->get_register(Simulator::fp)); 339#endif 340 } 341 342 private: 343 Simulator* simulator_; 344}; 345#endif // USE_SIMULATOR 346 347 348#if defined(USE_SIGNALS) 349 350class SignalHandler : public AllStatic { 351 public: 352 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 353 static void TearDown() { delete mutex_; mutex_ = NULL; } 354 355 static void IncreaseSamplerCount() { 356 base::LockGuard<base::Mutex> lock_guard(mutex_); 357 if (++client_count_ == 1) Install(); 358 } 359 360 static void DecreaseSamplerCount() { 361 base::LockGuard<base::Mutex> lock_guard(mutex_); 362 if (--client_count_ == 0) Restore(); 363 } 364 365 static bool Installed() { 366 return signal_handler_installed_; 367 } 368 369 private: 370 static void Install() { 371#if !V8_OS_NACL 372 struct sigaction sa; 373 sa.sa_sigaction = &HandleProfilerSignal; 374 sigemptyset(&sa.sa_mask); 375#if V8_OS_QNX 376 sa.sa_flags = SA_SIGINFO; 377#else 378 sa.sa_flags = SA_RESTART | SA_SIGINFO; 379#endif 380 signal_handler_installed_ = 381 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 382#endif 383 } 384 385 static void Restore() { 386#if !V8_OS_NACL 387 if (signal_handler_installed_) { 388 sigaction(SIGPROF, &old_signal_handler_, 0); 389 signal_handler_installed_ = false; 390 } 391#endif 392 } 393 394#if !V8_OS_NACL 395 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); 396#endif 397 // Protects the process wide state below. 398 static base::Mutex* mutex_; 399 static int client_count_; 400 static bool signal_handler_installed_; 401 static struct sigaction old_signal_handler_; 402}; 403 404 405base::Mutex* SignalHandler::mutex_ = NULL; 406int SignalHandler::client_count_ = 0; 407struct sigaction SignalHandler::old_signal_handler_; 408bool SignalHandler::signal_handler_installed_ = false; 409 410 411// As Native Client does not support signal handling, profiling is disabled. 412#if !V8_OS_NACL 413void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 414 void* context) { 415 USE(info); 416 if (signal != SIGPROF) return; 417 Isolate* isolate = Isolate::UnsafeCurrent(); 418 if (isolate == NULL || !isolate->IsInUse()) { 419 // We require a fully initialized and entered isolate. 420 return; 421 } 422 if (v8::Locker::IsActive() && 423 !isolate->thread_manager()->IsLockedByCurrentThread()) { 424 return; 425 } 426 427 Sampler* sampler = isolate->logger()->sampler(); 428 if (sampler == NULL) return; 429 430 v8::RegisterState state; 431 432#if defined(USE_SIMULATOR) 433 SimulatorHelper helper; 434 if (!helper.Init(isolate)) return; 435 helper.FillRegisters(&state); 436 // It possible that the simulator is interrupted while it is updating 437 // the sp or fp register. ARM64 simulator does this in two steps: 438 // first setting it to zero and then setting it to the new value. 439 // Bailout if sp/fp doesn't contain the new value. 440 if (state.sp == 0 || state.fp == 0) return; 441#else 442 // Extracting the sample from the context is extremely machine dependent. 443 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 444#if !(V8_OS_OPENBSD || (V8_OS_LINUX && V8_HOST_ARCH_PPC)) 445 mcontext_t& mcontext = ucontext->uc_mcontext; 446#endif 447#if V8_OS_LINUX 448#if V8_HOST_ARCH_IA32 449 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); 450 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); 451 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); 452#elif V8_HOST_ARCH_X64 453 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); 454 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); 455 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); 456#elif V8_HOST_ARCH_ARM 457#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 458 // Old GLibc ARM versions used a gregs[] array to access the register 459 // values from mcontext_t. 460 state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]); 461 state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]); 462 state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]); 463#else 464 state.pc = reinterpret_cast<Address>(mcontext.arm_pc); 465 state.sp = reinterpret_cast<Address>(mcontext.arm_sp); 466 state.fp = reinterpret_cast<Address>(mcontext.arm_fp); 467#endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 468#elif V8_HOST_ARCH_ARM64 469 state.pc = reinterpret_cast<Address>(mcontext.pc); 470 state.sp = reinterpret_cast<Address>(mcontext.sp); 471 // FP is an alias for x29. 472 state.fp = reinterpret_cast<Address>(mcontext.regs[29]); 473#elif V8_HOST_ARCH_MIPS 474 state.pc = reinterpret_cast<Address>(mcontext.pc); 475 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); 476 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); 477#elif V8_HOST_ARCH_MIPS64 478 state.pc = reinterpret_cast<Address>(mcontext.pc); 479 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); 480 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); 481#elif V8_HOST_ARCH_PPC 482 state.pc = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->nip); 483 state.sp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R1]); 484 state.fp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R31]); 485#endif // V8_HOST_ARCH_* 486#elif V8_OS_MACOSX 487#if V8_HOST_ARCH_X64 488#if __DARWIN_UNIX03 489 state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip); 490 state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp); 491 state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp); 492#else // !__DARWIN_UNIX03 493 state.pc = reinterpret_cast<Address>(mcontext->ss.rip); 494 state.sp = reinterpret_cast<Address>(mcontext->ss.rsp); 495 state.fp = reinterpret_cast<Address>(mcontext->ss.rbp); 496#endif // __DARWIN_UNIX03 497#elif V8_HOST_ARCH_IA32 498#if __DARWIN_UNIX03 499 state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip); 500 state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp); 501 state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp); 502#else // !__DARWIN_UNIX03 503 state.pc = reinterpret_cast<Address>(mcontext->ss.eip); 504 state.sp = reinterpret_cast<Address>(mcontext->ss.esp); 505 state.fp = reinterpret_cast<Address>(mcontext->ss.ebp); 506#endif // __DARWIN_UNIX03 507#endif // V8_HOST_ARCH_IA32 508#elif V8_OS_FREEBSD 509#if V8_HOST_ARCH_IA32 510 state.pc = reinterpret_cast<Address>(mcontext.mc_eip); 511 state.sp = reinterpret_cast<Address>(mcontext.mc_esp); 512 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp); 513#elif V8_HOST_ARCH_X64 514 state.pc = reinterpret_cast<Address>(mcontext.mc_rip); 515 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp); 516 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp); 517#elif V8_HOST_ARCH_ARM 518 state.pc = reinterpret_cast<Address>(mcontext.mc_r15); 519 state.sp = reinterpret_cast<Address>(mcontext.mc_r13); 520 state.fp = reinterpret_cast<Address>(mcontext.mc_r11); 521#endif // V8_HOST_ARCH_* 522#elif V8_OS_NETBSD 523#if V8_HOST_ARCH_IA32 524 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); 525 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); 526 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); 527#elif V8_HOST_ARCH_X64 528 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); 529 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); 530 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); 531#endif // V8_HOST_ARCH_* 532#elif V8_OS_OPENBSD 533#if V8_HOST_ARCH_IA32 534 state.pc = reinterpret_cast<Address>(ucontext->sc_eip); 535 state.sp = reinterpret_cast<Address>(ucontext->sc_esp); 536 state.fp = reinterpret_cast<Address>(ucontext->sc_ebp); 537#elif V8_HOST_ARCH_X64 538 state.pc = reinterpret_cast<Address>(ucontext->sc_rip); 539 state.sp = reinterpret_cast<Address>(ucontext->sc_rsp); 540 state.fp = reinterpret_cast<Address>(ucontext->sc_rbp); 541#endif // V8_HOST_ARCH_* 542#elif V8_OS_SOLARIS 543 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); 544 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); 545 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); 546#elif V8_OS_QNX 547#if V8_HOST_ARCH_IA32 548 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); 549 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); 550 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); 551#elif V8_HOST_ARCH_ARM 552 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); 553 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); 554 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); 555#endif // V8_HOST_ARCH_* 556#elif V8_OS_AIX 557 state.pc = reinterpret_cast<Address>(mcontext.jmp_context.iar); 558 state.sp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[1]); 559 state.fp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[31]); 560#endif // V8_OS_AIX 561#endif // USE_SIMULATOR 562 sampler->SampleStack(state); 563} 564#endif // V8_OS_NACL 565 566#endif 567 568 569class SamplerThread : public base::Thread { 570 public: 571 static const int kSamplerThreadStackSize = 64 * KB; 572 573 explicit SamplerThread(int interval) 574 : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)), 575 interval_(interval) {} 576 577 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 578 static void TearDown() { delete mutex_; mutex_ = NULL; } 579 580 static void AddActiveSampler(Sampler* sampler) { 581 bool need_to_start = false; 582 base::LockGuard<base::Mutex> lock_guard(mutex_); 583 if (instance_ == NULL) { 584 // Start a thread that will send SIGPROF signal to VM threads, 585 // when CPU profiling will be enabled. 586 instance_ = new SamplerThread(sampler->interval()); 587 need_to_start = true; 588 } 589 590 DCHECK(sampler->IsActive()); 591 DCHECK(!instance_->active_samplers_.Contains(sampler)); 592 DCHECK(instance_->interval_ == sampler->interval()); 593 instance_->active_samplers_.Add(sampler); 594 595 if (need_to_start) instance_->StartSynchronously(); 596 } 597 598 static void RemoveActiveSampler(Sampler* sampler) { 599 SamplerThread* instance_to_remove = NULL; 600 { 601 base::LockGuard<base::Mutex> lock_guard(mutex_); 602 603 DCHECK(sampler->IsActive()); 604 bool removed = instance_->active_samplers_.RemoveElement(sampler); 605 DCHECK(removed); 606 USE(removed); 607 608 // We cannot delete the instance immediately as we need to Join() the 609 // thread but we are holding mutex_ and the thread may try to acquire it. 610 if (instance_->active_samplers_.is_empty()) { 611 instance_to_remove = instance_; 612 instance_ = NULL; 613 } 614 } 615 616 if (!instance_to_remove) return; 617 instance_to_remove->Join(); 618 delete instance_to_remove; 619 } 620 621 // Implement Thread::Run(). 622 virtual void Run() { 623 while (true) { 624 { 625 base::LockGuard<base::Mutex> lock_guard(mutex_); 626 if (active_samplers_.is_empty()) break; 627 // When CPU profiling is enabled both JavaScript and C++ code is 628 // profiled. We must not suspend. 629 for (int i = 0; i < active_samplers_.length(); ++i) { 630 Sampler* sampler = active_samplers_.at(i); 631 if (!sampler->IsProfiling()) continue; 632 sampler->DoSample(); 633 } 634 } 635 base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_)); 636 } 637 } 638 639 private: 640 // Protects the process wide state below. 641 static base::Mutex* mutex_; 642 static SamplerThread* instance_; 643 644 const int interval_; 645 List<Sampler*> active_samplers_; 646 647 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 648}; 649 650 651base::Mutex* SamplerThread::mutex_ = NULL; 652SamplerThread* SamplerThread::instance_ = NULL; 653 654 655// 656// StackTracer implementation 657// 658DISABLE_ASAN void TickSample::Init(Isolate* isolate, 659 const v8::RegisterState& regs, 660 RecordCEntryFrame record_c_entry_frame) { 661 timestamp = base::TimeTicks::HighResolutionNow(); 662 pc = reinterpret_cast<Address>(regs.pc); 663 state = isolate->current_vm_state(); 664 665 // Avoid collecting traces while doing GC. 666 if (state == GC) return; 667 668 Address js_entry_sp = isolate->js_entry_sp(); 669 if (js_entry_sp == 0) return; // Not executing JS now. 670 671 if (pc && IsNoFrameRegion(pc)) { 672 pc = 0; 673 return; 674 } 675 676 ExternalCallbackScope* scope = isolate->external_callback_scope(); 677 Address handler = Isolate::handler(isolate->thread_local_top()); 678 // If there is a handler on top of the external callback scope then 679 // we have already entrered JavaScript again and the external callback 680 // is not the top function. 681 if (scope && scope->scope_address() < handler) { 682 external_callback = scope->callback(); 683 has_external_callback = true; 684 } else { 685 // sp register may point at an arbitrary place in memory, make 686 // sure MSAN doesn't complain about it. 687 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); 688 // Sample potential return address value for frameless invocation of 689 // stubs (we'll figure out later, if this value makes sense). 690 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); 691 has_external_callback = false; 692 } 693 694 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), 695 reinterpret_cast<Address>(regs.sp), js_entry_sp); 696 top_frame_type = it.top_frame_type(); 697 698 SampleInfo info; 699 GetStackSample(isolate, regs, record_c_entry_frame, 700 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info); 701 frames_count = static_cast<unsigned>(info.frames_count); 702} 703 704 705void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, 706 RecordCEntryFrame record_c_entry_frame, 707 void** frames, size_t frames_limit, 708 v8::SampleInfo* sample_info) { 709 sample_info->frames_count = 0; 710 sample_info->vm_state = isolate->current_vm_state(); 711 if (sample_info->vm_state == GC) return; 712 713 Address js_entry_sp = isolate->js_entry_sp(); 714 if (js_entry_sp == 0) return; // Not executing JS now. 715 716 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), 717 reinterpret_cast<Address>(regs.sp), js_entry_sp); 718 size_t i = 0; 719 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && 720 it.top_frame_type() == StackFrame::EXIT) { 721 frames[i++] = isolate->c_function(); 722 } 723 while (!it.done() && i < frames_limit) { 724 frames[i++] = it.frame()->pc(); 725 it.Advance(); 726 } 727 sample_info->frames_count = i; 728} 729 730 731void Sampler::SetUp() { 732#if defined(USE_SIGNALS) 733 SignalHandler::SetUp(); 734#endif 735 SamplerThread::SetUp(); 736} 737 738 739void Sampler::TearDown() { 740 SamplerThread::TearDown(); 741#if defined(USE_SIGNALS) 742 SignalHandler::TearDown(); 743#endif 744} 745 746 747Sampler::Sampler(Isolate* isolate, int interval) 748 : isolate_(isolate), 749 interval_(interval), 750 profiling_(false), 751 has_processing_thread_(false), 752 active_(false), 753 is_counting_samples_(false), 754 js_and_external_sample_count_(0) { 755 data_ = new PlatformData; 756} 757 758 759Sampler::~Sampler() { 760 DCHECK(!IsActive()); 761 delete data_; 762} 763 764 765void Sampler::Start() { 766 DCHECK(!IsActive()); 767 SetActive(true); 768 SamplerThread::AddActiveSampler(this); 769} 770 771 772void Sampler::Stop() { 773 DCHECK(IsActive()); 774 SamplerThread::RemoveActiveSampler(this); 775 SetActive(false); 776} 777 778 779void Sampler::IncreaseProfilingDepth() { 780 base::NoBarrier_AtomicIncrement(&profiling_, 1); 781#if defined(USE_SIGNALS) 782 SignalHandler::IncreaseSamplerCount(); 783#endif 784} 785 786 787void Sampler::DecreaseProfilingDepth() { 788#if defined(USE_SIGNALS) 789 SignalHandler::DecreaseSamplerCount(); 790#endif 791 base::NoBarrier_AtomicIncrement(&profiling_, -1); 792} 793 794 795void Sampler::SampleStack(const v8::RegisterState& state) { 796 TickSample* sample = isolate_->cpu_profiler()->StartTickSample(); 797 TickSample sample_obj; 798 if (sample == NULL) sample = &sample_obj; 799 sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame); 800 if (is_counting_samples_) { 801 if (sample->state == JS || sample->state == EXTERNAL) { 802 ++js_and_external_sample_count_; 803 } 804 } 805 Tick(sample); 806 if (sample != &sample_obj) { 807 isolate_->cpu_profiler()->FinishTickSample(); 808 } 809} 810 811 812#if defined(USE_SIGNALS) 813 814void Sampler::DoSample() { 815 if (!SignalHandler::Installed()) return; 816 pthread_kill(platform_data()->vm_tid(), SIGPROF); 817} 818 819#elif V8_OS_WIN || V8_OS_CYGWIN 820 821void Sampler::DoSample() { 822 HANDLE profiled_thread = platform_data()->profiled_thread(); 823 if (profiled_thread == NULL) return; 824 825#if defined(USE_SIMULATOR) 826 SimulatorHelper helper; 827 if (!helper.Init(isolate())) return; 828#endif 829 830 const DWORD kSuspendFailed = static_cast<DWORD>(-1); 831 if (SuspendThread(profiled_thread) == kSuspendFailed) return; 832 833 // Context used for sampling the register state of the profiled thread. 834 CONTEXT context; 835 memset(&context, 0, sizeof(context)); 836 context.ContextFlags = CONTEXT_FULL; 837 if (GetThreadContext(profiled_thread, &context) != 0) { 838 v8::RegisterState state; 839#if defined(USE_SIMULATOR) 840 helper.FillRegisters(&state); 841#else 842#if V8_HOST_ARCH_X64 843 state.pc = reinterpret_cast<Address>(context.Rip); 844 state.sp = reinterpret_cast<Address>(context.Rsp); 845 state.fp = reinterpret_cast<Address>(context.Rbp); 846#else 847 state.pc = reinterpret_cast<Address>(context.Eip); 848 state.sp = reinterpret_cast<Address>(context.Esp); 849 state.fp = reinterpret_cast<Address>(context.Ebp); 850#endif 851#endif // USE_SIMULATOR 852 SampleStack(state); 853 } 854 ResumeThread(profiled_thread); 855} 856 857#endif // USE_SIGNALS 858 859 860} // namespace internal 861} // namespace v8 862