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

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: Rebaseline. 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 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/strings/string_util.h"
7 #include "base/synchronization/cancellation_flag.h" 8 #include "base/synchronization/cancellation_flag.h"
8 #include "base/threading/platform_thread.h" 9 #include "base/threading/platform_thread.h"
9 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
11 #include "base/trace_event/trace_event_argument.h"
12 #include "content/renderer/render_thread_impl.h"
13 #include "v8/include/v8.h"
14
15 using base::trace_event::TraceLog;
16 using base::trace_event::TracedValue;
17 using v8::Isolate;
10 18
11 namespace content { 19 namespace content {
12 20
21 namespace {
22
23 std::string PtrToString(const void* value) {
24 char buffer[20];
25 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.
26 return buffer;
27 }
28
29 } // namespace
30
31 // The class implements a sampler responsible for sampling a single thread.
32 class Sampler {
33 public:
34 Sampler(base::PlatformThreadHandle handle, Isolate* isolate)
35 : handle_(handle), isolate_(isolate) {
36 DCHECK(isolate_);
37 }
38
39 static scoped_ptr<Sampler> CreateForCurrentThread();
40
41 // These methods are called from the sampler thread.
42 void Start();
43 void Stop();
44 void Sample();
45
46 private:
47 static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
48 static void JitCodeEventHandler(const v8::JitCodeEvent* event);
yurys 2015/02/24 13:45:47 HandleJitCodeEvent
alph 2015/02/24 15:28:16 Done.
49 static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
50 JitCodeEventToTraceFormat(const v8::JitCodeEvent* event);
51
52 base::PlatformThreadHandle handle_;
53 Isolate* isolate_;
54 };
55
56 // static
57 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() {
58 return scoped_ptr<Sampler>(new Sampler(base::PlatformThread::CurrentHandle(),
59 Isolate::GetCurrent()));
60 }
61
62 void Sampler::Start() {
63 v8::JitCodeEventHandler handler = &JitCodeEventHandler;
64 isolate_->RequestInterrupt(&InstallJitCodeEventHandler,
65 reinterpret_cast<void*>(handler));
66 }
67
68 void Sampler::Stop() {
69 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr);
70 }
71
72 void Sampler::Sample() {
73 }
74
75 // static
76 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) {
77 // Called on the sampled V8 thread.
78 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
79 "Sampler::InstallJitCodeEventHandler");
80 v8::JitCodeEventHandler handler =
81 reinterpret_cast<v8::JitCodeEventHandler>(data);
82 isolate->SetJitCodeEventHandler(
83 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler);
84 }
85
86 // static
87 void Sampler::JitCodeEventHandler(const v8::JitCodeEvent* event) {
88 // Called on the sampled V8 thread.
89 switch (event->type) {
90 case v8::JitCodeEvent::CODE_ADDED:
91 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
92 "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data",
93 JitCodeEventToTraceFormat(event));
94 break;
95
96 case v8::JitCodeEvent::CODE_MOVED:
97 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
98 "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data",
99 JitCodeEventToTraceFormat(event));
100 break;
101
102 case v8::JitCodeEvent::CODE_REMOVED:
103 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"),
104 "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data",
105 JitCodeEventToTraceFormat(event));
106 break;
107
108 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
109 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
110 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
111 break;
112 }
113 }
114
115 // static
116 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
117 Sampler::JitCodeEventToTraceFormat(const v8::JitCodeEvent* event) {
118 // Called on the sampled thread.
119 switch (event->type) {
120 case v8::JitCodeEvent::CODE_ADDED: {
121 scoped_refptr<TracedValue> data(new TracedValue());
122 data->SetString("code_start", PtrToString(event->code_start));
123 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
124 data->SetString("name", std::string(event->name.str, event->name.len));
125 return data;
126 }
127
128 case v8::JitCodeEvent::CODE_MOVED: {
129 scoped_refptr<TracedValue> data(new TracedValue());
130 data->SetString("code_start", PtrToString(event->code_start));
131 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
132 data->SetString("new_code_start", PtrToString(event->new_code_start));
133 return data;
134 }
135
136 case v8::JitCodeEvent::CODE_REMOVED: {
137 scoped_refptr<TracedValue> data(new TracedValue());
138 data->SetString("code_start", PtrToString(event->code_start));
139 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
140 return data;
141 }
142
143 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
144 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
145 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
146 return nullptr;
147 }
148 return nullptr;
149 }
150
13 class V8SamplingThread : public base::PlatformThread::Delegate { 151 class V8SamplingThread : public base::PlatformThread::Delegate {
14 public: 152 public:
15 explicit V8SamplingThread(base::WaitableEvent* event); 153 V8SamplingThread(Sampler*, base::WaitableEvent*);
16 154
17 // Implementation of PlatformThread::Delegate: 155 // Implementation of PlatformThread::Delegate:
18 void ThreadMain() override; 156 void ThreadMain() override;
19 157
20 void Start(); 158 void Start();
21 void Stop(); 159 void Stop();
22 160
23 private: 161 private:
162 void Sample();
163 void InstallSamplers();
164 void RemoveSamplers();
165 void StartSamplers();
166 void StopSamplers();
167 static void JitCodeEventHandler(const v8::JitCodeEvent* event);
168
169 Sampler* render_thread_sampler_;
24 base::CancellationFlag cancellation_flag_; 170 base::CancellationFlag cancellation_flag_;
25 base::WaitableEvent* waitable_event_for_testing_; 171 base::WaitableEvent* waitable_event_for_testing_;
26 base::PlatformThreadHandle sampling_thread_handle_; 172 base::PlatformThreadHandle sampling_thread_handle_;
173 std::vector<Sampler*> samplers_;
27 174
28 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread); 175 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread);
29 }; 176 };
30 177
31 V8SamplingThread::V8SamplingThread(base::WaitableEvent* event) 178 V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler,
32 : waitable_event_for_testing_(event) { 179 base::WaitableEvent* event)
180 : render_thread_sampler_(render_thread_sampler),
181 waitable_event_for_testing_(event) {
33 } 182 }
34 183
35 void V8SamplingThread::ThreadMain() { 184 void V8SamplingThread::ThreadMain() {
36 base::PlatformThread::SetName("V8 Sampling Profiler Thread"); 185 base::PlatformThread::SetName("V8SamplingProfilerThread");
186 InstallSamplers();
187 StartSamplers();
37 const int kSamplingFrequencyMicroseconds = 1000; 188 const int kSamplingFrequencyMicroseconds = 1000;
38 while (!cancellation_flag_.IsSet()) { 189 while (!cancellation_flag_.IsSet()) {
190 Sample();
39 if (waitable_event_for_testing_) { 191 if (waitable_event_for_testing_) {
40 waitable_event_for_testing_->Signal(); 192 waitable_event_for_testing_->Signal();
41 } 193 }
42 base::PlatformThread::Sleep( 194 base::PlatformThread::Sleep(
43 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); 195 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
44 } 196 }
197 StopSamplers();
198 RemoveSamplers();
199 }
200
201 void V8SamplingThread::Sample() {
202 for (Sampler* sampler : samplers_) {
203 sampler->Sample();
204 }
205 }
206
207 void V8SamplingThread::InstallSamplers() {
208 // Note that the list does not own samplers.
209 samplers_.push_back(render_thread_sampler_);
210 // TODO: add worker samplers.
211 }
212
213 void V8SamplingThread::RemoveSamplers() {
214 samplers_.clear();
215 }
216
217 void V8SamplingThread::StartSamplers() {
218 for (Sampler* sampler : samplers_) {
219 sampler->Start();
220 }
221 }
222
223 void V8SamplingThread::StopSamplers() {
224 for (Sampler* sampler : samplers_) {
225 sampler->Stop();
226 }
45 } 227 }
46 228
47 void V8SamplingThread::Start() { 229 void V8SamplingThread::Start() {
48 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { 230 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) {
49 DCHECK(false) << "failed to create thread"; 231 DCHECK(false) << "failed to create thread";
50 } 232 }
51 } 233 }
52 234
53 void V8SamplingThread::Stop() { 235 void V8SamplingThread::Stop() {
54 cancellation_flag_.Set(); 236 cancellation_flag_.Set();
55 base::PlatformThread::Join(sampling_thread_handle_); 237 base::PlatformThread::Join(sampling_thread_handle_);
56 } 238 }
57 239
58 V8SamplingProfiler::V8SamplingProfiler() : sampling_thread_(nullptr) { 240 V8SamplingProfiler::V8SamplingProfiler()
241 : sampling_thread_(nullptr),
242 render_thread_sampler_(Sampler::CreateForCurrentThread()) {
243 DCHECK(RenderThreadImpl::current());
59 // Force the "v8_cpu_profile" category to show up in the trace viewer. 244 // Force the "v8_cpu_profile" category to show up in the trace viewer.
60 base::trace_event::TraceLog::GetCategoryGroupEnabled( 245 TraceLog::GetCategoryGroupEnabled(
61 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile")); 246 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"));
62 base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this); 247 TraceLog::GetInstance()->AddEnabledStateObserver(this);
63 } 248 }
64 249
65 V8SamplingProfiler::~V8SamplingProfiler() { 250 V8SamplingProfiler::~V8SamplingProfiler() {
66 base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); 251 TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
67 DCHECK(!sampling_thread_.get()); 252 DCHECK(!sampling_thread_.get());
68 } 253 }
69 254
70 void V8SamplingProfiler::OnTraceLogEnabled() { 255 void V8SamplingProfiler::OnTraceLogEnabled() {
71 bool enabled; 256 bool enabled;
72 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 257 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
73 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled); 258 TRACE_DISABLED_BY_DEFAULT("v8_cpu_profile"), &enabled);
74 if (!enabled) 259 if (!enabled)
75 return; 260 return;
261
262 // Do not enable sampling profiler in continuous mode, as losing
263 // Jit code events may not be afforded.
264 base::trace_event::TraceRecordMode record_mode =
265 TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode;
266 if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY)
267 return;
268
76 DCHECK(!sampling_thread_.get()); 269 DCHECK(!sampling_thread_.get());
77 sampling_thread_.reset( 270 sampling_thread_.reset(new V8SamplingThread(
78 new V8SamplingThread(waitable_event_for_testing_.get())); 271 render_thread_sampler_.get(), waitable_event_for_testing_.get()));
79 sampling_thread_->Start(); 272 sampling_thread_->Start();
80 } 273 }
81 274
82 void V8SamplingProfiler::OnTraceLogDisabled() { 275 void V8SamplingProfiler::OnTraceLogDisabled() {
83 if (!sampling_thread_.get()) 276 if (!sampling_thread_.get())
84 return; 277 return;
85 sampling_thread_->Stop(); 278 sampling_thread_->Stop();
86 sampling_thread_.reset(); 279 sampling_thread_.reset();
87 } 280 }
88 281
89 void V8SamplingProfiler::EnableSamplingEventForTesting() { 282 void V8SamplingProfiler::EnableSamplingEventForTesting() {
90 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); 283 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false));
91 } 284 }
92 285
93 void V8SamplingProfiler::WaitSamplingEventForTesting() { 286 void V8SamplingProfiler::WaitSamplingEventForTesting() {
94 waitable_event_for_testing_->Wait(); 287 waitable_event_for_testing_->Wait();
95 } 288 }
96 289
97 } // namespace blink 290 } // namespace blink
OLDNEW
« 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