Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Unified Diff: content/renderer/devtools/v8_sampling_profiler.cc

Issue 792903003: V8 Sampling Profiler: Collect V8 JitCodeEvents in tracing (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix the test under Debug mode. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..17d7556559b7be9622c12feb2d573c0bd702fdd6 100644
--- a/content/renderer/devtools/v8_sampling_profiler.cc
+++ b/content/renderer/devtools/v8_sampling_profiler.cc
@@ -4,15 +4,150 @@
#include "content/renderer/devtools/v8_sampling_profiler.h"
+#include "base/format_macros.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), "0x%" PRIx64,
+ static_cast<uint64>(reinterpret_cast<intptr_t>(value)));
+ return buffer;
+}
+
+} // namespace
+
+// The class implements a sampler responsible for sampling a single thread.
+class Sampler {
+ public:
+ explicit Sampler(Isolate* isolate) : isolate_(isolate) { DCHECK(isolate_); }
+
+ static scoped_ptr<Sampler> CreateForCurrentThread();
+
+ // These methods are called from the sampling thread.
+ void Start();
+ void Stop();
+ void Sample();
+
+ private:
+ static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
+ static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
+ static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ JitCodeEventToTraceFormat(const v8::JitCodeEvent* event);
+
+ Isolate* isolate_;
+};
+
+// static
+scoped_ptr<Sampler> Sampler::CreateForCurrentThread() {
+ return scoped_ptr<Sampler>(new Sampler(Isolate::GetCurrent()));
+}
+
+void Sampler::Start() {
+ v8::JitCodeEventHandler handler = &HandleJitCodeEvent;
+ 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::HandleJitCodeEvent(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"),
+ "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 +156,71 @@ class V8SamplingThread : public base::PlatformThread::Delegate {
void Stop();
private:
+ void Sample();
+ void InstallSamplers();
+ void RemoveSamplers();
+ void StartSamplers();
+ void StopSamplers();
+ static void HandleJitCodeEvent(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,27 +234,38 @@ void V8SamplingThread::Stop() {
base::PlatformThread::Join(sampling_thread_handle_);
}
-V8SamplingProfiler::V8SamplingProfiler() : sampling_thread_(nullptr) {
- // Force the "v8_cpu_profile" category to show up in the trace viewer.
- base::trace_event::TraceLog::GetCategoryGroupEnabled(
- TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"));
- base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+V8SamplingProfiler::V8SamplingProfiler(bool underTest)
+ : sampling_thread_(nullptr),
+ render_thread_sampler_(Sampler::CreateForCurrentThread()) {
+ DCHECK(underTest || RenderThreadImpl::current());
+ // Force the "v8.cpu_profile" category to show up in the trace viewer.
+ TraceLog::GetCategoryGroupEnabled(
+ TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"));
+ TraceLog::GetInstance()->AddEnabledStateObserver(this);
}
V8SamplingProfiler::~V8SamplingProfiler() {
- base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+ TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
DCHECK(!sampling_thread_.get());
}
void V8SamplingProfiler::OnTraceLogEnabled() {
bool enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled);
+ 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();
}
« no previous file with comments | « content/renderer/devtools/v8_sampling_profiler.h ('k') | content/renderer/devtools/v8_sampling_profiler_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698