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/native_symbol.h" | 10 #include "vm/native_symbol.h" |
(...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1042 OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total, | 1042 OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total, |
1043 cache_hit_, cache_miss_); | 1043 cache_hit_, cache_miss_); |
1044 } | 1044 } |
1045 } | 1045 } |
1046 | 1046 |
1047 void Get(uword pc, | 1047 void Get(uword pc, |
1048 const Code& code, | 1048 const Code& code, |
1049 ProcessedSample* sample, | 1049 ProcessedSample* sample, |
1050 intptr_t frame_index, | 1050 intptr_t frame_index, |
1051 // Outputs: | 1051 // Outputs: |
1052 GrowableArray<Function*>** inlined_functions, | 1052 GrowableArray<const Function*>** inlined_functions, |
1053 GrowableArray<TokenPosition>** inlined_token_positions, | 1053 GrowableArray<TokenPosition>** inlined_token_positions, |
1054 TokenPosition* token_position) { | 1054 TokenPosition* token_position) { |
1055 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); | 1055 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); |
1056 if (FindInCache(pc, offset, inlined_functions, inlined_token_positions, | 1056 if (FindInCache(pc, offset, inlined_functions, inlined_token_positions, |
1057 token_position)) { | 1057 token_position)) { |
1058 // Found in cache. | 1058 // Found in cache. |
1059 return; | 1059 return; |
1060 } | 1060 } |
1061 Add(pc, code, sample, frame_index, inlined_functions, | 1061 Add(pc, code, sample, frame_index, inlined_functions, |
1062 inlined_token_positions, token_position); | 1062 inlined_token_positions, token_position); |
1063 } | 1063 } |
1064 | 1064 |
1065 private: | 1065 private: |
1066 bool FindInCache(uword pc, | 1066 bool FindInCache(uword pc, |
1067 intptr_t offset, | 1067 intptr_t offset, |
1068 GrowableArray<Function*>** inlined_functions, | 1068 GrowableArray<const Function*>** inlined_functions, |
1069 GrowableArray<TokenPosition>** inlined_token_positions, | 1069 GrowableArray<TokenPosition>** inlined_token_positions, |
1070 TokenPosition* token_position) { | 1070 TokenPosition* token_position) { |
1071 // Simple linear scan. | 1071 // Simple linear scan. |
1072 for (intptr_t i = 0; i < kCacheSize; i++) { | 1072 for (intptr_t i = 0; i < kCacheSize; i++) { |
1073 intptr_t index = (last_hit_ + i) % kCacheSize; | 1073 intptr_t index = (last_hit_ + i) % kCacheSize; |
1074 if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) { | 1074 if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) { |
1075 // Hit. | 1075 // Hit. |
1076 if (cache_[index].inlined_functions.length() == 0) { | 1076 if (cache_[index].inlined_functions.length() == 0) { |
1077 *inlined_functions = NULL; | 1077 *inlined_functions = NULL; |
1078 *inlined_token_positions = NULL; | 1078 *inlined_token_positions = NULL; |
(...skipping 10 matching lines...) Expand all Loading... |
1089 cache_miss_++; | 1089 cache_miss_++; |
1090 return false; | 1090 return false; |
1091 } | 1091 } |
1092 | 1092 |
1093 // Add to cache and fill in outputs. | 1093 // Add to cache and fill in outputs. |
1094 void Add(uword pc, | 1094 void Add(uword pc, |
1095 const Code& code, | 1095 const Code& code, |
1096 ProcessedSample* sample, | 1096 ProcessedSample* sample, |
1097 intptr_t frame_index, | 1097 intptr_t frame_index, |
1098 // Outputs: | 1098 // Outputs: |
1099 GrowableArray<Function*>** inlined_functions, | 1099 GrowableArray<const Function*>** inlined_functions, |
1100 GrowableArray<TokenPosition>** inlined_token_positions, | 1100 GrowableArray<TokenPosition>** inlined_token_positions, |
1101 TokenPosition* token_position) { | 1101 TokenPosition* token_position) { |
1102 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); | 1102 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); |
1103 CacheEntry* cache_entry = &cache_[NextFreeIndex()]; | 1103 CacheEntry* cache_entry = &cache_[NextFreeIndex()]; |
1104 cache_entry->pc = pc; | 1104 cache_entry->pc = pc; |
1105 cache_entry->offset = offset; | 1105 cache_entry->offset = offset; |
1106 code.GetInlinedFunctionsAt(offset, &(cache_entry->inlined_functions), | 1106 code.GetInlinedFunctionsAt(offset, &(cache_entry->inlined_functions), |
1107 &(cache_entry->inlined_token_positions)); | 1107 &(cache_entry->inlined_token_positions)); |
1108 cache_entry->token_position = code.GetTokenPositionAt(offset); | |
1109 *token_position = (cache_entry->token_position); | |
1110 if (cache_entry->inlined_functions.length() == 0) { | 1108 if (cache_entry->inlined_functions.length() == 0) { |
1111 *inlined_functions = NULL; | 1109 *inlined_functions = NULL; |
1112 *inlined_token_positions = NULL; | 1110 *inlined_token_positions = NULL; |
| 1111 *token_position = cache_entry->token_position = TokenPosition(); |
1113 return; | 1112 return; |
1114 } | 1113 } |
1115 // The inlined token position table does not include the token position | |
1116 // of the final call. Insert it at the beginning because the table. | |
1117 // is reversed. | |
1118 cache_entry->inlined_token_positions.InsertAt(0, | |
1119 cache_entry->token_position); | |
1120 | 1114 |
1121 // Write outputs. | 1115 // Write outputs. |
1122 *inlined_functions = &(cache_entry->inlined_functions); | 1116 *inlined_functions = &(cache_entry->inlined_functions); |
1123 *inlined_token_positions = &(cache_entry->inlined_token_positions); | 1117 *inlined_token_positions = &(cache_entry->inlined_token_positions); |
| 1118 *token_position = cache_entry->token_position = |
| 1119 cache_entry->inlined_token_positions[0]; |
1124 } | 1120 } |
1125 | 1121 |
1126 intptr_t NextFreeIndex() { | 1122 intptr_t NextFreeIndex() { |
1127 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize; | 1123 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize; |
1128 return cache_cursor_; | 1124 return cache_cursor_; |
1129 } | 1125 } |
1130 | 1126 |
1131 intptr_t OffsetForPC(uword pc, | 1127 intptr_t OffsetForPC(uword pc, |
1132 const Code& code, | 1128 const Code& code, |
1133 ProcessedSample* sample, | 1129 ProcessedSample* sample, |
(...skipping 16 matching lines...) Expand all Loading... |
1150 return offset; | 1146 return offset; |
1151 } | 1147 } |
1152 | 1148 |
1153 struct CacheEntry { | 1149 struct CacheEntry { |
1154 void Reset() { | 1150 void Reset() { |
1155 pc = 0; | 1151 pc = 0; |
1156 offset = 0; | 1152 offset = 0; |
1157 } | 1153 } |
1158 uword pc; | 1154 uword pc; |
1159 intptr_t offset; | 1155 intptr_t offset; |
1160 GrowableArray<Function*> inlined_functions; | 1156 GrowableArray<const Function*> inlined_functions; |
1161 GrowableArray<TokenPosition> inlined_token_positions; | 1157 GrowableArray<TokenPosition> inlined_token_positions; |
1162 TokenPosition token_position; | 1158 TokenPosition token_position; |
1163 }; | 1159 }; |
1164 | 1160 |
1165 static const intptr_t kCacheSize = 128; | 1161 static const intptr_t kCacheSize = 128; |
1166 intptr_t cache_cursor_; | 1162 intptr_t cache_cursor_; |
1167 intptr_t last_hit_; | 1163 intptr_t last_hit_; |
1168 CacheEntry cache_[kCacheSize]; | 1164 CacheEntry cache_[kCacheSize]; |
1169 intptr_t cache_miss_; | 1165 intptr_t cache_miss_; |
1170 intptr_t cache_hit_; | 1166 intptr_t cache_hit_; |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1585 intptr_t sample_index, | 1581 intptr_t sample_index, |
1586 ProcessedSample* sample, | 1582 ProcessedSample* sample, |
1587 intptr_t frame_index) { | 1583 intptr_t frame_index) { |
1588 const uword pc = sample->At(frame_index); | 1584 const uword pc = sample->At(frame_index); |
1589 ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp()); | 1585 ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp()); |
1590 ProfileFunction* function = profile_code->function(); | 1586 ProfileFunction* function = profile_code->function(); |
1591 ASSERT(function != NULL); | 1587 ASSERT(function != NULL); |
1592 const intptr_t code_index = profile_code->code_table_index(); | 1588 const intptr_t code_index = profile_code->code_table_index(); |
1593 ASSERT(profile_code != NULL); | 1589 ASSERT(profile_code != NULL); |
1594 const Code& code = Code::ZoneHandle(profile_code->code()); | 1590 const Code& code = Code::ZoneHandle(profile_code->code()); |
1595 GrowableArray<Function*>* inlined_functions = NULL; | 1591 GrowableArray<const Function*>* inlined_functions = NULL; |
1596 GrowableArray<TokenPosition>* inlined_token_positions = NULL; | 1592 GrowableArray<TokenPosition>* inlined_token_positions = NULL; |
1597 TokenPosition token_position = TokenPosition::kNoSource; | 1593 TokenPosition token_position = TokenPosition::kNoSource; |
1598 if (!code.IsNull()) { | 1594 if (!code.IsNull()) { |
1599 inlined_functions_cache_.Get(pc, code, sample, frame_index, | 1595 inlined_functions_cache_.Get(pc, code, sample, frame_index, |
1600 &inlined_functions, &inlined_token_positions, | 1596 &inlined_functions, &inlined_token_positions, |
1601 &token_position); | 1597 &token_position); |
1602 if (FLAG_trace_profiler_verbose) { | 1598 if (FLAG_trace_profiler_verbose) { |
1603 for (intptr_t i = 0; i < inlined_functions->length(); i++) { | 1599 for (intptr_t i = 0; i < inlined_functions->length(); i++) { |
1604 const String& name = | 1600 const String& name = |
1605 String::Handle((*inlined_functions)[i]->QualifiedScrubbedName()); | 1601 String::Handle((*inlined_functions)[i]->QualifiedScrubbedName()); |
1606 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", i, | 1602 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", i, |
1607 name.ToCString(), | 1603 name.ToCString(), |
1608 (*inlined_token_positions)[i].ToCString()); | 1604 (*inlined_token_positions)[i].ToCString()); |
1609 } | 1605 } |
1610 } | 1606 } |
1611 } | 1607 } |
| 1608 |
1612 if (code.IsNull() || (inlined_functions == NULL) || | 1609 if (code.IsNull() || (inlined_functions == NULL) || |
1613 (inlined_functions->length() == 0)) { | 1610 (inlined_functions->length() <= 1)) { |
1614 // No inlined functions. | 1611 // No inlined functions. |
1615 if (inclusive_tree_) { | 1612 if (inclusive_tree_) { |
1616 current = AppendKind(code, current); | 1613 current = AppendKind(code, current); |
1617 } | 1614 } |
1618 current = ProcessFunction(current, sample_index, sample, frame_index, | 1615 current = ProcessFunction(current, sample_index, sample, frame_index, |
1619 function, token_position, code_index); | 1616 function, token_position, code_index); |
1620 if (!inclusive_tree_) { | 1617 if (!inclusive_tree_) { |
1621 current = AppendKind(code, current); | 1618 current = AppendKind(code, current); |
1622 } | 1619 } |
1623 return current; | 1620 return current; |
1624 } | 1621 } |
1625 | 1622 |
1626 ASSERT(code.is_optimized()); | 1623 ASSERT(code.is_optimized()); |
1627 | 1624 |
1628 if (inclusive_tree_) { | 1625 if (inclusive_tree_) { |
1629 for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) { | 1626 for (intptr_t i = 0; i < inlined_functions->length(); i++) { |
1630 Function* inlined_function = (*inlined_functions)[i]; | 1627 const Function* inlined_function = (*inlined_functions)[i]; |
1631 ASSERT(inlined_function != NULL); | 1628 ASSERT(inlined_function != NULL); |
1632 ASSERT(!inlined_function->IsNull()); | 1629 ASSERT(!inlined_function->IsNull()); |
1633 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; | 1630 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; |
1634 const bool inliner = i == (inlined_functions->length() - 1); | 1631 const bool inliner = i == 0; |
1635 if (inliner) { | 1632 if (inliner) { |
1636 current = AppendKind(code, current); | 1633 current = AppendKind(code, current); |
1637 } | 1634 } |
1638 current = ProcessInlinedFunction(current, sample_index, sample, | 1635 current = ProcessInlinedFunction(current, sample_index, sample, |
1639 frame_index, inlined_function, | 1636 frame_index, inlined_function, |
1640 inlined_token_position, code_index); | 1637 inlined_token_position, code_index); |
1641 if (inliner) { | 1638 if (inliner) { |
1642 current = AppendKind(kInlineStart, current); | 1639 current = AppendKind(kInlineStart, current); |
1643 } | 1640 } |
1644 } | 1641 } |
1645 current = AppendKind(kInlineFinish, current); | 1642 current = AppendKind(kInlineFinish, current); |
1646 } else { | 1643 } else { |
1647 // Append the inlined children. | 1644 // Append the inlined children. |
1648 current = AppendKind(kInlineFinish, current); | 1645 current = AppendKind(kInlineFinish, current); |
1649 for (intptr_t i = 0; i < inlined_functions->length(); i++) { | 1646 for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) { |
1650 Function* inlined_function = (*inlined_functions)[i]; | 1647 const Function* inlined_function = (*inlined_functions)[i]; |
1651 ASSERT(inlined_function != NULL); | 1648 ASSERT(inlined_function != NULL); |
1652 ASSERT(!inlined_function->IsNull()); | 1649 ASSERT(!inlined_function->IsNull()); |
1653 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; | 1650 TokenPosition inlined_token_position = (*inlined_token_positions)[i]; |
1654 const bool inliner = i == (inlined_functions->length() - 1); | 1651 const bool inliner = i == 0; |
1655 if (inliner) { | 1652 if (inliner) { |
1656 current = AppendKind(kInlineStart, current); | 1653 current = AppendKind(kInlineStart, current); |
1657 } | 1654 } |
1658 current = ProcessInlinedFunction(current, sample_index, sample, | 1655 current = ProcessInlinedFunction(current, sample_index, sample, |
1659 frame_index + i, inlined_function, | 1656 frame_index + i, inlined_function, |
1660 inlined_token_position, code_index); | 1657 inlined_token_position, code_index); |
1661 if (inliner) { | 1658 if (inliner) { |
1662 current = AppendKind(code, current); | 1659 current = AppendKind(code, current); |
1663 } | 1660 } |
1664 } | 1661 } |
1665 } | 1662 } |
1666 | 1663 |
1667 return current; | 1664 return current; |
1668 } | 1665 } |
1669 | 1666 |
1670 ProfileFunctionTrieNode* ProcessInlinedFunction( | 1667 ProfileFunctionTrieNode* ProcessInlinedFunction( |
1671 ProfileFunctionTrieNode* current, | 1668 ProfileFunctionTrieNode* current, |
1672 intptr_t sample_index, | 1669 intptr_t sample_index, |
1673 ProcessedSample* sample, | 1670 ProcessedSample* sample, |
1674 intptr_t frame_index, | 1671 intptr_t frame_index, |
1675 Function* inlined_function, | 1672 const Function* inlined_function, |
1676 TokenPosition inlined_token_position, | 1673 TokenPosition inlined_token_position, |
1677 intptr_t code_index) { | 1674 intptr_t code_index) { |
1678 ProfileFunctionTable* function_table = profile_->functions_; | 1675 ProfileFunctionTable* function_table = profile_->functions_; |
1679 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); | 1676 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); |
1680 ASSERT(function != NULL); | 1677 ASSERT(function != NULL); |
1681 return ProcessFunction(current, sample_index, sample, frame_index, function, | 1678 return ProcessFunction(current, sample_index, sample, frame_index, function, |
1682 inlined_token_position, code_index); | 1679 inlined_token_position, code_index); |
1683 } | 1680 } |
1684 | 1681 |
1685 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) { | 1682 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) { |
(...skipping 1080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2766 // Disable thread interrupts while processing the buffer. | 2763 // Disable thread interrupts while processing the buffer. |
2767 DisableThreadInterruptsScope dtis(thread); | 2764 DisableThreadInterruptsScope dtis(thread); |
2768 | 2765 |
2769 ClearProfileVisitor clear_profile(isolate); | 2766 ClearProfileVisitor clear_profile(isolate); |
2770 sample_buffer->VisitSamples(&clear_profile); | 2767 sample_buffer->VisitSamples(&clear_profile); |
2771 } | 2768 } |
2772 | 2769 |
2773 #endif // !PRODUCT | 2770 #endif // !PRODUCT |
2774 | 2771 |
2775 } // namespace dart | 2772 } // namespace dart |
OLD | NEW |