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
68 typedef struct sigcontext mcontext_t;
69
70 typedef 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
80 typedef struct sigcontext mcontext_t;
81
82 typedef 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.
92 typedef 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
113 typedef 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.
123 typedef struct {
124 uint32_t gregs[19];
125 void* fpregs;
126 uint32_t oldmask;
127 uint32_t cr2;
128 } mcontext_t;
129
130 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
131 typedef 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;
138 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
139
140 #elif defined(__x86_64__)
141 // x64 version for Android.
142 typedef struct {
143 uint64_t gregs[23];
144 void* fpregs;
145 uint64_t __reserved1[8];
146 } mcontext_t;
147
148 typedef 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;
155 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
156 #endif
157
158 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
159
160
161 namespace v8 {
162 namespace internal {
163
164 namespace {
165
166 class PlatformDataCommon : public Malloced {
167 public:
PlatformDataCommon()168 PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
profiled_thread_id()169 ThreadId profiled_thread_id() { return profiled_thread_id_; }
170
171 protected:
~PlatformDataCommon()172 ~PlatformDataCommon() {}
173
174 private:
175 ThreadId profiled_thread_id_;
176 };
177
178 } // namespace
179
180 #if defined(USE_SIGNALS)
181
182 class Sampler::PlatformData : public PlatformDataCommon {
183 public:
PlatformData()184 PlatformData() : vm_tid_(pthread_self()) {}
vm_tid() const185 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
197 class 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.
PlatformData()204 PlatformData()
205 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
206 THREAD_SUSPEND_RESUME |
207 THREAD_QUERY_INFORMATION,
208 false,
209 GetCurrentThreadId())) {}
210
~PlatformData()211 ~PlatformData() {
212 if (profiled_thread_ != NULL) {
213 CloseHandle(profiled_thread_);
214 profiled_thread_ = NULL;
215 }
216 }
217
profiled_thread()218 HANDLE profiled_thread() { return profiled_thread_; }
219
220 private:
221 HANDLE profiled_thread_;
222 };
223 #endif
224
225
226 #if defined(USE_SIMULATOR)
227 class SimulatorHelper {
228 public:
Init(Sampler * sampler,Isolate * isolate)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
FillRegisters(RegisterState * state)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
270 class SignalHandler : public AllStatic {
271 public:
SetUp()272 static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
TearDown()273 static void TearDown() { delete mutex_; }
274
IncreaseSamplerCount()275 static void IncreaseSamplerCount() {
276 LockGuard<Mutex> lock_guard(mutex_);
277 if (++client_count_ == 1) Install();
278 }
279
DecreaseSamplerCount()280 static void DecreaseSamplerCount() {
281 LockGuard<Mutex> lock_guard(mutex_);
282 if (--client_count_ == 0) Restore();
283 }
284
Installed()285 static bool Installed() {
286 return signal_handler_installed_;
287 }
288
289 private:
Install()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
Restore()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
319 Mutex* SignalHandler::mutex_ = NULL;
320 int SignalHandler::client_count_ = 0;
321 struct sigaction SignalHandler::old_signal_handler_;
322 bool SignalHandler::signal_handler_installed_ = false;
323
324
HandleProfilerSignal(int signal,siginfo_t * info,void * context)325 void 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
476 class SamplerThread : public Thread {
477 public:
478 static const int kSamplerThreadStackSize = 64 * KB;
479
SamplerThread(int interval)480 explicit SamplerThread(int interval)
481 : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
482 interval_(interval) {}
483
SetUp()484 static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
TearDown()485 static void TearDown() { delete mutex_; mutex_ = NULL; }
486
AddActiveSampler(Sampler * sampler)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
RemoveActiveSampler(Sampler * sampler)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().
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
559 Mutex* SamplerThread::mutex_ = NULL;
560 SamplerThread* SamplerThread::instance_ = NULL;
561
562
563 //
564 // StackTracer implementation
565 //
Init(Isolate * isolate,const RegisterState & regs)566 DISABLE_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
SetUp()608 void Sampler::SetUp() {
609 #if defined(USE_SIGNALS)
610 SignalHandler::SetUp();
611 #endif
612 SamplerThread::SetUp();
613 }
614
615
TearDown()616 void Sampler::TearDown() {
617 SamplerThread::TearDown();
618 #if defined(USE_SIGNALS)
619 SignalHandler::TearDown();
620 #endif
621 }
622
623
Sampler(Isolate * isolate,int interval)624 Sampler::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
~Sampler()636 Sampler::~Sampler() {
637 ASSERT(!IsActive());
638 delete data_;
639 }
640
641
Start()642 void Sampler::Start() {
643 ASSERT(!IsActive());
644 SetActive(true);
645 SamplerThread::AddActiveSampler(this);
646 }
647
648
Stop()649 void Sampler::Stop() {
650 ASSERT(IsActive());
651 SamplerThread::RemoveActiveSampler(this);
652 SetActive(false);
653 }
654
655
IncreaseProfilingDepth()656 void Sampler::IncreaseProfilingDepth() {
657 base::NoBarrier_AtomicIncrement(&profiling_, 1);
658 #if defined(USE_SIGNALS)
659 SignalHandler::IncreaseSamplerCount();
660 #endif
661 }
662
663
DecreaseProfilingDepth()664 void Sampler::DecreaseProfilingDepth() {
665 #if defined(USE_SIGNALS)
666 SignalHandler::DecreaseSamplerCount();
667 #endif
668 base::NoBarrier_AtomicIncrement(&profiling_, -1);
669 }
670
671
SampleStack(const RegisterState & state)672 void 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
DoSample()691 void 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
DoSample()698 void 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