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

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

Issue 928833003: Add Function based profile tree (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) 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"
11 #include "vm/profiler.h" 11 #include "vm/profiler.h"
12 #include "vm/reusable_handles.h" 12 #include "vm/reusable_handles.h"
13 #include "vm/scope_timer.h" 13 #include "vm/scope_timer.h"
14 14
15 namespace dart { 15 namespace dart {
16 16
17 DECLARE_FLAG(int, profile_depth); 17 DECLARE_FLAG(int, profile_depth);
18 DECLARE_FLAG(bool, trace_profiler);
19 DECLARE_FLAG(int, profile_period); 18 DECLARE_FLAG(int, profile_period);
20 19
20 DEFINE_FLAG(bool, trace_profiler, true, "Trace profiler.");
21
22 // Forward declarations.
23 class CodeRegion;
24 class ProfileFunction;
25 class ProfileFunctionTable;
26
27
28 class ProfileFunction : public ZoneAllocated {
29 public:
30 enum Kind {
31 kDartFunction, // Dart function.
32 kNativeFunction, // Synthetic function for Native (C/C++).
33 kTagFunction, // Synthetic function for a VM or User tag.
34 kStubFunction, // Synthetic function for stub code.
35 kUnkownFunction, // A singleton function for unknown objects.
36 };
37 ProfileFunction(Kind kind,
38 const char* name,
39 const Function& function,
40 const intptr_t table_index)
41 : kind_(kind),
42 name_(name),
43 function_(Function::ZoneHandle(function.raw())),
44 table_index_(table_index),
45 code_objects_(new ZoneGrowableArray<intptr_t>()),
46 exclusive_ticks_(0),
47 inclusive_ticks_(0),
48 inclusive_tick_serial_(0) {
49 ASSERT((kind_ != kDartFunction) || !function_.IsNull());
50 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
51 ASSERT(code_objects_->length() == 0);
52 }
53
54 const char* name() const {
55 ASSERT(name_ != NULL);
56 return name_;
57 }
58
59 RawFunction* function() const {
60 return function_.raw();
61 }
62
63 intptr_t index() const {
64 return table_index_;
65 }
66
67 Kind kind() const {
68 return kind_;
69 }
70
71 const char* KindToCString(Kind kind) {
72 switch (kind) {
73 case kDartFunction:
74 return "Dart";
75 case kNativeFunction:
76 return "Native";
77 case kTagFunction:
78 return "Tag";
79 case kStubFunction:
80 return "Stub";
81 case kUnkownFunction:
82 return "Collected";
83 default:
84 UNIMPLEMENTED();
85 return "";
86 }
87 }
88
89 void Dump() {
90 const char* n = (name_ == NULL) ? "<NULL>" : name_;
91 const char* fn = "";
92 if (!function_.IsNull()) {
93 fn = function_.ToQualifiedCString();
94 }
95 OS::Print("%s %s [%s]", KindToCString(kind()), n, fn);
96 }
97
98 void AddCodeObjectIndex(intptr_t index) {
99 for (intptr_t i = 0; i < code_objects_->length(); i++) {
100 if ((*code_objects_)[i] == index) {
101 return;
102 }
103 }
104 code_objects_->Add(index);
105 }
106
107 intptr_t inclusive_ticks() const {
108 return inclusive_ticks_;
109 }
110
111 intptr_t exclusive_ticks() const {
112 return exclusive_ticks_;
113 }
114
115 void Tick(bool exclusive, intptr_t serial) {
116 // Assert that exclusive ticks are never passed a valid serial number.
117 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
118 if (!exclusive && (inclusive_tick_serial_ == serial)) {
119 // We've already given this object an inclusive tick for this sample.
120 return;
121 }
122 if (exclusive) {
123 exclusive_ticks_++;
124 } else {
125 inclusive_ticks_++;
126 // Mark the last serial we ticked the inclusive count.
127 inclusive_tick_serial_ = serial;
128 }
129 }
130
131 void PrintToJSONObject(JSONObject* func) {
132 if (kind() == kNativeFunction) {
133 func->AddProperty("type", "@Function");
134 func->AddProperty("name", name());
135 func->AddProperty("kind", "Native");
136 } else if (kind() == kTagFunction) {
137 func->AddProperty("type", "@Function");
138 func->AddProperty("kind", "Tag");
139 func->AddProperty("name", name());
140 } else if (kind() == kUnkownFunction) {
141 func->AddProperty("type", "@Function");
142 func->AddProperty("name", name());
143 func->AddProperty("kind", "Collected");
144 } else if (kind() == kStubFunction) {
145 func->AddProperty("type", "@Function");
146 func->AddProperty("name", name());
147 func->AddProperty("kind", "Stub");
148 } else {
149 UNREACHABLE();
150 }
151 }
152
153 void PrintToJSONArray(JSONArray* functions) {
154 JSONObject obj(functions);
155 obj.AddProperty("kind", KindToCString(kind()));
156 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
157 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
158 if (kind() == kDartFunction) {
159 ASSERT(!function_.IsNull());
160 obj.AddProperty("function", function_);
161 } else {
162 JSONObject func(&obj, "function");
163 PrintToJSONObject(&func);
164 }
165 {
166 JSONArray codes(&obj, "codes");
167 for (intptr_t i = 0; i < code_objects_->length(); i++) {
168 intptr_t code_index = (*code_objects_)[i];
169 codes.AddValue(code_index);
170 }
171 }
172 }
173
174 private:
175 const Kind kind_;
176 const char* name_;
177 const Function& function_;
178 const intptr_t table_index_;
179 ZoneGrowableArray<intptr_t>* code_objects_;
180 intptr_t exclusive_ticks_;
181 intptr_t inclusive_ticks_;
182 intptr_t inclusive_tick_serial_;
183 };
184
185
186 class ProfileFunctionTable : public ValueObject {
187 public:
188 ProfileFunctionTable()
189 : null_function_(Function::ZoneHandle()),
190 table_(new ZoneGrowableArray<ProfileFunction*>()),
191 unknown_function_(NULL) {
192 }
193
194 ProfileFunction* LookupOrAdd(const Function& function) {
195 ASSERT(!function.IsNull());
196 ProfileFunction* profile_function = Lookup(function);
197 if (profile_function != NULL) {
198 return profile_function;
199 }
200 return Add(function);
201 }
202
203 intptr_t LookupIndex(const Function& function) {
204 ASSERT(!function.IsNull());
205 for (intptr_t i = 0; i < table_->length(); i++) {
206 ProfileFunction* profile_function = (*table_)[i];
207 if (profile_function->function() == function.raw()) {
208 return i;
209 }
210 }
211 return -1;
212 }
213
214 ProfileFunction* GetUnknown() {
215 if (unknown_function_ == NULL) {
216 // Construct.
217 unknown_function_ = Add(ProfileFunction::kUnkownFunction,
218 "<unknown Dart function>");
219 }
220 ASSERT(unknown_function_ != NULL);
221 return unknown_function_;
222 }
223
224 // No protection against being called more than once for the same tag_id.
225 ProfileFunction* AddTag(uword tag_id, const char* name) {
226 // TODO(johnmccutchan): Canonicalize ProfileFunctions for tags.
227 return Add(ProfileFunction::kTagFunction, name);
228 }
229
230 // No protection against being called more than once for the same native
231 // address.
232 ProfileFunction* AddNative(uword start_address, const char* name) {
233 // TODO(johnmccutchan): Canonicalize ProfileFunctions for natives.
234 return Add(ProfileFunction::kNativeFunction, name);
235 }
236
237 // No protection against being called more tha once for the same stub.
238 ProfileFunction* AddStub(uword start_address, const char* name) {
239 return Add(ProfileFunction::kStubFunction, name);
240 }
241
242 intptr_t Length() const {
243 return table_->length();
244 }
245
246 ProfileFunction* At(intptr_t i) const {
247 ASSERT(i >= 0);
248 ASSERT(i < Length());
249 return (*table_)[i];
250 }
251
252 private:
253 ProfileFunction* Add(ProfileFunction::Kind kind, const char* name) {
254 ASSERT(kind != ProfileFunction::kDartFunction);
255 ASSERT(name != NULL);
256 ProfileFunction* profile_function =
257 new ProfileFunction(kind,
258 name,
259 null_function_,
260 table_->length());
261 table_->Add(profile_function);
262 return profile_function;
263 }
264
265 ProfileFunction* Add(const Function& function) {
266 ASSERT(Lookup(function) == NULL);
267 ProfileFunction* profile_function =
268 new ProfileFunction(ProfileFunction::kDartFunction,
269 NULL,
270 function,
271 table_->length());
272 table_->Add(profile_function);
273 return profile_function;
274 }
275
276 ProfileFunction* Lookup(const Function& function) {
277 ASSERT(!function.IsNull());
278 intptr_t index = LookupIndex(function);
279 if (index == -1) {
280 return NULL;
281 }
282 return (*table_)[index];
283 }
284
285 const Function& null_function_;
286 ZoneGrowableArray<ProfileFunction*>* table_;
287
288 ProfileFunction* unknown_function_;
289 };
290
291
21 struct AddressEntry { 292 struct AddressEntry {
22 uword pc; 293 uword pc;
23 intptr_t exclusive_ticks; 294 intptr_t exclusive_ticks;
24 intptr_t inclusive_ticks; 295 intptr_t inclusive_ticks;
25 296
26 void tick(bool exclusive) { 297 void tick(bool exclusive) {
27 if (exclusive) { 298 if (exclusive) {
28 exclusive_ticks++; 299 exclusive_ticks++;
29 } else { 300 } else {
30 inclusive_ticks++; 301 inclusive_ticks++;
31 } 302 }
32 } 303 }
33 }; 304 };
34 305
35
36 struct CallEntry {
37 intptr_t code_table_index;
38 intptr_t count;
39 };
40
41
42 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); 306 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
43 307
44
45 class CodeRegionTrieNode : public ZoneAllocated {
46 public:
47 explicit CodeRegionTrieNode(intptr_t code_region_index)
48 : code_region_index_(code_region_index),
49 count_(0),
50 children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) {
51 }
52
53 void Tick() {
54 ASSERT(code_region_index_ >= 0);
55 count_++;
56 }
57
58 intptr_t count() const {
59 ASSERT(code_region_index_ >= 0);
60 return count_;
61 }
62
63 intptr_t code_region_index() const {
64 return code_region_index_;
65 }
66
67 ZoneGrowableArray<CodeRegionTrieNode*>& children() const {
68 return *children_;
69 }
70
71 CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) {
72 const intptr_t length = children_->length();
73 intptr_t i = 0;
74 while (i < length) {
75 CodeRegionTrieNode* child = (*children_)[i];
76 if (child->code_region_index() == child_code_region_index) {
77 return child;
78 }
79 if (child->code_region_index() > child_code_region_index) {
80 break;
81 }
82 i++;
83 }
84 // Add new CodeRegion, sorted by CodeRegionTable index.
85 CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index);
86 if (i < length) {
87 // Insert at i.
88 children_->InsertAt(i, child);
89 } else {
90 // Add to end.
91 children_->Add(child);
92 }
93 return child;
94 }
95
96 // Sort this's children and (recursively) all descendants by count.
97 // This should only be called after the trie is completely built.
98 void SortByCount() {
99 children_->Sort(CodeRegionTrieNodeCompare);
100 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
101 intptr_t child_count = kids.length();
102 // Recurse.
103 for (intptr_t i = 0; i < child_count; i++) {
104 kids[i]->SortByCount();
105 }
106 }
107
108 void PrintToJSONArray(JSONArray* array) const {
109 ASSERT(array != NULL);
110 // Write CodeRegion index.
111 array->AddValue(code_region_index_);
112 // Write count.
113 array->AddValue(count_);
114 // Write number of children.
115 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
116 intptr_t child_count = kids.length();
117 array->AddValue(child_count);
118 // Recurse.
119 for (intptr_t i = 0; i < child_count; i++) {
120 kids[i]->PrintToJSONArray(array);
121 }
122 }
123
124 private:
125 static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a,
126 CodeRegionTrieNode* const* b) {
127 ASSERT(a != NULL);
128 ASSERT(b != NULL);
129 return (*b)->count() - (*a)->count();
130 }
131
132 const intptr_t code_region_index_;
133 intptr_t count_;
134 ZoneGrowableArray<CodeRegionTrieNode*>* children_;
135 };
136
137
138 // A contiguous address region that holds code. Each CodeRegion has a "kind" 308 // A contiguous address region that holds code. Each CodeRegion has a "kind"
139 // which describes the type of code contained inside the region. Each 309 // which describes the type of code contained inside the region. Each
140 // region covers the following interval: [start, end). 310 // region covers the following interval: [start, end).
141 class CodeRegion : public ZoneAllocated { 311 class CodeRegion : public ZoneAllocated {
142 public: 312 public:
143 enum Kind { 313 enum Kind {
144 kDartCode, // Live Dart code. 314 kDartCode, // Live Dart code.
145 kCollectedCode, // Dead Dart code. 315 kCollectedCode, // Dead Dart code.
146 kNativeCode, // Native code. 316 kNativeCode, // Native code.
147 kReusedCode, // Dead Dart code that has been reused by new kDartCode. 317 kReusedCode, // Dead Dart code that has been reused by new kDartCode.
148 kTagCode, // A special kind of code representing a tag. 318 kTagCode, // A special kind of code representing a tag.
149 }; 319 };
150 320
151 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) 321 CodeRegion(Kind kind,
322 uword start,
323 uword end,
324 int64_t timestamp,
325 const Code& code)
152 : kind_(kind), 326 : kind_(kind),
153 start_(start), 327 start_(start),
154 end_(end), 328 end_(end),
155 inclusive_ticks_(0), 329 inclusive_ticks_(0),
156 exclusive_ticks_(0), 330 exclusive_ticks_(0),
157 inclusive_tick_serial_(0), 331 inclusive_tick_serial_(0),
158 name_(NULL), 332 name_(NULL),
159 compile_timestamp_(timestamp), 333 compile_timestamp_(timestamp),
160 creation_serial_(0), 334 creation_serial_(0),
161 address_table_(new ZoneGrowableArray<AddressEntry>()), 335 code_(Code::ZoneHandle(code.raw())),
162 callers_table_(new ZoneGrowableArray<CallEntry>()), 336 profile_function_(NULL),
163 callees_table_(new ZoneGrowableArray<CallEntry>()) { 337 code_table_index_(-1) {
164 ASSERT(start_ < end_); 338 ASSERT(start_ < end_);
339 // Ensure all kDartCode have a valid code_ object.
340 ASSERT((kind != kDartCode) || (!code_.IsNull()));
165 } 341 }
166 342
167
168 uword start() const { return start_; } 343 uword start() const { return start_; }
169 void set_start(uword start) { 344 void set_start(uword start) {
170 start_ = start; 345 start_ = start;
171 } 346 }
172 347
173 uword end() const { return end_; } 348 uword end() const { return end_; }
174 void set_end(uword end) { 349 void set_end(uword end) {
175 end_ = end; 350 end_ = end;
176 } 351 }
177 352
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 void SetName(const char* name) { 395 void SetName(const char* name) {
221 if (name == NULL) { 396 if (name == NULL) {
222 name_ = NULL; 397 name_ = NULL;
223 } 398 }
224 intptr_t len = strlen(name); 399 intptr_t len = strlen(name);
225 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1); 400 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
226 strncpy(const_cast<char*>(name_), name, len); 401 strncpy(const_cast<char*>(name_), name, len);
227 const_cast<char*>(name_)[len] = '\0'; 402 const_cast<char*>(name_)[len] = '\0';
228 } 403 }
229 404
405 bool IsOptimizedDart() const {
406 return !code_.IsNull() && code_.is_optimized();
407 }
408
409 RawCode* code() const {
410 return code_.raw();
411 }
412
413 ProfileFunction* SetFunctionAndName(ProfileFunctionTable* table) {
414 ASSERT(profile_function_ == NULL);
415
416 ProfileFunction* function = NULL;
417 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) {
418 if (name() == NULL) {
419 // Lazily set generated name.
420 GenerateAndSetSymbolName("[Collected]");
421 }
422 // Map these to a canonical unknown function.
423 function = table->GetUnknown();
424 } else if (kind() == kDartCode) {
425 ASSERT(!code_.IsNull());
426 const Object& obj = Object::Handle(code_.owner());
427 if (obj.IsFunction()) {
428 const String& user_name = String::Handle(code_.PrettyName());
429 function = table->LookupOrAdd(Function::Cast(obj));
430 SetName(user_name.ToCString());
431 } else {
432 // A stub.
433 const String& user_name = String::Handle(code_.PrettyName());
434 function = table->AddStub(start(), user_name.ToCString());
435 SetName(user_name.ToCString());
436 }
437 } else if (kind() == kNativeCode) {
438 if (name() == NULL) {
439 // Lazily set generated name.
440 GenerateAndSetSymbolName("[Native]");
441 }
442 function = table->AddNative(start(), name());
443 } else if (kind() == kTagCode) {
444 if (name() == NULL) {
445 if (UserTags::IsUserTag(start())) {
446 const char* tag_name = UserTags::TagName(start());
447 ASSERT(tag_name != NULL);
448 SetName(tag_name);
449 } else if (VMTag::IsVMTag(start()) ||
450 VMTag::IsRuntimeEntryTag(start()) ||
451 VMTag::IsNativeEntryTag(start())) {
452 const char* tag_name = VMTag::TagName(start());
453 ASSERT(tag_name != NULL);
454 SetName(tag_name);
455 } else {
456 ASSERT(start() == 0);
457 SetName("root");
458 }
459 }
460 function = table->AddTag(start(), name());
461 } else {
462 UNREACHABLE();
463 }
464 ASSERT(function != NULL);
465 // Register this CodeRegion with this function.
466 function->AddCodeObjectIndex(code_table_index());
467 profile_function_ = function;
468 return profile_function_;
469 }
470
471 ProfileFunction* function() const {
472 ASSERT(profile_function_ != NULL);
473 return profile_function_;
474 }
475
476 void set_code_table_index(intptr_t code_table_index) {
477 ASSERT(code_table_index_ == -1);
478 ASSERT(code_table_index != -1);
479 code_table_index_ = code_table_index;
480 }
481 intptr_t code_table_index() const {
482 ASSERT(code_table_index_ != -1);
483 return code_table_index_;
484 }
485
230 Kind kind() const { return kind_; } 486 Kind kind() const { return kind_; }
231 487
232 static const char* KindToCString(Kind kind) { 488 static const char* KindToCString(Kind kind) {
233 switch (kind) { 489 switch (kind) {
234 case kDartCode: 490 case kDartCode:
235 return "Dart"; 491 return "Dart";
236 case kCollectedCode: 492 case kCollectedCode:
237 return "Collected"; 493 return "Collected";
238 case kNativeCode: 494 case kNativeCode:
239 return "Native"; 495 return "Native";
(...skipping 26 matching lines...) Expand all
266 if (exclusive) { 522 if (exclusive) {
267 exclusive_ticks_++; 523 exclusive_ticks_++;
268 } else { 524 } else {
269 inclusive_ticks_++; 525 inclusive_ticks_++;
270 // Mark the last serial we ticked the inclusive count. 526 // Mark the last serial we ticked the inclusive count.
271 inclusive_tick_serial_ = serial; 527 inclusive_tick_serial_ = serial;
272 } 528 }
273 TickAddress(pc, exclusive); 529 TickAddress(pc, exclusive);
274 } 530 }
275 531
276 void AddCaller(intptr_t index, intptr_t count) {
277 AddCallEntry(callers_table_, index, count);
278 }
279
280 void AddCallee(intptr_t index, intptr_t count) {
281 AddCallEntry(callees_table_, index, count);
282 }
283
284 void PrintNativeCode(JSONObject* profile_code_obj) { 532 void PrintNativeCode(JSONObject* profile_code_obj) {
285 ASSERT(kind() == kNativeCode); 533 ASSERT(kind() == kNativeCode);
286 JSONObject obj(profile_code_obj, "code"); 534 JSONObject obj(profile_code_obj, "code");
287 obj.AddProperty("type", "@Code"); 535 obj.AddProperty("type", "@Code");
288 obj.AddProperty("kind", "Native"); 536 obj.AddProperty("kind", "Native");
289 obj.AddProperty("name", name()); 537 obj.AddProperty("name", name());
290 obj.AddPropertyF("start", "%" Px "", start()); 538 obj.AddPropertyF("start", "%" Px "", start());
291 obj.AddPropertyF("end", "%" Px "", end()); 539 obj.AddPropertyF("end", "%" Px "", end());
292 obj.AddPropertyF("id", "code/native-%" Px "", start());
293 { 540 {
294 // Generate a fake function entry. 541 // Generate a fake function entry.
295 JSONObject func(&obj, "function"); 542 JSONObject func(&obj, "function");
296 func.AddProperty("type", "@Function"); 543 profile_function_->PrintToJSONObject(&func);
297 func.AddPropertyF("id", "functions/native-%" Px "", start());
298 func.AddProperty("name", name());
299 func.AddProperty("kind", "Native");
300 } 544 }
301 } 545 }
302 546
303 void PrintCollectedCode(JSONObject* profile_code_obj) { 547 void PrintCollectedCode(JSONObject* profile_code_obj) {
304 ASSERT(kind() == kCollectedCode); 548 ASSERT(kind() == kCollectedCode);
305 JSONObject obj(profile_code_obj, "code"); 549 JSONObject obj(profile_code_obj, "code");
306 obj.AddProperty("type", "@Code"); 550 obj.AddProperty("type", "@Code");
307 obj.AddProperty("kind", "Collected"); 551 obj.AddProperty("kind", "Collected");
308 obj.AddProperty("name", name()); 552 obj.AddProperty("name", name());
309 obj.AddPropertyF("start", "%" Px "", start()); 553 obj.AddPropertyF("start", "%" Px "", start());
310 obj.AddPropertyF("end", "%" Px "", end()); 554 obj.AddPropertyF("end", "%" Px "", end());
311 obj.AddPropertyF("id", "code/collected-%" Px "", start());
312 { 555 {
313 // Generate a fake function entry. 556 // Generate a fake function entry.
314 JSONObject func(&obj, "function"); 557 JSONObject func(&obj, "function");
315 func.AddProperty("type", "@Function"); 558 profile_function_->PrintToJSONObject(&func);
316 obj.AddPropertyF("id", "functions/collected-%" Px "", start());
317 func.AddProperty("name", name());
318 func.AddProperty("kind", "Collected");
319 } 559 }
320 } 560 }
321 561
322 void PrintOverwrittenCode(JSONObject* profile_code_obj) { 562 void PrintOverwrittenCode(JSONObject* profile_code_obj) {
323 ASSERT(kind() == kReusedCode); 563 ASSERT(kind() == kReusedCode);
324 JSONObject obj(profile_code_obj, "code"); 564 JSONObject obj(profile_code_obj, "code");
325 obj.AddProperty("type", "@Code"); 565 obj.AddProperty("type", "@Code");
326 obj.AddProperty("kind", "Reused"); 566 obj.AddProperty("kind", "Reused");
327 obj.AddProperty("name", name()); 567 obj.AddProperty("name", name());
328 obj.AddPropertyF("start", "%" Px "", start()); 568 obj.AddPropertyF("start", "%" Px "", start());
329 obj.AddPropertyF("end", "%" Px "", end()); 569 obj.AddPropertyF("end", "%" Px "", end());
330 obj.AddPropertyF("id", "code/reused-%" Px "", start());
331 {
332 // Generate a fake function entry.
333 JSONObject func(&obj, "function");
334 func.AddProperty("type", "@Function");
335 obj.AddPropertyF("id", "functions/reused-%" Px "", start());
336 func.AddProperty("name", name());
337 func.AddProperty("kind", "Reused");
338 }
339 }
340
341 void PrintTagCode(JSONObject* profile_code_obj) {
342 ASSERT(kind() == kTagCode);
343 JSONObject obj(profile_code_obj, "code");
344 obj.AddProperty("type", "@Code");
345 obj.AddProperty("kind", "Tag");
346 obj.AddPropertyF("id", "code/tag-%" Px "", start());
347 obj.AddProperty("name", name());
348 obj.AddPropertyF("start", "%" Px "", start());
349 obj.AddPropertyF("end", "%" Px "", end());
350 { 570 {
351 // Generate a fake function entry. 571 // Generate a fake function entry.
352 JSONObject func(&obj, "function"); 572 JSONObject func(&obj, "function");
353 func.AddProperty("type", "@Function"); 573 ASSERT(profile_function_ != NULL);
354 func.AddProperty("kind", "Tag"); 574 profile_function_->PrintToJSONObject(&func);
355 obj.AddPropertyF("id", "functions/tag-%" Px "", start());
356 func.AddProperty("name", name());
357 } 575 }
358 } 576 }
359 577
360 void PrintToJSONArray(Isolate* isolate, JSONArray* events) { 578 void PrintTagCode(JSONObject* profile_code_obj) {
361 JSONObject obj(events); 579 ASSERT(kind() == kTagCode);
580 JSONObject obj(profile_code_obj, "code");
581 obj.AddProperty("type", "@Code");
582 obj.AddProperty("kind", "Tag");
583 obj.AddProperty("name", name());
584 obj.AddPropertyF("start", "%" Px "", start());
585 obj.AddPropertyF("end", "%" Px "", end());
586 {
587 // Generate a fake function entry.
588 JSONObject func(&obj, "function");
589 ASSERT(profile_function_ != NULL);
590 profile_function_->PrintToJSONObject(&func);
591 }
592 }
593
594 void PrintToJSONArray(JSONArray* codes) {
595 JSONObject obj(codes);
362 obj.AddProperty("kind", KindToCString(kind())); 596 obj.AddProperty("kind", KindToCString(kind()));
363 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); 597 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
364 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); 598 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
365 if (kind() == kDartCode) { 599 if (kind() == kDartCode) {
366 // Look up code in Dart heap. 600 ASSERT(!code_.IsNull());
367 Code& code = Code::Handle(isolate); 601 obj.AddProperty("code", code_);
368 code ^= Code::LookupCode(start());
369 if (code.IsNull()) {
370 // Code is a stub in the Vm isolate.
371 code ^= Code::LookupCodeInVmIsolate(start());
372 }
373 ASSERT(!code.IsNull());
374 obj.AddProperty("code", code);
375 } else if (kind() == kCollectedCode) { 602 } else if (kind() == kCollectedCode) {
376 if (name() == NULL) {
377 // Lazily set generated name.
378 GenerateAndSetSymbolName("[Collected]");
379 }
380 PrintCollectedCode(&obj); 603 PrintCollectedCode(&obj);
381 } else if (kind() == kReusedCode) { 604 } else if (kind() == kReusedCode) {
382 if (name() == NULL) {
383 // Lazily set generated name.
384 GenerateAndSetSymbolName("[Reused]");
385 }
386 PrintOverwrittenCode(&obj); 605 PrintOverwrittenCode(&obj);
387 } else if (kind() == kTagCode) { 606 } else if (kind() == kTagCode) {
388 if (name() == NULL) {
389 if (UserTags::IsUserTag(start())) {
390 const char* tag_name = UserTags::TagName(start());
391 ASSERT(tag_name != NULL);
392 SetName(tag_name);
393 } else if (VMTag::IsVMTag(start()) ||
394 VMTag::IsRuntimeEntryTag(start()) ||
395 VMTag::IsNativeEntryTag(start())) {
396 const char* tag_name = VMTag::TagName(start());
397 ASSERT(tag_name != NULL);
398 SetName(tag_name);
399 } else {
400 ASSERT(start() == 0);
401 SetName("root");
402 }
403 }
404 PrintTagCode(&obj); 607 PrintTagCode(&obj);
405 } else { 608 } else {
406 ASSERT(kind() == kNativeCode); 609 ASSERT(kind() == kNativeCode);
407 if (name() == NULL) {
408 // Lazily set generated name.
409 GenerateAndSetSymbolName("[Native]");
410 }
411 PrintNativeCode(&obj); 610 PrintNativeCode(&obj);
412 } 611 }
413 { 612 {
414 JSONArray ticks(&obj, "ticks"); 613 JSONArray ticks(&obj, "ticks");
415 for (intptr_t i = 0; i < address_table_->length(); i++) { 614 for (intptr_t i = 0; i < address_table_.length(); i++) {
416 const AddressEntry& entry = (*address_table_)[i]; 615 const AddressEntry& entry = address_table_[i];
417 ticks.AddValueF("%" Px "", entry.pc); 616 ticks.AddValueF("%" Px "", entry.pc);
418 ticks.AddValueF("%" Pd "", entry.exclusive_ticks); 617 ticks.AddValueF("%" Pd "", entry.exclusive_ticks);
419 ticks.AddValueF("%" Pd "", entry.inclusive_ticks); 618 ticks.AddValueF("%" Pd "", entry.inclusive_ticks);
420 } 619 }
421 } 620 }
422 {
423 JSONArray callers(&obj, "callers");
424 for (intptr_t i = 0; i < callers_table_->length(); i++) {
425 const CallEntry& entry = (*callers_table_)[i];
426 callers.AddValueF("%" Pd "", entry.code_table_index);
427 callers.AddValueF("%" Pd "", entry.count);
428 }
429 }
430 {
431 JSONArray callees(&obj, "callees");
432 for (intptr_t i = 0; i < callees_table_->length(); i++) {
433 const CallEntry& entry = (*callees_table_)[i];
434 callees.AddValueF("%" Pd "", entry.code_table_index);
435 callees.AddValueF("%" Pd "", entry.count);
436 }
437 }
438 } 621 }
439 622
440 private: 623 private:
441 void TickAddress(uword pc, bool exclusive) { 624 void TickAddress(uword pc, bool exclusive) {
442 const intptr_t length = address_table_->length(); 625 const intptr_t length = address_table_.length();
443 intptr_t i = 0; 626 intptr_t i = 0;
444 for (; i < length; i++) { 627 for (; i < length; i++) {
445 AddressEntry& entry = (*address_table_)[i]; 628 AddressEntry& entry = address_table_[i];
446 if (entry.pc == pc) { 629 if (entry.pc == pc) {
447 // Tick the address entry. 630 // Tick the address entry.
448 entry.tick(exclusive); 631 entry.tick(exclusive);
449 return; 632 return;
450 } 633 }
451 if (entry.pc > pc) { 634 if (entry.pc > pc) {
452 break; 635 break;
453 } 636 }
454 } 637 }
455 // New address, add entry. 638 // New address, add entry.
456 AddressEntry entry; 639 AddressEntry entry;
457 entry.pc = pc; 640 entry.pc = pc;
458 entry.exclusive_ticks = 0; 641 entry.exclusive_ticks = 0;
459 entry.inclusive_ticks = 0; 642 entry.inclusive_ticks = 0;
460 entry.tick(exclusive); 643 entry.tick(exclusive);
461 if (i < length) { 644 if (i < length) {
462 // Insert at i. 645 // Insert at i.
463 address_table_->InsertAt(i, entry); 646 address_table_.InsertAt(i, entry);
464 } else { 647 } else {
465 // Add to end. 648 // Add to end.
466 address_table_->Add(entry); 649 address_table_.Add(entry);
467 } 650 }
468 } 651 }
469 652
470
471 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index,
472 intptr_t count) {
473 const intptr_t length = table->length();
474 intptr_t i = 0;
475 for (; i < length; i++) {
476 CallEntry& entry = (*table)[i];
477 if (entry.code_table_index == index) {
478 entry.count += count;
479 return;
480 }
481 if (entry.code_table_index > index) {
482 break;
483 }
484 }
485 CallEntry entry;
486 entry.code_table_index = index;
487 entry.count = count;
488 if (i < length) {
489 table->InsertAt(i, entry);
490 } else {
491 table->Add(entry);
492 }
493 }
494
495 void GenerateAndSetSymbolName(const char* prefix) { 653 void GenerateAndSetSymbolName(const char* prefix) {
496 const intptr_t kBuffSize = 512; 654 const intptr_t kBuffSize = 512;
497 char buff[kBuffSize]; 655 char buff[kBuffSize];
498 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", 656 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
499 prefix, start(), end()); 657 prefix, start(), end());
500 SetName(buff); 658 SetName(buff);
501 } 659 }
502 660
503 // CodeRegion kind. 661 // CodeRegion kind.
504 const Kind kind_; 662 const Kind kind_;
505 // CodeRegion start address. 663 // CodeRegion start address.
506 uword start_; 664 uword start_;
507 // CodeRegion end address. 665 // CodeRegion end address.
508 uword end_; 666 uword end_;
509 // Inclusive ticks. 667 // Inclusive ticks.
510 intptr_t inclusive_ticks_; 668 intptr_t inclusive_ticks_;
511 // Exclusive ticks. 669 // Exclusive ticks.
512 intptr_t exclusive_ticks_; 670 intptr_t exclusive_ticks_;
513 // Inclusive tick serial number, ensures that each CodeRegion is only given 671 // Inclusive tick serial number, ensures that each CodeRegion is only given
514 // a single inclusive tick per sample. 672 // a single inclusive tick per sample.
515 intptr_t inclusive_tick_serial_; 673 intptr_t inclusive_tick_serial_;
516 // Name of code region. 674 // Name of code region.
517 const char* name_; 675 const char* name_;
518 // The compilation timestamp associated with this code region. 676 // The compilation timestamp associated with this code region.
519 int64_t compile_timestamp_; 677 int64_t compile_timestamp_;
520 // Serial number at which this CodeRegion was created. 678 // Serial number at which this CodeRegion was created.
521 intptr_t creation_serial_; 679 intptr_t creation_serial_;
522 ZoneGrowableArray<AddressEntry>* address_table_; 680 // Dart code object (may be null).
523 ZoneGrowableArray<CallEntry>* callers_table_; 681 const Code& code_;
524 ZoneGrowableArray<CallEntry>* callees_table_; 682 // Pointer to ProfileFunction.
683 ProfileFunction* profile_function_;
684 // Final code table index.
685 intptr_t code_table_index_;
686 ZoneGrowableArray<AddressEntry> address_table_;
525 DISALLOW_COPY_AND_ASSIGN(CodeRegion); 687 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
526 }; 688 };
527 689
528 690
529 // A sorted table of CodeRegions. Does not allow for overlap. 691 // A sorted table of CodeRegions. Does not allow for overlap.
530 class CodeRegionTable : public ValueObject { 692 class CodeRegionTable : public ValueObject {
531 public: 693 public:
532 enum TickResult { 694 enum TickResult {
533 kTicked = 0, // CodeRegion found and ticked. 695 kTicked = 0, // CodeRegion found and ticked.
534 kNotFound = -1, // No CodeRegion found. 696 kNotFound = -1, // No CodeRegion found.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 if (region->overlaps(code_region)) { 796 if (region->overlaps(code_region)) {
635 HandleOverlap(region, code_region, start, end); 797 HandleOverlap(region, code_region, start, end);
636 return hi; 798 return hi;
637 } 799 }
638 code_region_table_->InsertAt(hi, code_region); 800 code_region_table_->InsertAt(hi, code_region);
639 return hi; 801 return hi;
640 } 802 }
641 UNREACHABLE(); 803 UNREACHABLE();
642 } 804 }
643 805
644 #if defined(DEBUG)
645 void Verify() { 806 void Verify() {
646 VerifyOrder(); 807 VerifyOrder();
647 VerifyOverlap(); 808 VerifyOverlap();
648 } 809 }
649 #endif
650 810
651 void DebugPrint() { 811 void DebugPrint() {
652 OS::Print("Dumping CodeRegionTable:\n"); 812 OS::Print("Dumping CodeRegionTable:\n");
653 for (intptr_t i = 0; i < code_region_table_->length(); i++) { 813 for (intptr_t i = 0; i < code_region_table_->length(); i++) {
654 CodeRegion* region = At(i); 814 CodeRegion* region = At(i);
655 region->DebugPrint(); 815 region->DebugPrint();
656 } 816 }
657 } 817 }
658 818
659 private: 819 private:
(...skipping 28 matching lines...) Expand all
688 uword start, uword end) { 848 uword start, uword end) {
689 // We should never see overlapping Dart code regions. 849 // We should never see overlapping Dart code regions.
690 ASSERT(region->kind() != CodeRegion::kDartCode); 850 ASSERT(region->kind() != CodeRegion::kDartCode);
691 // We should never see overlapping Tag code regions. 851 // We should never see overlapping Tag code regions.
692 ASSERT(region->kind() != CodeRegion::kTagCode); 852 ASSERT(region->kind() != CodeRegion::kTagCode);
693 // When code regions overlap, they should be of the same kind. 853 // When code regions overlap, they should be of the same kind.
694 ASSERT(region->kind() == code_region->kind()); 854 ASSERT(region->kind() == code_region->kind());
695 region->AdjustExtent(start, end); 855 region->AdjustExtent(start, end);
696 } 856 }
697 857
698 #if defined(DEBUG)
699 void VerifyOrder() { 858 void VerifyOrder() {
700 const intptr_t length = code_region_table_->length(); 859 const intptr_t length = code_region_table_->length();
701 if (length == 0) { 860 if (length == 0) {
702 return; 861 return;
703 } 862 }
704 uword last = (*code_region_table_)[0]->end(); 863 uword last = (*code_region_table_)[0]->end();
705 for (intptr_t i = 1; i < length; i++) { 864 for (intptr_t i = 1; i < length; i++) {
706 CodeRegion* a = (*code_region_table_)[i]; 865 CodeRegion* a = (*code_region_table_)[i];
707 ASSERT(last <= a->start()); 866 ASSERT(last <= a->start());
708 last = a->end(); 867 last = a->end();
709 } 868 }
710 } 869 }
711 870
712 void VerifyOverlap() { 871 void VerifyOverlap() {
713 const intptr_t length = code_region_table_->length(); 872 const intptr_t length = code_region_table_->length();
714 for (intptr_t i = 0; i < length; i++) { 873 for (intptr_t i = 0; i < length; i++) {
715 CodeRegion* a = (*code_region_table_)[i]; 874 CodeRegion* a = (*code_region_table_)[i];
716 for (intptr_t j = i+1; j < length; j++) { 875 for (intptr_t j = i+1; j < length; j++) {
717 CodeRegion* b = (*code_region_table_)[j]; 876 CodeRegion* b = (*code_region_table_)[j];
718 ASSERT(!a->contains(b->start()) && 877 ASSERT(!a->contains(b->start()) &&
719 !a->contains(b->end() - 1) && 878 !a->contains(b->end() - 1) &&
720 !b->contains(a->start()) && 879 !b->contains(a->start()) &&
721 !b->contains(a->end() - 1)); 880 !b->contains(a->end() - 1));
722 } 881 }
723 } 882 }
724 } 883 }
725 #endif
726 884
727 ZoneGrowableArray<CodeRegion*>* code_region_table_; 885 ZoneGrowableArray<CodeRegion*>* code_region_table_;
728 }; 886 };
729 887
730 888
731 class FixTopFrameVisitor : public SampleVisitor {
732 public:
733 explicit FixTopFrameVisitor(Isolate* isolate)
734 : SampleVisitor(isolate),
735 vm_isolate_(Dart::vm_isolate()) {
736 }
737
738 void VisitSample(Sample* sample) {
739 if (sample->processed()) {
740 // Already processed.
741 return;
742 }
743 REUSABLE_CODE_HANDLESCOPE(isolate());
744 // Mark that we've processed this sample.
745 sample->set_processed(true);
746 // Lookup code object for leaf frame.
747 Code& code = reused_code_handle.Handle();
748 code = FindCodeForPC(sample->At(0));
749 sample->set_leaf_frame_is_dart(!code.IsNull());
750 if (sample->pc_marker() == 0) {
751 // No pc marker. Nothing to do.
752 return;
753 }
754 if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) {
755 // Code compiled after sample. Ignore.
756 return;
757 }
758 if (sample->leaf_frame_is_dart()) {
759 CheckForMissingDartFrame(code, sample);
760 }
761 }
762
763 private:
764 void CheckForMissingDartFrame(const Code& code, Sample* sample) const {
765 // Some stubs (and intrinsics) do not push a frame onto the stack leaving
766 // the frame pointer in the caller.
767 //
768 // PC -> STUB
769 // FP -> DART3 <-+
770 // DART2 <-| <- TOP FRAME RETURN ADDRESS.
771 // DART1 <-|
772 // .....
773 //
774 // In this case, traversing the linked stack frames will not collect a PC
775 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1.
776 // In Dart code, after pushing the FP onto the stack, an IP in the current
777 // function is pushed onto the stack as well. This stack slot is called
778 // the PC marker. We can use the PC marker to insert DART3 into the stack
779 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the
780 // inserted PC may not accurately reflect the true return address from STUB.
781 ASSERT(!code.IsNull());
782 if (sample->sp() == sample->fp()) {
783 // Haven't pushed pc marker yet.
784 return;
785 }
786 uword pc_marker = sample->pc_marker();
787 if (code.ContainsInstructionAt(pc_marker)) {
788 // PC marker is in the same code as pc, no missing frame.
789 return;
790 }
791 if (!ContainedInDartCodeHeaps(pc_marker)) {
792 // Not a valid PC marker.
793 return;
794 }
795 sample->InsertCallerForTopFrame(pc_marker);
796 }
797
798 bool ContainedInDartCodeHeaps(uword pc) const {
799 return isolate()->heap()->CodeContains(pc) ||
800 vm_isolate()->heap()->CodeContains(pc);
801 }
802
803 Isolate* vm_isolate() const {
804 return vm_isolate_;
805 }
806
807 RawCode* FindCodeForPC(uword pc) const {
808 // Check current isolate for pc.
809 if (isolate()->heap()->CodeContains(pc)) {
810 return Code::LookupCode(pc);
811 }
812 // Check VM isolate for pc.
813 if (vm_isolate()->heap()->CodeContains(pc)) {
814 return Code::LookupCodeInVmIsolate(pc);
815 }
816 return Code::null();
817 }
818
819 Isolate* vm_isolate_;
820 };
821
822
823 class CodeRegionTableBuilder : public SampleVisitor { 889 class CodeRegionTableBuilder : public SampleVisitor {
824 public: 890 public:
825 CodeRegionTableBuilder(Isolate* isolate, 891 CodeRegionTableBuilder(Isolate* isolate,
826 CodeRegionTable* live_code_table, 892 CodeRegionTable* live_code_table,
827 CodeRegionTable* dead_code_table, 893 CodeRegionTable* dead_code_table,
828 CodeRegionTable* tag_code_table) 894 CodeRegionTable* tag_code_table)
829 : SampleVisitor(isolate), 895 : SampleVisitor(isolate),
830 live_code_table_(live_code_table), 896 live_code_table_(live_code_table),
831 dead_code_table_(dead_code_table), 897 dead_code_table_(dead_code_table),
832 tag_code_table_(tag_code_table), 898 tag_code_table_(tag_code_table),
833 isolate_(isolate), 899 isolate_(isolate),
834 vm_isolate_(Dart::vm_isolate()) { 900 vm_isolate_(Dart::vm_isolate()),
901 null_code_(Code::ZoneHandle()) {
835 ASSERT(live_code_table_ != NULL); 902 ASSERT(live_code_table_ != NULL);
836 ASSERT(dead_code_table_ != NULL); 903 ASSERT(dead_code_table_ != NULL);
837 ASSERT(tag_code_table_ != NULL); 904 ASSERT(tag_code_table_ != NULL);
905 ASSERT(isolate_ != NULL);
906 ASSERT(vm_isolate_ != NULL);
907 ASSERT(null_code_.IsNull());
838 frames_ = 0; 908 frames_ = 0;
839 min_time_ = kMaxInt64; 909 min_time_ = kMaxInt64;
840 max_time_ = 0; 910 max_time_ = 0;
841 ASSERT(isolate_ != NULL);
842 ASSERT(vm_isolate_ != NULL);
843 } 911 }
844 912
845 void VisitSample(Sample* sample) { 913 void VisitSample(Sample* sample) {
846 int64_t timestamp = sample->timestamp(); 914 int64_t timestamp = sample->timestamp();
847 if (timestamp > max_time_) { 915 if (timestamp > max_time_) {
848 max_time_ = timestamp; 916 max_time_ = timestamp;
849 } 917 }
850 if (timestamp < min_time_) { 918 if (timestamp < min_time_) {
851 min_time_ = timestamp; 919 min_time_ = timestamp;
852 } 920 }
853 // Make sure VM tag is created. 921 // Make sure VM tag is created.
854 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { 922 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
855 CreateTag(VMTag::kNativeTagId); 923 CreateTag(VMTag::kNativeTagId);
856 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 924 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
857 CreateTag(VMTag::kRuntimeTagId); 925 CreateTag(VMTag::kRuntimeTagId);
858 } 926 }
859 CreateTag(sample->vm_tag()); 927 CreateTag(sample->vm_tag());
860 // Make sure user tag is created. 928 // Make sure user tag is created.
861 CreateUserTag(sample->user_tag()); 929 CreateUserTag(sample->user_tag());
862 // Exclusive tick for bottom frame if we aren't sampled from an exit frame. 930 // Exclusive tick for top frame if we aren't sampled from an exit frame.
863 if (!sample->exit_frame_sample()) { 931 if (!sample->exit_frame_sample()) {
864 Tick(sample->At(0), true, timestamp); 932 Tick(sample->At(0), true, timestamp);
865 } 933 }
866 // Inclusive tick for all frames. 934 // Inclusive tick for all frames.
867 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { 935 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
868 if (sample->At(i) == 0) { 936 if (sample->At(i) == 0) {
869 break; 937 break;
870 } 938 }
871 frames_++; 939 frames_++;
872 Tick(sample->At(i), false, timestamp); 940 Tick(sample->At(i), false, timestamp);
(...skipping 10 matching lines...) Expand all
883 private: 951 private:
884 void CreateTag(uword tag) { 952 void CreateTag(uword tag) {
885 intptr_t index = tag_code_table_->FindIndex(tag); 953 intptr_t index = tag_code_table_->FindIndex(tag);
886 if (index >= 0) { 954 if (index >= 0) {
887 // Already created. 955 // Already created.
888 return; 956 return;
889 } 957 }
890 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 958 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
891 tag, 959 tag,
892 tag + 1, 960 tag + 1,
893 0); 961 0,
962 null_code_);
894 index = tag_code_table_->InsertCodeRegion(region); 963 index = tag_code_table_->InsertCodeRegion(region);
895 ASSERT(index >= 0); 964 ASSERT(index >= 0);
896 region->set_creation_serial(visited()); 965 region->set_creation_serial(visited());
897 } 966 }
898 967
899 void CreateUserTag(uword tag) { 968 void CreateUserTag(uword tag) {
900 if (tag == 0) { 969 if (tag == 0) {
901 // None set. 970 // None set.
902 return; 971 return;
903 } 972 }
904 intptr_t index = tag_code_table_->FindIndex(tag); 973 return CreateTag(tag);
905 if (index >= 0) {
906 // Already created.
907 return;
908 }
909 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
910 tag,
911 tag + 1,
912 0);
913 index = tag_code_table_->InsertCodeRegion(region);
914 ASSERT(index >= 0);
915 region->set_creation_serial(visited());
916 } 974 }
917 975
918 void Tick(uword pc, bool exclusive, int64_t timestamp) { 976 void Tick(uword pc, bool exclusive, int64_t timestamp) {
919 CodeRegionTable::TickResult r; 977 CodeRegionTable::TickResult r;
920 intptr_t serial = exclusive ? -1 : visited(); 978 intptr_t serial = exclusive ? -1 : visited();
921 r = live_code_table_->Tick(pc, exclusive, serial, timestamp); 979 r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
922 if (r == CodeRegionTable::kTicked) { 980 if (r == CodeRegionTable::kTicked) {
923 // Live code found and ticked. 981 // Live code found and ticked.
924 return; 982 return;
925 } 983 }
(...skipping 25 matching lines...) Expand all
951 // compiled after the sample. 1009 // compiled after the sample.
952 ASSERT(region->kind() == CodeRegion::kDartCode); 1010 ASSERT(region->kind() == CodeRegion::kDartCode);
953 CreateAndTickDeadCodeRegion(pc, exclusive, serial); 1011 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
954 } 1012 }
955 1013
956 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) { 1014 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
957 // Need to create dead code. 1015 // Need to create dead code.
958 CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode, 1016 CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode,
959 pc, 1017 pc,
960 pc + 1, 1018 pc + 1,
961 0); 1019 0,
1020 null_code_);
962 intptr_t index = dead_code_table_->InsertCodeRegion(region); 1021 intptr_t index = dead_code_table_->InsertCodeRegion(region);
963 region->set_creation_serial(visited()); 1022 region->set_creation_serial(visited());
964 ASSERT(index >= 0); 1023 ASSERT(index >= 0);
965 dead_code_table_->At(index)->Tick(pc, exclusive, serial); 1024 dead_code_table_->At(index)->Tick(pc, exclusive, serial);
966 } 1025 }
967 1026
968 CodeRegion* CreateCodeRegion(uword pc) { 1027 CodeRegion* CreateCodeRegion(uword pc) {
969 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment(); 1028 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
970 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); 1029 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
971 Code& code = Code::Handle(isolate_); 1030 Code& code = Code::Handle(isolate_);
972 // Check current isolate for pc. 1031 // Check current isolate for pc.
973 if (isolate_->heap()->CodeContains(pc)) { 1032 if (isolate_->heap()->CodeContains(pc)) {
974 code ^= Code::LookupCode(pc); 1033 code ^= Code::LookupCode(pc);
975 if (!code.IsNull()) { 1034 if (!code.IsNull()) {
976 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), 1035 return new CodeRegion(CodeRegion::kDartCode,
1036 code.EntryPoint(),
977 code.EntryPoint() + code.Size(), 1037 code.EntryPoint() + code.Size(),
978 code.compile_timestamp()); 1038 code.compile_timestamp(),
1039 code);
979 } 1040 }
980 return new CodeRegion(CodeRegion::kCollectedCode, pc, 1041 return new CodeRegion(CodeRegion::kCollectedCode,
1042 pc,
981 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment, 1043 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
982 0); 1044 0,
1045 code);
983 } 1046 }
984 // Check VM isolate for pc. 1047 // Check VM isolate for pc.
985 if (vm_isolate_->heap()->CodeContains(pc)) { 1048 if (vm_isolate_->heap()->CodeContains(pc)) {
986 code ^= Code::LookupCodeInVmIsolate(pc); 1049 code ^= Code::LookupCodeInVmIsolate(pc);
987 if (!code.IsNull()) { 1050 if (!code.IsNull()) {
988 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), 1051 return new CodeRegion(CodeRegion::kDartCode,
1052 code.EntryPoint(),
989 code.EntryPoint() + code.Size(), 1053 code.EntryPoint() + code.Size(),
990 code.compile_timestamp()); 1054 code.compile_timestamp(),
1055 code);
991 } 1056 }
992 return new CodeRegion(CodeRegion::kCollectedCode, pc, 1057 return new CodeRegion(CodeRegion::kCollectedCode,
1058 pc,
993 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment, 1059 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
994 0); 1060 0,
1061 code);
995 } 1062 }
996 // Check NativeSymbolResolver for pc. 1063 // Check NativeSymbolResolver for pc.
997 uintptr_t native_start = 0; 1064 uintptr_t native_start = 0;
998 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, 1065 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
999 &native_start); 1066 &native_start);
1000 if (native_name == NULL) { 1067 if (native_name == NULL) {
1001 // No native name found. 1068 // No native name found.
1002 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1, 0); 1069 return new CodeRegion(CodeRegion::kNativeCode,
1070 pc,
1071 pc + 1,
1072 0,
1073 code);
1003 } 1074 }
1004 ASSERT(pc >= native_start); 1075 ASSERT(pc >= native_start);
1005 CodeRegion* code_region = 1076 CodeRegion* code_region =
1006 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1, 0); 1077 new CodeRegion(CodeRegion::kNativeCode,
1078 native_start,
1079 pc + 1,
1080 0,
1081 code);
1007 code_region->SetName(native_name); 1082 code_region->SetName(native_name);
1008 free(native_name); 1083 free(native_name);
1009 return code_region; 1084 return code_region;
1010 } 1085 }
1011 1086
1012 intptr_t frames_; 1087 intptr_t frames_;
1013 int64_t min_time_; 1088 int64_t min_time_;
1014 int64_t max_time_; 1089 int64_t max_time_;
1015 CodeRegionTable* live_code_table_; 1090 CodeRegionTable* live_code_table_;
1016 CodeRegionTable* dead_code_table_; 1091 CodeRegionTable* dead_code_table_;
1017 CodeRegionTable* tag_code_table_; 1092 CodeRegionTable* tag_code_table_;
1018 Isolate* isolate_; 1093 Isolate* isolate_;
1019 Isolate* vm_isolate_; 1094 Isolate* vm_isolate_;
1095 const Code& null_code_;
1020 }; 1096 };
1021 1097
1022 1098
1023 class CodeRegionExclusiveTrieBuilder : public SampleVisitor { 1099 class CodeRegionFunctionMapper : public ValueObject {
1024 public: 1100 public:
1025 CodeRegionExclusiveTrieBuilder(Isolate* isolate, 1101 CodeRegionFunctionMapper(Isolate* isolate,
1026 CodeRegionTable* live_code_table, 1102 CodeRegionTable* live_code_table,
1027 CodeRegionTable* dead_code_table, 1103 CodeRegionTable* dead_code_table,
1028 CodeRegionTable* tag_code_table) 1104 CodeRegionTable* tag_code_table,
1029 : SampleVisitor(isolate), 1105 ProfileFunctionTable* function_table)
1106 : isolate_(isolate),
1030 live_code_table_(live_code_table), 1107 live_code_table_(live_code_table),
1031 dead_code_table_(dead_code_table), 1108 dead_code_table_(dead_code_table),
1032 tag_code_table_(tag_code_table) { 1109 tag_code_table_(tag_code_table),
1110 function_table_(function_table) {
1111 ASSERT(isolate_ != NULL);
1033 ASSERT(live_code_table_ != NULL); 1112 ASSERT(live_code_table_ != NULL);
1034 ASSERT(dead_code_table_ != NULL); 1113 ASSERT(dead_code_table_ != NULL);
1035 ASSERT(tag_code_table_ != NULL); 1114 ASSERT(tag_code_table_ != NULL);
1036 dead_code_table_offset_ = live_code_table_->Length(); 1115 dead_code_table_offset_ = live_code_table_->Length();
1037 tag_code_table_offset_ = dead_code_table_offset_ + 1116 tag_code_table_offset_ = dead_code_table_offset_ +
1038 dead_code_table_->Length(); 1117 dead_code_table_->Length();
1039 intptr_t root_index = tag_code_table_->FindIndex(0); 1118 intptr_t root_index = tag_code_table_->FindIndex(0);
1040 // Verify that the "0" tag does not exist. 1119 // Verify that the "0" tag does not exist.
1041 ASSERT(root_index < 0); 1120 ASSERT(root_index < 0);
1042 // Insert the dummy tag CodeRegion that is used for the Trie root. 1121 // Insert the dummy tag CodeRegion as the root.
1043 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0); 1122 const Code& null_code = Code::ZoneHandle();
1123 CodeRegion* region =
1124 new CodeRegion(CodeRegion::kTagCode, 0, 1, 0, null_code);
1044 root_index = tag_code_table_->InsertCodeRegion(region); 1125 root_index = tag_code_table_->InsertCodeRegion(region);
1045 ASSERT(root_index >= 0); 1126 ASSERT(root_index >= 0);
1046 region->set_creation_serial(0); 1127 region->set_creation_serial(0);
1047 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); 1128 }
1129
1130 void Map() {
1131 // Calculate final indexes in code table for each CodeRegion.
1132 for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
1133 const intptr_t index = i;
1134 CodeRegion* region = live_code_table_->At(i);
1135 ASSERT(region != NULL);
1136 region->set_code_table_index(index);
1137 }
1138
1139 for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
1140 const intptr_t index = dead_code_table_offset_ + i;
1141 CodeRegion* region = dead_code_table_->At(i);
1142 ASSERT(region != NULL);
1143 region->set_code_table_index(index);
1144 }
1145
1146 for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
1147 const intptr_t index = tag_code_table_offset_ + i;
1148 CodeRegion* region = tag_code_table_->At(i);
1149 ASSERT(region != NULL);
1150 region->set_code_table_index(index);
1151 }
1152
1153 // Associate a ProfileFunction with each CodeRegion.
1154 for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
1155 CodeRegion* region = live_code_table_->At(i);
1156 ASSERT(region != NULL);
1157 region->SetFunctionAndName(function_table_);
1158 }
1159
1160 for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
1161 CodeRegion* region = dead_code_table_->At(i);
1162 ASSERT(region != NULL);
1163 region->SetFunctionAndName(function_table_);
1164 }
1165
1166 for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
1167 CodeRegion* region = tag_code_table_->At(i);
1168 ASSERT(region != NULL);
1169 region->SetFunctionAndName(function_table_);
1170 }
1171 }
1172
1173 private:
1174 Isolate* isolate_;
1175 CodeRegionTable* live_code_table_;
1176 CodeRegionTable* dead_code_table_;
1177 CodeRegionTable* tag_code_table_;
1178 ProfileFunctionTable* function_table_;
1179 intptr_t dead_code_table_offset_;
1180 intptr_t tag_code_table_offset_;
1181 };
1182
1183
1184 class ProfileFunctionTrieNodeCode {
1185 public:
1186 explicit ProfileFunctionTrieNodeCode(intptr_t index)
1187 : code_index_(index),
1188 ticks_(0) {
1189 }
1190
1191 intptr_t index() const {
1192 return code_index_;
1193 }
1194
1195 void Tick() {
1196 ticks_++;
1197 }
1198
1199 intptr_t ticks() const {
1200 return ticks_;
1201 }
1202
1203 private:
1204 intptr_t code_index_;
1205 intptr_t ticks_;
1206 };
1207
1208
1209 class ProfileFunctionTrieNode : public ZoneAllocated {
1210 public:
1211 explicit ProfileFunctionTrieNode(intptr_t profile_function_table_index)
1212 : profile_function_table_index_(profile_function_table_index),
1213 count_(0),
1214 code_objects_(new ZoneGrowableArray<ProfileFunctionTrieNodeCode>()) {
1215 }
1216
1217 void Tick() {
1218 count_++;
1219 }
1220
1221 intptr_t count() const {
1222 return count_;
1223 }
1224
1225 intptr_t profile_function_table_index() const {
1226 return profile_function_table_index_;
1227 }
1228
1229
1230 ProfileFunctionTrieNode* GetChild(intptr_t child_index) {
1231 const intptr_t length = children_.length();
1232 intptr_t i = 0;
1233 while (i < length) {
1234 ProfileFunctionTrieNode* child = children_[i];
1235 if (child->profile_function_table_index() == child_index) {
1236 return child;
1237 }
1238 if (child->profile_function_table_index() > child_index) {
1239 break;
1240 }
1241 i++;
1242 }
1243 // Add new ProfileFunctionTrieNode, sorted by index.
1244 ProfileFunctionTrieNode* child =
1245 new ProfileFunctionTrieNode(child_index);
1246 if (i < length) {
1247 // Insert at i.
1248 children_.InsertAt(i, child);
1249 } else {
1250 // Add to end.
1251 children_.Add(child);
1252 }
1253 return child;
1254 }
1255
1256 void AddCodeObjectIndex(intptr_t index) {
1257 for (intptr_t i = 0; i < code_objects_->length(); i++) {
1258 ProfileFunctionTrieNodeCode& code_object = (*code_objects_)[i];
1259 if (code_object.index() == index) {
1260 code_object.Tick();
1261 return;
1262 }
1263 }
1264 ProfileFunctionTrieNodeCode code_object(index);
1265 code_object.Tick();
1266 code_objects_->Add(code_object);
1267 }
1268
1269 // This should only be called after the trie is completely built.
1270 void SortByCount() {
1271 code_objects_->Sort(ProfileFunctionTrieNodeCodeCompare);
1272 children_.Sort(ProfileFunctionTrieNodeCompare);
1273 intptr_t child_count = children_.length();
1274 // Recurse.
1275 for (intptr_t i = 0; i < child_count; i++) {
1276 children_[i]->SortByCount();
1277 }
1278 }
1279
1280 void PrintToJSONArray(JSONArray* array) const {
1281 ASSERT(array != NULL);
1282 // Write CodeRegion index.
1283 array->AddValue(profile_function_table_index_);
1284 // Write count.
1285 array->AddValue(count_);
1286 // Write number of code objects.
1287 intptr_t code_count = code_objects_->length();
1288 array->AddValue(code_count);
1289 // Write each code object index and ticks.
1290 for (intptr_t i = 0; i < code_count; i++) {
1291 array->AddValue((*code_objects_)[i].index());
1292 array->AddValue((*code_objects_)[i].ticks());
1293 }
1294 // Write number of children.
1295 intptr_t child_count = children_.length();
1296 array->AddValue(child_count);
1297 // Recurse.
1298 for (intptr_t i = 0; i < child_count; i++) {
1299 children_[i]->PrintToJSONArray(array);
1300 }
1301 }
1302
1303 private:
1304 static int ProfileFunctionTrieNodeCodeCompare(
1305 const ProfileFunctionTrieNodeCode* a,
1306 const ProfileFunctionTrieNodeCode* b) {
1307 ASSERT(a != NULL);
1308 ASSERT(b != NULL);
1309 return b->ticks() - a->ticks();
1310 }
1311
1312 static int ProfileFunctionTrieNodeCompare(ProfileFunctionTrieNode* const* a,
1313 ProfileFunctionTrieNode* const* b) {
1314 ASSERT(a != NULL);
1315 ASSERT(b != NULL);
1316 return (*b)->count() - (*a)->count();
1317 }
1318
1319 const intptr_t profile_function_table_index_;
1320 intptr_t count_;
1321 ZoneGrowableArray<ProfileFunctionTrieNode*> children_;
1322 ZoneGrowableArray<ProfileFunctionTrieNodeCode>* code_objects_;
1323 };
1324
1325
1326 class ProfileFunctionExclusiveTrieBuilder : public SampleVisitor {
1327 public:
1328 ProfileFunctionExclusiveTrieBuilder(Isolate* isolate,
1329 CodeRegionTable* live_code_table,
1330 CodeRegionTable* dead_code_table,
1331 CodeRegionTable* tag_code_table,
1332 ProfileFunctionTable* function_table)
1333 : SampleVisitor(isolate),
1334 live_code_table_(live_code_table),
1335 dead_code_table_(dead_code_table),
1336 tag_code_table_(tag_code_table),
1337 function_table_(function_table),
1338 trace_(false),
1339 trace_code_filter_(NULL) {
1340 ASSERT(live_code_table_ != NULL);
1341 ASSERT(dead_code_table_ != NULL);
1342 ASSERT(tag_code_table_ != NULL);
1343 ASSERT(function_table_ != NULL);
1048 set_tag_order(ProfilerService::kUserVM); 1344 set_tag_order(ProfilerService::kUserVM);
1345
1346 intptr_t root_index = tag_code_table_->FindIndex(0);
1347 // Verify that the "0" tag does exist.
1348 ASSERT(root_index >= 0);
1349 CodeRegion* region = tag_code_table_->At(root_index);
1350 ASSERT(region != NULL);
1351
1352 ProfileFunction* function = region->function();
1353 root_ = new ProfileFunctionTrieNode(function->index());
1049 } 1354 }
1050 1355
1051 void VisitSample(Sample* sample) { 1356 void VisitSample(Sample* sample) {
1052 // Give the root a tick. 1357 // Give the root a tick.
1053 root_->Tick(); 1358 root_->Tick();
1054 CodeRegionTrieNode* current = root_; 1359 ProfileFunctionTrieNode* current = root_;
1055 current = ProcessTags(sample, current); 1360 current = ProcessTags(sample, current);
1056 // Walk the sampled PCs. 1361 // Walk the sampled PCs.
1057 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { 1362 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
1058 if (sample->At(i) == 0) { 1363 if (sample->At(i) == 0) {
1059 break; 1364 break;
1060 } 1365 }
1061 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); 1366 // If we aren't sampled out of an exit frame and this is the top
1062 current = current->GetChild(index); 1367 // frame.
1063 current->Tick(); 1368 bool exclusive_tick = (i == 0) && !sample->exit_frame_sample();
1064 } 1369 current = ProcessPC(sample->At(i), sample->timestamp(), current,
1065 } 1370 visited(), exclusive_tick,
1066 1371 sample->missing_frame_inserted());
1067 CodeRegionTrieNode* root() const { 1372 }
1373 }
1374
1375 ProfileFunctionTrieNode* root() const {
1068 return root_; 1376 return root_;
1069 } 1377 }
1070 1378
1071 ProfilerService::TagOrder tag_order() const { 1379 ProfilerService::TagOrder tag_order() const {
1072 return tag_order_; 1380 return tag_order_;
1073 } 1381 }
1074 1382
1075 void set_tag_order(ProfilerService::TagOrder tag_order) { 1383 void set_tag_order(ProfilerService::TagOrder tag_order) {
1076 tag_order_ = tag_order; 1384 tag_order_ = tag_order;
1077 } 1385 }
1078 1386
1079 private: 1387 private:
1080 CodeRegionTrieNode* ProcessUserTags(Sample* sample, 1388 ProfileFunctionTrieNode* ProcessUserTags(Sample* sample,
1081 CodeRegionTrieNode* current) { 1389 ProfileFunctionTrieNode* current) {
1082 intptr_t user_tag_index = FindTagIndex(sample->user_tag()); 1390 intptr_t user_tag_index = FindTagIndex(sample->user_tag());
1083 if (user_tag_index >= 0) { 1391 if (user_tag_index >= 0) {
1084 current = current->GetChild(user_tag_index); 1392 current = current->GetChild(user_tag_index);
1085 // Give the tag a tick. 1393 // Give the tag a tick.
1086 current->Tick(); 1394 current->Tick();
1087 } 1395 }
1088 return current; 1396 return current;
1089 } 1397 }
1090 1398
1091 CodeRegionTrieNode* ProcessVMTags(Sample* sample, 1399 ProfileFunctionTrieNode* ProcessVMTags(Sample* sample,
1092 CodeRegionTrieNode* current) { 1400 ProfileFunctionTrieNode* current) {
1093 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { 1401 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
1094 // Insert a dummy kNativeTagId node. 1402 // Insert a dummy kNativeTagId node.
1095 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId); 1403 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId);
1096 current = current->GetChild(tag_index); 1404 current = current->GetChild(tag_index);
1097 // Give the tag a tick. 1405 // Give the tag a tick.
1098 current->Tick(); 1406 current->Tick();
1099 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 1407 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1100 // Insert a dummy kRuntimeTagId node. 1408 // Insert a dummy kRuntimeTagId node.
1101 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId); 1409 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId);
1102 current = current->GetChild(tag_index); 1410 current = current->GetChild(tag_index);
1103 // Give the tag a tick. 1411 // Give the tag a tick.
1104 current->Tick(); 1412 current->Tick();
1105 } 1413 }
1106 intptr_t tag_index = FindTagIndex(sample->vm_tag()); 1414 intptr_t tag_index = FindTagIndex(sample->vm_tag());
1107 current = current->GetChild(tag_index); 1415 current = current->GetChild(tag_index);
1108 // Give the tag a tick. 1416 // Give the tag a tick.
1109 current->Tick(); 1417 current->Tick();
1110 return current; 1418 return current;
1111 } 1419 }
1112 1420
1113 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) { 1421 ProfileFunctionTrieNode* ProcessTags(Sample* sample,
1422 ProfileFunctionTrieNode* current) {
1114 // None. 1423 // None.
1115 if (tag_order() == ProfilerService::kNoTags) { 1424 if (tag_order() == ProfilerService::kNoTags) {
1116 return current; 1425 return current;
1117 } 1426 }
1118 // User first. 1427 // User first.
1119 if ((tag_order() == ProfilerService::kUserVM) || 1428 if ((tag_order() == ProfilerService::kUserVM) ||
1120 (tag_order() == ProfilerService::kUser)) { 1429 (tag_order() == ProfilerService::kUser)) {
1121 current = ProcessUserTags(sample, current); 1430 current = ProcessUserTags(sample, current);
1122 // Only user. 1431 // Only user.
1123 if (tag_order() == ProfilerService::kUser) { 1432 if (tag_order() == ProfilerService::kUser) {
1124 return current; 1433 return current;
1125 } 1434 }
1126 return ProcessVMTags(sample, current); 1435 return ProcessVMTags(sample, current);
1127 } 1436 }
1128 // VM first. 1437 // VM first.
1129 ASSERT((tag_order() == ProfilerService::kVMUser) || 1438 ASSERT((tag_order() == ProfilerService::kVMUser) ||
1130 (tag_order() == ProfilerService::kVM)); 1439 (tag_order() == ProfilerService::kVM));
1131 current = ProcessVMTags(sample, current); 1440 current = ProcessVMTags(sample, current);
1132 // Only VM. 1441 // Only VM.
1133 if (tag_order() == ProfilerService::kVM) { 1442 if (tag_order() == ProfilerService::kVM) {
1134 return current; 1443 return current;
1135 } 1444 }
1136 return ProcessUserTags(sample, current); 1445 return ProcessUserTags(sample, current);
1137 } 1446 }
1138 1447
1139 intptr_t FindTagIndex(uword tag) const { 1448 intptr_t FindTagIndex(uword tag) const {
1140 if (tag == 0) { 1449 if (tag == 0) {
1450 UNREACHABLE();
1141 return -1; 1451 return -1;
1142 } 1452 }
1143 intptr_t index = tag_code_table_->FindIndex(tag); 1453 intptr_t index = tag_code_table_->FindIndex(tag);
1144 if (index <= 0) { 1454 if (index < 0) {
1455 UNREACHABLE();
1145 return -1; 1456 return -1;
1146 } 1457 }
1147 ASSERT(index >= 0); 1458 ASSERT(index >= 0);
1148 ASSERT((tag_code_table_->At(index))->contains(tag)); 1459 CodeRegion* region = tag_code_table_->At(index);
1149 return tag_code_table_offset_ + index; 1460 ASSERT(region->contains(tag));
1150 } 1461 ProfileFunction* function = region->function();
1151 1462 ASSERT(function != NULL);
1152 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const { 1463 return function->index();
1464 }
1465
1466 void Dump(ProfileFunctionTrieNode* current) {
1467 int current_index = current->profile_function_table_index();
1468 ProfileFunction* function = function_table_->At(current_index);
1469 function->Dump();
1470 OS::Print("\n");
1471 }
1472
1473 ProfileFunctionTrieNode* ProcessPC(uword pc, int64_t timestamp,
1474 ProfileFunctionTrieNode* current,
1475 intptr_t inclusive_serial,
1476 bool exclusive,
1477 bool missing_frame_inserted) {
1478 CodeRegion* region = FindCodeObject(pc, timestamp);
1479 const char* region_name = region->name();
1480 if (region_name == NULL) {
1481 region_name = "";
1482 }
1483 intptr_t code_index = region->code_table_index();
1484 const Code& code = Code::ZoneHandle(region->code());
1485 GrowableArray<Function*> inlined_functions;
1486 if (!code.IsNull()) {
1487 intptr_t offset = pc - code.EntryPoint();
1488 code.GetInlinedFunctionsAt(offset, &inlined_functions);
1489 }
1490 if (code.IsNull() || (inlined_functions.length() == 0)) {
1491 // No inlined functions.
1492 ProfileFunction* function = region->function();
1493 ASSERT(function != NULL);
1494 if (trace_) {
1495 OS::Print("[%" Px "] X - %s (%s)\n",
1496 pc, function->name(), region_name);
1497 }
1498 function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
1499 current = current->GetChild(function->index());
1500 current->AddCodeObjectIndex(code_index);
1501 current->Tick();
1502 if ((trace_code_filter_ != NULL) &&
1503 (strstr(region_name, trace_code_filter_) != NULL)) {
1504 trace_ = true;
1505 OS::Print("Tracing from: %" Px " [%s] ", pc,
1506 missing_frame_inserted ? "INSERTED" : "");
1507 Dump(current);
1508 }
1509 return current;
1510 }
1511
1512
1513 for (intptr_t i = 0; i < inlined_functions.length(); i++) {
1514 Function* inlined_function = inlined_functions[i];
1515 ASSERT(inlined_function != NULL);
1516 ASSERT(!inlined_function->IsNull());
1517 const char* inline_name = inlined_function->ToQualifiedCString();
1518 if (trace_) {
1519 OS::Print("[%" Px "] %" Pd " - %s (%s)\n",
1520 pc, i, inline_name, region_name);
1521 }
1522 ProfileFunction* function =
1523 function_table_->LookupOrAdd(*inlined_function);
1524 ASSERT(function != NULL);
1525 function->AddCodeObjectIndex(code_index);
1526 function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
1527 exclusive = false;
1528 current = current->GetChild(function->index());
1529 current->AddCodeObjectIndex(code_index);
1530 current->Tick();
1531 if ((trace_code_filter_ != NULL) &&
1532 (strstr(region_name, trace_code_filter_) != NULL)) {
1533 trace_ = true;
1534 OS::Print("Tracing from: %" Px " [%s] ",
1535 pc, missing_frame_inserted ? "INSERTED" : "");
1536 Dump(current);
1537 }
1538 }
1539 return current;
1540 }
1541
1542 CodeRegion* FindCodeObject(uword pc, int64_t timestamp) const {
1153 intptr_t index = live_code_table_->FindIndex(pc); 1543 intptr_t index = live_code_table_->FindIndex(pc);
1154 ASSERT(index >= 0); 1544 if (index < 0) {
1545 UNREACHABLE();
1546 return NULL;
1547 }
1155 CodeRegion* region = live_code_table_->At(index); 1548 CodeRegion* region = live_code_table_->At(index);
1156 ASSERT(region->contains(pc)); 1549 ASSERT(region->contains(pc));
1157 if (region->compile_timestamp() > timestamp) { 1550 if (region->compile_timestamp() > timestamp) {
1158 // Overwritten code, find in dead code table. 1551 // Overwritten code, find in dead code table.
1159 index = dead_code_table_->FindIndex(pc); 1552 index = dead_code_table_->FindIndex(pc);
1160 ASSERT(index >= 0); 1553 if (index < 0) {
1554 UNREACHABLE();
1555 return NULL;
1556 }
1161 region = dead_code_table_->At(index); 1557 region = dead_code_table_->At(index);
1162 ASSERT(region->contains(pc)); 1558 ASSERT(region->contains(pc));
1163 ASSERT(region->compile_timestamp() <= timestamp); 1559 ASSERT(region->compile_timestamp() <= timestamp);
1164 return index + dead_code_table_offset_; 1560 return region;
1165 } 1561 }
1166 ASSERT(region->compile_timestamp() <= timestamp); 1562 ASSERT(region->compile_timestamp() <= timestamp);
1167 return index; 1563 return region;
1564 }
1565
1566 ProfilerService::TagOrder tag_order_;
1567 ProfileFunctionTrieNode* root_;
1568 CodeRegionTable* live_code_table_;
1569 CodeRegionTable* dead_code_table_;
1570 CodeRegionTable* tag_code_table_;
1571 ProfileFunctionTable* function_table_;
1572 bool trace_;
1573 const char* trace_code_filter_;
1574 };
1575
1576
1577 class CodeRegionTrieNode : public ZoneAllocated {
1578 public:
1579 explicit CodeRegionTrieNode(intptr_t code_region_index)
1580 : code_region_index_(code_region_index),
1581 count_(0),
1582 children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) {
1583 }
1584
1585 void Tick() {
1586 ASSERT(code_region_index_ >= 0);
1587 count_++;
1588 }
1589
1590 intptr_t count() const {
1591 ASSERT(code_region_index_ >= 0);
1592 return count_;
1593 }
1594
1595 intptr_t code_region_index() const {
1596 return code_region_index_;
1597 }
1598
1599 ZoneGrowableArray<CodeRegionTrieNode*>& children() const {
1600 return *children_;
1601 }
1602
1603 CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) {
1604 const intptr_t length = children_->length();
1605 intptr_t i = 0;
1606 while (i < length) {
1607 CodeRegionTrieNode* child = (*children_)[i];
1608 if (child->code_region_index() == child_code_region_index) {
1609 return child;
1610 }
1611 if (child->code_region_index() > child_code_region_index) {
1612 break;
1613 }
1614 i++;
1615 }
1616 // Add new CodeRegion, sorted by CodeRegionTable index.
1617 CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index);
1618 if (i < length) {
1619 // Insert at i.
1620 children_->InsertAt(i, child);
1621 } else {
1622 // Add to end.
1623 children_->Add(child);
1624 }
1625 return child;
1626 }
1627
1628 // This should only be called after the trie is completely built.
1629 void SortByCount() {
1630 children_->Sort(CodeRegionTrieNodeCompare);
1631 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
1632 intptr_t child_count = kids.length();
1633 // Recurse.
1634 for (intptr_t i = 0; i < child_count; i++) {
1635 kids[i]->SortByCount();
1636 }
1637 }
1638
1639 void PrintToJSONArray(JSONArray* array) const {
1640 ASSERT(array != NULL);
1641 // Write CodeRegion index.
1642 array->AddValue(code_region_index_);
1643 // Write count.
1644 array->AddValue(count_);
1645 // Write number of children.
1646 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
1647 intptr_t child_count = kids.length();
1648 array->AddValue(child_count);
1649 // Recurse.
1650 for (intptr_t i = 0; i < child_count; i++) {
1651 kids[i]->PrintToJSONArray(array);
1652 }
1653 }
1654
1655 private:
1656 static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a,
1657 CodeRegionTrieNode* const* b) {
1658 ASSERT(a != NULL);
1659 ASSERT(b != NULL);
1660 return (*b)->count() - (*a)->count();
1661 }
1662
1663 const intptr_t code_region_index_;
1664 intptr_t count_;
1665 ZoneGrowableArray<CodeRegionTrieNode*>* children_;
1666 };
1667
1668
1669 class CodeRegionExclusiveTrieBuilder : public SampleVisitor {
1670 public:
1671 CodeRegionExclusiveTrieBuilder(Isolate* isolate,
1672 CodeRegionTable* live_code_table,
1673 CodeRegionTable* dead_code_table,
1674 CodeRegionTable* tag_code_table)
1675 : SampleVisitor(isolate),
1676 live_code_table_(live_code_table),
1677 dead_code_table_(dead_code_table),
1678 tag_code_table_(tag_code_table) {
1679 ASSERT(live_code_table_ != NULL);
1680 ASSERT(dead_code_table_ != NULL);
1681 ASSERT(tag_code_table_ != NULL);
1682 set_tag_order(ProfilerService::kUserVM);
1683
1684 intptr_t root_index = tag_code_table_->FindIndex(0);
1685 // Verify that the "0" (root) tag does exist.
1686 ASSERT(root_index >= 0);
1687 CodeRegion* region = tag_code_table_->At(root_index);
1688 ASSERT(region != NULL);
1689 root_ = new CodeRegionTrieNode(region->code_table_index());
1690 }
1691
1692 void VisitSample(Sample* sample) {
1693 // Give the root a tick.
1694 root_->Tick();
1695 CodeRegionTrieNode* current = root_;
1696 current = ProcessTags(sample, current);
1697 // Walk the sampled PCs.
1698 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
1699 if (sample->At(i) == 0) {
1700 break;
1701 }
1702 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
1703 current = current->GetChild(index);
1704 current->Tick();
1705 }
1706 }
1707
1708 CodeRegionTrieNode* root() const {
1709 return root_;
1710 }
1711
1712 ProfilerService::TagOrder tag_order() const {
1713 return tag_order_;
1714 }
1715
1716 void set_tag_order(ProfilerService::TagOrder tag_order) {
1717 tag_order_ = tag_order;
1718 }
1719
1720 private:
1721 CodeRegionTrieNode* ProcessUserTags(Sample* sample,
1722 CodeRegionTrieNode* current) {
1723 intptr_t user_tag_index = FindTagIndex(sample->user_tag());
1724 if (user_tag_index >= 0) {
1725 current = current->GetChild(user_tag_index);
1726 // Give the tag a tick.
1727 current->Tick();
1728 }
1729 return current;
1730 }
1731
1732 CodeRegionTrieNode* ProcessVMTags(Sample* sample,
1733 CodeRegionTrieNode* current) {
1734 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
1735 // Insert a dummy kNativeTagId node.
1736 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId);
1737 current = current->GetChild(tag_index);
1738 // Give the tag a tick.
1739 current->Tick();
1740 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1741 // Insert a dummy kRuntimeTagId node.
1742 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId);
1743 current = current->GetChild(tag_index);
1744 // Give the tag a tick.
1745 current->Tick();
1746 }
1747 intptr_t tag_index = FindTagIndex(sample->vm_tag());
1748 current = current->GetChild(tag_index);
1749 // Give the tag a tick.
1750 current->Tick();
1751 return current;
1752 }
1753
1754 CodeRegionTrieNode* ProcessTags(Sample* sample, CodeRegionTrieNode* current) {
1755 // None.
1756 if (tag_order() == ProfilerService::kNoTags) {
1757 return current;
1758 }
1759 // User first.
1760 if ((tag_order() == ProfilerService::kUserVM) ||
1761 (tag_order() == ProfilerService::kUser)) {
1762 current = ProcessUserTags(sample, current);
1763 // Only user.
1764 if (tag_order() == ProfilerService::kUser) {
1765 return current;
1766 }
1767 return ProcessVMTags(sample, current);
1768 }
1769 // VM first.
1770 ASSERT((tag_order() == ProfilerService::kVMUser) ||
1771 (tag_order() == ProfilerService::kVM));
1772 current = ProcessVMTags(sample, current);
1773 // Only VM.
1774 if (tag_order() == ProfilerService::kVM) {
1775 return current;
1776 }
1777 return ProcessUserTags(sample, current);
1778 }
1779
1780 intptr_t FindTagIndex(uword tag) const {
1781 if (tag == 0) {
1782 UNREACHABLE();
1783 return -1;
1784 }
1785 intptr_t index = tag_code_table_->FindIndex(tag);
1786 if (index < 0) {
1787 UNREACHABLE();
1788 return -1;
1789 }
1790 ASSERT(index >= 0);
1791 CodeRegion* region = tag_code_table_->At(index);
1792 ASSERT(region->contains(tag));
1793 return region->code_table_index();
1794 }
1795
1796 intptr_t FindDeadIndex(uword pc, int64_t timestamp) const {
1797 intptr_t index = dead_code_table_->FindIndex(pc);
1798 if (index < 0) {
1799 OS::Print("%" Px " cannot be found\n", pc);
1800 UNREACHABLE();
1801 return -1;
1802 }
1803 CodeRegion* region = dead_code_table_->At(index);
1804 ASSERT(region->contains(pc));
1805 ASSERT(region->compile_timestamp() <= timestamp);
1806 return region->code_table_index();
1807 }
1808
1809 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
1810 intptr_t index = live_code_table_->FindIndex(pc);
1811 if (index < 0) {
1812 // Try dead code table.
1813 return FindDeadIndex(pc, timestamp);
1814 }
1815 CodeRegion* region = live_code_table_->At(index);
1816 ASSERT(region->contains(pc));
1817 if (region->compile_timestamp() > timestamp) {
1818 // Overwritten code, find in dead code table.
1819 return FindDeadIndex(pc, timestamp);
1820 }
1821 ASSERT(region->compile_timestamp() <= timestamp);
1822 return region->code_table_index();
1168 } 1823 }
1169 1824
1170 ProfilerService::TagOrder tag_order_; 1825 ProfilerService::TagOrder tag_order_;
1171 CodeRegionTrieNode* root_; 1826 CodeRegionTrieNode* root_;
1172 CodeRegionTable* live_code_table_; 1827 CodeRegionTable* live_code_table_;
1173 CodeRegionTable* dead_code_table_; 1828 CodeRegionTable* dead_code_table_;
1174 CodeRegionTable* tag_code_table_; 1829 CodeRegionTable* tag_code_table_;
1175 intptr_t dead_code_table_offset_;
1176 intptr_t tag_code_table_offset_;
1177 }; 1830 };
1178 1831
1179 1832
1180 class CodeRegionTableCallersBuilder {
1181 public:
1182 CodeRegionTableCallersBuilder(CodeRegionTrieNode* exclusive_root,
1183 CodeRegionTable* live_code_table,
1184 CodeRegionTable* dead_code_table,
1185 CodeRegionTable* tag_code_table)
1186 : exclusive_root_(exclusive_root),
1187 live_code_table_(live_code_table),
1188 dead_code_table_(dead_code_table),
1189 tag_code_table_(tag_code_table) {
1190 ASSERT(exclusive_root_ != NULL);
1191 ASSERT(live_code_table_ != NULL);
1192 ASSERT(dead_code_table_ != NULL);
1193 ASSERT(tag_code_table_ != NULL);
1194 dead_code_table_offset_ = live_code_table_->Length();
1195 tag_code_table_offset_ = dead_code_table_offset_ +
1196 dead_code_table_->Length();
1197 }
1198
1199 void Build() {
1200 ProcessNode(exclusive_root_);
1201 }
1202
1203 private:
1204 void ProcessNode(CodeRegionTrieNode* parent) {
1205 const ZoneGrowableArray<CodeRegionTrieNode*>& children = parent->children();
1206 intptr_t parent_index = parent->code_region_index();
1207 ASSERT(parent_index >= 0);
1208 CodeRegion* parent_region = At(parent_index);
1209 ASSERT(parent_region != NULL);
1210 for (intptr_t i = 0; i < children.length(); i++) {
1211 CodeRegionTrieNode* node = children[i];
1212 ProcessNode(node);
1213 intptr_t index = node->code_region_index();
1214 ASSERT(index >= 0);
1215 CodeRegion* region = At(index);
1216 ASSERT(region != NULL);
1217 region->AddCallee(parent_index, node->count());
1218 parent_region->AddCaller(index, node->count());
1219 }
1220 }
1221
1222 CodeRegion* At(intptr_t final_index) {
1223 ASSERT(final_index >= 0);
1224 if (final_index < dead_code_table_offset_) {
1225 return live_code_table_->At(final_index);
1226 } else if (final_index < tag_code_table_offset_) {
1227 return dead_code_table_->At(final_index - dead_code_table_offset_);
1228 } else {
1229 return tag_code_table_->At(final_index - tag_code_table_offset_);
1230 }
1231 }
1232
1233 CodeRegionTrieNode* exclusive_root_;
1234 CodeRegionTable* live_code_table_;
1235 CodeRegionTable* dead_code_table_;
1236 CodeRegionTable* tag_code_table_;
1237 intptr_t dead_code_table_offset_;
1238 intptr_t tag_code_table_offset_;
1239 };
1240
1241
1242 void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { 1833 void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) {
1243 Isolate* isolate = Isolate::Current(); 1834 Isolate* isolate = Isolate::Current();
1244 // Disable profile interrupts while processing the buffer. 1835 // Disable profile interrupts while processing the buffer.
1245 Profiler::EndExecution(isolate); 1836 Profiler::EndExecution(isolate);
1246 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1837 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
1247 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1838 IsolateProfilerData* profiler_data = isolate->profiler_data();
1248 if (profiler_data == NULL) { 1839 if (profiler_data == NULL) {
1249 JSONObject error(stream); 1840 JSONObject error(stream);
1250 error.AddProperty("type", "Error"); 1841 error.AddProperty("type", "Error");
1251 error.AddProperty("text", "Isolate does not have profiling enabled."); 1842 error.AddProperty("text", "Isolate does not have profiling enabled.");
1252 return; 1843 return;
1253 } 1844 }
1254 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1845 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1255 ASSERT(sample_buffer != NULL); 1846 ASSERT(sample_buffer != NULL);
1256 { 1847 {
1257 StackZone zone(isolate); 1848 StackZone zone(isolate);
1849 HANDLESCOPE(isolate);
1258 { 1850 {
1259 // Live code holds Dart, Native, and Collected CodeRegions. 1851 // Live code holds Dart, Native, and Collected CodeRegions.
1260 CodeRegionTable live_code_table; 1852 CodeRegionTable live_code_table;
1261 // Dead code holds Overwritten CodeRegions. 1853 // Dead code holds Overwritten CodeRegions.
1262 CodeRegionTable dead_code_table; 1854 CodeRegionTable dead_code_table;
1263 // Tag code holds Tag CodeRegions. 1855 // Tag code holds Tag CodeRegions.
1264 CodeRegionTable tag_code_table; 1856 CodeRegionTable tag_code_table;
1265 CodeRegionTableBuilder builder(isolate, 1857 // Table holding all ProfileFunctions.
1266 &live_code_table, 1858 ProfileFunctionTable function_table;
1267 &dead_code_table, 1859
1268 &tag_code_table);
1269 { 1860 {
1270 ScopeTimer sw("FixTopFrame", FLAG_trace_profiler); 1861 ScopeTimer sw("FixTopFrame", FLAG_trace_profiler);
1271 // Preprocess samples and fix the caller when the top PC is in a 1862 // Preprocess samples and fix the caller when the top PC is in a
1272 // stub or intrinsic without a frame. 1863 // stub or intrinsic without a frame.
1273 FixTopFrameVisitor fixTopFrame(isolate); 1864 FixTopFrameVisitor fixTopFrame(isolate);
1274 sample_buffer->VisitSamples(&fixTopFrame); 1865 sample_buffer->VisitSamples(&fixTopFrame);
1275 } 1866 }
1867
1868 // Build CodeRegion tables.
1869 CodeRegionTableBuilder builder(isolate,
1870 &live_code_table,
1871 &dead_code_table,
1872 &tag_code_table);
1276 { 1873 {
1277 // Build CodeRegion tables.
1278 ScopeTimer sw("CodeRegionTableBuilder", FLAG_trace_profiler); 1874 ScopeTimer sw("CodeRegionTableBuilder", FLAG_trace_profiler);
1279 sample_buffer->VisitSamples(&builder); 1875 sample_buffer->VisitSamples(&builder);
1280 } 1876 }
1281 intptr_t samples = builder.visited(); 1877 intptr_t samples = builder.visited();
1282 intptr_t frames = builder.frames(); 1878 intptr_t frames = builder.frames();
1283 if (FLAG_trace_profiler) { 1879 if (FLAG_trace_profiler) {
1284 intptr_t total_live_code_objects = live_code_table.Length(); 1880 intptr_t total_live_code_objects = live_code_table.Length();
1285 intptr_t total_dead_code_objects = dead_code_table.Length(); 1881 intptr_t total_dead_code_objects = dead_code_table.Length();
1286 intptr_t total_tag_code_objects = tag_code_table.Length(); 1882 intptr_t total_tag_code_objects = tag_code_table.Length();
1287 OS::Print("Processed %" Pd " frames\n", frames); 1883 OS::Print("Processed %" Pd " frames\n", frames);
1288 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n", 1884 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
1289 total_live_code_objects, 1885 total_live_code_objects,
1290 total_dead_code_objects, 1886 total_dead_code_objects,
1291 total_tag_code_objects); 1887 total_tag_code_objects);
1292 } 1888 }
1293 #if defined(DEBUG) 1889
1294 live_code_table.Verify();
1295 dead_code_table.Verify();
1296 tag_code_table.Verify();
1297 if (FLAG_trace_profiler) { 1890 if (FLAG_trace_profiler) {
1298 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); 1891 ScopeTimer sw("CodeRegionTableVerify", FLAG_trace_profiler);
1892 live_code_table.Verify();
1893 dead_code_table.Verify();
1894 tag_code_table.Verify();
1299 } 1895 }
1300 #endif 1896
1301 CodeRegionExclusiveTrieBuilder build_trie(isolate, 1897 {
1302 &live_code_table, 1898 ScopeTimer st("CodeRegionFunctionMapping", FLAG_trace_profiler);
1303 &dead_code_table, 1899 CodeRegionFunctionMapper mapper(isolate, &live_code_table,
1304 &tag_code_table); 1900 &dead_code_table,
1305 build_trie.set_tag_order(tag_order); 1901 &tag_code_table,
1902 &function_table);
1903 mapper.Map();
1904 }
1905 if (FLAG_trace_profiler) {
1906 intptr_t total_functions = function_table.Length();
1907 OS::Print("FunctionTable: size=%" Pd "\n", total_functions);
1908 }
1909 CodeRegionExclusiveTrieBuilder code_trie_builder(isolate,
1910 &live_code_table,
1911 &dead_code_table,
1912 &tag_code_table);
1913 code_trie_builder.set_tag_order(tag_order);
1306 { 1914 {
1307 // Build CodeRegion trie. 1915 // Build CodeRegion trie.
1308 ScopeTimer sw("CodeRegionExclusiveTrieBuilder", FLAG_trace_profiler); 1916 ScopeTimer sw("CodeRegionExclusiveTrieBuilder", FLAG_trace_profiler);
1309 sample_buffer->VisitSamples(&build_trie); 1917 sample_buffer->VisitSamples(&code_trie_builder);
1310 build_trie.root()->SortByCount(); 1918 code_trie_builder.root()->SortByCount();
1311 } 1919 }
1312 CodeRegionTableCallersBuilder build_callers(build_trie.root(), 1920 ProfileFunctionExclusiveTrieBuilder
1313 &live_code_table, 1921 function_trie_builder(isolate,
1314 &dead_code_table, 1922 &live_code_table,
1315 &tag_code_table); 1923 &dead_code_table,
1924 &tag_code_table,
1925 &function_table);
1926 function_trie_builder.set_tag_order(tag_order);
1316 { 1927 {
1317 // Build CodeRegion callers. 1928 // Build ProfileFunction trie.
1318 ScopeTimer sw("CodeRegionTableCallersBuilder", FLAG_trace_profiler); 1929 ScopeTimer sw("ProfileFunctionExclusiveTrieBuilder",
1319 build_callers.Build(); 1930 FLAG_trace_profiler);
1931 sample_buffer->VisitSamples(&function_trie_builder);
1932 function_trie_builder.root()->SortByCount();
1320 } 1933 }
1321 { 1934 {
1322 ScopeTimer sw("CodeTableStream", FLAG_trace_profiler); 1935 ScopeTimer sw("CodeTableStream", FLAG_trace_profiler);
1323 // Serialize to JSON. 1936 // Serialize to JSON.
1324 JSONObject obj(stream); 1937 JSONObject obj(stream);
1325 obj.AddProperty("type", "CpuProfile"); 1938 obj.AddProperty("type", "_CpuProfile");
1326 obj.AddProperty("id", "profile"); 1939 obj.AddProperty("sampleCount", samples);
1327 obj.AddProperty("samples", samples); 1940 obj.AddProperty("samplePeriod",
1328 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth)); 1941 static_cast<intptr_t>(FLAG_profile_period));
1329 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period)); 1942 obj.AddProperty("stackDepth",
1943 static_cast<intptr_t>(FLAG_profile_depth));
1330 obj.AddProperty("timeSpan", 1944 obj.AddProperty("timeSpan",
1331 MicrosecondsToSeconds(builder.TimeDeltaMicros())); 1945 MicrosecondsToSeconds(builder.TimeDeltaMicros()));
1332 { 1946 {
1333 JSONArray exclusive_trie(&obj, "exclusive_trie"); 1947 JSONArray exclusive_trie(&obj, "exclusiveCodeTrie");
1334 CodeRegionTrieNode* root = build_trie.root(); 1948 CodeRegionTrieNode* root = code_trie_builder.root();
1335 ASSERT(root != NULL); 1949 ASSERT(root != NULL);
1336 root->PrintToJSONArray(&exclusive_trie); 1950 root->PrintToJSONArray(&exclusive_trie);
1337 } 1951 }
1338 JSONArray codes(&obj, "codes"); 1952 {
1339 for (intptr_t i = 0; i < live_code_table.Length(); i++) { 1953 JSONArray function_trie(&obj, "exclusiveFunctionTrie");
1340 CodeRegion* region = live_code_table.At(i); 1954 ProfileFunctionTrieNode* root = function_trie_builder.root();
1341 ASSERT(region != NULL); 1955 ASSERT(root != NULL);
1342 region->PrintToJSONArray(isolate, &codes); 1956 root->PrintToJSONArray(&function_trie);
1343 } 1957 }
1344 for (intptr_t i = 0; i < dead_code_table.Length(); i++) { 1958 {
1345 CodeRegion* region = dead_code_table.At(i); 1959 JSONArray codes(&obj, "codes");
1346 ASSERT(region != NULL); 1960 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
1347 region->PrintToJSONArray(isolate, &codes); 1961 CodeRegion* region = live_code_table.At(i);
1962 ASSERT(region != NULL);
1963 region->PrintToJSONArray(&codes);
1964 }
1965 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
1966 CodeRegion* region = dead_code_table.At(i);
1967 ASSERT(region != NULL);
1968 region->PrintToJSONArray(&codes);
1969 }
1970 for (intptr_t i = 0; i < tag_code_table.Length(); i++) {
1971 CodeRegion* region = tag_code_table.At(i);
1972 ASSERT(region != NULL);
1973 region->PrintToJSONArray(&codes);
1974 }
1348 } 1975 }
1349 for (intptr_t i = 0; i < tag_code_table.Length(); i++) { 1976 {
1350 CodeRegion* region = tag_code_table.At(i); 1977 JSONArray functions(&obj, "functions");
1351 ASSERT(region != NULL); 1978 for (intptr_t i = 0; i < function_table.Length(); i++) {
1352 region->PrintToJSONArray(isolate, &codes); 1979 ProfileFunction* function = function_table.At(i);
1980 ASSERT(function != NULL);
1981 function->PrintToJSONArray(&functions);
1982 }
1353 } 1983 }
1354 } 1984 }
1355 } 1985 }
1356 } 1986 }
1357 // Enable profile interrupts. 1987 // Enable profile interrupts.
1358 Profiler::BeginExecution(isolate); 1988 Profiler::BeginExecution(isolate);
1359 } 1989 }
1360 1990
1361 } // namespace dart 1991 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698