OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 "vm/profiler_service.h" | 5 #include "vm/profiler_service.h" |
6 | 6 |
7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
8 #include "vm/hash_map.h" | 8 #include "vm/hash_map.h" |
9 #include "vm/log.h" | 9 #include "vm/log.h" |
10 #include "vm/native_symbol.h" | 10 #include "vm/native_symbol.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 DECLARE_FLAG(bool, profile_vm); | 22 DECLARE_FLAG(bool, profile_vm); |
23 | 23 |
24 #ifndef PRODUCT | 24 #ifndef PRODUCT |
25 | 25 |
26 class DeoptimizedCodeSet : public ZoneAllocated { | 26 class DeoptimizedCodeSet : public ZoneAllocated { |
27 public: | 27 public: |
28 explicit DeoptimizedCodeSet(Isolate* isolate) | 28 explicit DeoptimizedCodeSet(Isolate* isolate) |
29 : previous_( | 29 : previous_( |
30 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())), | 30 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())), |
31 current_(GrowableObjectArray::ZoneHandle( | 31 current_(GrowableObjectArray::ZoneHandle( |
32 previous_.IsNull() ? GrowableObjectArray::null() : | 32 previous_.IsNull() ? GrowableObjectArray::null() |
33 GrowableObjectArray::New())) { | 33 : GrowableObjectArray::New())) {} |
34 } | |
35 | 34 |
36 void Add(const Code& code) { | 35 void Add(const Code& code) { |
37 if (current_.IsNull()) { | 36 if (current_.IsNull()) { |
38 return; | 37 return; |
39 } | 38 } |
40 if (!Contained(code, previous_) || Contained(code, current_)) { | 39 if (!Contained(code, previous_) || Contained(code, current_)) { |
41 return; | 40 return; |
42 } | 41 } |
43 current_.Add(code); | 42 current_.Add(code); |
44 } | 43 } |
45 | 44 |
46 void UpdateIsolate(Isolate* isolate) { | 45 void UpdateIsolate(Isolate* isolate) { |
47 intptr_t size_before = SizeOf(previous_); | 46 intptr_t size_before = SizeOf(previous_); |
48 intptr_t size_after = SizeOf(current_); | 47 intptr_t size_after = SizeOf(current_); |
49 if ((size_before > 0) && FLAG_trace_profiler) { | 48 if ((size_before > 0) && FLAG_trace_profiler) { |
50 intptr_t length_before = previous_.Length(); | 49 intptr_t length_before = previous_.Length(); |
51 intptr_t length_after = current_.Length(); | 50 intptr_t length_after = current_.Length(); |
52 OS::Print("Updating isolate deoptimized code array: " | 51 OS::Print( |
53 "%" Pd " -> %" Pd " [%" Pd " -> %" Pd "]\n", | 52 "Updating isolate deoptimized code array: " |
54 size_before, size_after, length_before, length_after); | 53 "%" Pd " -> %" Pd " [%" Pd " -> %" Pd "]\n", |
| 54 size_before, size_after, length_before, length_after); |
55 } | 55 } |
56 isolate->set_deoptimized_code_array(current_); | 56 isolate->set_deoptimized_code_array(current_); |
57 } | 57 } |
58 | 58 |
59 private: | 59 private: |
60 bool Contained(const Code& code, const GrowableObjectArray& array) { | 60 bool Contained(const Code& code, const GrowableObjectArray& array) { |
61 if (array.IsNull() || code.IsNull()) { | 61 if (array.IsNull() || code.IsNull()) { |
62 return false; | 62 return false; |
63 } | 63 } |
64 NoSafepointScope no_safepoint_scope; | 64 NoSafepointScope no_safepoint_scope; |
(...skipping 21 matching lines...) Expand all Loading... |
86 | 86 |
87 // Array holding code that is being kept around only for the profiler. | 87 // Array holding code that is being kept around only for the profiler. |
88 const GrowableObjectArray& previous_; | 88 const GrowableObjectArray& previous_; |
89 // Array holding code that should continue to be kept around for the profiler. | 89 // Array holding code that should continue to be kept around for the profiler. |
90 const GrowableObjectArray& current_; | 90 const GrowableObjectArray& current_; |
91 }; | 91 }; |
92 | 92 |
93 | 93 |
94 ProfileFunctionSourcePosition::ProfileFunctionSourcePosition( | 94 ProfileFunctionSourcePosition::ProfileFunctionSourcePosition( |
95 TokenPosition token_pos) | 95 TokenPosition token_pos) |
96 : token_pos_(token_pos), | 96 : token_pos_(token_pos), exclusive_ticks_(0), inclusive_ticks_(0) {} |
97 exclusive_ticks_(0), | |
98 inclusive_ticks_(0) { | |
99 } | |
100 | 97 |
101 | 98 |
102 void ProfileFunctionSourcePosition::Tick(bool exclusive) { | 99 void ProfileFunctionSourcePosition::Tick(bool exclusive) { |
103 if (exclusive) { | 100 if (exclusive) { |
104 exclusive_ticks_++; | 101 exclusive_ticks_++; |
105 } else { | 102 } else { |
106 inclusive_ticks_++; | 103 inclusive_ticks_++; |
107 } | 104 } |
108 } | 105 } |
109 | 106 |
110 | 107 |
111 ProfileFunction::ProfileFunction(Kind kind, | 108 ProfileFunction::ProfileFunction(Kind kind, |
112 const char* name, | 109 const char* name, |
113 const Function& function, | 110 const Function& function, |
114 const intptr_t table_index) | 111 const intptr_t table_index) |
115 : kind_(kind), | 112 : kind_(kind), |
116 name_(name), | 113 name_(name), |
117 function_(Function::ZoneHandle(function.raw())), | 114 function_(Function::ZoneHandle(function.raw())), |
118 table_index_(table_index), | 115 table_index_(table_index), |
119 profile_codes_(0), | 116 profile_codes_(0), |
120 source_position_ticks_(0), | 117 source_position_ticks_(0), |
121 exclusive_ticks_(0), | 118 exclusive_ticks_(0), |
122 inclusive_ticks_(0), | 119 inclusive_ticks_(0), |
123 inclusive_serial_(-1) { | 120 inclusive_serial_(-1) { |
124 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); | 121 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 } | 263 } |
267 if (source_position_ticks_.length() != 1) { | 264 if (source_position_ticks_.length() != 1) { |
268 return false; | 265 return false; |
269 } | 266 } |
270 *pfsp = source_position_ticks_[0]; | 267 *pfsp = source_position_ticks_[0]; |
271 return true; | 268 return true; |
272 } | 269 } |
273 | 270 |
274 | 271 |
275 ProfileCodeAddress::ProfileCodeAddress(uword pc) | 272 ProfileCodeAddress::ProfileCodeAddress(uword pc) |
276 : pc_(pc), | 273 : pc_(pc), exclusive_ticks_(0), inclusive_ticks_(0) {} |
277 exclusive_ticks_(0), | |
278 inclusive_ticks_(0) { | |
279 } | |
280 | 274 |
281 | 275 |
282 void ProfileCodeAddress::Tick(bool exclusive) { | 276 void ProfileCodeAddress::Tick(bool exclusive) { |
283 if (exclusive) { | 277 if (exclusive) { |
284 exclusive_ticks_++; | 278 exclusive_ticks_++; |
285 } else { | 279 } else { |
286 inclusive_ticks_++; | 280 inclusive_ticks_++; |
287 } | 281 } |
288 } | 282 } |
289 | 283 |
290 | 284 |
291 ProfileCode::ProfileCode(Kind kind, | 285 ProfileCode::ProfileCode(Kind kind, |
292 uword start, | 286 uword start, |
293 uword end, | 287 uword end, |
294 int64_t timestamp, | 288 int64_t timestamp, |
295 const Code& code) | 289 const Code& code) |
296 : kind_(kind), | 290 : kind_(kind), |
297 start_(start), | 291 start_(start), |
298 end_(end), | 292 end_(end), |
299 exclusive_ticks_(0), | 293 exclusive_ticks_(0), |
300 inclusive_ticks_(0), | 294 inclusive_ticks_(0), |
301 inclusive_serial_(-1), | 295 inclusive_serial_(-1), |
302 code_(code), | 296 code_(code), |
303 name_(NULL), | 297 name_(NULL), |
304 compile_timestamp_(0), | 298 compile_timestamp_(0), |
305 function_(NULL), | 299 function_(NULL), |
306 code_table_index_(-1), | 300 code_table_index_(-1), |
307 address_ticks_(0) { | 301 address_ticks_(0) {} |
308 } | |
309 | 302 |
310 | 303 |
311 void ProfileCode::AdjustExtent(uword start, uword end) { | 304 void ProfileCode::AdjustExtent(uword start, uword end) { |
312 if (start < start_) { | 305 if (start < start_) { |
313 start_ = start; | 306 start_ = start; |
314 } | 307 } |
315 if (end > end_) { | 308 if (end > end_) { |
316 end_ = end; | 309 end_ = end; |
317 } | 310 } |
318 ASSERT(start_ < end_); | 311 ASSERT(start_ < end_); |
319 } | 312 } |
320 | 313 |
321 | 314 |
322 bool ProfileCode::Overlaps(const ProfileCode* other) const { | 315 bool ProfileCode::Overlaps(const ProfileCode* other) const { |
323 ASSERT(other != NULL); | 316 ASSERT(other != NULL); |
324 return other->Contains(start_) || | 317 return other->Contains(start_) || other->Contains(end_ - 1) || |
325 other->Contains(end_ - 1) || | 318 Contains(other->start()) || Contains(other->end() - 1); |
326 Contains(other->start()) || | |
327 Contains(other->end() - 1); | |
328 } | 319 } |
329 | 320 |
330 | 321 |
331 bool ProfileCode::IsOptimizedDart() const { | 322 bool ProfileCode::IsOptimizedDart() const { |
332 return !code_.IsNull() && code_.is_optimized(); | 323 return !code_.IsNull() && code_.is_optimized(); |
333 } | 324 } |
334 | 325 |
335 | 326 |
336 void ProfileCode::SetName(const char* name) { | 327 void ProfileCode::SetName(const char* name) { |
337 if (name == NULL) { | 328 if (name == NULL) { |
338 name_ = NULL; | 329 name_ = NULL; |
339 } | 330 } |
340 intptr_t len = strlen(name); | 331 intptr_t len = strlen(name); |
341 name_ = Thread::Current()->zone()->Alloc<char>(len + 1); | 332 name_ = Thread::Current()->zone()->Alloc<char>(len + 1); |
342 strncpy(name_, name, len); | 333 strncpy(name_, name, len); |
343 name_[len] = '\0'; | 334 name_[len] = '\0'; |
344 } | 335 } |
345 | 336 |
346 | 337 |
347 void ProfileCode::GenerateAndSetSymbolName(const char* prefix) { | 338 void ProfileCode::GenerateAndSetSymbolName(const char* prefix) { |
348 const intptr_t kBuffSize = 512; | 339 const intptr_t kBuffSize = 512; |
349 char buff[kBuffSize]; | 340 char buff[kBuffSize]; |
350 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | 341 OS::SNPrint(&buff[0], kBuffSize - 1, "%s [%" Px ", %" Px ")", prefix, start(), |
351 prefix, start(), end()); | 342 end()); |
352 SetName(buff); | 343 SetName(buff); |
353 } | 344 } |
354 | 345 |
355 | 346 |
356 void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) { | 347 void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) { |
357 // If exclusive is set, tick it. | 348 // If exclusive is set, tick it. |
358 if (exclusive) { | 349 if (exclusive) { |
359 exclusive_ticks_++; | 350 exclusive_ticks_++; |
360 TickAddress(pc, true); | 351 TickAddress(pc, true); |
361 } | 352 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 } | 511 } |
521 } | 512 } |
522 | 513 |
523 | 514 |
524 class ProfileFunctionTable : public ZoneAllocated { | 515 class ProfileFunctionTable : public ZoneAllocated { |
525 public: | 516 public: |
526 ProfileFunctionTable() | 517 ProfileFunctionTable() |
527 : null_function_(Function::ZoneHandle()), | 518 : null_function_(Function::ZoneHandle()), |
528 unknown_function_(NULL), | 519 unknown_function_(NULL), |
529 table_(8) { | 520 table_(8) { |
530 unknown_function_ = Add(ProfileFunction::kUnknownFunction, | 521 unknown_function_ = |
531 "<unknown Dart function>"); | 522 Add(ProfileFunction::kUnknownFunction, "<unknown Dart function>"); |
532 } | 523 } |
533 | 524 |
534 ProfileFunction* LookupOrAdd(const Function& function) { | 525 ProfileFunction* LookupOrAdd(const Function& function) { |
535 ASSERT(!function.IsNull()); | 526 ASSERT(!function.IsNull()); |
536 ProfileFunction* profile_function = Lookup(function); | 527 ProfileFunction* profile_function = Lookup(function); |
537 if (profile_function != NULL) { | 528 if (profile_function != NULL) { |
538 return profile_function; | 529 return profile_function; |
539 } | 530 } |
540 return Add(function); | 531 return Add(function); |
541 } | 532 } |
(...skipping 19 matching lines...) Expand all Loading... |
561 ProfileFunction* AddNative(uword start_address, const char* name) { | 552 ProfileFunction* AddNative(uword start_address, const char* name) { |
562 // TODO(johnmccutchan): Canonicalize ProfileFunctions for natives. | 553 // TODO(johnmccutchan): Canonicalize ProfileFunctions for natives. |
563 return Add(ProfileFunction::kNativeFunction, name); | 554 return Add(ProfileFunction::kNativeFunction, name); |
564 } | 555 } |
565 | 556 |
566 // No protection against being called more tha once for the same stub. | 557 // No protection against being called more tha once for the same stub. |
567 ProfileFunction* AddStub(uword start_address, const char* name) { | 558 ProfileFunction* AddStub(uword start_address, const char* name) { |
568 return Add(ProfileFunction::kStubFunction, name); | 559 return Add(ProfileFunction::kStubFunction, name); |
569 } | 560 } |
570 | 561 |
571 intptr_t length() const { | 562 intptr_t length() const { return table_.length(); } |
572 return table_.length(); | |
573 } | |
574 | 563 |
575 ProfileFunction* At(intptr_t i) const { | 564 ProfileFunction* At(intptr_t i) const { |
576 ASSERT(i >= 0); | 565 ASSERT(i >= 0); |
577 ASSERT(i < length()); | 566 ASSERT(i < length()); |
578 return table_[i]; | 567 return table_[i]; |
579 } | 568 } |
580 | 569 |
581 private: | 570 private: |
582 ProfileFunction* Add(ProfileFunction::Kind kind, const char* name) { | 571 ProfileFunction* Add(ProfileFunction::Kind kind, const char* name) { |
583 ASSERT(kind != ProfileFunction::kDartFunction); | 572 ASSERT(kind != ProfileFunction::kDartFunction); |
584 ASSERT(name != NULL); | 573 ASSERT(name != NULL); |
585 ProfileFunction* profile_function = | 574 ProfileFunction* profile_function = |
586 new ProfileFunction(kind, | 575 new ProfileFunction(kind, name, null_function_, table_.length()); |
587 name, | |
588 null_function_, | |
589 table_.length()); | |
590 table_.Add(profile_function); | 576 table_.Add(profile_function); |
591 return profile_function; | 577 return profile_function; |
592 } | 578 } |
593 | 579 |
594 ProfileFunction* Add(const Function& function) { | 580 ProfileFunction* Add(const Function& function) { |
595 ASSERT(Lookup(function) == NULL); | 581 ASSERT(Lookup(function) == NULL); |
596 ProfileFunction* profile_function = | 582 ProfileFunction* profile_function = new ProfileFunction( |
597 new ProfileFunction(ProfileFunction::kDartFunction, | 583 ProfileFunction::kDartFunction, NULL, function, table_.length()); |
598 NULL, | |
599 function, | |
600 table_.length()); | |
601 table_.Add(profile_function); | 584 table_.Add(profile_function); |
602 function_hash_.Insert(profile_function); | 585 function_hash_.Insert(profile_function); |
603 return profile_function; | 586 return profile_function; |
604 } | 587 } |
605 | 588 |
606 // Needed for DirectChainedHashMap. | 589 // Needed for DirectChainedHashMap. |
607 struct ProfileFunctionTableTrait { | 590 struct ProfileFunctionTableTrait { |
608 typedef ProfileFunction* Value; | 591 typedef ProfileFunction* Value; |
609 typedef const Function* Key; | 592 typedef const Function* Key; |
610 typedef ProfileFunction* Pair; | 593 typedef ProfileFunction* Pair; |
611 | 594 |
612 static Key KeyOf(Pair kv) { | 595 static Key KeyOf(Pair kv) { return kv->function(); } |
613 return kv->function(); | |
614 } | |
615 | 596 |
616 static Value ValueOf(Pair kv) { | 597 static Value ValueOf(Pair kv) { return kv; } |
617 return kv; | |
618 } | |
619 | 598 |
620 static inline intptr_t Hashcode(Key key) { | 599 static inline intptr_t Hashcode(Key key) { return key->Hash(); } |
621 return key->Hash(); | |
622 } | |
623 | 600 |
624 static inline bool IsKeyEqual(Pair kv, Key key) { | 601 static inline bool IsKeyEqual(Pair kv, Key key) { |
625 return kv->function()->raw() == key->raw(); | 602 return kv->function()->raw() == key->raw(); |
626 } | 603 } |
627 }; | 604 }; |
628 | 605 |
629 const Function& null_function_; | 606 const Function& null_function_; |
630 ProfileFunction* unknown_function_; | 607 ProfileFunction* unknown_function_; |
631 ZoneGrowableArray<ProfileFunction*> table_; | 608 ZoneGrowableArray<ProfileFunction*> table_; |
632 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_; | 609 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_; |
(...skipping 27 matching lines...) Expand all Loading... |
660 // Lazily set generated name. | 637 // Lazily set generated name. |
661 GenerateAndSetSymbolName("[Native]"); | 638 GenerateAndSetSymbolName("[Native]"); |
662 } | 639 } |
663 function = table->AddNative(start(), name()); | 640 function = table->AddNative(start(), name()); |
664 } else if (kind() == kTagCode) { | 641 } else if (kind() == kTagCode) { |
665 if (name() == NULL) { | 642 if (name() == NULL) { |
666 if (UserTags::IsUserTag(start())) { | 643 if (UserTags::IsUserTag(start())) { |
667 const char* tag_name = UserTags::TagName(start()); | 644 const char* tag_name = UserTags::TagName(start()); |
668 ASSERT(tag_name != NULL); | 645 ASSERT(tag_name != NULL); |
669 SetName(tag_name); | 646 SetName(tag_name); |
670 } else if (VMTag::IsVMTag(start()) || | 647 } else if (VMTag::IsVMTag(start()) || VMTag::IsRuntimeEntryTag(start()) || |
671 VMTag::IsRuntimeEntryTag(start()) || | |
672 VMTag::IsNativeEntryTag(start())) { | 648 VMTag::IsNativeEntryTag(start())) { |
673 const char* tag_name = VMTag::TagName(start()); | 649 const char* tag_name = VMTag::TagName(start()); |
674 ASSERT(tag_name != NULL); | 650 ASSERT(tag_name != NULL); |
675 SetName(tag_name); | 651 SetName(tag_name); |
676 } else { | 652 } else { |
677 switch (start()) { | 653 switch (start()) { |
678 case VMTag::kRootTagId: | 654 case VMTag::kRootTagId: |
679 SetName("Root"); | 655 SetName("Root"); |
680 break; | 656 break; |
681 case VMTag::kTruncatedTagId: | 657 case VMTag::kTruncatedTagId: |
(...skipping 12 matching lines...) Expand all Loading... |
694 SetName("[Native Code]"); | 670 SetName("[Native Code]"); |
695 break; | 671 break; |
696 case VMTag::kInlineStartCodeTagId: | 672 case VMTag::kInlineStartCodeTagId: |
697 SetName("[Inline Start]"); | 673 SetName("[Inline Start]"); |
698 break; | 674 break; |
699 case VMTag::kInlineEndCodeTagId: | 675 case VMTag::kInlineEndCodeTagId: |
700 SetName("[Inline End]"); | 676 SetName("[Inline End]"); |
701 break; | 677 break; |
702 default: | 678 default: |
703 UNIMPLEMENTED(); | 679 UNIMPLEMENTED(); |
704 break; | 680 break; |
705 } | 681 } |
706 } | 682 } |
707 } | 683 } |
708 function = table->AddTag(start(), name()); | 684 function = table->AddTag(start(), name()); |
709 } else { | 685 } else { |
710 UNREACHABLE(); | 686 UNREACHABLE(); |
711 } | 687 } |
712 ASSERT(function != NULL); | 688 ASSERT(function != NULL); |
713 | 689 |
714 function->AddProfileCode(code_table_index()); | 690 function->AddProfileCode(code_table_index()); |
715 | 691 |
716 function_ = function; | 692 function_ = function; |
717 return function_; | 693 return function_; |
718 } | 694 } |
719 | 695 |
720 | 696 |
721 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); | 697 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); |
722 | 698 |
723 class ProfileCodeTable : public ZoneAllocated { | 699 class ProfileCodeTable : public ZoneAllocated { |
724 public: | 700 public: |
725 ProfileCodeTable() | 701 ProfileCodeTable() : table_(8) {} |
726 : table_(8) { | |
727 } | |
728 | 702 |
729 intptr_t length() const { return table_.length(); } | 703 intptr_t length() const { return table_.length(); } |
730 | 704 |
731 ProfileCode* At(intptr_t index) const { | 705 ProfileCode* At(intptr_t index) const { |
732 ASSERT(index >= 0); | 706 ASSERT(index >= 0); |
733 ASSERT(index < length()); | 707 ASSERT(index < length()); |
734 return table_[index]; | 708 return table_[index]; |
735 } | 709 } |
736 | 710 |
737 // Find the table index to the ProfileCode containing pc. | 711 // Find the table index to the ProfileCode containing pc. |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 } | 813 } |
840 | 814 |
841 static bool CompareUpperBound(uword pc, uword start, uword end) { | 815 static bool CompareUpperBound(uword pc, uword start, uword end) { |
842 return pc >= end; | 816 return pc >= end; |
843 } | 817 } |
844 | 818 |
845 static bool CompareLowerBound(uword pc, uword start, uword end) { | 819 static bool CompareLowerBound(uword pc, uword start, uword end) { |
846 return end <= pc; | 820 return end <= pc; |
847 } | 821 } |
848 | 822 |
849 void HandleOverlap(ProfileCode* existing, ProfileCode* code, | 823 void HandleOverlap(ProfileCode* existing, |
850 uword start, uword end) { | 824 ProfileCode* code, |
| 825 uword start, |
| 826 uword end) { |
851 // We should never see overlapping Dart code regions. | 827 // We should never see overlapping Dart code regions. |
852 ASSERT(existing->kind() != ProfileCode::kDartCode); | 828 ASSERT(existing->kind() != ProfileCode::kDartCode); |
853 // We should never see overlapping Tag code regions. | 829 // We should never see overlapping Tag code regions. |
854 ASSERT(existing->kind() != ProfileCode::kTagCode); | 830 ASSERT(existing->kind() != ProfileCode::kTagCode); |
855 // When code regions overlap, they should be of the same kind. | 831 // When code regions overlap, they should be of the same kind. |
856 ASSERT(existing->kind() == code->kind()); | 832 ASSERT(existing->kind() == code->kind()); |
857 existing->AdjustExtent(start, end); | 833 existing->AdjustExtent(start, end); |
858 } | 834 } |
859 | 835 |
860 void VerifyOrder() { | 836 void VerifyOrder() { |
861 const intptr_t length = table_.length(); | 837 const intptr_t length = table_.length(); |
862 if (length == 0) { | 838 if (length == 0) { |
863 return; | 839 return; |
864 } | 840 } |
865 uword last = table_[0]->end(); | 841 uword last = table_[0]->end(); |
866 for (intptr_t i = 1; i < length; i++) { | 842 for (intptr_t i = 1; i < length; i++) { |
867 ProfileCode* a = table_[i]; | 843 ProfileCode* a = table_[i]; |
868 ASSERT(last <= a->start()); | 844 ASSERT(last <= a->start()); |
869 last = a->end(); | 845 last = a->end(); |
870 } | 846 } |
871 } | 847 } |
872 | 848 |
873 void VerifyOverlap() { | 849 void VerifyOverlap() { |
874 const intptr_t length = table_.length(); | 850 const intptr_t length = table_.length(); |
875 for (intptr_t i = 0; i < length; i++) { | 851 for (intptr_t i = 0; i < length; i++) { |
876 ProfileCode* a = table_[i]; | 852 ProfileCode* a = table_[i]; |
877 for (intptr_t j = i+1; j < length; j++) { | 853 for (intptr_t j = i + 1; j < length; j++) { |
878 ProfileCode* b = table_[j]; | 854 ProfileCode* b = table_[j]; |
879 ASSERT(!a->Contains(b->start()) && | 855 ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && |
880 !a->Contains(b->end() - 1) && | 856 !b->Contains(a->start()) && !b->Contains(a->end() - 1)); |
881 !b->Contains(a->start()) && | |
882 !b->Contains(a->end() - 1)); | |
883 } | 857 } |
884 } | 858 } |
885 } | 859 } |
886 | 860 |
887 ZoneGrowableArray<ProfileCode*> table_; | 861 ZoneGrowableArray<ProfileCode*> table_; |
888 }; | 862 }; |
889 | 863 |
890 | 864 |
891 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) | 865 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
892 : table_index_(table_index), | 866 : table_index_(table_index), count_(0), children_(0), frame_id_(-1) { |
893 count_(0), | |
894 children_(0), | |
895 frame_id_(-1) { | |
896 ASSERT(table_index_ >= 0); | 867 ASSERT(table_index_ >= 0); |
897 } | 868 } |
898 | 869 |
899 | 870 |
900 ProfileTrieNode::~ProfileTrieNode() { | 871 ProfileTrieNode::~ProfileTrieNode() {} |
901 } | |
902 | 872 |
903 | 873 |
904 void ProfileTrieNode::SortChildren() { | 874 void ProfileTrieNode::SortChildren() { |
905 children_.Sort(ProfileTrieNodeCompare); | 875 children_.Sort(ProfileTrieNodeCompare); |
906 // Recurse. | 876 // Recurse. |
907 for (intptr_t i = 0; i < children_.length(); i++) { | 877 for (intptr_t i = 0; i < children_.length(); i++) { |
908 children_[i]->SortChildren(); | 878 children_[i]->SortChildren(); |
909 } | 879 } |
910 } | 880 } |
911 | 881 |
912 | 882 |
913 intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) { | 883 intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) { |
914 for (intptr_t i = 0; i < children_.length(); i++) { | 884 for (intptr_t i = 0; i < children_.length(); i++) { |
915 if (children_[i] == node) { | 885 if (children_[i] == node) { |
916 return i; | 886 return i; |
917 } | 887 } |
918 } | 888 } |
919 return -1; | 889 return -1; |
920 } | 890 } |
921 | 891 |
922 | 892 |
923 class ProfileCodeTrieNode : public ProfileTrieNode { | 893 class ProfileCodeTrieNode : public ProfileTrieNode { |
924 public: | 894 public: |
925 explicit ProfileCodeTrieNode(intptr_t table_index) | 895 explicit ProfileCodeTrieNode(intptr_t table_index) |
926 : ProfileTrieNode(table_index) { | 896 : ProfileTrieNode(table_index) {} |
927 } | |
928 | 897 |
929 void PrintToJSONArray(JSONArray* array) const { | 898 void PrintToJSONArray(JSONArray* array) const { |
930 ASSERT(array != NULL); | 899 ASSERT(array != NULL); |
931 // Write CodeRegion index. | 900 // Write CodeRegion index. |
932 array->AddValue(table_index()); | 901 array->AddValue(table_index()); |
933 // Write count. | 902 // Write count. |
934 array->AddValue(count()); | 903 array->AddValue(count()); |
935 // Write number of children. | 904 // Write number of children. |
936 intptr_t child_count = NumChildren(); | 905 intptr_t child_count = NumChildren(); |
937 array->AddValue(child_count); | 906 array->AddValue(child_count); |
(...skipping 26 matching lines...) Expand all Loading... |
964 children_.Add(reinterpret_cast<ProfileTrieNode*>(child)); | 933 children_.Add(reinterpret_cast<ProfileTrieNode*>(child)); |
965 } | 934 } |
966 return child; | 935 return child; |
967 } | 936 } |
968 }; | 937 }; |
969 | 938 |
970 | 939 |
971 class ProfileFunctionTrieNodeCode { | 940 class ProfileFunctionTrieNodeCode { |
972 public: | 941 public: |
973 explicit ProfileFunctionTrieNodeCode(intptr_t index) | 942 explicit ProfileFunctionTrieNodeCode(intptr_t index) |
974 : code_index_(index), | 943 : code_index_(index), ticks_(0) {} |
975 ticks_(0) { | |
976 } | |
977 | 944 |
978 intptr_t index() const { | 945 intptr_t index() const { return code_index_; } |
979 return code_index_; | |
980 } | |
981 | 946 |
982 void Tick() { | 947 void Tick() { ticks_++; } |
983 ticks_++; | |
984 } | |
985 | 948 |
986 intptr_t ticks() const { | 949 intptr_t ticks() const { return ticks_; } |
987 return ticks_; | |
988 } | |
989 | 950 |
990 private: | 951 private: |
991 intptr_t code_index_; | 952 intptr_t code_index_; |
992 intptr_t ticks_; | 953 intptr_t ticks_; |
993 }; | 954 }; |
994 | 955 |
995 | 956 |
996 class ProfileFunctionTrieNode : public ProfileTrieNode { | 957 class ProfileFunctionTrieNode : public ProfileTrieNode { |
997 public: | 958 public: |
998 explicit ProfileFunctionTrieNode(intptr_t table_index) | 959 explicit ProfileFunctionTrieNode(intptr_t table_index) |
999 : ProfileTrieNode(table_index), | 960 : ProfileTrieNode(table_index), code_objects_(1) {} |
1000 code_objects_(1) { | |
1001 } | |
1002 | 961 |
1003 void PrintToJSONArray(JSONArray* array) const { | 962 void PrintToJSONArray(JSONArray* array) const { |
1004 ASSERT(array != NULL); | 963 ASSERT(array != NULL); |
1005 // Write CodeRegion index. | 964 // Write CodeRegion index. |
1006 array->AddValue(table_index()); | 965 array->AddValue(table_index()); |
1007 // Write count. | 966 // Write count. |
1008 array->AddValue(count()); | 967 array->AddValue(count()); |
1009 // Write number of code objects. | 968 // Write number of code objects. |
1010 intptr_t code_count = code_objects_.length(); | 969 intptr_t code_count = code_objects_.length(); |
1011 array->AddValue(code_count); | 970 array->AddValue(code_count); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1062 code_objects_.Add(code_object); | 1021 code_objects_.Add(code_object); |
1063 } | 1022 } |
1064 | 1023 |
1065 private: | 1024 private: |
1066 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_; | 1025 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_; |
1067 }; | 1026 }; |
1068 | 1027 |
1069 | 1028 |
1070 class ProfileCodeInlinedFunctionsCache : public ValueObject { | 1029 class ProfileCodeInlinedFunctionsCache : public ValueObject { |
1071 public: | 1030 public: |
1072 ProfileCodeInlinedFunctionsCache() | 1031 ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) { |
1073 : cache_cursor_(0), | |
1074 last_hit_(0) { | |
1075 for (intptr_t i = 0; i < kCacheSize; i++) { | 1032 for (intptr_t i = 0; i < kCacheSize; i++) { |
1076 cache_[i].Reset(); | 1033 cache_[i].Reset(); |
1077 } | 1034 } |
1078 cache_hit_ = 0; | 1035 cache_hit_ = 0; |
1079 cache_miss_ = 0; | 1036 cache_miss_ = 0; |
1080 } | 1037 } |
1081 | 1038 |
1082 ~ProfileCodeInlinedFunctionsCache() { | 1039 ~ProfileCodeInlinedFunctionsCache() { |
1083 if (FLAG_trace_profiler) { | 1040 if (FLAG_trace_profiler) { |
1084 intptr_t total = cache_hit_ + cache_miss_; | 1041 intptr_t total = cache_hit_ + cache_miss_; |
1085 OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", | 1042 OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total, |
1086 total, | 1043 cache_hit_, cache_miss_); |
1087 cache_hit_, | |
1088 cache_miss_); | |
1089 } | 1044 } |
1090 } | 1045 } |
1091 | 1046 |
1092 void Get(uword pc, | 1047 void Get(uword pc, |
1093 const Code& code, | 1048 const Code& code, |
1094 ProcessedSample* sample, | 1049 ProcessedSample* sample, |
1095 intptr_t frame_index, | 1050 intptr_t frame_index, |
1096 // Outputs: | 1051 // Outputs: |
1097 GrowableArray<Function*>** inlined_functions, | 1052 GrowableArray<Function*>** inlined_functions, |
1098 GrowableArray<TokenPosition>** inlined_token_positions, | 1053 GrowableArray<TokenPosition>** inlined_token_positions, |
1099 TokenPosition* token_position) { | 1054 TokenPosition* token_position) { |
1100 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); | 1055 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); |
1101 if (FindInCache(pc, | 1056 if (FindInCache(pc, offset, inlined_functions, inlined_token_positions, |
1102 offset, | |
1103 inlined_functions, | |
1104 inlined_token_positions, | |
1105 token_position)) { | 1057 token_position)) { |
1106 // Found in cache. | 1058 // Found in cache. |
1107 return; | 1059 return; |
1108 } | 1060 } |
1109 Add(pc, code, sample, frame_index, | 1061 Add(pc, code, sample, frame_index, inlined_functions, |
1110 inlined_functions, inlined_token_positions, token_position); | 1062 inlined_token_positions, token_position); |
1111 } | 1063 } |
1112 | 1064 |
1113 private: | 1065 private: |
1114 bool FindInCache(uword pc, | 1066 bool FindInCache(uword pc, |
1115 intptr_t offset, | 1067 intptr_t offset, |
1116 GrowableArray<Function*>** inlined_functions, | 1068 GrowableArray<Function*>** inlined_functions, |
1117 GrowableArray<TokenPosition>** inlined_token_positions, | 1069 GrowableArray<TokenPosition>** inlined_token_positions, |
1118 TokenPosition* token_position) { | 1070 TokenPosition* token_position) { |
1119 // Simple linear scan. | 1071 // Simple linear scan. |
1120 for (intptr_t i = 0; i < kCacheSize; i++) { | 1072 for (intptr_t i = 0; i < kCacheSize; i++) { |
(...skipping 23 matching lines...) Expand all Loading... |
1144 ProcessedSample* sample, | 1096 ProcessedSample* sample, |
1145 intptr_t frame_index, | 1097 intptr_t frame_index, |
1146 // Outputs: | 1098 // Outputs: |
1147 GrowableArray<Function*>** inlined_functions, | 1099 GrowableArray<Function*>** inlined_functions, |
1148 GrowableArray<TokenPosition>** inlined_token_positions, | 1100 GrowableArray<TokenPosition>** inlined_token_positions, |
1149 TokenPosition* token_position) { | 1101 TokenPosition* token_position) { |
1150 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); | 1102 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); |
1151 CacheEntry* cache_entry = &cache_[NextFreeIndex()]; | 1103 CacheEntry* cache_entry = &cache_[NextFreeIndex()]; |
1152 cache_entry->pc = pc; | 1104 cache_entry->pc = pc; |
1153 cache_entry->offset = offset; | 1105 cache_entry->offset = offset; |
1154 code.GetInlinedFunctionsAt(offset, | 1106 code.GetInlinedFunctionsAt(offset, &(cache_entry->inlined_functions), |
1155 &(cache_entry->inlined_functions), | |
1156 &(cache_entry->inlined_token_positions)); | 1107 &(cache_entry->inlined_token_positions)); |
1157 cache_entry->token_position = code.GetTokenPositionAt(offset); | 1108 cache_entry->token_position = code.GetTokenPositionAt(offset); |
1158 *token_position = (cache_entry->token_position); | 1109 *token_position = (cache_entry->token_position); |
1159 if (cache_entry->inlined_functions.length() == 0) { | 1110 if (cache_entry->inlined_functions.length() == 0) { |
1160 *inlined_functions = NULL; | 1111 *inlined_functions = NULL; |
1161 *inlined_token_positions = NULL; | 1112 *inlined_token_positions = NULL; |
1162 return; | 1113 return; |
1163 } | 1114 } |
1164 // The inlined token position table does not include the token position | 1115 // The inlined token position table does not include the token position |
1165 // of the final call. Insert it at the beginning because the table. | 1116 // of the final call. Insert it at the beginning because the table. |
1166 // is reversed. | 1117 // is reversed. |
1167 cache_entry->inlined_token_positions.InsertAt( | 1118 cache_entry->inlined_token_positions.InsertAt(0, |
1168 0, | 1119 cache_entry->token_position); |
1169 cache_entry->token_position); | |
1170 | 1120 |
1171 // Write outputs. | 1121 // Write outputs. |
1172 *inlined_functions = &(cache_entry->inlined_functions); | 1122 *inlined_functions = &(cache_entry->inlined_functions); |
1173 *inlined_token_positions = &(cache_entry->inlined_token_positions); | 1123 *inlined_token_positions = &(cache_entry->inlined_token_positions); |
1174 } | 1124 } |
1175 | 1125 |
1176 intptr_t NextFreeIndex() { | 1126 intptr_t NextFreeIndex() { |
1177 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize; | 1127 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize; |
1178 return cache_cursor_; | 1128 return cache_cursor_; |
1179 } | 1129 } |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1268 BuildCodeTrie(Profile::kExclusiveCode); | 1218 BuildCodeTrie(Profile::kExclusiveCode); |
1269 BuildCodeTrie(Profile::kInclusiveCode); | 1219 BuildCodeTrie(Profile::kInclusiveCode); |
1270 | 1220 |
1271 BuildFunctionTrie(Profile::kExclusiveFunction); | 1221 BuildFunctionTrie(Profile::kExclusiveFunction); |
1272 BuildFunctionTrie(Profile::kInclusiveFunction); | 1222 BuildFunctionTrie(Profile::kInclusiveFunction); |
1273 } | 1223 } |
1274 | 1224 |
1275 private: | 1225 private: |
1276 // Returns true if |frame_index| in |sample| is using CPU. | 1226 // Returns true if |frame_index| in |sample| is using CPU. |
1277 static bool IsExecutingFrame(ProcessedSample* sample, intptr_t frame_index) { | 1227 static bool IsExecutingFrame(ProcessedSample* sample, intptr_t frame_index) { |
1278 return (frame_index == 0) && (sample->first_frame_executing() || | 1228 return (frame_index == 0) && |
1279 sample->IsAllocationSample()); | 1229 (sample->first_frame_executing() || sample->IsAllocationSample()); |
1280 } | 1230 } |
1281 | 1231 |
1282 static bool IsInclusiveTrie(Profile::TrieKind kind) { | 1232 static bool IsInclusiveTrie(Profile::TrieKind kind) { |
1283 return (kind == Profile::kInclusiveFunction) || | 1233 return (kind == Profile::kInclusiveFunction) || |
1284 (kind == Profile::kInclusiveCode); | 1234 (kind == Profile::kInclusiveCode); |
1285 } | 1235 } |
1286 | 1236 |
1287 void Setup() { | 1237 void Setup() { |
1288 profile_->live_code_ = new ProfileCodeTable(); | 1238 profile_->live_code_ = new ProfileCodeTable(); |
1289 profile_->dead_code_ = new ProfileCodeTable(); | 1239 profile_->dead_code_ = new ProfileCodeTable(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1333 ASSERT(isolate != NULL); | 1283 ASSERT(isolate != NULL); |
1334 | 1284 |
1335 // Build the live code table eagerly by populating it with code objects | 1285 // Build the live code table eagerly by populating it with code objects |
1336 // from the processed sample buffer. | 1286 // from the processed sample buffer. |
1337 const CodeLookupTable& code_lookup_table = samples_->code_lookup_table(); | 1287 const CodeLookupTable& code_lookup_table = samples_->code_lookup_table(); |
1338 for (intptr_t i = 0; i < code_lookup_table.length(); i++) { | 1288 for (intptr_t i = 0; i < code_lookup_table.length(); i++) { |
1339 const CodeDescriptor* descriptor = code_lookup_table.At(i); | 1289 const CodeDescriptor* descriptor = code_lookup_table.At(i); |
1340 ASSERT(descriptor != NULL); | 1290 ASSERT(descriptor != NULL); |
1341 const Code& code = Code::Handle(descriptor->code()); | 1291 const Code& code = Code::Handle(descriptor->code()); |
1342 ASSERT(!code.IsNull()); | 1292 ASSERT(!code.IsNull()); |
1343 RegisterLiveProfileCode( | 1293 RegisterLiveProfileCode(new ProfileCode( |
1344 new ProfileCode(ProfileCode::kDartCode, | 1294 ProfileCode::kDartCode, code.PayloadStart(), |
1345 code.PayloadStart(), | 1295 code.PayloadStart() + code.Size(), code.compile_timestamp(), code)); |
1346 code.PayloadStart() + code.Size(), | |
1347 code.compile_timestamp(), | |
1348 code)); | |
1349 } | 1296 } |
1350 | 1297 |
1351 // Iterate over samples. | 1298 // Iterate over samples. |
1352 for (intptr_t sample_index = 0; | 1299 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
1353 sample_index < samples_->length(); | |
1354 sample_index++) { | 1300 sample_index++) { |
1355 ProcessedSample* sample = samples_->At(sample_index); | 1301 ProcessedSample* sample = samples_->At(sample_index); |
1356 const int64_t timestamp = sample->timestamp(); | 1302 const int64_t timestamp = sample->timestamp(); |
1357 | 1303 |
1358 // This is our first pass over the sample buffer, use this as an | 1304 // This is our first pass over the sample buffer, use this as an |
1359 // opportunity to determine the min and max time ranges of this profile. | 1305 // opportunity to determine the min and max time ranges of this profile. |
1360 UpdateMinMaxTimes(timestamp); | 1306 UpdateMinMaxTimes(timestamp); |
1361 | 1307 |
1362 // Make sure VM tag exists. | 1308 // Make sure VM tag exists. |
1363 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | 1309 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { |
1364 RegisterProfileCodeTag(VMTag::kNativeTagId); | 1310 RegisterProfileCodeTag(VMTag::kNativeTagId); |
1365 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | 1311 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { |
1366 RegisterProfileCodeTag(VMTag::kRuntimeTagId); | 1312 RegisterProfileCodeTag(VMTag::kRuntimeTagId); |
1367 } | 1313 } |
1368 RegisterProfileCodeTag(sample->vm_tag()); | 1314 RegisterProfileCodeTag(sample->vm_tag()); |
1369 // Make sure user tag exists. | 1315 // Make sure user tag exists. |
1370 RegisterProfileCodeTag(sample->user_tag()); | 1316 RegisterProfileCodeTag(sample->user_tag()); |
1371 | 1317 |
1372 // Make sure that a ProfileCode objects exist for all pcs in the sample | 1318 // Make sure that a ProfileCode objects exist for all pcs in the sample |
1373 // and tick each one. | 1319 // and tick each one. |
1374 for (intptr_t frame_index = 0; | 1320 for (intptr_t frame_index = 0; frame_index < sample->length(); |
1375 frame_index < sample->length(); | |
1376 frame_index++) { | 1321 frame_index++) { |
1377 const uword pc = sample->At(frame_index); | 1322 const uword pc = sample->At(frame_index); |
1378 ASSERT(pc != 0); | 1323 ASSERT(pc != 0); |
1379 ProfileCode* code = FindOrRegisterProfileCode(pc, timestamp); | 1324 ProfileCode* code = FindOrRegisterProfileCode(pc, timestamp); |
1380 ASSERT(code != NULL); | 1325 ASSERT(code != NULL); |
1381 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index); | 1326 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index); |
1382 } | 1327 } |
1383 | 1328 |
1384 TickExitFrame(sample->vm_tag(), sample_index); | 1329 TickExitFrame(sample->vm_tag(), sample_index); |
1385 } | 1330 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1454 } else { | 1399 } else { |
1455 BuildExclusiveCodeTrie(root); | 1400 BuildExclusiveCodeTrie(root); |
1456 } | 1401 } |
1457 root->SortChildren(); | 1402 root->SortChildren(); |
1458 profile_->roots_[static_cast<intptr_t>(kind)] = root; | 1403 profile_->roots_[static_cast<intptr_t>(kind)] = root; |
1459 } | 1404 } |
1460 | 1405 |
1461 void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) { | 1406 void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) { |
1462 ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie", | 1407 ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie", |
1463 FLAG_trace_profiler); | 1408 FLAG_trace_profiler); |
1464 for (intptr_t sample_index = 0; | 1409 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
1465 sample_index < samples_->length(); | |
1466 sample_index++) { | 1410 sample_index++) { |
1467 ProcessedSample* sample = samples_->At(sample_index); | 1411 ProcessedSample* sample = samples_->At(sample_index); |
1468 | 1412 |
1469 // Tick the root. | 1413 // Tick the root. |
1470 ProfileCodeTrieNode* current = root; | 1414 ProfileCodeTrieNode* current = root; |
1471 current->Tick(); | 1415 current->Tick(); |
1472 | 1416 |
1473 // VM & User tags. | 1417 // VM & User tags. |
1474 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1418 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
1475 | 1419 |
1476 ResetKind(); | 1420 ResetKind(); |
1477 | 1421 |
1478 // Truncated tag. | 1422 // Truncated tag. |
1479 if (sample->truncated()) { | 1423 if (sample->truncated()) { |
1480 current = AppendTruncatedTag(current); | 1424 current = AppendTruncatedTag(current); |
1481 } | 1425 } |
1482 | 1426 |
1483 // Walk the sampled PCs. | 1427 // Walk the sampled PCs. |
1484 Code& code = Code::Handle(); | 1428 Code& code = Code::Handle(); |
1485 for (intptr_t frame_index = sample->length() - 1; | 1429 for (intptr_t frame_index = sample->length() - 1; frame_index >= 0; |
1486 frame_index >= 0; | |
1487 frame_index--) { | 1430 frame_index--) { |
1488 ASSERT(sample->At(frame_index) != 0); | 1431 ASSERT(sample->At(frame_index) != 0); |
1489 intptr_t index = | 1432 intptr_t index = |
1490 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); | 1433 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
1491 ASSERT(index >= 0); | 1434 ASSERT(index >= 0); |
1492 ProfileCode* profile_code = | 1435 ProfileCode* profile_code = |
1493 GetProfileCode(sample->At(frame_index), sample->timestamp()); | 1436 GetProfileCode(sample->At(frame_index), sample->timestamp()); |
1494 ASSERT(profile_code->code_table_index() == index); | 1437 ASSERT(profile_code->code_table_index() == index); |
1495 code ^= profile_code->code(); | 1438 code ^= profile_code->code(); |
1496 current = AppendKind(code, current); | 1439 current = AppendKind(code, current); |
1497 current = current->GetChild(index); | 1440 current = current->GetChild(index); |
1498 current->Tick(); | 1441 current->Tick(); |
1499 } | 1442 } |
1500 | 1443 |
1501 if (!sample->first_frame_executing()) { | 1444 if (!sample->first_frame_executing()) { |
1502 current = AppendExitFrame(sample->vm_tag(), current); | 1445 current = AppendExitFrame(sample->vm_tag(), current); |
1503 } | 1446 } |
1504 } | 1447 } |
1505 } | 1448 } |
1506 | 1449 |
1507 void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) { | 1450 void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) { |
1508 ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie", | 1451 ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie", |
1509 FLAG_trace_profiler); | 1452 FLAG_trace_profiler); |
1510 for (intptr_t sample_index = 0; | 1453 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
1511 sample_index < samples_->length(); | |
1512 sample_index++) { | 1454 sample_index++) { |
1513 ProcessedSample* sample = samples_->At(sample_index); | 1455 ProcessedSample* sample = samples_->At(sample_index); |
1514 | 1456 |
1515 // Tick the root. | 1457 // Tick the root. |
1516 ProfileCodeTrieNode* current = root; | 1458 ProfileCodeTrieNode* current = root; |
1517 current->Tick(); | 1459 current->Tick(); |
1518 | 1460 |
1519 // VM & User tags. | 1461 // VM & User tags. |
1520 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1462 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
1521 | 1463 |
1522 ResetKind(); | 1464 ResetKind(); |
1523 | 1465 |
1524 if (!sample->first_frame_executing()) { | 1466 if (!sample->first_frame_executing()) { |
1525 current = AppendExitFrame(sample->vm_tag(), current); | 1467 current = AppendExitFrame(sample->vm_tag(), current); |
1526 } | 1468 } |
1527 | 1469 |
1528 // Walk the sampled PCs. | 1470 // Walk the sampled PCs. |
1529 Code& code = Code::Handle(); | 1471 Code& code = Code::Handle(); |
1530 for (intptr_t frame_index = 0; | 1472 for (intptr_t frame_index = 0; frame_index < sample->length(); |
1531 frame_index < sample->length(); | |
1532 frame_index++) { | 1473 frame_index++) { |
1533 ASSERT(sample->At(frame_index) != 0); | 1474 ASSERT(sample->At(frame_index) != 0); |
1534 intptr_t index = | 1475 intptr_t index = |
1535 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); | 1476 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
1536 ASSERT(index >= 0); | 1477 ASSERT(index >= 0); |
1537 ProfileCode* profile_code = | 1478 ProfileCode* profile_code = |
1538 GetProfileCode(sample->At(frame_index), sample->timestamp()); | 1479 GetProfileCode(sample->At(frame_index), sample->timestamp()); |
1539 ASSERT(profile_code->code_table_index() == index); | 1480 ASSERT(profile_code->code_table_index() == index); |
1540 code ^= profile_code->code(); | 1481 code ^= profile_code->code(); |
1541 current = current->GetChild(index); | 1482 current = current->GetChild(index); |
1542 if (ShouldTickNode(sample, frame_index)) { | 1483 if (ShouldTickNode(sample, frame_index)) { |
1543 current->Tick(); | 1484 current->Tick(); |
1544 } | 1485 } |
1545 current = AppendKind(code, current); | 1486 current = AppendKind(code, current); |
1546 } | 1487 } |
1547 // Truncated tag. | 1488 // Truncated tag. |
1548 if (sample->truncated()) { | 1489 if (sample->truncated()) { |
1549 current = AppendTruncatedTag(current); | 1490 current = AppendTruncatedTag(current); |
1550 } | 1491 } |
1551 } | 1492 } |
1552 } | 1493 } |
1553 | 1494 |
1554 void BuildFunctionTrie(Profile::TrieKind kind) { | 1495 void BuildFunctionTrie(Profile::TrieKind kind) { |
1555 ProfileFunctionTrieNode* root = | 1496 ProfileFunctionTrieNode* root = new ProfileFunctionTrieNode( |
1556 new ProfileFunctionTrieNode( | 1497 GetProfileFunctionTagIndex(VMTag::kRootTagId)); |
1557 GetProfileFunctionTagIndex(VMTag::kRootTagId)); | |
1558 // We tick the functions while building the trie, but, we don't want to do | 1498 // We tick the functions while building the trie, but, we don't want to do |
1559 // it for both tries, just the exclusive trie. | 1499 // it for both tries, just the exclusive trie. |
1560 inclusive_tree_ = IsInclusiveTrie(kind); | 1500 inclusive_tree_ = IsInclusiveTrie(kind); |
1561 tick_functions_ = !inclusive_tree_; | 1501 tick_functions_ = !inclusive_tree_; |
1562 if (inclusive_tree_) { | 1502 if (inclusive_tree_) { |
1563 BuildInclusiveFunctionTrie(root); | 1503 BuildInclusiveFunctionTrie(root); |
1564 } else { | 1504 } else { |
1565 BuildExclusiveFunctionTrie(root); | 1505 BuildExclusiveFunctionTrie(root); |
1566 } | 1506 } |
1567 root->SortChildren(); | 1507 root->SortChildren(); |
1568 profile_->roots_[static_cast<intptr_t>(kind)] = root; | 1508 profile_->roots_[static_cast<intptr_t>(kind)] = root; |
1569 } | 1509 } |
1570 | 1510 |
1571 void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) { | 1511 void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) { |
1572 ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie", | 1512 ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie", |
1573 FLAG_trace_profiler); | 1513 FLAG_trace_profiler); |
1574 ASSERT(!tick_functions_); | 1514 ASSERT(!tick_functions_); |
1575 for (intptr_t sample_index = 0; | 1515 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
1576 sample_index < samples_->length(); | |
1577 sample_index++) { | 1516 sample_index++) { |
1578 ProcessedSample* sample = samples_->At(sample_index); | 1517 ProcessedSample* sample = samples_->At(sample_index); |
1579 | 1518 |
1580 // Tick the root. | 1519 // Tick the root. |
1581 ProfileFunctionTrieNode* current = root; | 1520 ProfileFunctionTrieNode* current = root; |
1582 current->Tick(); | 1521 current->Tick(); |
1583 | 1522 |
1584 // VM & User tags. | 1523 // VM & User tags. |
1585 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1524 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
1586 | 1525 |
1587 // Truncated tag. | 1526 // Truncated tag. |
1588 if (sample->truncated()) { | 1527 if (sample->truncated()) { |
1589 current = AppendTruncatedTag(current); | 1528 current = AppendTruncatedTag(current); |
1590 } | 1529 } |
1591 | 1530 |
1592 // Walk the sampled PCs. | 1531 // Walk the sampled PCs. |
1593 for (intptr_t frame_index = sample->length() - 1; | 1532 for (intptr_t frame_index = sample->length() - 1; frame_index >= 0; |
1594 frame_index >= 0; | |
1595 frame_index--) { | 1533 frame_index--) { |
1596 ASSERT(sample->At(frame_index) != 0); | 1534 ASSERT(sample->At(frame_index) != 0); |
1597 current = ProcessFrame(current, sample_index, sample, frame_index); | 1535 current = ProcessFrame(current, sample_index, sample, frame_index); |
1598 } | 1536 } |
1599 | 1537 |
1600 if (!sample->first_frame_executing()) { | 1538 if (!sample->first_frame_executing()) { |
1601 current = AppendExitFrame(sample->vm_tag(), current); | 1539 current = AppendExitFrame(sample->vm_tag(), current); |
1602 } | 1540 } |
1603 | 1541 |
1604 sample->set_timeline_trie(current); | 1542 sample->set_timeline_trie(current); |
1605 } | 1543 } |
1606 } | 1544 } |
1607 | 1545 |
1608 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { | 1546 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { |
1609 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", | 1547 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", |
1610 FLAG_trace_profiler); | 1548 FLAG_trace_profiler); |
1611 ASSERT(tick_functions_); | 1549 ASSERT(tick_functions_); |
1612 for (intptr_t sample_index = 0; | 1550 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
1613 sample_index < samples_->length(); | |
1614 sample_index++) { | 1551 sample_index++) { |
1615 ProcessedSample* sample = samples_->At(sample_index); | 1552 ProcessedSample* sample = samples_->At(sample_index); |
1616 | 1553 |
1617 // Tick the root. | 1554 // Tick the root. |
1618 ProfileFunctionTrieNode* current = root; | 1555 ProfileFunctionTrieNode* current = root; |
1619 current->Tick(); | 1556 current->Tick(); |
1620 | 1557 |
1621 // VM & User tags. | 1558 // VM & User tags. |
1622 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1559 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
1623 | 1560 |
1624 ResetKind(); | 1561 ResetKind(); |
1625 | 1562 |
1626 if (!sample->first_frame_executing()) { | 1563 if (!sample->first_frame_executing()) { |
1627 current = AppendExitFrame(sample->vm_tag(), current); | 1564 current = AppendExitFrame(sample->vm_tag(), current); |
1628 } | 1565 } |
1629 | 1566 |
1630 // Walk the sampled PCs. | 1567 // Walk the sampled PCs. |
1631 for (intptr_t frame_index = 0; | 1568 for (intptr_t frame_index = 0; frame_index < sample->length(); |
1632 frame_index < sample->length(); | |
1633 frame_index++) { | 1569 frame_index++) { |
1634 ASSERT(sample->At(frame_index) != 0); | 1570 ASSERT(sample->At(frame_index) != 0); |
1635 current = ProcessFrame(current, sample_index, sample, frame_index); | 1571 current = ProcessFrame(current, sample_index, sample, frame_index); |
1636 } | 1572 } |
1637 | 1573 |
1638 TickExitFrameFunction(sample->vm_tag(), sample_index); | 1574 TickExitFrameFunction(sample->vm_tag(), sample_index); |
1639 | 1575 |
1640 // Truncated tag. | 1576 // Truncated tag. |
1641 if (sample->truncated()) { | 1577 if (sample->truncated()) { |
1642 current = AppendTruncatedTag(current); | 1578 current = AppendTruncatedTag(current); |
1643 InclusiveTickTruncatedTag(); | 1579 InclusiveTickTruncatedTag(); |
1644 } | 1580 } |
1645 } | 1581 } |
1646 } | 1582 } |
1647 | 1583 |
1648 ProfileFunctionTrieNode* ProcessFrame( | 1584 ProfileFunctionTrieNode* ProcessFrame(ProfileFunctionTrieNode* current, |
1649 ProfileFunctionTrieNode* current, | 1585 intptr_t sample_index, |
1650 intptr_t sample_index, | 1586 ProcessedSample* sample, |
1651 ProcessedSample* sample, | 1587 intptr_t frame_index) { |
1652 intptr_t frame_index) { | |
1653 const uword pc = sample->At(frame_index); | 1588 const uword pc = sample->At(frame_index); |
1654 ProfileCode* profile_code = GetProfileCode(pc, | 1589 ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp()); |
1655 sample->timestamp()); | |
1656 ProfileFunction* function = profile_code->function(); | 1590 ProfileFunction* function = profile_code->function(); |
1657 ASSERT(function != NULL); | 1591 ASSERT(function != NULL); |
1658 const intptr_t code_index = profile_code->code_table_index(); | 1592 const intptr_t code_index = profile_code->code_table_index(); |
1659 ASSERT(profile_code != NULL); | 1593 ASSERT(profile_code != NULL); |
1660 const Code& code = Code::ZoneHandle(profile_code->code()); | 1594 const Code& code = Code::ZoneHandle(profile_code->code()); |
1661 GrowableArray<Function*>* inlined_functions = NULL; | 1595 GrowableArray<Function*>* inlined_functions = NULL; |
1662 GrowableArray<TokenPosition>* inlined_token_positions = NULL; | 1596 GrowableArray<TokenPosition>* inlined_token_positions = NULL; |
1663 TokenPosition token_position = TokenPosition::kNoSource; | 1597 TokenPosition token_position = TokenPosition::kNoSource; |
1664 if (!code.IsNull()) { | 1598 if (!code.IsNull()) { |
1665 inlined_functions_cache_.Get(pc, code, sample, frame_index, | 1599 inlined_functions_cache_.Get(pc, code, sample, frame_index, |
1666 &inlined_functions, | 1600 &inlined_functions, &inlined_token_positions, |
1667 &inlined_token_positions, | |
1668 &token_position); | 1601 &token_position); |
1669 if (FLAG_trace_profiler_verbose) { | 1602 if (FLAG_trace_profiler_verbose) { |
1670 for (intptr_t i = 0; i < inlined_functions->length(); i++) { | 1603 for (intptr_t i = 0; i < inlined_functions->length(); i++) { |
1671 const String& name = | 1604 const String& name = |
1672 String::Handle((*inlined_functions)[i]->QualifiedScrubbedName()); | 1605 String::Handle((*inlined_functions)[i]->QualifiedScrubbedName()); |
1673 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", | 1606 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", i, |
1674 i, | |
1675 name.ToCString(), | 1607 name.ToCString(), |
1676 (*inlined_token_positions)[i].ToCString()); | 1608 (*inlined_token_positions)[i].ToCString()); |
1677 } | 1609 } |
1678 } | 1610 } |
1679 } | 1611 } |
1680 if (code.IsNull() || | 1612 if (code.IsNull() || (inlined_functions == NULL) || |
1681 (inlined_functions == NULL) || | |
1682 (inlined_functions->length() == 0)) { | 1613 (inlined_functions->length() == 0)) { |
1683 // No inlined functions. | 1614 // No inlined functions. |
1684 if (inclusive_tree_) { | 1615 if (inclusive_tree_) { |
1685 current = AppendKind(code, current); | 1616 current = AppendKind(code, current); |
1686 } | 1617 } |
1687 current = ProcessFunction(current, | 1618 current = ProcessFunction(current, sample_index, sample, frame_index, |
1688 sample_index, | 1619 function, token_position, code_index); |
1689 sample, | |
1690 frame_index, | |
1691 function, | |
1692 token_position, | |
1693 code_index); | |
1694 if (!inclusive_tree_) { | 1620 if (!inclusive_tree_) { |
1695 current = AppendKind(code, current); | 1621 current = AppendKind(code, current); |
1696 } | 1622 } |
1697 return current; | 1623 return current; |
1698 } | 1624 } |
1699 | 1625 |
1700 ASSERT(code.is_optimized()); | 1626 ASSERT(code.is_optimized()); |
1701 | 1627 |
1702 if (inclusive_tree_) { | 1628 if (inclusive_tree_) { |
1703 for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) { | 1629 for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) { |
1704 Function* inlined_function = (*inlined_functions)[i]; | 1630 Function* inlined_function = (*inlined_functions)[i]; |
1705 ASSERT(inlined_function != NULL); | 1631 ASSERT(inlined_function != NULL); |
1706 ASSERT(!inlined_function->IsNull()); | 1632 ASSERT(!inlined_function->IsNull()); |
1707 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; | 1633 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; |
1708 const bool inliner = i == (inlined_functions->length() - 1); | 1634 const bool inliner = i == (inlined_functions->length() - 1); |
1709 if (inliner) { | 1635 if (inliner) { |
1710 current = AppendKind(code, current); | 1636 current = AppendKind(code, current); |
1711 } | 1637 } |
1712 current = ProcessInlinedFunction(current, | 1638 current = ProcessInlinedFunction(current, sample_index, sample, |
1713 sample_index, | 1639 frame_index, inlined_function, |
1714 sample, | 1640 inlined_token_position, code_index); |
1715 frame_index, | |
1716 inlined_function, | |
1717 inlined_token_position, | |
1718 code_index); | |
1719 if (inliner) { | 1641 if (inliner) { |
1720 current = AppendKind(kInlineStart, current); | 1642 current = AppendKind(kInlineStart, current); |
1721 } | 1643 } |
1722 } | 1644 } |
1723 current = AppendKind(kInlineFinish, current); | 1645 current = AppendKind(kInlineFinish, current); |
1724 } else { | 1646 } else { |
1725 // Append the inlined children. | 1647 // Append the inlined children. |
1726 current = AppendKind(kInlineFinish, current); | 1648 current = AppendKind(kInlineFinish, current); |
1727 for (intptr_t i = 0; i < inlined_functions->length(); i++) { | 1649 for (intptr_t i = 0; i < inlined_functions->length(); i++) { |
1728 Function* inlined_function = (*inlined_functions)[i]; | 1650 Function* inlined_function = (*inlined_functions)[i]; |
1729 ASSERT(inlined_function != NULL); | 1651 ASSERT(inlined_function != NULL); |
1730 ASSERT(!inlined_function->IsNull()); | 1652 ASSERT(!inlined_function->IsNull()); |
1731 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; | 1653 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; |
1732 const bool inliner = i == (inlined_functions->length() - 1); | 1654 const bool inliner = i == (inlined_functions->length() - 1); |
1733 if (inliner) { | 1655 if (inliner) { |
1734 current = AppendKind(kInlineStart, current); | 1656 current = AppendKind(kInlineStart, current); |
1735 } | 1657 } |
1736 current = ProcessInlinedFunction(current, | 1658 current = ProcessInlinedFunction(current, sample_index, sample, |
1737 sample_index, | 1659 frame_index + i, inlined_function, |
1738 sample, | 1660 inlined_token_position, code_index); |
1739 frame_index + i, | |
1740 inlined_function, | |
1741 inlined_token_position, | |
1742 code_index); | |
1743 if (inliner) { | 1661 if (inliner) { |
1744 current = AppendKind(code, current); | 1662 current = AppendKind(code, current); |
1745 } | 1663 } |
1746 } | 1664 } |
1747 } | 1665 } |
1748 | 1666 |
1749 return current; | 1667 return current; |
1750 } | 1668 } |
1751 | 1669 |
1752 ProfileFunctionTrieNode* ProcessInlinedFunction( | 1670 ProfileFunctionTrieNode* ProcessInlinedFunction( |
1753 ProfileFunctionTrieNode* current, | 1671 ProfileFunctionTrieNode* current, |
1754 intptr_t sample_index, | 1672 intptr_t sample_index, |
1755 ProcessedSample* sample, | 1673 ProcessedSample* sample, |
1756 intptr_t frame_index, | 1674 intptr_t frame_index, |
1757 Function* inlined_function, | 1675 Function* inlined_function, |
1758 TokenPosition inlined_token_position, | 1676 TokenPosition inlined_token_position, |
1759 intptr_t code_index) { | 1677 intptr_t code_index) { |
1760 ProfileFunctionTable* function_table = profile_->functions_; | 1678 ProfileFunctionTable* function_table = profile_->functions_; |
1761 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); | 1679 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); |
1762 ASSERT(function != NULL); | 1680 ASSERT(function != NULL); |
1763 return ProcessFunction(current, | 1681 return ProcessFunction(current, sample_index, sample, frame_index, function, |
1764 sample_index, | 1682 inlined_token_position, code_index); |
1765 sample, | |
1766 frame_index, | |
1767 function, | |
1768 inlined_token_position, | |
1769 code_index); | |
1770 } | 1683 } |
1771 | 1684 |
1772 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) { | 1685 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) { |
1773 if (frame_index != 0) { | 1686 if (frame_index != 0) { |
1774 return true; | 1687 return true; |
1775 } | 1688 } |
1776 // Only tick the first frame's node, if we are executing OR | 1689 // Only tick the first frame's node, if we are executing OR |
1777 // vm tags have been emitted. | 1690 // vm tags have been emitted. |
1778 return IsExecutingFrame(sample, frame_index) || | 1691 return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm || |
1779 !FLAG_profile_vm || vm_tags_emitted(); | 1692 vm_tags_emitted(); |
1780 } | 1693 } |
1781 | 1694 |
1782 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, | 1695 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, |
1783 intptr_t sample_index, | 1696 intptr_t sample_index, |
1784 ProcessedSample* sample, | 1697 ProcessedSample* sample, |
1785 intptr_t frame_index, | 1698 intptr_t frame_index, |
1786 ProfileFunction* function, | 1699 ProfileFunction* function, |
1787 TokenPosition token_position, | 1700 TokenPosition token_position, |
1788 intptr_t code_index) { | 1701 intptr_t code_index) { |
1789 if (!function->is_visible()) { | 1702 if (!function->is_visible()) { |
1790 return current; | 1703 return current; |
1791 } | 1704 } |
1792 if (tick_functions_) { | 1705 if (tick_functions_) { |
1793 if (FLAG_trace_profiler_verbose) { | 1706 if (FLAG_trace_profiler_verbose) { |
1794 THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", | 1707 THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", sample_index, |
1795 sample_index, | 1708 frame_index, function->Name(), token_position.ToCString(), |
1796 frame_index, | |
1797 function->Name(), | |
1798 token_position.ToCString(), | |
1799 sample->At(frame_index)); | 1709 sample->At(frame_index)); |
1800 } | 1710 } |
1801 function->Tick(IsExecutingFrame(sample, frame_index), | 1711 function->Tick(IsExecutingFrame(sample, frame_index), sample_index, |
1802 sample_index, | |
1803 token_position); | 1712 token_position); |
1804 } | 1713 } |
1805 function->AddProfileCode(code_index); | 1714 function->AddProfileCode(code_index); |
1806 current = current->GetChild(function->table_index()); | 1715 current = current->GetChild(function->table_index()); |
1807 if (ShouldTickNode(sample, frame_index)) { | 1716 if (ShouldTickNode(sample, frame_index)) { |
1808 current->Tick(); | 1717 current->Tick(); |
1809 } | 1718 } |
1810 current->AddCodeObjectIndex(code_index); | 1719 current->AddCodeObjectIndex(code_index); |
1811 return current; | 1720 return current; |
1812 } | 1721 } |
(...skipping 27 matching lines...) Expand all Loading... |
1840 | 1749 |
1841 ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current) { | 1750 ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current) { |
1842 intptr_t truncated_tag_index = | 1751 intptr_t truncated_tag_index = |
1843 GetProfileCodeTagIndex(VMTag::kTruncatedTagId); | 1752 GetProfileCodeTagIndex(VMTag::kTruncatedTagId); |
1844 ASSERT(truncated_tag_index >= 0); | 1753 ASSERT(truncated_tag_index >= 0); |
1845 current = current->GetChild(truncated_tag_index); | 1754 current = current->GetChild(truncated_tag_index); |
1846 current->Tick(); | 1755 current->Tick(); |
1847 return current; | 1756 return current; |
1848 } | 1757 } |
1849 | 1758 |
1850 ProfileCodeTrieNode* AppendVMTag(uword vm_tag, | 1759 ProfileCodeTrieNode* AppendVMTag(uword vm_tag, ProfileCodeTrieNode* current) { |
1851 ProfileCodeTrieNode* current) { | |
1852 if (VMTag::IsNativeEntryTag(vm_tag)) { | 1760 if (VMTag::IsNativeEntryTag(vm_tag)) { |
1853 // Insert a dummy kNativeTagId node. | 1761 // Insert a dummy kNativeTagId node. |
1854 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId); | 1762 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId); |
1855 current = current->GetChild(tag_index); | 1763 current = current->GetChild(tag_index); |
1856 // Give the tag a tick. | 1764 // Give the tag a tick. |
1857 current->Tick(); | 1765 current->Tick(); |
1858 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) { | 1766 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) { |
1859 // Insert a dummy kRuntimeTagId node. | 1767 // Insert a dummy kRuntimeTagId node. |
1860 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId); | 1768 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId); |
1861 current = current->GetChild(tag_index); | 1769 current = current->GetChild(tag_index); |
1862 // Give the tag a tick. | 1770 // Give the tag a tick. |
1863 current->Tick(); | 1771 current->Tick(); |
1864 } else { | 1772 } else { |
1865 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); | 1773 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); |
1866 current = current->GetChild(tag_index); | 1774 current = current->GetChild(tag_index); |
1867 // Give the tag a tick. | 1775 // Give the tag a tick. |
1868 current->Tick(); | 1776 current->Tick(); |
1869 } | 1777 } |
1870 return current; | 1778 return current; |
1871 } | 1779 } |
1872 | 1780 |
1873 ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag( | 1781 ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag( |
1874 uword vm_tag, ProfileCodeTrieNode* current) { | 1782 uword vm_tag, |
| 1783 ProfileCodeTrieNode* current) { |
1875 // Only Native and Runtime entries have a second VM tag. | 1784 // Only Native and Runtime entries have a second VM tag. |
1876 if (!VMTag::IsNativeEntryTag(vm_tag) && | 1785 if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) { |
1877 !VMTag::IsRuntimeEntryTag(vm_tag)) { | |
1878 return current; | 1786 return current; |
1879 } | 1787 } |
1880 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); | 1788 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); |
1881 current = current->GetChild(tag_index); | 1789 current = current->GetChild(tag_index); |
1882 // Give the tag a tick. | 1790 // Give the tag a tick. |
1883 current->Tick(); | 1791 current->Tick(); |
1884 return current; | 1792 return current; |
1885 } | 1793 } |
1886 | 1794 |
1887 uword ProfileInfoKindToVMTag(ProfileInfoKind kind) { | 1795 uword ProfileInfoKindToVMTag(ProfileInfoKind kind) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1969 ProfileCodeTrieNode* AppendExitFrame(uword vm_tag, | 1877 ProfileCodeTrieNode* AppendExitFrame(uword vm_tag, |
1970 ProfileCodeTrieNode* current) { | 1878 ProfileCodeTrieNode* current) { |
1971 if (FLAG_profile_vm) { | 1879 if (FLAG_profile_vm) { |
1972 return current; | 1880 return current; |
1973 } | 1881 } |
1974 | 1882 |
1975 if (!VMTag::IsExitFrameTag(vm_tag)) { | 1883 if (!VMTag::IsExitFrameTag(vm_tag)) { |
1976 return current; | 1884 return current; |
1977 } | 1885 } |
1978 | 1886 |
1979 if (VMTag::IsNativeEntryTag(vm_tag) || | 1887 if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) { |
1980 VMTag::IsRuntimeEntryTag(vm_tag)) { | |
1981 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); | 1888 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); |
1982 } else { | 1889 } else { |
1983 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); | 1890 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag); |
1984 current = current->GetChild(tag_index); | 1891 current = current->GetChild(tag_index); |
1985 // Give the tag a tick. | 1892 // Give the tag a tick. |
1986 current->Tick(); | 1893 current->Tick(); |
1987 } | 1894 } |
1988 return current; | 1895 return current; |
1989 } | 1896 } |
1990 | 1897 |
(...skipping 27 matching lines...) Expand all Loading... |
2018 } | 1925 } |
2019 | 1926 |
2020 if (tag_order() == Profile::kNoTags) { | 1927 if (tag_order() == Profile::kNoTags) { |
2021 return current; | 1928 return current; |
2022 } | 1929 } |
2023 | 1930 |
2024 return AppendUserTag(user_tag, current); | 1931 return AppendUserTag(user_tag, current); |
2025 } | 1932 } |
2026 | 1933 |
2027 // ProfileFunctionTrieNode | 1934 // ProfileFunctionTrieNode |
2028 void ResetKind() { | 1935 void ResetKind() { info_kind_ = kNone; } |
2029 info_kind_ = kNone; | |
2030 } | |
2031 | 1936 |
2032 ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind, | 1937 ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind, |
2033 ProfileFunctionTrieNode* current) { | 1938 ProfileFunctionTrieNode* current) { |
2034 if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) { | 1939 if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) { |
2035 // Only emit if debug tags are requested. | 1940 // Only emit if debug tags are requested. |
2036 return current; | 1941 return current; |
2037 } | 1942 } |
2038 if (kind != info_kind_) { | 1943 if (kind != info_kind_) { |
2039 info_kind_ = kind; | 1944 info_kind_ = kind; |
2040 intptr_t tag_index = | 1945 intptr_t tag_index = |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2094 } else { | 1999 } else { |
2095 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); | 2000 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); |
2096 current = current->GetChild(tag_index); | 2001 current = current->GetChild(tag_index); |
2097 // Give the tag a tick. | 2002 // Give the tag a tick. |
2098 current->Tick(); | 2003 current->Tick(); |
2099 } | 2004 } |
2100 return current; | 2005 return current; |
2101 } | 2006 } |
2102 | 2007 |
2103 ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag( | 2008 ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag( |
2104 uword vm_tag, ProfileFunctionTrieNode* current) { | 2009 uword vm_tag, |
| 2010 ProfileFunctionTrieNode* current) { |
2105 // Only Native and Runtime entries have a second VM tag. | 2011 // Only Native and Runtime entries have a second VM tag. |
2106 if (!VMTag::IsNativeEntryTag(vm_tag) && | 2012 if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) { |
2107 !VMTag::IsRuntimeEntryTag(vm_tag)) { | |
2108 return current; | 2013 return current; |
2109 } | 2014 } |
2110 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); | 2015 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); |
2111 current = current->GetChild(tag_index); | 2016 current = current->GetChild(tag_index); |
2112 // Give the tag a tick. | 2017 // Give the tag a tick. |
2113 current->Tick(); | 2018 current->Tick(); |
2114 return current; | 2019 return current; |
2115 } | 2020 } |
2116 | 2021 |
2117 ProfileFunctionTrieNode* AppendVMTags(uword vm_tag, | 2022 ProfileFunctionTrieNode* AppendVMTags(uword vm_tag, |
2118 ProfileFunctionTrieNode* current) { | 2023 ProfileFunctionTrieNode* current) { |
2119 current = AppendVMTag(vm_tag, current); | 2024 current = AppendVMTag(vm_tag, current); |
2120 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); | 2025 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); |
2121 return current; | 2026 return current; |
2122 } | 2027 } |
2123 | 2028 |
2124 ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag, | 2029 ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag, |
2125 ProfileFunctionTrieNode* current) { | 2030 ProfileFunctionTrieNode* current) { |
2126 if (FLAG_profile_vm) { | 2031 if (FLAG_profile_vm) { |
2127 return current; | 2032 return current; |
2128 } | 2033 } |
2129 | 2034 |
2130 if (!VMTag::IsExitFrameTag(vm_tag)) { | 2035 if (!VMTag::IsExitFrameTag(vm_tag)) { |
2131 return current; | 2036 return current; |
2132 } | 2037 } |
2133 if (VMTag::IsNativeEntryTag(vm_tag) || | 2038 if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) { |
2134 VMTag::IsRuntimeEntryTag(vm_tag)) { | |
2135 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); | 2039 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current); |
2136 } else { | 2040 } else { |
2137 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); | 2041 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag); |
2138 current = current->GetChild(tag_index); | 2042 current = current->GetChild(tag_index); |
2139 // Give the tag a tick. | 2043 // Give the tag a tick. |
2140 current->Tick(); | 2044 current->Tick(); |
2141 } | 2045 } |
2142 return current; | 2046 return current; |
2143 } | 2047 } |
2144 | 2048 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2233 if (tag == 0) { | 2137 if (tag == 0) { |
2234 // No tag. | 2138 // No tag. |
2235 return; | 2139 return; |
2236 } | 2140 } |
2237 ProfileCodeTable* tag_table = profile_->tag_code_; | 2141 ProfileCodeTable* tag_table = profile_->tag_code_; |
2238 intptr_t index = tag_table->FindCodeIndexForPC(tag); | 2142 intptr_t index = tag_table->FindCodeIndexForPC(tag); |
2239 if (index >= 0) { | 2143 if (index >= 0) { |
2240 // Already created. | 2144 // Already created. |
2241 return; | 2145 return; |
2242 } | 2146 } |
2243 ProfileCode* code = new ProfileCode(ProfileCode::kTagCode, | 2147 ProfileCode* code = |
2244 tag, | 2148 new ProfileCode(ProfileCode::kTagCode, tag, tag + 1, 0, null_code_); |
2245 tag + 1, | |
2246 0, | |
2247 null_code_); | |
2248 index = tag_table->InsertCode(code); | 2149 index = tag_table->InsertCode(code); |
2249 ASSERT(index >= 0); | 2150 ASSERT(index >= 0); |
2250 } | 2151 } |
2251 | 2152 |
2252 ProfileCode* CreateProfileCodeReused(uword pc) { | 2153 ProfileCode* CreateProfileCodeReused(uword pc) { |
2253 ProfileCode* code = new ProfileCode(ProfileCode::kReusedCode, | 2154 ProfileCode* code = |
2254 pc, | 2155 new ProfileCode(ProfileCode::kReusedCode, pc, pc + 1, 0, null_code_); |
2255 pc + 1, | |
2256 0, | |
2257 null_code_); | |
2258 return code; | 2156 return code; |
2259 } | 2157 } |
2260 | 2158 |
2261 bool IsPCInDartHeap(uword pc) { | 2159 bool IsPCInDartHeap(uword pc) { |
2262 return vm_isolate_->heap()->CodeContains(pc) || | 2160 return vm_isolate_->heap()->CodeContains(pc) || |
2263 thread_->isolate()->heap()->CodeContains(pc); | 2161 thread_->isolate()->heap()->CodeContains(pc); |
2264 } | 2162 } |
2265 | 2163 |
2266 | 2164 |
2267 ProfileCode* FindOrRegisterNativeProfileCode(uword pc) { | 2165 ProfileCode* FindOrRegisterNativeProfileCode(uword pc) { |
2268 // Check if |pc| is already known in the live code table. | 2166 // Check if |pc| is already known in the live code table. |
2269 ProfileCodeTable* live_table = profile_->live_code_; | 2167 ProfileCodeTable* live_table = profile_->live_code_; |
2270 ProfileCode* profile_code = live_table->FindCodeForPC(pc); | 2168 ProfileCode* profile_code = live_table->FindCodeForPC(pc); |
2271 if (profile_code != NULL) { | 2169 if (profile_code != NULL) { |
2272 return profile_code; | 2170 return profile_code; |
2273 } | 2171 } |
2274 | 2172 |
2275 // We haven't seen this pc yet. | 2173 // We haven't seen this pc yet. |
2276 Code& code = Code::Handle(thread_->zone()); | 2174 Code& code = Code::Handle(thread_->zone()); |
2277 | 2175 |
2278 // Check NativeSymbolResolver for pc. | 2176 // Check NativeSymbolResolver for pc. |
2279 uintptr_t native_start = 0; | 2177 uintptr_t native_start = 0; |
2280 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, | 2178 char* native_name = |
2281 &native_start); | 2179 NativeSymbolResolver::LookupSymbolName(pc, &native_start); |
2282 if (native_name == NULL) { | 2180 if (native_name == NULL) { |
2283 // Failed to find a native symbol for pc. | 2181 // Failed to find a native symbol for pc. |
2284 native_start = pc; | 2182 native_start = pc; |
2285 } | 2183 } |
2286 | 2184 |
2287 #if defined(HOST_ARCH_ARM) | 2185 #if defined(HOST_ARCH_ARM) |
2288 // The symbol for a Thumb function will be xxx1, but we may have samples | 2186 // The symbol for a Thumb function will be xxx1, but we may have samples |
2289 // at function entry which will have pc xxx0. | 2187 // at function entry which will have pc xxx0. |
2290 native_start &= ~1; | 2188 native_start &= ~1; |
2291 #endif | 2189 #endif |
2292 | 2190 |
2293 ASSERT(pc >= native_start); | 2191 ASSERT(pc >= native_start); |
2294 profile_code = new ProfileCode(ProfileCode::kNativeCode, | 2192 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, |
2295 native_start, | 2193 pc + 1, 0, code); |
2296 pc + 1, | |
2297 0, | |
2298 code); | |
2299 if (native_name != NULL) { | 2194 if (native_name != NULL) { |
2300 profile_code->SetName(native_name); | 2195 profile_code->SetName(native_name); |
2301 NativeSymbolResolver::FreeSymbolName(native_name); | 2196 NativeSymbolResolver::FreeSymbolName(native_name); |
2302 } | 2197 } |
2303 | 2198 |
2304 RegisterLiveProfileCode(profile_code); | 2199 RegisterLiveProfileCode(profile_code); |
2305 return profile_code; | 2200 return profile_code; |
2306 } | 2201 } |
2307 | 2202 |
2308 void RegisterLiveProfileCode(ProfileCode* code) { | 2203 void RegisterLiveProfileCode(ProfileCode* code) { |
(...skipping 24 matching lines...) Expand all Loading... |
2333 return code; | 2228 return code; |
2334 } | 2229 } |
2335 if ((code == NULL) && !IsPCInDartHeap(pc)) { | 2230 if ((code == NULL) && !IsPCInDartHeap(pc)) { |
2336 // Not a PC from Dart code. Check with native code. | 2231 // Not a PC from Dart code. Check with native code. |
2337 return FindOrRegisterNativeProfileCode(pc); | 2232 return FindOrRegisterNativeProfileCode(pc); |
2338 } | 2233 } |
2339 // We either didn't find the code or it was compiled after the sample. | 2234 // We either didn't find the code or it was compiled after the sample. |
2340 return FindOrRegisterDeadProfileCode(pc); | 2235 return FindOrRegisterDeadProfileCode(pc); |
2341 } | 2236 } |
2342 | 2237 |
2343 Profile::TagOrder tag_order() const { | 2238 Profile::TagOrder tag_order() const { return tag_order_; } |
2344 return tag_order_; | |
2345 } | |
2346 | 2239 |
2347 bool vm_tags_emitted() const { | 2240 bool vm_tags_emitted() const { |
2348 return (tag_order_ == Profile::kUserVM) || | 2241 return (tag_order_ == Profile::kUserVM) || |
2349 (tag_order_ == Profile::kVMUser) || | 2242 (tag_order_ == Profile::kVMUser) || (tag_order_ == Profile::kVM); |
2350 (tag_order_ == Profile::kVM); | |
2351 } | 2243 } |
2352 | 2244 |
2353 bool TagsEnabled(intptr_t extra_tags_bits) const { | 2245 bool TagsEnabled(intptr_t extra_tags_bits) const { |
2354 return (extra_tags_ & extra_tags_bits) != 0; | 2246 return (extra_tags_ & extra_tags_bits) != 0; |
2355 } | 2247 } |
2356 | 2248 |
2357 Thread* thread_; | 2249 Thread* thread_; |
2358 Isolate* vm_isolate_; | 2250 Isolate* vm_isolate_; |
2359 SampleFilter* filter_; | 2251 SampleFilter* filter_; |
2360 Profile::TagOrder tag_order_; | 2252 Profile::TagOrder tag_order_; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2434 return tag_code_->At(index); | 2326 return tag_code_->At(index); |
2435 } | 2327 } |
2436 | 2328 |
2437 | 2329 |
2438 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { | 2330 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) { |
2439 return roots_[static_cast<intptr_t>(trie_kind)]; | 2331 return roots_[static_cast<intptr_t>(trie_kind)]; |
2440 } | 2332 } |
2441 | 2333 |
2442 | 2334 |
2443 void Profile::PrintHeaderJSON(JSONObject* obj) { | 2335 void Profile::PrintHeaderJSON(JSONObject* obj) { |
2444 obj->AddProperty("samplePeriod", | 2336 obj->AddProperty("samplePeriod", static_cast<intptr_t>(FLAG_profile_period)); |
2445 static_cast<intptr_t>(FLAG_profile_period)); | 2337 obj->AddProperty("stackDepth", static_cast<intptr_t>(FLAG_max_profile_depth)); |
2446 obj->AddProperty("stackDepth", | |
2447 static_cast<intptr_t>(FLAG_max_profile_depth)); | |
2448 obj->AddProperty("sampleCount", sample_count()); | 2338 obj->AddProperty("sampleCount", sample_count()); |
2449 obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); | 2339 obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan())); |
2450 obj->AddPropertyTimeMicros("timeOriginMicros", min_time()); | 2340 obj->AddPropertyTimeMicros("timeOriginMicros", min_time()); |
2451 obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan()); | 2341 obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan()); |
2452 | 2342 |
2453 ProfilerCounters counters = Profiler::counters(); | 2343 ProfilerCounters counters = Profiler::counters(); |
2454 { | 2344 { |
2455 JSONObject counts(obj, "counters"); | 2345 JSONObject counts(obj, "counters"); |
2456 counts.AddProperty64( | 2346 counts.AddProperty64("bail_out_unknown_task", |
2457 "bail_out_unknown_task", | 2347 counters.bail_out_unknown_task); |
2458 counters.bail_out_unknown_task); | 2348 counts.AddProperty64("bail_out_jump_to_exception_handler", |
2459 counts.AddProperty64( | 2349 counters.bail_out_jump_to_exception_handler); |
2460 "bail_out_jump_to_exception_handler", | 2350 counts.AddProperty64("bail_out_check_isolate", |
2461 counters.bail_out_jump_to_exception_handler); | 2351 counters.bail_out_check_isolate); |
2462 counts.AddProperty64( | 2352 counts.AddProperty64("single_frame_sample_deoptimizing", |
2463 "bail_out_check_isolate", | 2353 counters.single_frame_sample_deoptimizing); |
2464 counters.bail_out_check_isolate); | 2354 counts.AddProperty64("single_frame_sample_register_check", |
2465 counts.AddProperty64( | 2355 counters.single_frame_sample_register_check); |
2466 "single_frame_sample_deoptimizing", | |
2467 counters.single_frame_sample_deoptimizing); | |
2468 counts.AddProperty64( | |
2469 "single_frame_sample_register_check", | |
2470 counters.single_frame_sample_register_check); | |
2471 counts.AddProperty64( | 2356 counts.AddProperty64( |
2472 "single_frame_sample_get_and_validate_stack_bounds", | 2357 "single_frame_sample_get_and_validate_stack_bounds", |
2473 counters.single_frame_sample_get_and_validate_stack_bounds); | 2358 counters.single_frame_sample_get_and_validate_stack_bounds); |
2474 counts.AddProperty64( | 2359 counts.AddProperty64("stack_walker_native", counters.stack_walker_native); |
2475 "stack_walker_native", | 2360 counts.AddProperty64("stack_walker_dart_exit", |
2476 counters.stack_walker_native); | 2361 counters.stack_walker_dart_exit); |
2477 counts.AddProperty64( | 2362 counts.AddProperty64("stack_walker_dart", counters.stack_walker_dart); |
2478 "stack_walker_dart_exit", | 2363 counts.AddProperty64("stack_walker_none", counters.stack_walker_none); |
2479 counters.stack_walker_dart_exit); | |
2480 counts.AddProperty64( | |
2481 "stack_walker_dart", | |
2482 counters.stack_walker_dart); | |
2483 counts.AddProperty64( | |
2484 "stack_walker_none", | |
2485 counters.stack_walker_none); | |
2486 } | 2364 } |
2487 } | 2365 } |
2488 | 2366 |
2489 | 2367 |
2490 void Profile::PrintTimelineFrameJSON(JSONObject* frames, | 2368 void Profile::PrintTimelineFrameJSON(JSONObject* frames, |
2491 ProfileTrieNode* current, | 2369 ProfileTrieNode* current, |
2492 ProfileTrieNode* parent, | 2370 ProfileTrieNode* parent, |
2493 intptr_t* next_id) { | 2371 intptr_t* next_id) { |
2494 ASSERT(current->frame_id() == -1); | 2372 ASSERT(current->frame_id() == -1); |
2495 const intptr_t id = *next_id; | 2373 const intptr_t id = *next_id; |
2496 *next_id = id + 1; | 2374 *next_id = id + 1; |
2497 current->set_frame_id(id); | 2375 current->set_frame_id(id); |
2498 ASSERT(current->frame_id() != -1); | 2376 ASSERT(current->frame_id() != -1); |
2499 | 2377 |
2500 { | 2378 { |
2501 // The samples from many isolates may be merged into a single timeline, | 2379 // The samples from many isolates may be merged into a single timeline, |
2502 // so prefix frames id with the isolate. | 2380 // so prefix frames id with the isolate. |
2503 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); | 2381 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
2504 const char* key = zone_->PrintToString("%" Pd "-%" Pd, | 2382 const char* key = |
2505 isolate_id, current->frame_id()); | 2383 zone_->PrintToString("%" Pd "-%" Pd, isolate_id, current->frame_id()); |
2506 JSONObject frame(frames, key); | 2384 JSONObject frame(frames, key); |
2507 frame.AddProperty("category", "Dart"); | 2385 frame.AddProperty("category", "Dart"); |
2508 ProfileFunction* func = GetFunction(current->table_index()); | 2386 ProfileFunction* func = GetFunction(current->table_index()); |
2509 frame.AddProperty("name", func->Name()); | 2387 frame.AddProperty("name", func->Name()); |
2510 if (parent != NULL) { | 2388 if (parent != NULL) { |
2511 ASSERT(parent->frame_id() != -1); | 2389 ASSERT(parent->frame_id() != -1); |
2512 frame.AddPropertyF("parent", "%" Pd "-%" Pd, | 2390 frame.AddPropertyF("parent", "%" Pd "-%" Pd, isolate_id, |
2513 isolate_id, parent->frame_id()); | 2391 parent->frame_id()); |
2514 } | 2392 } |
2515 } | 2393 } |
2516 | 2394 |
2517 for (intptr_t i = 0; i < current->NumChildren(); i++) { | 2395 for (intptr_t i = 0; i < current->NumChildren(); i++) { |
2518 ProfileTrieNode* child = current->At(i); | 2396 ProfileTrieNode* child = current->At(i); |
2519 PrintTimelineFrameJSON(frames, child, current, next_id); | 2397 PrintTimelineFrameJSON(frames, child, current, next_id); |
2520 } | 2398 } |
2521 } | 2399 } |
2522 | 2400 |
2523 | 2401 |
2524 void Profile::PrintTimelineJSON(JSONStream* stream) { | 2402 void Profile::PrintTimelineJSON(JSONStream* stream) { |
2525 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); | 2403 ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler); |
2526 JSONObject obj(stream); | 2404 JSONObject obj(stream); |
2527 obj.AddProperty("type", "_CpuProfileTimeline"); | 2405 obj.AddProperty("type", "_CpuProfileTimeline"); |
2528 PrintHeaderJSON(&obj); | 2406 PrintHeaderJSON(&obj); |
2529 { | 2407 { |
2530 JSONObject frames(&obj, "stackFrames"); | 2408 JSONObject frames(&obj, "stackFrames"); |
2531 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); | 2409 ProfileTrieNode* root = GetTrieRoot(kInclusiveFunction); |
2532 intptr_t next_id = 0; | 2410 intptr_t next_id = 0; |
2533 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); | 2411 PrintTimelineFrameJSON(&frames, root, NULL, &next_id); |
2534 } | 2412 } |
2535 { | 2413 { |
2536 JSONArray events(&obj, "traceEvents"); | 2414 JSONArray events(&obj, "traceEvents"); |
2537 intptr_t pid = OS::ProcessId(); | 2415 intptr_t pid = OS::ProcessId(); |
2538 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); | 2416 intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_); |
2539 for (intptr_t sample_index = 0; | 2417 for (intptr_t sample_index = 0; sample_index < samples_->length(); |
2540 sample_index < samples_->length(); | |
2541 sample_index++) { | 2418 sample_index++) { |
2542 ProcessedSample* sample = samples_->At(sample_index); | 2419 ProcessedSample* sample = samples_->At(sample_index); |
2543 JSONObject event(&events); | 2420 JSONObject event(&events); |
2544 event.AddProperty("ph", "P"); // kind = sample event | 2421 event.AddProperty("ph", "P"); // kind = sample event |
2545 event.AddProperty64("pid", pid); | 2422 event.AddProperty64("pid", pid); |
2546 event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid())); | 2423 event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid())); |
2547 event.AddPropertyTimeMicros("ts", sample->timestamp()); | 2424 event.AddPropertyTimeMicros("ts", sample->timestamp()); |
2548 event.AddProperty("cat", "Dart"); | 2425 event.AddProperty("cat", "Dart"); |
2549 | 2426 |
2550 ProfileTrieNode* trie = sample->timeline_trie(); | 2427 ProfileTrieNode* trie = sample->timeline_trie(); |
2551 ASSERT(trie->frame_id() != -1); | 2428 ASSERT(trie->frame_id() != -1); |
2552 event.AddPropertyF("sf", "%" Pd "-%" Pd, | 2429 event.AddPropertyF("sf", "%" Pd "-%" Pd, isolate_id, trie->frame_id()); |
2553 isolate_id, trie->frame_id()); | |
2554 } | 2430 } |
2555 } | 2431 } |
2556 } | 2432 } |
2557 | 2433 |
2558 | 2434 |
2559 ProfileFunction* Profile::FindFunction(const Function& function) { | 2435 ProfileFunction* Profile::FindFunction(const Function& function) { |
2560 return (functions_ != NULL) ? functions_->Lookup(function) : NULL; | 2436 return (functions_ != NULL) ? functions_->Lookup(function) : NULL; |
2561 } | 2437 } |
2562 | 2438 |
2563 | 2439 |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2794 | 2670 |
2795 class NoAllocationSampleFilter : public SampleFilter { | 2671 class NoAllocationSampleFilter : public SampleFilter { |
2796 public: | 2672 public: |
2797 NoAllocationSampleFilter(Isolate* isolate, | 2673 NoAllocationSampleFilter(Isolate* isolate, |
2798 intptr_t thread_task_mask, | 2674 intptr_t thread_task_mask, |
2799 int64_t time_origin_micros, | 2675 int64_t time_origin_micros, |
2800 int64_t time_extent_micros) | 2676 int64_t time_extent_micros) |
2801 : SampleFilter(isolate, | 2677 : SampleFilter(isolate, |
2802 thread_task_mask, | 2678 thread_task_mask, |
2803 time_origin_micros, | 2679 time_origin_micros, |
2804 time_extent_micros) { | 2680 time_extent_micros) {} |
2805 } | |
2806 | 2681 |
2807 bool FilterSample(Sample* sample) { | 2682 bool FilterSample(Sample* sample) { return !sample->is_allocation_sample(); } |
2808 return !sample->is_allocation_sample(); | |
2809 } | |
2810 }; | 2683 }; |
2811 | 2684 |
2812 | 2685 |
2813 void ProfilerService::PrintJSON(JSONStream* stream, | 2686 void ProfilerService::PrintJSON(JSONStream* stream, |
2814 Profile::TagOrder tag_order, | 2687 Profile::TagOrder tag_order, |
2815 intptr_t extra_tags, | 2688 intptr_t extra_tags, |
2816 int64_t time_origin_micros, | 2689 int64_t time_origin_micros, |
2817 int64_t time_extent_micros) { | 2690 int64_t time_extent_micros) { |
2818 Thread* thread = Thread::Current(); | 2691 Thread* thread = Thread::Current(); |
2819 Isolate* isolate = thread->isolate(); | 2692 Isolate* isolate = thread->isolate(); |
2820 NoAllocationSampleFilter filter(isolate, | 2693 NoAllocationSampleFilter filter(isolate, Thread::kMutatorTask, |
2821 Thread::kMutatorTask, | 2694 time_origin_micros, time_extent_micros); |
2822 time_origin_micros, | |
2823 time_extent_micros); | |
2824 const bool as_timeline = false; | 2695 const bool as_timeline = false; |
2825 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline); | 2696 PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline); |
2826 } | 2697 } |
2827 | 2698 |
2828 | 2699 |
2829 class ClassAllocationSampleFilter : public SampleFilter { | 2700 class ClassAllocationSampleFilter : public SampleFilter { |
2830 public: | 2701 public: |
2831 ClassAllocationSampleFilter(Isolate* isolate, | 2702 ClassAllocationSampleFilter(Isolate* isolate, |
2832 const Class& cls, | 2703 const Class& cls, |
2833 intptr_t thread_task_mask, | 2704 intptr_t thread_task_mask, |
(...skipping 17 matching lines...) Expand all Loading... |
2851 }; | 2722 }; |
2852 | 2723 |
2853 | 2724 |
2854 void ProfilerService::PrintAllocationJSON(JSONStream* stream, | 2725 void ProfilerService::PrintAllocationJSON(JSONStream* stream, |
2855 Profile::TagOrder tag_order, | 2726 Profile::TagOrder tag_order, |
2856 const Class& cls, | 2727 const Class& cls, |
2857 int64_t time_origin_micros, | 2728 int64_t time_origin_micros, |
2858 int64_t time_extent_micros) { | 2729 int64_t time_extent_micros) { |
2859 Thread* thread = Thread::Current(); | 2730 Thread* thread = Thread::Current(); |
2860 Isolate* isolate = thread->isolate(); | 2731 Isolate* isolate = thread->isolate(); |
2861 ClassAllocationSampleFilter filter(isolate, | 2732 ClassAllocationSampleFilter filter(isolate, cls, Thread::kMutatorTask, |
2862 cls, | 2733 time_origin_micros, time_extent_micros); |
2863 Thread::kMutatorTask, | |
2864 time_origin_micros, | |
2865 time_extent_micros); | |
2866 const bool as_timeline = false; | 2734 const bool as_timeline = false; |
2867 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); | 2735 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
2868 } | 2736 } |
2869 | 2737 |
2870 | 2738 |
2871 void ProfilerService::PrintTimelineJSON(JSONStream* stream, | 2739 void ProfilerService::PrintTimelineJSON(JSONStream* stream, |
2872 Profile::TagOrder tag_order, | 2740 Profile::TagOrder tag_order, |
2873 int64_t time_origin_micros, | 2741 int64_t time_origin_micros, |
2874 int64_t time_extent_micros) { | 2742 int64_t time_extent_micros) { |
2875 Thread* thread = Thread::Current(); | 2743 Thread* thread = Thread::Current(); |
2876 Isolate* isolate = thread->isolate(); | 2744 Isolate* isolate = thread->isolate(); |
2877 const intptr_t thread_task_mask = Thread::kMutatorTask | | 2745 const intptr_t thread_task_mask = Thread::kMutatorTask | |
2878 Thread::kCompilerTask | | 2746 Thread::kCompilerTask | |
2879 Thread::kSweeperTask | | 2747 Thread::kSweeperTask | Thread::kMarkerTask; |
2880 Thread::kMarkerTask; | 2748 NoAllocationSampleFilter filter(isolate, thread_task_mask, time_origin_micros, |
2881 NoAllocationSampleFilter filter(isolate, | |
2882 thread_task_mask, | |
2883 time_origin_micros, | |
2884 time_extent_micros); | 2749 time_extent_micros); |
2885 const bool as_timeline = true; | 2750 const bool as_timeline = true; |
2886 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); | 2751 PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline); |
2887 } | 2752 } |
2888 | 2753 |
2889 | 2754 |
2890 void ProfilerService::ClearSamples() { | 2755 void ProfilerService::ClearSamples() { |
2891 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 2756 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
2892 if (sample_buffer == NULL) { | 2757 if (sample_buffer == NULL) { |
2893 return; | 2758 return; |
2894 } | 2759 } |
2895 | 2760 |
2896 Thread* thread = Thread::Current(); | 2761 Thread* thread = Thread::Current(); |
2897 Isolate* isolate = thread->isolate(); | 2762 Isolate* isolate = thread->isolate(); |
2898 | 2763 |
2899 // Disable thread interrupts while processing the buffer. | 2764 // Disable thread interrupts while processing the buffer. |
2900 DisableThreadInterruptsScope dtis(thread); | 2765 DisableThreadInterruptsScope dtis(thread); |
2901 | 2766 |
2902 ClearProfileVisitor clear_profile(isolate); | 2767 ClearProfileVisitor clear_profile(isolate); |
2903 sample_buffer->VisitSamples(&clear_profile); | 2768 sample_buffer->VisitSamples(&clear_profile); |
2904 } | 2769 } |
2905 | 2770 |
2906 #endif // !PRODUCT | 2771 #endif // !PRODUCT |
2907 | 2772 |
2908 } // namespace dart | 2773 } // namespace dart |
OLD | NEW |