| Index: src/sampler.cc
|
| diff --git a/src/sampler.cc b/src/sampler.cc
|
| index 0ed4b379626a9746038b6e05b1661cee522f4f1f..bebbf53efdf409d6d4eb68670eb37c6e24efb2f2 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
|
| }
|
|
|
| @@ -686,6 +740,15 @@ void Sampler::SampleStack(const RegisterState& state) {
|
| }
|
|
|
|
|
| +void Sampler::CopyTickSampleToSample(TickSample* tick_sample,
|
| + v8::Sample* sample) {
|
| + for (unsigned i = 0; i < tick_sample->frames_count; i++) {
|
| + sample->stack[i] = tick_sample->stack[i];
|
| + }
|
| + sample->frames_count = tick_sample->frames_count;
|
| +}
|
| +
|
| +
|
| #if defined(USE_SIGNALS)
|
|
|
| void Sampler::DoSample() {
|
| @@ -693,19 +756,32 @@ void Sampler::DoSample() {
|
| pthread_kill(platform_data()->vm_tid(), SIGPROF);
|
| }
|
|
|
| +
|
| +void Sampler::GetSample(v8::Sample* sample) {
|
| + sample->frames_count = 0;
|
| + SignalHandler::called_from_get_sample_ = true;
|
| + pthread_kill(platform_data()->vm_tid(), SIGPROF);
|
| + SignalHandler::sampling_semaphore_->Wait();
|
| + if (SignalHandler::sample_available_) {
|
| + CopyTickSampleToSample(&SignalHandler::sample_, sample);
|
| + }
|
| + SignalHandler::called_from_get_sample_ = false;
|
| +}
|
| +
|
| #elif V8_OS_WIN || V8_OS_CYGWIN
|
|
|
| -void Sampler::DoSample() {
|
| +void Sampler::GetSampleHelper(TickSample * sample,
|
| + 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 +802,31 @@ 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);
|
| + } 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);
|
| + CopyTickSampleToSample(&tick_sample, sample);
|
| +}
|
| +
|
| #endif // USE_SIGNALS
|
|
|
|
|
|
|