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

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

Powered by Google App Engine
This is Rietveld 408576698