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 #if defined(OS_WIN) |
| 13 #include <windows.h> |
| 14 #endif |
| 15 |
12 #include "base/format_macros.h" | 16 #include "base/format_macros.h" |
13 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
14 #include "base/synchronization/cancellation_flag.h" | 18 #include "base/synchronization/cancellation_flag.h" |
15 #include "base/threading/platform_thread.h" | 19 #include "base/threading/platform_thread.h" |
16 #include "base/trace_event/trace_event.h" | 20 #include "base/trace_event/trace_event.h" |
17 #include "base/trace_event/trace_event_argument.h" | 21 #include "base/trace_event/trace_event_argument.h" |
18 #if defined(OS_WIN) | |
19 #include "base/win/scoped_handle.h" | |
20 #endif | |
21 #include "content/renderer/devtools/lock_free_circular_queue.h" | 22 #include "content/renderer/devtools/lock_free_circular_queue.h" |
22 #include "content/renderer/render_thread_impl.h" | 23 #include "content/renderer/render_thread_impl.h" |
23 #include "v8/include/v8.h" | 24 #include "v8/include/v8.h" |
24 | 25 |
25 using base::trace_event::ConvertableToTraceFormat; | 26 using base::trace_event::ConvertableToTraceFormat; |
26 using base::trace_event::TraceLog; | 27 using base::trace_event::TraceLog; |
27 using base::trace_event::TracedValue; | 28 using base::trace_event::TracedValue; |
28 using v8::Isolate; | 29 using v8::Isolate; |
29 | 30 |
30 namespace content { | 31 namespace content { |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 #if defined(OS_WIN) | 35 class PlatformDataCommon { |
35 typedef base::win::ScopedHandle UniversalThreadHandle; | 36 public: |
36 #else | 37 base::PlatformThreadId thread_id() { return thread_id_; } |
37 typedef base::PlatformThreadHandle UniversalThreadHandle; | 38 |
| 39 protected: |
| 40 PlatformDataCommon() : thread_id_(base::PlatformThread::CurrentId()) {} |
| 41 |
| 42 private: |
| 43 base::PlatformThreadId thread_id_; |
| 44 }; |
| 45 |
| 46 #if defined(USE_SIGNALS) |
| 47 |
| 48 class PlatformData : public PlatformDataCommon { |
| 49 public: |
| 50 PlatformData() : vm_tid_(pthread_self()) {} |
| 51 pthread_t vm_tid() const { return vm_tid_; } |
| 52 |
| 53 private: |
| 54 pthread_t vm_tid_; |
| 55 }; |
| 56 |
| 57 #elif defined(OS_WIN) |
| 58 |
| 59 class PlatformData : public PlatformDataCommon { |
| 60 public: |
| 61 // Get a handle to the calling thread. This is the thread that we are |
| 62 // going to profile. We need to make a copy of the handle because we are |
| 63 // going to use it in the sampler thread. Using GetThreadHandle() will |
| 64 // not work in this case. We're using OpenThread because DuplicateHandle |
| 65 // doesn't work in Chrome's sandbox. |
| 66 PlatformData() |
| 67 : thread_handle_(::OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | |
| 68 THREAD_QUERY_INFORMATION, |
| 69 false, |
| 70 ::GetCurrentThreadId())) {} |
| 71 |
| 72 ~PlatformData() { |
| 73 if (thread_handle_ == NULL) |
| 74 return; |
| 75 ::CloseHandle(thread_handle_); |
| 76 thread_handle_ = NULL; |
| 77 } |
| 78 |
| 79 HANDLE thread_handle() { return thread_handle_; } |
| 80 |
| 81 private: |
| 82 HANDLE thread_handle_; |
| 83 }; |
38 #endif | 84 #endif |
39 | 85 |
40 std::string PtrToString(const void* value) { | 86 std::string PtrToString(const void* value) { |
41 return base::StringPrintf( | 87 return base::StringPrintf( |
42 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value))); | 88 "0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(value))); |
43 } | 89 } |
44 | 90 |
45 class SampleRecord { | 91 class SampleRecord { |
46 public: | 92 public: |
47 static const int kMaxFramesCountLog2 = 8; | 93 static const int kMaxFramesCountLog2 = 8; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 sample_events_to_collect_for_test_; | 184 sample_events_to_collect_for_test_; |
139 } | 185 } |
140 | 186 |
141 private: | 187 private: |
142 Sampler(); | 188 Sampler(); |
143 | 189 |
144 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); | 190 static void InstallJitCodeEventHandler(Isolate* isolate, void* data); |
145 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); | 191 static void HandleJitCodeEvent(const v8::JitCodeEvent* event); |
146 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat( | 192 static scoped_refptr<ConvertableToTraceFormat> JitCodeEventToTraceFormat( |
147 const v8::JitCodeEvent* event); | 193 const v8::JitCodeEvent* event); |
148 static UniversalThreadHandle GetCurrentThreadHandle(); | |
149 | 194 |
150 void InjectPendingEvents(); | 195 void InjectPendingEvents(); |
151 | 196 |
152 static const unsigned kNumberOfSamples = 10; | 197 static const unsigned kNumberOfSamples = 10; |
153 typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue; | 198 typedef LockFreeCircularQueue<SampleRecord, kNumberOfSamples> SamplingQueue; |
154 | 199 |
155 base::PlatformThreadId thread_id_; | 200 PlatformData platform_data_; |
156 UniversalThreadHandle thread_handle_; | |
157 Isolate* isolate_; | 201 Isolate* isolate_; |
158 scoped_ptr<SamplingQueue> samples_data_; | 202 scoped_ptr<SamplingQueue> samples_data_; |
159 base::subtle::Atomic32 code_added_events_count_; | 203 base::subtle::Atomic32 code_added_events_count_; |
160 base::subtle::Atomic32 samples_count_; | 204 base::subtle::Atomic32 samples_count_; |
161 int code_added_events_to_collect_for_test_; | 205 int code_added_events_to_collect_for_test_; |
162 int sample_events_to_collect_for_test_; | 206 int sample_events_to_collect_for_test_; |
163 | 207 |
164 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky | 208 static base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky |
165 tls_instance_; | 209 tls_instance_; |
166 }; | 210 }; |
167 | 211 |
168 base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky | 212 base::LazyInstance<base::ThreadLocalPointer<Sampler>>::Leaky |
169 Sampler::tls_instance_ = LAZY_INSTANCE_INITIALIZER; | 213 Sampler::tls_instance_ = LAZY_INSTANCE_INITIALIZER; |
170 | 214 |
171 Sampler::Sampler() | 215 Sampler::Sampler() |
172 : thread_id_(base::PlatformThread::CurrentId()), | 216 : isolate_(Isolate::GetCurrent()), |
173 thread_handle_(Sampler::GetCurrentThreadHandle()), | |
174 isolate_(Isolate::GetCurrent()), | |
175 code_added_events_count_(0), | 217 code_added_events_count_(0), |
176 samples_count_(0), | 218 samples_count_(0), |
177 code_added_events_to_collect_for_test_(0), | 219 code_added_events_to_collect_for_test_(0), |
178 sample_events_to_collect_for_test_(0) { | 220 sample_events_to_collect_for_test_(0) { |
179 DCHECK(isolate_); | 221 DCHECK(isolate_); |
180 DCHECK(!GetInstance()); | 222 DCHECK(!GetInstance()); |
181 tls_instance_.Pointer()->Set(this); | 223 tls_instance_.Pointer()->Set(this); |
182 } | 224 } |
183 | 225 |
184 Sampler::~Sampler() { | 226 Sampler::~Sampler() { |
185 DCHECK(GetInstance()); | 227 DCHECK(GetInstance()); |
186 tls_instance_.Pointer()->Set(nullptr); | 228 tls_instance_.Pointer()->Set(nullptr); |
187 } | 229 } |
188 | 230 |
189 // static | 231 // static |
190 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { | 232 scoped_ptr<Sampler> Sampler::CreateForCurrentThread() { |
191 return scoped_ptr<Sampler>(new Sampler()); | 233 return scoped_ptr<Sampler>(new Sampler()); |
192 } | 234 } |
193 | 235 |
194 // static | |
195 UniversalThreadHandle Sampler::GetCurrentThreadHandle() { | |
196 #ifdef OS_WIN | |
197 return base::win::ScopedHandle(::OpenThread( | |
198 THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, | |
199 false, base::PlatformThread::CurrentId())); | |
200 #else | |
201 return base::PlatformThread::CurrentHandle(); | |
202 #endif | |
203 } | |
204 | |
205 void Sampler::Start() { | 236 void Sampler::Start() { |
206 samples_data_.reset(new SamplingQueue()); | 237 samples_data_.reset(new SamplingQueue()); |
207 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; | 238 v8::JitCodeEventHandler handler = &HandleJitCodeEvent; |
208 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, | 239 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, |
209 reinterpret_cast<void*>(handler)); | 240 reinterpret_cast<void*>(handler)); |
210 } | 241 } |
211 | 242 |
212 void Sampler::Stop() { | 243 void Sampler::Stop() { |
213 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); | 244 isolate_->RequestInterrupt(&InstallJitCodeEventHandler, nullptr); |
214 samples_data_.reset(); | 245 samples_data_.reset(); |
215 } | 246 } |
216 | 247 |
217 #if ARCH_CPU_64_BITS | 248 #if ARCH_CPU_64_BITS |
218 #define REG_64_32(reg64, reg32) reg64 | 249 #define REG_64_32(reg64, reg32) reg64 |
219 #else | 250 #else |
220 #define REG_64_32(reg64, reg32) reg32 | 251 #define REG_64_32(reg64, reg32) reg32 |
221 #endif // ARCH_CPU_64_BITS | 252 #endif // ARCH_CPU_64_BITS |
222 | 253 |
223 void Sampler::Sample() { | 254 void Sampler::Sample() { |
224 #if defined(OS_WIN) | 255 #if defined(OS_WIN) |
225 const DWORD kSuspendFailed = static_cast<DWORD>(-1); | 256 const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
226 if (::SuspendThread(thread_handle_.Get()) == kSuspendFailed) | 257 if (::SuspendThread(platform_data_.thread_handle()) == kSuspendFailed) |
227 return; | 258 return; |
228 CONTEXT context; | 259 CONTEXT context; |
229 memset(&context, 0, sizeof(context)); | 260 memset(&context, 0, sizeof(context)); |
230 context.ContextFlags = CONTEXT_FULL; | 261 context.ContextFlags = CONTEXT_FULL; |
231 if (::GetThreadContext(thread_handle_.Get(), &context) != 0) { | 262 if (::GetThreadContext(platform_data_.thread_handle(), &context) != 0) { |
232 v8::RegisterState state; | 263 v8::RegisterState state; |
233 state.pc = reinterpret_cast<void*>(context.REG_64_32(Rip, Eip)); | 264 state.pc = reinterpret_cast<void*>(context.REG_64_32(Rip, Eip)); |
234 state.sp = reinterpret_cast<void*>(context.REG_64_32(Rsp, Esp)); | 265 state.sp = reinterpret_cast<void*>(context.REG_64_32(Rsp, Esp)); |
235 state.fp = reinterpret_cast<void*>(context.REG_64_32(Rbp, Ebp)); | 266 state.fp = reinterpret_cast<void*>(context.REG_64_32(Rbp, Ebp)); |
236 // TODO(alph): It is not needed to buffer the events on Windows. | 267 // TODO(alph): It is not needed to buffer the events on Windows. |
237 // We can just collect and fire trace event right away. | 268 // We can just collect and fire trace event right away. |
238 DoSample(state); | 269 DoSample(state); |
239 } | 270 } |
240 ::ResumeThread(thread_handle_.Get()); | 271 ::ResumeThread(platform_data_.thread_handle()); |
241 #elif defined(USE_SIGNALS) | 272 #elif defined(USE_SIGNALS) |
242 int error = pthread_kill(thread_handle_.platform_handle(), SIGPROF); | 273 int error = pthread_kill(platform_data_.vm_tid(), SIGPROF); |
243 if (error) { | 274 if (error) { |
244 LOG(ERROR) << "pthread_kill failed with error " << error << " " | 275 LOG(ERROR) << "pthread_kill failed with error " << error << " " |
245 << strerror(error); | 276 << strerror(error); |
246 } | 277 } |
247 #endif | 278 #endif |
248 InjectPendingEvents(); | 279 InjectPendingEvents(); |
249 } | 280 } |
250 | 281 |
251 void Sampler::DoSample(const v8::RegisterState& state) { | 282 void Sampler::DoSample(const v8::RegisterState& state) { |
252 // Called in the sampled thread signal handler. | 283 // Called in the sampled thread signal handler. |
253 // Because of that it is not allowed to do any memory allocation here. | 284 // Because of that it is not allowed to do any memory allocation here. |
254 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime(); | 285 base::TimeTicks timestamp = base::TimeTicks::NowFromSystemTraceTime(); |
255 SampleRecord* record = samples_data_->StartEnqueue(); | 286 SampleRecord* record = samples_data_->StartEnqueue(); |
256 if (!record) | 287 if (!record) |
257 return; | 288 return; |
258 record->Collect(isolate_, timestamp, state); | 289 record->Collect(isolate_, timestamp, state); |
259 samples_data_->FinishEnqueue(); | 290 samples_data_->FinishEnqueue(); |
260 } | 291 } |
261 | 292 |
262 void Sampler::InjectPendingEvents() { | 293 void Sampler::InjectPendingEvents() { |
263 SampleRecord* record = samples_data_->Peek(); | 294 SampleRecord* record = samples_data_->Peek(); |
264 while (record) { | 295 while (record) { |
265 TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1( | 296 TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1( |
266 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), "V8Sample", thread_id_, | 297 TRACE_DISABLED_BY_DEFAULT("v8.cpu_profile"), "V8Sample", |
| 298 platform_data_.thread_id(), |
267 (record->timestamp() - base::TimeTicks()).InMicroseconds(), "data", | 299 (record->timestamp() - base::TimeTicks()).InMicroseconds(), "data", |
268 record->ToTraceFormat()); | 300 record->ToTraceFormat()); |
269 samples_data_->Remove(); | 301 samples_data_->Remove(); |
270 record = samples_data_->Peek(); | 302 record = samples_data_->Peek(); |
271 base::subtle::NoBarrier_AtomicIncrement(&samples_count_, 1); | 303 base::subtle::NoBarrier_AtomicIncrement(&samples_count_, 1); |
272 } | 304 } |
273 } | 305 } |
274 | 306 |
275 // static | 307 // static |
276 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) { | 308 void Sampler::InstallJitCodeEventHandler(Isolate* isolate, void* data) { |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 render_thread_sampler_->SetEventsToCollectForTest(code_added_events, | 611 render_thread_sampler_->SetEventsToCollectForTest(code_added_events, |
580 sample_events); | 612 sample_events); |
581 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); | 613 waitable_event_for_testing_.reset(new base::WaitableEvent(false, false)); |
582 } | 614 } |
583 | 615 |
584 void V8SamplingProfiler::WaitSamplingEventForTesting() { | 616 void V8SamplingProfiler::WaitSamplingEventForTesting() { |
585 waitable_event_for_testing_->Wait(); | 617 waitable_event_for_testing_->Wait(); |
586 } | 618 } |
587 | 619 |
588 } // namespace blink | 620 } // namespace blink |
OLD | NEW |