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 |