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

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

Issue 864173008: Split profiler.cc into profiler.cc and profiler_service.cc (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, 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 "platform/address_sanitizer.h" 5 #include "vm/profiler_service.h"
6 #include "platform/memory_sanitizer.h"
7 #include "platform/utils.h"
8 6
9 #include "vm/allocation.h" 7 #include "vm/growable_array.h"
10 #include "vm/atomic.h"
11 #include "vm/code_patcher.h"
12 #include "vm/isolate.h"
13 #include "vm/json_stream.h"
14 #include "vm/lockers.h"
15 #include "vm/native_symbol.h" 8 #include "vm/native_symbol.h"
16 #include "vm/object.h" 9 #include "vm/object.h"
17 #include "vm/os.h" 10 #include "vm/os.h"
18 #include "vm/profiler.h" 11 #include "vm/profiler.h"
19 #include "vm/reusable_handles.h" 12 #include "vm/reusable_handles.h"
20 #include "vm/signal_handler.h" 13 #include "vm/scope_timer.h"
21 #include "vm/simulator.h"
22 #include "vm/stack_frame.h"
23 14
24 namespace dart { 15 namespace dart {
25 16
26 17 DECLARE_FLAG(int, profile_depth);
27 #if defined(TARGET_OS_ANDROID) || defined(HOST_ARCH_ARM64) 18 DECLARE_FLAG(bool, trace_profiler);
28 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); 19 DECLARE_FLAG(int, profile_period);
29 #else
30 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
31 #endif
32 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
33 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler.");
34 DEFINE_FLAG(int, profile_period, 1000,
35 "Time between profiler samples in microseconds. Minimum 50.");
36 DEFINE_FLAG(int, profile_depth, 8,
37 "Maximum number stack frames walked. Minimum 1. Maximum 255.");
38 #if defined(PROFILE_NATIVE_CODE) || defined(USING_SIMULATOR)
39 DEFINE_FLAG(bool, profile_vm, true,
40 "Always collect native stack traces.");
41 #else
42 DEFINE_FLAG(bool, profile_vm, false,
43 "Always collect native stack traces.");
44 #endif
45
46 bool Profiler::initialized_ = false;
47 SampleBuffer* Profiler::sample_buffer_ = NULL;
48
49 void Profiler::InitOnce() {
50 // Place some sane restrictions on user controlled flags.
51 SetSamplePeriod(FLAG_profile_period);
52 SetSampleDepth(FLAG_profile_depth);
53 Sample::InitOnce();
54 if (!FLAG_profile) {
55 return;
56 }
57 ASSERT(!initialized_);
58 sample_buffer_ = new SampleBuffer();
59 NativeSymbolResolver::InitOnce();
60 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period);
61 ThreadInterrupter::Startup();
62 initialized_ = true;
63 }
64
65
66 void Profiler::Shutdown() {
67 if (!FLAG_profile) {
68 return;
69 }
70 ASSERT(initialized_);
71 ThreadInterrupter::Shutdown();
72 NativeSymbolResolver::ShutdownOnce();
73 }
74
75
76 void Profiler::SetSampleDepth(intptr_t depth) {
77 const int kMinimumDepth = 1;
78 const int kMaximumDepth = 255;
79 if (depth < kMinimumDepth) {
80 FLAG_profile_depth = kMinimumDepth;
81 } else if (depth > kMaximumDepth) {
82 FLAG_profile_depth = kMaximumDepth;
83 } else {
84 FLAG_profile_depth = depth;
85 }
86 }
87
88
89 void Profiler::SetSamplePeriod(intptr_t period) {
90 const int kMinimumProfilePeriod = 50;
91 if (period < kMinimumProfilePeriod) {
92 FLAG_profile_period = kMinimumProfilePeriod;
93 } else {
94 FLAG_profile_period = period;
95 }
96 }
97
98
99 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
100 if (!FLAG_profile) {
101 return;
102 }
103 ASSERT(isolate == Isolate::Current());
104 ASSERT(isolate != NULL);
105 ASSERT(sample_buffer_ != NULL);
106 {
107 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
108 SampleBuffer* sample_buffer = sample_buffer_;
109 if (!shared_buffer) {
110 sample_buffer = new SampleBuffer();
111 }
112 IsolateProfilerData* profiler_data =
113 new IsolateProfilerData(sample_buffer, !shared_buffer);
114 ASSERT(profiler_data != NULL);
115 isolate->set_profiler_data(profiler_data);
116 if (FLAG_trace_profiled_isolates) {
117 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
118 }
119 }
120 BeginExecution(isolate);
121 }
122
123
124 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
125 ASSERT(isolate != NULL);
126 if (!FLAG_profile) {
127 return;
128 }
129 // We do not have a current isolate.
130 ASSERT(Isolate::Current() == NULL);
131 {
132 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
133 IsolateProfilerData* profiler_data = isolate->profiler_data();
134 if (profiler_data == NULL) {
135 // Already freed.
136 return;
137 }
138 isolate->set_profiler_data(NULL);
139 delete profiler_data;
140 if (FLAG_trace_profiled_isolates) {
141 OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
142 }
143 }
144 }
145
146
147 void Profiler::BeginExecution(Isolate* isolate) {
148 if (isolate == NULL) {
149 return;
150 }
151 if (!FLAG_profile) {
152 return;
153 }
154 ASSERT(initialized_);
155 IsolateProfilerData* profiler_data = isolate->profiler_data();
156 if (profiler_data == NULL) {
157 return;
158 }
159 ThreadInterrupter::Register(RecordSampleInterruptCallback, isolate);
160 ThreadInterrupter::WakeUp();
161 }
162
163
164 void Profiler::EndExecution(Isolate* isolate) {
165 if (isolate == NULL) {
166 return;
167 }
168 if (!FLAG_profile) {
169 return;
170 }
171 ASSERT(initialized_);
172 ThreadInterrupter::Unregister();
173 }
174
175
176 class ScopeStopwatch : public ValueObject {
177 public:
178 explicit ScopeStopwatch(const char* name) : name_(name) {
179 start_ = FLAG_trace_profiler ? OS::GetCurrentTimeMillis() : 0;
180 }
181
182 int64_t GetElapsed() const {
183 int64_t end = OS::GetCurrentTimeMillis();
184 ASSERT(end >= start_);
185 return end - start_;
186 }
187
188 ~ScopeStopwatch() {
189 if (FLAG_trace_profiler) {
190 int64_t elapsed = GetElapsed();
191 OS::Print("%s took %" Pd64 " millis.\n", name_, elapsed);
192 }
193 }
194
195 private:
196 const char* name_;
197 int64_t start_;
198 };
199
200 20
201 struct AddressEntry { 21 struct AddressEntry {
202 uword pc; 22 uword pc;
203 intptr_t exclusive_ticks; 23 intptr_t exclusive_ticks;
204 intptr_t inclusive_ticks; 24 intptr_t inclusive_ticks;
205 25
206 void tick(bool exclusive) { 26 void tick(bool exclusive) {
207 if (exclusive) { 27 if (exclusive) {
208 exclusive_ticks++; 28 exclusive_ticks++;
209 } else { 29 } else {
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 { 350 {
531 // Generate a fake function entry. 351 // Generate a fake function entry.
532 JSONObject func(&obj, "function"); 352 JSONObject func(&obj, "function");
533 func.AddProperty("type", "@Function"); 353 func.AddProperty("type", "@Function");
534 func.AddProperty("kind", "Tag"); 354 func.AddProperty("kind", "Tag");
535 obj.AddPropertyF("id", "functions/tag-%" Px "", start()); 355 obj.AddPropertyF("id", "functions/tag-%" Px "", start());
536 func.AddProperty("name", name()); 356 func.AddProperty("name", name());
537 } 357 }
538 } 358 }
539 359
540 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) { 360 void PrintToJSONArray(Isolate* isolate, JSONArray* events) {
541 JSONObject obj(events); 361 JSONObject obj(events);
542 obj.AddProperty("kind", KindToCString(kind())); 362 obj.AddProperty("kind", KindToCString(kind()));
543 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); 363 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks());
544 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); 364 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks());
545 if (kind() == kDartCode) { 365 if (kind() == kDartCode) {
546 // Look up code in Dart heap. 366 // Look up code in Dart heap.
547 Code& code = Code::Handle(isolate); 367 Code& code = Code::Handle(isolate);
548 code ^= Code::LookupCode(start()); 368 code ^= Code::LookupCode(start());
549 if (code.IsNull()) { 369 if (code.IsNull()) {
550 // Code is a stub in the Vm isolate. 370 // Code is a stub in the Vm isolate.
551 code ^= Code::LookupCodeInVmIsolate(start()); 371 code ^= Code::LookupCodeInVmIsolate(start());
552 } 372 }
553 ASSERT(!code.IsNull()); 373 ASSERT(!code.IsNull());
554 obj.AddProperty("code", code, !full); 374 obj.AddProperty("code", code);
555 } else if (kind() == kCollectedCode) { 375 } else if (kind() == kCollectedCode) {
556 if (name() == NULL) { 376 if (name() == NULL) {
557 // Lazily set generated name. 377 // Lazily set generated name.
558 GenerateAndSetSymbolName("[Collected]"); 378 GenerateAndSetSymbolName("[Collected]");
559 } 379 }
560 PrintCollectedCode(&obj); 380 PrintCollectedCode(&obj);
561 } else if (kind() == kReusedCode) { 381 } else if (kind() == kReusedCode) {
562 if (name() == NULL) { 382 if (name() == NULL) {
563 // Lazily set generated name. 383 // Lazily set generated name.
564 GenerateAndSetSymbolName("[Reused]"); 384 GenerateAndSetSymbolName("[Reused]");
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
1218 dead_code_table_->Length(); 1038 dead_code_table_->Length();
1219 intptr_t root_index = tag_code_table_->FindIndex(0); 1039 intptr_t root_index = tag_code_table_->FindIndex(0);
1220 // Verify that the "0" tag does not exist. 1040 // Verify that the "0" tag does not exist.
1221 ASSERT(root_index < 0); 1041 ASSERT(root_index < 0);
1222 // Insert the dummy tag CodeRegion that is used for the Trie root. 1042 // Insert the dummy tag CodeRegion that is used for the Trie root.
1223 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0); 1043 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0);
1224 root_index = tag_code_table_->InsertCodeRegion(region); 1044 root_index = tag_code_table_->InsertCodeRegion(region);
1225 ASSERT(root_index >= 0); 1045 ASSERT(root_index >= 0);
1226 region->set_creation_serial(0); 1046 region->set_creation_serial(0);
1227 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); 1047 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index);
1228 set_tag_order(Profiler::kUserVM); 1048 set_tag_order(ProfilerService::kUserVM);
1229 } 1049 }
1230 1050
1231 void VisitSample(Sample* sample) { 1051 void VisitSample(Sample* sample) {
1232 // Give the root a tick. 1052 // Give the root a tick.
1233 root_->Tick(); 1053 root_->Tick();
1234 CodeRegionTrieNode* current = root_; 1054 CodeRegionTrieNode* current = root_;
1235 current = ProcessTags(sample, current); 1055 current = ProcessTags(sample, current);
1236 // Walk the sampled PCs. 1056 // Walk the sampled PCs.
1237 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { 1057 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
1238 if (sample->At(i) == 0) { 1058 if (sample->At(i) == 0) {
1239 break; 1059 break;
1240 } 1060 }
1241 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); 1061 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
1242 current = current->GetChild(index); 1062 current = current->GetChild(index);
1243 current->Tick(); 1063 current->Tick();
1244 } 1064 }
1245 } 1065 }
1246 1066
1247 CodeRegionTrieNode* root() const { 1067 CodeRegionTrieNode* root() const {
1248 return root_; 1068 return root_;
1249 } 1069 }
1250 1070
1251 Profiler::TagOrder tag_order() const { 1071 ProfilerService::TagOrder tag_order() const {
1252 return tag_order_; 1072 return tag_order_;
1253 } 1073 }
1254 1074
1255 void set_tag_order(Profiler::TagOrder tag_order) { 1075 void set_tag_order(ProfilerService::TagOrder tag_order) {
1256 tag_order_ = tag_order; 1076 tag_order_ = tag_order;
1257 } 1077 }
1258 1078
1259 private: 1079 private:
1260 CodeRegionTrieNode* ProcessUserTags(Sample* sample, 1080 CodeRegionTrieNode* ProcessUserTags(Sample* sample,
1261 CodeRegionTrieNode* current) { 1081 CodeRegionTrieNode* current) {
1262 intptr_t user_tag_index = FindTagIndex(sample->user_tag()); 1082 intptr_t user_tag_index = FindTagIndex(sample->user_tag());
1263 if (user_tag_index >= 0) { 1083 if (user_tag_index >= 0) {
1264 current = current->GetChild(user_tag_index); 1084 current = current->GetChild(user_tag_index);
1265 // Give the tag a tick. 1085 // Give the tag a tick.
(...skipping 19 matching lines...) Expand all
1285 } 1105 }
1286 intptr_t tag_index = FindTagIndex(sample->vm_tag()); 1106 intptr_t tag_index = FindTagIndex(sample->vm_tag());
1287 current = current->GetChild(tag_index); 1107 current = current->GetChild(tag_index);
1288 // Give the tag a tick. 1108 // Give the tag a tick.
1289 current->Tick(); 1109 current->Tick();
1290 return current; 1110 return current;
1291 } 1111 }
1292 1112
1293 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) { 1113 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) {
1294 // None. 1114 // None.
1295 if (tag_order() == Profiler::kNoTags) { 1115 if (tag_order() == ProfilerService::kNoTags) {
1296 return current; 1116 return current;
1297 } 1117 }
1298 // User first. 1118 // User first.
1299 if ((tag_order() == Profiler::kUserVM) || 1119 if ((tag_order() == ProfilerService::kUserVM) ||
1300 (tag_order() == Profiler::kUser)) { 1120 (tag_order() == ProfilerService::kUser)) {
1301 current = ProcessUserTags(sample, current); 1121 current = ProcessUserTags(sample, current);
1302 // Only user. 1122 // Only user.
1303 if (tag_order() == Profiler::kUser) { 1123 if (tag_order() == ProfilerService::kUser) {
1304 return current; 1124 return current;
1305 } 1125 }
1306 return ProcessVMTags(sample, current); 1126 return ProcessVMTags(sample, current);
1307 } 1127 }
1308 // VM first. 1128 // VM first.
1309 ASSERT((tag_order() == Profiler::kVMUser) || 1129 ASSERT((tag_order() == ProfilerService::kVMUser) ||
1310 (tag_order() == Profiler::kVM)); 1130 (tag_order() == ProfilerService::kVM));
1311 current = ProcessVMTags(sample, current); 1131 current = ProcessVMTags(sample, current);
1312 // Only VM. 1132 // Only VM.
1313 if (tag_order() == Profiler::kVM) { 1133 if (tag_order() == ProfilerService::kVM) {
1314 return current; 1134 return current;
1315 } 1135 }
1316 return ProcessUserTags(sample, current); 1136 return ProcessUserTags(sample, current);
1317 } 1137 }
1318 1138
1319 intptr_t FindTagIndex(uword tag) const { 1139 intptr_t FindTagIndex(uword tag) const {
1320 if (tag == 0) { 1140 if (tag == 0) {
1321 return -1; 1141 return -1;
1322 } 1142 }
1323 intptr_t index = tag_code_table_->FindIndex(tag); 1143 intptr_t index = tag_code_table_->FindIndex(tag);
(...skipping 16 matching lines...) Expand all
1340 ASSERT(index >= 0); 1160 ASSERT(index >= 0);
1341 region = dead_code_table_->At(index); 1161 region = dead_code_table_->At(index);
1342 ASSERT(region->contains(pc)); 1162 ASSERT(region->contains(pc));
1343 ASSERT(region->compile_timestamp() <= timestamp); 1163 ASSERT(region->compile_timestamp() <= timestamp);
1344 return index + dead_code_table_offset_; 1164 return index + dead_code_table_offset_;
1345 } 1165 }
1346 ASSERT(region->compile_timestamp() <= timestamp); 1166 ASSERT(region->compile_timestamp() <= timestamp);
1347 return index; 1167 return index;
1348 } 1168 }
1349 1169
1350 Profiler::TagOrder tag_order_; 1170 ProfilerService::TagOrder tag_order_;
1351 CodeRegionTrieNode* root_; 1171 CodeRegionTrieNode* root_;
1352 CodeRegionTable* live_code_table_; 1172 CodeRegionTable* live_code_table_;
1353 CodeRegionTable* dead_code_table_; 1173 CodeRegionTable* dead_code_table_;
1354 CodeRegionTable* tag_code_table_; 1174 CodeRegionTable* tag_code_table_;
1355 intptr_t dead_code_table_offset_; 1175 intptr_t dead_code_table_offset_;
1356 intptr_t tag_code_table_offset_; 1176 intptr_t tag_code_table_offset_;
1357 }; 1177 };
1358 1178
1359 1179
1360 class CodeRegionTableCallersBuilder { 1180 class CodeRegionTableCallersBuilder {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1412 1232
1413 CodeRegionTrieNode* exclusive_root_; 1233 CodeRegionTrieNode* exclusive_root_;
1414 CodeRegionTable* live_code_table_; 1234 CodeRegionTable* live_code_table_;
1415 CodeRegionTable* dead_code_table_; 1235 CodeRegionTable* dead_code_table_;
1416 CodeRegionTable* tag_code_table_; 1236 CodeRegionTable* tag_code_table_;
1417 intptr_t dead_code_table_offset_; 1237 intptr_t dead_code_table_offset_;
1418 intptr_t tag_code_table_offset_; 1238 intptr_t tag_code_table_offset_;
1419 }; 1239 };
1420 1240
1421 1241
1422 void Profiler::PrintJSON(Isolate* isolate, JSONStream* stream, 1242 void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) {
1423 bool full, TagOrder tag_order) { 1243 Isolate* isolate = Isolate::Current();
1424 ASSERT(isolate == Isolate::Current());
1425 // Disable profile interrupts while processing the buffer. 1244 // Disable profile interrupts while processing the buffer.
1426 EndExecution(isolate); 1245 Profiler::EndExecution(isolate);
1427 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1246 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
1428 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1247 IsolateProfilerData* profiler_data = isolate->profiler_data();
1429 if (profiler_data == NULL) { 1248 if (profiler_data == NULL) {
1430 JSONObject error(stream); 1249 JSONObject error(stream);
1431 error.AddProperty("type", "Error"); 1250 error.AddProperty("type", "Error");
1432 error.AddProperty("text", "Isolate does not have profiling enabled."); 1251 error.AddProperty("text", "Isolate does not have profiling enabled.");
1433 return; 1252 return;
1434 } 1253 }
1435 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1254 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1436 ASSERT(sample_buffer != NULL); 1255 ASSERT(sample_buffer != NULL);
1437 { 1256 {
1438 StackZone zone(isolate); 1257 StackZone zone(isolate);
1439 { 1258 {
1440 // Live code holds Dart, Native, and Collected CodeRegions. 1259 // Live code holds Dart, Native, and Collected CodeRegions.
1441 CodeRegionTable live_code_table; 1260 CodeRegionTable live_code_table;
1442 // Dead code holds Overwritten CodeRegions. 1261 // Dead code holds Overwritten CodeRegions.
1443 CodeRegionTable dead_code_table; 1262 CodeRegionTable dead_code_table;
1444 // Tag code holds Tag CodeRegions. 1263 // Tag code holds Tag CodeRegions.
1445 CodeRegionTable tag_code_table; 1264 CodeRegionTable tag_code_table;
1446 CodeRegionTableBuilder builder(isolate, 1265 CodeRegionTableBuilder builder(isolate,
1447 &live_code_table, 1266 &live_code_table,
1448 &dead_code_table, 1267 &dead_code_table,
1449 &tag_code_table); 1268 &tag_code_table);
1450 { 1269 {
1451 ScopeStopwatch sw("FixTopFrame"); 1270 ScopeTimer sw("FixTopFrame", FLAG_trace_profiler);
1452 // Preprocess samples and fix the caller when the top PC is in a 1271 // Preprocess samples and fix the caller when the top PC is in a
1453 // stub or intrinsic without a frame. 1272 // stub or intrinsic without a frame.
1454 FixTopFrameVisitor fixTopFrame(isolate); 1273 FixTopFrameVisitor fixTopFrame(isolate);
1455 sample_buffer->VisitSamples(&fixTopFrame); 1274 sample_buffer->VisitSamples(&fixTopFrame);
1456 } 1275 }
1457 { 1276 {
1458 // Build CodeRegion tables. 1277 // Build CodeRegion tables.
1459 ScopeStopwatch sw("CodeRegionTableBuilder"); 1278 ScopeTimer sw("CodeRegionTableBuilder", FLAG_trace_profiler);
1460 sample_buffer->VisitSamples(&builder); 1279 sample_buffer->VisitSamples(&builder);
1461 } 1280 }
1462 intptr_t samples = builder.visited(); 1281 intptr_t samples = builder.visited();
1463 intptr_t frames = builder.frames(); 1282 intptr_t frames = builder.frames();
1464 if (FLAG_trace_profiler) { 1283 if (FLAG_trace_profiler) {
1465 intptr_t total_live_code_objects = live_code_table.Length(); 1284 intptr_t total_live_code_objects = live_code_table.Length();
1466 intptr_t total_dead_code_objects = dead_code_table.Length(); 1285 intptr_t total_dead_code_objects = dead_code_table.Length();
1467 intptr_t total_tag_code_objects = tag_code_table.Length(); 1286 intptr_t total_tag_code_objects = tag_code_table.Length();
1468 OS::Print("Processed %" Pd " frames\n", frames); 1287 OS::Print("Processed %" Pd " frames\n", frames);
1469 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n", 1288 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
1470 total_live_code_objects, 1289 total_live_code_objects,
1471 total_dead_code_objects, 1290 total_dead_code_objects,
1472 total_tag_code_objects); 1291 total_tag_code_objects);
1473 } 1292 }
1474 #if defined(DEBUG) 1293 #if defined(DEBUG)
1475 live_code_table.Verify(); 1294 live_code_table.Verify();
1476 dead_code_table.Verify(); 1295 dead_code_table.Verify();
1477 tag_code_table.Verify(); 1296 tag_code_table.Verify();
1478 if (FLAG_trace_profiler) { 1297 if (FLAG_trace_profiler) {
1479 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); 1298 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n");
1480 } 1299 }
1481 #endif 1300 #endif
1482 CodeRegionExclusiveTrieBuilder build_trie(isolate, 1301 CodeRegionExclusiveTrieBuilder build_trie(isolate,
1483 &live_code_table, 1302 &live_code_table,
1484 &dead_code_table, 1303 &dead_code_table,
1485 &tag_code_table); 1304 &tag_code_table);
1486 build_trie.set_tag_order(tag_order); 1305 build_trie.set_tag_order(tag_order);
1487 { 1306 {
1488 // Build CodeRegion trie. 1307 // Build CodeRegion trie.
1489 ScopeStopwatch sw("CodeRegionExclusiveTrieBuilder"); 1308 ScopeTimer sw("CodeRegionExclusiveTrieBuilder", FLAG_trace_profiler);
1490 sample_buffer->VisitSamples(&build_trie); 1309 sample_buffer->VisitSamples(&build_trie);
1491 build_trie.root()->SortByCount(); 1310 build_trie.root()->SortByCount();
1492 } 1311 }
1493 CodeRegionTableCallersBuilder build_callers(build_trie.root(), 1312 CodeRegionTableCallersBuilder build_callers(build_trie.root(),
1494 &live_code_table, 1313 &live_code_table,
1495 &dead_code_table, 1314 &dead_code_table,
1496 &tag_code_table); 1315 &tag_code_table);
1497 { 1316 {
1498 // Build CodeRegion callers. 1317 // Build CodeRegion callers.
1499 ScopeStopwatch sw("CodeRegionTableCallersBuilder"); 1318 ScopeTimer sw("CodeRegionTableCallersBuilder", FLAG_trace_profiler);
1500 build_callers.Build(); 1319 build_callers.Build();
1501 } 1320 }
1502 { 1321 {
1503 ScopeStopwatch sw("CodeTableStream"); 1322 ScopeTimer sw("CodeTableStream", FLAG_trace_profiler);
1504 // Serialize to JSON. 1323 // Serialize to JSON.
1505 JSONObject obj(stream); 1324 JSONObject obj(stream);
1506 obj.AddProperty("type", "CpuProfile"); 1325 obj.AddProperty("type", "CpuProfile");
1507 obj.AddProperty("id", "profile"); 1326 obj.AddProperty("id", "profile");
1508 obj.AddProperty("samples", samples); 1327 obj.AddProperty("samples", samples);
1509 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth)); 1328 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth));
1510 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period)); 1329 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period));
1511 obj.AddProperty("timeSpan", 1330 obj.AddProperty("timeSpan",
1512 MicrosecondsToSeconds(builder.TimeDeltaMicros())); 1331 MicrosecondsToSeconds(builder.TimeDeltaMicros()));
1513 { 1332 {
1514 JSONArray exclusive_trie(&obj, "exclusive_trie"); 1333 JSONArray exclusive_trie(&obj, "exclusive_trie");
1515 CodeRegionTrieNode* root = build_trie.root(); 1334 CodeRegionTrieNode* root = build_trie.root();
1516 ASSERT(root != NULL); 1335 ASSERT(root != NULL);
1517 root->PrintToJSONArray(&exclusive_trie); 1336 root->PrintToJSONArray(&exclusive_trie);
1518 } 1337 }
1519 JSONArray codes(&obj, "codes"); 1338 JSONArray codes(&obj, "codes");
1520 for (intptr_t i = 0; i < live_code_table.Length(); i++) { 1339 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
1521 CodeRegion* region = live_code_table.At(i); 1340 CodeRegion* region = live_code_table.At(i);
1522 ASSERT(region != NULL); 1341 ASSERT(region != NULL);
1523 region->PrintToJSONArray(isolate, &codes, full); 1342 region->PrintToJSONArray(isolate, &codes);
1524 } 1343 }
1525 for (intptr_t i = 0; i < dead_code_table.Length(); i++) { 1344 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
1526 CodeRegion* region = dead_code_table.At(i); 1345 CodeRegion* region = dead_code_table.At(i);
1527 ASSERT(region != NULL); 1346 ASSERT(region != NULL);
1528 region->PrintToJSONArray(isolate, &codes, full); 1347 region->PrintToJSONArray(isolate, &codes);
1529 } 1348 }
1530 for (intptr_t i = 0; i < tag_code_table.Length(); i++) { 1349 for (intptr_t i = 0; i < tag_code_table.Length(); i++) {
1531 CodeRegion* region = tag_code_table.At(i); 1350 CodeRegion* region = tag_code_table.At(i);
1532 ASSERT(region != NULL); 1351 ASSERT(region != NULL);
1533 region->PrintToJSONArray(isolate, &codes, full); 1352 region->PrintToJSONArray(isolate, &codes);
1534 } 1353 }
1535 } 1354 }
1536 } 1355 }
1537 } 1356 }
1538 // Enable profile interrupts. 1357 // Enable profile interrupts.
1539 BeginExecution(isolate); 1358 Profiler::BeginExecution(isolate);
1540 }
1541
1542
1543 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
1544 bool own_sample_buffer) {
1545 ASSERT(sample_buffer != NULL);
1546 sample_buffer_ = sample_buffer;
1547 own_sample_buffer_ = own_sample_buffer;
1548 block_count_ = 0;
1549 }
1550
1551
1552 IsolateProfilerData::~IsolateProfilerData() {
1553 if (own_sample_buffer_) {
1554 delete sample_buffer_;
1555 sample_buffer_ = NULL;
1556 own_sample_buffer_ = false;
1557 }
1558 }
1559
1560
1561 void IsolateProfilerData::Block() {
1562 block_count_++;
1563 }
1564
1565
1566 void IsolateProfilerData::Unblock() {
1567 block_count_--;
1568 if (block_count_ < 0) {
1569 FATAL("Too many calls to Dart_IsolateUnblocked.");
1570 }
1571 if (!blocked()) {
1572 // We just unblocked this isolate, wake up the thread interrupter.
1573 ThreadInterrupter::WakeUp();
1574 }
1575 }
1576
1577
1578 intptr_t Sample::pcs_length_ = 0;
1579 intptr_t Sample::instance_size_ = 0;
1580
1581
1582 void Sample::InitOnce() {
1583 ASSERT(FLAG_profile_depth >= 1);
1584 pcs_length_ = FLAG_profile_depth;
1585 instance_size_ =
1586 sizeof(Sample) + (sizeof(uword) * pcs_length_); // NOLINT.
1587 }
1588
1589
1590 uword* Sample::GetPCArray() const {
1591 return reinterpret_cast<uword*>(
1592 reinterpret_cast<uintptr_t>(this) + sizeof(*this));
1593 }
1594
1595
1596 SampleBuffer::SampleBuffer(intptr_t capacity) {
1597 ASSERT(Sample::instance_size() > 0);
1598 samples_ = reinterpret_cast<Sample*>(
1599 calloc(capacity, Sample::instance_size()));
1600 capacity_ = capacity;
1601 cursor_ = 0;
1602 }
1603
1604
1605 Sample* SampleBuffer::At(intptr_t idx) const {
1606 ASSERT(idx >= 0);
1607 ASSERT(idx < capacity_);
1608 intptr_t offset = idx * Sample::instance_size();
1609 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_);
1610 return reinterpret_cast<Sample*>(samples + offset);
1611 }
1612
1613
1614 Sample* SampleBuffer::ReserveSample() {
1615 ASSERT(samples_ != NULL);
1616 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
1617 // Map back into sample buffer range.
1618 cursor = cursor % capacity_;
1619 return At(cursor);
1620 }
1621
1622
1623 static void SetPCMarkerIfSafe(Sample* sample) {
1624 ASSERT(sample != NULL);
1625
1626 uword* fp = reinterpret_cast<uword*>(sample->fp());
1627 uword* sp = reinterpret_cast<uword*>(sample->sp());
1628
1629 // If FP == SP, the pc marker hasn't been pushed.
1630 if (fp > sp) {
1631 #if defined(TARGET_OS_WINDOWS)
1632 // If the fp is at the beginning of a page, it may be unsafe to access
1633 // the pc marker, because we are reading it from a different thread on
1634 // Windows. The marker is below fp and the previous page may be a guard
1635 // page.
1636 const intptr_t kPageMask = VirtualMemory::PageSize() - 1;
1637 if ((sample->fp() & kPageMask) == 0) {
1638 return;
1639 }
1640 #endif
1641 uword* pc_marker_ptr = fp + kPcMarkerSlotFromFp;
1642 // MSan/ASan are unaware of frames initialized by generated code.
1643 MSAN_UNPOISON(pc_marker_ptr, kWordSize);
1644 ASAN_UNPOISON(pc_marker_ptr, kWordSize);
1645 sample->set_pc_marker(*pc_marker_ptr);
1646 }
1647 }
1648
1649
1650 // Given an exit frame, walk the Dart stack.
1651 class ProfilerDartExitStackWalker : public ValueObject {
1652 public:
1653 ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample)
1654 : sample_(sample),
1655 frame_iterator_(isolate) {
1656 ASSERT(sample_ != NULL);
1657 // Mark that this sample was collected from an exit frame.
1658 sample_->set_exit_frame_sample(true);
1659 }
1660
1661 void walk() {
1662 intptr_t frame_index = 0;
1663 StackFrame* frame = frame_iterator_.NextFrame();
1664 while (frame != NULL) {
1665 sample_->SetAt(frame_index, frame->pc());
1666 frame_index++;
1667 if (frame_index >= FLAG_profile_depth) {
1668 break;
1669 }
1670 frame = frame_iterator_.NextFrame();
1671 }
1672 }
1673
1674 private:
1675 Sample* sample_;
1676 DartFrameIterator frame_iterator_;
1677 };
1678
1679
1680 // Executing Dart code, walk the stack.
1681 class ProfilerDartStackWalker : public ValueObject {
1682 public:
1683 ProfilerDartStackWalker(Isolate* isolate,
1684 Sample* sample,
1685 uword stack_lower,
1686 uword stack_upper,
1687 uword pc,
1688 uword fp,
1689 uword sp)
1690 : isolate_(isolate),
1691 sample_(sample),
1692 stack_upper_(stack_upper),
1693 stack_lower_(stack_lower) {
1694 ASSERT(sample_ != NULL);
1695 pc_ = reinterpret_cast<uword*>(pc);
1696 fp_ = reinterpret_cast<uword*>(fp);
1697 sp_ = reinterpret_cast<uword*>(sp);
1698 }
1699
1700 void walk() {
1701 if (!ValidFramePointer()) {
1702 sample_->set_ignore_sample(true);
1703 return;
1704 }
1705 ASSERT(ValidFramePointer());
1706 uword return_pc = InitialReturnAddress();
1707 if (StubCode::InInvocationStubForIsolate(isolate_, return_pc)) {
1708 // Edge case- we have called out from the Invocation Stub but have not
1709 // created the stack frame of the callee. Attempt to locate the exit
1710 // frame before walking the stack.
1711 if (!NextExit() || !ValidFramePointer()) {
1712 // Nothing to sample.
1713 sample_->set_ignore_sample(true);
1714 return;
1715 }
1716 }
1717 for (int i = 0; i < FLAG_profile_depth; i++) {
1718 sample_->SetAt(i, reinterpret_cast<uword>(pc_));
1719 if (!Next()) {
1720 return;
1721 }
1722 }
1723 }
1724
1725 private:
1726 bool Next() {
1727 if (!ValidFramePointer()) {
1728 return false;
1729 }
1730 if (StubCode::InInvocationStubForIsolate(isolate_,
1731 reinterpret_cast<uword>(pc_))) {
1732 // In invocation stub.
1733 return NextExit();
1734 }
1735 // In regular Dart frame.
1736 uword* new_pc = CallerPC();
1737 // Check if we've moved into the invocation stub.
1738 if (StubCode::InInvocationStubForIsolate(isolate_,
1739 reinterpret_cast<uword>(new_pc))) {
1740 // New PC is inside invocation stub, skip.
1741 return NextExit();
1742 }
1743 uword* new_fp = CallerFP();
1744 if (new_fp <= fp_) {
1745 // FP didn't move to a higher address.
1746 return false;
1747 }
1748 // Success, update fp and pc.
1749 fp_ = new_fp;
1750 pc_ = new_pc;
1751 return true;
1752 }
1753
1754 bool NextExit() {
1755 if (!ValidFramePointer()) {
1756 return false;
1757 }
1758 uword* new_fp = ExitLink();
1759 if (new_fp == NULL) {
1760 // No exit link.
1761 return false;
1762 }
1763 if (new_fp <= fp_) {
1764 // FP didn't move to a higher address.
1765 return false;
1766 }
1767 if (!ValidFramePointer(new_fp)) {
1768 return false;
1769 }
1770 // Success, update fp and pc.
1771 fp_ = new_fp;
1772 pc_ = CallerPC();
1773 return true;
1774 }
1775
1776 uword InitialReturnAddress() const {
1777 ASSERT(sp_ != NULL);
1778 return *(sp_);
1779 }
1780
1781 uword* CallerPC() const {
1782 ASSERT(fp_ != NULL);
1783 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerPcSlotFromFp));
1784 }
1785
1786 uword* CallerFP() const {
1787 ASSERT(fp_ != NULL);
1788 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerFpSlotFromFp));
1789 }
1790
1791 uword* ExitLink() const {
1792 ASSERT(fp_ != NULL);
1793 return reinterpret_cast<uword*>(*(fp_ + kExitLinkSlotFromEntryFp));
1794 }
1795
1796 bool ValidFramePointer() const {
1797 return ValidFramePointer(fp_);
1798 }
1799
1800 bool ValidFramePointer(uword* fp) const {
1801 if (fp == NULL) {
1802 return false;
1803 }
1804 uword cursor = reinterpret_cast<uword>(fp);
1805 cursor += sizeof(fp);
1806 return (cursor >= stack_lower_) && (cursor < stack_upper_);
1807 }
1808
1809 uword* pc_;
1810 uword* fp_;
1811 uword* sp_;
1812 Isolate* isolate_;
1813 Sample* sample_;
1814 const uword stack_upper_;
1815 uword stack_lower_;
1816 };
1817
1818
1819 // If the VM is compiled without frame pointers (which is the default on
1820 // recent GCC versions with optimizing enabled) the stack walking code may
1821 // fail.
1822 //
1823 class ProfilerNativeStackWalker : public ValueObject {
1824 public:
1825 ProfilerNativeStackWalker(Sample* sample,
1826 uword stack_lower,
1827 uword stack_upper,
1828 uword pc,
1829 uword fp,
1830 uword sp)
1831 : sample_(sample),
1832 stack_upper_(stack_upper),
1833 original_pc_(pc),
1834 original_fp_(fp),
1835 original_sp_(sp),
1836 lower_bound_(stack_lower) {
1837 ASSERT(sample_ != NULL);
1838 }
1839
1840 void walk() {
1841 const uword kMaxStep = VirtualMemory::PageSize();
1842
1843 sample_->SetAt(0, original_pc_);
1844
1845 uword* pc = reinterpret_cast<uword*>(original_pc_);
1846 uword* fp = reinterpret_cast<uword*>(original_fp_);
1847 uword* previous_fp = fp;
1848
1849 uword gap = original_fp_ - original_sp_;
1850 if (gap >= kMaxStep) {
1851 // Gap between frame pointer and stack pointer is
1852 // too large.
1853 return;
1854 }
1855
1856 if (!ValidFramePointer(fp)) {
1857 return;
1858 }
1859
1860 for (int i = 0; i < FLAG_profile_depth; i++) {
1861 sample_->SetAt(i, reinterpret_cast<uword>(pc));
1862
1863 pc = CallerPC(fp);
1864 previous_fp = fp;
1865 fp = CallerFP(fp);
1866
1867 if (fp == NULL) {
1868 return;
1869 }
1870
1871 if (fp <= previous_fp) {
1872 // Frame pointer did not move to a higher address.
1873 return;
1874 }
1875
1876 gap = fp - previous_fp;
1877 if (gap >= kMaxStep) {
1878 // Frame pointer step is too large.
1879 return;
1880 }
1881
1882 if (!ValidFramePointer(fp)) {
1883 // Frame pointer is outside of isolate stack boundary.
1884 return;
1885 }
1886
1887 // Move the lower bound up.
1888 lower_bound_ = reinterpret_cast<uword>(fp);
1889 }
1890 }
1891
1892 private:
1893 uword* CallerPC(uword* fp) const {
1894 ASSERT(fp != NULL);
1895 uword* caller_pc_ptr = fp + kSavedCallerPcSlotFromFp;
1896 // This may actually be uninitialized, by design (see class comment above).
1897 MSAN_UNPOISON(caller_pc_ptr, kWordSize);
1898 ASAN_UNPOISON(caller_pc_ptr, kWordSize);
1899 return reinterpret_cast<uword*>(*caller_pc_ptr);
1900 }
1901
1902 uword* CallerFP(uword* fp) const {
1903 ASSERT(fp != NULL);
1904 uword* caller_fp_ptr = fp + kSavedCallerFpSlotFromFp;
1905 // This may actually be uninitialized, by design (see class comment above).
1906 MSAN_UNPOISON(caller_fp_ptr, kWordSize);
1907 ASAN_UNPOISON(caller_fp_ptr, kWordSize);
1908 return reinterpret_cast<uword*>(*caller_fp_ptr);
1909 }
1910
1911 bool ValidFramePointer(uword* fp) const {
1912 if (fp == NULL) {
1913 return false;
1914 }
1915 uword cursor = reinterpret_cast<uword>(fp);
1916 cursor += sizeof(fp);
1917 bool r = (cursor >= lower_bound_) && (cursor < stack_upper_);
1918 return r;
1919 }
1920
1921 Sample* sample_;
1922 const uword stack_upper_;
1923 const uword original_pc_;
1924 const uword original_fp_;
1925 const uword original_sp_;
1926 uword lower_bound_;
1927 };
1928
1929
1930 void Profiler::RecordSampleInterruptCallback(
1931 const InterruptedThreadState& state,
1932 void* data) {
1933 Isolate* isolate = reinterpret_cast<Isolate*>(data);
1934 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
1935 // No isolate.
1936 return;
1937 }
1938
1939 ASSERT(isolate != Dart::vm_isolate());
1940
1941 uintptr_t sp = 0;
1942 if ((isolate->stub_code() != NULL) &&
1943 (isolate->top_exit_frame_info() == 0) &&
1944 (isolate->vm_tag() == VMTag::kDartTagId)) {
1945 // If we're in Dart code, use the Dart stack pointer.
1946 sp = state.dsp;
1947 } else {
1948 // If we're in runtime code, use the C stack pointer.
1949 sp = state.csp;
1950 }
1951
1952 IsolateProfilerData* profiler_data = isolate->profiler_data();
1953 if (profiler_data == NULL) {
1954 // Profiler not initialized.
1955 return;
1956 }
1957
1958 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1959 if (sample_buffer == NULL) {
1960 // Profiler not initialized.
1961 return;
1962 }
1963
1964 if ((sp == 0) || (state.fp == 0) || (state.pc == 0)) {
1965 // None of these registers should be zero.
1966 return;
1967 }
1968
1969 if (sp > state.fp) {
1970 // Assuming the stack grows down, we should never have a stack pointer above
1971 // the frame pointer.
1972 return;
1973 }
1974
1975 if (StubCode::InJumpToExceptionHandlerStub(state.pc)) {
1976 // The JumpToExceptionHandler stub manually adjusts the stack pointer,
1977 // frame pointer, and some isolate state before jumping to a catch entry.
1978 // It is not safe to walk the stack when executing this stub.
1979 return;
1980 }
1981
1982 uword stack_lower = 0;
1983 uword stack_upper = 0;
1984 if (!isolate->GetProfilerStackBounds(&stack_lower, &stack_upper) ||
1985 (stack_lower == 0) || (stack_upper == 0)) {
1986 // Could not get stack boundary.
1987 return;
1988 }
1989
1990 if (sp > stack_lower) {
1991 // The stack pointer gives us a tighter lower bound.
1992 stack_lower = sp;
1993 }
1994
1995 if (stack_lower >= stack_upper) {
1996 // Stack boundary is invalid.
1997 return;
1998 }
1999
2000 if ((sp < stack_lower) || (sp >= stack_upper)) {
2001 // Stack pointer is outside isolate stack boundary.
2002 return;
2003 }
2004
2005 if ((state.fp < stack_lower) || (state.fp >= stack_upper)) {
2006 // Frame pointer is outside isolate stack boundary.
2007 return;
2008 }
2009
2010 // At this point we have a valid stack boundary for this isolate and
2011 // know that our initial stack and frame pointers are within the boundary.
2012
2013 // Setup sample.
2014 Sample* sample = sample_buffer->ReserveSample();
2015 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid);
2016 uword vm_tag = isolate->vm_tag();
2017 #if defined(USING_SIMULATOR)
2018 // When running in the simulator, the runtime entry function address
2019 // (stored as the vm tag) is the address of a redirect function.
2020 // Attempt to find the real runtime entry function address and use that.
2021 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag);
2022 if (redirect_vm_tag != 0) {
2023 vm_tag = redirect_vm_tag;
2024 }
2025 #endif
2026 // Increment counter for vm tag.
2027 VMTagCounters* counters = isolate->vm_tag_counters();
2028 ASSERT(counters != NULL);
2029 counters->Increment(vm_tag);
2030 sample->set_vm_tag(vm_tag);
2031 sample->set_user_tag(isolate->user_tag());
2032 sample->set_sp(sp);
2033 sample->set_fp(state.fp);
2034 #if !(defined(TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64))
2035 // It is never safe to read other thread's stack unless on Win64
2036 // other thread is inside Dart code.
2037 SetPCMarkerIfSafe(sample);
2038 #endif
2039
2040 // Walk the call stack.
2041 if (FLAG_profile_vm) {
2042 // Always walk the native stack collecting both native and Dart frames.
2043 ProfilerNativeStackWalker stackWalker(sample,
2044 stack_lower,
2045 stack_upper,
2046 state.pc,
2047 state.fp,
2048 sp);
2049 stackWalker.walk();
2050 } else {
2051 // Attempt to walk only the Dart call stack, falling back to walking
2052 // the native stack.
2053 if ((isolate->stub_code() != NULL) &&
2054 (isolate->top_exit_frame_info() != 0) &&
2055 (isolate->vm_tag() != VMTag::kDartTagId)) {
2056 // We have a valid exit frame info, use the Dart stack walker.
2057 ProfilerDartExitStackWalker stackWalker(isolate, sample);
2058 stackWalker.walk();
2059 } else if ((isolate->stub_code() != NULL) &&
2060 (isolate->top_exit_frame_info() == 0) &&
2061 (isolate->vm_tag() == VMTag::kDartTagId)) {
2062 // We are executing Dart code. We have frame pointers.
2063 ProfilerDartStackWalker stackWalker(isolate,
2064 sample,
2065 stack_lower,
2066 stack_upper,
2067 state.pc,
2068 state.fp,
2069 sp);
2070 stackWalker.walk();
2071 } else {
2072 #if defined(TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64)
2073 // ProfilerNativeStackWalker is known to cause crashes on Win64.
2074 // BUG=20423.
2075 sample->set_ignore_sample(true);
2076 #else
2077 // Fall back to an extremely conservative stack walker.
2078 ProfilerNativeStackWalker stackWalker(sample,
2079 stack_lower,
2080 stack_upper,
2081 state.pc,
2082 state.fp,
2083 sp);
2084 stackWalker.walk();
2085 #endif
2086 }
2087 }
2088 } 1359 }
2089 1360
2090 } // namespace dart 1361 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698