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