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

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
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_android.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 may
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 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
32 defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
33 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
34 #else
35 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
36 #endif
72 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); 37 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
73 38 DEFINE_FLAG(charp, profile_dir, NULL,
74 bool ProfilerManager::initialized_ = false; 39 "Enable writing profile data into specified directory.");
75 bool ProfilerManager::shutdown_ = false; 40
76 bool ProfilerManager::thread_running_ = false; 41 bool Profiler::initialized_ = false;
77 Monitor* ProfilerManager::monitor_ = NULL; 42 Monitor* Profiler::monitor_ = NULL;
78 Monitor* ProfilerManager::start_stop_monitor_ = NULL; 43 SampleBuffer* Profiler::sample_buffer_ = NULL;
79 Isolate** ProfilerManager::isolates_ = NULL; 44
80 intptr_t ProfilerManager::isolates_capacity_ = 0; 45 void Profiler::InitOnce() {
81 intptr_t ProfilerManager::isolates_size_ = 0; 46 if (!FLAG_profile) {
82 47 return;
83 48 }
84 void ProfilerManager::InitOnce() { 49 ASSERT(!initialized_);
85 #if defined(USING_SIMULATOR) 50 initialized_ = true;
86 // Force disable of profiling on simulator. 51 monitor_ = new Monitor();
87 FLAG_profile = false; 52 sample_buffer_ = new SampleBuffer();
88 #endif
89 #if defined(TARGET_OS_WINDOWS)
90 // Force disable of profiling on Windows.
91 FLAG_profile = false;
92 #endif
93 if (!FLAG_profile) {
94 return;
95 }
96 NativeSymbolResolver::InitOnce(); 53 NativeSymbolResolver::InitOnce();
97 ASSERT(!initialized_); 54 ThreadInterrupter::InitOnce();
98 monitor_ = new Monitor(); 55 }
99 start_stop_monitor_ = new Monitor(); 56
100 initialized_ = true; 57
101 ResizeIsolates(16); 58 void Profiler::Shutdown() {
102 if (FLAG_trace_profiled_isolates) { 59 if (!FLAG_profile) {
103 OS::Print("ProfilerManager starting up.\n"); 60 return;
104 } 61 }
62 ASSERT(initialized_);
63 ThreadInterrupter::Shutdown();
64 NativeSymbolResolver::ShutdownOnce();
65 }
66
67
68 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
69 if (!FLAG_profile) {
70 return;
71 }
72 ASSERT(isolate != NULL);
73 ASSERT(sample_buffer_ != NULL);
74 MonitorLocker ml(monitor_);
105 { 75 {
106 ScopedMonitor startup_lock(start_stop_monitor_); 76 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
107 Thread::Start(ThreadMain, 0); 77 SampleBuffer* sample_buffer = sample_buffer_;
108 while (!thread_running_) { 78 if (!shared_buffer) {
109 // Wait until profiler thread has started up. 79 sample_buffer = new SampleBuffer();
110 startup_lock.Wait(); 80 }
111 } 81 IsolateProfilerData* profiler_data =
112 } 82 new IsolateProfilerData(sample_buffer, !shared_buffer);
113 if (FLAG_trace_profiled_isolates) { 83 ASSERT(profiler_data != NULL);
114 OS::Print("ProfilerManager running.\n"); 84 isolate->set_profiler_data(profiler_data);
115 } 85 if (FLAG_trace_profiled_isolates) {
116 } 86 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
117 87 }
118 88 }
119 void ProfilerManager::Shutdown() { 89 }
120 if (!FLAG_profile) { 90
121 return; 91
122 } 92 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
123 ASSERT(initialized_); 93 ASSERT(isolate != NULL);
124 if (FLAG_trace_profiled_isolates) { 94 if (!FLAG_profile) {
125 OS::Print("ProfilerManager shutting down.\n"); 95 return;
126 } 96 }
127 intptr_t size_at_shutdown = 0; 97 // We do not have a current isolate.
98 ASSERT(Isolate::Current() == NULL);
99 MonitorLocker ml(monitor_);
128 { 100 {
129 ScopedSignalBlocker ssb; 101 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
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();
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 }
152
153
154 void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) {
155 if (!FLAG_profile) {
156 return;
157 }
158 ASSERT(isolate != NULL);
159 {
160 ScopedSignalBlocker ssb;
161 {
162 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
163 SampleBuffer* sample_buffer = new SampleBuffer();
164 ASSERT(sample_buffer != NULL);
165 IsolateProfilerData* profiler_data =
166 new IsolateProfilerData(isolate, sample_buffer);
167 ASSERT(profiler_data != NULL);
168 profiler_data->set_sample_interval_micros(1000);
169 isolate->set_profiler_data(profiler_data);
170 if (FLAG_trace_profiled_isolates) {
171 OS::Print("ProfilerManager Setup Isolate %p %s %p\n",
172 isolate,
173 isolate->name(),
174 reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
175 }
176 }
177 }
178 }
179
180
181 void ProfilerManager::FreeIsolateProfilingData(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);
205 if (!FLAG_profile) {
206 return;
207 }
208 {
209 ScopedSignalBlocker ssb;
210 FreeIsolateProfilingData(isolate);
211 }
212 }
213
214
215 void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
216 ScopedMonitor lock(monitor_);
217 {
218 if (shutdown_) {
219 // Shutdown.
220 return;
221 }
222 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
223 IsolateProfilerData* profiler_data = isolate->profiler_data(); 102 IsolateProfilerData* profiler_data = isolate->profiler_data();
224 if (profiler_data == NULL) { 103 if (profiler_data == NULL) {
104 // Already freed.
225 return; 105 return;
226 } 106 }
227 profiler_data->Scheduled(OS::GetCurrentTimeMicros(), 107 isolate->set_profiler_data(NULL);
228 Thread::GetCurrentThreadId()); 108 profiler_data->set_sample_buffer(NULL);
229 } 109 delete profiler_data;
230 intptr_t i = FindIsolate(isolate); 110 if (FLAG_trace_profiled_isolates) {
231 if (i >= 0) { 111 OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
232 // Already scheduled. 112 }
233 return; 113 }
234 } 114 }
235 AddIsolate(isolate); 115
236 lock.Notify(); 116
237 } 117 void Profiler::BeginExecution(Isolate* isolate) {
238 118 if (isolate == NULL) {
239 119 return;
240 void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) { 120 }
241 if (!FLAG_profile) { 121 if (!FLAG_profile) {
242 return; 122 return;
243 } 123 }
244 ASSERT(initialized_); 124 ASSERT(initialized_);
245 ASSERT(isolate != NULL); 125 IsolateProfilerData* profiler_data = isolate->profiler_data();
246 if (!inside_signal) { 126 if (profiler_data == NULL) {
247 ScopedSignalBlocker ssb; 127 return;
248 { 128 }
249 ScheduleIsolateHelper(isolate); 129 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
250 } 130 if (sample_buffer == NULL) {
251 } else { 131 return;
252 // Do not need a signal blocker inside a signal handler. 132 }
253 { 133 Sample* sample = sample_buffer->ReserveSample();
254 ScheduleIsolateHelper(isolate); 134 sample->Init(Sample::kIsolateStart, isolate, OS::GetCurrentTimeMicros(),
255 } 135 Thread::GetCurrentThreadId());
256 } 136 ThreadInterrupter::Register(RecordSampleInterruptCallback, isolate);
257 } 137 }
258 138
259 139
260 void ProfilerManager::DescheduleIsolate(Isolate* isolate) { 140 void Profiler::EndExecution(Isolate* isolate) {
141 if (isolate == NULL) {
142 return;
143 }
261 if (!FLAG_profile) { 144 if (!FLAG_profile) {
262 return; 145 return;
263 } 146 }
264 ASSERT(initialized_); 147 ASSERT(initialized_);
265 ASSERT(isolate != NULL); 148 ThreadInterrupter::Unregister();
266 { 149 IsolateProfilerData* profiler_data = isolate->profiler_data();
267 ScopedSignalBlocker ssb; 150 if (profiler_data == NULL) {
268 { 151 return;
269 ScopedMonitor lock(monitor_); 152 }
270 if (shutdown_) { 153 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
271 // Shutdown. 154 if (sample_buffer == NULL) {
272 return; 155 return;
273 } 156 }
274 intptr_t i = FindIsolate(isolate); 157 Sample* sample = sample_buffer->ReserveSample();
275 if (i < 0) { 158 sample->Init(Sample::kIsolateStop, isolate, OS::GetCurrentTimeMicros(),
276 // Not scheduled. 159 Thread::GetCurrentThreadId());
277 return; 160 }
278 } 161
279 { 162
280 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); 163 void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state,
281 IsolateProfilerData* profiler_data = isolate->profiler_data(); 164 void* data) {
282 if (profiler_data != NULL) { 165 Isolate* isolate = reinterpret_cast<Isolate*>(data);
283 profiler_data->Descheduled(); 166 if (isolate == NULL) {
284 } 167 return;
285 } 168 }
286 RemoveIsolate(i); 169 IsolateProfilerData* profiler_data = isolate->profiler_data();
287 lock.Notify(); 170 if (profiler_data == NULL) {
288 } 171 return;
289 } 172 }
290 } 173 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
291 174 if (sample_buffer == NULL) {
292 175 return;
293 void PrintToJSONStream(Isolate* isolate, JSONStream* stream) { 176 }
177 Sample* sample = sample_buffer->ReserveSample();
178 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
179 state.tid);
180 }
181
182
183 void Profiler::RecordSampleInterruptCallback(
184 const InterruptedThreadState& state,
185 void* data) {
186 Isolate* isolate = reinterpret_cast<Isolate*>(data);
187 if (isolate == NULL) {
188 return;
189 }
190 IsolateProfilerData* profiler_data = isolate->profiler_data();
191 if (profiler_data == NULL) {
192 return;
193 }
194 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
195 if (sample_buffer == NULL) {
196 return;
197 }
198 Sample* sample = sample_buffer->ReserveSample();
199 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
200 state.tid);
201 uintptr_t stack_lower = 0;
202 uintptr_t stack_upper = 0;
203 isolate->GetStackBounds(&stack_lower, &stack_upper);
204 if ((stack_lower == 0) || (stack_upper == 0)) {
205 stack_lower = 0;
206 stack_upper = 0;
207 }
208 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
209 state.pc, state.fp, state.sp);
210 stackWalker.walk();
211 }
212
213
214 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
294 ASSERT(isolate == Isolate::Current()); 215 ASSERT(isolate == Isolate::Current());
295 {
296 // We can't get signals here.
297 }
298 UNIMPLEMENTED(); 216 UNIMPLEMENTED();
299 } 217 }
300 218
301 219
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) { 220 static char* FindSymbolName(uintptr_t pc, bool* native_symbol) {
360 // TODO(johnmccutchan): Differentiate between symbols which can't be found 221 // TODO(johnmccutchan): Differentiate between symbols which can't be found
361 // and symbols which were GCed. (Heap::CodeContains). 222 // and symbols which were GCed. (Heap::CodeContains).
362 ASSERT(native_symbol != NULL); 223 ASSERT(native_symbol != NULL);
363 const char* symbol_name = "Unknown"; 224 const char* symbol_name = "Unknown";
364 *native_symbol = false; 225 *native_symbol = false;
226 if (pc == 0) {
227 return const_cast<char*>(Sample::kNoFrame);
228 }
365 const Code& code = Code::Handle(Code::LookupCode(pc)); 229 const Code& code = Code::Handle(Code::LookupCode(pc));
366 if (code.IsNull()) { 230 if (code.IsNull()) {
367 // Possibly a native symbol. 231 // Possibly a native symbol.
368 char* native_name = NativeSymbolResolver::LookupSymbolName(pc); 232 char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
369 if (native_name != NULL) { 233 if (native_name != NULL) {
370 symbol_name = native_name; 234 symbol_name = native_name;
371 *native_symbol = true; 235 *native_symbol = true;
372 } 236 }
373 } else { 237 } else {
374 const Function& function = Function::Handle(code.function()); 238 const Function& function = Function::Handle(code.function());
375 if (!function.IsNull()) { 239 if (!function.IsNull()) {
376 const String& name = String::Handle(function.QualifiedUserVisibleName()); 240 const String& name = String::Handle(function.QualifiedUserVisibleName());
377 if (!name.IsNull()) { 241 if (!name.IsNull()) {
378 symbol_name = name.ToCString(); 242 symbol_name = name.ToCString();
379 } 243 }
380 } 244 }
381 } 245 }
382 return const_cast<char*>(symbol_name); 246 return const_cast<char*>(symbol_name);
383 } 247 }
384 248
385 249
386 void ProfilerManager::WriteTracing(Isolate* isolate, const char* name, 250 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid,
387 Dart_Port port) { 251 Sample* sample, JSONArray& events) {
388 ASSERT(isolate == Isolate::Current()); 252 Sample::SampleType type = sample->type;
389 { 253 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
390 ScopedSignalBlocker ssb; 254 double timestamp = static_cast<double>(sample->timestamp);
391 { 255 const char* isolate_name = isolate->name();
392 ScopedMutex profiler_data_lock(isolate->profiler_data_mutex()); 256 switch (type) {
393 IsolateProfilerData* profiler_data = isolate->profiler_data(); 257 case Sample::kIsolateStart: {
394 if (profiler_data == NULL) { 258 JSONObject begin(&events);
395 return; 259 begin.AddProperty("ph", "B");
396 } 260 begin.AddProperty("tid", tid);
397 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 261 begin.AddProperty("pid", pid);
398 ASSERT(sample_buffer != NULL); 262 begin.AddProperty("name", isolate_name);
399 JSONStream stream(10 * MB); 263 begin.AddProperty("ts", timestamp);
400 intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer); 264 }
401 intptr_t pid = 1; 265 break;
402 { 266 case Sample::kIsolateStop: {
403 JSONArray events(&stream); 267 JSONObject begin(&events);
268 begin.AddProperty("ph", "E");
269 begin.AddProperty("tid", tid);
270 begin.AddProperty("pid", pid);
271 begin.AddProperty("name", isolate_name);
272 begin.AddProperty("ts", timestamp);
273 }
274 break;
275 case Sample::kIsolateSample:
276 // Write "B" events.
277 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
278 bool native_symbol = false;
279 char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
404 { 280 {
405 JSONObject thread_name(&events); 281 JSONObject begin(&events);
406 thread_name.AddProperty("name", "thread_name"); 282 begin.AddProperty("ph", "B");
407 thread_name.AddProperty("ph", "M"); 283 begin.AddProperty("tid", tid);
408 thread_name.AddProperty("tid", tid); 284 begin.AddProperty("pid", pid);
409 thread_name.AddProperty("pid", pid); 285 begin.AddProperty("name", symbol_name);
410 { 286 begin.AddProperty("ts", timestamp);
411 JSONObject args(&thread_name, "args");
412 args.AddProperty("name", name);
413 }
414 } 287 }
415 { 288 if (native_symbol) {
416 JSONObject process_name(&events); 289 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 } 290 }
505 } 291 }
506 char fname[1024]; 292 // Write "E" events.
507 #if defined(TARGET_OS_WINDOWS) 293 for (int i = 0; i < Sample::kNumStackFrames; i++) {
508 snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof", 294 bool native_symbol = false;
509 static_cast<int>(port)); 295 char* symbol_name = FindSymbolName(sample->pcs[i], &native_symbol);
510 #else 296 {
511 snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof", 297 JSONObject begin(&events);
512 static_cast<int>(port)); 298 begin.AddProperty("ph", "E");
513 #endif 299 begin.AddProperty("tid", tid);
514 printf("%s\n", fname); 300 begin.AddProperty("pid", pid);
515 FILE* f = fopen(fname, "wb"); 301 begin.AddProperty("name", symbol_name);
516 ASSERT(f != NULL); 302 begin.AddProperty("ts", timestamp);
517 fputs(stream.ToCString(), f); 303 }
518 fclose(f); 304 if (native_symbol) {
519 } 305 NativeSymbolResolver::FreeSymbolName(symbol_name);
306 }
307 }
308 break;
309 default:
310 UNIMPLEMENTED();
520 } 311 }
521 } 312 }
522 313
523 314
524 IsolateProfilerData::IsolateProfilerData(Isolate* isolate, 315 void Profiler::WriteTracing(Isolate* isolate) {
525 SampleBuffer* sample_buffer) { 316 if (isolate == NULL) {
526 isolate_ = isolate; 317 return;
318 }
319 if (!FLAG_profile) {
320 return;
321 }
322 ASSERT(initialized_);
323 if (FLAG_profile_dir == NULL) {
324 return;
325 }
326 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
327 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
328 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
329 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) {
330 // Embedder has not provided necessary callbacks.
331 return;
332 }
333 // We will be looking up code objects within the isolate.
334 ASSERT(Isolate::Current() != NULL);
335 // We do not want to be interrupted while processing the buffer.
336 EndExecution(isolate);
337 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
338 IsolateProfilerData* profiler_data = isolate->profiler_data();
339 if (profiler_data == NULL) {
340 return;
341 }
342 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
343 ASSERT(sample_buffer != NULL);
344 JSONStream stream(10 * MB);
345 intptr_t pid = OS::ProcessId();
346 {
347 JSONArray events(&stream);
348 {
349 JSONObject process_name(&events);
350 process_name.AddProperty("name", "process_name");
351 process_name.AddProperty("ph", "M");
352 process_name.AddProperty("pid", pid);
353 {
354 JSONObject args(&process_name, "args");
355 args.AddProperty("name", "Dart VM");
356 }
357 }
358 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
359 Sample* sample = sample_buffer->GetSample(i);
360 if (sample->isolate != isolate) {
361 continue;
362 }
363 if (sample->timestamp == 0) {
364 continue;
365 }
366 WriteTracingSample(isolate, pid, sample, events);
367 }
368 }
369 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json";
370 intptr_t len = OS::SNPrint(NULL, 0, format,
371 FLAG_profile_dir, pid, isolate->main_port());
372 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
373 OS::SNPrint(filename, len + 1, format,
374 FLAG_profile_dir, pid, isolate->main_port());
375 void* f = file_open(filename, true);
376 if (f == NULL) {
377 // Cannot write.
378 return;
379 }
380 TextBuffer* buffer = stream.buffer();
381 ASSERT(buffer != NULL);
382 file_write(buffer->buf(), buffer->length(), f);
383 file_close(f);
384 BeginExecution(isolate);
385 }
386
387
388 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
389 bool own_sample_buffer) {
527 sample_buffer_ = sample_buffer; 390 sample_buffer_ = sample_buffer;
528 timer_expiration_micros_ = kNoExpirationTime; 391 own_sample_buffer_ = own_sample_buffer;
529 last_sampled_micros_ = 0;
530 thread_id_ = 0;
531 } 392 }
532 393
533 394
534 IsolateProfilerData::~IsolateProfilerData() { 395 IsolateProfilerData::~IsolateProfilerData() {
535 } 396 if (own_sample_buffer_) {
536 397 delete sample_buffer_;
537 398 sample_buffer_ = NULL;
538 void IsolateProfilerData::SampledAt(int64_t current_time) { 399 own_sample_buffer_ = false;
539 last_sampled_micros_ = current_time; 400 }
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 } 401 }
562 402
563 403
564 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; 404 const char* Sample::kLookupSymbol = "Symbol Not Looked Up";
565 const char* Sample::kNoSymbol = "No Symbol Found"; 405 const char* Sample::kNoSymbol = "No Symbol Found";
406 const char* Sample::kNoFrame = "<no frame>";
566 407
567 Sample::Sample() { 408 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
568 timestamp = 0; 409 ThreadId tid) {
569 cpu_usage = 0; 410 this->timestamp = timestamp;
570 for (int i = 0; i < kNumStackFrames; i++) { 411 this->tid = tid;
412 this->isolate = isolate;
413 for (intptr_t i = 0; i < kNumStackFrames; i++) {
571 pcs[i] = 0; 414 pcs[i] = 0;
572 } 415 }
573 vm_tags = kIdle; 416 this->type = type;
417 vm_tags = 0;
574 runtime_tags = 0; 418 runtime_tags = 0;
575 } 419 }
576 420
577
578 SampleBuffer::SampleBuffer(intptr_t capacity) { 421 SampleBuffer::SampleBuffer(intptr_t capacity) {
579 start_ = 0;
580 end_ = 0;
581 capacity_ = capacity; 422 capacity_ = capacity;
582 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample))); 423 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample)));
424 cursor_ = 0;
583 } 425 }
584 426
585 427
586 SampleBuffer::~SampleBuffer() { 428 SampleBuffer::~SampleBuffer() {
587 if (samples_ != NULL) { 429 if (samples_ != NULL) {
588 free(samples_); 430 free(samples_);
589 samples_ = NULL; 431 samples_ = NULL;
590 start_ = 0; 432 cursor_ = 0;
591 end_ = 0;
592 capacity_ = 0; 433 capacity_ = 0;
593 } 434 }
594 } 435 }
595 436
596 437
597 Sample* SampleBuffer::ReserveSample() { 438 Sample* SampleBuffer::ReserveSample() {
598 ASSERT(samples_ != NULL); 439 ASSERT(samples_ != NULL);
599 intptr_t index = end_; 440 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
600 end_ = WrapIncrement(end_); 441 // Map back into sample buffer range.
601 if (end_ == start_) { 442 cursor = cursor % capacity_;
602 start_ = WrapIncrement(start_); 443 return &samples_[cursor];
603 }
604 ASSERT(index >= 0);
605 ASSERT(index < capacity_);
606 // Reset.
607 samples_[index] = Sample();
608 return &samples_[index];
609 } 444 }
610 445
611 446
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, 447 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample,
637 uintptr_t stack_lower, 448 uintptr_t stack_lower,
638 uintptr_t stack_upper, 449 uintptr_t stack_upper,
639 uintptr_t pc, 450 uintptr_t pc,
640 uintptr_t fp, 451 uintptr_t fp,
641 uintptr_t sp) : 452 uintptr_t sp) :
642 sample_(sample), 453 sample_(sample),
643 stack_lower_(stack_lower), 454 stack_lower_(stack_lower),
644 stack_upper_(stack_upper), 455 stack_upper_(stack_upper),
645 original_pc_(pc), 456 original_pc_(pc),
646 original_fp_(fp), 457 original_fp_(fp),
647 original_sp_(sp), 458 original_sp_(sp),
648 lower_bound_(stack_lower) { 459 lower_bound_(stack_lower) {
649 ASSERT(sample_ != NULL); 460 ASSERT(sample_ != NULL);
650 } 461 }
651 462
652 463
653 int ProfilerSampleStackWalker::walk() { 464 int ProfilerSampleStackWalker::walk() {
654 uword* pc = reinterpret_cast<uword*>(original_pc_); 465 uword* pc = reinterpret_cast<uword*>(original_pc_);
466 #define WALK_STACK
655 #if defined(WALK_STACK) 467 #if defined(WALK_STACK)
656 uword* fp = reinterpret_cast<uword*>(original_fp_); 468 uword* fp = reinterpret_cast<uword*>(original_fp_);
657 uword* previous_fp = fp; 469 uword* previous_fp = fp;
658 if (original_sp_ < lower_bound_) { 470 if (original_sp_ < lower_bound_) {
659 // The stack pointer gives us a better lower bound than 471 // The stack pointer gives us a better lower bound than
660 // the isolates stack limit. 472 // the isolates stack limit.
661 lower_bound_ = original_sp_; 473 lower_bound_ = original_sp_;
662 } 474 }
663 int i = 0; 475 int i = 0;
664 for (; i < Sample::kNumStackFrames; i++) { 476 for (; i < Sample::kNumStackFrames; i++) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 return false; 513 return false;
702 } 514 }
703 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); 515 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp);
704 cursor += sizeof(fp); 516 cursor += sizeof(fp);
705 bool r = cursor >= lower_bound_ && cursor < stack_upper_; 517 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
706 return r; 518 return r;
707 } 519 }
708 520
709 521
710 } // namespace dart 522 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_android.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698