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

Side by Side 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: Created 5 years, 11 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/devtools/v8_sampling_profiler.h" 5 #include "content/renderer/devtools/v8_sampling_profiler.h"
6 6
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "base/debug/trace_event_argument.h"
9 #include "base/strings/string_util.h"
8 #include "base/synchronization/cancellation_flag.h" 10 #include "base/synchronization/cancellation_flag.h"
9 #include "base/threading/platform_thread.h" 11 #include "base/threading/platform_thread.h"
12 #include "content/renderer/render_thread_impl.h"
13 #include "v8/include/v8.h"
14
15 using v8::Isolate;
16 using base::debug::TracedValue;
10 17
11 namespace content { 18 namespace content {
12 19
20 namespace {
21
22 std::string PtrToString(const void* value) {
23 char buffer[20];
24 base::snprintf(buffer, sizeof(buffer), "%p", value);
25 return buffer;
26 }
27
28 // The class implements a sampler responsible for sampling a single thread.
29 class Sampler {
30 public:
31 Sampler(base::PlatformThreadHandle handle, Isolate* isolate)
32 : handle_(handle), isolate_(isolate) {
33 DCHECK(isolate_);
34 }
35 virtual ~Sampler() {}
36
37 void Start();
yurys 2015/01/14 13:41:36 Please add a comment that these methods can be cal
alph 2015/01/14 14:31:10 Done.
38 void Stop();
39
40 void Sample();
41
42 private:
43 static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
44 static void JitCodeEventHandler(const v8::JitCodeEvent* event);
45 static scoped_refptr<base::debug::ConvertableToTraceFormat>
46 JitCodeEventToTraceFormat(const v8::JitCodeEvent* event);
yurys 2015/01/14 13:41:37 Wrong indentation.
alph 2015/01/14 14:31:10 That's not me! That's git cl format
47
48 base::PlatformThreadHandle handle_;
49 Isolate* isolate_;
50 };
51
52 void Sampler::Start() {
53 v8::JitCodeEventHandler handler = &JitCodeEventHandler;
54 isolate_->RequestInterrupt(&InstallJitCodeEventHandler,
55 reinterpret_cast<void*>(handler));
56 }
57
58 void Sampler::Stop() {
59 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr);
60 }
61
62 void Sampler::Sample() {
63 }
64
65 // static
66 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) {
67 // Called on the sampled V8 thread.
68 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
69 "Sampler::InstallJitCodeEventHandler");
70 v8::JitCodeEventHandler handler =
71 reinterpret_cast<v8::JitCodeEventHandler>(data);
72 isolate->SetJitCodeEventHandler(
73 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler);
74 }
75
76 // static
77 void Sampler::JitCodeEventHandler(const v8::JitCodeEvent* event) {
78 // Called on the sampled V8 thread.
79 switch (event->type) {
80 case v8::JitCodeEvent::CODE_ADDED:
81 TRACE_EVENT_SAMPLE_METADATA1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
yurys 2015/01/14 13:41:36 How does this relate to the stack trace format des
alph 2015/01/14 14:31:10 Yes, it's a different format. I'm not feeling comf
82 "JitCodeAdded", "data",
83 JitCodeEventToTraceFormat(event));
84 break;
85
86 case v8::JitCodeEvent::CODE_MOVED:
87 TRACE_EVENT_SAMPLE_METADATA1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
yurys 2015/01/14 13:41:36 Why is this metadata event rather than instant one
alph 2015/01/14 14:31:10 I tried not to garble the trace view with the samp
88 "JitCodeMoved", "data",
89 JitCodeEventToTraceFormat(event));
90 break;
91
92 case v8::JitCodeEvent::CODE_REMOVED:
93 TRACE_EVENT_SAMPLE_METADATA1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
94 "JitCodeRemoved", "data",
95 JitCodeEventToTraceFormat(event));
96 break;
97
98 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
99 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
100 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
101 break;
102 }
103 }
104
105 // static
106 scoped_refptr<base::debug::ConvertableToTraceFormat>
107 Sampler::JitCodeEventToTraceFormat(const v8::JitCodeEvent* event) {
108 // Called on the sampled thread.
109 switch (event->type) {
110 case v8::JitCodeEvent::CODE_ADDED: {
111 scoped_refptr<TracedValue> data(new TracedValue());
112 data->SetString("code_start", PtrToString(event->code_start));
yurys 2015/01/14 13:41:36 Do we want to see isolate identifier as one of the
alph 2015/01/14 14:31:10 It is not necessary. The code_start uniquely ident
113 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
114 data->SetString("name", std::string(event->name.str, event->name.len));
115 return data;
116 }
117
118 case v8::JitCodeEvent::CODE_MOVED: {
119 scoped_refptr<TracedValue> data(new TracedValue());
120 data->SetString("code_start", PtrToString(event->code_start));
121 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
122 data->SetString("new_code_start", PtrToString(event->new_code_start));
123 return data;
124 }
125
126 case v8::JitCodeEvent::CODE_REMOVED: {
127 scoped_refptr<TracedValue> data(new TracedValue());
128 data->SetString("code_start", PtrToString(event->code_start));
129 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
130 return data;
131 }
132
133 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
134 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
135 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
136 return nullptr;
137 }
138 return nullptr;
139 }
140
141 } // namespace
142
143 // Main thread sampler. Must be created on the main thread.
144 class RenderThreadSampler : public Sampler {
145 public:
146 RenderThreadSampler()
yurys 2015/01/14 13:41:36 Why do we need a subclass here? Wouldn't Sampler::
alph 2015/01/14 14:31:10 Done.
147 : Sampler(base::PlatformThread::CurrentHandle(), Isolate::GetCurrent()) {
148 // Must be called on the render thread.
149 DCHECK(RenderThreadImpl::current());
150 }
151 };
152
13 class V8SamplingThread : public base::PlatformThread::Delegate { 153 class V8SamplingThread : public base::PlatformThread::Delegate {
14 public: 154 public:
15 explicit V8SamplingThread(base::WaitableEvent* event); 155 V8SamplingThread(RenderThreadSampler*, base::WaitableEvent*);
16 156
17 // Implementation of PlatformThread::Delegate: 157 // Implementation of PlatformThread::Delegate:
18 void ThreadMain() override; 158 void ThreadMain() override;
19 159
20 void Start(); 160 void Start();
21 void Stop(); 161 void Stop();
22 162
23 private: 163 private:
164 void Sample();
165 void InstallSamplers();
166 void RemoveSamplers();
167 void StartSamplers();
168 void StopSamplers();
169 static void JitCodeEventHandler(const v8::JitCodeEvent* event);
170
171 RenderThreadSampler* render_thread_sampler_;
24 base::CancellationFlag cancellation_flag_; 172 base::CancellationFlag cancellation_flag_;
25 base::WaitableEvent* waitable_event_for_testing_; 173 base::WaitableEvent* waitable_event_for_testing_;
26 base::PlatformThreadHandle sampling_thread_handle_; 174 base::PlatformThreadHandle sampling_thread_handle_;
175 std::vector<Sampler*> samplers_;
27 176
28 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread); 177 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread);
29 }; 178 };
30 179
31 V8SamplingThread::V8SamplingThread(base::WaitableEvent* event) 180 V8SamplingThread::V8SamplingThread(RenderThreadSampler* render_thread_sampler,
32 : waitable_event_for_testing_(event) { 181 base::WaitableEvent* event)
182 : render_thread_sampler_(render_thread_sampler),
yurys 2015/01/14 13:41:37 May be pass an array of all samplers?
alph 2015/01/14 14:31:10 I'm not yet sure who will be responsible for creat
183 waitable_event_for_testing_(event) {
33 } 184 }
34 185
35 void V8SamplingThread::ThreadMain() { 186 void V8SamplingThread::ThreadMain() {
36 base::PlatformThread::SetName("V8 Sampling Profiler Thread"); 187 base::PlatformThread::SetName("V8SamplingProfilerThread");
188 InstallSamplers();
189 StartSamplers();
37 const int kSamplingFrequencyMicroseconds = 1000; 190 const int kSamplingFrequencyMicroseconds = 1000;
38 while (!cancellation_flag_.IsSet()) { 191 while (!cancellation_flag_.IsSet()) {
192 Sample();
39 if (waitable_event_for_testing_) { 193 if (waitable_event_for_testing_) {
40 waitable_event_for_testing_->Signal(); 194 waitable_event_for_testing_->Signal();
41 } 195 }
42 base::PlatformThread::Sleep( 196 base::PlatformThread::Sleep(
43 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); 197 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
44 } 198 }
199 StopSamplers();
200 RemoveSamplers();
201 }
202
203 void V8SamplingThread::Sample() {
204 for (auto sampler : samplers_) {
yurys 2015/01/14 13:41:36 auto -> Sampler* here and below
alph 2015/01/14 14:31:10 Done.
205 sampler->Sample();
206 }
207 }
208
209 void V8SamplingThread::InstallSamplers() {
210 // Note that the list does not own samplers.
211 samplers_.push_back(render_thread_sampler_);
212 // TODO: add worker samplers.
213 }
214
215 void V8SamplingThread::RemoveSamplers() {
216 samplers_.clear();
217 }
218
219 void V8SamplingThread::StartSamplers() {
220 for (auto sampler : samplers_) {
221 sampler->Start();
222 }
223 }
224
225 void V8SamplingThread::StopSamplers() {
226 for (auto sampler : samplers_) {
227 sampler->Stop();
228 }
45 } 229 }
46 230
47 void V8SamplingThread::Start() { 231 void V8SamplingThread::Start() {
48 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { 232 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) {
49 DCHECK(false) << "failed to create thread"; 233 DCHECK(false) << "failed to create thread";
50 } 234 }
51 } 235 }
52 236
53 void V8SamplingThread::Stop() { 237 void V8SamplingThread::Stop() {
54 cancellation_flag_.Set(); 238 cancellation_flag_.Set();
55 base::PlatformThread::Join(sampling_thread_handle_); 239 base::PlatformThread::Join(sampling_thread_handle_);
56 } 240 }
57 241
58 V8SamplingProfiler::V8SamplingProfiler() : sampling_thread_(nullptr) { 242 V8SamplingProfiler::V8SamplingProfiler()
243 : sampling_thread_(nullptr),
244 render_thread_sampler_(new RenderThreadSampler()) {
59 // Force the "v8_cpu_profile" category to show up in the trace viewer. 245 // Force the "v8_cpu_profile" category to show up in the trace viewer.
60 base::debug::TraceLog::GetCategoryGroupEnabled( 246 base::debug::TraceLog::GetCategoryGroupEnabled(
61 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile")); 247 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"));
62 base::debug::TraceLog::GetInstance()->AddEnabledStateObserver(this); 248 base::debug::TraceLog::GetInstance()->AddEnabledStateObserver(this);
63 } 249 }
64 250
65 V8SamplingProfiler::~V8SamplingProfiler() { 251 V8SamplingProfiler::~V8SamplingProfiler() {
66 base::debug::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); 252 base::debug::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
67 DCHECK(!sampling_thread_.get()); 253 DCHECK(!sampling_thread_.get());
68 } 254 }
69 255
70 void V8SamplingProfiler::OnTraceLogEnabled() { 256 void V8SamplingProfiler::OnTraceLogEnabled() {
71 bool enabled; 257 bool enabled;
72 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 258 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
73 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled); 259 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled);
74 if (!enabled) 260 if (!enabled)
75 return; 261 return;
76 DCHECK(!sampling_thread_.get()); 262 DCHECK(!sampling_thread_.get());
77 sampling_thread_.reset( 263 sampling_thread_.reset(new V8SamplingThread(
78 new V8SamplingThread(waitable_event_for_testing_.get())); 264 render_thread_sampler_.get(), waitable_event_for_testing_.get()));
79 sampling_thread_->Start(); 265 sampling_thread_->Start();
80 } 266 }
81 267
82 void V8SamplingProfiler::OnTraceLogDisabled() { 268 void V8SamplingProfiler::OnTraceLogDisabled() {
83 if (!sampling_thread_.get()) 269 if (!sampling_thread_.get())
84 return; 270 return;
85 sampling_thread_->Stop(); 271 sampling_thread_->Stop();
86 sampling_thread_.reset(); 272 sampling_thread_.reset();
87 } 273 }
88 274
89 void V8SamplingProfiler::EnableSamplingEventForTesting() { 275 void V8SamplingProfiler::EnableSamplingEventForTesting() {
90 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); 276 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false));
91 } 277 }
92 278
93 void V8SamplingProfiler::WaitSamplingEventForTesting() { 279 void V8SamplingProfiler::WaitSamplingEventForTesting() {
94 waitable_event_for_testing_->Wait(); 280 waitable_event_for_testing_->Wait();
95 } 281 }
96 282
97 } // namespace blink 283 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698