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

Side by Side Diff: runtime/vm/profiler.cc

Issue 109803002: Profiler Take 2 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include <cstdio> 5 #include <cstdio>
6 6
7 #include "platform/utils.h" 7 #include "platform/utils.h"
8 8
9 #include "vm/atomic.h"
9 #include "vm/isolate.h" 10 #include "vm/isolate.h"
10 #include "vm/json_stream.h" 11 #include "vm/json_stream.h"
11 #include "vm/native_symbol.h" 12 #include "vm/native_symbol.h"
12 #include "vm/object.h" 13 #include "vm/object.h"
13 #include "vm/os.h" 14 #include "vm/os.h"
14 #include "vm/profiler.h" 15 #include "vm/profiler.h"
15 #include "vm/signal_handler.h" 16 #include "vm/signal_handler.h"
17 #include "vm/simulator.h"
16 18
17 namespace dart { 19 namespace dart {
18 20
19 // Notes on locking and signal handling:
20 //
21 // The ProfilerManager has a single monitor (monitor_). This monitor guards
22 // access to the schedule list of isolates (isolates_, isolates_size_, etc).
23 //
24 // Each isolate has a mutex (profiler_data_mutex_) which protects access
25 // to the isolate's profiler data.
26 //
27 // Locks can be taken in this order:
28 // 1. ProfilerManager::monitor_
29 // 2. isolate->profiler_data_mutex_
30 // In other words, it is not acceptable to take ProfilerManager::monitor_
31 // after grabbing isolate->profiler_data_mutex_.
32 //
33 // ProfileManager::monitor_ taking entry points:
34 // InitOnce, Shutdown
35 // ProfilerManager::monitor_
36 // ScheduleIsolate, DescheduleIsolate.
37 // ProfilerManager::monitor_, isolate->profiler_data_mutex_
38 // ThreadMain
39 // isolate->profiler_data_mutex_ taking entry points:
40 // SetupIsolateForProfiling, FreeIsolateForProfiling.
41 // ProfilerManager::monitor_, isolate->profiler_data_mutex_
42 // ScheduleIsolate, DescheduleIsolate.
43 // ProfilerManager::monitor_, isolate->profiler_data_mutex_
44 // ProfileSignalAction
45 // isolate->profiler_data_mutex_
46 // ProfilerManager::monitor_, isolate->profiler_data_mutex_
47 //
48 // Signal handling and locking:
49 // On OSes with pthreads (Android, Linux, and Mac) we use signal delivery
50 // to interrupt the isolate running thread for sampling. After a thread
51 // is sent the SIGPROF, it is removed from the scheduled isolate list.
52 // Inside the signal handler, after the sample is taken, the isolate is
53 // added to the scheduled isolate list again. The side effect of this is
54 // that the signal handler must be able to acquire the isolate profiler data
55 // mutex and the profile manager monitor. When an isolate running thread
56 // (potential signal target) calls into an entry point which acquires
57 // ProfileManager::monitor_ signal delivery must be blocked. An example is
58 // ProfileManager::ScheduleIsolate which blocks signal delivery while removing
59 // the scheduling the isolate.
60 //
61 21
62 // Notes on stack frame walking: 22 // Notes on stack frame walking:
63 // 23 //
64 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames 24 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames
65 // The stack frame walking code uses the frame pointer to traverse the stack. 25 // The stack frame walking code uses the frame pointer to traverse the stack.
66 // If the VM is compiled without frame pointers (which is the default on 26 // If the VM is compiled without frame pointers (which is the default on
67 // recent GCC versions with optimizing enabled) the stack walking code will 27 // recent GCC versions with optimizing enabled) the stack walking code will
68 // fail (sometimes leading to a crash). 28 // fail (sometimes leading to a crash).
69 // 29 //
70 30
71 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); 31 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
72 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); 32 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
73 33
74 bool ProfilerManager::initialized_ = false; 34 bool Profiler::initialized_ = false;
75 bool ProfilerManager::shutdown_ = false; 35 Monitor* Profiler::monitor_ = NULL;
76 bool ProfilerManager::thread_running_ = false; 36 SampleBuffer* Profiler::sample_buffer_ = NULL;
77 Monitor* ProfilerManager::monitor_ = NULL;
78 Monitor* ProfilerManager::start_stop_monitor_ = NULL;
79 Isolate** ProfilerManager::isolates_ = NULL;
80 intptr_t ProfilerManager::isolates_capacity_ = 0;
81 intptr_t ProfilerManager::isolates_size_ = 0;
82 37
83 38 void Profiler::InitOnce() {
84 void ProfilerManager::InitOnce() {
85 #if defined(USING_SIMULATOR) 39 #if defined(USING_SIMULATOR)
86 // Force disable of profiling on simulator.
87 FLAG_profile = false;
88 #endif
89 #if defined(TARGET_OS_WINDOWS)
90 // Force disable of profiling on Windows.
91 FLAG_profile = false; 40 FLAG_profile = false;
92 #endif 41 #endif
93 if (!FLAG_profile) { 42 if (!FLAG_profile) {
94 return; 43 return;
95 } 44 }
45 ASSERT(!initialized_);
46 initialized_ = true;
47 monitor_ = new Monitor();
48 sample_buffer_ = new SampleBuffer();
96 NativeSymbolResolver::InitOnce(); 49 NativeSymbolResolver::InitOnce();
97 ASSERT(!initialized_);
98 monitor_ = new Monitor();
99 start_stop_monitor_ = new Monitor();
100 initialized_ = true;
101 ResizeIsolates(16);
102 if (FLAG_trace_profiled_isolates) {
103 OS::Print("ProfilerManager starting up.\n");
104 }
105 {
106 ScopedMonitor startup_lock(start_stop_monitor_);
107 Thread::Start(ThreadMain, 0);
108 while (!thread_running_) {
109 // Wait until profiler thread has started up.
110 startup_lock.Wait();
111 }
112 }
113 if (FLAG_trace_profiled_isolates) {
114 OS::Print("ProfilerManager running.\n");
115 }
116 } 50 }
117 51
118 52
119 void ProfilerManager::Shutdown() { 53 void Profiler::Shutdown() {
120 if (!FLAG_profile) { 54 if (!FLAG_profile) {
121 return; 55 return;
122 } 56 }
123 ASSERT(initialized_); 57 ASSERT(initialized_);
124 if (FLAG_trace_profiled_isolates) {
125 OS::Print("ProfilerManager shutting down.\n");
126 }
127 intptr_t size_at_shutdown = 0;
128 {
129 ScopedSignalBlocker ssb;
130 {
131 ScopedMonitor lock(monitor_);
132 shutdown_ = true;
133 size_at_shutdown = isolates_size_;
134 isolates_size_ = 0;
135 free(isolates_);
136 isolates_ = NULL;
137 lock.Notify();
138 }
139 }
140 NativeSymbolResolver::ShutdownOnce(); 58 NativeSymbolResolver::ShutdownOnce();
141 {
142 ScopedMonitor shutdown_lock(start_stop_monitor_);
143 while (thread_running_) {
144 // Wait until profiler thread has exited.
145 shutdown_lock.Wait();
146 }
147 }
148 if (FLAG_trace_profiled_isolates) {
149 OS::Print("ProfilerManager shut down (%" Pd ").\n", size_at_shutdown);
150 }
151 } 59 }
152 60
153 61
154 void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) { 62 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
155 if (!FLAG_profile) { 63 if (!FLAG_profile) {
156 return; 64 return;
157 } 65 }
158 ASSERT(isolate != NULL); 66 ASSERT(isolate != NULL);
67 ASSERT(sample_buffer_ != NULL);
68 MonitorLocker ml(monitor_);
159 { 69 {
160 ScopedSignalBlocker ssb; 70 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
161 { 71 SampleBuffer* sample_buffer = sample_buffer_;
162 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); 72 if (!shared_buffer) {
163 SampleBuffer* sample_buffer = new SampleBuffer(); 73 sample_buffer = new SampleBuffer();
164 ASSERT(sample_buffer != NULL); 74 }
165 IsolateProfilerData* profiler_data = 75 IsolateProfilerData* profiler_data =
166 new IsolateProfilerData(isolate, sample_buffer); 76 new IsolateProfilerData(sample_buffer, !shared_buffer);
167 ASSERT(profiler_data != NULL); 77 ASSERT(profiler_data != NULL);
168 profiler_data->set_sample_interval_micros(1000); 78 isolate->set_profiler_data(profiler_data);
169 isolate->set_profiler_data(profiler_data); 79 if (FLAG_trace_profiled_isolates) {
170 if (FLAG_trace_profiled_isolates) { 80 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
171 OS::Print("ProfilerManager Setup Isolate %p %s %p\n",
172 isolate,
173 isolate->name(),
174 reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
175 }
176 } 81 }
177 } 82 }
178 } 83 }
179 84
180 85
181 void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) { 86 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
182 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
183 IsolateProfilerData* profiler_data = isolate->profiler_data();
184 if (profiler_data == NULL) {
185 // Already freed.
186 return;
187 }
188 isolate->set_profiler_data(NULL);
189 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
190 ASSERT(sample_buffer != NULL);
191 profiler_data->set_sample_buffer(NULL);
192 delete sample_buffer;
193 delete profiler_data;
194 if (FLAG_trace_profiled_isolates) {
195 OS::Print("ProfilerManager Shutdown Isolate %p %s %p\n",
196 isolate,
197 isolate->name(),
198 reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
199 }
200 }
201
202
203 void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) {
204 ASSERT(isolate != NULL); 87 ASSERT(isolate != NULL);
205 if (!FLAG_profile) { 88 if (!FLAG_profile) {
206 return; 89 return;
207 } 90 }
91 // We do not have a current isolate.
92 ASSERT(Isolate::Current() == NULL);
93 MonitorLocker ml(monitor_);
208 { 94 {
209 ScopedSignalBlocker ssb; 95 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
210 FreeIsolateProfilingData(isolate); 96 IsolateProfilerData* profiler_data = isolate->profiler_data();
211 } 97 if (profiler_data == NULL) {
212 } 98 // Already freed.
213
214
215 void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
216 ScopedMonitor lock(monitor_);
217 {
218 if (shutdown_) {
219 // Shutdown.
220 return; 99 return;
221 } 100 }
222 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); 101 isolate->set_profiler_data(NULL);
223 IsolateProfilerData* profiler_data = isolate->profiler_data(); 102 profiler_data->set_sample_buffer(NULL);
224 if (profiler_data == NULL) { 103 delete profiler_data;
225 return; 104 if (FLAG_trace_profiled_isolates) {
226 } 105 OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
227 profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
228 Thread::GetCurrentThreadId());
229 }
230 intptr_t i = FindIsolate(isolate);
231 if (i >= 0) {
232 // Already scheduled.
233 return;
234 }
235 AddIsolate(isolate);
236 lock.Notify();
237 }
238
239
240 void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) {
241 if (!FLAG_profile) {
242 return;
243 }
244 ASSERT(initialized_);
245 ASSERT(isolate != NULL);
246 if (!inside_signal) {
247 ScopedSignalBlocker ssb;
248 {
249 ScheduleIsolateHelper(isolate);
250 }
251 } else {
252 // Do not need a signal blocker inside a signal handler.
253 {
254 ScheduleIsolateHelper(isolate);
255 } 106 }
256 } 107 }
257 } 108 }
258 109
259 110
260 void ProfilerManager::DescheduleIsolate(Isolate* isolate) { 111 void Profiler::BeginExecution(Isolate* isolate) {
112 if (isolate == NULL) {
113 return;
114 }
261 if (!FLAG_profile) { 115 if (!FLAG_profile) {
262 return; 116 return;
263 } 117 }
264 ASSERT(initialized_); 118 IsolateProfilerData* profiler_data = isolate->profiler_data();
265 ASSERT(isolate != NULL); 119 if (profiler_data == NULL) {
266 { 120 return;
267 ScopedSignalBlocker ssb;
268 {
269 ScopedMonitor lock(monitor_);
270 if (shutdown_) {
271 // Shutdown.
272 return;
273 }
274 intptr_t i = FindIsolate(isolate);
275 if (i < 0) {
276 // Not scheduled.
277 return;
278 }
279 {
280 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
281 IsolateProfilerData* profiler_data = isolate->profiler_data();
282 if (profiler_data != NULL) {
283 profiler_data->Descheduled();
284 }
285 }
286 RemoveIsolate(i);
287 lock.Notify();
288 }
289 } 121 }
122 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
123 if (sample_buffer == NULL) {
124 return;
125 }
126 Sample* sample = sample_buffer->ReserveSample();
127 sample->Init(Sample::kIsolateStart, isolate, OS::GetCurrentTimeMicros(),
128 Thread::GetCurrentThreadId());
129 ThreadInterrupter::Register(RecordSampleInterruptCallback, isolate);
290 } 130 }
291 131
292 132
293 void PrintToJSONStream(Isolate* isolate, JSONStream* stream) { 133 void Profiler::EndExecution(Isolate* isolate) {
134 if (isolate == NULL) {
135 return;
136 }
137 if (!FLAG_profile) {
138 return;
139 }
140 ThreadInterrupter::Unregister();
141 IsolateProfilerData* profiler_data = isolate->profiler_data();
142 if (profiler_data == NULL) {
143 return;
144 }
145 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
146 if (sample_buffer == NULL) {
147 return;
148 }
149 Sample* sample = sample_buffer->ReserveSample();
150 sample->Init(Sample::kIsolateStop, isolate, OS::GetCurrentTimeMicros(),
151 Thread::GetCurrentThreadId());
152 }
153
154
155 void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state,
156 void* data) {
157 Isolate* isolate = reinterpret_cast<Isolate*>(data);
158 if (isolate == NULL) {
159 return;
160 }
161 IsolateProfilerData* profiler_data = isolate->profiler_data();
162 if (profiler_data == NULL) {
163 return;
164 }
165 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
166 if (sample_buffer == NULL) {
167 return;
168 }
169 Sample* sample = sample_buffer->ReserveSample();
170 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
171 state.tid);
172 }
173
174
175 void Profiler::RecordSampleInterruptCallback(
176 const InterruptedThreadState& state,
177 void* data) {
178 Isolate* isolate = reinterpret_cast<Isolate*>(data);
179 if (isolate == NULL) {
180 return;
181 }
182 IsolateProfilerData* profiler_data = isolate->profiler_data();
183 if (profiler_data == NULL) {
184 return;
185 }
186 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
187 if (sample_buffer == NULL) {
188 return;
189 }
190 Sample* sample = sample_buffer->ReserveSample();
191 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
192 state.tid);
193 uintptr_t stack_lower = 0;
194 uintptr_t stack_upper = 0;
195 isolate->GetStackBounds(&stack_lower, &stack_upper);
196 if ((stack_lower == 0) || (stack_upper == 0)) {
197 stack_lower = 0;
198 stack_upper = 0;
199 }
200 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
201 state.pc, state.fp, state.sp);
202 stackWalker.walk();
203 }
204
205
206 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
294 ASSERT(isolate == Isolate::Current()); 207 ASSERT(isolate == Isolate::Current());
295 {
296 // We can't get signals here.
297 }
298 UNIMPLEMENTED(); 208 UNIMPLEMENTED();
299 } 209 }
300 210
301 211
302 void ProfilerManager::ResizeIsolates(intptr_t new_capacity) {
303 ASSERT(new_capacity < kMaxProfiledIsolates);
304 ASSERT(new_capacity > isolates_capacity_);
305 Isolate* isolate = NULL;
306 isolates_ = reinterpret_cast<Isolate**>(
307 realloc(isolates_, sizeof(isolate) * new_capacity));
308 isolates_capacity_ = new_capacity;
309 }
310
311
312 void ProfilerManager::AddIsolate(Isolate* isolate) {
313 // Must be called with monitor_ locked.
314 if (isolates_ == NULL) {
315 // We are shutting down.
316 return;
317 }
318 if (isolates_size_ == isolates_capacity_) {
319 ResizeIsolates(isolates_capacity_ == 0 ? 16 : isolates_capacity_ * 2);
320 }
321 isolates_[isolates_size_] = isolate;
322 isolates_size_++;
323 }
324
325
326 intptr_t ProfilerManager::FindIsolate(Isolate* isolate) {
327 // Must be called with monitor_ locked.
328 if (isolates_ == NULL) {
329 // We are shutting down.
330 return -1;
331 }
332 for (intptr_t i = 0; i < isolates_size_; i++) {
333 if (isolates_[i] == isolate) {
334 return i;
335 }
336 }
337 return -1;
338 }
339
340
341 void ProfilerManager::RemoveIsolate(intptr_t i) {
342 // Must be called with monitor_ locked.
343 if (isolates_ == NULL) {
344 // We are shutting down.
345 return;
346 }
347 ASSERT(i < isolates_size_);
348 intptr_t last = isolates_size_ - 1;
349 if (i != last) {
350 isolates_[i] = isolates_[last];
351 }
352 // Mark last as NULL.
353 isolates_[last] = NULL;
354 // Pop.
355 isolates_size_--;
356 }
357
358
359 static char* FindSymbolName(uintptr_t pc, bool* native_symbol) { 212 static char* FindSymbolName(uintptr_t pc, bool* native_symbol) {
360 // TODO(johnmccutchan): Differentiate between symbols which can't be found 213 // TODO(johnmccutchan): Differentiate between symbols which can't be found
361 // and symbols which were GCed. (Heap::CodeContains). 214 // and symbols which were GCed. (Heap::CodeContains).
362 ASSERT(native_symbol != NULL); 215 ASSERT(native_symbol != NULL);
363 const char* symbol_name = "Unknown"; 216 const char* symbol_name = "Unknown";
364 *native_symbol = false; 217 *native_symbol = false;
218 if (pc == 0) {
219 return const_cast<char*>(Sample::kNoFrame);
220 }
365 const Code& code = Code::Handle(Code::LookupCode(pc)); 221 const Code& code = Code::Handle(Code::LookupCode(pc));
366 if (code.IsNull()) { 222 if (code.IsNull()) {
367 // Possibly a native symbol. 223 // Possibly a native symbol.
368 char* native_name = NativeSymbolResolver::LookupSymbolName(pc); 224 char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
369 if (native_name != NULL) { 225 if (native_name != NULL) {
370 symbol_name = native_name; 226 symbol_name = native_name;
371 *native_symbol = true; 227 *native_symbol = true;
372 } 228 }
373 } else { 229 } else {
374 const Function& function = Function::Handle(code.function()); 230 const Function& function = Function::Handle(code.function());
375 if (!function.IsNull()) { 231 if (!function.IsNull()) {
376 const String& name = String::Handle(function.QualifiedUserVisibleName()); 232 const String& name = String::Handle(function.QualifiedUserVisibleName());
377 if (!name.IsNull()) { 233 if (!name.IsNull()) {
378 symbol_name = name.ToCString(); 234 symbol_name = name.ToCString();
379 } 235 }
380 } 236 }
381 } 237 }
382 return const_cast<char*>(symbol_name); 238 return const_cast<char*>(symbol_name);
383 } 239 }
384 240
385 241
386 void ProfilerManager::WriteTracing(Isolate* isolate, const char* name, 242 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid,
387 Dart_Port port) { 243 Sample* sample, JSONArray& events) {
388 ASSERT(isolate == Isolate::Current()); 244 Sample::SampleType type = sample->type;
389 { 245 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
390 ScopedSignalBlocker ssb; 246 double timestamp = static_cast<double>(sample->timestamp);
391 { 247 const char* isolate_name = isolate->name();
392 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); 248 switch (type) {
393 IsolateProfilerData* profiler_data = isolate->profiler_data(); 249 case Sample::kIsolateStart: {
394 if (profiler_data == NULL) { 250 JSONObject begin(&events);
395 return; 251 begin.AddProperty("ph", "B");
396 } 252 begin.AddProperty("tid", tid);
397 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 253 begin.AddProperty("pid", pid);
398 ASSERT(sample_buffer != NULL); 254 begin.AddProperty("name", isolate_name);
399 JSONStream stream(10 * MB); 255 begin.AddProperty("ts", timestamp);
400 intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer); 256 }
401 intptr_t pid = 1; 257 break;
402 { 258 case Sample::kIsolateStop: {
403 JSONArray events(&stream); 259 JSONObject begin(&events);
260 begin.AddProperty("ph", "E");
261 begin.AddProperty("tid", tid);
262 begin.AddProperty("pid", pid);
263 begin.AddProperty("name", isolate_name);
264 begin.AddProperty("ts", timestamp);
265 }
266 break;
267 case Sample::kIsolateSample:
268 // Write "B" events.
269 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
270 bool native_symbol = false;
271 char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
404 { 272 {
405 JSONObject thread_name(&events); 273 JSONObject begin(&events);
406 thread_name.AddProperty("name", "thread_name"); 274 begin.AddProperty("ph", "B");
407 thread_name.AddProperty("ph", "M"); 275 begin.AddProperty("tid", tid);
408 thread_name.AddProperty("tid", tid); 276 begin.AddProperty("pid", pid);
409 thread_name.AddProperty("pid", pid); 277 begin.AddProperty("name", symbol_name);
410 { 278 begin.AddProperty("ts", timestamp);
411 JSONObject args(&thread_name, "args");
412 args.AddProperty("name", name);
413 }
414 } 279 }
415 { 280 if (native_symbol) {
416 JSONObject process_name(&events); 281 NativeSymbolResolver::FreeSymbolName(symbol_name);
417 process_name.AddProperty("name", "process_name");
418 process_name.AddProperty("ph", "M");
419 process_name.AddProperty("tid", tid);
420 process_name.AddProperty("pid", pid);
421 {
422 JSONObject args(&process_name, "args");
423 args.AddProperty("name", "Dart VM");
424 }
425 }
426 uint64_t last_time = 0;
427 for (Sample* i = sample_buffer->FirstSample();
428 i != sample_buffer->LastSample();
429 i = sample_buffer->NextSample(i)) {
430 if (last_time == 0) {
431 last_time = i->timestamp;
432 }
433 intptr_t delta = i->timestamp - last_time;
434 {
435 double percentage = static_cast<double>(i->cpu_usage) /
436 static_cast<double>(delta) * 100.0;
437 if (percentage != percentage) {
438 percentage = 0.0;
439 }
440 percentage = percentage < 0.0 ? 0.0 : percentage;
441 percentage = percentage > 100.0 ? 100.0 : percentage;
442 {
443 JSONObject cpu_usage(&events);
444 cpu_usage.AddProperty("name", "CPU Usage");
445 cpu_usage.AddProperty("ph", "C");
446 cpu_usage.AddProperty("tid", tid);
447 cpu_usage.AddProperty("pid", pid);
448 cpu_usage.AddProperty("ts", static_cast<double>(last_time));
449 {
450 JSONObject args(&cpu_usage, "args");
451 args.AddProperty("CPU", percentage);
452 }
453 }
454 {
455 JSONObject cpu_usage(&events);
456 cpu_usage.AddProperty("name", "CPU Usage");
457 cpu_usage.AddProperty("ph", "C");
458 cpu_usage.AddProperty("tid", tid);
459 cpu_usage.AddProperty("pid", pid);
460 cpu_usage.AddProperty("ts", static_cast<double>(i->timestamp));
461 {
462 JSONObject args(&cpu_usage, "args");
463 args.AddProperty("CPU", percentage);
464 }
465 }
466 }
467 for (int j = 0; j < Sample::kNumStackFrames; j++) {
468 if (i->pcs[j] == 0) {
469 continue;
470 }
471 bool native_symbol = false;
472 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
473 {
474 JSONObject begin(&events);
475 begin.AddProperty("ph", "B");
476 begin.AddProperty("tid", tid);
477 begin.AddProperty("pid", pid);
478 begin.AddProperty("name", symbol_name);
479 begin.AddProperty("ts", static_cast<double>(last_time));
480 }
481 if (native_symbol) {
482 NativeSymbolResolver::FreeSymbolName(symbol_name);
483 }
484 }
485 for (int j = Sample::kNumStackFrames-1; j >= 0; j--) {
486 if (i->pcs[j] == 0) {
487 continue;
488 }
489 bool native_symbol = false;
490 char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
491 {
492 JSONObject end(&events);
493 end.AddProperty("ph", "E");
494 end.AddProperty("tid", tid);
495 end.AddProperty("pid", pid);
496 end.AddProperty("name", symbol_name);
497 end.AddProperty("ts", static_cast<double>(i->timestamp));
498 }
499 if (native_symbol) {
500 NativeSymbolResolver::FreeSymbolName(symbol_name);
501 }
502 }
503 last_time = i->timestamp;
504 } 282 }
505 } 283 }
506 char fname[1024]; 284 // Write "E" events.
507 #if defined(TARGET_OS_WINDOWS) 285 for (int i = 0; i < Sample::kNumStackFrames; i++) {
508 snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof", 286 bool native_symbol = false;
509 static_cast<int>(port)); 287 char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
510 #else 288 {
511 snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof", 289 JSONObject begin(&events);
512 static_cast<int>(port)); 290 begin.AddProperty("ph", "E");
513 #endif 291 begin.AddProperty("tid", tid);
514 printf("%s\n", fname); 292 begin.AddProperty("pid", pid);
515 FILE* f = fopen(fname, "wb"); 293 begin.AddProperty("name", symbol_name);
516 ASSERT(f != NULL); 294 begin.AddProperty("ts", timestamp);
517 fputs(stream.ToCString(), f); 295 }
518 fclose(f); 296 if (native_symbol) {
519 } 297 NativeSymbolResolver::FreeSymbolName(symbol_name);
298 }
299 }
300 break;
301 default:
302 UNIMPLEMENTED();
520 } 303 }
521 } 304 }
522 305
523 306
524 IsolateProfilerData::IsolateProfilerData(Isolate* isolate, 307 void Profiler::WriteTracing(Isolate* isolate) {
525 SampleBuffer* sample_buffer) { 308 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
526 isolate_ = isolate; 309 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
310 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
311 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) {
312 // Embedder has not provided necessary callbacks.
313 return;
314 }
315 // We will be looking up code objects within the isolate.
316 ASSERT(Isolate::Current() != NULL);
317 // We do not want to be interrupted while processing the buffer.
318 EndExecution(isolate);
319 Dart_Port port = isolate->main_port();
320 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
321 IsolateProfilerData* profiler_data = isolate->profiler_data();
322 if (profiler_data == NULL) {
323 return;
324 }
325 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
326 ASSERT(sample_buffer != NULL);
327 JSONStream stream(10 * MB);
328 intptr_t pid = OS::ProcessId();
329 {
330 JSONArray events(&stream);
331 {
332 JSONObject process_name(&events);
333 process_name.AddProperty("name", "process_name");
334 process_name.AddProperty("ph", "M");
335 process_name.AddProperty("pid", pid);
336 {
337 JSONObject args(&process_name, "args");
338 args.AddProperty("name", "Dart VM");
339 }
340 }
341 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
342 Sample* sample = sample_buffer->GetSample(i);
343 if (sample->isolate != isolate) {
344 continue;
345 }
346 if (sample->timestamp == 0) {
347 continue;
348 }
349 WriteTracingSample(isolate, pid, sample, events);
350 }
351 }
352 char fname[1024];
353 #if defined(TARGET_OS_WINDOWS)
354 snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d-%d.prof",
355 static_cast<int>(pid), static_cast<int>(port));
356 #else
357 snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d-%d.prof",
358 static_cast<int>(pid), static_cast<int>(port));
359 #endif
360 void* f = file_open(fname, true);
361 if (f == NULL) {
362 // Cannot write.
363 return;
364 }
365 TextBuffer* buffer = stream.buffer();
366 ASSERT(buffer != NULL);
367 file_write(buffer->buf(), buffer->length(), f);
368 file_close(f);
369 BeginExecution(isolate);
370 }
371
372
373 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
374 bool own_sample_buffer) {
527 sample_buffer_ = sample_buffer; 375 sample_buffer_ = sample_buffer;
528 timer_expiration_micros_ = kNoExpirationTime; 376 own_sample_buffer_ = own_sample_buffer;
529 last_sampled_micros_ = 0;
530 thread_id_ = 0;
531 } 377 }
532 378
533 379
534 IsolateProfilerData::~IsolateProfilerData() { 380 IsolateProfilerData::~IsolateProfilerData() {
535 } 381 if (own_sample_buffer_) {
536 382 delete sample_buffer_;
537 383 sample_buffer_ = NULL;
538 void IsolateProfilerData::SampledAt(int64_t current_time) { 384 own_sample_buffer_ = false;
539 last_sampled_micros_ = current_time; 385 }
540 }
541
542
543 void IsolateProfilerData::Scheduled(int64_t current_time, ThreadId thread_id) {
544 timer_expiration_micros_ = current_time + sample_interval_micros_;
545 thread_id_ = thread_id;
546 Thread::GetThreadCpuUsage(thread_id_, &cpu_usage_);
547 }
548
549
550 void IsolateProfilerData::Descheduled() {
551 // TODO(johnmccutchan): Track when we ran for a fraction of our sample
552 // interval and incorporate the time difference when scheduling the
553 // isolate again.
554 cpu_usage_ = kDescheduledCpuUsage;
555 timer_expiration_micros_ = kNoExpirationTime;
556 Sample* sample = sample_buffer_->ReserveSample();
557 ASSERT(sample != NULL);
558 sample->timestamp = OS::GetCurrentTimeMicros();
559 sample->cpu_usage = 0;
560 sample->vm_tags = Sample::kIdle;
561 } 386 }
562 387
563 388
564 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; 389 const char* Sample::kLookupSymbol = "Symbol Not Looked Up";
565 const char* Sample::kNoSymbol = "No Symbol Found"; 390 const char* Sample::kNoSymbol = "No Symbol Found";
391 const char* Sample::kNoFrame = "<no frame>";
566 392
567 Sample::Sample() { 393 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
568 timestamp = 0; 394 ThreadId tid) {
569 cpu_usage = 0; 395 this->timestamp = timestamp;
570 for (int i = 0; i < kNumStackFrames; i++) { 396 this->tid = tid;
397 this->isolate = isolate;
398 for (intptr_t i = 0; i < kNumStackFrames; i++) {
571 pcs[i] = 0; 399 pcs[i] = 0;
572 } 400 }
573 vm_tags = kIdle; 401 this->type = type;
402 vm_tags = 0;
574 runtime_tags = 0; 403 runtime_tags = 0;
575 } 404 }
576 405
577
578 SampleBuffer::SampleBuffer(intptr_t capacity) { 406 SampleBuffer::SampleBuffer(intptr_t capacity) {
579 start_ = 0;
580 end_ = 0;
581 capacity_ = capacity; 407 capacity_ = capacity;
582 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample))); 408 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample)));
409 cursor_ = 0;
583 } 410 }
584 411
585 412
586 SampleBuffer::~SampleBuffer() { 413 SampleBuffer::~SampleBuffer() {
587 if (samples_ != NULL) { 414 if (samples_ != NULL) {
588 free(samples_); 415 free(samples_);
589 samples_ = NULL; 416 samples_ = NULL;
590 start_ = 0; 417 cursor_ = 0;
591 end_ = 0;
592 capacity_ = 0; 418 capacity_ = 0;
593 } 419 }
594 } 420 }
595 421
596 422
597 Sample* SampleBuffer::ReserveSample() { 423 Sample* SampleBuffer::ReserveSample() {
598 ASSERT(samples_ != NULL); 424 ASSERT(samples_ != NULL);
599 intptr_t index = end_; 425 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
600 end_ = WrapIncrement(end_); 426 // Map back into sample buffer range.
601 if (end_ == start_) { 427 cursor = cursor % capacity_;
602 start_ = WrapIncrement(start_); 428 return &samples_[cursor];
603 }
604 ASSERT(index >= 0);
605 ASSERT(index < capacity_);
606 // Reset.
607 samples_[index] = Sample();
608 return &samples_[index];
609 } 429 }
610 430
611 431
612 Sample* SampleBuffer::FirstSample() const {
613 return &samples_[start_];
614 }
615
616
617 Sample* SampleBuffer::NextSample(Sample* sample) const {
618 ASSERT(sample >= &samples_[0]);
619 ASSERT(sample < &samples_[capacity_]);
620 intptr_t index = sample - samples_;
621 index = WrapIncrement(index);
622 return &samples_[index];
623 }
624
625
626 Sample* SampleBuffer::LastSample() const {
627 return &samples_[end_];
628 }
629
630
631 intptr_t SampleBuffer::WrapIncrement(intptr_t i) const {
632 return (i + 1) % capacity_;
633 }
634
635
636 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, 432 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample,
637 uintptr_t stack_lower, 433 uintptr_t stack_lower,
638 uintptr_t stack_upper, 434 uintptr_t stack_upper,
639 uintptr_t pc, 435 uintptr_t pc,
640 uintptr_t fp, 436 uintptr_t fp,
641 uintptr_t sp) : 437 uintptr_t sp) :
642 sample_(sample), 438 sample_(sample),
643 stack_lower_(stack_lower), 439 stack_lower_(stack_lower),
644 stack_upper_(stack_upper), 440 stack_upper_(stack_upper),
645 original_pc_(pc), 441 original_pc_(pc),
646 original_fp_(fp), 442 original_fp_(fp),
647 original_sp_(sp), 443 original_sp_(sp),
648 lower_bound_(stack_lower) { 444 lower_bound_(stack_lower) {
649 ASSERT(sample_ != NULL); 445 ASSERT(sample_ != NULL);
650 } 446 }
651 447
652 448
653 int ProfilerSampleStackWalker::walk() { 449 int ProfilerSampleStackWalker::walk() {
654 uword* pc = reinterpret_cast<uword*>(original_pc_); 450 uword* pc = reinterpret_cast<uword*>(original_pc_);
451 #define WALK_STACK
655 #if defined(WALK_STACK) 452 #if defined(WALK_STACK)
656 uword* fp = reinterpret_cast<uword*>(original_fp_); 453 uword* fp = reinterpret_cast<uword*>(original_fp_);
657 uword* previous_fp = fp; 454 uword* previous_fp = fp;
658 if (original_sp_ < lower_bound_) { 455 if (original_sp_ < lower_bound_) {
659 // The stack pointer gives us a better lower bound than 456 // The stack pointer gives us a better lower bound than
660 // the isolates stack limit. 457 // the isolates stack limit.
661 lower_bound_ = original_sp_; 458 lower_bound_ = original_sp_;
662 } 459 }
663 int i = 0; 460 int i = 0;
664 for (; i < Sample::kNumStackFrames; i++) { 461 for (; i < Sample::kNumStackFrames; i++) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 return false; 498 return false;
702 } 499 }
703 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); 500 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp);
704 cursor += sizeof(fp); 501 cursor += sizeof(fp);
705 bool r = cursor >= lower_bound_ && cursor < stack_upper_; 502 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
706 return r; 503 return r;
707 } 504 }
708 505
709 506
710 } // namespace dart 507 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698