 Chromium Code Reviews
 Chromium Code Reviews Issue 422593003:
  Initial GetSample implementation.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 422593003:
  Initial GetSample implementation.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/sampler.cc | 
| diff --git a/src/sampler.cc b/src/sampler.cc | 
| index 0ed4b379626a9746038b6e05b1661cee522f4f1f..c0b25f102bbb5856f6d87856ce5e6130e192a74c 100644 | 
| --- a/src/sampler.cc | 
| +++ b/src/sampler.cc | 
| @@ -1,7 +1,6 @@ | 
| // Copyright 2013 the V8 project authors. All rights reserved. | 
| // Use of this source code is governed by a BSD-style license that can be | 
| // found in the LICENSE file. | 
| - | 
| #include "src/sampler.h" | 
| #if V8_OS_POSIX && !V8_OS_CYGWIN | 
| @@ -44,6 +43,7 @@ | 
| #include "src/v8.h" | 
| +#include "src/base/logging.h" | 
| #include "src/base/platform/platform.h" | 
| #include "src/cpu-profiler-inl.h" | 
| #include "src/flags.h" | 
| @@ -269,8 +269,21 @@ class SimulatorHelper { | 
| class SignalHandler : public AllStatic { | 
| public: | 
| - static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } | 
| - static void TearDown() { delete mutex_; } | 
| + static void SetUp() { | 
| + ASSERT_EQ(NULL, mutex_); | 
| + ASSERT_EQ(NULL, sampling_semaphore_); | 
| + | 
| + mutex_ = new base::Mutex(); | 
| + sampling_semaphore_ = new base::Semaphore(0); | 
| + } | 
| + | 
| + static void TearDown() { | 
| + delete mutex_; | 
| + delete sampling_semaphore_; | 
| + | 
| + mutex_ = NULL; | 
| + sampling_semaphore_ = NULL; | 
| + } | 
| static void IncreaseSamplerCount() { | 
| base::LockGuard<base::Mutex> lock_guard(mutex_); | 
| @@ -308,14 +321,45 @@ class SignalHandler : public AllStatic { | 
| } | 
| static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); | 
| + | 
| + // The SIGPROF could have come from DoSample or from GetSample. | 
| + // GetSample is the internal endpoint for the public | 
| + // GetSample API, which aims to bypass all the internal buffers | 
| + // and return just one sample instead, rightaway. | 
| + // TODO(gholap): Eventually, get rid of DoSample. | 
| + // Only GetSample should remain. | 
| + | 
| + // This is the sample which will be filled by the call from GetSample. | 
| + static TickSample sample_; | 
| + | 
| + // For the SIGPROF handler to know whether the call was from GetSample. | 
| + static volatile bool called_from_get_sample_; | 
| + | 
| + // GetSample waits synchronously till the SIGPROF handler returns. | 
| + // this semaphore is used to signal GetSample. | 
| + static base::Semaphore* sampling_semaphore_; | 
| + | 
| + // It is not that every time HandleProfilerSignal is invoked, | 
| + // it succeeds in obtaining a sample. | 
| + // This provides GetSample with the information whether | 
| + // the handler finished with or without getting the sample. | 
| + static bool sample_available_; | 
| + | 
| // Protects the process wide state below. | 
| static base::Mutex* mutex_; | 
| static int client_count_; | 
| static bool signal_handler_installed_; | 
| static struct sigaction old_signal_handler_; | 
| + | 
| + friend class Sampler; | 
| }; | 
| +TickSample SignalHandler::sample_; | 
| +volatile bool SignalHandler::called_from_get_sample_ = false; | 
| +base::Semaphore* SignalHandler::sampling_semaphore_ = NULL; | 
| +bool SignalHandler::sample_available_ = false; | 
| + | 
| base::Mutex* SignalHandler::mutex_ = NULL; | 
| int SignalHandler::client_count_ = 0; | 
| struct sigaction SignalHandler::old_signal_handler_; | 
| @@ -329,6 +373,11 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 
| // is disabled. | 
| return; | 
| #else | 
| + // Even if we return prematurely, | 
| + // we need to signal the sampling_semaphore_ | 
| + sample_available_ = false; | 
| + ScopedSemaphore scoped_semaphore(sampling_semaphore_); | 
| + | 
| USE(info); | 
| if (signal != SIGPROF) return; | 
| Isolate* isolate = Isolate::UncheckedReentrantCurrent(); | 
| @@ -466,7 +515,12 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, | 
| #endif // V8_HOST_ARCH_* | 
| #endif // V8_OS_QNX | 
| #endif // USE_SIMULATOR | 
| - sampler->SampleStack(state); | 
| + if (called_from_get_sample_) { | 
| + sample_.Init(sampler->isolate(), state); | 
| + } else { | 
| + sampler->SampleStack(state); | 
| + } | 
| + sample_available_ = true; | 
| #endif // V8_OS_NACL | 
| } | 
| @@ -569,6 +623,7 @@ DISABLE_ASAN void TickSample::Init(Isolate* isolate, | 
| timestamp = base::TimeTicks::HighResolutionNow(); | 
| pc = regs.pc; | 
| state = isolate->current_vm_state(); | 
| + frames_count = 0; | 
| // Avoid collecting traces while doing GC. | 
| if (state == GC) return; | 
| @@ -693,19 +748,33 @@ void Sampler::DoSample() { | 
| pthread_kill(platform_data()->vm_tid(), SIGPROF); | 
| } | 
| + | 
| +void Sampler::GetSample(v8::Sample* sample) { | 
| + SignalHandler::called_from_get_sample_ = true; | 
| + pthread_kill(platform_data()->vm_tid(), SIGPROF); | 
| + SignalHandler::sampling_semaphore_->Wait(); | 
| + if (SignalHandler::sample_available_) { | 
| + *sample = v8::Sample(SignalHandler::sample_.stack, | 
| 
Benedikt Meurer
2014/09/05 03:50:00
Nit: Use
 v8::Sample(&SignalHandler::sample_.stac
 
alph
2014/09/08 12:47:40
Note it will always copy all the 255 frames.
The p
 
gholap
2014/09/08 23:57:38
Done.
 
gholap
2014/09/08 23:57:38
Done.
 | 
| + SignalHandler::sample_.stack | 
| + + SignalHandler::sample_.frames_count); | 
| + } | 
| + SignalHandler::called_from_get_sample_ = false; | 
| +} | 
| + | 
| #elif V8_OS_WIN || V8_OS_CYGWIN | 
| -void Sampler::DoSample() { | 
| +void Sampler::GetSampleHelper(TickSample * sample, | 
| 
alph
2014/09/08 12:47:40
nit: it doesn't match the declaration in .h
 
gholap
2014/09/08 23:57:38
Done.
 | 
| + bool called_from_get_sample) { | 
| HANDLE profiled_thread = platform_data()->profiled_thread(); | 
| - if (profiled_thread == NULL) return; | 
| + if (profiled_thread == NULL) return NULL; | 
| #if defined(USE_SIMULATOR) | 
| SimulatorHelper helper; | 
| - if (!helper.Init(this, isolate())) return; | 
| + if (!helper.Init(this, isolate())) return NULL; | 
| #endif | 
| const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 
| - if (SuspendThread(profiled_thread) == kSuspendFailed) return; | 
| + if (SuspendThread(profiled_thread) == kSuspendFailed) return NULL; | 
| // Context used for sampling the register state of the profiled thread. | 
| CONTEXT context; | 
| @@ -726,11 +795,32 @@ void Sampler::DoSample() { | 
| state.fp = reinterpret_cast<Address>(context.Ebp); | 
| #endif | 
| #endif // USE_SIMULATOR | 
| - SampleStack(state); | 
| + if (called_from_get_sample) { | 
| + sample->Init(sampler->isolate(), state); | 
| 
alph
2014/09/08 12:47:40
hmm... what is sampler?
Does it compile on Win?
 
gholap
2014/09/08 23:57:38
Corrected.
 | 
| + } else { | 
| + SampleStack(state); | 
| + } | 
| } | 
| ResumeThread(profiled_thread); | 
| } | 
| + | 
| +void Sampler::DoSample() { | 
| + GetSampleHelper(NULL, false); | 
| +} | 
| + | 
| + | 
| +void Sampler::GetSample(v8::Sample* sample) { | 
| + // We need this tick_sample because, | 
| + // GetSampleHelper calls Init, which must be called on | 
| + // a TickSample and never on Sample. | 
| + TickSample tick_sample; | 
| + sample->frames_count = 0; | 
| + GetSampleHelper(&tick_sample, true); | 
| + *sample = v8::Sample(tick_sample.stack, | 
| 
Benedikt Meurer
2014/09/05 03:50:00
Nit: Use
 v8::Sample(&tick_sample.stack[0], &tick
 
gholap
2014/09/08 23:57:38
Done.
 | 
| + tick_sample.stack + tick_sample.frames_count); | 
| +} | 
| + | 
| #endif // USE_SIGNALS |