| 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/malloc_hooks.h" | 10 #include "vm/malloc_hooks.h" |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 inclusive_ticks_(0), | 295 inclusive_ticks_(0), |
| 296 inclusive_serial_(-1), | 296 inclusive_serial_(-1), |
| 297 code_(code), | 297 code_(code), |
| 298 name_(NULL), | 298 name_(NULL), |
| 299 compile_timestamp_(0), | 299 compile_timestamp_(0), |
| 300 function_(NULL), | 300 function_(NULL), |
| 301 code_table_index_(-1), | 301 code_table_index_(-1), |
| 302 address_ticks_(0) {} | 302 address_ticks_(0) {} |
| 303 | 303 |
| 304 | 304 |
| 305 void ProfileCode::AdjustExtent(uword start, uword end) { | 305 void ProfileCode::TruncateLower(uword start) { |
| 306 if (start > start_) { |
| 307 start_ = start; |
| 308 } |
| 309 ASSERT(start_ < end_); |
| 310 } |
| 311 |
| 312 |
| 313 void ProfileCode::TruncateUpper(uword end) { |
| 314 if (end < end_) { |
| 315 end_ = end; |
| 316 } |
| 317 ASSERT(start_ < end_); |
| 318 } |
| 319 |
| 320 |
| 321 void ProfileCode::ExpandLower(uword start) { |
| 306 if (start < start_) { | 322 if (start < start_) { |
| 307 start_ = start; | 323 start_ = start; |
| 308 } | 324 } |
| 325 ASSERT(start_ < end_); |
| 326 } |
| 327 |
| 328 |
| 329 void ProfileCode::ExpandUpper(uword end) { |
| 309 if (end > end_) { | 330 if (end > end_) { |
| 310 end_ = end; | 331 end_ = end; |
| 311 } | 332 } |
| 312 ASSERT(start_ < end_); | 333 ASSERT(start_ < end_); |
| 313 } | 334 } |
| 314 | 335 |
| 315 | 336 |
| 316 bool ProfileCode::Overlaps(const ProfileCode* other) const { | 337 bool ProfileCode::Overlaps(const ProfileCode* other) const { |
| 317 ASSERT(other != NULL); | 338 ASSERT(other != NULL); |
| 318 return other->Contains(start_) || other->Contains(end_ - 1) || | 339 return other->Contains(start_) || other->Contains(end_ - 1) || |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 } | 709 } |
| 689 ASSERT(function != NULL); | 710 ASSERT(function != NULL); |
| 690 | 711 |
| 691 function->AddProfileCode(code_table_index()); | 712 function->AddProfileCode(code_table_index()); |
| 692 | 713 |
| 693 function_ = function; | 714 function_ = function; |
| 694 return function_; | 715 return function_; |
| 695 } | 716 } |
| 696 | 717 |
| 697 | 718 |
| 698 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); | 719 intptr_t ProfileCodeTable::FindCodeIndexForPC(uword pc) const { |
| 720 intptr_t length = table_.length(); |
| 721 if (length == 0) { |
| 722 return -1; // Not found. |
| 723 } |
| 724 intptr_t lo = 0; |
| 725 intptr_t hi = length - 1; |
| 726 while (lo <= hi) { |
| 727 intptr_t mid = (hi - lo + 1) / 2 + lo; |
| 728 ASSERT(mid >= lo); |
| 729 ASSERT(mid <= hi); |
| 730 ProfileCode* code = At(mid); |
| 731 if (code->Contains(pc)) { |
| 732 return mid; |
| 733 } else if (pc < code->start()) { |
| 734 hi = mid - 1; |
| 735 } else { |
| 736 lo = mid + 1; |
| 737 } |
| 738 } |
| 739 return -1; |
| 740 } |
| 699 | 741 |
| 700 class ProfileCodeTable : public ZoneAllocated { | |
| 701 public: | |
| 702 ProfileCodeTable() : table_(8) {} | |
| 703 | 742 |
| 704 intptr_t length() const { return table_.length(); } | 743 intptr_t ProfileCodeTable::InsertCode(ProfileCode* new_code) { |
| 705 | 744 const intptr_t length = table_.length(); |
| 706 ProfileCode* At(intptr_t index) const { | 745 if (length == 0) { |
| 707 ASSERT(index >= 0); | 746 table_.Add(new_code); |
| 708 ASSERT(index < length()); | 747 return length; |
| 709 return table_[index]; | |
| 710 } | 748 } |
| 711 | 749 |
| 712 // Find the table index to the ProfileCode containing pc. | 750 // Determine the correct place to insert or merge |new_code| into table. |
| 713 // Returns < 0 if not found. | 751 intptr_t lo = -1; |
| 714 intptr_t FindCodeIndexForPC(uword pc) const { | 752 intptr_t hi = -1; |
| 715 intptr_t index = FindCodeIndex(pc, &CompareLowerBound); | 753 ProfileCode* lo_code = NULL; |
| 716 if (index == length()) { | 754 ProfileCode* hi_code = NULL; |
| 717 // Not present. | 755 const uword pc = new_code->end() - 1; |
| 718 return -1; | 756 FindNeighbors(pc, &lo, &hi, &lo_code, &hi_code); |
| 719 } | 757 ASSERT((lo_code != NULL) || (hi_code != NULL)); |
| 720 const ProfileCode* code = At(index); | 758 |
| 721 if (!code->Contains(pc)) { | 759 if (lo != -1) { |
| 722 // Not present. | 760 // Has left neighbor. |
| 723 return -1; | 761 new_code->TruncateLower(lo_code->end()); |
| 724 } | 762 ASSERT(!new_code->Overlaps(lo_code)); |
| 725 // Found at index. | 763 } |
| 726 return index; | 764 if (hi != -1) { |
| 765 // Has right neighbor. |
| 766 new_code->TruncateUpper(hi_code->start()); |
| 767 ASSERT(!new_code->Overlaps(hi_code)); |
| 727 } | 768 } |
| 728 | 769 |
| 729 ProfileCode* FindCodeForPC(uword pc) const { | 770 if ((lo != -1) && (lo_code->kind() == ProfileCode::kNativeCode) && |
| 730 intptr_t index = FindCodeIndexForPC(pc); | 771 (new_code->kind() == ProfileCode::kNativeCode) && |
| 731 if (index < 0) { | 772 (lo_code->end() == new_code->start())) { |
| 732 return NULL; | 773 // Adjacent left neighbor of the same kind: merge. |
| 733 } | 774 // (dladdr doesn't give us symbol size so processing more samples may see |
| 734 return At(index); | 775 // more PCs we didn't previously know belonged to it.) |
| 776 lo_code->ExpandUpper(new_code->end()); |
| 777 return lo; |
| 735 } | 778 } |
| 736 | 779 |
| 737 // Insert |new_code| into the table. Returns the table index where |new_code| | 780 if ((hi != -1) && (hi_code->kind() == ProfileCode::kNativeCode) && |
| 738 // was inserted. Will merge with an overlapping ProfileCode if one is present. | 781 (new_code->kind() == ProfileCode::kNativeCode) && |
| 739 intptr_t InsertCode(ProfileCode* new_code) { | 782 (new_code->end() == hi_code->start())) { |
| 740 const uword start = new_code->start(); | 783 // Adjacent right neighbor of the same kind: merge. |
| 741 const uword end = new_code->end(); | 784 // (dladdr doesn't give us symbol size so processing more samples may see |
| 742 const intptr_t length = table_.length(); | 785 // more PCs we didn't previously know belonged to it.) |
| 743 if (length == 0) { | 786 hi_code->ExpandLower(new_code->start()); |
| 744 table_.Add(new_code); | 787 return hi; |
| 745 return length; | |
| 746 } | |
| 747 // Determine the correct place to insert or merge |new_code| into table. | |
| 748 intptr_t lo = FindCodeIndex(start, &CompareLowerBound); | |
| 749 intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound); | |
| 750 // TODO(johnmccutchan): Simplify below logic. | |
| 751 if ((lo == length) && (hi == length)) { | |
| 752 lo = length - 1; | |
| 753 } | |
| 754 if (lo == length) { | |
| 755 ProfileCode* code = At(hi); | |
| 756 if (code->Overlaps(new_code)) { | |
| 757 HandleOverlap(code, new_code, start, end); | |
| 758 return hi; | |
| 759 } | |
| 760 table_.Add(new_code); | |
| 761 return length; | |
| 762 } else if (hi == length) { | |
| 763 ProfileCode* code = At(lo); | |
| 764 if (code->Overlaps(new_code)) { | |
| 765 HandleOverlap(code, new_code, start, end); | |
| 766 return lo; | |
| 767 } | |
| 768 table_.Add(new_code); | |
| 769 return length; | |
| 770 } else if (lo == hi) { | |
| 771 ProfileCode* code = At(lo); | |
| 772 if (code->Overlaps(new_code)) { | |
| 773 HandleOverlap(code, new_code, start, end); | |
| 774 return lo; | |
| 775 } | |
| 776 table_.InsertAt(lo, new_code); | |
| 777 return lo; | |
| 778 } else { | |
| 779 ProfileCode* code = At(lo); | |
| 780 if (code->Overlaps(new_code)) { | |
| 781 HandleOverlap(code, new_code, start, end); | |
| 782 return lo; | |
| 783 } | |
| 784 code = At(hi); | |
| 785 if (code->Overlaps(new_code)) { | |
| 786 HandleOverlap(code, new_code, start, end); | |
| 787 return hi; | |
| 788 } | |
| 789 table_.InsertAt(hi, new_code); | |
| 790 return hi; | |
| 791 } | |
| 792 UNREACHABLE(); | |
| 793 return -1; | |
| 794 } | 788 } |
| 795 | 789 |
| 796 private: | 790 intptr_t insert; |
| 797 intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const { | 791 if (lo == -1) { |
| 798 ASSERT(comparator != NULL); | 792 insert = 0; |
| 799 intptr_t count = table_.length(); | 793 } else if (hi == -1) { |
| 800 intptr_t first = 0; | 794 insert = length; |
| 801 while (count > 0) { | 795 } else { |
| 802 intptr_t it = first; | 796 insert = lo + 1; |
| 803 intptr_t step = count / 2; | 797 } |
| 804 it += step; | 798 table_.InsertAt(insert, new_code); |
| 805 const ProfileCode* code = At(it); | 799 return insert; |
| 806 if (comparator(pc, code->start(), code->end())) { | 800 } |
| 807 first = ++it; | 801 |
| 808 count -= (step + 1); | 802 |
| 809 } else { | 803 void ProfileCodeTable::FindNeighbors(uword pc, |
| 810 count = step; | 804 intptr_t* lo, |
| 811 } | 805 intptr_t* hi, |
| 812 } | 806 ProfileCode** lo_code, |
| 813 return first; | 807 ProfileCode** hi_code) const { |
| 808 ASSERT(table_.length() >= 1); |
| 809 |
| 810 intptr_t length = table_.length(); |
| 811 |
| 812 if (pc < At(0)->start()) { |
| 813 // Lower than any existing code. |
| 814 *lo = -1; |
| 815 *lo_code = NULL; |
| 816 *hi = 0; |
| 817 *hi_code = At(*hi); |
| 818 return; |
| 814 } | 819 } |
| 815 | 820 |
| 816 static bool CompareUpperBound(uword pc, uword start, uword end) { | 821 if (pc >= At(length - 1)->end()) { |
| 817 return pc >= end; | 822 // Higher than any existing code. |
| 823 *lo = length - 1; |
| 824 *lo_code = At(*lo); |
| 825 *hi = -1; |
| 826 *hi_code = NULL; |
| 827 return; |
| 818 } | 828 } |
| 819 | 829 |
| 820 static bool CompareLowerBound(uword pc, uword start, uword end) { | 830 *lo = 0; |
| 821 return end <= pc; | 831 *lo_code = At(*lo); |
| 822 } | 832 *hi = length - 1; |
| 833 *hi_code = At(*hi); |
| 823 | 834 |
| 824 void HandleOverlap(ProfileCode* existing, | 835 while ((*hi - *lo) > 1) { |
| 825 ProfileCode* code, | 836 intptr_t mid = (*hi - *lo + 1) / 2 + *lo; |
| 826 uword start, | 837 ASSERT(*lo <= mid); |
| 827 uword end) { | 838 ASSERT(*hi >= mid); |
| 828 // We should never see overlapping Dart code regions. | 839 ProfileCode* code = At(mid); |
| 829 ASSERT(existing->kind() != ProfileCode::kDartCode); | 840 if (code->end() <= pc) { |
| 830 // We should never see overlapping Tag code regions. | 841 *lo = mid; |
| 831 ASSERT(existing->kind() != ProfileCode::kTagCode); | 842 *lo_code = code; |
| 832 // When code regions overlap, they should be of the same kind. | |
| 833 ASSERT(existing->kind() == code->kind()); | |
| 834 existing->AdjustExtent(start, end); | |
| 835 } | |
| 836 | |
| 837 void VerifyOrder() { | |
| 838 const intptr_t length = table_.length(); | |
| 839 if (length == 0) { | |
| 840 return; | |
| 841 } | 843 } |
| 842 uword last = table_[0]->end(); | 844 if (pc < code->end()) { |
| 843 for (intptr_t i = 1; i < length; i++) { | 845 *hi = mid; |
| 844 ProfileCode* a = table_[i]; | 846 *hi_code = code; |
| 845 ASSERT(last <= a->start()); | |
| 846 last = a->end(); | |
| 847 } | 847 } |
| 848 } | 848 } |
| 849 } |
| 849 | 850 |
| 850 void VerifyOverlap() { | 851 |
| 851 const intptr_t length = table_.length(); | 852 void ProfileCodeTable::VerifyOrder() { |
| 852 for (intptr_t i = 0; i < length; i++) { | 853 const intptr_t length = table_.length(); |
| 853 ProfileCode* a = table_[i]; | 854 if (length == 0) { |
| 854 for (intptr_t j = i + 1; j < length; j++) { | 855 return; |
| 855 ProfileCode* b = table_[j]; | 856 } |
| 856 ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && | 857 uword last = table_[0]->end(); |
| 857 !b->Contains(a->start()) && !b->Contains(a->end() - 1)); | 858 for (intptr_t i = 1; i < length; i++) { |
| 858 } | 859 ProfileCode* a = table_[i]; |
| 860 ASSERT(last <= a->start()); |
| 861 last = a->end(); |
| 862 } |
| 863 } |
| 864 |
| 865 void ProfileCodeTable::VerifyOverlap() { |
| 866 const intptr_t length = table_.length(); |
| 867 for (intptr_t i = 0; i < length; i++) { |
| 868 ProfileCode* a = table_[i]; |
| 869 for (intptr_t j = i + 1; j < length; j++) { |
| 870 ProfileCode* b = table_[j]; |
| 871 ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && |
| 872 !b->Contains(a->start()) && !b->Contains(a->end() - 1)); |
| 859 } | 873 } |
| 860 } | 874 } |
| 861 | 875 } |
| 862 ZoneGrowableArray<ProfileCode*> table_; | |
| 863 }; | |
| 864 | 876 |
| 865 | 877 |
| 866 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) | 878 ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
| 867 : table_index_(table_index), | 879 : table_index_(table_index), |
| 868 count_(0), | 880 count_(0), |
| 869 exclusive_allocations_(0), | 881 exclusive_allocations_(0), |
| 870 inclusive_allocations_(0), | 882 inclusive_allocations_(0), |
| 871 children_(0), | 883 children_(0), |
| 872 frame_id_(-1) { | 884 frame_id_(-1) { |
| 873 ASSERT(table_index_ >= 0); | 885 ASSERT(table_index_ >= 0); |
| (...skipping 1358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2232 // Failed to find a native symbol for pc. | 2244 // Failed to find a native symbol for pc. |
| 2233 native_start = pc; | 2245 native_start = pc; |
| 2234 } | 2246 } |
| 2235 | 2247 |
| 2236 #if defined(HOST_ARCH_ARM) | 2248 #if defined(HOST_ARCH_ARM) |
| 2237 // The symbol for a Thumb function will be xxx1, but we may have samples | 2249 // The symbol for a Thumb function will be xxx1, but we may have samples |
| 2238 // at function entry which will have pc xxx0. | 2250 // at function entry which will have pc xxx0. |
| 2239 native_start &= ~1; | 2251 native_start &= ~1; |
| 2240 #endif | 2252 #endif |
| 2241 | 2253 |
| 2254 if (native_start > pc) { |
| 2255 // Bogus lookup result. |
| 2256 if (native_name != NULL) { |
| 2257 NativeSymbolResolver::FreeSymbolName(native_name); |
| 2258 native_name = NULL; |
| 2259 } |
| 2260 native_start = pc; |
| 2261 } |
| 2262 if ((pc - native_start) > (32 * KB)) { |
| 2263 // Suspect lookup result. More likely dladdr going off the rails than a |
| 2264 // jumbo function. |
| 2265 if (native_name != NULL) { |
| 2266 NativeSymbolResolver::FreeSymbolName(native_name); |
| 2267 native_name = NULL; |
| 2268 } |
| 2269 native_start = pc; |
| 2270 } |
| 2271 |
| 2242 ASSERT(pc >= native_start); | 2272 ASSERT(pc >= native_start); |
| 2243 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, | 2273 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, |
| 2244 pc + 1, 0, code); | 2274 pc + 1, 0, code); |
| 2245 if (native_name != NULL) { | 2275 if (native_name != NULL) { |
| 2246 profile_code->SetName(native_name); | 2276 profile_code->SetName(native_name); |
| 2247 NativeSymbolResolver::FreeSymbolName(native_name); | 2277 NativeSymbolResolver::FreeSymbolName(native_name); |
| 2248 } | 2278 } |
| 2249 | 2279 |
| 2250 RegisterLiveProfileCode(profile_code); | 2280 RegisterLiveProfileCode(profile_code); |
| 2251 return profile_code; | 2281 return profile_code; |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2848 // Disable thread interrupts while processing the buffer. | 2878 // Disable thread interrupts while processing the buffer. |
| 2849 DisableThreadInterruptsScope dtis(thread); | 2879 DisableThreadInterruptsScope dtis(thread); |
| 2850 | 2880 |
| 2851 ClearProfileVisitor clear_profile(isolate); | 2881 ClearProfileVisitor clear_profile(isolate); |
| 2852 sample_buffer->VisitSamples(&clear_profile); | 2882 sample_buffer->VisitSamples(&clear_profile); |
| 2853 } | 2883 } |
| 2854 | 2884 |
| 2855 #endif // !PRODUCT | 2885 #endif // !PRODUCT |
| 2856 | 2886 |
| 2857 } // namespace dart | 2887 } // namespace dart |
| OLD | NEW |