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 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); |
699 | 720 |
700 class ProfileCodeTable : public ZoneAllocated { | 721 class ProfileCodeTable : public ZoneAllocated { |
zra
2017/06/14 05:00:05
Could you add unit tests for this class? If you mo
rmacnak
2017/06/14 17:32:14
Done. Adjusted neighbor test to compare end instea
| |
701 public: | 722 public: |
702 ProfileCodeTable() : table_(8) {} | 723 ProfileCodeTable() : table_(8) {} |
703 | 724 |
704 intptr_t length() const { return table_.length(); } | 725 intptr_t length() const { return table_.length(); } |
705 | 726 |
706 ProfileCode* At(intptr_t index) const { | 727 ProfileCode* At(intptr_t index) const { |
707 ASSERT(index >= 0); | 728 ASSERT(index >= 0); |
708 ASSERT(index < length()); | 729 ASSERT(index < length()); |
709 return table_[index]; | 730 return table_[index]; |
710 } | 731 } |
711 | 732 |
712 // Find the table index to the ProfileCode containing pc. | 733 // Find the table index to the ProfileCode containing pc. |
713 // Returns < 0 if not found. | 734 // Returns < 0 if not found. |
714 intptr_t FindCodeIndexForPC(uword pc) const { | 735 intptr_t FindCodeIndexForPC(uword pc) const { |
715 intptr_t index = FindCodeIndex(pc, &CompareLowerBound); | 736 intptr_t length = table_.length(); |
716 if (index == length()) { | 737 if (length == 0) { |
717 // Not present. | 738 return -1; // No found. |
zra
2017/06/14 05:00:05
Not
rmacnak
2017/06/14 17:32:14
Done.
| |
718 return -1; | |
719 } | 739 } |
720 const ProfileCode* code = At(index); | 740 intptr_t lo = 0; |
721 if (!code->Contains(pc)) { | 741 intptr_t hi = length - 1; |
722 // Not present. | 742 while (lo <= hi) { |
723 return -1; | 743 intptr_t mid = (hi - lo + 1) / 2 + lo; |
744 ASSERT(mid >= lo); | |
745 ASSERT(mid <= hi); | |
746 ProfileCode* code = At(mid); | |
747 if (code->Contains(pc)) { | |
748 return mid; | |
749 } else if (pc < code->start()) { | |
750 hi = mid - 1; | |
751 } else { | |
752 lo = mid + 1; | |
753 } | |
724 } | 754 } |
725 // Found at index. | 755 return -1; |
726 return index; | |
727 } | 756 } |
728 | 757 |
729 ProfileCode* FindCodeForPC(uword pc) const { | 758 ProfileCode* FindCodeForPC(uword pc) const { |
730 intptr_t index = FindCodeIndexForPC(pc); | 759 intptr_t index = FindCodeIndexForPC(pc); |
731 if (index < 0) { | 760 if (index < 0) { |
732 return NULL; | 761 return NULL; |
733 } | 762 } |
734 return At(index); | 763 return At(index); |
735 } | 764 } |
736 | 765 |
737 // Insert |new_code| into the table. Returns the table index where |new_code| | 766 // Insert |new_code| into the table. Returns the table index where |new_code| |
738 // was inserted. Will merge with an overlapping ProfileCode if one is present. | 767 // was inserted. Will merge with an overlapping ProfileCode if one is present. |
739 intptr_t InsertCode(ProfileCode* new_code) { | 768 intptr_t InsertCode(ProfileCode* new_code) { |
740 const uword start = new_code->start(); | |
741 const uword end = new_code->end(); | |
742 const intptr_t length = table_.length(); | 769 const intptr_t length = table_.length(); |
743 if (length == 0) { | 770 if (length == 0) { |
744 table_.Add(new_code); | 771 table_.Add(new_code); |
745 return length; | 772 return length; |
746 } | 773 } |
774 | |
747 // Determine the correct place to insert or merge |new_code| into table. | 775 // Determine the correct place to insert or merge |new_code| into table. |
748 intptr_t lo = FindCodeIndex(start, &CompareLowerBound); | 776 intptr_t lo = -1; |
749 intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound); | 777 intptr_t hi = -1; |
750 // TODO(johnmccutchan): Simplify below logic. | 778 ProfileCode* lo_code = NULL; |
751 if ((lo == length) && (hi == length)) { | 779 ProfileCode* hi_code = NULL; |
752 lo = length - 1; | 780 const uword pc = new_code->end() - 1; |
781 FindNeighbors(pc, &lo, &hi, &lo_code, &hi_code); | |
782 ASSERT((lo_code != NULL) || (hi_code != NULL)); | |
783 | |
784 if (lo != -1) { | |
785 // Has left neighbor. | |
786 new_code->TruncateLower(lo_code->end()); | |
787 ASSERT(!new_code->Overlaps(lo_code)); | |
753 } | 788 } |
754 if (lo == length) { | 789 if (hi != -1) { |
755 ProfileCode* code = At(hi); | 790 // Has right neighbor. |
756 if (code->Overlaps(new_code)) { | 791 new_code->TruncateUpper(hi_code->start()); |
757 HandleOverlap(code, new_code, start, end); | 792 ASSERT(!new_code->Overlaps(hi_code)); |
758 return hi; | 793 } |
759 } | 794 |
760 table_.Add(new_code); | 795 if ((lo != -1) && (lo_code->kind() == ProfileCode::kNativeCode) && |
761 return length; | 796 (new_code->kind() == ProfileCode::kNativeCode) && |
762 } else if (hi == length) { | 797 (lo_code->end() == new_code->start())) { |
763 ProfileCode* code = At(lo); | 798 // Adjacent left neighbor of the same kind: merge. |
764 if (code->Overlaps(new_code)) { | 799 // (dladdr doesn't give us symbol size so we may new PCs we didn't |
zra
2017/06/14 05:00:05
may see new PCs
rmacnak
2017/06/14 17:32:14
Done.
| |
765 HandleOverlap(code, new_code, start, end); | 800 // previously know belonged to it.) |
766 return lo; | 801 lo_code->ExpandUpper(new_code->end()); |
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; | 802 return lo; |
778 } else { | 803 } |
779 ProfileCode* code = At(lo); | 804 |
780 if (code->Overlaps(new_code)) { | 805 if ((hi != -1) && (hi_code->kind() == ProfileCode::kNativeCode) && |
781 HandleOverlap(code, new_code, start, end); | 806 (new_code->kind() == ProfileCode::kNativeCode) && |
782 return lo; | 807 (new_code->end() == hi_code->start())) { |
783 } | 808 // Adjacent right neighbor of the same kind: merge. |
784 code = At(hi); | 809 // (dladdr doesn't give us symbol size so we may new PCs we didn't |
zra
2017/06/14 05:00:05
may see new PCs
rmacnak
2017/06/14 17:32:14
Done.
| |
785 if (code->Overlaps(new_code)) { | 810 // previously know belonged to it.) |
786 HandleOverlap(code, new_code, start, end); | 811 hi_code->ExpandLower(new_code->start()); |
787 return hi; | |
788 } | |
789 table_.InsertAt(hi, new_code); | |
790 return hi; | 812 return hi; |
791 } | 813 } |
792 UNREACHABLE(); | 814 |
793 return -1; | 815 intptr_t insert; |
816 if (lo == -1) { | |
817 insert = 0; | |
818 } else if (hi == -1) { | |
819 insert = length; | |
820 } else { | |
821 insert = lo + 1; | |
822 } | |
823 table_.InsertAt(insert, new_code); | |
824 return insert; | |
794 } | 825 } |
795 | 826 |
796 private: | 827 private: |
797 intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const { | 828 void FindNeighbors(uword pc, |
798 ASSERT(comparator != NULL); | 829 intptr_t* lo, |
799 intptr_t count = table_.length(); | 830 intptr_t* hi, |
800 intptr_t first = 0; | 831 ProfileCode** lo_code, |
801 while (count > 0) { | 832 ProfileCode** hi_code) const { |
802 intptr_t it = first; | 833 ASSERT(table_.length() >= 1); |
803 intptr_t step = count / 2; | 834 |
804 it += step; | 835 intptr_t length = table_.length(); |
805 const ProfileCode* code = At(it); | 836 |
806 if (comparator(pc, code->start(), code->end())) { | 837 if (pc < At(0)->start()) { |
807 first = ++it; | 838 // Lower than any existing code. |
808 count -= (step + 1); | 839 *lo = -1; |
809 } else { | 840 *lo_code = NULL; |
810 count = step; | 841 *hi = 0; |
842 *hi_code = At(*hi); | |
843 return; | |
844 } | |
845 | |
846 if (pc >= At(length - 1)->end()) { | |
847 // Higher than any existing code. | |
848 *lo = length - 1; | |
849 *lo_code = At(*lo); | |
850 *hi = -1; | |
851 *hi_code = NULL; | |
852 return; | |
853 } | |
854 | |
855 *lo = 0; | |
856 *lo_code = At(*lo); | |
857 *hi = length - 1; | |
858 *hi_code = At(*hi); | |
859 | |
860 while ((*hi - *lo) > 1) { | |
861 intptr_t mid = (*hi - *lo + 1) / 2 + *lo; | |
862 ASSERT(*lo <= mid); | |
863 ASSERT(*hi >= mid); | |
864 ProfileCode* code = At(mid); | |
865 if (code->start() <= pc) { | |
866 *lo = mid; | |
867 *lo_code = code; | |
868 } | |
869 if (pc < code->end()) { | |
870 *hi = mid; | |
871 *hi_code = code; | |
811 } | 872 } |
812 } | 873 } |
813 return first; | |
814 } | |
815 | |
816 static bool CompareUpperBound(uword pc, uword start, uword end) { | |
817 return pc >= end; | |
818 } | |
819 | |
820 static bool CompareLowerBound(uword pc, uword start, uword end) { | |
821 return end <= pc; | |
822 } | |
823 | |
824 void HandleOverlap(ProfileCode* existing, | |
825 ProfileCode* code, | |
826 uword start, | |
827 uword end) { | |
828 // We should never see overlapping Dart code regions. | |
829 ASSERT(existing->kind() != ProfileCode::kDartCode); | |
830 // We should never see overlapping Tag code regions. | |
831 ASSERT(existing->kind() != ProfileCode::kTagCode); | |
832 // When code regions overlap, they should be of the same kind. | |
833 ASSERT(existing->kind() == code->kind()); | |
834 existing->AdjustExtent(start, end); | |
835 } | 874 } |
836 | 875 |
837 void VerifyOrder() { | 876 void VerifyOrder() { |
838 const intptr_t length = table_.length(); | 877 const intptr_t length = table_.length(); |
839 if (length == 0) { | 878 if (length == 0) { |
840 return; | 879 return; |
841 } | 880 } |
842 uword last = table_[0]->end(); | 881 uword last = table_[0]->end(); |
843 for (intptr_t i = 1; i < length; i++) { | 882 for (intptr_t i = 1; i < length; i++) { |
844 ProfileCode* a = table_[i]; | 883 ProfileCode* a = table_[i]; |
(...skipping 1387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2232 // Failed to find a native symbol for pc. | 2271 // Failed to find a native symbol for pc. |
2233 native_start = pc; | 2272 native_start = pc; |
2234 } | 2273 } |
2235 | 2274 |
2236 #if defined(HOST_ARCH_ARM) | 2275 #if defined(HOST_ARCH_ARM) |
2237 // The symbol for a Thumb function will be xxx1, but we may have samples | 2276 // The symbol for a Thumb function will be xxx1, but we may have samples |
2238 // at function entry which will have pc xxx0. | 2277 // at function entry which will have pc xxx0. |
2239 native_start &= ~1; | 2278 native_start &= ~1; |
2240 #endif | 2279 #endif |
2241 | 2280 |
2281 if (native_start > pc) { | |
2282 // Bogus lookup result. | |
2283 if (native_name != NULL) { | |
2284 NativeSymbolResolver::FreeSymbolName(native_name); | |
2285 native_name = NULL; | |
2286 } | |
2287 native_start = pc; | |
2288 } | |
2289 if ((pc - native_start) > (32 * KB)) { | |
2290 // Suspect lookup result. More likely dladdr going off the rails than a | |
2291 // jumbo function. | |
2292 if (native_name != NULL) { | |
2293 NativeSymbolResolver::FreeSymbolName(native_name); | |
2294 native_name = NULL; | |
2295 } | |
2296 native_start = pc; | |
2297 } | |
2298 | |
2242 ASSERT(pc >= native_start); | 2299 ASSERT(pc >= native_start); |
2243 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, | 2300 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, |
2244 pc + 1, 0, code); | 2301 pc + 1, 0, code); |
2245 if (native_name != NULL) { | 2302 if (native_name != NULL) { |
2246 profile_code->SetName(native_name); | 2303 profile_code->SetName(native_name); |
2247 NativeSymbolResolver::FreeSymbolName(native_name); | 2304 NativeSymbolResolver::FreeSymbolName(native_name); |
2248 } | 2305 } |
2249 | 2306 |
2250 RegisterLiveProfileCode(profile_code); | 2307 RegisterLiveProfileCode(profile_code); |
2251 return profile_code; | 2308 return profile_code; |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2848 // Disable thread interrupts while processing the buffer. | 2905 // Disable thread interrupts while processing the buffer. |
2849 DisableThreadInterruptsScope dtis(thread); | 2906 DisableThreadInterruptsScope dtis(thread); |
2850 | 2907 |
2851 ClearProfileVisitor clear_profile(isolate); | 2908 ClearProfileVisitor clear_profile(isolate); |
2852 sample_buffer->VisitSamples(&clear_profile); | 2909 sample_buffer->VisitSamples(&clear_profile); |
2853 } | 2910 } |
2854 | 2911 |
2855 #endif // !PRODUCT | 2912 #endif // !PRODUCT |
2856 | 2913 |
2857 } // namespace dart | 2914 } // namespace dart |
OLD | NEW |