OLD | NEW |
---|---|
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) | 7 #if defined(OS_POSIX) |
8 #include <signal.h> | 8 #include <signal.h> |
9 #define USE_SIGNALS | 9 #define USE_SIGNALS |
10 #endif | 10 #endif |
11 | 11 |
12 #include "base/format_macros.h" | 12 #include "base/format_macros.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "base/synchronization/cancellation_flag.h" | 14 #include "base/synchronization/cancellation_flag.h" |
15 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
16 #include "base/trace_event/trace_event.h" | 16 #include "base/trace_event/trace_event.h" |
17 #include "base/trace_event/trace_event_argument.h" | 17 #include "base/trace_event/trace_event_argument.h" |
18 #if defined(OS_WIN) | |
19 #include "base/win/scoped_handle.h" | |
yurys
2015/03/24 14:15:25
Please minimize number of dependencies on base/ an
alph
2015/03/24 14:17:08
Acknowledged.
| |
20 #endif | |
18 #include "content/renderer/devtools/lock_free_circular_queue.h" | 21 #include "content/renderer/devtools/lock_free_circular_queue.h" |
19 #include "content/renderer/render_thread_impl.h" | 22 #include "content/renderer/render_thread_impl.h" |
20 #include "v8/include/v8.h" | 23 #include "v8/include/v8.h" |
21 | 24 |
22 using base::trace_event::ConvertableToTraceFormat; | 25 using base::trace_event::ConvertableToTraceFormat; |
23 using base::trace_event::TraceLog; | 26 using base::trace_event::TraceLog; |
24 using base::trace_event::TracedValue; | 27 using base::trace_event::TracedValue; |
25 using v8::Isolate; | 28 using v8::Isolate; |
26 | 29 |
27 namespace content { | 30 namespace content { |
28 | 31 |
29 namespace { | 32 namespace { |
30 | 33 |
34 #if defined(OS_WIN) | |
35 typedef base::win::ScopedHandle UniversalThreadHandle; | |
36 #else | |
37 typedef base::PlatformThreadHandle UniversalThreadHandle; | |
38 #endif | |
39 | |
31 std::string PtrToString(const void* value) { | 40 std::string PtrToString(const void* value) { |
32 return base::StringPrintf( | 41 return base::StringPrintf( |
33 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value))); | 42 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value))); |
34 } | 43 } |
35 | 44 |
36 class SampleRecord { | 45 class SampleRecord { |
37 public: | 46 public: |
38 static const int kMaxFramesCountLog2 = 8; | 47 static const int kMaxFramesCountLog2 = 8; |
39 static const unsigned kMaxFramesCount = (1u << kMaxFramesCountLog2) - 1; | 48 static const unsigned kMaxFramesCount = (1u << kMaxFramesCountLog2) - 1; |
40 | 49 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 sample_events_to_collect_for_test_; | 138 sample_events_to_collect_for_test_; |
130 } | 139 } |
131 | 140 |
132 private: | 141 private: |
133 Sampler(); | 142 Sampler(); |
134 | 143 |
135 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); | 144 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); |
136 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); | 145 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); |
137 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat( | 146 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat( |
138 const v8::JitCodeEvent* event); | 147 const v8::JitCodeEvent* event); |
139 static base::PlatformThreadHandle GetCurrentThreadHandle(); | 148 static UniversalThreadHandle GetCurrentThreadHandle(); |
140 | 149 |
141 void InjectPendingEvents(); | 150 void InjectPendingEvents(); |
142 | 151 |
143 static const unsigned kNumberOfSamples = 10; | 152 static const unsigned kNumberOfSamples = 10; |
144 typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue; | 153 typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue; |
145 | 154 |
146 base::PlatformThreadId thread_id_; | 155 base::PlatformThreadId thread_id_; |
147 base::PlatformThreadHandle thread_handle_; | 156 UniversalThreadHandle thread_handle_; |
148 Isolate* isolate_; | 157 Isolate* isolate_; |
149 scoped_ptr<SamplingQueue> samples_data_; | 158 scoped_ptr<SamplingQueue> samples_data_; |
150 base::subtle::Atomic32 code_added_events_count_; | 159 base::subtle::Atomic32 code_added_events_count_; |
151 base::subtle::Atomic32 samples_count_; | 160 base::subtle::Atomic32 samples_count_; |
152 int code_added_events_to_collect_for_test_; | 161 int code_added_events_to_collect_for_test_; |
153 int sample_events_to_collect_for_test_; | 162 int sample_events_to_collect_for_test_; |
154 | 163 |
155 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky | 164 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky |
156 tls_instance_; | 165 tls_instance_; |
157 }; | 166 }; |
(...skipping 18 matching lines...) Expand all Loading... | |
176 DCHECK(GetInstance()); | 185 DCHECK(GetInstance()); |
177 tls_instance_.Pointer()->Set(nullptr); | 186 tls_instance_.Pointer()->Set(nullptr); |
178 } | 187 } |
179 | 188 |
180 // static | 189 // static |
181 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { | 190 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { |
182 return scoped_ptr<Sampler>(new Sampler()); | 191 return scoped_ptr<Sampler>(new Sampler()); |
183 } | 192 } |
184 | 193 |
185 // static | 194 // static |
186 base::PlatformThreadHandle Sampler::GetCurrentThreadHandle() { | 195 UniversalThreadHandle Sampler::GetCurrentThreadHandle() { |
187 #ifdef OS_WIN | 196 #ifdef OS_WIN |
188 // TODO(alph): Add Windows support. | 197 return base::win::ScopedHandle(::OpenThread( |
189 return base::PlatformThreadHandle(); | 198 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, |
199 false, base::PlatformThread::CurrentId())); | |
190 #else | 200 #else |
191 return base::PlatformThread::CurrentHandle(); | 201 return base::PlatformThread::CurrentHandle(); |
192 #endif | 202 #endif |
193 } | 203 } |
194 | 204 |
195 void Sampler::Start() { | 205 void Sampler::Start() { |
196 samples_data_.reset(new SamplingQueue()); | 206 samples_data_.reset(new SamplingQueue()); |
197 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; | 207 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; |
198 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, | 208 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, |
199 reinterpret_cast<void*>(handler)); | 209 reinterpret_cast<void*>(handler)); |
200 } | 210 } |
201 | 211 |
202 void Sampler::Stop() { | 212 void Sampler::Stop() { |
203 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); | 213 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); |
204 samples_data_.reset(); | 214 samples_data_.reset(); |
205 } | 215 } |
206 | 216 |
217 #if ARCH_CPU_64_BITS | |
218 #define REG_64_32(reg64, reg32) reg64 | |
219 #else | |
220 #define REG_64_32(reg64, reg32) reg32 | |
221 #endif // ARCH_CPU_64_BITS | |
222 | |
207 void Sampler::Sample() { | 223 void Sampler::Sample() { |
208 #if defined(USE_SIGNALS) | 224 #if defined(OS_WIN) |
225 const DWORD kSuspendFailed = static_cast<DWORD>(-1); | |
226 if (::SuspendThread(thread_handle_.Get()) == kSuspendFailed) | |
227 return; | |
228 CONTEXT context; | |
229 memset(&context, 0, sizeof(context)); | |
230 context.ContextFlags = CONTEXT_FULL; | |
231 if (::GetThreadContext(thread_handle_.Get(), &context) != 0) { | |
232 v8::RegisterState state; | |
233 state.pc = reinterpret_cast<void*>(context.REG_64_32(Rip, Eip)); | |
234 state.sp = reinterpret_cast<void*>(context.REG_64_32(Rsp, Esp)); | |
235 state.fp = reinterpret_cast<void*>(context.REG_64_32(Rbp, Ebp)); | |
236 // TODO(alph): It is not needed to buffer the events on Windows. | |
237 // We can just collect and fire trace event right away. | |
238 DoSample(state); | |
239 } | |
240 ::ResumeThread(thread_handle_.Get()); | |
241 #elif defined(USE_SIGNALS) | |
209 int error = pthread_kill(thread_handle_.platform_handle(), SIGPROF); | 242 int error = pthread_kill(thread_handle_.platform_handle(), SIGPROF); |
210 if (error) { | 243 if (error) { |
211 LOG(ERROR) << "pthread_kill failed with error " << error << " " | 244 LOG(ERROR) << "pthread_kill failed with error " << error << " " |
212 << strerror(error); | 245 << strerror(error); |
213 } | 246 } |
247 #endif | |
214 InjectPendingEvents(); | 248 InjectPendingEvents(); |
215 #endif | |
216 } | 249 } |
217 | 250 |
218 void Sampler::DoSample(const v8::RegisterState& state) { | 251 void Sampler::DoSample(const v8::RegisterState& state) { |
219 // Called in the sampled thread signal handler. | 252 // Called in the sampled thread signal handler. |
220 // Because of that it is not allowed to do any memory allocation here. | 253 // Because of that it is not allowed to do any memory allocation here. |
221 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime(); | 254 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime(); |
222 SampleRecord* record = samples_data_->StartEnqueue(); | 255 SampleRecord* record = samples_data_->StartEnqueue(); |
223 if (!record) | 256 if (!record) |
224 return; | 257 return; |
225 record->Collect(isolate_, timestamp, state); | 258 record->Collect(isolate_, timestamp, state); |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
450 void V8SamplingThread::HandleProfilerSignal(int signal, | 483 void V8SamplingThread::HandleProfilerSignal(int signal, |
451 siginfo_t* info, | 484 siginfo_t* info, |
452 void* context) { | 485 void* context) { |
453 if (signal != SIGPROF) | 486 if (signal != SIGPROF) |
454 return; | 487 return; |
455 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 488 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
456 mcontext_t& mcontext = ucontext->uc_mcontext; | 489 mcontext_t& mcontext = ucontext->uc_mcontext; |
457 v8::RegisterState state; | 490 v8::RegisterState state; |
458 | 491 |
459 #if defined(ARCH_CPU_ARM_FAMILY) | 492 #if defined(ARCH_CPU_ARM_FAMILY) |
460 | 493 state.pc = reinterpret_cast<void*>(mcontext.REG_64_32(pc, arm_pc)); |
461 #if ARCH_CPU_64_BITS | 494 state.sp = reinterpret_cast<void*>(mcontext.REG_64_32(sp, arm_sp)); |
462 state.pc = reinterpret_cast<void*>(mcontext.pc); | 495 state.fp = reinterpret_cast<void*>(mcontext.REG_64_32(regs[29], arm_fp)); |
463 state.sp = reinterpret_cast<void*>(mcontext.sp); | |
464 state.fp = reinterpret_cast<void*>(mcontext.regs[29]); | |
465 #elif ARCH_CPU_32_BITS | |
466 state.pc = reinterpret_cast<void*>(mcontext.arm_pc); | |
467 state.sp = reinterpret_cast<void*>(mcontext.arm_sp); | |
468 state.fp = reinterpret_cast<void*>(mcontext.arm_fp); | |
469 #endif // ARCH_CPU_32_BITS | |
470 | 496 |
471 #elif defined(ARCH_CPU_X86_FAMILY) | 497 #elif defined(ARCH_CPU_X86_FAMILY) |
472 | |
473 #if defined(OS_MACOSX) | 498 #if defined(OS_MACOSX) |
474 #if ARCH_CPU_64_BITS | 499 state.pc = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rip, __eip)); |
475 state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip); | 500 state.sp = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rsp, __esp)); |
476 state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp); | 501 state.fp = reinterpret_cast<void*>(mcontext->__ss.REG_64_32(__rbp, __ebp)); |
477 state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp); | |
478 #elif ARCH_CPU_32_BITS | |
479 state.pc = reinterpret_cast<void*>(mcontext->__ss.__eip); | |
480 state.sp = reinterpret_cast<void*>(mcontext->__ss.__esp); | |
481 state.fp = reinterpret_cast<void*>(mcontext->__ss.__ebp); | |
482 #endif // ARCH_CPU_32_BITS | |
483 | |
484 #else | 502 #else |
485 #if ARCH_CPU_64_BITS | 503 state.pc = |
486 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]); | 504 reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RIP, REG_EIP)]); |
487 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]); | 505 state.sp = |
488 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]); | 506 reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RSP, REG_ESP)]); |
489 #elif ARCH_CPU_32_BITS | 507 state.fp = |
490 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]); | 508 reinterpret_cast<void*>(mcontext.gregs[REG_64_32(REG_RBP, REG_EBP)]); |
491 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]); | |
492 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]); | |
493 #endif // ARCH_CPU_32_BITS | |
494 #endif // OS_MACOS | 509 #endif // OS_MACOS |
495 #endif // ARCH_CPU_X86_FAMILY | 510 #endif // ARCH_CPU_X86_FAMILY |
496 | 511 |
497 Sampler::GetInstance()->DoSample(state); | 512 Sampler::GetInstance()->DoSample(state); |
498 } | 513 } |
499 #endif | 514 #endif |
500 | 515 |
501 void V8SamplingThread::Start() { | 516 void V8SamplingThread::Start() { |
502 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { | 517 if (!base::PlatformThread::Create(0, this, &sampling_thread_handle_)) { |
503 DCHECK(false) << "failed to create sampling thread"; | 518 DCHECK(false) << "failed to create sampling thread"; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
564 render_thread_sampler_->SetEventsToCollectForTest(code_added_events, | 579 render_thread_sampler_->SetEventsToCollectForTest(code_added_events, |
565 sample_events); | 580 sample_events); |
566 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); | 581 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); |
567 } | 582 } |
568 | 583 |
569 void V8SamplingProfiler::WaitSamplingEventForTesting() { | 584 void V8SamplingProfiler::WaitSamplingEventForTesting() { |
570 waitable_event_for_testing_->Wait(); | 585 waitable_event_for_testing_->Wait(); |
571 } | 586 } |
572 | 587 |
573 } // namespace blink | 588 } // namespace blink |
OLD | NEW |