Chromium Code Reviews| 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 |