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

Side by Side Diff: content/renderer/devtools/v8_sampling_profiler.cc

Issue 1017063002: V8 Sampling Profiler: Collect V8 sample trace events on Linux and MacOS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Disable tests on Win and Android Created 5 years, 9 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 #if defined(OS_POSIX)
8 #include <signal.h>
9 #define USE_SIGNALS
10 #endif
11
7 #include "base/format_macros.h" 12 #include "base/format_macros.h"
8 #include "base/strings/string_util.h" 13 #include "base/strings/stringprintf.h"
9 #include "base/synchronization/cancellation_flag.h" 14 #include "base/synchronization/cancellation_flag.h"
10 #include "base/threading/platform_thread.h" 15 #include "base/threading/platform_thread.h"
11 #include "base/trace_event/trace_event.h" 16 #include "base/trace_event/trace_event.h"
12 #include "base/trace_event/trace_event_argument.h" 17 #include "base/trace_event/trace_event_argument.h"
18 #include "content/renderer/devtools/lock_free_circular_queue.h"
13 #include "content/renderer/render_thread_impl.h" 19 #include "content/renderer/render_thread_impl.h"
14 #include "v8/include/v8.h" 20 #include "v8/include/v8.h"
15 21
22 using base::trace_event::ConvertableToTraceFormat;
16 using base::trace_event::TraceLog; 23 using base::trace_event::TraceLog;
17 using base::trace_event::TracedValue; 24 using base::trace_event::TracedValue;
18 using v8::Isolate; 25 using v8::Isolate;
19 26
20 namespace content { 27 namespace content {
21 28
22 namespace { 29 namespace {
23 30
24 std::string PtrToString(const void* value) { 31 std::string PtrToString(const void* value) {
25 char buffer[20]; 32 return base::StringPrintf(
26 base::snprintf(buffer, sizeof(buffer), "0x%" PRIx64, 33 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value)));
27 static_cast<uint64>(reinterpret_cast<intptr_t>(value))); 34 }
28 return buffer; 35
36 class SampleRecord {
37 public:
38 static const int kMaxFramesCountLog2 = 8;
39 static const unsigned kMaxFramesCount = (1u << kMaxFramesCountLog2) - 1;
40
41 SampleRecord() {}
42
43 base::TimeTicks timestamp() const { return timestamp_; }
44 void Collect(v8::Isolate* isolate,
45 base::TimeTicks timestamp,
46 const v8::RegisterState& state);
47 scoped_refptr<ConvertableToTraceFormat> ToTraceFormat() const;
48
49 private:
50 base::TimeTicks timestamp_;
51 unsigned vm_state_ : 4;
52 unsigned frames_count_ : kMaxFramesCountLog2;
53 const void* frames_[kMaxFramesCount];
54
55 DISALLOW_COPY_AND_ASSIGN(SampleRecord);
56 };
57
58 void SampleRecord::Collect(v8::Isolate* isolate,
59 base::TimeTicks timestamp,
60 const v8::RegisterState& state) {
61 v8::SampleInfo sample_info;
62 isolate->GetStackSample(state, (void**)frames_, kMaxFramesCount,
63 &sample_info);
64 timestamp_ = timestamp;
65 frames_count_ = sample_info.frames_count;
66 vm_state_ = sample_info.vm_state;
67 }
68
69 scoped_refptr<ConvertableToTraceFormat> SampleRecord::ToTraceFormat() const {
70 scoped_refptr<TracedValue> data(new TracedValue());
71 const char* vm_state = nullptr;
72 switch (vm_state_) {
73 case v8::StateTag::JS:
74 vm_state = "js";
75 break;
76 case v8::StateTag::GC:
77 vm_state = "gc";
78 break;
79 case v8::StateTag::COMPILER:
80 vm_state = "compiler";
81 break;
82 case v8::StateTag::OTHER:
83 vm_state = "other";
84 break;
85 case v8::StateTag::EXTERNAL:
86 vm_state = "external";
87 break;
88 case v8::StateTag::IDLE:
89 vm_state = "idle";
90 break;
91 default:
92 NOTREACHED();
93 }
94 data->SetString("vm_state", vm_state);
95 data->BeginArray("stack");
96 for (unsigned i = 0; i < frames_count_; ++i) {
97 data->AppendString(PtrToString(frames_[i]));
98 }
99 data->EndArray();
100 return data;
29 } 101 }
30 102
31 } // namespace 103 } // namespace
32 104
33 // The class implements a sampler responsible for sampling a single thread. 105 // The class implements a sampler responsible for sampling a single thread.
34 class Sampler { 106 class Sampler {
35 public: 107 public:
36 explicit Sampler(Isolate* isolate) : isolate_(isolate) { DCHECK(isolate_); } 108 ~Sampler();
37 109
38 static scoped_ptr<Sampler> CreateForCurrentThread(); 110 static scoped_ptr<Sampler> CreateForCurrentThread();
111 static Sampler* GetInstance() { return tls_instance_.Pointer()->Get(); }
39 112
40 // These methods are called from the sampling thread. 113 // These methods are called from the sampling thread.
41 void Start(); 114 void Start();
42 void Stop(); 115 void Stop();
43 void Sample(); 116 void Sample();
44 117
118 void DoSample(const v8::RegisterState& state);
119
120 bool EventsCollectedForTest() const {
121 return base::subtle::NoBarrier_Load(&code_added_events_count_) != 0 ||
122 base::subtle::NoBarrier_Load(&samples_count_) != 0;
123 }
124
45 private: 125 private:
126 Sampler();
127
46 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); 128 static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
47 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); 129 static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
48 static scoped_refptr<base::trace_event::ConvertableToTraceFormat> 130 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat(
49 JitCodeEventToTraceFormat(const v8::JitCodeEvent* event); 131 const v8::JitCodeEvent* event);
132 static base::PlatformThreadHandle GetCurrentThreadHandle();
50 133
134 void InjectPendingEvents();
135
136 static const unsigned kNumberOfSamples = 10;
137 typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue;
138
139 base::PlatformThreadId thread_id_;
140 base::PlatformThreadHandle thread_handle_;
51 Isolate* isolate_; 141 Isolate* isolate_;
142 scoped_ptr<SamplingQueue> samples_data_;
143 base::subtle::Atomic32 code_added_events_count_;
144 base::subtle::Atomic32 samples_count_;
145
146 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
147 tls_instance_;
52 }; 148 };
53 149
150 base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
151 Sampler::tls_instance_ = LAZY_INSTANCE_INITIALIZER;
152
153 Sampler::Sampler()
154 : thread_id_(base::PlatformThread::CurrentId()),
155 thread_handle_(Sampler::GetCurrentThreadHandle()),
156 isolate_(Isolate::GetCurrent()),
157 code_added_events_count_(0),
158 samples_count_(0) {
159 DCHECK(isolate_);
160 DCHECK(!GetInstance());
161 tls_instance_.Pointer()->Set(this);
162 }
163
164 Sampler::~Sampler() {
165 DCHECK(GetInstance());
166 tls_instance_.Pointer()->Set(nullptr);
167 }
168
54 // static 169 // static
55 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { 170 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() {
56 return scoped_ptr<Sampler>(new Sampler(Isolate::GetCurrent())); 171 return scoped_ptr<Sampler>(new Sampler());
172 }
173
174 // static
175 base::PlatformThreadHandle Sampler::GetCurrentThreadHandle() {
176 #ifdef OS_WIN
177 // TODO(alph): Add Windows support.
178 return base::PlatformThreadHandle();
179 #else
180 return base::PlatformThread::CurrentHandle();
181 #endif
57 } 182 }
58 183
59 void Sampler::Start() { 184 void Sampler::Start() {
185 samples_data_.reset(new SamplingQueue());
60 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; 186 v8::JitCodeEventHandler handler = &HandleJitCodeEvent;
61 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, 187 isolate_->RequestInterrupt(&InstallJitCodeEventHandler,
62 reinterpret_cast<void*>(handler)); 188 reinterpret_cast<void*>(handler));
63 } 189 }
64 190
65 void Sampler::Stop() { 191 void Sampler::Stop() {
66 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); 192 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr);
193 samples_data_.reset();
67 } 194 }
68 195
69 void Sampler::Sample() { 196 void Sampler::Sample() {
197 #if defined(USE_SIGNALS)
198 int error = pthread_kill(thread_handle_.platform_handle(), SIGPROF);
199 if (error) {
200 LOG(ERROR) << "pthread_kill failed with error " << error << " "
201 << strerror(error);
202 }
203 InjectPendingEvents();
204 #endif
205 }
206
207 void Sampler::DoSample(const v8::RegisterState& state) {
208 // Called in the sampled thread signal handler.
209 // Because of that it is not allowed to do any memory allocation here.
210 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime();
211 SampleRecord* record = samples_data_->StartEnqueue();
212 if (!record)
213 return;
214 record->Collect(isolate_, timestamp, state);
215 samples_data_->FinishEnqueue();
216 base::subtle::NoBarrier_AtomicIncrement(&samples_count_, 1);
217 }
218
219 void Sampler::InjectPendingEvents() {
220 SampleRecord* record = samples_data_->Peek();
221 while (record) {
222 TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(
223 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), "V8Sample", thread_id_,
224 (record->timestamp() - base::TimeTicks()).InMicroseconds(), "data",
225 record->ToTraceFormat());
226 samples_data_->Remove();
227 record = samples_data_->Peek();
228 }
70 } 229 }
71 230
72 // static 231 // static
73 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) { 232 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) {
74 // Called on the sampled V8 thread. 233 // Called on the sampled V8 thread.
75 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 234 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
76 "Sampler::InstallJitCodeEventHandler"); 235 "Sampler::InstallJitCodeEventHandler");
77 v8::JitCodeEventHandler handler = 236 v8::JitCodeEventHandler handler =
78 reinterpret_cast<v8::JitCodeEventHandler>(data); 237 reinterpret_cast<v8::JitCodeEventHandler>(data);
79 isolate->SetJitCodeEventHandler( 238 isolate->SetJitCodeEventHandler(
80 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler); 239 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler);
81 } 240 }
82 241
83 // static 242 // static
84 void Sampler::HandleJitCodeEvent(const v8::JitCodeEvent* event) { 243 void Sampler::HandleJitCodeEvent(const v8::JitCodeEvent* event) {
85 // Called on the sampled V8 thread. 244 // Called on the sampled V8 thread.
245 Sampler* sampler = GetInstance();
246 // The sampler may have already been destroyed.
247 // That's fine, we're not interested in these events anymore.
248 if (!sampler)
249 return;
86 switch (event->type) { 250 switch (event->type) {
87 case v8::JitCodeEvent::CODE_ADDED: 251 case v8::JitCodeEvent::CODE_ADDED:
88 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 252 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
89 "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data", 253 "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data",
90 JitCodeEventToTraceFormat(event)); 254 JitCodeEventToTraceFormat(event));
255 base::subtle::NoBarrier_AtomicIncrement(
256 &sampler->code_added_events_count_, 1);
91 break; 257 break;
92 258
93 case v8::JitCodeEvent::CODE_MOVED: 259 case v8::JitCodeEvent::CODE_MOVED:
94 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 260 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
95 "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data", 261 "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data",
96 JitCodeEventToTraceFormat(event)); 262 JitCodeEventToTraceFormat(event));
97 break; 263 break;
98 264
99 case v8::JitCodeEvent::CODE_REMOVED: 265 case v8::JitCodeEvent::CODE_REMOVED:
100 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 266 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
101 "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data", 267 "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data",
102 JitCodeEventToTraceFormat(event)); 268 JitCodeEventToTraceFormat(event));
103 break; 269 break;
104 270
105 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: 271 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
106 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: 272 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
107 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: 273 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
108 break; 274 break;
109 } 275 }
110 } 276 }
111 277
112 // static 278 // static
113 scoped_refptr<base::trace_event::ConvertableToTraceFormat> 279 scoped_refptr<ConvertableToTraceFormat> Sampler::JitCodeEventToTraceFormat(
114 Sampler::JitCodeEventToTraceFormat(const v8::JitCodeEvent* event) { 280 const v8::JitCodeEvent* event) {
115 // Called on the sampled thread.
116 switch (event->type) { 281 switch (event->type) {
117 case v8::JitCodeEvent::CODE_ADDED: { 282 case v8::JitCodeEvent::CODE_ADDED: {
118 scoped_refptr<TracedValue> data(new TracedValue()); 283 scoped_refptr<TracedValue> data(new TracedValue());
119 data->SetString("code_start", PtrToString(event->code_start)); 284 data->SetString("code_start", PtrToString(event->code_start));
120 data->SetInteger("code_len", static_cast<unsigned>(event->code_len)); 285 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
121 data->SetString("name", std::string(event->name.str, event->name.len)); 286 data->SetString("name", std::string(event->name.str, event->name.len));
122 return data; 287 return data;
123 } 288 }
124 289
125 case v8::JitCodeEvent::CODE_MOVED: { 290 case v8::JitCodeEvent::CODE_MOVED: {
(...skipping 28 matching lines...) Expand all
154 319
155 void Start(); 320 void Start();
156 void Stop(); 321 void Stop();
157 322
158 private: 323 private:
159 void Sample(); 324 void Sample();
160 void InstallSamplers(); 325 void InstallSamplers();
161 void RemoveSamplers(); 326 void RemoveSamplers();
162 void StartSamplers(); 327 void StartSamplers();
163 void StopSamplers(); 328 void StopSamplers();
329
330 static void InstallSignalHandler();
331 static void RestoreSignalHandler();
332 #ifdef USE_SIGNALS
333 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
334 #endif
335
164 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); 336 static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
165 337
166 Sampler* render_thread_sampler_; 338 Sampler* render_thread_sampler_;
167 base::CancellationFlag cancellation_flag_; 339 base::CancellationFlag cancellation_flag_;
168 base::WaitableEvent* waitable_event_for_testing_; 340 base::WaitableEvent* waitable_event_for_testing_;
169 base::PlatformThreadHandle sampling_thread_handle_; 341 base::PlatformThreadHandle sampling_thread_handle_;
170 std::vector<Sampler*> samplers_; 342 std::vector<Sampler*> samplers_;
171 343
344 #ifdef USE_SIGNALS
345 static bool signal_handler_installed_;
346 static struct sigaction old_signal_handler_;
347 #endif
348
172 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread); 349 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread);
173 }; 350 };
174 351
352 #ifdef USE_SIGNALS
353 bool V8SamplingThread::signal_handler_installed_;
354 struct sigaction V8SamplingThread::old_signal_handler_;
355 #endif
356
175 V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler, 357 V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler,
176 base::WaitableEvent* event) 358 base::WaitableEvent* event)
177 : render_thread_sampler_(render_thread_sampler), 359 : render_thread_sampler_(render_thread_sampler),
178 waitable_event_for_testing_(event) { 360 waitable_event_for_testing_(event) {
179 } 361 }
180 362
181 void V8SamplingThread::ThreadMain() { 363 void V8SamplingThread::ThreadMain() {
182 base::PlatformThread::SetName("V8SamplingProfilerThread"); 364 base::PlatformThread::SetName("V8SamplingProfilerThread");
183 InstallSamplers(); 365 InstallSamplers();
184 StartSamplers(); 366 StartSamplers();
367 InstallSignalHandler();
185 const int kSamplingFrequencyMicroseconds = 1000; 368 const int kSamplingFrequencyMicroseconds = 1000;
186 while (!cancellation_flag_.IsSet()) { 369 while (!cancellation_flag_.IsSet()) {
187 Sample(); 370 Sample();
188 if (waitable_event_for_testing_) { 371 if (waitable_event_for_testing_ &&
372 render_thread_sampler_->EventsCollectedForTest()) {
189 waitable_event_for_testing_->Signal(); 373 waitable_event_for_testing_->Signal();
190 } 374 }
375 // TODO(alph): make the samples firing interval not depend on the sample
376 // taking duration.
191 base::PlatformThread::Sleep( 377 base::PlatformThread::Sleep(
192 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); 378 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
193 } 379 }
380 RestoreSignalHandler();
194 StopSamplers(); 381 StopSamplers();
195 RemoveSamplers(); 382 RemoveSamplers();
196 } 383 }
197 384
198 void V8SamplingThread::Sample() { 385 void V8SamplingThread::Sample() {
199 for (Sampler* sampler : samplers_) { 386 for (Sampler* sampler : samplers_) {
200 sampler->Sample(); 387 sampler->Sample();
201 } 388 }
202 } 389 }
203 390
(...skipping 12 matching lines...) Expand all
216 sampler->Start(); 403 sampler->Start();
217 } 404 }
218 } 405 }
219 406
220 void V8SamplingThread::StopSamplers() { 407 void V8SamplingThread::StopSamplers() {
221 for (Sampler* sampler : samplers_) { 408 for (Sampler* sampler : samplers_) {
222 sampler->Stop(); 409 sampler->Stop();
223 } 410 }
224 } 411 }
225 412
413 // static
414 void V8SamplingThread::InstallSignalHandler() {
415 #ifdef USE_SIGNALS
416 // There must be the only one!
417 DCHECK(!signal_handler_installed_);
418 struct sigaction sa;
419 sa.sa_sigaction = &HandleProfilerSignal;
420 sigemptyset(&sa.sa_mask);
421 sa.sa_flags = SA_RESTART | SA_SIGINFO;
422 signal_handler_installed_ =
423 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
424 #endif
425 }
426
427 // static
428 void V8SamplingThread::RestoreSignalHandler() {
429 #ifdef USE_SIGNALS
430 if (!signal_handler_installed_)
431 return;
432 sigaction(SIGPROF, &old_signal_handler_, 0);
433 signal_handler_installed_ = false;
434 #endif
435 }
436
437 #ifdef USE_SIGNALS
438 // static
439 void V8SamplingThread::HandleProfilerSignal(int signal,
440 siginfo_t* info,
441 void* context) {
442 if (signal != SIGPROF)
443 return;
444 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
445 mcontext_t& mcontext = ucontext->uc_mcontext;
446 v8::RegisterState state;
447
448 #if defined(OS_ANDROID)
449 // TODO(alph): Add support for Android
450 ALLOW_UNUSED_LOCAL(mcontext);
451
452 #elif defined(OS_MACOSX)
453 #if ARCH_CPU_64_BITS
454 state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
455 state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
456 state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
457 #elif ARCH_CPU_32_BITS
458 state.pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
459 state.sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
460 state.fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
461 #endif // ARCH_CPU_32_BITS
462
463 #else
464 #if ARCH_CPU_64_BITS
465 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
466 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
467 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
468 #elif ARCH_CPU_32_BITS
469 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
470 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
471 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
472 #endif // ARCH_CPU_32_BITS
473 #endif
474 Sampler::GetInstance()->DoSample(state);
475 }
476 #endif
477
226 void V8SamplingThread::Start() { 478 void V8SamplingThread::Start() {
227 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { 479 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) {
228 DCHECK(false) << "failed to create thread"; 480 DCHECK(false) << "failed to create sampling thread";
229 } 481 }
230 } 482 }
231 483
232 void V8SamplingThread::Stop() { 484 void V8SamplingThread::Stop() {
233 cancellation_flag_.Set(); 485 cancellation_flag_.Set();
234 base::PlatformThread::Join(sampling_thread_handle_); 486 base::PlatformThread::Join(sampling_thread_handle_);
235 } 487 }
236 488
237 V8SamplingProfiler::V8SamplingProfiler(bool underTest) 489 V8SamplingProfiler::V8SamplingProfiler(bool underTest)
238 : sampling_thread_(nullptr), 490 : sampling_thread_(nullptr),
239 render_thread_sampler_(Sampler::CreateForCurrentThread()) { 491 render_thread_sampler_(Sampler::CreateForCurrentThread()),
492 message_loop_proxy_(base::MessageLoopProxy::current()) {
240 DCHECK(underTest || RenderThreadImpl::current()); 493 DCHECK(underTest || RenderThreadImpl::current());
241 // Force the "v8.cpu_profile" category to show up in the trace viewer. 494 // Force the "v8.cpu_profile" category to show up in the trace viewer.
242 TraceLog::GetCategoryGroupEnabled( 495 TraceLog::GetCategoryGroupEnabled(
243 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile")); 496 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"));
244 TraceLog::GetInstance()->AddEnabledStateObserver(this); 497 TraceLog::GetInstance()->AddEnabledStateObserver(this);
245 } 498 }
246 499
247 V8SamplingProfiler::~V8SamplingProfiler() { 500 V8SamplingProfiler::~V8SamplingProfiler() {
248 TraceLog::GetInstance()->RemoveEnabledStateObserver(this); 501 TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
249 DCHECK(!sampling_thread_.get()); 502 DCHECK(!sampling_thread_.get());
250 } 503 }
251 504
505 void V8SamplingProfiler::StartSamplingThread() {
506 DCHECK(!sampling_thread_.get());
507 sampling_thread_.reset(new V8SamplingThread(
508 render_thread_sampler_.get(), waitable_event_for_testing_.get()));
509 sampling_thread_->Start();
510 }
511
252 void V8SamplingProfiler::OnTraceLogEnabled() { 512 void V8SamplingProfiler::OnTraceLogEnabled() {
253 bool enabled; 513 bool enabled;
254 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 514 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
255 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), &enabled); 515 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), &enabled);
256 if (!enabled) 516 if (!enabled)
257 return; 517 return;
258 518
259 // Do not enable sampling profiler in continuous mode, as losing 519 // Do not enable sampling profiler in continuous mode, as losing
260 // Jit code events may not be afforded. 520 // Jit code events may not be afforded.
521 // TODO(alph): add support of infinite recording of meta trace events.
261 base::trace_event::TraceRecordMode record_mode = 522 base::trace_event::TraceRecordMode record_mode =
262 TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode; 523 TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode;
263 if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY) 524 if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY)
264 return; 525 return;
265 526
266 DCHECK(!sampling_thread_.get()); 527 message_loop_proxy_->PostTask(
267 sampling_thread_.reset(new V8SamplingThread( 528 FROM_HERE, base::Bind(&V8SamplingProfiler::StartSamplingThread,
268 render_thread_sampler_.get(), waitable_event_for_testing_.get())); 529 base::Unretained(this)));
269 sampling_thread_->Start();
270 } 530 }
271 531
272 void V8SamplingProfiler::OnTraceLogDisabled() { 532 void V8SamplingProfiler::OnTraceLogDisabled() {
273 if (!sampling_thread_.get()) 533 if (!sampling_thread_.get())
274 return; 534 return;
275 sampling_thread_->Stop(); 535 sampling_thread_->Stop();
276 sampling_thread_.reset(); 536 sampling_thread_.reset();
277 } 537 }
278 538
279 void V8SamplingProfiler::EnableSamplingEventForTesting() { 539 void V8SamplingProfiler::EnableSamplingEventForTesting() {
280 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); 540 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false));
281 } 541 }
282 542
283 void V8SamplingProfiler::WaitSamplingEventForTesting() { 543 void V8SamplingProfiler::WaitSamplingEventForTesting() {
284 waitable_event_for_testing_->Wait(); 544 waitable_event_for_testing_->Wait();
285 } 545 }
286 546
287 } // namespace blink 547 } // 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