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

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

Issue 1020853013: V8 Sampling profiler: Introduce PlatformData (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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) 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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698