Index: src/sampler.cc |
diff --git a/src/sampler.cc b/src/sampler.cc |
index 0ed4b379626a9746038b6e05b1661cee522f4f1f..cd69c1cfe03067285b4eb3950dd2592295bed451 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 |
@@ -42,6 +41,8 @@ |
#endif |
+#include "include/v8-sampler.h" |
+ |
#include "src/v8.h" |
#include "src/base/platform/platform.h" |
@@ -269,8 +270,16 @@ class SimulatorHelper { |
class SignalHandler : public AllStatic { |
public: |
- static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } |
- static void TearDown() { delete mutex_; } |
+ static void SetUp() { |
+ if (!mutex_) mutex_ = new base::Mutex(); |
+ if (!new_sample_semaphore_) |
+ new_sample_semaphore_ = new base::Semaphore(0); |
+ } |
+ |
+ static void TearDown() { |
+ delete mutex_; |
+ delete new_sample_semaphore_; |
+ } |
static void IncreaseSamplerCount() { |
base::LockGuard<base::Mutex> lock_guard(mutex_); |
@@ -286,6 +295,7 @@ class SignalHandler : public AllStatic { |
return signal_handler_installed_; |
} |
+ |
fmeawad
2014/07/29 18:30:50
Delete the added line.
gholap
2014/07/29 23:25:20
Done.
|
private: |
static void Install() { |
struct sigaction sa; |
@@ -308,14 +318,43 @@ 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. |
fmeawad
2014/07/29 18:30:50
Add a TODO that we will eventually have GetSample,
gholap
2014/07/29 23:25:20
Done.
|
+ |
+ // 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 bool called_from_get_sample_; |
+ |
+ // GetSample waits synchronously till the SIGPROF handler returns. |
+ // this semaphore is used to signal GetSample. |
+ static base::Semaphore* new_sample_semaphore_; |
fmeawad
2014/07/29 18:30:50
I would call it, sampling_semaphore instead.
gholap
2014/07/29 23:25:20
Done.
|
+ |
+ // 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 new_sample_available_; |
fmeawad
2014/07/29 18:30:50
just sample_available_
gholap
2014/07/29 23:25:20
Done.
|
+ |
// 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_; |
+bool SignalHandler::called_from_get_sample_ = false; |
+base::Semaphore* SignalHandler::new_sample_semaphore_ = NULL; |
+bool SignalHandler::new_sample_available_ = false; |
+ |
base::Mutex* SignalHandler::mutex_ = NULL; |
int SignalHandler::client_count_ = 0; |
struct sigaction SignalHandler::old_signal_handler_; |
@@ -329,32 +368,40 @@ void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
// is disabled. |
return; |
#else |
+ |
+#define SIGNAL_AND_RETURN(GOT_NEW) \ |
fmeawad
2014/07/29 18:30:50
Explain why this macro is needed.
gholap
2014/07/29 23:25:20
Done.
|
+ { \ |
+ new_sample_available_ = GOT_NEW; \ |
+ new_sample_semaphore_->Signal(); \ |
+ return; \ |
+ } |
+ |
USE(info); |
- if (signal != SIGPROF) return; |
+ if (signal != SIGPROF) SIGNAL_AND_RETURN(false); |
Isolate* isolate = Isolate::UncheckedReentrantCurrent(); |
if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
// We require a fully initialized and entered isolate. |
- return; |
+ SIGNAL_AND_RETURN(false); |
} |
if (v8::Locker::IsActive() && |
!isolate->thread_manager()->IsLockedByCurrentThread()) { |
- return; |
+ SIGNAL_AND_RETURN(false); |
} |
Sampler* sampler = isolate->logger()->sampler(); |
- if (sampler == NULL) return; |
+ if (sampler == NULL) SIGNAL_AND_RETURN(false); |
RegisterState state; |
#if defined(USE_SIMULATOR) |
SimulatorHelper helper; |
- if (!helper.Init(sampler, isolate)) return; |
+ if (!helper.Init(sampler, isolate)) SIGNAL_AND_RETURN(false); |
helper.FillRegisters(&state); |
// It possible that the simulator is interrupted while it is updating |
// the sp or fp register. ARM64 simulator does this in two steps: |
// first setting it to zero and then setting it to the new value. |
// Bailout if sp/fp doesn't contain the new value. |
- if (state.sp == 0 || state.fp == 0) return; |
+ if (state.sp == 0 || state.fp == 0) SIGNAL_AND_RETURN(false); |
#else |
// Extracting the sample from the context is extremely machine dependent. |
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
@@ -466,7 +513,13 @@ 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); |
+ } |
+ SIGNAL_AND_RETURN(true); |
+#undef SIGNAL_AND_RETURN |
#endif // V8_OS_NACL |
} |
@@ -669,7 +722,7 @@ void Sampler::DecreaseProfilingDepth() { |
} |
-void Sampler::SampleStack(const RegisterState& state) { |
+void Sampler::SampleStack(const RegisterState& state) |
TickSample* sample = isolate_->cpu_profiler()->StartTickSample(); |
TickSample sample_obj; |
if (sample == NULL) sample = &sample_obj; |
@@ -693,19 +746,39 @@ void Sampler::DoSample() { |
pthread_kill(platform_data()->vm_tid(), SIGPROF); |
} |
+ |
+TickSample* Sampler::GetSample(TickSample* sample) { |
+ if (!SignalHandler::Installed()) return NULL; |
+ SignalHandler::called_from_get_sample_ = true; |
+ pthread_kill(platform_data()->vm_tid(), SIGPROF); |
+ SignalHandler::new_sample_semaphore_->Wait(); |
+ if (SignalHandler::new_sample_available_) { |
+ sample->state = SignalHandler::sample_.state; |
+ for (int i = 0; i < SignalHandler::sample_.frames_count; i++) { |
+ sample->stack[i] = SignalHandler::sample_.stack[i]; |
+ } |
+ sample->frames_count = SignalHandler::sample_.frames_count; |
+ } else { |
+ sample = NULL; |
+ } |
+ SignalHandler::called_from_get_sample_ = false; |
+ return sample; |
+} |
+ |
#elif V8_OS_WIN || V8_OS_CYGWIN |
-void Sampler::DoSample() { |
+TickSample* 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,9 +799,24 @@ 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); |
+ return sample; |
+} |
+ |
+ |
+void Sampler::DoSample() { |
+ GetSampleHelper_(NULL, false); |
+} |
+ |
+ |
+TickSample* Sampler::GetSample(TickSample* sample) { |
+ return GetSampleHelper_(sample, true); |
} |
#endif // USE_SIGNALS |