OLD | NEW |
---|---|
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> | |
6 | |
7 #include "platform/utils.h" | 5 #include "platform/utils.h" |
8 | 6 |
7 #include "vm/allocation.h" | |
9 #include "vm/atomic.h" | 8 #include "vm/atomic.h" |
9 #include "vm/code_patcher.h" | |
10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
11 #include "vm/json_stream.h" | 11 #include "vm/json_stream.h" |
12 #include "vm/native_symbol.h" | 12 #include "vm/native_symbol.h" |
13 #include "vm/object.h" | 13 #include "vm/object.h" |
14 #include "vm/os.h" | 14 #include "vm/os.h" |
15 #include "vm/profiler.h" | 15 #include "vm/profiler.h" |
16 #include "vm/signal_handler.h" | 16 #include "vm/signal_handler.h" |
17 #include "vm/simulator.h" | 17 #include "vm/simulator.h" |
18 | 18 |
19 namespace dart { | 19 namespace dart { |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 if ((stack_lower == 0) || (stack_upper == 0)) { | 211 if ((stack_lower == 0) || (stack_upper == 0)) { |
212 stack_lower = 0; | 212 stack_lower = 0; |
213 stack_upper = 0; | 213 stack_upper = 0; |
214 } | 214 } |
215 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 215 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
216 state.pc, state.fp, state.sp); | 216 state.pc, state.fp, state.sp); |
217 stackWalker.walk(); | 217 stackWalker.walk(); |
218 } | 218 } |
219 | 219 |
220 | 220 |
221 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) { | 221 struct AddressEntry { |
222 uintptr_t pc; | |
223 uintptr_t ticks; | |
224 }; | |
225 | |
226 | |
227 // A region of code. Each region is a kind of code (Dart, Collected, or Native). | |
228 class CodeRegion : public ZoneAllocated { | |
229 public: | |
230 enum Kind { | |
231 kDartCode, | |
232 kCollectedCode, | |
233 kNativeCode | |
234 }; | |
235 | |
236 CodeRegion(Kind kind, uintptr_t start, uintptr_t end) : | |
237 kind_(kind), | |
238 start_(start), | |
239 end_(end), | |
240 inclusive_ticks_(0), | |
241 exclusive_ticks_(0), | |
242 name_(NULL), | |
243 address_table_(new ZoneGrowableArray<AddressEntry>()) { | |
244 } | |
245 | |
246 ~CodeRegion() { | |
Ivan Posva
2014/01/03 19:24:54
ZoneAllocated and thus CodeRegion destructors are
Cutch
2014/01/03 19:42:30
Done.
| |
247 if (name_ != NULL) { | |
248 free(const_cast<char*>(name_)); | |
249 name_ = NULL; | |
250 } | |
251 } | |
252 | |
253 uintptr_t start() const { return start_; } | |
254 void set_start(uintptr_t start) { | |
255 start_ = start; | |
256 } | |
257 | |
258 uintptr_t end() const { return end_; } | |
259 void set_end(uintptr_t end) { | |
260 end_ = end; | |
261 } | |
262 | |
263 void AdjustExtent(uintptr_t start, uintptr_t end) { | |
264 if (start < start_) { | |
265 start_ = start; | |
266 } | |
267 if (end > end_) { | |
268 end_ = end; | |
269 } | |
270 } | |
271 | |
272 bool contains(uintptr_t pc) const { | |
273 return (pc >= start_) && (pc < end_); | |
274 } | |
275 | |
276 intptr_t inclusive_ticks() const { return inclusive_ticks_; } | |
277 void set_inclusive_ticks(intptr_t inclusive_ticks) { | |
278 inclusive_ticks_ = inclusive_ticks; | |
279 } | |
280 | |
281 intptr_t exclusive_ticks() const { return exclusive_ticks_; } | |
282 void set_exclusive_ticks(intptr_t exclusive_ticks) { | |
283 exclusive_ticks_ = exclusive_ticks; | |
284 } | |
285 | |
286 const char* name() const { return name_; } | |
287 void SetName(const char* name) { | |
288 if (name == NULL) { | |
289 name_ = NULL; | |
290 } | |
291 intptr_t len = strlen(name); | |
292 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1); | |
293 strncpy(const_cast<char*>(name_), name, len); | |
294 const_cast<char*>(name_)[len] = '\0'; | |
295 } | |
296 | |
297 Kind kind() const { return kind_; } | |
298 | |
299 static const char* KindToCString(Kind kind) { | |
300 switch (kind) { | |
301 case kDartCode: | |
302 return "Dart"; | |
303 case kCollectedCode: | |
304 return "Collected"; | |
305 case kNativeCode: | |
306 return "Native"; | |
307 } | |
308 UNREACHABLE(); | |
309 return NULL; | |
310 } | |
311 | |
312 void AddTick(bool exclusive) { | |
313 if (exclusive) { | |
314 exclusive_ticks_++; | |
315 } else { | |
316 inclusive_ticks_++; | |
317 } | |
318 } | |
319 | |
320 void AddTickAtAddress(uintptr_t pc) { | |
321 const intptr_t length = address_table_->length(); | |
322 intptr_t i = 0; | |
323 for (; i < length; i++) { | |
324 AddressEntry& entry = (*address_table_)[i]; | |
325 if (entry.pc == pc) { | |
326 entry.ticks++; | |
327 return; | |
328 } | |
329 if (entry.pc > pc) { | |
330 break; | |
331 } | |
332 } | |
333 AddressEntry entry; | |
334 entry.pc = pc; | |
335 entry.ticks = 1; | |
336 if (i < length) { | |
337 // Insert at i. | |
338 address_table_->InsertAt(i, entry); | |
339 } else { | |
340 // Add to end. | |
341 address_table_->Add(entry); | |
342 } | |
343 } | |
344 | |
345 | |
346 void PrintToJSONArray(JSONArray* events, bool full) { | |
347 JSONObject obj(events); | |
348 obj.AddProperty("type", "ProfileCode"); | |
349 obj.AddProperty("kind", KindToCString(kind())); | |
350 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); | |
351 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); | |
352 if (kind() == kDartCode) { | |
353 // Look up code in Dart heap. | |
354 Code& code = Code::Handle(Code::LookupCode(start())); | |
355 Function& func = Function::Handle(); | |
356 ASSERT(!code.IsNull()); | |
357 func ^= code.function(); | |
358 if (func.IsNull()) { | |
359 if (name() == NULL) { | |
360 GenerateAndSetSymbolName("Stub"); | |
361 } | |
362 obj.AddPropertyF("start", "%" Px "", start()); | |
363 obj.AddPropertyF("end", "%" Px "", end()); | |
364 obj.AddProperty("name", name()); | |
365 } else { | |
366 obj.AddProperty("code", code, !full); | |
367 } | |
368 } else if (kind() == kCollectedCode) { | |
369 if (name() == NULL) { | |
370 GenerateAndSetSymbolName("Collected"); | |
371 } | |
372 obj.AddPropertyF("start", "%" Px "", start()); | |
373 obj.AddPropertyF("end", "%" Px "", end()); | |
374 obj.AddProperty("name", name()); | |
375 } else { | |
376 ASSERT(kind() == kNativeCode); | |
377 if (name() == NULL) { | |
378 GenerateAndSetSymbolName("Native"); | |
379 } | |
380 obj.AddPropertyF("start", "%" Px "", start()); | |
381 obj.AddPropertyF("end", "%" Px "", end()); | |
382 obj.AddProperty("name", name()); | |
383 } | |
384 { | |
385 JSONArray ticks(&obj, "ticks"); | |
386 for (intptr_t i = 0; i < address_table_->length(); i++) { | |
387 const AddressEntry& entry = (*address_table_)[i]; | |
388 ticks.AddValueF("%" Px "", entry.pc); | |
389 ticks.AddValueF("%" Pd "", entry.ticks); | |
390 } | |
391 } | |
392 } | |
393 | |
394 private: | |
395 void GenerateAndSetSymbolName(const char* prefix) { | |
396 const intptr_t kBuffSize = 512; | |
397 char buff[kBuffSize]; | |
398 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | |
399 prefix, start(), end()); | |
400 SetName(buff); | |
401 } | |
402 | |
403 Kind kind_; | |
404 uintptr_t start_; | |
405 uintptr_t end_; | |
406 intptr_t inclusive_ticks_; | |
407 intptr_t exclusive_ticks_; | |
408 const char* name_; | |
409 ZoneGrowableArray<AddressEntry>* address_table_; | |
410 | |
411 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | |
412 }; | |
413 | |
414 | |
415 // All code regions. Code region tables are built on demand when a profile | |
416 // is requested (through the service or on isolate shutdown). | |
417 class ProfilerCodeRegionTable : public ValueObject { | |
418 public: | |
419 explicit ProfilerCodeRegionTable(Isolate* isolate) : | |
420 heap_(isolate->heap()), | |
421 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { | |
422 } | |
423 | |
424 ~ProfilerCodeRegionTable() { | |
425 } | |
426 | |
427 void AddTick(uintptr_t pc, bool exclusive) { | |
428 intptr_t index = FindIndex(pc); | |
429 if (index < 0) { | |
430 CodeRegion* code_region = CreateCodeRegion(pc); | |
431 ASSERT(code_region != NULL); | |
432 index = InsertCodeRegion(code_region); | |
433 } | |
434 ASSERT(index >= 0); | |
435 ASSERT(index < code_region_table_->length()); | |
436 (*code_region_table_)[index]->AddTick(exclusive); | |
437 (*code_region_table_)[index]->AddTickAtAddress(pc); | |
Ivan Posva
2014/01/03 19:24:54
This will distort the exclusive ticks with too man
Cutch
2014/01/03 19:42:30
Good catch. Fixed by conditionally ticking the add
| |
438 } | |
439 | |
440 intptr_t Length() const { return code_region_table_->length(); } | |
441 | |
442 CodeRegion* At(intptr_t idx) { | |
443 return (*code_region_table_)[idx]; | |
444 } | |
445 | |
446 private: | |
447 intptr_t FindIndex(uintptr_t pc) { | |
448 const intptr_t length = code_region_table_->length(); | |
449 for (intptr_t i = 0; i < length; i++) { | |
450 const CodeRegion* code_region = (*code_region_table_)[i]; | |
451 if (code_region->contains(pc)) { | |
452 return i; | |
453 } | |
454 } | |
455 return -1; | |
456 } | |
457 | |
458 CodeRegion* CreateCodeRegion(uintptr_t pc) { | |
459 Code& code = Code::Handle(Code::LookupCode(pc)); | |
460 if (!code.IsNull()) { | |
461 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), | |
462 code.EntryPoint() + code.Size()); | |
463 } | |
464 if (heap_->CodeContains(pc)) { | |
465 const intptr_t kDartCodeAlignment = 0x10; | |
466 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | |
467 return new CodeRegion(CodeRegion::kCollectedCode, | |
468 (pc & kDartCodeAlignmentMask), | |
469 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment); | |
470 } | |
471 uintptr_t native_start = 0; | |
472 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, | |
473 &native_start); | |
474 if (native_name == NULL) { | |
475 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1); | |
476 } | |
477 ASSERT(pc >= native_start); | |
478 CodeRegion* code_region = | |
479 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1); | |
480 code_region->SetName(native_name); | |
481 free(native_name); | |
482 return code_region; | |
483 } | |
484 | |
485 intptr_t InsertCodeRegion(CodeRegion* code_region) { | |
486 const intptr_t length = code_region_table_->length(); | |
487 const uintptr_t start = code_region->start(); | |
488 const uintptr_t end = code_region->end(); | |
489 intptr_t i = 0; | |
490 for (; i < length; i++) { | |
491 CodeRegion* region = (*code_region_table_)[i]; | |
492 if (region->contains(start) || region->contains(end - 1)) { | |
493 // We should only see overlapping native code regions. | |
494 ASSERT(region->kind() == CodeRegion::kNativeCode); | |
495 // When code regions overlap, they should be of the same kind. | |
496 ASSERT(region->kind() == code_region->kind()); | |
497 // Overlapping code region. | |
498 region->AdjustExtent(start, end); | |
499 return i; | |
500 } else if (start >= region->end()) { | |
501 // Insert here. | |
502 break; | |
503 } | |
504 } | |
505 if (i != length) { | |
506 code_region_table_->InsertAt(i, code_region); | |
507 return i; | |
508 } | |
509 code_region_table_->Add(code_region); | |
510 return code_region_table_->length() - 1; | |
511 } | |
512 | |
513 Heap* heap_; | |
514 ZoneGrowableArray<CodeRegion*>* code_region_table_; | |
515 }; | |
516 | |
517 | |
518 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | |
519 bool full) { | |
222 ASSERT(isolate == Isolate::Current()); | 520 ASSERT(isolate == Isolate::Current()); |
223 UNIMPLEMENTED(); | 521 // Disable profile interrupts while processing the buffer. |
522 EndExecution(isolate); | |
523 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | |
524 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
525 if (profiler_data == NULL) { | |
526 JSONObject error(stream); | |
527 error.AddProperty("type", "Error"); | |
528 error.AddProperty("text", "Isolate does not have profiling enabled."); | |
529 return; | |
530 } | |
531 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
532 ASSERT(sample_buffer != NULL); | |
533 { | |
534 StackZone zone(isolate); | |
535 { | |
536 // Build code region table. | |
537 ProfilerCodeRegionTable code_region_table(isolate); | |
538 intptr_t samples = | |
539 ProcessSamples(isolate, &code_region_table, sample_buffer); | |
540 { | |
541 // Serialize to JSON. | |
542 JSONObject obj(stream); | |
543 obj.AddProperty("type", "Profile"); | |
544 obj.AddProperty("samples", samples); | |
545 JSONArray codes(&obj, "codes"); | |
546 for (intptr_t i = 0; i < code_region_table.Length(); i++) { | |
547 CodeRegion* region = code_region_table.At(i); | |
548 ASSERT(region != NULL); | |
549 region->PrintToJSONArray(&codes, full); | |
550 } | |
551 } | |
552 } | |
553 } | |
554 // Enable profile interrupts. | |
555 BeginExecution(isolate); | |
224 } | 556 } |
225 | 557 |
226 | 558 |
227 static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) { | 559 intptr_t Profiler::ProcessSamples(Isolate* isolate, |
228 // TODO(johnmccutchan): Differentiate between symbols which can't be found | 560 ProfilerCodeRegionTable* code_region_table, |
229 // and symbols which were GCed. (Heap::CodeContains). | 561 SampleBuffer* sample_buffer) { |
230 ASSERT(symbol_name_allocated != NULL); | 562 int64_t start = OS::GetCurrentTimeMillis(); |
231 const char* symbol_name = "Unknown"; | 563 intptr_t samples = 0; |
232 *symbol_name_allocated = false; | 564 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { |
233 if (pc == 0) { | 565 Sample sample = sample_buffer->GetSample(i); |
234 return const_cast<char*>(Sample::kNoFrame); | 566 if (sample.isolate != isolate) { |
235 } | 567 continue; |
236 const Code& code = Code::Handle(Code::LookupCode(pc)); | 568 } |
237 if (!code.IsNull()) { | 569 if (sample.timestamp == 0) { |
238 const Function& function = Function::Handle(code.function()); | 570 continue; |
239 if (!function.IsNull()) { | 571 } |
240 const String& name = String::Handle(function.QualifiedUserVisibleName()); | 572 samples += ProcessSample(isolate, code_region_table, &sample); |
241 if (!name.IsNull()) { | 573 } |
242 symbol_name = name.ToCString(); | 574 int64_t end = OS::GetCurrentTimeMillis(); |
243 return symbol_name; | 575 if (FLAG_trace_profiled_isolates) { |
244 } | 576 int64_t delta = end - start; |
245 } | 577 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", |
246 } else { | 578 samples, |
247 // Possibly a native symbol. | 579 isolate->name(), |
248 char* native_name = NativeSymbolResolver::LookupSymbolName(pc); | 580 delta); |
249 if (native_name != NULL) { | 581 } |
250 symbol_name = native_name; | 582 return samples; |
251 *symbol_name_allocated = true; | |
252 return symbol_name; | |
253 } | |
254 } | |
255 const intptr_t kBucketSize = 256; | |
256 const intptr_t kBucketMask = ~(kBucketSize - 1); | |
257 // Not a Dart symbol or a native symbol. Bin into buckets by PC. | |
258 pc &= kBucketMask; | |
259 { | |
260 const intptr_t kBuffSize = 256; | |
261 char buff[kBuffSize]; | |
262 OS::SNPrint(&buff[0], kBuffSize-1, "Unknown [%" Px ", %" Px ")", | |
263 pc, pc + kBucketSize); | |
264 symbol_name = strdup(buff); | |
265 *symbol_name_allocated = true; | |
266 } | |
267 return symbol_name; | |
268 } | 583 } |
269 | 584 |
270 | 585 |
271 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid, | 586 intptr_t Profiler::ProcessSample(Isolate* isolate, |
272 Sample* sample, JSONArray& events) { | 587 ProfilerCodeRegionTable* code_region_table, |
588 Sample* sample) { | |
273 Sample::SampleType type = sample->type; | 589 Sample::SampleType type = sample->type; |
274 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid); | 590 if (type != Sample::kIsolateSample) { |
275 double timestamp = static_cast<double>(sample->timestamp); | 591 return 0; |
276 const char* isolate_name = isolate->name(); | 592 } |
277 switch (type) { | 593 if (sample->pcs[0] == 0) { |
278 case Sample::kIsolateStart: { | 594 // No frames in this sample. |
279 JSONObject begin(&events); | 595 return 0; |
280 begin.AddProperty("ph", "B"); | 596 } |
281 begin.AddProperty("tid", tid); | 597 intptr_t i = 0; |
282 begin.AddProperty("pid", pid); | 598 // i points to the leaf (exclusive) PC sample. |
283 begin.AddProperty("name", isolate_name); | 599 code_region_table->AddTick(sample->pcs[i], true); |
284 begin.AddProperty("ts", timestamp); | 600 for (; i < Sample::kNumStackFrames; i++) { |
285 } | 601 if (sample->pcs[i] == 0) { |
286 break; | 602 break; |
287 case Sample::kIsolateStop: { | 603 } |
288 JSONObject begin(&events); | 604 code_region_table->AddTick(sample->pcs[i], false); |
Ivan Posva
2014/01/03 19:24:54
Double counting the exclusive ticks as inclusive t
Cutch
2014/01/03 19:42:30
Giving all code regions an inclusive tick was int
| |
289 begin.AddProperty("ph", "E"); | 605 } |
290 begin.AddProperty("tid", tid); | 606 return 1; |
291 begin.AddProperty("pid", pid); | |
292 begin.AddProperty("name", isolate_name); | |
293 begin.AddProperty("ts", timestamp); | |
294 } | |
295 break; | |
296 case Sample::kIsolateSample: | |
297 // Write "B" events. | |
298 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) { | |
299 bool symbol_name_allocated = false; | |
300 const char* symbol_name = FindSymbolName(sample->pcs[i], | |
301 &symbol_name_allocated); | |
302 { | |
303 JSONObject begin(&events); | |
304 begin.AddProperty("ph", "B"); | |
305 begin.AddProperty("tid", tid); | |
306 begin.AddProperty("pid", pid); | |
307 begin.AddProperty("name", symbol_name); | |
308 begin.AddProperty("ts", timestamp); | |
309 } | |
310 if (symbol_name_allocated) { | |
311 free(const_cast<char*>(symbol_name)); | |
312 } | |
313 } | |
314 // Write "E" events. | |
315 for (int i = 0; i < Sample::kNumStackFrames; i++) { | |
316 bool symbol_name_allocated = false; | |
317 const char* symbol_name = FindSymbolName(sample->pcs[i], | |
318 &symbol_name_allocated); | |
319 { | |
320 JSONObject begin(&events); | |
321 begin.AddProperty("ph", "E"); | |
322 begin.AddProperty("tid", tid); | |
323 begin.AddProperty("pid", pid); | |
324 begin.AddProperty("name", symbol_name); | |
325 begin.AddProperty("ts", timestamp); | |
326 } | |
327 if (symbol_name_allocated) { | |
328 free(const_cast<char*>(symbol_name)); | |
329 } | |
330 } | |
331 break; | |
332 default: | |
333 UNIMPLEMENTED(); | |
334 } | |
335 } | 607 } |
336 | 608 |
337 | 609 |
338 void Profiler::WriteTracing(Isolate* isolate) { | 610 void Profiler::WriteProfile(Isolate* isolate) { |
339 if (isolate == NULL) { | 611 if (isolate == NULL) { |
340 return; | 612 return; |
341 } | 613 } |
342 if (!FLAG_profile) { | 614 if (!FLAG_profile) { |
343 return; | 615 return; |
344 } | 616 } |
345 ASSERT(initialized_); | 617 ASSERT(initialized_); |
346 if (FLAG_profile_dir == NULL) { | 618 if (FLAG_profile_dir == NULL) { |
347 return; | 619 return; |
348 } | 620 } |
349 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 621 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
350 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 622 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
351 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 623 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
352 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { | 624 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { |
353 // Embedder has not provided necessary callbacks. | 625 // Embedder has not provided necessary callbacks. |
354 return; | 626 return; |
355 } | 627 } |
356 // We will be looking up code objects within the isolate. | 628 // We will be looking up code objects within the isolate. |
357 ASSERT(Isolate::Current() != NULL); | 629 ASSERT(Isolate::Current() == isolate); |
358 // We do not want to be interrupted while processing the buffer. | |
359 EndExecution(isolate); | |
360 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | |
361 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
362 if (profiler_data == NULL) { | |
363 return; | |
364 } | |
365 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
366 ASSERT(sample_buffer != NULL); | |
367 JSONStream stream(10 * MB); | 630 JSONStream stream(10 * MB); |
368 intptr_t pid = OS::ProcessId(); | 631 intptr_t pid = OS::ProcessId(); |
369 { | 632 PrintToJSONStream(isolate, &stream, true); |
370 JSONArray events(&stream); | |
371 { | |
372 JSONObject process_name(&events); | |
373 process_name.AddProperty("name", "process_name"); | |
374 process_name.AddProperty("ph", "M"); | |
375 process_name.AddProperty("pid", pid); | |
376 { | |
377 JSONObject args(&process_name, "args"); | |
378 args.AddProperty("name", "Dart VM"); | |
379 } | |
380 } | |
381 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { | |
382 Sample* sample = sample_buffer->GetSample(i); | |
383 if (sample->isolate != isolate) { | |
384 continue; | |
385 } | |
386 if (sample->timestamp == 0) { | |
387 continue; | |
388 } | |
389 WriteTracingSample(isolate, pid, sample, events); | |
390 } | |
391 } | |
392 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; | 633 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; |
393 intptr_t len = OS::SNPrint(NULL, 0, format, | 634 intptr_t len = OS::SNPrint(NULL, 0, format, |
394 FLAG_profile_dir, pid, isolate->main_port()); | 635 FLAG_profile_dir, pid, isolate->main_port()); |
395 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 636 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
396 OS::SNPrint(filename, len + 1, format, | 637 OS::SNPrint(filename, len + 1, format, |
397 FLAG_profile_dir, pid, isolate->main_port()); | 638 FLAG_profile_dir, pid, isolate->main_port()); |
398 void* f = file_open(filename, true); | 639 void* f = file_open(filename, true); |
399 if (f == NULL) { | 640 if (f == NULL) { |
400 // Cannot write. | 641 // Cannot write. |
401 return; | 642 return; |
402 } | 643 } |
403 TextBuffer* buffer = stream.buffer(); | 644 TextBuffer* buffer = stream.buffer(); |
404 ASSERT(buffer != NULL); | 645 ASSERT(buffer != NULL); |
405 file_write(buffer->buf(), buffer->length(), f); | 646 file_write(buffer->buf(), buffer->length(), f); |
406 file_close(f); | 647 file_close(f); |
407 BeginExecution(isolate); | |
408 } | 648 } |
409 | 649 |
410 | 650 |
411 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, | 651 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, |
412 bool own_sample_buffer) { | 652 bool own_sample_buffer) { |
413 sample_buffer_ = sample_buffer; | 653 sample_buffer_ = sample_buffer; |
414 own_sample_buffer_ = own_sample_buffer; | 654 own_sample_buffer_ = own_sample_buffer; |
415 } | 655 } |
416 | 656 |
417 | 657 |
418 IsolateProfilerData::~IsolateProfilerData() { | 658 IsolateProfilerData::~IsolateProfilerData() { |
419 if (own_sample_buffer_) { | 659 if (own_sample_buffer_) { |
420 delete sample_buffer_; | 660 delete sample_buffer_; |
421 sample_buffer_ = NULL; | 661 sample_buffer_ = NULL; |
422 own_sample_buffer_ = false; | 662 own_sample_buffer_ = false; |
423 } | 663 } |
424 } | 664 } |
425 | 665 |
426 | 666 |
427 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; | |
428 const char* Sample::kNoSymbol = "No Symbol Found"; | |
429 const char* Sample::kNoFrame = "<no frame>"; | |
430 | |
431 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, | 667 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, |
432 ThreadId tid) { | 668 ThreadId tid) { |
433 this->timestamp = timestamp; | 669 this->timestamp = timestamp; |
434 this->tid = tid; | 670 this->tid = tid; |
435 this->isolate = isolate; | 671 this->isolate = isolate; |
436 for (intptr_t i = 0; i < kNumStackFrames; i++) { | 672 for (intptr_t i = 0; i < kNumStackFrames; i++) { |
437 pcs[i] = 0; | 673 pcs[i] = 0; |
438 } | 674 } |
439 this->type = type; | 675 this->type = type; |
440 vm_tags = 0; | 676 vm_tags = 0; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
550 return false; | 786 return false; |
551 } | 787 } |
552 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); | 788 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
553 cursor += sizeof(fp); | 789 cursor += sizeof(fp); |
554 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 790 bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
555 return r; | 791 return r; |
556 } | 792 } |
557 | 793 |
558 | 794 |
559 } // namespace dart | 795 } // namespace dart |
OLD | NEW |