Chromium Code Reviews| Index: content/renderer/devtools/v8_sampling_profiler.cc |
| diff --git a/content/renderer/devtools/v8_sampling_profiler.cc b/content/renderer/devtools/v8_sampling_profiler.cc |
| index a0e063a6e311dbb2ca1a5d39a0ec9f977ec911bd..0c351fa1352e526234daa025b1e282b0052e60a5 100644 |
| --- a/content/renderer/devtools/v8_sampling_profiler.cc |
| +++ b/content/renderer/devtools/v8_sampling_profiler.cc |
| @@ -4,15 +4,153 @@ |
| #include "content/renderer/devtools/v8_sampling_profiler.h" |
| +#include "base/strings/string_util.h" |
| #include "base/synchronization/cancellation_flag.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/trace_event/trace_event.h" |
| +#include "base/trace_event/trace_event_argument.h" |
| +#include "content/renderer/render_thread_impl.h" |
| +#include "v8/include/v8.h" |
| + |
| +using base::trace_event::TraceLog; |
| +using base::trace_event::TracedValue; |
| +using v8::Isolate; |
| namespace content { |
| +namespace { |
| + |
| +std::string PtrToString(const void* value) { |
| + char buffer[20]; |
| + base::snprintf(buffer, sizeof(buffer), "%p", value); |
|
yurys
2015/02/24 13:45:47
It might make sense to share implementation with t
alph
2015/02/24 15:28:16
Done.
|
| + return buffer; |
| +} |
| + |
| +} // namespace |
| + |
| +// The class implements a sampler responsible for sampling a single thread. |
| +class Sampler { |
| + public: |
| + Sampler(base::PlatformThreadHandle handle, Isolate* isolate) |
| + : handle_(handle), isolate_(isolate) { |
| + DCHECK(isolate_); |
| + } |
| + |
| + static scoped_ptr<Sampler> CreateForCurrentThread(); |
| + |
| + // These methods are called from the sampler thread. |
| + void Start(); |
| + void Stop(); |
| + void Sample(); |
| + |
| + private: |
| + static void InstallJitCodeEventHandler(Isolate* isolate, void* data); |
| + static void JitCodeEventHandler(const v8::JitCodeEvent* event); |
|
yurys
2015/02/24 13:45:47
HandleJitCodeEvent
alph
2015/02/24 15:28:16
Done.
|
| + static scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| + JitCodeEventToTraceFormat(const v8::JitCodeEvent* event); |
| + |
| + base::PlatformThreadHandle handle_; |
| + Isolate* isolate_; |
| +}; |
| + |
| +// static |
| +scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { |
| + return scoped_ptr<Sampler>(new Sampler(base::PlatformThread::CurrentHandle(), |
| + Isolate::GetCurrent())); |
| +} |
| + |
| +void Sampler::Start() { |
| + v8::JitCodeEventHandler handler = &JitCodeEventHandler; |
| + isolate_->RequestInterrupt(&InstallJitCodeEventHandler, |
| + reinterpret_cast<void*>(handler)); |
| +} |
| + |
| +void Sampler::Stop() { |
| + isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); |
| +} |
| + |
| +void Sampler::Sample() { |
| +} |
| + |
| +// static |
| +void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) { |
| + // Called on the sampled V8 thread. |
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), |
| + "Sampler::InstallJitCodeEventHandler"); |
| + v8::JitCodeEventHandler handler = |
| + reinterpret_cast<v8::JitCodeEventHandler>(data); |
| + isolate->SetJitCodeEventHandler( |
| + v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler); |
| +} |
| + |
| +// static |
| +void Sampler::JitCodeEventHandler(const v8::JitCodeEvent* event) { |
| + // Called on the sampled V8 thread. |
| + switch (event->type) { |
| + case v8::JitCodeEvent::CODE_ADDED: |
| + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), |
|
dsinclair
2015/02/24 14:40:17
Using dots seems to be more common then _'s in cat
alph
2015/02/24 15:28:16
I have an impression that dots are used to form a
|
| + "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data", |
| + JitCodeEventToTraceFormat(event)); |
| + break; |
| + |
| + case v8::JitCodeEvent::CODE_MOVED: |
| + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), |
| + "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data", |
| + JitCodeEventToTraceFormat(event)); |
| + break; |
| + |
| + case v8::JitCodeEvent::CODE_REMOVED: |
| + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), |
| + "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data", |
| + JitCodeEventToTraceFormat(event)); |
| + break; |
| + |
| + case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: |
| + case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: |
| + case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: |
| + break; |
| + } |
| +} |
| + |
| +// static |
| +scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| +Sampler::JitCodeEventToTraceFormat(const v8::JitCodeEvent* event) { |
| + // Called on the sampled thread. |
| + switch (event->type) { |
| + case v8::JitCodeEvent::CODE_ADDED: { |
| + scoped_refptr<TracedValue> data(new TracedValue()); |
| + data->SetString("code_start", PtrToString(event->code_start)); |
| + data->SetInteger("code_len", static_cast<unsigned>(event->code_len)); |
| + data->SetString("name", std::string(event->name.str, event->name.len)); |
| + return data; |
| + } |
| + |
| + case v8::JitCodeEvent::CODE_MOVED: { |
| + scoped_refptr<TracedValue> data(new TracedValue()); |
| + data->SetString("code_start", PtrToString(event->code_start)); |
| + data->SetInteger("code_len", static_cast<unsigned>(event->code_len)); |
| + data->SetString("new_code_start", PtrToString(event->new_code_start)); |
| + return data; |
| + } |
| + |
| + case v8::JitCodeEvent::CODE_REMOVED: { |
| + scoped_refptr<TracedValue> data(new TracedValue()); |
| + data->SetString("code_start", PtrToString(event->code_start)); |
| + data->SetInteger("code_len", static_cast<unsigned>(event->code_len)); |
| + return data; |
| + } |
| + |
| + case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: |
| + case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: |
| + case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: |
| + return nullptr; |
| + } |
| + return nullptr; |
| +} |
| + |
| class V8SamplingThread : public base::PlatformThread::Delegate { |
| public: |
| - explicit V8SamplingThread(base::WaitableEvent* event); |
| + V8SamplingThread(Sampler*, base::WaitableEvent*); |
| // Implementation of PlatformThread::Delegate: |
| void ThreadMain() override; |
| @@ -21,27 +159,71 @@ class V8SamplingThread : public base::PlatformThread::Delegate { |
| void Stop(); |
| private: |
| + void Sample(); |
| + void InstallSamplers(); |
| + void RemoveSamplers(); |
| + void StartSamplers(); |
| + void StopSamplers(); |
| + static void JitCodeEventHandler(const v8::JitCodeEvent* event); |
| + |
| + Sampler* render_thread_sampler_; |
| base::CancellationFlag cancellation_flag_; |
| base::WaitableEvent* waitable_event_for_testing_; |
| base::PlatformThreadHandle sampling_thread_handle_; |
| + std::vector<Sampler*> samplers_; |
| DISALLOW_COPY_AND_ASSIGN(V8SamplingThread); |
| }; |
| -V8SamplingThread::V8SamplingThread(base::WaitableEvent* event) |
| - : waitable_event_for_testing_(event) { |
| +V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler, |
| + base::WaitableEvent* event) |
| + : render_thread_sampler_(render_thread_sampler), |
| + waitable_event_for_testing_(event) { |
| } |
| void V8SamplingThread::ThreadMain() { |
| - base::PlatformThread::SetName("V8 Sampling Profiler Thread"); |
| + base::PlatformThread::SetName("V8SamplingProfilerThread"); |
| + InstallSamplers(); |
| + StartSamplers(); |
| const int kSamplingFrequencyMicroseconds = 1000; |
| while (!cancellation_flag_.IsSet()) { |
| + Sample(); |
| if (waitable_event_for_testing_) { |
| waitable_event_for_testing_->Signal(); |
| } |
| base::PlatformThread::Sleep( |
| base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); |
| } |
| + StopSamplers(); |
| + RemoveSamplers(); |
| +} |
| + |
| +void V8SamplingThread::Sample() { |
| + for (Sampler* sampler : samplers_) { |
| + sampler->Sample(); |
| + } |
| +} |
| + |
| +void V8SamplingThread::InstallSamplers() { |
| + // Note that the list does not own samplers. |
| + samplers_.push_back(render_thread_sampler_); |
| + // TODO: add worker samplers. |
| +} |
| + |
| +void V8SamplingThread::RemoveSamplers() { |
| + samplers_.clear(); |
| +} |
| + |
| +void V8SamplingThread::StartSamplers() { |
| + for (Sampler* sampler : samplers_) { |
| + sampler->Start(); |
| + } |
| +} |
| + |
| +void V8SamplingThread::StopSamplers() { |
| + for (Sampler* sampler : samplers_) { |
| + sampler->Stop(); |
| + } |
| } |
| void V8SamplingThread::Start() { |
| @@ -55,15 +237,18 @@ void V8SamplingThread::Stop() { |
| base::PlatformThread::Join(sampling_thread_handle_); |
| } |
| -V8SamplingProfiler::V8SamplingProfiler() : sampling_thread_(nullptr) { |
| +V8SamplingProfiler::V8SamplingProfiler() |
| + : sampling_thread_(nullptr), |
| + render_thread_sampler_(Sampler::CreateForCurrentThread()) { |
| + DCHECK(RenderThreadImpl::current()); |
| // Force the "v8_cpu_profile" category to show up in the trace viewer. |
| - base::trace_event::TraceLog::GetCategoryGroupEnabled( |
| + TraceLog::GetCategoryGroupEnabled( |
| TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile")); |
| - base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this); |
| + TraceLog::GetInstance()->AddEnabledStateObserver(this); |
| } |
| V8SamplingProfiler::~V8SamplingProfiler() { |
| - base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); |
| + TraceLog::GetInstance()->RemoveEnabledStateObserver(this); |
| DCHECK(!sampling_thread_.get()); |
| } |
| @@ -73,9 +258,17 @@ void V8SamplingProfiler::OnTraceLogEnabled() { |
| TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled); |
| if (!enabled) |
| return; |
| + |
| + // Do not enable sampling profiler in continuous mode, as losing |
| + // Jit code events may not be afforded. |
| + base::trace_event::TraceRecordMode record_mode = |
| + TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode; |
| + if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY) |
| + return; |
| + |
| DCHECK(!sampling_thread_.get()); |
| - sampling_thread_.reset( |
| - new V8SamplingThread(waitable_event_for_testing_.get())); |
| + sampling_thread_.reset(new V8SamplingThread( |
| + render_thread_sampler_.get(), waitable_event_for_testing_.get())); |
| sampling_thread_->Start(); |
| } |