sampler.cc 21.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

28 29
#include "sampler.h"

30 31 32
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
    || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \
    || defined(__native_client__)
33 34

#define USE_SIGNALS
35 36 37 38 39 40

#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/syscall.h>
41
#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
42 43
#include <ucontext.h>
#endif
44
#include <unistd.h>
45 46 47

// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
// Old versions of the C library <signal.h> didn't define the type.
48 49
#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
50 51 52
#include <asm/sigcontext.h>
#endif

53 54 55 56 57
#elif defined(__MACH__)

#include <mach/mach.h>

#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
58 59 60 61 62

#include "win32-headers.h"

#endif

63 64
#include "v8.h"

65 66
#include "cpu-profiler.h"
#include "flags.h"
67
#include "frames-inl.h"
68 69 70 71
#include "log.h"
#include "platform.h"
#include "simulator.h"
#include "v8threads.h"
72
#include "vm-state-inl.h"
73 74


75
#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
76 77 78 79 80 81 82 83

// Not all versions of Android's C library provide ucontext_t.
// Detect this and provide custom but compatible definitions. Note that these
// follow the GLibc naming convention to access register values from
// mcontext_t.
//
// See http://code.google.com/p/android/issues/detail?id=34784

84
#if defined(__arm__)
85 86 87 88 89 90 91 92 93 94 95

typedef struct sigcontext mcontext_t;

typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;

96
#elif defined(__mips__)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
// MIPS version of sigcontext, for Android bionic.
typedef struct {
  uint32_t regmask;
  uint32_t status;
  uint64_t pc;
  uint64_t gregs[32];
  uint64_t fpregs[32];
  uint32_t acx;
  uint32_t fpc_csr;
  uint32_t fpc_eir;
  uint32_t used_math;
  uint32_t dsp;
  uint64_t mdhi;
  uint64_t mdlo;
  uint32_t hi1;
  uint32_t lo1;
  uint32_t hi2;
  uint32_t lo2;
  uint32_t hi3;
  uint32_t lo3;
} mcontext_t;

typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;

127
#elif defined(__i386__)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
// x86 version for Android.
typedef struct {
  uint32_t gregs[19];
  void* fpregs;
  uint32_t oldmask;
  uint32_t cr2;
} mcontext_t;

typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;
enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
#endif

147
#endif  // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
148 149


150 151 152
namespace v8 {
namespace internal {

153
namespace {
154

155
class PlatformDataCommon : public Malloced {
156
 public:
157 158 159 160 161 162 163 164 165 166 167
  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
  ThreadId profiled_thread_id() { return profiled_thread_id_; }

 protected:
  ~PlatformDataCommon() {}

 private:
  ThreadId profiled_thread_id_;
};

}  // namespace
168

169 170 171 172 173
#if defined(USE_SIGNALS)

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  PlatformData() : vm_tid_(pthread_self()) {}
174 175 176 177
  pthread_t vm_tid() const { return vm_tid_; }

 private:
  pthread_t vm_tid_;
178 179
};

180
#elif defined(__MACH__)
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  PlatformData() : profiled_thread_(mach_thread_self()) {}

  ~PlatformData() {
    // Deallocate Mach port for thread.
    mach_port_deallocate(mach_task_self(), profiled_thread_);
  }

  thread_act_t profiled_thread() { return profiled_thread_; }

 private:
  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
  // because the latter doesn't provide thread manipulation primitives required.
  // For details, consult "Mac OS X Internals" book, Section 7.3.
  thread_act_t profiled_thread_;
};

200
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

// ----------------------------------------------------------------------------
// Win32 profiler support. On Cygwin we use the same sampler implementation as
// on Win32.

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  // Get a handle to the calling thread. This is the thread that we are
  // going to profile. We need to make a copy of the handle because we are
  // going to use it in the sampler thread. Using GetThreadHandle() will
  // not work in this case. We're using OpenThread because DuplicateHandle
  // for some reason doesn't work in Chrome's sandbox.
  PlatformData()
      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
                                    THREAD_SUSPEND_RESUME |
                                    THREAD_QUERY_INFORMATION,
                                    false,
                                    GetCurrentThreadId())) {}

  ~PlatformData() {
    if (profiled_thread_ != NULL) {
      CloseHandle(profiled_thread_);
      profiled_thread_ = NULL;
    }
  }

  HANDLE profiled_thread() { return profiled_thread_; }

 private:
  HANDLE profiled_thread_;
};
#endif


