OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | |
5 #include "src/sampler.h" | 4 #include "src/sampler.h" |
6 | 5 |
7 #if V8_OS_POSIX && !V8_OS_CYGWIN | 6 #if V8_OS_POSIX && !V8_OS_CYGWIN |
8 | 7 |
9 #define USE_SIGNALS | 8 #define USE_SIGNALS |
10 | 9 |
11 #include <errno.h> | 10 #include <errno.h> |
12 #include <pthread.h> | 11 #include <pthread.h> |
13 #include <signal.h> | 12 #include <signal.h> |
14 #include <sys/time.h> | 13 #include <sys/time.h> |
(...skipping 20 matching lines...) Expand all Loading... | |
35 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) | 34 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) |
36 #include <asm/sigcontext.h> // NOLINT | 35 #include <asm/sigcontext.h> // NOLINT |
37 #endif | 36 #endif |
38 | 37 |
39 #elif V8_OS_WIN || V8_OS_CYGWIN | 38 #elif V8_OS_WIN || V8_OS_CYGWIN |
40 | 39 |
41 #include "src/base/win32-headers.h" | 40 #include "src/base/win32-headers.h" |
42 | 41 |
43 #endif | 42 #endif |
44 | 43 |
44 #include "include/v8-sampler.h" | |
45 | |
45 #include "src/v8.h" | 46 #include "src/v8.h" |
46 | 47 |
47 #include "src/base/platform/platform.h" | 48 #include "src/base/platform/platform.h" |
48 #include "src/cpu-profiler-inl.h" | 49 #include "src/cpu-profiler-inl.h" |
49 #include "src/flags.h" | 50 #include "src/flags.h" |
50 #include "src/frames-inl.h" | 51 #include "src/frames-inl.h" |
51 #include "src/log.h" | 52 #include "src/log.h" |
52 #include "src/simulator.h" | 53 #include "src/simulator.h" |
53 #include "src/v8threads.h" | 54 #include "src/v8threads.h" |
54 #include "src/vm-state-inl.h" | 55 #include "src/vm-state-inl.h" |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
262 private: | 263 private: |
263 Simulator* simulator_; | 264 Simulator* simulator_; |
264 }; | 265 }; |
265 #endif // USE_SIMULATOR | 266 #endif // USE_SIMULATOR |
266 | 267 |
267 | 268 |
268 #if defined(USE_SIGNALS) | 269 #if defined(USE_SIGNALS) |
269 | 270 |
270 class SignalHandler : public AllStatic { | 271 class SignalHandler : public AllStatic { |
271 public: | 272 public: |
272 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 273 static void SetUp() { |
273 static void TearDown() { delete mutex_; } | 274 if (!mutex_) mutex_ = new base::Mutex(); |
275 if (!sampling_semaphore_) | |
276 sampling_semaphore_ = new base::Semaphore(0); | |
277 } | |
278 | |
279 static void TearDown() { | |
280 delete mutex_; | |
281 delete sampling_semaphore_; | |
282 } | |
274 | 283 |
275 static void IncreaseSamplerCount() { | 284 static void IncreaseSamplerCount() { |
276 base::LockGuard<base::Mutex> lock_guard(mutex_); | 285 base::LockGuard<base::Mutex> lock_guard(mutex_); |
277 if (++client_count_ == 1) Install(); | 286 if (++client_count_ == 1) Install(); |
278 } | 287 } |
279 | 288 |
280 static void DecreaseSamplerCount() { | 289 static void DecreaseSamplerCount() { |
281 base::LockGuard<base::Mutex> lock_guard(mutex_); | 290 base::LockGuard<base::Mutex> lock_guard(mutex_); |
282 if (--client_count_ == 0) Restore(); | 291 if (--client_count_ == 0) Restore(); |
283 } | 292 } |
(...skipping 17 matching lines...) Expand all Loading... | |
301 } | 310 } |
302 | 311 |
303 static void Restore() { | 312 static void Restore() { |
304 if (signal_handler_installed_) { | 313 if (signal_handler_installed_) { |
305 sigaction(SIGPROF, &old_signal_handler_, 0); | 314 sigaction(SIGPROF, &old_signal_handler_, 0); |
306 signal_handler_installed_ = false; | 315 signal_handler_installed_ = false; |
307 } | 316 } |
308 } | 317 } |
309 | 318 |
310 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 319 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); |
320 | |
321 // The SIGPROF could have come from DoSample or from GetSample. | |
322 // GetSample is the internal endpoint for the public | |
323 // GetSample API, which aims to bypass all the internal buffers | |
324 // and return just one sample instead, rightaway. | |
325 // TODO(gholap): Eventually, get rid of DoSample. | |
326 // Only GetSample should remain. | |
327 | |
328 // This is the sample which will be filled by the call from GetSample. | |
329 static TickSample sample_; | |
330 | |
331 // For the SIGPROF handler to know whether the call was from GetSample. | |
332 static bool called_from_get_sample_; | |
333 | |
334 // GetSample waits synchronously till the SIGPROF handler returns. | |
335 // this semaphore is used to signal GetSample. | |
336 static base::Semaphore* sampling_semaphore_; | |
337 | |
338 // It is not that every time HandleProfilerSignal is invoked, | |
339 // it succeeds in obtaining a sample. | |
340 // This provides GetSample with the information whether | |
341 // the handler finished with or without getting the sample. | |
342 static bool sample_available_; | |
343 | |
311 // Protects the process wide state below. | 344 // Protects the process wide state below. |
312 static base::Mutex* mutex_; | 345 static base::Mutex* mutex_; |
313 static int client_count_; | 346 static int client_count_; |
314 static bool signal_handler_installed_; | 347 static bool signal_handler_installed_; |
315 static struct sigaction old_signal_handler_; | 348 static struct sigaction old_signal_handler_; |
349 | |
350 friend class Sampler; | |
316 }; | 351 }; |
317 | 352 |
318 | 353 |
354 TickSample SignalHandler::sample_; | |
355 bool SignalHandler::called_from_get_sample_ = false; | |
356 base::Semaphore* SignalHandler::sampling_semaphore_ = NULL; | |
357 bool SignalHandler::sample_available_ = false; | |
358 | |
319 base::Mutex* SignalHandler::mutex_ = NULL; | 359 base::Mutex* SignalHandler::mutex_ = NULL; |
320 int SignalHandler::client_count_ = 0; | 360 int SignalHandler::client_count_ = 0; |
321 struct sigaction SignalHandler::old_signal_handler_; | 361 struct sigaction SignalHandler::old_signal_handler_; |
322 bool SignalHandler::signal_handler_installed_ = false; | 362 bool SignalHandler::signal_handler_installed_ = false; |
323 | 363 |
324 | 364 |
325 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 365 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
326 void* context) { | 366 void* context) { |
327 #if V8_OS_NACL | 367 #if V8_OS_NACL |
328 // As Native Client does not support signal handling, profiling | 368 // As Native Client does not support signal handling, profiling |
329 // is disabled. | 369 // is disabled. |
330 return; | 370 return; |
331 #else | 371 #else |
372 | |
373 // Even if we return from the signal handler without | |
374 // successfully getting a sampler, the caller of GetSample | |
375 // needs to know that the signal handler's work is finished. | |
376 // Otherwise, the caller will synchronously wait indefinitely. | |
377 // Also, the caller should have a way of knowing whether the | |
378 // signal handler successfully collected a sample or not. | |
379 #define SIGNAL_AND_RETURN(GOT_NEW) \ | |
380 { \ | |
381 sample_available_ = GOT_NEW; \ | |
382 sampling_semaphore_->Signal(); \ | |
383 return; \ | |
Yang
2014/08/12 14:21:36
Using a scope, which signals in its destructor, se
gholap
2014/08/13 21:09:21
Done.
| |
384 } | |
385 | |
332 USE(info); | 386 USE(info); |
333 if (signal != SIGPROF) return; | 387 if (signal != SIGPROF) SIGNAL_AND_RETURN(false); |
334 Isolate* isolate = Isolate::UncheckedReentrantCurrent(); | 388 Isolate* isolate = Isolate::UncheckedReentrantCurrent(); |
335 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { | 389 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
336 // We require a fully initialized and entered isolate. | 390 // We require a fully initialized and entered isolate. |
337 return; | 391 SIGNAL_AND_RETURN(false); |
338 } | 392 } |
339 if (v8::Locker::IsActive() && | 393 if (v8::Locker::IsActive() && |
340 !isolate->thread_manager()->IsLockedByCurrentThread()) { | 394 !isolate->thread_manager()->IsLockedByCurrentThread()) { |
341 return; | 395 SIGNAL_AND_RETURN(false); |
342 } | 396 } |
343 | 397 |
344 Sampler* sampler = isolate->logger()->sampler(); | 398 Sampler* sampler = isolate->logger()->sampler(); |
345 if (sampler == NULL) return; | 399 if (sampler == NULL) SIGNAL_AND_RETURN(false); |
346 | 400 |
347 RegisterState state; | 401 RegisterState state; |
348 | 402 |
349 #if defined(USE_SIMULATOR) | 403 #if defined(USE_SIMULATOR) |
350 SimulatorHelper helper; | 404 SimulatorHelper helper; |
351 if (!helper.Init(sampler, isolate)) return; | 405 if (!helper.Init(sampler, isolate)) SIGNAL_AND_RETURN(false); |
352 helper.FillRegisters(&state); | 406 helper.FillRegisters(&state); |
353 // It possible that the simulator is interrupted while it is updating | 407 // It possible that the simulator is interrupted while it is updating |
354 // the sp or fp register. ARM64 simulator does this in two steps: | 408 // 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. | 409 // first setting it to zero and then setting it to the new value. |
356 // Bailout if sp/fp doesn't contain the new value. | 410 // Bailout if sp/fp doesn't contain the new value. |
357 if (state.sp == 0 || state.fp == 0) return; | 411 if (state.sp == 0 || state.fp == 0) SIGNAL_AND_RETURN(false); |
358 #else | 412 #else |
359 // Extracting the sample from the context is extremely machine dependent. | 413 // Extracting the sample from the context is extremely machine dependent. |
360 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 414 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
361 #if !V8_OS_OPENBSD | 415 #if !V8_OS_OPENBSD |
362 mcontext_t& mcontext = ucontext->uc_mcontext; | 416 mcontext_t& mcontext = ucontext->uc_mcontext; |
363 #endif | 417 #endif |
364 #if V8_OS_LINUX | 418 #if V8_OS_LINUX |
365 #if V8_HOST_ARCH_IA32 | 419 #if V8_HOST_ARCH_IA32 |
366 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); | 420 state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); |
367 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); | 421 state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); | 513 state.pc = reinterpret_cast<Address>(mcontext.cpu.eip); |
460 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); | 514 state.sp = reinterpret_cast<Address>(mcontext.cpu.esp); |
461 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); | 515 state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp); |
462 #elif V8_HOST_ARCH_ARM | 516 #elif V8_HOST_ARCH_ARM |
463 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); | 517 state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]); |
464 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); | 518 state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]); |
465 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); | 519 state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]); |
466 #endif // V8_HOST_ARCH_* | 520 #endif // V8_HOST_ARCH_* |
467 #endif // V8_OS_QNX | 521 #endif // V8_OS_QNX |
468 #endif // USE_SIMULATOR | 522 #endif // USE_SIMULATOR |
469 sampler->SampleStack(state); | 523 if (called_from_get_sample_) { |
524 sample_.Init(sampler->isolate(), state); | |
525 } else { | |
526 sampler->SampleStack(state); | |
527 } | |
528 SIGNAL_AND_RETURN(true); | |
529 #undef SIGNAL_AND_RETURN | |
470 #endif // V8_OS_NACL | 530 #endif // V8_OS_NACL |
471 } | 531 } |
472 | 532 |
473 #endif | 533 #endif |
474 | 534 |
475 | 535 |
476 class SamplerThread : public base::Thread { | 536 class SamplerThread : public base::Thread { |
477 public: | 537 public: |
478 static const int kSamplerThreadStackSize = 64 * KB; | 538 static const int kSamplerThreadStackSize = 64 * KB; |
479 | 539 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
686 } | 746 } |
687 | 747 |
688 | 748 |
689 #if defined(USE_SIGNALS) | 749 #if defined(USE_SIGNALS) |
690 | 750 |
691 void Sampler::DoSample() { | 751 void Sampler::DoSample() { |
692 if (!SignalHandler::Installed()) return; | 752 if (!SignalHandler::Installed()) return; |
693 pthread_kill(platform_data()->vm_tid(), SIGPROF); | 753 pthread_kill(platform_data()->vm_tid(), SIGPROF); |
694 } | 754 } |
695 | 755 |
756 | |
757 TickSample* Sampler::GetSample(TickSample* sample) { | |
758 if (!SignalHandler::Installed()) return NULL; | |
759 SignalHandler::called_from_get_sample_ = true; | |
Yang
2014/08/12 14:21:36
Don't we need a memory barrier here? Is it guarant
Benedikt Meurer
2014/08/13 06:29:11
At the very least, this has to be volatile.
gholap
2014/08/13 21:09:21
Done.
gholap
2014/08/13 21:09:21
Yes. Made it volatile.
This would just be a transi
| |
760 pthread_kill(platform_data()->vm_tid(), SIGPROF); | |
761 SignalHandler::sampling_semaphore_->Wait(); | |
762 if (SignalHandler::sample_available_) { | |
763 sample->state = SignalHandler::sample_.state; | |
Yang
2014/08/12 14:21:36
Why doesn't GetSample simply set a static pointer
gholap
2014/08/13 21:09:21
Let's call the code that uses the API as "consumer
| |
764 for (int i = 0; i < SignalHandler::sample_.frames_count; i++) { | |
765 sample->stack[i] = SignalHandler::sample_.stack[i]; | |
766 } | |
767 sample->frames_count = SignalHandler::sample_.frames_count; | |
768 } else { | |
769 sample = NULL; | |
770 } | |
771 SignalHandler::called_from_get_sample_ = false; | |
772 return sample; | |
773 } | |
774 | |
696 #elif V8_OS_WIN || V8_OS_CYGWIN | 775 #elif V8_OS_WIN || V8_OS_CYGWIN |
697 | 776 |
698 void Sampler::DoSample() { | 777 TickSample* Sampler::GetSampleHelper_(TickSample * sample, |
Yang
2014/08/12 14:21:36
Please omit that _ in the method name.
gholap
2014/08/13 21:09:21
Done.
| |
778 bool called_from_get_sample) { | |
699 HANDLE profiled_thread = platform_data()->profiled_thread(); | 779 HANDLE profiled_thread = platform_data()->profiled_thread(); |
700 if (profiled_thread == NULL) return; | 780 if (profiled_thread == NULL) return NULL; |
701 | 781 |
702 #if defined(USE_SIMULATOR) | 782 #if defined(USE_SIMULATOR) |
703 SimulatorHelper helper; | 783 SimulatorHelper helper; |
704 if (!helper.Init(this, isolate())) return; | 784 if (!helper.Init(this, isolate())) return NULL; |
705 #endif | 785 #endif |
706 | 786 |
707 const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 787 const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
708 if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 788 if (SuspendThread(profiled_thread) == kSuspendFailed) return NULL; |
709 | 789 |
710 // Context used for sampling the register state of the profiled thread. | 790 // Context used for sampling the register state of the profiled thread. |
711 CONTEXT context; | 791 CONTEXT context; |
712 memset(&context, 0, sizeof(context)); | 792 memset(&context, 0, sizeof(context)); |
713 context.ContextFlags = CONTEXT_FULL; | 793 context.ContextFlags = CONTEXT_FULL; |
714 if (GetThreadContext(profiled_thread, &context) != 0) { | 794 if (GetThreadContext(profiled_thread, &context) != 0) { |
715 RegisterState state; | 795 RegisterState state; |
716 #if defined(USE_SIMULATOR) | 796 #if defined(USE_SIMULATOR) |
717 helper.FillRegisters(&state); | 797 helper.FillRegisters(&state); |
718 #else | 798 #else |
719 #if V8_HOST_ARCH_X64 | 799 #if V8_HOST_ARCH_X64 |
720 state.pc = reinterpret_cast<Address>(context.Rip); | 800 state.pc = reinterpret_cast<Address>(context.Rip); |
721 state.sp = reinterpret_cast<Address>(context.Rsp); | 801 state.sp = reinterpret_cast<Address>(context.Rsp); |
722 state.fp = reinterpret_cast<Address>(context.Rbp); | 802 state.fp = reinterpret_cast<Address>(context.Rbp); |
723 #else | 803 #else |
724 state.pc = reinterpret_cast<Address>(context.Eip); | 804 state.pc = reinterpret_cast<Address>(context.Eip); |
725 state.sp = reinterpret_cast<Address>(context.Esp); | 805 state.sp = reinterpret_cast<Address>(context.Esp); |
726 state.fp = reinterpret_cast<Address>(context.Ebp); | 806 state.fp = reinterpret_cast<Address>(context.Ebp); |
727 #endif | 807 #endif |
728 #endif // USE_SIMULATOR | 808 #endif // USE_SIMULATOR |
729 SampleStack(state); | 809 if (called_from_get_sample) { |
810 sample->Init(sampler->isolate(), state); | |
811 } else { | |
812 SampleStack(state); | |
813 } | |
730 } | 814 } |
731 ResumeThread(profiled_thread); | 815 ResumeThread(profiled_thread); |
816 return sample; | |
817 } | |
818 | |
819 | |
820 void Sampler::DoSample() { | |
821 GetSampleHelper_(NULL, false); | |
822 } | |
823 | |
824 | |
825 TickSample* Sampler::GetSample(TickSample* sample) { | |
826 return GetSampleHelper_(sample, true); | |
732 } | 827 } |
733 | 828 |
734 #endif // USE_SIGNALS | 829 #endif // USE_SIGNALS |
735 | 830 |
736 | 831 |
737 } } // namespace v8::internal | 832 } } // namespace v8::internal |
OLD | NEW |