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

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

Powered by Google App Engine
This is Rietveld 408576698