#if defined(USE_SIMULATOR)
236 237 238
class SimulatorHelper {
 public:
  inline bool Init(Sampler* sampler, Isolate* isolate) {
239 240 241
    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
    Isolate::PerIsolateThreadData* per_thread_data = isolate->
        FindPerThreadDataForThread(thread_id);
242
    if (!per_thread_data) return false;
243
    simulator_ = per_thread_data->simulator();
244 245
    // Check if there is active simulator.
    return simulator_ != NULL;
246 247
  }

248 249 250
  inline void FillRegisters(RegisterState* state) {
    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    state->sp = reinterpret_cast<Address>(simulator_->get_register(
251 252
        Simulator::sp));
#if V8_TARGET_ARCH_ARM
253
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
254 255
        Simulator::r11));
#elif V8_TARGET_ARCH_MIPS
256
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
257 258 259 260 261 262
        Simulator::fp));
#endif
  }

 private:
  Simulator* simulator_;
263
};
264
#endif  // USE_SIMULATOR
265 266


267 268
#if defined(USE_SIGNALS)

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
class SignalHandler : public AllStatic {
 public:
  static inline void EnsureInstalled() {
    if (signal_handler_installed_) return;
    struct sigaction sa;
    sa.sa_sigaction = &HandleProfilerSignal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    signal_handler_installed_ =
        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
  }

  static inline void Restore() {
    if (signal_handler_installed_) {
      sigaction(SIGPROF, &old_signal_handler_, 0);
      signal_handler_installed_ = false;
    }
  }

  static inline bool Installed() {
    return signal_handler_installed_;
  }

 private:
  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
  static bool signal_handler_installed_;
  static struct sigaction old_signal_handler_;
};

struct sigaction SignalHandler::old_signal_handler_;
bool SignalHandler::signal_handler_installed_ = false;


void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
                                         void* context) {
304
#if defined(__native_client__)
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
  // As Native Client does not support signal handling, profiling
  // is disabled.
  return;
#else
  USE(info);
  if (signal != SIGPROF) return;
  Isolate* isolate = Isolate::UncheckedCurrent();
  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
    // We require a fully initialized and entered isolate.
    return;
  }
  if (v8::Locker::IsActive() &&
      !isolate->thread_manager()->IsLockedByCurrentThread()) {
    return;
  }

  Sampler* sampler = isolate->logger()->sampler();
  if (sampler == NULL || !sampler->IsActive()) return;

324
  RegisterState state;
325 326

#if defined(USE_SIMULATOR)
327 328 329
  SimulatorHelper helper;
  if (!helper.Init(sampler, isolate)) return;
  helper.FillRegisters(&state);
330 331 332 333
#else
  // Extracting the sample from the context is extremely machine dependent.
  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
  mcontext_t& mcontext = ucontext->uc_mcontext;
334
#if defined(__linux__) || defined(__ANDROID__)
335
#if V8_HOST_ARCH_IA32
336 337 338
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
339
#elif V8_HOST_ARCH_X64
340 341 342
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
343 344 345 346 347
#elif V8_HOST_ARCH_ARM
#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
  // Old GLibc ARM versions used a gregs[] array to access the register
  // values from mcontext_t.
348 349 350
  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
351
#else
352 353 354
  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
355 356 357
#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
#elif V8_HOST_ARCH_MIPS
358 359 360
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
361
#endif  // V8_HOST_ARCH_*
362
#elif defined(__FreeBSD__)
363
#if V8_HOST_ARCH_IA32
364 365 366
  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
367
#elif V8_HOST_ARCH_X64
368 369 370
  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
371
#elif V8_HOST_ARCH_ARM
372 373 374
  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
375
#endif  // V8_HOST_ARCH_*
376
#elif defined(__NetBSD__)
377
#if V8_HOST_ARCH_IA32
378 379 380
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
381
#elif V8_HOST_ARCH_X64
382 383 384
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
385
#endif  // V8_HOST_ARCH_*
386
#elif defined(__OpenBSD__)
387 388
  USE(mcontext);
#if V8_HOST_ARCH_IA32
389 390 391
  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
392
#elif V8_HOST_ARCH_X64
393 394 395
  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
396
#endif  // V8_HOST_ARCH_*
397
#elif defined(__sun)
398 399 400
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
401
#endif  // __sun
402
#endif  // USE_SIMULATOR
403
  sampler->SampleStack(state);
404 405 406
#endif  // __native_client__
}

407 408 409 410 411 412 413 414 415
#endif


class SamplerThread : public Thread {
 public:
  static const int kSamplerThreadStackSize = 64 * KB;

  explicit SamplerThread(int interval)
      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
416 417
        interval_(interval) {}

418
  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
419 420 421
  static void TearDown() { delete mutex_; }

