Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: runtime/vm/profiler_service.cc

Issue 1826753003: Use a cache for inlining information (functions + token positions) to speed up function profile (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 ProfileFunctionTrieNodeCode code_object(index); 1058 ProfileFunctionTrieNodeCode code_object(index);
1059 code_object.Tick(); 1059 code_object.Tick();
1060 code_objects_.Add(code_object); 1060 code_objects_.Add(code_object);
1061 } 1061 }
1062 1062
1063 private: 1063 private:
1064 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_; 1064 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_;
1065 }; 1065 };
1066 1066
1067 1067
1068 class ProfileCodeInlinedFunctionsCache : public ValueObject {
1069 public:
1070 ProfileCodeInlinedFunctionsCache()
1071 : cache_cursor_(0),
1072 last_hit_(0) {
1073 for (intptr_t i = 0; i < kCacheSize; i++) {
1074 cache_[i].Reset();
1075 }
1076 cache_hit_ = 0;
1077 cache_miss_ = 0;
1078 }
1079
1080 ~ProfileCodeInlinedFunctionsCache() {
1081 if (FLAG_trace_profiler) {
1082 intptr_t total = cache_hit_ + cache_miss_;
1083 OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n",
1084 total,
1085 cache_hit_,
1086 cache_miss_);
1087 }
1088 }
1089
1090 void Get(uword pc,
1091 const Code& code,
1092 ProcessedSample* sample,
1093 intptr_t frame_index,
1094 // Outputs:
1095 GrowableArray<Function*>** inlined_functions,
1096 GrowableArray<TokenPosition>** inlined_token_positions,
1097 TokenPosition* token_position) {
1098 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
1099 if (FindInCache(pc,
1100 offset,
1101 inlined_functions,
1102 inlined_token_positions,
1103 token_position)) {
1104 // Found in cache.
1105 return;
1106 }
1107 Add(pc, code, sample, frame_index,
1108 inlined_functions, inlined_token_positions, token_position);
1109 }
1110
1111 private:
1112 bool FindInCache(uword pc,
1113 intptr_t offset,
1114 GrowableArray<Function*>** inlined_functions,
1115 GrowableArray<TokenPosition>** inlined_token_positions,
1116 TokenPosition* token_position) {
1117 // Simple linear scan.
1118 for (intptr_t i = 0; i < kCacheSize; i++) {
1119 intptr_t index = (last_hit_ + i) % kCacheSize;
1120 if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
1121 // Hit.
1122 if (cache_[index].inlined_functions.length() == 0) {
1123 *inlined_functions = NULL;
1124 *inlined_token_positions = NULL;
1125 } else {
1126 *inlined_functions = &cache_[index].inlined_functions;
1127 *inlined_token_positions = &cache_[index].inlined_token_positions;
1128 }
1129 *token_position = cache_[index].token_position;
1130 cache_hit_++;
1131 last_hit_ = index;
1132 return true;
1133 }
1134 }
1135 cache_miss_++;
1136 return false;
1137 }
1138
1139 // Add to cache and fill in outputs.
1140 void Add(uword pc,
1141 const Code& code,
1142 ProcessedSample* sample,
1143 intptr_t frame_index,
1144 // Outputs:
1145 GrowableArray<Function*>** inlined_functions,
1146 GrowableArray<TokenPosition>** inlined_token_positions,
1147 TokenPosition* token_position) {
1148 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
1149 CacheEntry* cache_entry = &cache_[NextFreeIndex()];
1150 cache_entry->pc = pc;
1151 cache_entry->offset = offset;
1152 code.GetInlinedFunctionsAt(offset,
1153 &(cache_entry->inlined_functions),
1154 &(cache_entry->inlined_token_positions));
1155 cache_entry->token_position = code.GetTokenPositionAt(offset);
1156 *token_position = (cache_entry->token_position);
1157 if (cache_entry->inlined_functions.length() == 0) {
1158 *inlined_functions = NULL;
1159 *inlined_token_positions = NULL;
1160 return;
1161 }
1162 // The inlined token position table does not include the token position
1163 // of the final call. Insert it at the beginning because the table.
1164 // is reversed.
1165 cache_entry->inlined_token_positions.InsertAt(
1166 0,
1167 cache_entry->token_position);
1168
1169 // Write outputs.
1170 *inlined_functions = &(cache_entry->inlined_functions);
1171 *inlined_token_positions = &(cache_entry->inlined_token_positions);
1172 }
1173
1174 intptr_t NextFreeIndex() {
1175 cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
1176 return cache_cursor_;
1177 }
1178
1179 intptr_t OffsetForPC(uword pc,
1180 const Code& code,
1181 ProcessedSample* sample,
1182 intptr_t frame_index) {
1183 intptr_t offset = pc - code.EntryPoint();
1184 if (frame_index != 0) {
1185 // The PC of frames below the top frame is a call's return address,
1186 // which can belong to a different inlining interval than the call.
1187 offset--;
1188 } else if (sample->IsAllocationSample()) {
1189 // Allocation samples skip the top frame, so the top frame's pc is
1190 // also a call's return address.
1191 offset--;
1192 } else if (!sample->first_frame_executing()) {
1193 // If the first frame wasn't executing code (i.e. we started to collect
1194 // the stack trace at an exit frame), the top frame's pc is also a
1195 // call's return address.
1196 offset--;
1197 }
1198 return offset;
1199 }
1200
1201 struct CacheEntry {
1202 void Reset() {
1203 pc = 0;
1204 offset = 0;
1205 }
1206 uword pc;
1207 intptr_t offset;
1208 GrowableArray<Function*> inlined_functions;
1209 GrowableArray<TokenPosition> inlined_token_positions;
1210 TokenPosition token_position;
1211 };
1212
1213 static const intptr_t kCacheSize = 128;
1214 intptr_t cache_cursor_;
1215 intptr_t last_hit_;
1216 CacheEntry cache_[kCacheSize];
1217 intptr_t cache_miss_;
1218 intptr_t cache_hit_;
1219 };
1220
1221
1068 class ProfileBuilder : public ValueObject { 1222 class ProfileBuilder : public ValueObject {
1069 public: 1223 public:
1070 enum ProfileInfoKind { 1224 enum ProfileInfoKind {
1071 kNone, 1225 kNone,
1072 kOptimized, 1226 kOptimized,
1073 kUnoptimized, 1227 kUnoptimized,
1074 kNative, 1228 kNative,
1075 kInlineStart, 1229 kInlineStart,
1076 kInlineFinish, 1230 kInlineFinish,
1077 kNumProfileInfoKind, 1231 kNumProfileInfoKind,
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
1459 } 1613 }
1460 1614
1461 // Truncated tag. 1615 // Truncated tag.
1462 if (sample->truncated()) { 1616 if (sample->truncated()) {
1463 current = AppendTruncatedTag(current); 1617 current = AppendTruncatedTag(current);
1464 InclusiveTickTruncatedTag(); 1618 InclusiveTickTruncatedTag();
1465 } 1619 }
1466 } 1620 }
1467 } 1621 }
1468 1622
1469 intptr_t OffsetForPC(uword pc,
1470 const Code& code,
1471 ProcessedSample* sample,
1472 intptr_t frame_index) {
1473 intptr_t offset = pc - code.EntryPoint();
1474 if (frame_index != 0) {
1475 // The PC of frames below the top frame is a call's return address,
1476 // which can belong to a different inlining interval than the call.
1477 offset--;
1478 } else if (sample->IsAllocationSample()) {
1479 // Allocation samples skip the top frame, so the top frame's pc is
1480 // also a call's return address.
1481 offset--;
1482 } else if (!sample->first_frame_executing()) {
1483 // If the first frame wasn't executing code (i.e. we started to collect
1484 // the stack trace at an exit frame), the top frame's pc is also a
1485 // call's return address.
1486 offset--;
1487 }
1488 return offset;
1489 }
1490
1491 ProfileFunctionTrieNode* ProcessFrame( 1623 ProfileFunctionTrieNode* ProcessFrame(
1492 ProfileFunctionTrieNode* current, 1624 ProfileFunctionTrieNode* current,
1493 intptr_t sample_index, 1625 intptr_t sample_index,
1494 ProcessedSample* sample, 1626 ProcessedSample* sample,
1495 intptr_t frame_index) { 1627 intptr_t frame_index) {
1496 const uword pc = sample->At(frame_index); 1628 const uword pc = sample->At(frame_index);
1497 ProfileCode* profile_code = GetProfileCode(pc, 1629 ProfileCode* profile_code = GetProfileCode(pc,
1498 sample->timestamp()); 1630 sample->timestamp());
1499 ProfileFunction* function = profile_code->function(); 1631 ProfileFunction* function = profile_code->function();
1500 ASSERT(function != NULL); 1632 ASSERT(function != NULL);
1501 const intptr_t code_index = profile_code->code_table_index(); 1633 const intptr_t code_index = profile_code->code_table_index();
1502 ASSERT(profile_code != NULL); 1634 ASSERT(profile_code != NULL);
1503 const Code& code = Code::ZoneHandle(profile_code->code()); 1635 const Code& code = Code::ZoneHandle(profile_code->code());
1504 GrowableArray<Function*> inlined_functions; 1636 GrowableArray<Function*>* inlined_functions = NULL;
1505 GrowableArray<TokenPosition> inlined_token_positions; 1637 GrowableArray<TokenPosition>* inlined_token_positions = NULL;
1506 TokenPosition token_position = TokenPosition::kNoSource; 1638 TokenPosition token_position = TokenPosition::kNoSource;
1507 if (!code.IsNull()) { 1639 if (!code.IsNull()) {
1508 const intptr_t offset = OffsetForPC(pc, code, sample, frame_index); 1640 inlined_functions_cache_.Get(pc, code, sample, frame_index,
1509 code.GetInlinedFunctionsAt(offset, 1641 &inlined_functions,
1510 &inlined_functions, 1642 &inlined_token_positions,
1511 &inlined_token_positions); 1643 &token_position);
1512 token_position = code.GetTokenPositionAt(offset);
1513 if (inlined_functions.length() > 0) {
1514 // The inlined token position table does not include the token position
1515 // of the final call. Insert it at the beginning because the table.
1516 // is reversed.
1517 inlined_token_positions.InsertAt(0, token_position);
1518 }
1519 ASSERT(inlined_functions.length() <= inlined_token_positions.length());
1520 if (FLAG_trace_profiler_verbose) { 1644 if (FLAG_trace_profiler_verbose) {
1521 for (intptr_t i = 0; i < inlined_functions.length(); i++) { 1645 for (intptr_t i = 0; i < inlined_functions->length(); i++) {
1522 const String& name = 1646 const String& name =
1523 String::Handle(inlined_functions[i]->QualifiedScrubbedName()); 1647 String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
1524 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", 1648 THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n",
1525 i, 1649 i,
1526 name.ToCString(), 1650 name.ToCString(),
1527 inlined_token_positions[i].ToCString()); 1651 (*inlined_token_positions)[i].ToCString());
1528 } 1652 }
1529 } 1653 }
1530 } 1654 }
1531 if (code.IsNull() || (inlined_functions.length() == 0)) { 1655 if (code.IsNull() ||
1656 (inlined_functions == NULL) ||
1657 (inlined_functions->length() == 0)) {
1532 // No inlined functions. 1658 // No inlined functions.
1533 if (inclusive_tree_) { 1659 if (inclusive_tree_) {
1534 current = AppendKind(code, current); 1660 current = AppendKind(code, current);
1535 } 1661 }
1536 current = ProcessFunction(current, 1662 current = ProcessFunction(current,
1537 sample_index, 1663 sample_index,
1538 sample, 1664 sample,
1539 frame_index, 1665 frame_index,
1540 function, 1666 function,
1541 token_position, 1667 token_position,
1542 code_index); 1668 code_index);
1543 if (!inclusive_tree_) { 1669 if (!inclusive_tree_) {
1544 current = AppendKind(code, current); 1670 current = AppendKind(code, current);
1545 } 1671 }
1546 return current; 1672 return current;
1547 } 1673 }
1548 1674
1549 ASSERT(code.is_optimized()); 1675 ASSERT(code.is_optimized());
1550 1676
1551 if (inclusive_tree_) { 1677 if (inclusive_tree_) {
1552 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { 1678 for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
1553 Function* inlined_function = inlined_functions[i]; 1679 Function* inlined_function = (*inlined_functions)[i];
1554 ASSERT(inlined_function != NULL); 1680 ASSERT(inlined_function != NULL);
1555 ASSERT(!inlined_function->IsNull()); 1681 ASSERT(!inlined_function->IsNull());
1556 TokenPosition inlined_token_position = inlined_token_positions[i]; 1682 TokenPosition inlined_token_position = (*inlined_token_positions)[i];
1557 const bool inliner = i == (inlined_functions.length() - 1); 1683 const bool inliner = i == (inlined_functions->length() - 1);
1558 if (inliner) { 1684 if (inliner) {
1559 current = AppendKind(code, current); 1685 current = AppendKind(code, current);
1560 } 1686 }
1561 current = ProcessInlinedFunction(current, 1687 current = ProcessInlinedFunction(current,
1562 sample_index, 1688 sample_index,
1563 sample, 1689 sample,
1564 frame_index, 1690 frame_index,
1565 inlined_function, 1691 inlined_function,
1566 inlined_token_position, 1692 inlined_token_position,
1567 code_index); 1693 code_index);
1568 if (inliner) { 1694 if (inliner) {
1569 current = AppendKind(kInlineStart, current); 1695 current = AppendKind(kInlineStart, current);
1570 } 1696 }
1571 } 1697 }
1572 current = AppendKind(kInlineFinish, current); 1698 current = AppendKind(kInlineFinish, current);
1573 } else { 1699 } else {
1574 // Append the inlined children. 1700 // Append the inlined children.
1575 current = AppendKind(kInlineFinish, current); 1701 current = AppendKind(kInlineFinish, current);
1576 for (intptr_t i = 0; i < inlined_functions.length(); i++) { 1702 for (intptr_t i = 0; i < inlined_functions->length(); i++) {
1577 Function* inlined_function = inlined_functions[i]; 1703 Function* inlined_function = (*inlined_functions)[i];
1578 ASSERT(inlined_function != NULL); 1704 ASSERT(inlined_function != NULL);
1579 ASSERT(!inlined_function->IsNull()); 1705 ASSERT(!inlined_function->IsNull());
1580 TokenPosition inlined_token_position = inlined_token_positions[i]; 1706 TokenPosition inlined_token_position = (*inlined_token_positions)[i];
1581 const bool inliner = i == (inlined_functions.length() - 1); 1707 const bool inliner = i == (inlined_functions->length() - 1);
1582 if (inliner) { 1708 if (inliner) {
1583 current = AppendKind(kInlineStart, current); 1709 current = AppendKind(kInlineStart, current);
1584 } 1710 }
1585 current = ProcessInlinedFunction(current, 1711 current = ProcessInlinedFunction(current,
1586 sample_index, 1712 sample_index,
1587 sample, 1713 sample,
1588 frame_index + i, 1714 frame_index + i,
1589 inlined_function, 1715 inlined_function,
1590 inlined_token_position, 1716 inlined_token_position,
1591 code_index); 1717 code_index);
(...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after
2119 Isolate* vm_isolate_; 2245 Isolate* vm_isolate_;
2120 SampleFilter* filter_; 2246 SampleFilter* filter_;
2121 Profile::TagOrder tag_order_; 2247 Profile::TagOrder tag_order_;
2122 intptr_t extra_tags_; 2248 intptr_t extra_tags_;
2123 Profile* profile_; 2249 Profile* profile_;
2124 DeoptimizedCodeSet* deoptimized_code_; 2250 DeoptimizedCodeSet* deoptimized_code_;
2125 const Code& null_code_; 2251 const Code& null_code_;
2126 const Function& null_function_; 2252 const Function& null_function_;
2127 bool tick_functions_; 2253 bool tick_functions_;
2128 bool inclusive_tree_; 2254 bool inclusive_tree_;
2129 2255 ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
2130 ProcessedSampleBuffer* samples_; 2256 ProcessedSampleBuffer* samples_;
2131 ProfileInfoKind info_kind_; 2257 ProfileInfoKind info_kind_;
2132 }; // ProfileBuilder. 2258 }; // ProfileBuilder.
2133 2259
2134 2260
2135 Profile::Profile(Isolate* isolate) 2261 Profile::Profile(Isolate* isolate)
2136 : isolate_(isolate), 2262 : isolate_(isolate),
2137 zone_(Thread::Current()->zone()), 2263 zone_(Thread::Current()->zone()),
2138 samples_(NULL), 2264 samples_(NULL),
2139 live_code_(NULL), 2265 live_code_(NULL),
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
2619 // Disable thread interrupts while processing the buffer. 2745 // Disable thread interrupts while processing the buffer.
2620 DisableThreadInterruptsScope dtis(thread); 2746 DisableThreadInterruptsScope dtis(thread);
2621 2747
2622 ClearProfileVisitor clear_profile(isolate); 2748 ClearProfileVisitor clear_profile(isolate);
2623 sample_buffer->VisitSamples(&clear_profile); 2749 sample_buffer->VisitSamples(&clear_profile);
2624 } 2750 }
2625 2751
2626 #endif // !PRODUCT 2752 #endif // !PRODUCT
2627 2753
2628 } // namespace dart 2754 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698