| 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/native_symbol.h" | 8 #include "vm/native_symbol.h" |
| 9 #include "vm/object.h" | 9 #include "vm/object.h" |
| 10 #include "vm/os.h" | 10 #include "vm/os.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } | 110 } |
| 111 ASSERT(!function_.IsNull()); | 111 ASSERT(!function_.IsNull()); |
| 112 const String& func_name = | 112 const String& func_name = |
| 113 String::Handle(function_.QualifiedUserVisibleName()); | 113 String::Handle(function_.QualifiedUserVisibleName()); |
| 114 return func_name.ToCString(); | 114 return func_name.ToCString(); |
| 115 } | 115 } |
| 116 | 116 |
| 117 void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) { | 117 void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) { |
| 118 if (exclusive) { | 118 if (exclusive) { |
| 119 exclusive_ticks_++; | 119 exclusive_ticks_++; |
| 120 } else { | |
| 121 if (inclusive_serial_ == inclusive_serial) { | |
| 122 // Already ticket. | |
| 123 return; | |
| 124 } | |
| 125 inclusive_serial_ = inclusive_serial; | |
| 126 inclusive_ticks_++; | |
| 127 } | 120 } |
| 121 // Fall through and tick inclusive count too. |
| 122 if (inclusive_serial_ == inclusive_serial) { |
| 123 // Already ticked. |
| 124 return; |
| 125 } |
| 126 inclusive_serial_ = inclusive_serial; |
| 127 inclusive_ticks_++; |
| 128 } | 128 } |
| 129 | 129 |
| 130 | 130 |
| 131 const char* ProfileFunction::KindToCString(Kind kind) { | 131 const char* ProfileFunction::KindToCString(Kind kind) { |
| 132 switch (kind) { | 132 switch (kind) { |
| 133 case kDartFunction: | 133 case kDartFunction: |
| 134 return "Dart"; | 134 return "Dart"; |
| 135 case kNativeFunction: | 135 case kNativeFunction: |
| 136 return "Native"; | 136 return "Native"; |
| 137 case kTagFunction: | 137 case kTagFunction: |
| (...skipping 818 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 956 Profile* profile) | 956 Profile* profile) |
| 957 : isolate_(isolate), | 957 : isolate_(isolate), |
| 958 vm_isolate_(Dart::vm_isolate()), | 958 vm_isolate_(Dart::vm_isolate()), |
| 959 filter_(filter), | 959 filter_(filter), |
| 960 tag_order_(tag_order), | 960 tag_order_(tag_order), |
| 961 profile_(profile), | 961 profile_(profile), |
| 962 deoptimized_code_(new DeoptimizedCodeSet(isolate)), | 962 deoptimized_code_(new DeoptimizedCodeSet(isolate)), |
| 963 null_code_(Code::ZoneHandle()), | 963 null_code_(Code::ZoneHandle()), |
| 964 null_function_(Function::ZoneHandle()), | 964 null_function_(Function::ZoneHandle()), |
| 965 tick_functions_(false), | 965 tick_functions_(false), |
| 966 inclusive_tree_(false), |
| 966 samples_(NULL) { | 967 samples_(NULL) { |
| 967 ASSERT(profile_ != NULL); | 968 ASSERT(profile_ != NULL); |
| 968 } | 969 } |
| 969 | 970 |
| 970 void Build() { | 971 void Build() { |
| 971 ScopeTimer sw("ProfileBuilder::Build", FLAG_trace_profiler); | 972 ScopeTimer sw("ProfileBuilder::Build", FLAG_trace_profiler); |
| 972 FilterSamples(); | 973 FilterSamples(); |
| 973 | 974 |
| 974 Setup(); | 975 Setup(); |
| 975 BuildCodeTable(); | 976 BuildCodeTable(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 | 1023 |
| 1023 void UpdateMinMaxTimes(int64_t timestamp) { | 1024 void UpdateMinMaxTimes(int64_t timestamp) { |
| 1024 profile_->min_time_ = | 1025 profile_->min_time_ = |
| 1025 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_; | 1026 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_; |
| 1026 profile_->max_time_ = | 1027 profile_->max_time_ = |
| 1027 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_; | 1028 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_; |
| 1028 } | 1029 } |
| 1029 | 1030 |
| 1030 void BuildCodeTable() { | 1031 void BuildCodeTable() { |
| 1031 ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler); | 1032 ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler); |
| 1032 for (intptr_t i = 0; i < samples_->length(); i++) { | 1033 for (intptr_t sample_index = 0; |
| 1033 ProcessedSample* sample = samples_->At(i); | 1034 sample_index < samples_->length(); |
| 1035 sample_index++) { |
| 1036 ProcessedSample* sample = samples_->At(sample_index); |
| 1034 const int64_t timestamp = sample->timestamp(); | 1037 const int64_t timestamp = sample->timestamp(); |
| 1035 | 1038 |
| 1036 // This is our first pass over the sample buffer, use this as an | 1039 // This is our first pass over the sample buffer, use this as an |
| 1037 // opportunity to determine the min and max time ranges of this profile. | 1040 // opportunity to determine the min and max time ranges of this profile. |
| 1038 UpdateMinMaxTimes(timestamp); | 1041 UpdateMinMaxTimes(timestamp); |
| 1039 | 1042 |
| 1040 // Make sure VM tag exists. | 1043 // Make sure VM tag exists. |
| 1041 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | 1044 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { |
| 1042 RegisterProfileCodeTag(VMTag::kNativeTagId); | 1045 RegisterProfileCodeTag(VMTag::kNativeTagId); |
| 1043 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | 1046 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { |
| 1044 RegisterProfileCodeTag(VMTag::kRuntimeTagId); | 1047 RegisterProfileCodeTag(VMTag::kRuntimeTagId); |
| 1045 } | 1048 } |
| 1046 RegisterProfileCodeTag(sample->vm_tag()); | 1049 RegisterProfileCodeTag(sample->vm_tag()); |
| 1047 // Make sure user tag exists. | 1050 // Make sure user tag exists. |
| 1048 RegisterProfileCodeTag(sample->user_tag()); | 1051 RegisterProfileCodeTag(sample->user_tag()); |
| 1049 | 1052 |
| 1050 // Make sure that a ProfileCode objects exist for all pcs in the sample | 1053 // Make sure that a ProfileCode objects exist for all pcs in the sample |
| 1051 // and tick each one. | 1054 // and tick each one. |
| 1052 for (intptr_t j = 0; j < sample->length(); j++) { | 1055 for (intptr_t frame_index = 0; |
| 1053 const uword pc = sample->At(j); | 1056 frame_index < sample->length(); |
| 1057 frame_index++) { |
| 1058 const uword pc = sample->At(frame_index); |
| 1054 ASSERT(pc != 0); | 1059 ASSERT(pc != 0); |
| 1055 ProfileCode* code = RegisterProfileCode(pc, timestamp); | 1060 ProfileCode* code = RegisterProfileCode(pc, timestamp); |
| 1056 ASSERT(code != NULL); | 1061 ASSERT(code != NULL); |
| 1057 code->Tick(pc, IsExecutingFrame(sample, j), i); | 1062 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index); |
| 1058 } | 1063 } |
| 1059 } | 1064 } |
| 1060 } | 1065 } |
| 1061 | 1066 |
| 1062 void FinalizeCodeIndexes() { | 1067 void FinalizeCodeIndexes() { |
| 1063 ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler); | 1068 ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler); |
| 1064 ProfileCodeTable* live_table = profile_->live_code_; | 1069 ProfileCodeTable* live_table = profile_->live_code_; |
| 1065 ProfileCodeTable* dead_table = profile_->dead_code_; | 1070 ProfileCodeTable* dead_table = profile_->dead_code_; |
| 1066 ProfileCodeTable* tag_table = profile_->tag_code_; | 1071 ProfileCodeTable* tag_table = profile_->tag_code_; |
| 1067 const intptr_t dead_code_index_offset = live_table->length(); | 1072 const intptr_t dead_code_index_offset = live_table->length(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 for (intptr_t i = 0; i < tag_table->length(); i++) { | 1119 for (intptr_t i = 0; i < tag_table->length(); i++) { |
| 1115 ProfileCode* code = tag_table->At(i); | 1120 ProfileCode* code = tag_table->At(i); |
| 1116 ASSERT(code != NULL); | 1121 ASSERT(code != NULL); |
| 1117 code->SetFunctionAndName(function_table); | 1122 code->SetFunctionAndName(function_table); |
| 1118 } | 1123 } |
| 1119 } | 1124 } |
| 1120 | 1125 |
| 1121 void BuildCodeTrie(Profile::TrieKind kind) { | 1126 void BuildCodeTrie(Profile::TrieKind kind) { |
| 1122 ProfileCodeTrieNode* root = | 1127 ProfileCodeTrieNode* root = |
| 1123 new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId)); | 1128 new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId)); |
| 1124 if (IsInclusiveTrie(kind)) { | 1129 inclusive_tree_ = IsInclusiveTrie(kind); |
| 1130 if (inclusive_tree_) { |
| 1125 BuildInclusiveCodeTrie(root); | 1131 BuildInclusiveCodeTrie(root); |
| 1126 } else { | 1132 } else { |
| 1127 BuildExclusiveCodeTrie(root); | 1133 BuildExclusiveCodeTrie(root); |
| 1128 } | 1134 } |
| 1129 root->SortChildren(); | 1135 root->SortChildren(); |
| 1130 profile_->roots_[static_cast<intptr_t>(kind)] = root; | 1136 profile_->roots_[static_cast<intptr_t>(kind)] = root; |
| 1131 } | 1137 } |
| 1132 | 1138 |
| 1133 void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) { | 1139 void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) { |
| 1134 ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie", | 1140 ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie", |
| 1135 FLAG_trace_profiler); | 1141 FLAG_trace_profiler); |
| 1136 for (intptr_t i = 0; i < samples_->length(); i++) { | 1142 for (intptr_t sample_index = 0; |
| 1137 ProcessedSample* sample = samples_->At(i); | 1143 sample_index < samples_->length(); |
| 1144 sample_index++) { |
| 1145 ProcessedSample* sample = samples_->At(sample_index); |
| 1138 | 1146 |
| 1139 // Tick the root. | 1147 // Tick the root. |
| 1140 ProfileCodeTrieNode* current = root; | 1148 ProfileCodeTrieNode* current = root; |
| 1141 current->Tick(); | 1149 current->Tick(); |
| 1142 | 1150 |
| 1143 // VM & User tags. | 1151 // VM & User tags. |
| 1144 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1152 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| 1145 | 1153 |
| 1146 // Truncated tag. | 1154 // Truncated tag. |
| 1147 if (sample->truncated()) { | 1155 if (sample->truncated()) { |
| 1148 current = AppendTruncatedTag(current); | 1156 current = AppendTruncatedTag(current); |
| 1149 } | 1157 } |
| 1150 | 1158 |
| 1151 // Walk the sampled PCs. | 1159 // Walk the sampled PCs. |
| 1152 for (intptr_t j = sample->length() - 1; j >= 0; j--) { | 1160 for (intptr_t frame_index = sample->length() - 1; |
| 1153 ASSERT(sample->At(j) != 0); | 1161 frame_index >= 0; |
| 1162 frame_index--) { |
| 1163 ASSERT(sample->At(frame_index) != 0); |
| 1154 intptr_t index = | 1164 intptr_t index = |
| 1155 GetProfileCodeIndex(sample->At(j), sample->timestamp()); | 1165 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
| 1156 ASSERT(index >= 0); | 1166 ASSERT(index >= 0); |
| 1157 current = current->GetChild(index); | 1167 current = current->GetChild(index); |
| 1158 current->Tick(); | 1168 current->Tick(); |
| 1159 } | 1169 } |
| 1160 } | 1170 } |
| 1161 } | 1171 } |
| 1162 | 1172 |
| 1163 void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) { | 1173 void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) { |
| 1164 ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie", | 1174 ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie", |
| 1165 FLAG_trace_profiler); | 1175 FLAG_trace_profiler); |
| 1166 for (intptr_t i = 0; i < samples_->length(); i++) { | 1176 for (intptr_t sample_index = 0; |
| 1167 ProcessedSample* sample = samples_->At(i); | 1177 sample_index < samples_->length(); |
| 1178 sample_index++) { |
| 1179 ProcessedSample* sample = samples_->At(sample_index); |
| 1168 | 1180 |
| 1169 // Tick the root. | 1181 // Tick the root. |
| 1170 ProfileCodeTrieNode* current = root; | 1182 ProfileCodeTrieNode* current = root; |
| 1171 current->Tick(); | 1183 current->Tick(); |
| 1172 | 1184 |
| 1173 // VM & User tags. | 1185 // VM & User tags. |
| 1174 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1186 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| 1175 | 1187 |
| 1176 // Walk the sampled PCs. | 1188 // Walk the sampled PCs. |
| 1177 for (intptr_t j = 0; j < sample->length(); j++) { | 1189 for (intptr_t frame_index = 0; |
| 1178 ASSERT(sample->At(j) != 0); | 1190 frame_index < sample->length(); |
| 1191 frame_index++) { |
| 1192 ASSERT(sample->At(frame_index) != 0); |
| 1179 intptr_t index = | 1193 intptr_t index = |
| 1180 GetProfileCodeIndex(sample->At(j), sample->timestamp()); | 1194 GetProfileCodeIndex(sample->At(frame_index), sample->timestamp()); |
| 1181 ASSERT(index >= 0); | 1195 ASSERT(index >= 0); |
| 1182 current = current->GetChild(index); | 1196 current = current->GetChild(index); |
| 1183 current->Tick(); | 1197 current->Tick(); |
| 1184 } | 1198 } |
| 1185 | 1199 |
| 1186 // Truncated tag. | 1200 // Truncated tag. |
| 1187 if (sample->truncated()) { | 1201 if (sample->truncated()) { |
| 1188 current = AppendTruncatedTag(current); | 1202 current = AppendTruncatedTag(current); |
| 1189 } | 1203 } |
| 1190 } | 1204 } |
| 1191 } | 1205 } |
| 1192 | 1206 |
| 1193 void BuildFunctionTrie(Profile::TrieKind kind) { | 1207 void BuildFunctionTrie(Profile::TrieKind kind) { |
| 1194 ProfileFunctionTrieNode* root = | 1208 ProfileFunctionTrieNode* root = |
| 1195 new ProfileFunctionTrieNode( | 1209 new ProfileFunctionTrieNode( |
| 1196 GetProfileFunctionTagIndex(VMTag::kRootTagId)); | 1210 GetProfileFunctionTagIndex(VMTag::kRootTagId)); |
| 1197 // We tick the functions while building the trie, but, we don't want to do | 1211 // We tick the functions while building the trie, but, we don't want to do |
| 1198 // it for both tries, just one. | 1212 // it for both tries, just the exclusive trie. |
| 1199 tick_functions_ = IsInclusiveTrie(kind); | 1213 inclusive_tree_ = IsInclusiveTrie(kind); |
| 1200 if (IsInclusiveTrie(kind)) { | 1214 tick_functions_ = !inclusive_tree_; |
| 1215 if (inclusive_tree_) { |
| 1201 BuildInclusiveFunctionTrie(root); | 1216 BuildInclusiveFunctionTrie(root); |
| 1202 } else { | 1217 } else { |
| 1203 BuildExclusiveFunctionTrie(root); | 1218 BuildExclusiveFunctionTrie(root); |
| 1204 } | 1219 } |
| 1205 root->SortChildren(); | 1220 root->SortChildren(); |
| 1206 profile_->roots_[static_cast<intptr_t>(kind)] = root; | 1221 profile_->roots_[static_cast<intptr_t>(kind)] = root; |
| 1207 } | 1222 } |
| 1208 | 1223 |
| 1209 void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) { | 1224 void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) { |
| 1210 ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie", | 1225 ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie", |
| 1211 FLAG_trace_profiler); | 1226 FLAG_trace_profiler); |
| 1212 for (intptr_t i = 0; i < samples_->length(); i++) { | 1227 for (intptr_t sample_index = 0; |
| 1213 ProcessedSample* sample = samples_->At(i); | 1228 sample_index < samples_->length(); |
| 1229 sample_index++) { |
| 1230 ProcessedSample* sample = samples_->At(sample_index); |
| 1214 | 1231 |
| 1215 // Tick the root. | 1232 // Tick the root. |
| 1216 ProfileFunctionTrieNode* current = root; | 1233 ProfileFunctionTrieNode* current = root; |
| 1217 current->Tick(); | 1234 current->Tick(); |
| 1218 | 1235 |
| 1219 // VM & User tags. | 1236 // VM & User tags. |
| 1220 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1237 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| 1221 | 1238 |
| 1222 // Truncated tag. | 1239 // Truncated tag. |
| 1223 if (sample->truncated()) { | 1240 if (sample->truncated()) { |
| 1224 current = AppendTruncatedTag(current); | 1241 current = AppendTruncatedTag(current); |
| 1225 InclusiveTickTruncatedTag(); | |
| 1226 } | 1242 } |
| 1227 | 1243 |
| 1228 // Walk the sampled PCs. | 1244 // Walk the sampled PCs. |
| 1229 for (intptr_t j = sample->length() - 1; j >= 0; j--) { | 1245 for (intptr_t frame_index = sample->length() - 1; |
| 1230 ASSERT(sample->At(j) != 0); | 1246 frame_index >= 0; |
| 1231 current = ProcessFunctionPC( | 1247 frame_index--) { |
| 1232 sample->At(j), | 1248 ASSERT(sample->At(frame_index) != 0); |
| 1233 sample->timestamp(), | 1249 current = ProcessFrame(current, sample_index, sample, frame_index); |
| 1234 current, | |
| 1235 i, | |
| 1236 (j == 0), | |
| 1237 sample->first_frame_executing() || sample->IsAllocationSample(), | |
| 1238 true); | |
| 1239 } | 1250 } |
| 1240 } | 1251 } |
| 1241 } | 1252 } |
| 1242 | 1253 |
| 1243 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { | 1254 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) { |
| 1244 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", | 1255 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie", |
| 1245 FLAG_trace_profiler); | 1256 FLAG_trace_profiler); |
| 1246 for (intptr_t i = 0; i < samples_->length(); i++) { | 1257 for (intptr_t sample_index = 0; |
| 1247 ProcessedSample* sample = samples_->At(i); | 1258 sample_index < samples_->length(); |
| 1259 sample_index++) { |
| 1260 ProcessedSample* sample = samples_->At(sample_index); |
| 1248 | 1261 |
| 1249 // Tick the root. | 1262 // Tick the root. |
| 1250 ProfileFunctionTrieNode* current = root; | 1263 ProfileFunctionTrieNode* current = root; |
| 1251 current->Tick(); | 1264 current->Tick(); |
| 1252 | 1265 |
| 1253 // VM & User tags. | 1266 // VM & User tags. |
| 1254 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); | 1267 current = AppendTags(sample->vm_tag(), sample->user_tag(), current); |
| 1255 | 1268 |
| 1256 // Walk the sampled PCs. | 1269 // Walk the sampled PCs. |
| 1257 for (intptr_t j = 0; j < sample->length(); j++) { | 1270 for (intptr_t frame_index = 0; |
| 1258 ASSERT(sample->At(j) != 0); | 1271 frame_index < sample->length(); |
| 1259 current = ProcessFunctionPC( | 1272 frame_index++) { |
| 1260 sample->At(j), | 1273 ASSERT(sample->At(frame_index) != 0); |
| 1261 sample->timestamp(), | 1274 current = ProcessFrame(current, sample_index, sample, frame_index); |
| 1262 current, | |
| 1263 i, | |
| 1264 (j == 0), | |
| 1265 sample->first_frame_executing() || sample->IsAllocationSample(), | |
| 1266 false); | |
| 1267 } | 1275 } |
| 1268 | 1276 |
| 1269 // Truncated tag. | 1277 // Truncated tag. |
| 1270 if (sample->truncated()) { | 1278 if (sample->truncated()) { |
| 1271 current = AppendTruncatedTag(current); | 1279 current = AppendTruncatedTag(current); |
| 1280 InclusiveTickTruncatedTag(); |
| 1272 } | 1281 } |
| 1273 } | 1282 } |
| 1274 } | 1283 } |
| 1275 | 1284 |
| 1276 ProfileFunctionTrieNode* ProcessFunctionPC( | 1285 ProfileFunctionTrieNode* ProcessFrame( |
| 1277 uword pc, | |
| 1278 int64_t timestamp, | |
| 1279 ProfileFunctionTrieNode* current, | 1286 ProfileFunctionTrieNode* current, |
| 1280 intptr_t inclusive_serial, | 1287 intptr_t sample_index, |
| 1281 bool top_frame, | 1288 ProcessedSample* sample, |
| 1282 bool top_frame_executing, | 1289 intptr_t frame_index) { |
| 1283 bool inclusive_tree) { | 1290 const uword pc = sample->At(frame_index); |
| 1284 ProfileCode* profile_code = GetProfileCode(pc, timestamp); | 1291 ProfileCode* profile_code = GetProfileCode(pc, |
| 1292 sample->timestamp()); |
| 1285 ASSERT(profile_code != NULL); | 1293 ASSERT(profile_code != NULL); |
| 1286 const char* code_name = profile_code->name(); | |
| 1287 if (code_name == NULL) { | |
| 1288 code_name = ""; | |
| 1289 } | |
| 1290 intptr_t code_index = profile_code->code_table_index(); | |
| 1291 const Code& code = Code::ZoneHandle(profile_code->code()); | 1294 const Code& code = Code::ZoneHandle(profile_code->code()); |
| 1292 GrowableArray<Function*> inlined_functions; | 1295 GrowableArray<Function*> inlined_functions; |
| 1293 if (!code.IsNull()) { | 1296 if (!code.IsNull()) { |
| 1294 intptr_t offset = pc - code.EntryPoint(); | 1297 intptr_t offset = pc - code.EntryPoint(); |
| 1295 code.GetInlinedFunctionsAt(offset, &inlined_functions); | 1298 code.GetInlinedFunctionsAt(offset, &inlined_functions); |
| 1296 } | 1299 } |
| 1297 if (code.IsNull() || (inlined_functions.length() == 0)) { | 1300 if (code.IsNull() || (inlined_functions.length() == 0)) { |
| 1298 // No inlined functions. | 1301 // No inlined functions. |
| 1299 ProfileFunction* function = profile_code->function(); | 1302 ProfileFunction* function = profile_code->function(); |
| 1300 ASSERT(function != NULL); | 1303 ASSERT(function != NULL); |
| 1301 current = ProcessFunction(function, | 1304 current = ProcessFunction(current, |
| 1302 current, | 1305 sample_index, |
| 1303 inclusive_serial, | 1306 sample, |
| 1304 top_frame, | 1307 frame_index, |
| 1305 top_frame_executing, | 1308 function); |
| 1306 code_index); | |
| 1307 return current; | 1309 return current; |
| 1308 } | 1310 } |
| 1309 | 1311 |
| 1310 if (inclusive_tree) { | 1312 if (inclusive_tree_) { |
| 1311 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { | 1313 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { |
| 1312 Function* inlined_function = inlined_functions[i]; | 1314 Function* inlined_function = inlined_functions[i]; |
| 1313 ASSERT(inlined_function != NULL); | 1315 ASSERT(inlined_function != NULL); |
| 1314 ASSERT(!inlined_function->IsNull()); | 1316 ASSERT(!inlined_function->IsNull()); |
| 1315 current = ProcessInlinedFunction(inlined_function, | 1317 current = ProcessInlinedFunction(current, |
| 1316 current, | 1318 sample_index, |
| 1317 inclusive_serial, | 1319 sample, |
| 1318 top_frame, | 1320 frame_index, |
| 1319 top_frame_executing, | 1321 inlined_function); |
| 1320 code_index); | |
| 1321 top_frame = false; | |
| 1322 } | 1322 } |
| 1323 } else { | 1323 } else { |
| 1324 for (intptr_t i = 0; i < inlined_functions.length(); i++) { | 1324 for (intptr_t i = 0; i < inlined_functions.length(); i++) { |
| 1325 Function* inlined_function = inlined_functions[i]; | 1325 Function* inlined_function = inlined_functions[i]; |
| 1326 ASSERT(inlined_function != NULL); | 1326 ASSERT(inlined_function != NULL); |
| 1327 ASSERT(!inlined_function->IsNull()); | 1327 ASSERT(!inlined_function->IsNull()); |
| 1328 current = ProcessInlinedFunction(inlined_function, | 1328 current = ProcessInlinedFunction(current, |
| 1329 current, | 1329 sample_index, |
| 1330 inclusive_serial, | 1330 sample, |
| 1331 top_frame, | 1331 frame_index + i, |
| 1332 top_frame_executing, | 1332 inlined_function); |
| 1333 code_index); | |
| 1334 top_frame = false; | |
| 1335 } | 1333 } |
| 1336 } | 1334 } |
| 1337 | 1335 |
| 1338 return current; | 1336 return current; |
| 1339 } | 1337 } |
| 1340 | 1338 |
| 1341 ProfileFunctionTrieNode* ProcessInlinedFunction( | 1339 ProfileFunctionTrieNode* ProcessInlinedFunction( |
| 1342 Function* inlined_function, | |
| 1343 ProfileFunctionTrieNode* current, | 1340 ProfileFunctionTrieNode* current, |
| 1344 intptr_t inclusive_serial, | 1341 intptr_t sample_index, |
| 1345 bool top_frame, | 1342 ProcessedSample* sample, |
| 1346 bool top_frame_executing, | 1343 intptr_t frame_index, |
| 1347 intptr_t code_index) { | 1344 Function* inlined_function) { |
| 1348 ProfileFunctionTable* function_table = profile_->functions_; | 1345 ProfileFunctionTable* function_table = profile_->functions_; |
| 1349 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); | 1346 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function); |
| 1350 ASSERT(function != NULL); | 1347 ASSERT(function != NULL); |
| 1351 return ProcessFunction(function, | 1348 return ProcessFunction(current, |
| 1352 current, | 1349 sample_index, |
| 1353 inclusive_serial, | 1350 sample, |
| 1354 top_frame, | 1351 frame_index, |
| 1355 top_frame_executing, | 1352 function); |
| 1356 code_index); | |
| 1357 } | 1353 } |
| 1358 | 1354 |
| 1359 ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function, | 1355 ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current, |
| 1360 ProfileFunctionTrieNode* current, | 1356 intptr_t sample_index, |
| 1361 intptr_t inclusive_serial, | 1357 ProcessedSample* sample, |
| 1362 bool top_frame, | 1358 intptr_t frame_index, |
| 1363 bool top_frame_executing, | 1359 ProfileFunction* function) { |
| 1364 intptr_t code_index) { | |
| 1365 const bool exclusive = top_frame && top_frame_executing; | |
| 1366 if (tick_functions_) { | 1360 if (tick_functions_) { |
| 1367 function->Tick(exclusive, exclusive ? -1 : inclusive_serial); | 1361 function->Tick(IsExecutingFrame(sample, frame_index), sample_index); |
| 1368 } | 1362 } |
| 1369 function->AddProfileCode(code_index); | |
| 1370 current = current->GetChild(function->table_index()); | 1363 current = current->GetChild(function->table_index()); |
| 1371 current->AddCodeObjectIndex(code_index); | 1364 current->Tick(); |
| 1372 if (top_frame) { | |
| 1373 if (top_frame_executing || vm_tags_emitted()) { | |
| 1374 // Only tick if this function is using CPU time or VM tags are emitted. | |
| 1375 current->Tick(); | |
| 1376 } | |
| 1377 } else { | |
| 1378 current->Tick(); | |
| 1379 } | |
| 1380 return current; | 1365 return current; |
| 1381 } | 1366 } |
| 1382 | 1367 |
| 1383 // Tick the truncated tag's inclusive tick count. | 1368 // Tick the truncated tag's inclusive tick count. |
| 1384 void InclusiveTickTruncatedTag() { | 1369 void InclusiveTickTruncatedTag() { |
| 1385 ProfileCodeTable* tag_table = profile_->tag_code_; | 1370 ProfileCodeTable* tag_table = profile_->tag_code_; |
| 1386 intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId); | 1371 intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId); |
| 1387 ASSERT(index >= 0); | 1372 ASSERT(index >= 0); |
| 1388 ProfileCode* code = tag_table->At(index); | 1373 ProfileCode* code = tag_table->At(index); |
| 1389 code->IncInclusiveTicks(); | 1374 code->IncInclusiveTicks(); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1503 ProfileFunctionTrieNode* current) { | 1488 ProfileFunctionTrieNode* current) { |
| 1504 intptr_t truncated_tag_index = | 1489 intptr_t truncated_tag_index = |
| 1505 GetProfileFunctionTagIndex(VMTag::kTruncatedTagId); | 1490 GetProfileFunctionTagIndex(VMTag::kTruncatedTagId); |
| 1506 ASSERT(truncated_tag_index >= 0); | 1491 ASSERT(truncated_tag_index >= 0); |
| 1507 current = current->GetChild(truncated_tag_index); | 1492 current = current->GetChild(truncated_tag_index); |
| 1508 current->Tick(); | 1493 current->Tick(); |
| 1509 return current; | 1494 return current; |
| 1510 } | 1495 } |
| 1511 | 1496 |
| 1512 ProfileFunctionTrieNode* AppendVMTag(uword vm_tag, | 1497 ProfileFunctionTrieNode* AppendVMTag(uword vm_tag, |
| 1513 ProfileFunctionTrieNode* current) { | 1498 ProfileFunctionTrieNode* current) { |
| 1514 if (VMTag::IsNativeEntryTag(vm_tag)) { | 1499 if (VMTag::IsNativeEntryTag(vm_tag)) { |
| 1515 // Insert a dummy kNativeTagId node. | 1500 // Insert a dummy kNativeTagId node. |
| 1516 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId); | 1501 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId); |
| 1517 current = current->GetChild(tag_index); | 1502 current = current->GetChild(tag_index); |
| 1518 // Give the tag a tick. | 1503 // Give the tag a tick. |
| 1519 current->Tick(); | 1504 current->Tick(); |
| 1520 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) { | 1505 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) { |
| 1521 // Insert a dummy kRuntimeTagId node. | 1506 // Insert a dummy kRuntimeTagId node. |
| 1522 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId); | 1507 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId); |
| 1523 current = current->GetChild(tag_index); | 1508 current = current->GetChild(tag_index); |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 | 1759 |
| 1775 Isolate* isolate_; | 1760 Isolate* isolate_; |
| 1776 Isolate* vm_isolate_; | 1761 Isolate* vm_isolate_; |
| 1777 SampleFilter* filter_; | 1762 SampleFilter* filter_; |
| 1778 Profile::TagOrder tag_order_; | 1763 Profile::TagOrder tag_order_; |
| 1779 Profile* profile_; | 1764 Profile* profile_; |
| 1780 DeoptimizedCodeSet* deoptimized_code_; | 1765 DeoptimizedCodeSet* deoptimized_code_; |
| 1781 const Code& null_code_; | 1766 const Code& null_code_; |
| 1782 const Function& null_function_; | 1767 const Function& null_function_; |
| 1783 bool tick_functions_; | 1768 bool tick_functions_; |
| 1769 bool inclusive_tree_; |
| 1784 | 1770 |
| 1785 ProcessedSampleBuffer* samples_; | 1771 ProcessedSampleBuffer* samples_; |
| 1786 }; | 1772 }; |
| 1787 | 1773 |
| 1788 | 1774 |
| 1789 Profile::Profile(Isolate* isolate) | 1775 Profile::Profile(Isolate* isolate) |
| 1790 : isolate_(isolate), | 1776 : isolate_(isolate), |
| 1791 live_code_(NULL), | 1777 live_code_(NULL), |
| 1792 dead_code_(NULL), | 1778 dead_code_(NULL), |
| 1793 tag_code_(NULL), | 1779 tag_code_(NULL), |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2089 ASSERT(sample_buffer != NULL); | 2075 ASSERT(sample_buffer != NULL); |
| 2090 | 2076 |
| 2091 ClearProfileVisitor clear_profile(isolate); | 2077 ClearProfileVisitor clear_profile(isolate); |
| 2092 sample_buffer->VisitSamples(&clear_profile); | 2078 sample_buffer->VisitSamples(&clear_profile); |
| 2093 | 2079 |
| 2094 // Enable profile interrupts. | 2080 // Enable profile interrupts. |
| 2095 Profiler::BeginExecution(isolate); | 2081 Profiler::BeginExecution(isolate); |
| 2096 } | 2082 } |
| 2097 | 2083 |
| 2098 } // namespace dart | 2084 } // namespace dart |
| OLD | NEW |