  static void AddActiveSampler(Sampler* sampler) {
422
    bool need_to_start = false;
423 424 425 426
    ScopedLock lock(mutex_);
    if (instance_ == NULL) {
      // Start a thread that will send SIGPROF signal to VM threads,
      // when CPU profiling will be enabled.
427
      instance_ = new SamplerThread(sampler->interval());
428
      need_to_start = true;
429
    }
430 431 432 433 434 435 436 437 438 439

    ASSERT(sampler->IsActive());
    ASSERT(!instance_->active_samplers_.Contains(sampler));
    ASSERT(instance_->interval_ == sampler->interval());
    instance_->active_samplers_.Add(sampler);

#if defined(USE_SIGNALS)
    SignalHandler::EnsureInstalled();
#endif
    if (need_to_start) instance_->StartSynchronously();
440 441 442
  }

  static void RemoveActiveSampler(Sampler* sampler) {
443 444 445 446 447 448 449 450 451 452 453 454 455 456
    SamplerThread* instance_to_remove = NULL;
    {
      ScopedLock lock(mutex_);

      ASSERT(sampler->IsActive());
      bool removed = instance_->active_samplers_.RemoveElement(sampler);
      ASSERT(removed);
      USE(removed);

      // We cannot delete the instance immediately as we need to Join() the
      // thread but we are holding mutex_ and the thread may try to acquire it.
      if (instance_->active_samplers_.is_empty()) {
        instance_to_remove = instance_;
        instance_ = NULL;
457
#if defined(USE_SIGNALS)
458
        SignalHandler::Restore();
459
#endif
460
      }
461
    }
462 463 464 465

    if (!instance_to_remove) return;
    instance_to_remove->Join();
    delete instance_to_remove;
466 467 468 469
  }

  // Implement Thread::Run().
  virtual void Run() {
470 471 472 473 474 475 476 477 478 479 480 481
    while (true) {
      {
        ScopedLock lock(mutex_);
        if (active_samplers_.is_empty()) break;
        // When CPU profiling is enabled both JavaScript and C++ code is
        // profiled. We must not suspend.
        for (int i = 0; i < active_samplers_.length(); ++i) {
          Sampler* sampler = active_samplers_.at(i);
          if (!sampler->isolate()->IsInitialized()) continue;
          if (!sampler->IsProfiling()) continue;
          SampleContext(sampler);
        }
482
      }
483
      OS::Sleep(interval_);
484 485 486
    }
  }

487
 private:
488
#if defined(USE_SIGNALS)
489

490
  void SampleContext(Sampler* sampler) {
491
    if (!SignalHandler::Installed()) return;
492
    pthread_t tid = sampler->platform_data()->vm_tid();
493
    pthread_kill(tid, SIGPROF);
494 495
  }

496
#elif defined(__MACH__)
497 498 499

  void SampleContext(Sampler* sampler) {
    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
500

501 502
#if defined(USE_SIMULATOR)
    SimulatorHelper helper;
503
    Isolate* isolate = sampler->isolate();
504 505
    if (!helper.Init(sampler, isolate)) return;
#endif
506 507 508 509 510

    if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;

#if V8_HOST_ARCH_X64
    thread_state_flavor_t flavor = x86_THREAD_STATE64;
511
    x86_thread_state64_t thread_state;
512 513 514 515 516 517 518 519
    mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __r ## name
#else
#define REGISTER_FIELD(name) r ## name
#endif  // __DARWIN_UNIX03
#elif V8_HOST_ARCH_IA32
    thread_state_flavor_t flavor = i386_THREAD_STATE;
520
    i386_thread_state_t thread_state;
521 522 523 524 525 526 527 528 529 530 531 532
    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __e ## name
#else
#define REGISTER_FIELD(name) e ## name
#endif  // __DARWIN_UNIX03
#else
#error Unsupported Mac OS X host architecture.
#endif  // V8_HOST_ARCH

    if (thread_get_state(profiled_thread,
                         flavor,
533
                         reinterpret_cast<natural_t*>(&thread_state),
534
                         &count) == KERN_SUCCESS) {
535
      RegisterState state;
536
#if defined(USE_SIMULATOR)
537
      helper.FillRegisters(&state);
538
#else
539 540 541
      state.pc = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(ip));
      state.sp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(sp));
      state.fp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(bp));
542 543
#endif  // USE_SIMULATOR
#undef REGISTER_FIELD
544
      sampler->SampleStack(state);
545 546 547 548
    }
    thread_resume(profiled_thread);
  }

