v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sampler.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "sampler.h"
29 
30 #if V8_OS_POSIX && !V8_OS_CYGWIN
31 
32 #define USE_SIGNALS
33 
34 #include <errno.h>
35 #include <pthread.h>
36 #include <signal.h>
37 #include <sys/time.h>
38 
39 #if !V8_OS_QNX
40 #include <sys/syscall.h>
41 #endif
42 
43 #if V8_OS_MACOSX
44 #include <mach/mach.h>
45 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
46 // and is a typedef for struct sigcontext. There is no uc_mcontext.
47 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) \
48  && !V8_OS_OPENBSD
49 #include <ucontext.h>
50 #endif
51 
52 #include <unistd.h>
53 
54 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
55 // Old versions of the C library <signal.h> didn't define the type.
56 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
57  (defined(__arm__) || defined(__aarch64__)) && \
58  !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
59 #include <asm/sigcontext.h>
60 #endif
61 
62 #elif V8_OS_WIN || V8_OS_CYGWIN
63 
64 #include "win32-headers.h"
65 
66 #endif
67 
68 #include "v8.h"
69 
70 #include "cpu-profiler-inl.h"
71 #include "flags.h"
72 #include "frames-inl.h"
73 #include "log.h"
74 #include "platform.h"
75 #include "simulator.h"
76 #include "v8threads.h"
77 #include "vm-state-inl.h"
78 
79 
80 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
81 
82 // Not all versions of Android's C library provide ucontext_t.
83 // Detect this and provide custom but compatible definitions. Note that these
84 // follow the GLibc naming convention to access register values from
85 // mcontext_t.
86 //
87 // See http://code.google.com/p/android/issues/detail?id=34784
88 
89 #if defined(__arm__)
90 
91 typedef struct sigcontext mcontext_t;
92 
93 typedef struct ucontext {
94  uint32_t uc_flags;
95  struct ucontext* uc_link;
96  stack_t uc_stack;
97  mcontext_t uc_mcontext;
98  // Other fields are not used by V8, don't define them here.
99 } ucontext_t;
100 
101 #elif defined(__aarch64__)
102 
103 typedef struct sigcontext mcontext_t;
104 
105 typedef struct ucontext {
106  uint64_t uc_flags;
107  struct ucontext *uc_link;
108  stack_t uc_stack;
109  mcontext_t uc_mcontext;
110  // Other fields are not used by V8, don't define them here.
111 } ucontext_t;
112 
113 #elif defined(__mips__)
114 // MIPS version of sigcontext, for Android bionic.
115 typedef struct {
116  uint32_t regmask;
117  uint32_t status;
118  uint64_t pc;
119  uint64_t gregs[32];
120  uint64_t fpregs[32];
121  uint32_t acx;
122  uint32_t fpc_csr;
123  uint32_t fpc_eir;
124  uint32_t used_math;
125  uint32_t dsp;
126  uint64_t mdhi;
127  uint64_t mdlo;
128  uint32_t hi1;
129  uint32_t lo1;
130  uint32_t hi2;
131  uint32_t lo2;
132  uint32_t hi3;
133  uint32_t lo3;
134 } mcontext_t;
135 
136 typedef struct ucontext {
137  uint32_t uc_flags;
138  struct ucontext* uc_link;
139  stack_t uc_stack;
140  mcontext_t uc_mcontext;
141  // Other fields are not used by V8, don't define them here.
142 } ucontext_t;
143 
144 #elif defined(__i386__)
145 // x86 version for Android.
146 typedef struct {
147  uint32_t gregs[19];
148  void* fpregs;
149  uint32_t oldmask;
150  uint32_t cr2;
151 } mcontext_t;
152 
153 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
154 typedef struct ucontext {
155  uint32_t uc_flags;
156  struct ucontext* uc_link;
157  stack_t uc_stack;
158  mcontext_t uc_mcontext;
159  // Other fields are not used by V8, don't define them here.
160 } ucontext_t;
161 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
162 
163 #elif defined(__x86_64__)
164 // x64 version for Android.
165 typedef struct {
166  uint64_t gregs[23];
167  void* fpregs;
168  uint64_t __reserved1[8];
169 } mcontext_t;
170 
171 typedef struct ucontext {
172  uint64_t uc_flags;
173  struct ucontext *uc_link;
174  stack_t uc_stack;
175  mcontext_t uc_mcontext;
176  // Other fields are not used by V8, don't define them here.
177 } ucontext_t;
178 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
179 #endif
180 
181 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
182 
183 
184 namespace v8 {
185 namespace internal {
186 
187 namespace {
188 
189 class PlatformDataCommon : public Malloced {
190  public:
191  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
192  ThreadId profiled_thread_id() { return profiled_thread_id_; }
193 
194  protected:
195  ~PlatformDataCommon() {}
196 
197  private:
199 };
200 
201 } // namespace
202 
203 #if defined(USE_SIGNALS)
204 
205 class Sampler::PlatformData : public PlatformDataCommon {
206  public:
207  PlatformData() : vm_tid_(pthread_self()) {}
208  pthread_t vm_tid() const { return vm_tid_; }
209 
210  private:
211  pthread_t vm_tid_;
212 };
213 
214 #elif V8_OS_WIN || V8_OS_CYGWIN
215 
216 // ----------------------------------------------------------------------------
217 // Win32 profiler support. On Cygwin we use the same sampler implementation as
218 // on Win32.
219 
220 class Sampler::PlatformData : public PlatformDataCommon {
221  public:
222  // Get a handle to the calling thread. This is the thread that we are
223  // going to profile. We need to make a copy of the handle because we are
224  // going to use it in the sampler thread. Using GetThreadHandle() will
225  // not work in this case. We're using OpenThread because DuplicateHandle
226  // for some reason doesn't work in Chrome's sandbox.
227  PlatformData()
228  : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
229  THREAD_SUSPEND_RESUME |
230  THREAD_QUERY_INFORMATION,
231  false,
232  GetCurrentThreadId())) {}
233 
234  ~PlatformData() {
235  if (profiled_thread_ != NULL) {
236  CloseHandle(profiled_thread_);
237  profiled_thread_ = NULL;
238  }
239  }
240 
241  HANDLE profiled_thread() { return profiled_thread_; }
242 
243  private:
244  HANDLE profiled_thread_;
245 };
246 #endif
247 
248 
249 #if defined(USE_SIMULATOR)
250 class SimulatorHelper {
251  public:
252  inline bool Init(Sampler* sampler, Isolate* isolate) {
253  simulator_ = isolate->thread_local_top()->simulator_;
254  // Check if there is active simulator.
255  return simulator_ != NULL;
256  }
257 
258  inline void FillRegisters(RegisterState* state) {
259 #if V8_TARGET_ARCH_ARM
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::r11));
265 #elif V8_TARGET_ARCH_ARM64
266  if (simulator_->sp() == 0 || simulator_->fp() == 0) {
267  // It possible that the simulator is interrupted while it is updating
268  // the sp or fp register. ARM64 simulator does this in two steps:
269  // first setting it to zero and then setting it to the new value.
270  // Bailout if sp/fp doesn't contain the new value.
271  return;
272  }
273  state->pc = reinterpret_cast<Address>(simulator_->pc());
274  state->sp = reinterpret_cast<Address>(simulator_->sp());
275  state->fp = reinterpret_cast<Address>(simulator_->fp());
276 #elif V8_TARGET_ARCH_MIPS
277  state->pc = reinterpret_cast<Address>(simulator_->get_pc());
278  state->sp = reinterpret_cast<Address>(simulator_->get_register(
279  Simulator::sp));
280  state->fp = reinterpret_cast<Address>(simulator_->get_register(
281  Simulator::fp));
282 #endif
283  }
284 
285  private:
286  Simulator* simulator_;
287 };
288 #endif // USE_SIMULATOR
289 
290 
291 #if defined(USE_SIGNALS)
292 
293 class SignalHandler : public AllStatic {
294  public:
295  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
296  static void TearDown() { delete mutex_; }
297 
298  static void IncreaseSamplerCount() {
299  LockGuard<Mutex> lock_guard(mutex_);
300  if (++client_count_ == 1) Install();
301  }
302 
303  static void DecreaseSamplerCount() {
304  LockGuard<Mutex> lock_guard(mutex_);
305  if (--client_count_ == 0) Restore();
306  }
307 
308  static bool Installed() {
309  return signal_handler_installed_;
310  }
311 
312  private:
313  static void Install() {
314  struct sigaction sa;
315  sa.sa_sigaction = &HandleProfilerSignal;
316  sigemptyset(&sa.sa_mask);
317 #if V8_OS_QNX
318  sa.sa_flags = SA_SIGINFO;
319 #else
320  sa.sa_flags = SA_RESTART | SA_SIGINFO;
321 #endif
322  signal_handler_installed_ =
323  (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
324  }
325 
326  static void Restore() {
327  if (signal_handler_installed_) {
328  sigaction(SIGPROF, &old_signal_handler_, 0);
329  signal_handler_installed_ = false;
330  }
331  }
332 
333  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
334  // Protects the process wide state below.
335  static Mutex* mutex_;
336  static int client_count_;
337  static bool signal_handler_installed_;
338  static struct sigaction old_signal_handler_;
339 };
340 
341 
342 Mutex* SignalHandler::mutex_ = NULL;
343 int SignalHandler::client_count_ = 0;
344 struct sigaction SignalHandler::old_signal_handler_;
345 bool SignalHandler::signal_handler_installed_ = false;
346 
347 
348 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
349  void* context) {
350 #if V8_OS_NACL
351  // As Native Client does not support signal handling, profiling
352  // is disabled.
353  return;
354 #else
355  USE(info);
356  if (signal != SIGPROF) return;
357  Isolate* isolate = Isolate::UncheckedCurrent();
358  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
359  // We require a fully initialized and entered isolate.
360  return;
361  }
362  if (v8::Locker::IsActive() &&
363  !isolate->thread_manager()->IsLockedByCurrentThread()) {
364  return;
365  }
366 
367  Sampler* sampler = isolate->logger()->sampler();
368  if (sampler == NULL) return;
369 
370  RegisterState state;
371 
372 #if defined(USE_SIMULATOR)
373  SimulatorHelper helper;
374  if (!helper.Init(sampler, isolate)) return;
375  helper.FillRegisters(&state);
376  // It possible that the simulator is interrupted while it is updating
377  // the sp or fp register. ARM64 simulator does this in two steps:
378  // first setting it to zero and then setting it to the new value.
379  // Bailout if sp/fp doesn't contain the new value.
380  if (state.sp == 0 || state.fp == 0) return;
381 #else
382  // Extracting the sample from the context is extremely machine dependent.
383  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
384 #if !V8_OS_OPENBSD
385  mcontext_t& mcontext = ucontext->uc_mcontext;
386 #endif
387 #if V8_OS_LINUX
388 #if V8_HOST_ARCH_IA32
389  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
390  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
391  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
392 #elif V8_HOST_ARCH_X64
393  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
394  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
395  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
396 #elif V8_HOST_ARCH_ARM
397 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
398  (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
399  // Old GLibc ARM versions used a gregs[] array to access the register
400  // values from mcontext_t.
401  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
402  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
403  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
404 #else
405  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
406  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
407  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
408 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
409  // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
410 #elif V8_HOST_ARCH_ARM64
411  state.pc = reinterpret_cast<Address>(mcontext.pc);
412  state.sp = reinterpret_cast<Address>(mcontext.sp);
413  // FP is an alias for x29.
414  state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
415 #elif V8_HOST_ARCH_MIPS
416  state.pc = reinterpret_cast<Address>(mcontext.pc);
417  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
418  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
419 #endif // V8_HOST_ARCH_*
420 #elif V8_OS_MACOSX
421 #if V8_HOST_ARCH_X64
422 #if __DARWIN_UNIX03
423  state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
424  state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
425  state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
426 #else // !__DARWIN_UNIX03
427  state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
428  state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
429  state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
430 #endif // __DARWIN_UNIX03
431 #elif V8_HOST_ARCH_IA32
432 #if __DARWIN_UNIX03
433  state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
434  state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
435  state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
436 #else // !__DARWIN_UNIX03
437  state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
438  state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
439  state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
440 #endif // __DARWIN_UNIX03
441 #endif // V8_HOST_ARCH_IA32
442 #elif V8_OS_FREEBSD
443 #if V8_HOST_ARCH_IA32
444  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
445  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
446  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
447 #elif V8_HOST_ARCH_X64
448  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
449  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
450  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
451 #elif V8_HOST_ARCH_ARM
452  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
453  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
454  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
455 #endif // V8_HOST_ARCH_*
456 #elif V8_OS_NETBSD
457 #if V8_HOST_ARCH_IA32
458  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
459  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
460  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
461 #elif V8_HOST_ARCH_X64
462  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
463  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
464  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
465 #endif // V8_HOST_ARCH_*
466 #elif V8_OS_OPENBSD
467 #if V8_HOST_ARCH_IA32
468  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
469  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
470  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
471 #elif V8_HOST_ARCH_X64
472  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
473  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
474  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
475 #endif // V8_HOST_ARCH_*
476 #elif V8_OS_SOLARIS
477  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
478  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
479  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
480 #elif V8_OS_QNX
481 #if V8_HOST_ARCH_IA32
482  state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
483  state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
484  state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
485 #elif V8_HOST_ARCH_ARM
486  state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
487  state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
488  state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
489 #endif // V8_HOST_ARCH_*
490 #endif // V8_OS_QNX
491 #endif // USE_SIMULATOR
492  sampler->SampleStack(state);
493 #endif // V8_OS_NACL
494 }
495 
496 #endif
497 
498 
499 class SamplerThread : public Thread {
500  public:
501  static const int kSamplerThreadStackSize = 64 * KB;
502 
503  explicit SamplerThread(int interval)
504  : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
505  interval_(interval) {}
506 
507  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
508  static void TearDown() { delete mutex_; mutex_ = NULL; }
509 
510  static void AddActiveSampler(Sampler* sampler) {
511  bool need_to_start = false;
512  LockGuard<Mutex> lock_guard(mutex_);
513  if (instance_ == NULL) {
514  // Start a thread that will send SIGPROF signal to VM threads,
515  // when CPU profiling will be enabled.
516  instance_ = new SamplerThread(sampler->interval());
517  need_to_start = true;
518  }
519 
520  ASSERT(sampler->IsActive());
521  ASSERT(!instance_->active_samplers_.Contains(sampler));
522  ASSERT(instance_->interval_ == sampler->interval());
523  instance_->active_samplers_.Add(sampler);
524 
525  if (need_to_start) instance_->StartSynchronously();
526  }
527 
528  static void RemoveActiveSampler(Sampler* sampler) {
529  SamplerThread* instance_to_remove = NULL;
530  {
531  LockGuard<Mutex> lock_guard(mutex_);
532 
533  ASSERT(sampler->IsActive());
534  bool removed = instance_->active_samplers_.RemoveElement(sampler);
535  ASSERT(removed);
536  USE(removed);
537 
538  // We cannot delete the instance immediately as we need to Join() the
539  // thread but we are holding mutex_ and the thread may try to acquire it.
540  if (instance_->active_samplers_.is_empty()) {
541  instance_to_remove = instance_;
542  instance_ = NULL;
543  }
544  }
545 
546  if (!instance_to_remove) return;
547  instance_to_remove->Join();
548  delete instance_to_remove;
549  }
550 
551  // Implement Thread::Run().
552  virtual void Run() {
553  while (true) {
554  {
555  LockGuard<Mutex> lock_guard(mutex_);
556  if (active_samplers_.is_empty()) break;
557  // When CPU profiling is enabled both JavaScript and C++ code is
558  // profiled. We must not suspend.
559  for (int i = 0; i < active_samplers_.length(); ++i) {
560  Sampler* sampler = active_samplers_.at(i);
561  if (!sampler->isolate()->IsInitialized()) continue;
562  if (!sampler->IsProfiling()) continue;
563  sampler->DoSample();
564  }
565  }
566  OS::Sleep(interval_);
567  }
568  }
569 
570  private:
571  // Protects the process wide state below.
572  static Mutex* mutex_;
573  static SamplerThread* instance_;
574 
575  const int interval_;
576  List<Sampler*> active_samplers_;
577 
578  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
579 };
580 
581 
582 Mutex* SamplerThread::mutex_ = NULL;
583 SamplerThread* SamplerThread::instance_ = NULL;
584 
585 
586 //
587 // StackTracer implementation
588 //
590  const RegisterState& regs) {
591  ASSERT(isolate->IsInitialized());
592  pc = regs.pc;
593  state = isolate->current_vm_state();
594 
595  // Avoid collecting traces while doing GC.
596  if (state == GC) return;
597 
598  Address js_entry_sp = isolate->js_entry_sp();
599  if (js_entry_sp == 0) {
600  // Not executing JS now.
601  return;
602  }
603 
604  ExternalCallbackScope* scope = isolate->external_callback_scope();
605  Address handler = Isolate::handler(isolate->thread_local_top());
606  // If there is a handler on top of the external callback scope then
607  // we have already entrered JavaScript again and the external callback
608  // is not the top function.
609  if (scope && scope->scope_address() < handler) {
610  external_callback = scope->callback();
611  has_external_callback = true;
612  } else {
613  // Sample potential return address value for frameless invocation of
614  // stubs (we'll figure out later, if this value makes sense).
615  tos = Memory::Address_at(regs.sp);
616  has_external_callback = false;
617  }
618 
619  SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
621  int i = 0;
622  while (!it.done() && i < TickSample::kMaxFramesCount) {
623  stack[i++] = it.frame()->pc();
624  it.Advance();
625  }
626  frames_count = i;
627 }
628 
629 
631 #if defined(USE_SIGNALS)
632  SignalHandler::SetUp();
633 #endif
635 }
636 
637 
640 #if defined(USE_SIGNALS)
641  SignalHandler::TearDown();
642 #endif
643 }
644 
645 
646 Sampler::Sampler(Isolate* isolate, int interval)
647  : isolate_(isolate),
648  interval_(interval),
649  profiling_(false),
650  has_processing_thread_(false),
651  active_(false),
652  is_counting_samples_(false),
653  js_and_external_sample_count_(0) {
654  data_ = new PlatformData;
655 }
656 
657 
659  ASSERT(!IsActive());
660  delete data_;
661 }
662 
663 
665  ASSERT(!IsActive());
666  SetActive(true);
668 }
669 
670 
672  ASSERT(IsActive());
674  SetActive(false);
675 }
676 
677 
679  NoBarrier_AtomicIncrement(&profiling_, 1);
680 #if defined(USE_SIGNALS)
681  SignalHandler::IncreaseSamplerCount();
682 #endif
683 }
684 
685 
687 #if defined(USE_SIGNALS)
688  SignalHandler::DecreaseSamplerCount();
689 #endif
690  NoBarrier_AtomicIncrement(&profiling_, -1);
691 }
692 
693 
695  TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
696  TickSample sample_obj;
697  if (sample == NULL) sample = &sample_obj;
698  sample->Init(isolate_, state);
699  if (is_counting_samples_) {
700  if (sample->state == JS || sample->state == EXTERNAL) {
701  ++js_and_external_sample_count_;
702  }
703  }
704  Tick(sample);
705  if (sample != &sample_obj) {
706  isolate_->cpu_profiler()->FinishTickSample();
707  }
708 }
709 
710 
711 #if defined(USE_SIGNALS)
712 
713 void Sampler::DoSample() {
714  if (!SignalHandler::Installed()) return;
715  pthread_kill(platform_data()->vm_tid(), SIGPROF);
716 }
717 
718 #elif V8_OS_WIN || V8_OS_CYGWIN
719 
720 void Sampler::DoSample() {
721  HANDLE profiled_thread = platform_data()->profiled_thread();
722  if (profiled_thread == NULL) return;
723 
724 #if defined(USE_SIMULATOR)
725  SimulatorHelper helper;
726  if (!helper.Init(this, isolate())) return;
727 #endif
728 
729  const DWORD kSuspendFailed = static_cast<DWORD>(-1);
730  if (SuspendThread(profiled_thread) == kSuspendFailed) return;
731 
732  // Context used for sampling the register state of the profiled thread.
733  CONTEXT context;
734  memset(&context, 0, sizeof(context));
735  context.ContextFlags = CONTEXT_FULL;
736  if (GetThreadContext(profiled_thread, &context) != 0) {
737  RegisterState state;
738 #if defined(USE_SIMULATOR)
739  helper.FillRegisters(&state);
740 #else
741 #if V8_HOST_ARCH_X64
742  state.pc = reinterpret_cast<Address>(context.Rip);
743  state.sp = reinterpret_cast<Address>(context.Rsp);
744  state.fp = reinterpret_cast<Address>(context.Rbp);
745 #else
746  state.pc = reinterpret_cast<Address>(context.Eip);
747  state.sp = reinterpret_cast<Address>(context.Esp);
748  state.fp = reinterpret_cast<Address>(context.Ebp);
749 #endif
750 #endif // USE_SIMULATOR
751  SampleStack(state);
752  }
753  ResumeThread(profiled_thread);
754 }
755 
756 #endif // USE_SIGNALS
757 
758 
759 } } // namespace v8::internal
byte * Address
Definition: globals.h:186
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
static void RemoveActiveSampler(Sampler *sampler)
Definition: sampler.cc:528
static const int kSamplerThreadStackSize
Definition: sampler.cc:501
Address js_entry_sp()
Definition: isolate.h:659
const Register r11
StackFrame::Type top_frame_type() const
Definition: frames.h:923
const int KB
Definition: globals.h:245
static const int kMaxFramesCount
Definition: sampler.h:70
bool IsActive() const
Definition: sampler.h:106
SamplerThread(int interval)
Definition: sampler.cc:503
TickSample * sample
Address external_callback
Definition: sampler.h:68
void DecreaseProfilingDepth()
Definition: sampler.cc:686
static Address handler(ThreadLocalTop *thread)
Definition: isolate.h:651
static void AddActiveSampler(Sampler *sampler)
Definition: sampler.cc:510
#define ASSERT(condition)
Definition: checks.h:329
typedef HANDLE(__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(DWORD dwFlags
int interval() const
Definition: sampler.h:88
typedef DWORD(__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID)
const Register sp
virtual ~Sampler()
Definition: sampler.cc:658
void IncreaseProfilingDepth()
Definition: sampler.cc:678
bool IsProfiling() const
Definition: sampler.h:98
static Address & Address_at(Address addr)
Definition: v8memory.h:79
const Register pc
static bool IsActive()
Definition: v8threads.cc:93
StackFrame::Type top_frame_type
Definition: sampler.h:74
Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, Atomic32 increment)
Address stack[kMaxFramesCount]
Definition: sampler.h:71
static void TearDown()
Definition: sampler.cc:638
static void Sleep(const int milliseconds)
void StartSynchronously()
Definition: platform.h:550
void SampleStack(const RegisterState &regs)
Definition: sampler.cc:694
#define DISABLE_ASAN
Definition: globals.h:393
const CRegister cr2
static void TearDown()
Definition: sampler.cc:508
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function info
Definition: flags.cc:317
CpuProfiler * cpu_profiler() const
Definition: isolate.h:984
static void SetUp()
Definition: sampler.cc:630
void USE(T)
Definition: globals.h:341
void Init(Isolate *isolate, const RegisterState &state)
Definition: sampler.cc:589
Sampler(Isolate *isolate, int interval)
Definition: sampler.cc:646
virtual void Tick(TickSample *sample)=0
const Register fp
PlatformData * platform_data() const
Definition: sampler.h:125
ThreadId profiled_thread_id_
Definition: sampler.cc:198
ThreadLocalTop * thread_local_top()
Definition: isolate.h:879
TickSample * StartTickSample()
Isolate * isolate() const
Definition: sampler.h:87