Chromium Code Reviews| 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 |