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/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 17#include <sys/syscall.h> 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 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> 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/cpu-profiler-inl.h" 48#include "src/flags.h" 49#include "src/frames-inl.h" 50#include "src/log.h" 51#include "src/platform.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: 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; 233 } 234 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( 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) { 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. 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()); 253#elif V8_TARGET_ARCH_MIPS 254 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 Mutex(); } 273 static void TearDown() { delete mutex_; } 274 275 static void IncreaseSamplerCount() { 276 LockGuard<Mutex> lock_guard(mutex_); 277 if (++client_count_ == 1) Install(); 278 } 279 280 static void DecreaseSamplerCount() { 281 LockGuard<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 struct sigaction sa; 292 sa.sa_sigaction = &HandleProfilerSignal; 293 sigemptyset(&sa.sa_mask); 294#if V8_OS_QNX 295 sa.sa_flags = SA_SIGINFO; 296#else 297 sa.sa_flags = SA_RESTART | SA_SIGINFO; 298#endif 299 signal_handler_installed_ = 300 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 301 } 302 303 static void Restore() { 304 if (signal_handler_installed_) { 305 sigaction(SIGPROF, &old_signal_handler_, 0); 306 signal_handler_installed_ = false; 307 } 308 } 309 310 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); 311 // Protects the process wide state below. 312 static Mutex* mutex_; 313 static int client_count_; 314 static bool signal_handler_installed_; 315 static struct sigaction old_signal_handler_; 316}; 317 318 319Mutex* SignalHandler::mutex_ = NULL; 320int SignalHandler::client_count_ = 0; 321struct sigaction SignalHandler::old_signal_handler_; 322bool SignalHandler::signal_handler_installed_ = false; 323 324 325void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 326 void* context) { 327#if V8_OS_NACL 328 // As Native Client does not support signal handling, profiling 329 // is disabled. 330 return; 331#else 332 USE(info); 333 if (signal != SIGPROF) return; 334 Isolate* isolate = Isolate::UncheckedCurrent(); 335 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { 336 // We require a fully initialized and entered isolate. 337 return; 338 } 339 if (v8::Locker::IsActive() && 340 !isolate->thread_manager()->IsLockedByCurrentThread()) { 341 return; 342 } 343 344 Sampler* sampler = isolate->logger()->sampler(); 345 if (sampler == NULL) return; 346 347 RegisterState state; 348 349#if defined(USE_SIMULATOR) 350 SimulatorHelper helper; 351 if (!helper.Init(sampler, isolate)) return; 352 helper.FillRegisters(&state); 353 // It possible that the simulator is interrupted while it is updating 354 // the sp or fp register. ARM64 simulator does this in two steps: 355 // first setting it to zero and then setting it to the new value. 356 // Bailout if sp/fp doesn't contain the new value. 357 if (state.sp == 0 || state.fp == 0) return; 358#else 359 // Extracting the sample from the context is extremely machine dependent. 360 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 361#if !V8_OS_OPENBSD 362 mcontext_t& mcontext = ucontext->uc_mcontext; 363#endif 364#if V8_OS_LINUX 365#if V8_HOST_ARCH_IA32 366 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); 367 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); 368 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); 369#elif V8_HOST_ARCH_X64 370 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); 371 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); 372 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); 373#elif V8_HOST_ARCH_ARM 374#if defined(__GLIBC__) && !defined(__UCLIBC__) && \ 375 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 376 // Old GLibc ARM versions used a gregs[] array to access the register 377 // values from mcontext_t. 378 state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]); 379 state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]); 380 state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]); 381#else 382 state.pc = reinterpret_cast<Address>(mcontext.arm_pc); 383 state.sp = reinterpret_cast<Address>(mcontext.arm_sp); 384 state.fp = reinterpret_cast<Address>(mcontext.arm_fp); 385#endif // defined(__GLIBC__) && !defined(__UCLIBC__) && 386 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 387#elif V8_HOST_ARCH_ARM64 388 state.pc = reinterpret_cast<Address>(mcontext.pc); 389 state.sp = reinterpret_cast<Address>(mcontext.sp); 390 // FP is an alias for x29. 391 state.fp = reinterpret_cast<Address>(mcontext.regs[29]); 392#elif V8_HOST_ARCH_MIPS 393 state.pc = reinterpret_cast<Address>(mcontext.pc); 394 state.sp = reinterpret_cast<Address>(mcontext.gregs[29]); 395 state.fp = reinterpret_cast<Address>(mcontext.gregs[30]); 396#endif // V8_HOST_ARCH_* 397#elif V8_OS_MACOSX 398#if V8_HOST_ARCH_X64 399#if __DARWIN_UNIX03 400 state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip); 401 state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp); 402 state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp); 403#else // !__DARWIN_UNIX03 404 state.pc = reinterpret_cast<Address>(mcontext->ss.rip); 405 state.sp = reinterpret_cast<Address>(mcontext->ss.rsp); 406 state.fp = reinterpret_cast<Address>(mcontext->ss.rbp); 407#endif // __DARWIN_UNIX03 408#elif V8_HOST_ARCH_IA32 409#if __DARWIN_UNIX03 410 state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip); 411 state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp); 412 state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp); 413#else // !__DARWIN_UNIX03 414 state.pc = reinterpret_cast<Address>(mcontext->ss.eip); 415 state.sp = reinterpret_cast<Address>(mcontext->ss.esp); 416 state.fp = reinterpret_cast<Address>(mcontext->ss.ebp); 417#endif // __DARWIN_UNIX03 418#endif // V8_HOST_ARCH_IA32 419#elif V8_OS_FREEBSD 420#if V8_HOST_ARCH_IA32 421 state.pc = reinterpret_cast<Address>(mcontext.mc_eip); 422 state.sp = reinterpret_cast<Address>(mcontext.mc_esp); 423 state.fp = reinterpret_cast<Address>(mcontext.mc_ebp); 424#elif V8_HOST_ARCH_X64 425 state.pc = reinterpret_cast<Address>(mcontext.mc_rip); 426 state.sp = reinterpret_cast<Address>(mcontext.mc_rsp); 427 state.fp = reinterpret_cast<Address>(mcontext.mc_rbp); 428#elif V8_HOST_ARCH_ARM 429 state.pc = reinterpret_cast<Address>(mcontext.mc_r15); 430 state.sp = reinterpret_cast<Address>(mcontext.mc_r13); 431 state.fp = reinterpret_cast<Address>(mcontext.mc_r11); 432#endif // V8_HOST_ARCH_* 433#elif V8_OS_NETBSD 434#if V8_HOST_ARCH_IA32 435 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]); 436 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]); 437 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]); 438#elif V8_HOST_ARCH_X64 439 state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]); 440 state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]); 441 state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]); 442#endif // V8_HOST_ARCH_* 443#elif V8_OS_OPENBSD 444#if V8_HOST_ARCH_IA32 445 state.pc = reinterpret_cast<Address>(ucontext->sc_eip); 446 state.sp = reinterpret_cast<Address>(ucontext->sc_esp); 447 state.fp = reinterpret_cast<Address>(ucontext->sc_ebp); 448#elif V8_HOST_ARCH_X64 449 state.pc = reinterpret_cast<Address>(ucontext->sc_rip); 450 state.sp = reinterpret_cast<Address>(ucontext->sc_rsp); 451 state.fp = reinterpret_cast<Address>(ucontext->sc_rbp); 452#endif // V8_HOST_ARCH_* 453#elif V8_OS_SOLARIS 454 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); 455 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); 456 state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); 457#elif V8_OS_QNX 458#if V8_HOST_ARCH_IA32 459 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); 460 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); 461 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); 462#elif V8_HOST_ARCH_ARM 463 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); 464 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); 465 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); 466#endif // V8_HOST_ARCH_* 467#endif // V8_OS_QNX 468#endif // USE_SIMULATOR 469 sampler->SampleStack(state); 470#endif // V8_OS_NACL 471} 472 473#endif 474 475 476class SamplerThread : public Thread { 477 public: 478 static const int kSamplerThreadStackSize = 64 * KB; 479 480 explicit SamplerThread(int interval) 481 : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), 482 interval_(interval) {} 483 484 static void SetUp() { if (!mutex_) mutex_ = new Mutex(); } 485 static void TearDown() { delete mutex_; mutex_ = NULL; } 486 487 static void AddActiveSampler(Sampler* sampler) { 488 bool need_to_start = false; 489 LockGuard<Mutex> lock_guard(mutex_); 490 if (instance_ == NULL) { 491 // Start a thread that will send SIGPROF signal to VM threads, 492 // when CPU profiling will be enabled. 493 instance_ = new SamplerThread(sampler->interval()); 494 need_to_start = true; 495 } 496 497 ASSERT(sampler->IsActive()); 498 ASSERT(!instance_->active_samplers_.Contains(sampler)); 499 ASSERT(instance_->interval_ == sampler->interval()); 500 instance_->active_samplers_.Add(sampler); 501 502 if (need_to_start) instance_->StartSynchronously(); 503 } 504 505 static void RemoveActiveSampler(Sampler* sampler) { 506 SamplerThread* instance_to_remove = NULL; 507 { 508 LockGuard<Mutex> lock_guard(mutex_); 509 510 ASSERT(sampler->IsActive()); 511 bool removed = instance_->active_samplers_.RemoveElement(sampler); 512 ASSERT(removed); 513 USE(removed); 514 515 // We cannot delete the instance immediately as we need to Join() the 516 // thread but we are holding mutex_ and the thread may try to acquire it. 517 if (instance_->active_samplers_.is_empty()) { 518 instance_to_remove = instance_; 519 instance_ = NULL; 520 } 521 } 522 523 if (!instance_to_remove) return; 524 instance_to_remove->Join(); 525 delete instance_to_remove; 526 } 527 528 // Implement Thread::Run(). 529 virtual void Run() { 530 while (true) { 531 { 532 LockGuard<Mutex> lock_guard(mutex_); 533 if (active_samplers_.is_empty()) break; 534 // When CPU profiling is enabled both JavaScript and C++ code is 535 // profiled. We must not suspend. 536 for (int i = 0; i < active_samplers_.length(); ++i) { 537 Sampler* sampler = active_samplers_.at(i); 538 if (!sampler->isolate()->IsInitialized()) continue; 539 if (!sampler->IsProfiling()) continue; 540 sampler->DoSample(); 541 } 542 } 543 OS::Sleep(interval_); 544 } 545 } 546 547 private: 548 // Protects the process wide state below. 549 static Mutex* mutex_; 550 static SamplerThread* instance_; 551 552 const int interval_; 553 List<Sampler*> active_samplers_; 554 555 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 556}; 557 558 559Mutex* SamplerThread::mutex_ = NULL; 560SamplerThread* SamplerThread::instance_ = NULL; 561 562 563// 564// StackTracer implementation 565// 566DISABLE_ASAN void TickSample::Init(Isolate* isolate, 567 const RegisterState& regs) { 568 ASSERT(isolate->IsInitialized()); 569 timestamp = TimeTicks::HighResolutionNow(); 570 pc = regs.pc; 571 state = isolate->current_vm_state(); 572 573 // Avoid collecting traces while doing GC. 574 if (state == GC) return; 575 576 Address js_entry_sp = isolate->js_entry_sp(); 577 if (js_entry_sp == 0) { 578 // Not executing JS now. 579 return; 580 } 581 582 ExternalCallbackScope* scope = isolate->external_callback_scope(); 583 Address handler = Isolate::handler(isolate->thread_local_top()); 584 // If there is a handler on top of the external callback scope then 585 // we have already entrered JavaScript again and the external callback 586 // is not the top function. 587 if (scope && scope->scope_address() < handler) { 588 external_callback = scope->callback(); 589 has_external_callback = true; 590 } else { 591 // Sample potential return address value for frameless invocation of 592 // stubs (we'll figure out later, if this value makes sense). 593 tos = Memory::Address_at(regs.sp); 594 has_external_callback = false; 595 } 596 597 SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp); 598 top_frame_type = it.top_frame_type(); 599 int i = 0; 600 while (!it.done() && i < TickSample::kMaxFramesCount) { 601 stack[i++] = it.frame()->pc(); 602 it.Advance(); 603 } 604 frames_count = i; 605} 606 607 608void Sampler::SetUp() { 609#if defined(USE_SIGNALS) 610 SignalHandler::SetUp(); 611#endif 612 SamplerThread::SetUp(); 613} 614 615 616void Sampler::TearDown() { 617 SamplerThread::TearDown(); 618#if defined(USE_SIGNALS) 619 SignalHandler::TearDown(); 620#endif 621} 622 623 624Sampler::Sampler(Isolate* isolate, int interval) 625 : isolate_(isolate), 626 interval_(interval), 627 profiling_(false), 628 has_processing_thread_(false), 629 active_(false), 630 is_counting_samples_(false), 631 js_and_external_sample_count_(0) { 632 data_ = new PlatformData; 633} 634 635 636Sampler::~Sampler() { 637 ASSERT(!IsActive()); 638 delete data_; 639} 640 641 642void Sampler::Start() { 643 ASSERT(!IsActive()); 644 SetActive(true); 645 SamplerThread::AddActiveSampler(this); 646} 647 648 649void Sampler::Stop() { 650 ASSERT(IsActive()); 651 SamplerThread::RemoveActiveSampler(this); 652 SetActive(false); 653} 654 655 656void Sampler::IncreaseProfilingDepth() { 657 base::NoBarrier_AtomicIncrement(&profiling_, 1); 658#if defined(USE_SIGNALS) 659 SignalHandler::IncreaseSamplerCount(); 660#endif 661} 662 663 664void Sampler::DecreaseProfilingDepth() { 665#if defined(USE_SIGNALS) 666 SignalHandler::DecreaseSamplerCount(); 667#endif 668 base::NoBarrier_AtomicIncrement(&profiling_, -1); 669} 670 671 672void Sampler::SampleStack(const RegisterState& state) { 673 TickSample* sample = isolate_->cpu_profiler()->StartTickSample(); 674 TickSample sample_obj; 675 if (sample == NULL) sample = &sample_obj; 676 sample->Init(isolate_, state); 677 if (is_counting_samples_) { 678 if (sample->state == JS || sample->state == EXTERNAL) { 679 ++js_and_external_sample_count_; 680 } 681 } 682 Tick(sample); 683 if (sample != &sample_obj) { 684 isolate_->cpu_profiler()->FinishTickSample(); 685 } 686} 687 688 689#if defined(USE_SIGNALS) 690 691void Sampler::DoSample() { 692 if (!SignalHandler::Installed()) return; 693 pthread_kill(platform_data()->vm_tid(), SIGPROF); 694} 695 696#elif V8_OS_WIN || V8_OS_CYGWIN 697 698void Sampler::DoSample() { 699 HANDLE profiled_thread = platform_data()->profiled_thread(); 700 if (profiled_thread == NULL) return; 701 702#if defined(USE_SIMULATOR) 703 SimulatorHelper helper; 704 if (!helper.Init(this, isolate())) return; 705#endif 706 707 const DWORD kSuspendFailed = static_cast<DWORD>(-1); 708 if (SuspendThread(profiled_thread) == kSuspendFailed) return; 709 710 // Context used for sampling the register state of the profiled thread. 711 CONTEXT context; 712 memset(&context, 0, sizeof(context)); 713 context.ContextFlags = CONTEXT_FULL; 714 if (GetThreadContext(profiled_thread, &context) != 0) { 715 RegisterState state; 716#if defined(USE_SIMULATOR) 717 helper.FillRegisters(&state); 718#else 719#if V8_HOST_ARCH_X64 720 state.pc = reinterpret_cast<Address>(context.Rip); 721 state.sp = reinterpret_cast<Address>(context.Rsp); 722 state.fp = reinterpret_cast<Address>(context.Rbp); 723#else 724 state.pc = reinterpret_cast<Address>(context.Eip); 725 state.sp = reinterpret_cast<Address>(context.Esp); 726 state.fp = reinterpret_cast<Address>(context.Ebp); 727#endif 728#endif // USE_SIMULATOR 729 SampleStack(state); 730 } 731 ResumeThread(profiled_thread); 732} 733 734#endif // USE_SIGNALS 735 736 737} } // namespace v8::internal 738