549
#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
550 551 552 553 554 555

  void SampleContext(Sampler* sampler) {
    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
    if (profiled_thread == NULL) return;

    Isolate* isolate = sampler->isolate();
556 557 558 559
#if defined(USE_SIMULATOR)
    SimulatorHelper helper;
    if (!helper.Init(sampler, isolate)) return;
#endif
560

561
    const DWORD kSuspendFailed = static_cast<DWORD>(-1);
562 563
    if (SuspendThread(profiled_thread) == kSuspendFailed) return;

564 565 566
    // Context used for sampling the register state of the profiled thread.
    CONTEXT context;
    memset(&context, 0, sizeof(context));
567 568
    context.ContextFlags = CONTEXT_FULL;
    if (GetThreadContext(profiled_thread, &context) != 0) {
569
      RegisterState state;
570
#if defined(USE_SIMULATOR)
571
      helper.FillRegisters(&state);
572 573
#else
#if V8_HOST_ARCH_X64
574 575 576
      state.pc = reinterpret_cast<Address>(context.Rip);
      state.sp = reinterpret_cast<Address>(context.Rsp);
      state.fp = reinterpret_cast<Address>(context.Rbp);
577
#else
578 579 580
      state.pc = reinterpret_cast<Address>(context.Eip);
      state.sp = reinterpret_cast<Address>(context.Esp);
      state.fp = reinterpret_cast<Address>(context.Ebp);
581 582
#endif
#endif  // USE_SIMULATOR
583
      sampler->SampleStack(state);
584 585 586 587 588 589
    }
    ResumeThread(profiled_thread);
  }

#endif  // USE_SIGNALS

590 591 592

  // Protects the process wide state below.
  static Mutex* mutex_;
593
  static SamplerThread* instance_;
594

595 596 597
  const int interval_;
  List<Sampler*> active_samplers_;

598
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
599 600 601
};


602 603
Mutex* SamplerThread::mutex_ = NULL;
SamplerThread* SamplerThread::instance_ = NULL;
604 605


606 607 608
//
// StackTracer implementation
//
609 610
DISABLE_ASAN void TickSample::Init(Isolate* isolate,
                                   const RegisterState& regs) {
611
  ASSERT(isolate->IsInitialized());
612 613
  pc = regs.pc;
  state = isolate->current_vm_state();
614 615 616 617 618 619 620 621 622 623 624

  // Avoid collecting traces while doing GC.
  if (state == GC) return;

  const Address js_entry_sp =
      Isolate::js_entry_sp(isolate->thread_local_top());
  if (js_entry_sp == 0) {
    // Not executing JS now.
    return;
  }

625 626 627 628 629 630 631
  ExternalCallbackScope* scope = isolate->external_callback_scope();
  Address handler = Isolate::handler(isolate->thread_local_top());
  // If there is a handler on top of the external callback scope then
  // we have already entrered JavaScript again and the external callback
  // is not the top function.
  if (scope && scope->scope_address() < handler) {
    external_callback = scope->callback();
632 633 634 635
    has_external_callback = true;
  } else {
    // Sample potential return address value for frameless invocation of
    // stubs (we'll figure out later, if this value makes sense).
636
    tos = Memory::Address_at(regs.sp);
637 638
    has_external_callback = false;
  }
639

640
  SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
641
  top_frame_type = it.top_frame_type();
642 643 644 645 646 647 648 649 650
  int i = 0;
  while (!it.done() && i < TickSample::kMaxFramesCount) {
    stack[i++] = it.frame()->pc();
    it.Advance();
  }
  frames_count = i;
}


651
void Sampler::SetUp() {
652
  SamplerThread::SetUp();
653 654 655 656
}


void Sampler::TearDown() {
657
  SamplerThread::TearDown();
658 659 660 661 662 663 664 665
}


Sampler::Sampler(Isolate* isolate, int interval)
    : isolate_(isolate),
      interval_(interval),
      profiling_(false),
      active_(false),
666 667
      is_counting_samples_(false),
      js_and_external_sample_count_(0) {
668 669 670 671 672 673 674 675 676
  data_ = new PlatformData;
}


Sampler::~Sampler() {
  ASSERT(!IsActive());
  delete data_;
}

677

678 679 680
void Sampler::Start() {
  ASSERT(!IsActive());
  SetActive(true);
681
  SamplerThread::AddActiveSampler(this);
682 683 684 685 686
}


void Sampler::Stop() {
  ASSERT(IsActive());
687
  SamplerThread::RemoveActiveSampler(this);
688 689 690
  SetActive(false);
}

691

692 693 694 695 696
void Sampler::SampleStack(const RegisterState& state) {
  TickSample* sample = isolate_->cpu_profiler()->TickSampleEvent();
  TickSample sample_obj;
  if (sample == NULL) sample = &sample_obj;
  sample->Init(isolate_, state);
697 698 699 700 701
  if (is_counting_samples_) {
    if (sample->state == JS || sample->state == EXTERNAL) {
      ++js_and_external_sample_count_;
    }
  }
702
  Tick(sample);
703 704 705
}

} }  // namespace v8::internal