| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "platform/utils.h" | 5 #include "platform/utils.h" |
| 6 | 6 |
| 7 #include "vm/allocation.h" | 7 #include "vm/allocation.h" |
| 8 #include "vm/atomic.h" | 8 #include "vm/atomic.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| (...skipping 1113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 dead_code_table_->Length(); | 1124 dead_code_table_->Length(); |
| 1125 intptr_t root_index = tag_code_table_->FindIndex(0); | 1125 intptr_t root_index = tag_code_table_->FindIndex(0); |
| 1126 // Verify that the "0" tag does not exist. | 1126 // Verify that the "0" tag does not exist. |
| 1127 ASSERT(root_index < 0); | 1127 ASSERT(root_index < 0); |
| 1128 // Insert the dummy tag CodeRegion that is used for the Trie root. | 1128 // Insert the dummy tag CodeRegion that is used for the Trie root. |
| 1129 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0); | 1129 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0); |
| 1130 root_index = tag_code_table_->InsertCodeRegion(region); | 1130 root_index = tag_code_table_->InsertCodeRegion(region); |
| 1131 ASSERT(root_index >= 0); | 1131 ASSERT(root_index >= 0); |
| 1132 region->set_creation_serial(0); | 1132 region->set_creation_serial(0); |
| 1133 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); | 1133 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); |
| 1134 // Use tags by default. | 1134 set_tag_order(Profiler::kUserVM); |
| 1135 set_use_tags(true); | |
| 1136 } | 1135 } |
| 1137 | 1136 |
| 1138 void VisitSample(Sample* sample) { | 1137 void VisitSample(Sample* sample) { |
| 1139 // Give the root a tick. | 1138 // Give the root a tick. |
| 1140 root_->Tick(); | 1139 root_->Tick(); |
| 1141 CodeRegionTrieNode* current = root_; | 1140 CodeRegionTrieNode* current = root_; |
| 1142 if (use_tags()) { | 1141 current = ProcessTags(sample, current); |
| 1143 intptr_t user_tag_index = FindTagIndex(sample->user_tag()); | |
| 1144 if (user_tag_index >= 0) { | |
| 1145 current = current->GetChild(user_tag_index); | |
| 1146 // Give the tag a tick. | |
| 1147 current->Tick(); | |
| 1148 } | |
| 1149 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | |
| 1150 // Insert a dummy kNativeTagId node. | |
| 1151 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId); | |
| 1152 current = current->GetChild(tag_index); | |
| 1153 // Give the tag a tick. | |
| 1154 current->Tick(); | |
| 1155 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | |
| 1156 // Insert a dummy kRuntimeTagId node. | |
| 1157 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId); | |
| 1158 current = current->GetChild(tag_index); | |
| 1159 // Give the tag a tick. | |
| 1160 current->Tick(); | |
| 1161 } | |
| 1162 intptr_t tag_index = FindTagIndex(sample->vm_tag()); | |
| 1163 current = current->GetChild(tag_index); | |
| 1164 // Give the tag a tick. | |
| 1165 current->Tick(); | |
| 1166 } | |
| 1167 // Walk the sampled PCs. | 1142 // Walk the sampled PCs. |
| 1168 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 1143 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 1169 if (sample->At(i) == 0) { | 1144 if (sample->At(i) == 0) { |
| 1170 break; | 1145 break; |
| 1171 } | 1146 } |
| 1172 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); | 1147 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); |
| 1173 current = current->GetChild(index); | 1148 current = current->GetChild(index); |
| 1174 current->Tick(); | 1149 current->Tick(); |
| 1175 } | 1150 } |
| 1176 } | 1151 } |
| 1177 | 1152 |
| 1178 CodeRegionTrieNode* root() const { | 1153 CodeRegionTrieNode* root() const { |
| 1179 return root_; | 1154 return root_; |
| 1180 } | 1155 } |
| 1181 | 1156 |
| 1182 bool use_tags() const { | 1157 Profiler::TagOrder tag_order() const { |
| 1183 return use_tags_; | 1158 return tag_order_; |
| 1184 } | 1159 } |
| 1185 | 1160 |
| 1186 void set_use_tags(bool use_tags) { | 1161 void set_tag_order(Profiler::TagOrder tag_order) { |
| 1187 use_tags_ = use_tags; | 1162 tag_order_ = tag_order; |
| 1188 } | 1163 } |
| 1189 | 1164 |
| 1190 private: | 1165 private: |
| 1166 CodeRegionTrieNode* ProcessUserTags(Sample* sample, |
| 1167 CodeRegionTrieNode* current) { |
| 1168 intptr_t user_tag_index = FindTagIndex(sample->user_tag()); |
| 1169 if (user_tag_index >= 0) { |
| 1170 current = current->GetChild(user_tag_index); |
| 1171 // Give the tag a tick. |
| 1172 current->Tick(); |
| 1173 } |
| 1174 return current; |
| 1175 } |
| 1176 |
| 1177 CodeRegionTrieNode* ProcessVMTags(Sample* sample, |
| 1178 CodeRegionTrieNode* current) { |
| 1179 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { |
| 1180 // Insert a dummy kNativeTagId node. |
| 1181 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId); |
| 1182 current = current->GetChild(tag_index); |
| 1183 // Give the tag a tick. |
| 1184 current->Tick(); |
| 1185 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { |
| 1186 // Insert a dummy kRuntimeTagId node. |
| 1187 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId); |
| 1188 current = current->GetChild(tag_index); |
| 1189 // Give the tag a tick. |
| 1190 current->Tick(); |
| 1191 } |
| 1192 intptr_t tag_index = FindTagIndex(sample->vm_tag()); |
| 1193 current = current->GetChild(tag_index); |
| 1194 // Give the tag a tick. |
| 1195 current->Tick(); |
| 1196 return current; |
| 1197 } |
| 1198 |
| 1199 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) { |
| 1200 // None. |
| 1201 if (tag_order() == Profiler::kNoTags) { |
| 1202 return current; |
| 1203 } |
| 1204 // User first. |
| 1205 if ((tag_order() == Profiler::kUserVM) || |
| 1206 (tag_order() == Profiler::kUser)) { |
| 1207 current = ProcessUserTags(sample, current); |
| 1208 // Only user. |
| 1209 if (tag_order() == Profiler::kUser) { |
| 1210 return current; |
| 1211 } |
| 1212 return ProcessVMTags(sample, current); |
| 1213 } |
| 1214 // VM first. |
| 1215 ASSERT((tag_order() == Profiler::kVMUser) || |
| 1216 (tag_order() == Profiler::kVM)); |
| 1217 current = ProcessVMTags(sample, current); |
| 1218 // Only VM. |
| 1219 if (tag_order() == Profiler::kVM) { |
| 1220 return current; |
| 1221 } |
| 1222 return ProcessUserTags(sample, current); |
| 1223 } |
| 1224 |
| 1191 intptr_t FindTagIndex(uword tag) const { | 1225 intptr_t FindTagIndex(uword tag) const { |
| 1192 if (tag == 0) { | 1226 if (tag == 0) { |
| 1193 return -1; | 1227 return -1; |
| 1194 } | 1228 } |
| 1195 intptr_t index = tag_code_table_->FindIndex(tag); | 1229 intptr_t index = tag_code_table_->FindIndex(tag); |
| 1196 if (index <= 0) { | 1230 if (index <= 0) { |
| 1197 return -1; | 1231 return -1; |
| 1198 } | 1232 } |
| 1199 ASSERT(index >= 0); | 1233 ASSERT(index >= 0); |
| 1200 ASSERT((tag_code_table_->At(index))->contains(tag)); | 1234 ASSERT((tag_code_table_->At(index))->contains(tag)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1212 ASSERT(index >= 0); | 1246 ASSERT(index >= 0); |
| 1213 region = dead_code_table_->At(index); | 1247 region = dead_code_table_->At(index); |
| 1214 ASSERT(region->contains(pc)); | 1248 ASSERT(region->contains(pc)); |
| 1215 ASSERT(region->compile_timestamp() <= timestamp); | 1249 ASSERT(region->compile_timestamp() <= timestamp); |
| 1216 return index + dead_code_table_offset_; | 1250 return index + dead_code_table_offset_; |
| 1217 } | 1251 } |
| 1218 ASSERT(region->compile_timestamp() <= timestamp); | 1252 ASSERT(region->compile_timestamp() <= timestamp); |
| 1219 return index; | 1253 return index; |
| 1220 } | 1254 } |
| 1221 | 1255 |
| 1222 bool use_tags_; | 1256 Profiler::TagOrder tag_order_; |
| 1223 CodeRegionTrieNode* root_; | 1257 CodeRegionTrieNode* root_; |
| 1224 CodeRegionTable* live_code_table_; | 1258 CodeRegionTable* live_code_table_; |
| 1225 CodeRegionTable* dead_code_table_; | 1259 CodeRegionTable* dead_code_table_; |
| 1226 CodeRegionTable* tag_code_table_; | 1260 CodeRegionTable* tag_code_table_; |
| 1227 intptr_t dead_code_table_offset_; | 1261 intptr_t dead_code_table_offset_; |
| 1228 intptr_t tag_code_table_offset_; | 1262 intptr_t tag_code_table_offset_; |
| 1229 }; | 1263 }; |
| 1230 | 1264 |
| 1231 | 1265 |
| 1232 class CodeRegionTableCallersBuilder { | 1266 class CodeRegionTableCallersBuilder { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 CodeRegionTrieNode* exclusive_root_; | 1319 CodeRegionTrieNode* exclusive_root_; |
| 1286 CodeRegionTable* live_code_table_; | 1320 CodeRegionTable* live_code_table_; |
| 1287 CodeRegionTable* dead_code_table_; | 1321 CodeRegionTable* dead_code_table_; |
| 1288 CodeRegionTable* tag_code_table_; | 1322 CodeRegionTable* tag_code_table_; |
| 1289 intptr_t dead_code_table_offset_; | 1323 intptr_t dead_code_table_offset_; |
| 1290 intptr_t tag_code_table_offset_; | 1324 intptr_t tag_code_table_offset_; |
| 1291 }; | 1325 }; |
| 1292 | 1326 |
| 1293 | 1327 |
| 1294 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | 1328 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 1295 bool full, bool use_tags) { | 1329 bool full, TagOrder tag_order) { |
| 1296 ASSERT(isolate == Isolate::Current()); | 1330 ASSERT(isolate == Isolate::Current()); |
| 1297 // Disable profile interrupts while processing the buffer. | 1331 // Disable profile interrupts while processing the buffer. |
| 1298 EndExecution(isolate); | 1332 EndExecution(isolate); |
| 1299 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 1333 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 1300 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 1334 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 1301 if (profiler_data == NULL) { | 1335 if (profiler_data == NULL) { |
| 1302 JSONObject error(stream); | 1336 JSONObject error(stream); |
| 1303 error.AddProperty("type", "Error"); | 1337 error.AddProperty("type", "Error"); |
| 1304 error.AddProperty("text", "Isolate does not have profiling enabled."); | 1338 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 1305 return; | 1339 return; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1341 dead_code_table.Verify(); | 1375 dead_code_table.Verify(); |
| 1342 tag_code_table.Verify(); | 1376 tag_code_table.Verify(); |
| 1343 if (FLAG_trace_profiled_isolates) { | 1377 if (FLAG_trace_profiled_isolates) { |
| 1344 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); | 1378 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); |
| 1345 } | 1379 } |
| 1346 #endif | 1380 #endif |
| 1347 CodeRegionExclusiveTrieBuilder build_trie(isolate, | 1381 CodeRegionExclusiveTrieBuilder build_trie(isolate, |
| 1348 &live_code_table, | 1382 &live_code_table, |
| 1349 &dead_code_table, | 1383 &dead_code_table, |
| 1350 &tag_code_table); | 1384 &tag_code_table); |
| 1351 build_trie.set_use_tags(use_tags); | 1385 build_trie.set_tag_order(tag_order); |
| 1352 { | 1386 { |
| 1353 // Build CodeRegion trie. | 1387 // Build CodeRegion trie. |
| 1354 ScopeStopwatch sw("CodeRegionExclusiveTrieBuilder"); | 1388 ScopeStopwatch sw("CodeRegionExclusiveTrieBuilder"); |
| 1355 sample_buffer->VisitSamples(&build_trie); | 1389 sample_buffer->VisitSamples(&build_trie); |
| 1356 build_trie.root()->SortByCount(); | 1390 build_trie.root()->SortByCount(); |
| 1357 } | 1391 } |
| 1358 CodeRegionTableCallersBuilder build_callers(build_trie.root(), | 1392 CodeRegionTableCallersBuilder build_callers(build_trie.root(), |
| 1359 &live_code_table, | 1393 &live_code_table, |
| 1360 &dead_code_table, | 1394 &dead_code_table, |
| 1361 &tag_code_table); | 1395 &tag_code_table); |
| 1362 { | 1396 { |
| 1363 // Build CodeRegion callers. | 1397 // Build CodeRegion callers. |
| 1364 ScopeStopwatch sw("CodeRegionTableCallersBuilder"); | 1398 ScopeStopwatch sw("CodeRegionTableCallersBuilder"); |
| 1365 build_callers.Build(); | 1399 build_callers.Build(); |
| 1366 } | 1400 } |
| 1367 { | 1401 { |
| 1368 ScopeStopwatch sw("CodeTableStream"); | 1402 ScopeStopwatch sw("CodeTableStream"); |
| 1369 // Serialize to JSON. | 1403 // Serialize to JSON. |
| 1370 JSONObject obj(stream); | 1404 JSONObject obj(stream); |
| 1371 obj.AddProperty("type", "Profile"); | 1405 obj.AddProperty("type", "Profile"); |
| 1372 obj.AddProperty("id", "profile"); | 1406 obj.AddProperty("id", "profile"); |
| 1373 obj.AddProperty("samples", samples); | 1407 obj.AddProperty("samples", samples); |
| 1374 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth)); | 1408 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth)); |
| 1375 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period)); | 1409 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period)); |
| 1376 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros()); | 1410 obj.AddProperty("timeSpan", |
| 1411 MicrosecondsToSeconds(builder.TimeDeltaMicros())); |
| 1377 { | 1412 { |
| 1378 JSONArray exclusive_trie(&obj, "exclusive_trie"); | 1413 JSONArray exclusive_trie(&obj, "exclusive_trie"); |
| 1379 CodeRegionTrieNode* root = build_trie.root(); | 1414 CodeRegionTrieNode* root = build_trie.root(); |
| 1380 ASSERT(root != NULL); | 1415 ASSERT(root != NULL); |
| 1381 root->PrintToJSONArray(&exclusive_trie); | 1416 root->PrintToJSONArray(&exclusive_trie); |
| 1382 } | 1417 } |
| 1383 JSONArray codes(&obj, "codes"); | 1418 JSONArray codes(&obj, "codes"); |
| 1384 for (intptr_t i = 0; i < live_code_table.Length(); i++) { | 1419 for (intptr_t i = 0; i < live_code_table.Length(); i++) { |
| 1385 CodeRegion* region = live_code_table.At(i); | 1420 CodeRegion* region = live_code_table.At(i); |
| 1386 ASSERT(region != NULL); | 1421 ASSERT(region != NULL); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 1454 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
| 1420 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 1455 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
| 1421 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { | 1456 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { |
| 1422 // Embedder has not provided necessary callbacks. | 1457 // Embedder has not provided necessary callbacks. |
| 1423 return; | 1458 return; |
| 1424 } | 1459 } |
| 1425 // We will be looking up code objects within the isolate. | 1460 // We will be looking up code objects within the isolate. |
| 1426 ASSERT(Isolate::Current() == isolate); | 1461 ASSERT(Isolate::Current() == isolate); |
| 1427 JSONStream stream(10 * MB); | 1462 JSONStream stream(10 * MB); |
| 1428 intptr_t pid = OS::ProcessId(); | 1463 intptr_t pid = OS::ProcessId(); |
| 1429 PrintToJSONStream(isolate, &stream, true, false); | 1464 PrintToJSONStream(isolate, &stream, true, Profiler::kNoTags); |
| 1430 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; | 1465 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; |
| 1431 intptr_t len = OS::SNPrint(NULL, 0, format, | 1466 intptr_t len = OS::SNPrint(NULL, 0, format, |
| 1432 FLAG_profile_dir, pid, isolate->main_port()); | 1467 FLAG_profile_dir, pid, isolate->main_port()); |
| 1433 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 1468 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 1434 OS::SNPrint(filename, len + 1, format, | 1469 OS::SNPrint(filename, len + 1, format, |
| 1435 FLAG_profile_dir, pid, isolate->main_port()); | 1470 FLAG_profile_dir, pid, isolate->main_port()); |
| 1436 void* f = file_open(filename, true); | 1471 void* f = file_open(filename, true); |
| 1437 if (f == NULL) { | 1472 if (f == NULL) { |
| 1438 // Cannot write. | 1473 // Cannot write. |
| 1439 return; | 1474 return; |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1684 ProfilerDartStackWalker stackWalker(sample); | 1719 ProfilerDartStackWalker stackWalker(sample); |
| 1685 stackWalker.walk(); | 1720 stackWalker.walk(); |
| 1686 } else { | 1721 } else { |
| 1687 // TODO(johnmccutchan): Support collecting only Dart frames with | 1722 // TODO(johnmccutchan): Support collecting only Dart frames with |
| 1688 // ProfilerNativeStackWalker. | 1723 // ProfilerNativeStackWalker. |
| 1689 } | 1724 } |
| 1690 } | 1725 } |
| 1691 } | 1726 } |
| 1692 | 1727 |
| 1693 } // namespace dart | 1728 } // namespace dart |
| OLD | NEW |