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 && !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: 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#elif V8_TARGET_ARCH_MIPS64 260 state->pc = reinterpret_cast<Address>(simulator_->get_pc()); 261 state->sp = reinterpret_cast<Address>(simulator_->get_register( 262 Simulator::sp)); 263 state->fp = reinterpret_cast<Address>(simulator_->get_register( 264 Simulator::fp)); 265#endif 266 } 267 268 private: 269 Simulator* simulator_; 270}; 271#endif // USE_SIMULATOR 272 273 274#if defined(USE_SIGNALS) 275 276class SignalHandler : public AllStatic { 277 public: 278 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 279 static void TearDown() { delete mutex_; mutex_ = NULL; } 280 281 static void IncreaseSamplerCount() { 282 base::LockGuard<base::Mutex> lock_guard(mutex_); 283 if (++client_count_ == 1) Install(); 284 } 285 286 static void DecreaseSamplerCount() { 287 base::LockGuard<base::Mutex> lock_guard(mutex_); 288 if (--client_count_ == 0) Restore(); 289 } 290 291 static bool Installed() { 292 return signal_handler_installed_; 293 } 294 295 private: 296 static void Install() { 297#if !V8_OS_NACL 298 struct sigaction sa; 299 sa.sa_sigaction = &HandleProfilerSignal; 300 sigemptyset(&sa.sa_mask); 301#if V8_OS_QNX 302 sa.sa_flags = SA_SIGINFO; 303#else 304 sa.sa_flags = SA_RESTART | SA_SIGINFO; 305#endif 306 signal_handler_installed_ = 307 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 308#endif 309 } 310 311 static void Restore() { 312#if !V8_OS_NACL 313 if (signal_handler_installed_) { 314 sigaction(SIGPROF, &old_signal_handler_, 0); 315 signal_handler_installed_ = false; 316 } 317#endif 318 } 319 320#if !V8_OS_NACL 321 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); 322#endif 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_; 328}; 329 330 331base::Mutex* SignalHandler::mutex_ = NULL; 332int SignalHandler::client_count_ = 0; 333struct sigaction SignalHandler::old_signal_handler_; 334bool SignalHandler::signal_handler_installed_ = false; 335 336 337// As Native Client does not support signal handling, profiling is disabled. 338#if !V8_OS_NACL 339void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 340 void* context) { 341 USE(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. 346 return; 347 } 348 if (v8::Locker::IsActive() && 349 !isolate->thread_manager()->IsLockedByCurrentThread()) { 350 return; 351 } 352 353 Sampler* sampler = isolate->logger()->sampler(); 354 if (sampler == NULL) return; 355 356 RegisterState state; 357 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; 367#else 368 // Extracting the sample from the context is extremely machine dependent. 369 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 370#if !V8_OS_OPENBSD 371 mcontext_t& mcontext = ucontext->uc_mcontext; 372#endif 373#if V8_OS_LINUX 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]); 390#else 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_* 410#elif V8_OS_MACOSX 411#if V8_HOST_ARCH_X64 412#if __DARWIN_UNIX03 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 422#if __DARWIN_UNIX03 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 432#elif V8_OS_FREEBSD 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_* 446#elif V8_OS_NETBSD 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_* 456#elif V8_OS_OPENBSD 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_* 466#elif V8_OS_SOLARIS 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]); 470#elif V8_OS_QNX 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_* 480#endif // V8_OS_QNX 481#endif // USE_SIMULATOR 482 sampler->SampleStack(state); 483} 484#endif // V8_OS_NACL 485 486#endif 487 488 489class SamplerThread : public base::Thread { 490 public: 491 static const int kSamplerThreadStackSize = 64 * KB; 492 493 explicit SamplerThread(int interval) 494 : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)), 495 interval_(interval) {} 496 497 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 498 static void TearDown() { delete mutex_; mutex_ = NULL; } 499 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; 508 } 509 510 DCHECK(sampler->IsActive()); 511 DCHECK(!instance_->active_samplers_.Contains(sampler)); 512 DCHECK(instance_->interval_ == sampler->interval()); 513 instance_->active_samplers_.Add(sampler); 514 515 if (need_to_start) instance_->StartSynchronously(); 516 } 517 518 static void RemoveActiveSampler(Sampler* sampler) { 519 SamplerThread* instance_to_remove = NULL; 520 { 521 base::LockGuard<base::Mutex> lock_guard(mutex_); 522 523 DCHECK(sampler->IsActive()); 524 bool removed = instance_->active_samplers_.RemoveElement(sampler); 525 DCHECK(removed); 526 USE(removed); 527 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_; 532 instance_ = NULL; 533 } 534 } 535 536 if (!instance_to_remove) return; 537 instance_to_remove->Join(); 538 delete instance_to_remove; 539 } 540 541 // Implement Thread::Run(). 542 virtual void Run() { 543 while (true) { 544 { 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; 553 sampler->DoSample(); 554 } 555 } 556 base::OS::Sleep(interval_); 557 } 558 } 559 560 private: 561 // Protects the process wide state below. 562 static base::Mutex* mutex_; 563 static SamplerThread* instance_; 564 565 const int interval_; 566 List<Sampler*> active_samplers_; 567 568 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 569}; 570 571 572base::Mutex* SamplerThread::mutex_ = NULL; 573SamplerThread* SamplerThread::instance_ = NULL; 574 575 576// 577// StackTracer implementation 578// 579DISABLE_ASAN void TickSample::Init(Isolate* isolate, 580 const RegisterState& regs) { 581 DCHECK(isolate->IsInitialized()); 582 timestamp = base::TimeTicks::HighResolutionNow(); 583 pc = regs.pc; 584 state = isolate->current_vm_state(); 585 586 // Avoid collecting traces while doing GC. 587 if (state == GC) return; 588 589 Address js_entry_sp = isolate->js_entry_sp(); 590 if (js_entry_sp == 0) { 591 // Not executing JS now. 592 return; 593 } 594 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; 603 } else { 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; 608 } 609 610 SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp); 611 top_frame_type = it.top_frame_type(); 612 unsigned i = 0; 613 while (!it.done() && i < TickSample::kMaxFramesCount) { 614 stack[i++] = it.frame()->pc(); 615 it.Advance(); 616 } 617 frames_count = i; 618} 619 620 621void Sampler::SetUp() { 622#if defined(USE_SIGNALS) 623 SignalHandler::SetUp(); 624#endif 625 SamplerThread::SetUp(); 626} 627 628 629void Sampler::TearDown() { 630 SamplerThread::TearDown(); 631#if defined(USE_SIGNALS) 632 SignalHandler::TearDown(); 633#endif 634} 635 636 637Sampler::Sampler(Isolate* isolate, int interval) 638 : isolate_(isolate), 639 interval_(interval), 640 profiling_(false), 641 has_processing_thread_(false), 642 active_(false), 643 is_counting_samples_(false), 644 js_and_external_sample_count_(0) { 645 data_ = new PlatformData; 646} 647 648 649Sampler::~Sampler() { 650 DCHECK(!IsActive()); 651 delete data_; 652} 653 654 655void Sampler::Start() { 656 DCHECK(!IsActive()); 657 SetActive(true); 658 SamplerThread::AddActiveSampler(this); 659} 660 661 662void Sampler::Stop() { 663 DCHECK(IsActive()); 664 SamplerThread::RemoveActiveSampler(this); 665 SetActive(false); 666} 667 668 669void Sampler::IncreaseProfilingDepth() { 670 base::NoBarrier_AtomicIncrement(&profiling_, 1); 671#if defined(USE_SIGNALS) 672 SignalHandler::IncreaseSamplerCount(); 673#endif 674} 675 676 677void Sampler::DecreaseProfilingDepth() { 678#if defined(USE_SIGNALS) 679 SignalHandler::DecreaseSamplerCount(); 680#endif 681 base::NoBarrier_AtomicIncrement(&profiling_, -1); 682} 683 684 685void 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_; 693 } 694 } 695 Tick(sample); 696 if (sample != &sample_obj) { 697 isolate_->cpu_profiler()->FinishTickSample(); 698 } 699} 700 701 702#if defined(USE_SIGNALS) 703 704void Sampler::DoSample() { 705 if (!SignalHandler::Installed()) return; 706 pthread_kill(platform_data()->vm_tid(), SIGPROF); 707} 708 709#elif V8_OS_WIN || V8_OS_CYGWIN 710 711void Sampler::DoSample() { 712 HANDLE profiled_thread = platform_data()->profiled_thread(); 713 if (profiled_thread == NULL) return; 714 715#if defined(USE_SIMULATOR) 716 SimulatorHelper helper; 717 if (!helper.Init(this, isolate())) return; 718#endif 719 720 const DWORD kSuspendFailed = static_cast<DWORD>(-1); 721 if (SuspendThread(profiled_thread) == kSuspendFailed) return; 722 723 // Context used for sampling the register state of the profiled thread. 724 CONTEXT context; 725 memset(&context, 0, sizeof(context)); 726 context.ContextFlags = CONTEXT_FULL; 727 if (GetThreadContext(profiled_thread, &context) != 0) { 728 RegisterState state; 729#if defined(USE_SIMULATOR) 730 helper.FillRegisters(&state); 731#else 732#if V8_HOST_ARCH_X64 733 state.pc = reinterpret_cast<Address>(context.Rip); 734 state.sp = reinterpret_cast<Address>(context.Rsp); 735 state.fp = reinterpret_cast<Address>(context.Rbp); 736#else 737 state.pc = reinterpret_cast<Address>(context.Eip); 738 state.sp = reinterpret_cast<Address>(context.Esp); 739 state.fp = reinterpret_cast<Address>(context.Ebp); 740#endif 741#endif // USE_SIMULATOR 742 SampleStack(state); 743 } 744 ResumeThread(profiled_thread); 745} 746 747#endif // USE_SIGNALS 748 749 750} } // namespace v8::internal 751