Index: runtime/vm/profiler_service.cc |
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc |
index f245ed5f29657d2f5ac8d176c217fdc1f26b4ba9..9a4fe3b6916104fcf09acde7a1eaa54342033f1b 100644 |
--- a/runtime/vm/profiler_service.cc |
+++ b/runtime/vm/profiler_service.cc |
@@ -302,10 +302,31 @@ ProfileCode::ProfileCode(Kind kind, |
address_ticks_(0) {} |
-void ProfileCode::AdjustExtent(uword start, uword end) { |
+void ProfileCode::TruncateLower(uword start) { |
+ if (start > start_) { |
+ start_ = start; |
+ } |
+ ASSERT(start_ < end_); |
+} |
+ |
+ |
+void ProfileCode::TruncateUpper(uword end) { |
+ if (end < end_) { |
+ end_ = end; |
+ } |
+ ASSERT(start_ < end_); |
+} |
+ |
+ |
+void ProfileCode::ExpandLower(uword start) { |
if (start < start_) { |
start_ = start; |
} |
+ ASSERT(start_ < end_); |
+} |
+ |
+ |
+void ProfileCode::ExpandUpper(uword end) { |
if (end > end_) { |
end_ = end; |
} |
@@ -695,172 +716,163 @@ ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) { |
} |
-typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); |
- |
-class ProfileCodeTable : public ZoneAllocated { |
- public: |
- ProfileCodeTable() : table_(8) {} |
+intptr_t ProfileCodeTable::FindCodeIndexForPC(uword pc) const { |
+ intptr_t length = table_.length(); |
+ if (length == 0) { |
+ return -1; // Not found. |
+ } |
+ intptr_t lo = 0; |
+ intptr_t hi = length - 1; |
+ while (lo <= hi) { |
+ intptr_t mid = (hi - lo + 1) / 2 + lo; |
+ ASSERT(mid >= lo); |
+ ASSERT(mid <= hi); |
+ ProfileCode* code = At(mid); |
+ if (code->Contains(pc)) { |
+ return mid; |
+ } else if (pc < code->start()) { |
+ hi = mid - 1; |
+ } else { |
+ lo = mid + 1; |
+ } |
+ } |
+ return -1; |
+} |
- intptr_t length() const { return table_.length(); } |
- ProfileCode* At(intptr_t index) const { |
- ASSERT(index >= 0); |
- ASSERT(index < length()); |
- return table_[index]; |
+intptr_t ProfileCodeTable::InsertCode(ProfileCode* new_code) { |
+ const intptr_t length = table_.length(); |
+ if (length == 0) { |
+ table_.Add(new_code); |
+ return length; |
+ } |
+ |
+ // Determine the correct place to insert or merge |new_code| into table. |
+ intptr_t lo = -1; |
+ intptr_t hi = -1; |
+ ProfileCode* lo_code = NULL; |
+ ProfileCode* hi_code = NULL; |
+ const uword pc = new_code->end() - 1; |
+ FindNeighbors(pc, &lo, &hi, &lo_code, &hi_code); |
+ ASSERT((lo_code != NULL) || (hi_code != NULL)); |
+ |
+ if (lo != -1) { |
+ // Has left neighbor. |
+ new_code->TruncateLower(lo_code->end()); |
+ ASSERT(!new_code->Overlaps(lo_code)); |
+ } |
+ if (hi != -1) { |
+ // Has right neighbor. |
+ new_code->TruncateUpper(hi_code->start()); |
+ ASSERT(!new_code->Overlaps(hi_code)); |
+ } |
+ |
+ if ((lo != -1) && (lo_code->kind() == ProfileCode::kNativeCode) && |
+ (new_code->kind() == ProfileCode::kNativeCode) && |
+ (lo_code->end() == new_code->start())) { |
+ // Adjacent left neighbor of the same kind: merge. |
+ // (dladdr doesn't give us symbol size so processing more samples may see |
+ // more PCs we didn't previously know belonged to it.) |
+ lo_code->ExpandUpper(new_code->end()); |
+ return lo; |
+ } |
+ |
+ if ((hi != -1) && (hi_code->kind() == ProfileCode::kNativeCode) && |
+ (new_code->kind() == ProfileCode::kNativeCode) && |
+ (new_code->end() == hi_code->start())) { |
+ // Adjacent right neighbor of the same kind: merge. |
+ // (dladdr doesn't give us symbol size so processing more samples may see |
+ // more PCs we didn't previously know belonged to it.) |
+ hi_code->ExpandLower(new_code->start()); |
+ return hi; |
+ } |
+ |
+ intptr_t insert; |
+ if (lo == -1) { |
+ insert = 0; |
+ } else if (hi == -1) { |
+ insert = length; |
+ } else { |
+ insert = lo + 1; |
} |
+ table_.InsertAt(insert, new_code); |
+ return insert; |
+} |
- // Find the table index to the ProfileCode containing pc. |
- // Returns < 0 if not found. |
- intptr_t FindCodeIndexForPC(uword pc) const { |
- intptr_t index = FindCodeIndex(pc, &CompareLowerBound); |
- if (index == length()) { |
- // Not present. |
- return -1; |
- } |
- const ProfileCode* code = At(index); |
- if (!code->Contains(pc)) { |
- // Not present. |
- return -1; |
- } |
- // Found at index. |
- return index; |
- } |
- ProfileCode* FindCodeForPC(uword pc) const { |
- intptr_t index = FindCodeIndexForPC(pc); |
- if (index < 0) { |
- return NULL; |
- } |
- return At(index); |
- } |
- |
- // Insert |new_code| into the table. Returns the table index where |new_code| |
- // was inserted. Will merge with an overlapping ProfileCode if one is present. |
- intptr_t InsertCode(ProfileCode* new_code) { |
- const uword start = new_code->start(); |
- const uword end = new_code->end(); |
- const intptr_t length = table_.length(); |
- if (length == 0) { |
- table_.Add(new_code); |
- return length; |
- } |
- // Determine the correct place to insert or merge |new_code| into table. |
- intptr_t lo = FindCodeIndex(start, &CompareLowerBound); |
- intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound); |
- // TODO(johnmccutchan): Simplify below logic. |
- if ((lo == length) && (hi == length)) { |
- lo = length - 1; |
- } |
- if (lo == length) { |
- ProfileCode* code = At(hi); |
- if (code->Overlaps(new_code)) { |
- HandleOverlap(code, new_code, start, end); |
- return hi; |
- } |
- table_.Add(new_code); |
- return length; |
- } else if (hi == length) { |
- ProfileCode* code = At(lo); |
- if (code->Overlaps(new_code)) { |
- HandleOverlap(code, new_code, start, end); |
- return lo; |
- } |
- table_.Add(new_code); |
- return length; |
- } else if (lo == hi) { |
- ProfileCode* code = At(lo); |
- if (code->Overlaps(new_code)) { |
- HandleOverlap(code, new_code, start, end); |
- return lo; |
- } |
- table_.InsertAt(lo, new_code); |
- return lo; |
- } else { |
- ProfileCode* code = At(lo); |
- if (code->Overlaps(new_code)) { |
- HandleOverlap(code, new_code, start, end); |
- return lo; |
- } |
- code = At(hi); |
- if (code->Overlaps(new_code)) { |
- HandleOverlap(code, new_code, start, end); |
- return hi; |
- } |
- table_.InsertAt(hi, new_code); |
- return hi; |
- } |
- UNREACHABLE(); |
- return -1; |
- } |
+void ProfileCodeTable::FindNeighbors(uword pc, |
+ intptr_t* lo, |
+ intptr_t* hi, |
+ ProfileCode** lo_code, |
+ ProfileCode** hi_code) const { |
+ ASSERT(table_.length() >= 1); |
- private: |
- intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const { |
- ASSERT(comparator != NULL); |
- intptr_t count = table_.length(); |
- intptr_t first = 0; |
- while (count > 0) { |
- intptr_t it = first; |
- intptr_t step = count / 2; |
- it += step; |
- const ProfileCode* code = At(it); |
- if (comparator(pc, code->start(), code->end())) { |
- first = ++it; |
- count -= (step + 1); |
- } else { |
- count = step; |
- } |
- } |
- return first; |
- } |
+ intptr_t length = table_.length(); |
- static bool CompareUpperBound(uword pc, uword start, uword end) { |
- return pc >= end; |
+ if (pc < At(0)->start()) { |
+ // Lower than any existing code. |
+ *lo = -1; |
+ *lo_code = NULL; |
+ *hi = 0; |
+ *hi_code = At(*hi); |
+ return; |
} |
- static bool CompareLowerBound(uword pc, uword start, uword end) { |
- return end <= pc; |
+ if (pc >= At(length - 1)->end()) { |
+ // Higher than any existing code. |
+ *lo = length - 1; |
+ *lo_code = At(*lo); |
+ *hi = -1; |
+ *hi_code = NULL; |
+ return; |
} |
- void HandleOverlap(ProfileCode* existing, |
- ProfileCode* code, |
- uword start, |
- uword end) { |
- // We should never see overlapping Dart code regions. |
- ASSERT(existing->kind() != ProfileCode::kDartCode); |
- // We should never see overlapping Tag code regions. |
- ASSERT(existing->kind() != ProfileCode::kTagCode); |
- // When code regions overlap, they should be of the same kind. |
- ASSERT(existing->kind() == code->kind()); |
- existing->AdjustExtent(start, end); |
- } |
+ *lo = 0; |
+ *lo_code = At(*lo); |
+ *hi = length - 1; |
+ *hi_code = At(*hi); |
- void VerifyOrder() { |
- const intptr_t length = table_.length(); |
- if (length == 0) { |
- return; |
+ while ((*hi - *lo) > 1) { |
+ intptr_t mid = (*hi - *lo + 1) / 2 + *lo; |
+ ASSERT(*lo <= mid); |
+ ASSERT(*hi >= mid); |
+ ProfileCode* code = At(mid); |
+ if (code->end() <= pc) { |
+ *lo = mid; |
+ *lo_code = code; |
} |
- uword last = table_[0]->end(); |
- for (intptr_t i = 1; i < length; i++) { |
- ProfileCode* a = table_[i]; |
- ASSERT(last <= a->start()); |
- last = a->end(); |
+ if (pc < code->end()) { |
+ *hi = mid; |
+ *hi_code = code; |
} |
} |
+} |
+ |
+ |
+void ProfileCodeTable::VerifyOrder() { |
+ const intptr_t length = table_.length(); |
+ if (length == 0) { |
+ return; |
+ } |
+ uword last = table_[0]->end(); |
+ for (intptr_t i = 1; i < length; i++) { |
+ ProfileCode* a = table_[i]; |
+ ASSERT(last <= a->start()); |
+ last = a->end(); |
+ } |
+} |
- void VerifyOverlap() { |
- const intptr_t length = table_.length(); |
- for (intptr_t i = 0; i < length; i++) { |
- ProfileCode* a = table_[i]; |
- for (intptr_t j = i + 1; j < length; j++) { |
- ProfileCode* b = table_[j]; |
- ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && |
- !b->Contains(a->start()) && !b->Contains(a->end() - 1)); |
- } |
+void ProfileCodeTable::VerifyOverlap() { |
+ const intptr_t length = table_.length(); |
+ for (intptr_t i = 0; i < length; i++) { |
+ ProfileCode* a = table_[i]; |
+ for (intptr_t j = i + 1; j < length; j++) { |
+ ProfileCode* b = table_[j]; |
+ ASSERT(!a->Contains(b->start()) && !a->Contains(b->end() - 1) && |
+ !b->Contains(a->start()) && !b->Contains(a->end() - 1)); |
} |
} |
- |
- ZoneGrowableArray<ProfileCode*> table_; |
-}; |
+} |
ProfileTrieNode::ProfileTrieNode(intptr_t table_index) |
@@ -2239,6 +2251,24 @@ class ProfileBuilder : public ValueObject { |
native_start &= ~1; |
#endif |
+ if (native_start > pc) { |
+ // Bogus lookup result. |
+ if (native_name != NULL) { |
+ NativeSymbolResolver::FreeSymbolName(native_name); |
+ native_name = NULL; |
+ } |
+ native_start = pc; |
+ } |
+ if ((pc - native_start) > (32 * KB)) { |
+ // Suspect lookup result. More likely dladdr going off the rails than a |
+ // jumbo function. |
+ if (native_name != NULL) { |
+ NativeSymbolResolver::FreeSymbolName(native_name); |
+ native_name = NULL; |
+ } |
+ native_start = pc; |
+ } |
+ |
ASSERT(pc >= native_start); |
profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, |
pc + 1, 0, code); |