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

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: 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>
yurys 2015/03/18 12:49:03 You'll likely need <ucontext.h> and <mach/mach.h>
alph 2015/03/18 13:37:49 It compiles so far. I'll add these includes when i
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"
13 #include "content/renderer/render_thread_impl.h" 18 #include "content/renderer/render_thread_impl.h"
14 #include "v8/include/v8.h" 19 #include "v8/include/v8.h"
15 20
21 using base::trace_event::ConvertableToTraceFormat;
16 using base::trace_event::TraceLog; 22 using base::trace_event::TraceLog;
17 using base::trace_event::TracedValue; 23 using base::trace_event::TracedValue;
18 using v8::Isolate; 24 using v8::Isolate;
19 25
20 namespace content { 26 namespace content {
21 27
22 namespace { 28 namespace {
23 29
24 std::string PtrToString(const void* value) { 30 std::string PtrToString(const void* value) {
25 char buffer[20]; 31 return base::StringPrintf(
26 base::snprintf(buffer, sizeof(buffer), "0x%" PRIx64, 32 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value)));
27 static_cast<uint64>(reinterpret_cast<intptr_t>(value))); 33 }
28 return buffer; 34
35 // Lock-free cache-friendly sampling circular queue for large
36 // records. Intended for fast transfer of large records between a
37 // single producer and a single consumer. If the queue is full,
38 // StartEnqueue will return nullptr. The queue is designed with
39 // a goal in mind to evade cache lines thrashing by preventing
40 // simultaneous reads and writes to adjanced memory locations.
41 template <typename T, unsigned Length>
42 class SamplingCircularQueue {
yurys 2015/03/18 12:49:04 Let's move it in a separate file.
alph 2015/03/18 13:37:49 Done.
43 public:
44 // Executed on the application thread.
45 SamplingCircularQueue();
46 ~SamplingCircularQueue();
47
48 // StartEnqueue returns a pointer to a memory location for storing the next
49 // record or nullptr if all entries are full at the moment.
50 T* StartEnqueue();
51 // Notifies the queue that the producer has complete writing data into the
52 // memory returned by StartEnqueue and it can be passed to the consumer.
53 void FinishEnqueue();
54
55 // Executed on the consumer (analyzer) thread.
56 // Retrieves, but does not remove, the head of this queue, returning nullptr
57 // if this queue is empty. After the record had been read by a consumer,
58 // Remove must be called.
59 T* Peek();
60 void Remove();
61
62 private:
63 // Reserved values for the entry marker.
64 enum {
65 kEmpty, // Marks clean (processed) entries.
66 kFull // Marks entries already filled by the producer but not yet
67 // completely processed by the consumer.
68 };
69
70 struct /*V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE)*/ Entry {
71 Entry() : marker(kEmpty) {}
72 T record;
73 base::subtle::Atomic32 marker;
74 };
75
76 Entry* Next(Entry* entry);
77
78 Entry buffer_[Length];
79 /*V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE)*/ Entry* enqueue_pos_;
80 /*V8_ALIGNED(PROCESSOR_CACHE_LINE_SIZE)*/ Entry* dequeue_pos_;
81
82 DISALLOW_COPY_AND_ASSIGN(SamplingCircularQueue);
83 };
84
85 template <typename T, unsigned L>
86 SamplingCircularQueue<T, L>::SamplingCircularQueue()
87 : enqueue_pos_(buffer_), dequeue_pos_(buffer_) {
88 }
89
90 template <typename T, unsigned L>
91 SamplingCircularQueue<T, L>::~SamplingCircularQueue() {
92 }
93
94 template <typename T, unsigned L>
95 T* SamplingCircularQueue<T, L>::Peek() {
96 base::subtle::MemoryBarrier();
97 if (base::subtle::Acquire_Load(&dequeue_pos_->marker) == kFull) {
98 return &dequeue_pos_->record;
99 }
100 return nullptr;
101 }
102
103 template <typename T, unsigned L>
104 void SamplingCircularQueue<T, L>::Remove() {
105 base::subtle::Release_Store(&dequeue_pos_->marker, kEmpty);
106 dequeue_pos_ = Next(dequeue_pos_);
107 }
108
109 template <typename T, unsigned L>
110 T* SamplingCircularQueue<T, L>::StartEnqueue() {
111 base::subtle::MemoryBarrier();
112 if (base::subtle::Acquire_Load(&enqueue_pos_->marker) == kEmpty) {
113 return &enqueue_pos_->record;
114 }
115 return nullptr;
116 }
117
118 template <typename T, unsigned L>
119 void SamplingCircularQueue<T, L>::FinishEnqueue() {
120 base::subtle::Release_Store(&enqueue_pos_->marker, kFull);
121 enqueue_pos_ = Next(enqueue_pos_);
122 }
123
124 template <typename T, unsigned L>
125 typename SamplingCircularQueue<T, L>::Entry* SamplingCircularQueue<T, L>::Next(
126 Entry* entry) {
127 Entry* next = entry + 1;
128 if (next == &buffer_[L])
129 return buffer_;
130 return next;
131 }
132
133 class SampleRecord {
134 public:
135 static const int kMaxFramesCountLog2 = 8;
136 static const unsigned kMaxFramesCount = (1u << kMaxFramesCountLog2) - 1;
137
138 SampleRecord() {}
139
140 base::TimeTicks timestamp() const { return timestamp_; }
141 void Collect(v8::Isolate* isolate,
142 base::TimeTicks timestamp,
143 const v8::RegisterState& state);
144 scoped_refptr<ConvertableToTraceFormat> ToTraceFormat() const;
145
146 private:
147 base::TimeTicks timestamp_;
148 unsigned vm_state_ : 4;
149 unsigned frames_count_ : kMaxFramesCountLog2;
150 const void* frames_[kMaxFramesCount];
151
152 DISALLOW_COPY_AND_ASSIGN(SampleRecord);
153 };
154
155 void SampleRecord::Collect(v8::Isolate* isolate,
156 base::TimeTicks timestamp,
157 const v8::RegisterState& state) {
158 v8::SampleInfo sample_info;
159 isolate->GetStackSample(state, (void**)frames_, kMaxFramesCount,
160 &sample_info);
161 timestamp_ = timestamp;
162 frames_count_ = sample_info.frames_count;
163 vm_state_ = sample_info.vm_state;
164 }
165
166 scoped_refptr<ConvertableToTraceFormat> SampleRecord::ToTraceFormat() const {
167 scoped_refptr<TracedValue> data(new TracedValue());
168 const char* vm_state = nullptr;
169 switch (vm_state_) {
170 case v8::StateTag::JS:
171 vm_state = "js";
172 break;
173 case v8::StateTag::GC:
174 vm_state = "gc";
175 break;
176 case v8::StateTag::COMPILER:
177 vm_state = "compiler";
178 break;
179 case v8::StateTag::OTHER:
180 vm_state = "other";
181 break;
182 case v8::StateTag::EXTERNAL:
183 vm_state = "external";
184 break;
185 case v8::StateTag::IDLE:
186 vm_state = "idle";
187 break;
188 default:
189 NOTREACHED();
190 }
191 data->SetString("vm_state", vm_state);
192 data->BeginArray("stack");
193 for (unsigned i = 0; i < frames_count_; ++i) {
194 data->AppendString(PtrToString(frames_[i]));
195 }
196 data->EndArray();
197 return data;
29 } 198 }
30 199
31 } // namespace 200 } // namespace
32 201
33 // The class implements a sampler responsible for sampling a single thread. 202 // The class implements a sampler responsible for sampling a single thread.
34 class Sampler { 203 class Sampler {
35 public: 204 public:
36 explicit Sampler(Isolate* isolate) : isolate_(isolate) { DCHECK(isolate_); } 205 Sampler(base::PlatformThreadHandle thread_handle,
206 base::PlatformThreadId thread_id,
207 Isolate* isolate);
208 ~Sampler();
37 209
38 static scoped_ptr<Sampler> CreateForCurrentThread(); 210 static scoped_ptr<Sampler> CreateForCurrentThread();
211 static Sampler* GetInstance() { return tls_instance_.Pointer()->Get(); }
39 212
40 // These methods are called from the sampling thread. 213 // These methods are called from the sampling thread.
41 void Start(); 214 void Start();
42 void Stop(); 215 void Stop();
43 void Sample(); 216 void Sample();
44 217
218 void DoSample(const v8::RegisterState& state);
219
220 bool EventsCollectedForTest() const {
221 return base::subtle::NoBarrier_Load(&code_added_events_count_) != 0 ||
222 base::subtle::NoBarrier_Load(&samples_count_) != 0;
223 }
224
45 private: 225 private:
46 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); 226 static void InstallJitCodeEventHandler(Isolate* isolate, void* data);
47 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); 227 static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
48 static scoped_refptr<base::trace_event::ConvertableToTraceFormat> 228 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat(
49 JitCodeEventToTraceFormat(const v8::JitCodeEvent* event); 229 const v8::JitCodeEvent* event);
50 230
231 void InjectPendingEvents();
232
233 static const unsigned kNumberOfSamples = 10;
234 typedef SamplingCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue;
235
236 base::PlatformThreadId thread_id_;
237 base::PlatformThreadHandle thread_handle_;
51 Isolate* isolate_; 238 Isolate* isolate_;
239 scoped_ptr<SamplingQueue> samples_data_;
240 base::subtle::Atomic32 code_added_events_count_;
241 base::subtle::Atomic32 samples_count_;
242
243 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
244 tls_instance_;
52 }; 245 };
53 246
247 base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky
248 Sampler::tls_instance_ = LAZY_INSTANCE_INITIALIZER;
249
250 Sampler::Sampler(base::PlatformThreadHandle thread_handle,
251 base::PlatformThreadId thread_id,
252 Isolate* isolate)
253 : thread_id_(thread_id),
254 thread_handle_(thread_handle),
255 isolate_(isolate),
256 code_added_events_count_(0),
257 samples_count_(0) {
258 DCHECK(isolate_);
259 DCHECK(!GetInstance());
260 tls_instance_.Pointer()->Set(this);
261 }
262
263 Sampler::~Sampler() {
264 DCHECK(GetInstance());
265 tls_instance_.Pointer()->Set(nullptr);
yurys 2015/03/18 12:49:03 It is not safe to access TLS storage in signal han
alph 2015/03/18 13:37:49 It should be safe provided that: - the tls variabl
266 }
267
54 // static 268 // static
55 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { 269 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() {
56 return scoped_ptr<Sampler>(new Sampler(Isolate::GetCurrent())); 270 return scoped_ptr<Sampler>(new Sampler(base::PlatformThread::CurrentHandle(),
271 base::PlatformThread::CurrentId(),
272 Isolate::GetCurrent()));
57 } 273 }
58 274
59 void Sampler::Start() { 275 void Sampler::Start() {
276 samples_data_.reset(new SamplingQueue());
60 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; 277 v8::JitCodeEventHandler handler = &HandleJitCodeEvent;
61 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, 278 isolate_->RequestInterrupt(&InstallJitCodeEventHandler,
62 reinterpret_cast<void*>(handler)); 279 reinterpret_cast<void*>(handler));
63 } 280 }
64 281
65 void Sampler::Stop() { 282 void Sampler::Stop() {
66 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); 283 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr);
284 samples_data_.reset();
67 } 285 }
68 286
69 void Sampler::Sample() { 287 void Sampler::Sample() {
288 #if defined(USE_SIGNALS)
289 int error = pthread_kill(thread_handle_.platform_handle(), SIGPROF);
290 if (error) {
291 LOG(ERROR) << "pthread_kill failed with error " << error << " "
292 << strerror(error);
293 }
294 InjectPendingEvents();
295 #endif
296 }
297
298 void Sampler::DoSample(const v8::RegisterState& state) {
299 // Called in the sampled thread signal handler.
300 // Because of that it is not allowed to do any memory allocation here.
301 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime();
302 SampleRecord* record = samples_data_->StartEnqueue();
303 if (!record) {
304 LOG(ERROR) << "No space left in the sampling buffer";
yurys 2015/03/18 12:49:04 I'm pretty much sure it will allocate.
alph 2015/03/18 13:37:49 Acknowledged.
305 return;
306 }
307 record->Collect(isolate_, timestamp, state);
308 samples_data_->FinishEnqueue();
309 base::subtle::NoBarrier_AtomicIncrement(&samples_count_, 1);
310 }
311
312 void Sampler::InjectPendingEvents() {
313 SampleRecord* record = samples_data_->Peek();
314 while (record) {
315 TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(
316 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), "V8Sample", thread_id_,
317 (record->timestamp() - base::TimeTicks()).InMicroseconds(), "data",
318 record->ToTraceFormat());
319 samples_data_->Remove();
320 record = samples_data_->Peek();
321 }
70 } 322 }
71 323
72 // static 324 // static
73 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) { 325 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) {
74 // Called on the sampled V8 thread. 326 // Called on the sampled V8 thread.
75 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 327 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
76 "Sampler::InstallJitCodeEventHandler"); 328 "Sampler::InstallJitCodeEventHandler");
77 v8::JitCodeEventHandler handler = 329 v8::JitCodeEventHandler handler =
78 reinterpret_cast<v8::JitCodeEventHandler>(data); 330 reinterpret_cast<v8::JitCodeEventHandler>(data);
79 isolate->SetJitCodeEventHandler( 331 isolate->SetJitCodeEventHandler(
80 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler); 332 v8::JitCodeEventOptions::kJitCodeEventEnumExisting, handler);
81 } 333 }
82 334
83 // static 335 // static
84 void Sampler::HandleJitCodeEvent(const v8::JitCodeEvent* event) { 336 void Sampler::HandleJitCodeEvent(const v8::JitCodeEvent* event) {
85 // Called on the sampled V8 thread. 337 // Called on the sampled V8 thread.
338 Sampler* sampler = GetInstance();
339 // The sampler may have already been destroyed.
340 // That's fine, we're not interested in these events anymore.
341 if (!sampler)
342 return;
86 switch (event->type) { 343 switch (event->type) {
87 case v8::JitCodeEvent::CODE_ADDED: 344 case v8::JitCodeEvent::CODE_ADDED:
88 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 345 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
89 "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data", 346 "JitCodeAdded", TRACE_EVENT_SCOPE_THREAD, "data",
90 JitCodeEventToTraceFormat(event)); 347 JitCodeEventToTraceFormat(event));
348 base::subtle::NoBarrier_AtomicIncrement(
349 &sampler->code_added_events_count_, 1);
91 break; 350 break;
92 351
93 case v8::JitCodeEvent::CODE_MOVED: 352 case v8::JitCodeEvent::CODE_MOVED:
94 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 353 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
95 "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data", 354 "JitCodeMoved", TRACE_EVENT_SCOPE_THREAD, "data",
96 JitCodeEventToTraceFormat(event)); 355 JitCodeEventToTraceFormat(event));
97 break; 356 break;
98 357
99 case v8::JitCodeEvent::CODE_REMOVED: 358 case v8::JitCodeEvent::CODE_REMOVED:
100 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), 359 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"),
101 "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data", 360 "JitCodeRemoved", TRACE_EVENT_SCOPE_THREAD, "data",
102 JitCodeEventToTraceFormat(event)); 361 JitCodeEventToTraceFormat(event));
103 break; 362 break;
104 363
105 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: 364 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO:
106 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: 365 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING:
107 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: 366 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING:
108 break; 367 break;
109 } 368 }
110 } 369 }
111 370
112 // static 371 // static
113 scoped_refptr<base::trace_event::ConvertableToTraceFormat> 372 scoped_refptr<ConvertableToTraceFormat> Sampler::JitCodeEventToTraceFormat(
114 Sampler::JitCodeEventToTraceFormat(const v8::JitCodeEvent* event) { 373 const v8::JitCodeEvent* event) {
115 // Called on the sampled thread.
116 switch (event->type) { 374 switch (event->type) {
117 case v8::JitCodeEvent::CODE_ADDED: { 375 case v8::JitCodeEvent::CODE_ADDED: {
118 scoped_refptr<TracedValue> data(new TracedValue()); 376 scoped_refptr<TracedValue> data(new TracedValue());
119 data->SetString("code_start", PtrToString(event->code_start)); 377 data->SetString("code_start", PtrToString(event->code_start));
120 data->SetInteger("code_len", static_cast<unsigned>(event->code_len)); 378 data->SetInteger("code_len", static_cast<unsigned>(event->code_len));
121 data->SetString("name", std::string(event->name.str, event->name.len)); 379 data->SetString("name", std::string(event->name.str, event->name.len));
122 return data; 380 return data;
123 } 381 }
124 382
125 case v8::JitCodeEvent::CODE_MOVED: { 383 case v8::JitCodeEvent::CODE_MOVED: {
(...skipping 28 matching lines...) Expand all
154 412
155 void Start(); 413 void Start();
156 void Stop(); 414 void Stop();
157 415
158 private: 416 private:
159 void Sample(); 417 void Sample();
160 void InstallSamplers(); 418 void InstallSamplers();
161 void RemoveSamplers(); 419 void RemoveSamplers();
162 void StartSamplers(); 420 void StartSamplers();
163 void StopSamplers(); 421 void StopSamplers();
422
423 static void InstallSignalHandler();
424 static void RestoreSignalHandler();
425 #ifdef USE_SIGNALS
426 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
427 #endif
428
164 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); 429 static void HandleJitCodeEvent(const v8::JitCodeEvent* event);
165 430
166 Sampler* render_thread_sampler_; 431 Sampler* render_thread_sampler_;
167 base::CancellationFlag cancellation_flag_; 432 base::CancellationFlag cancellation_flag_;
168 base::WaitableEvent* waitable_event_for_testing_; 433 base::WaitableEvent* waitable_event_for_testing_;
169 base::PlatformThreadHandle sampling_thread_handle_; 434 base::PlatformThreadHandle sampling_thread_handle_;
170 std::vector<Sampler*> samplers_; 435 std::vector<Sampler*> samplers_;
171 436
437 static bool signal_handler_installed_;
yurys 2015/03/18 12:49:03 Should be behind #ifdef
alph 2015/03/18 13:37:49 Done.
438 #ifdef USE_SIGNALS
439 static struct sigaction old_signal_handler_;
440 #endif
441
172 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread); 442 DISALLOW_COPY_AND_ASSIGN(V8SamplingThread);
173 }; 443 };
174 444
445 bool V8SamplingThread::signal_handler_installed_;
446 #ifdef USE_SIGNALS
447 struct sigaction V8SamplingThread::old_signal_handler_;
448 #endif
449
175 V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler, 450 V8SamplingThread::V8SamplingThread(Sampler* render_thread_sampler,
176 base::WaitableEvent* event) 451 base::WaitableEvent* event)
177 : render_thread_sampler_(render_thread_sampler), 452 : render_thread_sampler_(render_thread_sampler),
178 waitable_event_for_testing_(event) { 453 waitable_event_for_testing_(event) {
179 } 454 }
180 455
181 void V8SamplingThread::ThreadMain() { 456 void V8SamplingThread::ThreadMain() {
182 base::PlatformThread::SetName("V8SamplingProfilerThread"); 457 base::PlatformThread::SetName("V8SamplingProfilerThread");
183 InstallSamplers(); 458 InstallSamplers();
184 StartSamplers(); 459 StartSamplers();
460 InstallSignalHandler();
185 const int kSamplingFrequencyMicroseconds = 1000; 461 const int kSamplingFrequencyMicroseconds = 1000;
186 while (!cancellation_flag_.IsSet()) { 462 while (!cancellation_flag_.IsSet()) {
187 Sample(); 463 Sample();
188 if (waitable_event_for_testing_) { 464 if (waitable_event_for_testing_ &&
465 render_thread_sampler_->EventsCollectedForTest()) {
189 waitable_event_for_testing_->Signal(); 466 waitable_event_for_testing_->Signal();
190 } 467 }
468 // TODO(alph): make the samples firing interval not depend on the sample
469 // taking duration.
191 base::PlatformThread::Sleep( 470 base::PlatformThread::Sleep(
192 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); 471 base::TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
193 } 472 }
473 RestoreSignalHandler();
194 StopSamplers(); 474 StopSamplers();
195 RemoveSamplers(); 475 RemoveSamplers();
196 } 476 }
197 477
198 void V8SamplingThread::Sample() { 478 void V8SamplingThread::Sample() {
199 for (Sampler* sampler : samplers_) { 479 for (Sampler* sampler : samplers_) {
200 sampler->Sample(); 480 sampler->Sample();
201 } 481 }
202 } 482 }
203 483
(...skipping 12 matching lines...) Expand all
216 sampler->Start(); 496 sampler->Start();
217 } 497 }
218 } 498 }
219 499
220 void V8SamplingThread::StopSamplers() { 500 void V8SamplingThread::StopSamplers() {
221 for (Sampler* sampler : samplers_) { 501 for (Sampler* sampler : samplers_) {
222 sampler->Stop(); 502 sampler->Stop();
223 } 503 }
224 } 504 }
225 505
506 // static
507 void V8SamplingThread::InstallSignalHandler() {
508 #ifdef USE_SIGNALS
509 // There must be the only one!
510 DCHECK(!signal_handler_installed_);
511 struct sigaction sa;
512 sa.sa_sigaction = &HandleProfilerSignal;
513 sigemptyset(&sa.sa_mask);
514 sa.sa_flags = SA_RESTART | SA_SIGINFO;
515 signal_handler_installed_ =
516 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
517 #endif
518 }
519
520 // static
521 void V8SamplingThread::RestoreSignalHandler() {
522 #ifdef USE_SIGNALS
523 if (!signal_handler_installed_)
524 return;
525 sigaction(SIGPROF, &old_signal_handler_, 0);
526 signal_handler_installed_ = false;
527 #endif
528 }
529
530 #ifdef USE_SIGNALS
531 // static
532 void V8SamplingThread::HandleProfilerSignal(int signal,
533 siginfo_t* info,
534 void* context) {
535 if (signal != SIGPROF)
536 return;
537 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
538 mcontext_t& mcontext = ucontext->uc_mcontext;
539 v8::RegisterState state;
540
541 #if defined(OS_ANDROID)
542 // TODO(alph): Add support for Android
543 ALLOW_UNUSED_LOCAL(mcontext);
544
545 #elif defined(OS_MACOSX)
546 #if ARCH_CPU_64_BITS
547 state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
548 state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
549 state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
550 #elif ARCH_CPU_32_BITS
551 state.pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
552 state.sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
553 state.fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
554 #endif // ARCH_CPU_32_BITS
555
556 #else
557 #if ARCH_CPU_64_BITS
558 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
559 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
560 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
561 #elif ARCH_CPU_32_BITS
562 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
563 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
564 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
565 #endif // ARCH_CPU_32_BITS
566 #endif
567 Sampler::GetInstance()->DoSample(state);
568 }
569 #endif
570
226 void V8SamplingThread::Start() { 571 void V8SamplingThread::Start() {
227 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { 572 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) {
228 DCHECK(false) << "failed to create thread"; 573 DCHECK(false) << "failed to create sampling thread";
229 } 574 }
230 } 575 }
231 576
232 void V8SamplingThread::Stop() { 577 void V8SamplingThread::Stop() {
233 cancellation_flag_.Set(); 578 cancellation_flag_.Set();
234 base::PlatformThread::Join(sampling_thread_handle_); 579 base::PlatformThread::Join(sampling_thread_handle_);
235 } 580 }
236 581
237 V8SamplingProfiler::V8SamplingProfiler(bool underTest) 582 V8SamplingProfiler::V8SamplingProfiler(bool underTest)
238 : sampling_thread_(nullptr), 583 : sampling_thread_(nullptr),
239 render_thread_sampler_(Sampler::CreateForCurrentThread()) { 584 render_thread_sampler_(Sampler::CreateForCurrentThread()),
585 message_loop_proxy_(base::MessageLoopProxy::current()) {
240 DCHECK(underTest || RenderThreadImpl::current()); 586 DCHECK(underTest || RenderThreadImpl::current());
241 // Force the "v8.cpu_profile" category to show up in the trace viewer. 587 // Force the "v8.cpu_profile" category to show up in the trace viewer.
242 TraceLog::GetCategoryGroupEnabled( 588 TraceLog::GetCategoryGroupEnabled(
243 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile")); 589 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"));
244 TraceLog::GetInstance()->AddEnabledStateObserver(this); 590 TraceLog::GetInstance()->AddEnabledStateObserver(this);
245 } 591 }
246 592
247 V8SamplingProfiler::~V8SamplingProfiler() { 593 V8SamplingProfiler::~V8SamplingProfiler() {
248 TraceLog::GetInstance()->RemoveEnabledStateObserver(this); 594 TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
249 DCHECK(!sampling_thread_.get()); 595 DCHECK(!sampling_thread_.get());
250 } 596 }
251 597
598 void V8SamplingProfiler::StartSamplingThread() {
599 DCHECK(!sampling_thread_.get());
600 sampling_thread_.reset(new V8SamplingThread(
601 render_thread_sampler_.get(), waitable_event_for_testing_.get()));
602 sampling_thread_->Start();
603 }
604
252 void V8SamplingProfiler::OnTraceLogEnabled() { 605 void V8SamplingProfiler::OnTraceLogEnabled() {
253 bool enabled; 606 bool enabled;
254 TRACE_EVENT_CATEGORY_GROUP_ENABLED( 607 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
255 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), &enabled); 608 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), &enabled);
256 if (!enabled) 609 if (!enabled)
257 return; 610 return;
258 611
259 // Do not enable sampling profiler in continuous mode, as losing 612 // Do not enable sampling profiler in continuous mode, as losing
260 // Jit code events may not be afforded. 613 // Jit code events may not be afforded.
614 // TODO(alph): add support of infinite recording of meta trace events.
261 base::trace_event::TraceRecordMode record_mode = 615 base::trace_event::TraceRecordMode record_mode =
262 TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode; 616 TraceLog::GetInstance()->GetCurrentTraceOptions().record_mode;
263 if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY) 617 if (record_mode == base::trace_event::TraceRecordMode::RECORD_CONTINUOUSLY)
264 return; 618 return;
265 619
266 DCHECK(!sampling_thread_.get()); 620 message_loop_proxy_->PostTask(
267 sampling_thread_.reset(new V8SamplingThread( 621 FROM_HERE, base::Bind(&V8SamplingProfiler::StartSamplingThread,
268 render_thread_sampler_.get(), waitable_event_for_testing_.get())); 622 base::Unretained(this)));
269 sampling_thread_->Start();
270 } 623 }
271 624
272 void V8SamplingProfiler::OnTraceLogDisabled() { 625 void V8SamplingProfiler::OnTraceLogDisabled() {
273 if (!sampling_thread_.get()) 626 if (!sampling_thread_.get())
274 return; 627 return;
275 sampling_thread_->Stop(); 628 sampling_thread_->Stop();
276 sampling_thread_.reset(); 629 sampling_thread_.reset();
277 } 630 }
278 631
279 void V8SamplingProfiler::EnableSamplingEventForTesting() { 632 void V8SamplingProfiler::EnableSamplingEventForTesting() {
280 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); 633 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false));
281 } 634 }
282 635
283 void V8SamplingProfiler::WaitSamplingEventForTesting() { 636 void V8SamplingProfiler::WaitSamplingEventForTesting() {
284 waitable_event_for_testing_->Wait(); 637 waitable_event_for_testing_->Wait();
285 } 638 }
286 639
287 } // namespace blink 640 } // 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