| 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 |