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

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

Issue 1210333002: Make CPU profile models public and refactor model building code (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 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
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | runtime/vm/service.cc » ('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(int, profile_period); 18 DECLARE_FLAG(int, profile_period);
19 19
20 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler."); 20 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler.");
21 21
22 // Forward declarations.
23 class CodeRegion;
24 class ProfileFunction;
25 class ProfileFunctionTable;
26
27
28 class DeoptimizedCodeSet : public ZoneAllocated { 22 class DeoptimizedCodeSet : public ZoneAllocated {
29 public: 23 public:
30 explicit DeoptimizedCodeSet(Isolate* isolate) 24 explicit DeoptimizedCodeSet(Isolate* isolate)
31 : previous_( 25 : previous_(
32 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())), 26 GrowableObjectArray::ZoneHandle(isolate->deoptimized_code_array())),
33 current_(GrowableObjectArray::ZoneHandle( 27 current_(GrowableObjectArray::ZoneHandle(
34 previous_.IsNull() ? GrowableObjectArray::null() : 28 previous_.IsNull() ? GrowableObjectArray::null() :
35 GrowableObjectArray::New())) { 29 GrowableObjectArray::New())) {
36 } 30 }
37 31
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 } 79 }
86 return size; 80 return size;
87 } 81 }
88 82
89 // Array holding code that is being kept around only for the profiler. 83 // Array holding code that is being kept around only for the profiler.
90 const GrowableObjectArray& previous_; 84 const GrowableObjectArray& previous_;
91 // Array holding code that should continue to be kept around for the profiler. 85 // Array holding code that should continue to be kept around for the profiler.
92 const GrowableObjectArray& current_; 86 const GrowableObjectArray& current_;
93 }; 87 };
94 88
95 class ProfileFunction : public ZoneAllocated { 89
96 public: 90 ProfileFunction::ProfileFunction(Kind kind,
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, 91 const char* name,
106 const Function& function, 92 const Function& function,
107 const intptr_t table_index) 93 const intptr_t table_index)
108 : kind_(kind), 94 : kind_(kind),
109 name_(name), 95 name_(name),
110 function_(Function::ZoneHandle(function.raw())), 96 function_(Function::ZoneHandle(function.raw())),
111 table_index_(table_index), 97 table_index_(table_index),
112 code_objects_(new ZoneGrowableArray<intptr_t>()), 98 profile_codes_(0),
113 exclusive_ticks_(0), 99 exclusive_ticks_(0),
114 inclusive_ticks_(0), 100 inclusive_ticks_(0) {
115 inclusive_tick_serial_(0) { 101 ASSERT((kind_ != kDartFunction) || !function_.IsNull());
116 ASSERT((kind_ != kDartFunction) || !function_.IsNull()); 102 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0));
117 ASSERT((kind_ != kDartFunction) || (table_index_ >= 0)); 103 ASSERT(profile_codes_.length() == 0);
118 ASSERT(code_objects_->length() == 0); 104 }
119 } 105
120 106
121 const char* name() const { 107 void ProfileFunction::Tick(bool exclusive, intptr_t inclusive_serial) {
122 ASSERT(name_ != NULL); 108 if (exclusive) {
123 return name_; 109 exclusive_ticks_++;
124 } 110 } else {
125 111 if (inclusive_serial_ == inclusive_serial) {
126 RawFunction* function() const { 112 // Already ticket.
127 return function_.raw(); 113 return;
128 } 114 }
129 115 inclusive_serial_ = inclusive_serial;
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 void inc_inclusive_ticks() {
178 inclusive_ticks_++; 116 inclusive_ticks_++;
179 } 117 }
180 intptr_t exclusive_ticks() const { 118 }
181 return exclusive_ticks_; 119
182 } 120
183 121 const char* ProfileFunction::KindToCString(Kind kind) {
184 void Tick(bool exclusive, intptr_t serial) { 122 switch (kind) {
185 // Assert that exclusive ticks are never passed a valid serial number. 123 case kDartFunction:
186 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1))); 124 return "Dart";
187 if (!exclusive && (inclusive_tick_serial_ == serial)) { 125 case kNativeFunction:
188 // We've already given this object an inclusive tick for this sample. 126 return "Native";
127 case kTagFunction:
128 return "Tag";
129 case kStubFunction:
130 return "Stub";
131 case kUnknownFunction:
132 return "Collected";
133 default:
134 UNIMPLEMENTED();
135 return "";
136 }
137 }
138
139
140 void ProfileFunction::PrintToJSONObject(JSONObject* func) {
141 func->AddProperty("type", "@Function");
142 func->AddProperty("name", name());
143 func->AddProperty("_kind", KindToCString(kind()));
144 }
145
146
147 void ProfileFunction::PrintToJSONArray(JSONArray* functions) {
148 JSONObject obj(functions);
149 obj.AddProperty("kind", KindToCString(kind()));
150 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
151 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
152 if (kind() == kDartFunction) {
153 ASSERT(!function_.IsNull());
154 obj.AddProperty("function", function_);
155 } else {
156 JSONObject func(&obj, "function");
157 PrintToJSONObject(&func);
158 }
159 {
160 JSONArray codes(&obj, "codes");
161 for (intptr_t i = 0; i < profile_codes_.length(); i++) {
162 intptr_t code_index = profile_codes_[i];
163 codes.AddValue(code_index);
164 }
165 }
166 }
167
168
169 void ProfileFunction::AddProfileCode(intptr_t code_table_index) {
170 for (intptr_t i = 0; i < profile_codes_.length(); i++) {
171 if (profile_codes_[i] == code_table_index) {
189 return; 172 return;
190 } 173 }
191 if (exclusive) { 174 }
192 exclusive_ticks_++; 175 profile_codes_.Add(code_table_index);
193 } else { 176 }
194 inclusive_ticks_++; 177
195 // Mark the last serial we ticked the inclusive count. 178
196 inclusive_tick_serial_ = serial; 179 ProfileCodeAddress::ProfileCodeAddress(uword pc)
197 } 180 : pc_(pc),
198 } 181 exclusive_ticks_(0),
199 182 inclusive_ticks_(0) {
200 void PrintToJSONObject(JSONObject* func) { 183 }
201 func->AddProperty("type", "@Function"); 184
202 func->AddProperty("name", name()); 185
203 func->AddProperty("_kind", KindToCString(kind())); 186 void ProfileCodeAddress::Tick(bool exclusive) {
204 } 187 if (exclusive) {
205 188 exclusive_ticks_++;
206 void PrintToJSONArray(JSONArray* functions) { 189 } else {
207 JSONObject obj(functions); 190 inclusive_ticks_++;
208 obj.AddProperty("kind", KindToCString(kind())); 191 }
209 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks()); 192 }
210 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks()); 193
211 if (kind() == kDartFunction) { 194
212 ASSERT(!function_.IsNull()); 195 ProfileCode::ProfileCode(Kind kind,
213 obj.AddProperty("function", function_); 196 uword start,
214 } else { 197 uword end,
215 JSONObject func(&obj, "function"); 198 int64_t timestamp,
216 PrintToJSONObject(&func); 199 const Code& code)
217 } 200 : kind_(kind),
218 { 201 start_(start),
219 JSONArray codes(&obj, "codes"); 202 end_(end),
220 for (intptr_t i = 0; i < code_objects_->length(); i++) { 203 exclusive_ticks_(0),
221 intptr_t code_index = (*code_objects_)[i]; 204 inclusive_ticks_(0),
222 codes.AddValue(code_index); 205 inclusive_serial_(-1),
223 } 206 code_(code),
224 } 207 name_(NULL),
225 } 208 compile_timestamp_(0),
226 209 function_(NULL),
227 private: 210 code_table_index_(-1),
228 const Kind kind_; 211 address_ticks_(0) {
229 const char* name_; 212 }
230 const Function& function_; 213
231 const intptr_t table_index_; 214
232 ZoneGrowableArray<intptr_t>* code_objects_; 215 void ProfileCode::AdjustExtent(uword start, uword end) {
233 intptr_t exclusive_ticks_; 216 if (start < start_) {
234 intptr_t inclusive_ticks_; 217 start_ = start;
235 intptr_t inclusive_tick_serial_; 218 }
236 }; 219 if (end > end_) {
237 220 end_ = end;
238 221 }
239 class ProfileFunctionTable : public ValueObject { 222 ASSERT(start_ < end_);
223 }
224
225
226 bool ProfileCode::Overlaps(const ProfileCode* other) const {
227 ASSERT(other != NULL);
228 return other->Contains(start_) ||
229 other->Contains(end_ - 1) ||
230 Contains(other->start()) ||
231 Contains(other->end() - 1);
232 }
233
234
235 bool ProfileCode::IsOptimizedDart() const {
236 return !code_.IsNull() && code_.is_optimized();
237 }
238
239
240 void ProfileCode::SetName(const char* name) {
241 if (name == NULL) {
242 name_ = NULL;
243 }
244 intptr_t len = strlen(name);
245 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
246 strncpy(const_cast<char*>(name_), name, len);
247 const_cast<char*>(name_)[len] = '\0';
248 }
249
250
251 void ProfileCode::GenerateAndSetSymbolName(const char* prefix) {
252 const intptr_t kBuffSize = 512;
253 char buff[kBuffSize];
254 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
255 prefix, start(), end());
256 SetName(buff);
257 }
258
259
260 void ProfileCode::Tick(uword pc, bool exclusive, intptr_t serial) {
261 if (exclusive) {
262 exclusive_ticks_++;
263 } else {
264 if (inclusive_serial_ == serial) {
265 // Already ticked for this sample.
266 return;
267 }
268 inclusive_serial_ = serial;
269 inclusive_ticks_++;
270 }
271 TickAddress(pc, exclusive);
272 }
273
274
275 void ProfileCode::TickAddress(uword pc, bool exclusive) {
276 const intptr_t length = address_ticks_.length();
277
278 intptr_t i = 0;
279 for (; i < length; i++) {
280 ProfileCodeAddress& entry = address_ticks_[i];
281 if (entry.pc() == pc) {
282 // Tick the address entry.
283 entry.Tick(exclusive);
284 return;
285 }
286 if (entry.pc() > pc) {
287 break;
288 }
289 }
290
291 // New address, add entry.
292 ProfileCodeAddress entry(pc);
293
294 entry.Tick(exclusive);
295
296 if (i < length) {
297 // Insert at i.
298 address_ticks_.InsertAt(i, entry);
299 } else {
300 // Add to end.
301 address_ticks_.Add(entry);
302 }
303 }
304
305
306 void ProfileCode::PrintNativeCode(JSONObject* profile_code_obj) {
307 ASSERT(kind() == kNativeCode);
308 JSONObject obj(profile_code_obj, "code");
309 obj.AddProperty("type", "@Code");
310 obj.AddProperty("kind", "Native");
311 obj.AddProperty("name", name());
312 obj.AddProperty("_optimized", false);
313 obj.AddPropertyF("start", "%" Px "", start());
314 obj.AddPropertyF("end", "%" Px "", end());
315 {
316 // Generate a fake function entry.
317 JSONObject func(&obj, "function");
318 ASSERT(function_ != NULL);
319 function_->PrintToJSONObject(&func);
320 }
321 }
322
323
324 void ProfileCode::PrintCollectedCode(JSONObject* profile_code_obj) {
325 ASSERT(kind() == kCollectedCode);
326 JSONObject obj(profile_code_obj, "code");
327 obj.AddProperty("type", "@Code");
328 obj.AddProperty("kind", "Collected");
329 obj.AddProperty("name", name());
330 obj.AddProperty("_optimized", false);
331 obj.AddPropertyF("start", "%" Px "", start());
332 obj.AddPropertyF("end", "%" Px "", end());
333 {
334 // Generate a fake function entry.
335 JSONObject func(&obj, "function");
336 ASSERT(function_ != NULL);
337 function_->PrintToJSONObject(&func);
338 }
339 }
340
341
342 void ProfileCode::PrintOverwrittenCode(JSONObject* profile_code_obj) {
343 ASSERT(kind() == kReusedCode);
344 JSONObject obj(profile_code_obj, "code");
345 obj.AddProperty("type", "@Code");
346 obj.AddProperty("kind", "Collected");
347 obj.AddProperty("name", name());
348 obj.AddProperty("_optimized", false);
349 obj.AddPropertyF("start", "%" Px "", start());
350 obj.AddPropertyF("end", "%" Px "", end());
351 {
352 // Generate a fake function entry.
353 JSONObject func(&obj, "function");
354 ASSERT(function_ != NULL);
355 function_->PrintToJSONObject(&func);
356 }
357 }
358
359
360 void ProfileCode::PrintTagCode(JSONObject* profile_code_obj) {
361 ASSERT(kind() == kTagCode);
362 JSONObject obj(profile_code_obj, "code");
363 obj.AddProperty("type", "@Code");
364 obj.AddProperty("kind", "Tag");
365 obj.AddProperty("name", name());
366 obj.AddPropertyF("start", "%" Px "", start());
367 obj.AddPropertyF("end", "%" Px "", end());
368 obj.AddProperty("_optimized", false);
369 {
370 // Generate a fake function entry.
371 JSONObject func(&obj, "function");
372 ASSERT(function_ != NULL);
373 function_->PrintToJSONObject(&func);
374 }
375 }
376
377
378 const char* ProfileCode::KindToCString(Kind kind) {
379 switch (kind) {
380 case kDartCode:
381 return "Dart";
382 case kCollectedCode:
383 return "Collected";
384 case kNativeCode:
385 return "Native";
386 case kReusedCode:
387 return "Overwritten";
388 case kTagCode:
389 return "Tag";
390 }
391 UNREACHABLE();
392 return NULL;
393 }
394
395
396 void ProfileCode::PrintToJSONArray(JSONArray* codes) {
397 JSONObject obj(codes);
398 obj.AddProperty("kind", ProfileCode::KindToCString(kind()));
399 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
400 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
401 if (kind() == kDartCode) {
402 ASSERT(!code_.IsNull());
403 obj.AddProperty("code", code_);
404 } else if (kind() == kCollectedCode) {
405 PrintCollectedCode(&obj);
406 } else if (kind() == kReusedCode) {
407 PrintOverwrittenCode(&obj);
408 } else if (kind() == kTagCode) {
409 PrintTagCode(&obj);
410 } else {
411 ASSERT(kind() == kNativeCode);
412 PrintNativeCode(&obj);
413 }
414 {
415 JSONArray ticks(&obj, "ticks");
416 for (intptr_t i = 0; i < address_ticks_.length(); i++) {
417 const ProfileCodeAddress& entry = address_ticks_[i];
418 ticks.AddValueF("%" Px "", entry.pc());
419 ticks.AddValueF("%" Pd "", entry.exclusive_ticks());
420 ticks.AddValueF("%" Pd "", entry.inclusive_ticks());
421 }
422 }
423 }
424
425
426 class ProfileFunctionTable : public ZoneAllocated {
240 public: 427 public:
241 ProfileFunctionTable() 428 ProfileFunctionTable()
242 : null_function_(Function::ZoneHandle()), 429 : null_function_(Function::ZoneHandle()),
243 table_(new ZoneGrowableArray<ProfileFunction*>()), 430 table_(8),
244 unknown_function_(NULL) { 431 unknown_function_(NULL) {
432 unknown_function_ = Add(ProfileFunction::kUnknownFunction,
433 "<unknown Dart function>");
245 } 434 }
246 435
247 ProfileFunction* LookupOrAdd(const Function& function) { 436 ProfileFunction* LookupOrAdd(const Function& function) {
248 ASSERT(!function.IsNull()); 437 ASSERT(!function.IsNull());
249 ProfileFunction* profile_function = Lookup(function); 438 ProfileFunction* profile_function = Lookup(function);
250 if (profile_function != NULL) { 439 if (profile_function != NULL) {
251 return profile_function; 440 return profile_function;
252 } 441 }
253 return Add(function); 442 return Add(function);
254 } 443 }
255 444
256 intptr_t LookupIndex(const Function& function) { 445 intptr_t LookupIndex(const Function& function) {
257 ASSERT(!function.IsNull()); 446 ASSERT(!function.IsNull());
258 for (intptr_t i = 0; i < table_->length(); i++) { 447 for (intptr_t i = 0; i < table_.length(); i++) {
259 ProfileFunction* profile_function = (*table_)[i]; 448 ProfileFunction* profile_function = table_[i];
260 if (profile_function->function() == function.raw()) { 449 if (profile_function->function() == function.raw()) {
261 return i; 450 return i;
262 } 451 }
263 } 452 }
264 return -1; 453 return -1;
265 } 454 }
266 455
267 ProfileFunction* GetUnknown() { 456 ProfileFunction* GetUnknown() {
268 if (unknown_function_ == NULL) {
269 // Construct.
270 unknown_function_ = Add(ProfileFunction::kUnkownFunction,
271 "<unknown Dart function>");
272 }
273 ASSERT(unknown_function_ != NULL); 457 ASSERT(unknown_function_ != NULL);
274 return unknown_function_; 458 return unknown_function_;
275 } 459 }
276 460
277 // No protection against being called more than once for the same tag_id. 461 // No protection against being called more than once for the same tag_id.
278 ProfileFunction* AddTag(uword tag_id, const char* name) { 462 ProfileFunction* AddTag(uword tag_id, const char* name) {
279 // TODO(johnmccutchan): Canonicalize ProfileFunctions for tags. 463 // TODO(johnmccutchan): Canonicalize ProfileFunctions for tags.
280 return Add(ProfileFunction::kTagFunction, name); 464 return Add(ProfileFunction::kTagFunction, name);
281 } 465 }
282 466
283 // No protection against being called more than once for the same native 467 // No protection against being called more than once for the same native
284 // address. 468 // address.
285 ProfileFunction* AddNative(uword start_address, const char* name) { 469 ProfileFunction* AddNative(uword start_address, const char* name) {
286 // TODO(johnmccutchan): Canonicalize ProfileFunctions for natives. 470 // TODO(johnmccutchan): Canonicalize ProfileFunctions for natives.
287 return Add(ProfileFunction::kNativeFunction, name); 471 return Add(ProfileFunction::kNativeFunction, name);
288 } 472 }
289 473
290 // No protection against being called more tha once for the same stub. 474 // No protection against being called more tha once for the same stub.
291 ProfileFunction* AddStub(uword start_address, const char* name) { 475 ProfileFunction* AddStub(uword start_address, const char* name) {
292 return Add(ProfileFunction::kStubFunction, name); 476 return Add(ProfileFunction::kStubFunction, name);
293 } 477 }
294 478
295 intptr_t Length() const { 479 intptr_t length() const {
296 return table_->length(); 480 return table_.length();
297 } 481 }
298 482
299 ProfileFunction* At(intptr_t i) const { 483 ProfileFunction* At(intptr_t i) const {
300 ASSERT(i >= 0); 484 ASSERT(i >= 0);
301 ASSERT(i < Length()); 485 ASSERT(i < length());
302 return (*table_)[i]; 486 return table_[i];
303 } 487 }
304 488
305 private: 489 private:
306 ProfileFunction* Add(ProfileFunction::Kind kind, const char* name) { 490 ProfileFunction* Add(ProfileFunction::Kind kind, const char* name) {
307 ASSERT(kind != ProfileFunction::kDartFunction); 491 ASSERT(kind != ProfileFunction::kDartFunction);
308 ASSERT(name != NULL); 492 ASSERT(name != NULL);
309 ProfileFunction* profile_function = 493 ProfileFunction* profile_function =
310 new ProfileFunction(kind, 494 new ProfileFunction(kind,
311 name, 495 name,
312 null_function_, 496 null_function_,
313 table_->length()); 497 table_.length());
314 table_->Add(profile_function); 498 table_.Add(profile_function);
315 return profile_function; 499 return profile_function;
316 } 500 }
317 501
318 ProfileFunction* Add(const Function& function) { 502 ProfileFunction* Add(const Function& function) {
319 ASSERT(Lookup(function) == NULL); 503 ASSERT(Lookup(function) == NULL);
320 ProfileFunction* profile_function = 504 ProfileFunction* profile_function =
321 new ProfileFunction(ProfileFunction::kDartFunction, 505 new ProfileFunction(ProfileFunction::kDartFunction,
322 NULL, 506 NULL,
323 function, 507 function,
324 table_->length()); 508 table_.length());
325 table_->Add(profile_function); 509 table_.Add(profile_function);
326 return profile_function; 510 return profile_function;
327 } 511 }
328 512
329 ProfileFunction* Lookup(const Function& function) { 513 ProfileFunction* Lookup(const Function& function) {
330 ASSERT(!function.IsNull()); 514 ASSERT(!function.IsNull());
331 intptr_t index = LookupIndex(function); 515 intptr_t index = LookupIndex(function);
332 if (index == -1) { 516 if (index == -1) {
333 return NULL; 517 return NULL;
334 } 518 }
335 return (*table_)[index]; 519 return table_[index];
336 } 520 }
337 521
338 const Function& null_function_; 522 const Function& null_function_;
339 ZoneGrowableArray<ProfileFunction*>* table_; 523 ZoneGrowableArray<ProfileFunction*> table_;
340
341 ProfileFunction* unknown_function_; 524 ProfileFunction* unknown_function_;
342 }; 525 };
343 526
344 527
345 struct AddressEntry { 528 ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable* table) {
346 uword pc; 529 ASSERT(function_ == NULL);
347 intptr_t exclusive_ticks;
348 intptr_t inclusive_ticks;
349 530
350 void tick(bool exclusive) { 531 ProfileFunction* function = NULL;
351 if (exclusive) { 532 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) {
352 exclusive_ticks++; 533 if (name() == NULL) {
534 // Lazily set generated name.
535 GenerateAndSetSymbolName("[Collected]");
536 }
537 // Map these to a canonical unknown function.
538 function = table->GetUnknown();
539 } else if (kind() == kDartCode) {
540 ASSERT(!code_.IsNull());
541 const Object& obj = Object::Handle(code_.owner());
542 if (obj.IsFunction()) {
543 const String& user_name = String::Handle(code_.PrettyName());
544 function = table->LookupOrAdd(Function::Cast(obj));
545 SetName(user_name.ToCString());
353 } else { 546 } else {
354 inclusive_ticks++; 547 // A stub.
548 const String& user_name = String::Handle(code_.PrettyName());
549 function = table->AddStub(start(), user_name.ToCString());
550 SetName(user_name.ToCString());
355 } 551 }
552 } else if (kind() == kNativeCode) {
553 if (name() == NULL) {
554 // Lazily set generated name.
555 GenerateAndSetSymbolName("[Native]");
556 }
557 function = table->AddNative(start(), name());
558 } else if (kind() == kTagCode) {
559 if (name() == NULL) {
560 if (UserTags::IsUserTag(start())) {
561 const char* tag_name = UserTags::TagName(start());
562 ASSERT(tag_name != NULL);
563 SetName(tag_name);
564 } else if (VMTag::IsVMTag(start()) ||
565 VMTag::IsRuntimeEntryTag(start()) ||
566 VMTag::IsNativeEntryTag(start())) {
567 const char* tag_name = VMTag::TagName(start());
568 ASSERT(tag_name != NULL);
569 SetName(tag_name);
570 } else {
571 if (start() == VMTag::kRootTagId) {
572 SetName("Root");
573 } else {
574 ASSERT(start() == VMTag::kTruncatedTagId);
575 SetName("[Truncated]");
576 }
577 }
578 }
579 function = table->AddTag(start(), name());
580 } else {
581 UNREACHABLE();
356 } 582 }
357 }; 583 ASSERT(function != NULL);
358 584
359 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); 585 function->AddProfileCode(code_table_index());
360 586
361 // A contiguous address region that holds code. Each CodeRegion has a "kind" 587 function_ = function;
362 // which describes the type of code contained inside the region. Each 588 return function_;
363 // region covers the following interval: [start, end). 589 }
364 class CodeRegion : public ZoneAllocated { 590
591
592 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end);
593
594 class ProfileCodeTable : public ZoneAllocated {
365 public: 595 public:
366 enum Kind { 596 ProfileCodeTable()
367 kDartCode, // Live Dart code. 597 : table_(8) {
368 kCollectedCode, // Dead Dart code.
369 kNativeCode, // Native code.
370 kReusedCode, // Dead Dart code that has been reused by new kDartCode.
371 kTagCode, // A special kind of code representing a tag.
372 };
373
374 CodeRegion(Kind kind,
375 uword start,
376 uword end,
377 int64_t timestamp,
378 const Code& code)
379 : kind_(kind),
380 start_(start),
381 end_(end),
382 inclusive_ticks_(0),
383 exclusive_ticks_(0),
384 inclusive_tick_serial_(0),
385 name_(NULL),
386 compile_timestamp_(timestamp),
387 code_(Code::ZoneHandle(code.raw())),
388 profile_function_(NULL),
389 code_table_index_(-1) {
390 ASSERT(start_ < end_);
391 // Ensure all kDartCode have a valid code_ object.
392 ASSERT((kind != kDartCode) || (!code_.IsNull()));
393 } 598 }
394 599
395 uword start() const { return start_; } 600 intptr_t length() const { return table_.length(); }
396 void set_start(uword start) { 601
397 start_ = start; 602 ProfileCode* At(intptr_t index) const {
603 ASSERT(index >= 0);
604 ASSERT(index < length());
605 return table_[index];
398 } 606 }
399 607
400 uword end() const { return end_; } 608 // Find the table index to the ProfileCode containing pc.
401 void set_end(uword end) {
402 end_ = end;
403 }
404
405 void AdjustExtent(uword start, uword end) {
406 if (start < start_) {
407 start_ = start;
408 }
409 if (end > end_) {
410 end_ = end;
411 }
412 ASSERT(start_ < end_);
413 }
414
415 bool contains(uword pc) const {
416 return (pc >= start_) && (pc < end_);
417 }
418
419 bool overlaps(const CodeRegion* other) const {
420 ASSERT(other != NULL);
421 return other->contains(start_) ||
422 other->contains(end_ - 1) ||
423 contains(other->start()) ||
424 contains(other->end() - 1);
425 }
426
427 int64_t compile_timestamp() const { return compile_timestamp_; }
428 void set_compile_timestamp(int64_t timestamp) {
429 compile_timestamp_ = timestamp;
430 }
431
432 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
433 void set_inclusive_ticks(intptr_t inclusive_ticks) {
434 inclusive_ticks_ = inclusive_ticks;
435 }
436 void inc_inclusive_ticks() {
437 inclusive_ticks_++;
438 }
439
440 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
441 void set_exclusive_ticks(intptr_t exclusive_ticks) {
442 exclusive_ticks_ = exclusive_ticks;
443 }
444
445 const char* name() const { return name_; }
446 void SetName(const char* name) {
447 if (name == NULL) {
448 name_ = NULL;
449 }
450 intptr_t len = strlen(name);
451 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1);
452 strncpy(const_cast<char*>(name_), name, len);
453 const_cast<char*>(name_)[len] = '\0';
454 }
455
456 bool IsOptimizedDart() const {
457 return !code_.IsNull() && code_.is_optimized();
458 }
459
460 RawCode* code() const {
461 return code_.raw();
462 }
463
464 ProfileFunction* SetFunctionAndName(ProfileFunctionTable* table) {
465 ASSERT(profile_function_ == NULL);
466
467 ProfileFunction* function = NULL;
468 if ((kind() == kReusedCode) || (kind() == kCollectedCode)) {
469 if (name() == NULL) {
470 // Lazily set generated name.
471 GenerateAndSetSymbolName("[Collected]");
472 }
473 // Map these to a canonical unknown function.
474 function = table->GetUnknown();
475 } else if (kind() == kDartCode) {
476 ASSERT(!code_.IsNull());
477 const Object& obj = Object::Handle(code_.owner());
478 if (obj.IsFunction()) {
479 const String& user_name = String::Handle(code_.PrettyName());
480 function = table->LookupOrAdd(Function::Cast(obj));
481 SetName(user_name.ToCString());
482 } else {
483 // A stub.
484 const String& user_name = String::Handle(code_.PrettyName());
485 function = table->AddStub(start(), user_name.ToCString());
486 SetName(user_name.ToCString());
487 }
488 } else if (kind() == kNativeCode) {
489 if (name() == NULL) {
490 // Lazily set generated name.
491 GenerateAndSetSymbolName("[Native]");
492 }
493 function = table->AddNative(start(), name());
494 } else if (kind() == kTagCode) {
495 if (name() == NULL) {
496 if (UserTags::IsUserTag(start())) {
497 const char* tag_name = UserTags::TagName(start());
498 ASSERT(tag_name != NULL);
499 SetName(tag_name);
500 } else if (VMTag::IsVMTag(start()) ||
501 VMTag::IsRuntimeEntryTag(start()) ||
502 VMTag::IsNativeEntryTag(start())) {
503 const char* tag_name = VMTag::TagName(start());
504 ASSERT(tag_name != NULL);
505 SetName(tag_name);
506 } else {
507 if (start() == VMTag::kRootTagId) {
508 SetName("Root");
509 } else {
510 ASSERT(start() == VMTag::kTruncatedTagId);
511 SetName("[Truncated]");
512 }
513 }
514 }
515 function = table->AddTag(start(), name());
516 } else {
517 UNREACHABLE();
518 }
519 ASSERT(function != NULL);
520 // Register this CodeRegion with this function.
521 function->AddCodeObjectIndex(code_table_index());
522 profile_function_ = function;
523 return profile_function_;
524 }
525
526 ProfileFunction* function() const {
527 ASSERT(profile_function_ != NULL);
528 return profile_function_;
529 }
530
531 void set_code_table_index(intptr_t code_table_index) {
532 ASSERT(code_table_index_ == -1);
533 ASSERT(code_table_index != -1);
534 code_table_index_ = code_table_index;
535 }
536 intptr_t code_table_index() const {
537 ASSERT(code_table_index_ != -1);
538 return code_table_index_;
539 }
540
541 Kind kind() const { return kind_; }
542
543 static const char* KindToCString(Kind kind) {
544 switch (kind) {
545 case kDartCode:
546 return "Dart";
547 case kCollectedCode:
548 return "Collected";
549 case kNativeCode:
550 return "Native";
551 case kReusedCode:
552 return "Overwritten";
553 case kTagCode:
554 return "Tag";
555 }
556 UNREACHABLE();
557 return NULL;
558 }
559
560 void DebugPrint() const {
561 OS::Print("%s [%" Px ", %" Px ") %" Pd64 "\n",
562 KindToCString(kind_),
563 start(),
564 end(),
565 compile_timestamp_);
566 }
567
568 void Tick(uword pc, bool exclusive, intptr_t serial) {
569 // Assert that exclusive ticks are never passed a valid serial number.
570 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
571 if (!exclusive && (inclusive_tick_serial_ == serial)) {
572 // We've already given this code object an inclusive tick for this sample.
573 return;
574 }
575 // Tick the code object.
576 if (exclusive) {
577 exclusive_ticks_++;
578 } else {
579 inclusive_ticks_++;
580 // Mark the last serial we ticked the inclusive count.
581 inclusive_tick_serial_ = serial;
582 }
583 TickAddress(pc, exclusive);
584 }
585
586 void PrintNativeCode(JSONObject* profile_code_obj) {
587 ASSERT(kind() == kNativeCode);
588 JSONObject obj(profile_code_obj, "code");
589 obj.AddProperty("type", "@Code");
590 obj.AddProperty("kind", "Native");
591 obj.AddProperty("name", name());
592 obj.AddProperty("_optimized", false);
593 obj.AddPropertyF("start", "%" Px "", start());
594 obj.AddPropertyF("end", "%" Px "", end());
595 {
596 // Generate a fake function entry.
597 JSONObject func(&obj, "function");
598 profile_function_->PrintToJSONObject(&func);
599 }
600 }
601
602 void PrintCollectedCode(JSONObject* profile_code_obj) {
603 ASSERT(kind() == kCollectedCode);
604 JSONObject obj(profile_code_obj, "code");
605 obj.AddProperty("type", "@Code");
606 obj.AddProperty("kind", "Collected");
607 obj.AddProperty("name", name());
608 obj.AddProperty("_optimized", false);
609 obj.AddPropertyF("start", "%" Px "", start());
610 obj.AddPropertyF("end", "%" Px "", end());
611 {
612 // Generate a fake function entry.
613 JSONObject func(&obj, "function");
614 profile_function_->PrintToJSONObject(&func);
615 }
616 }
617
618 void PrintOverwrittenCode(JSONObject* profile_code_obj) {
619 ASSERT(kind() == kReusedCode);
620 JSONObject obj(profile_code_obj, "code");
621 obj.AddProperty("type", "@Code");
622 obj.AddProperty("kind", "Collected");
623 obj.AddProperty("name", name());
624 obj.AddProperty("_optimized", false);
625 obj.AddPropertyF("start", "%" Px "", start());
626 obj.AddPropertyF("end", "%" Px "", end());
627 {
628 // Generate a fake function entry.
629 JSONObject func(&obj, "function");
630 ASSERT(profile_function_ != NULL);
631 profile_function_->PrintToJSONObject(&func);
632 }
633 }
634
635 void PrintTagCode(JSONObject* profile_code_obj) {
636 ASSERT(kind() == kTagCode);
637 JSONObject obj(profile_code_obj, "code");
638 obj.AddProperty("type", "@Code");
639 obj.AddProperty("kind", "Tag");
640 obj.AddProperty("name", name());
641 obj.AddPropertyF("start", "%" Px "", start());
642 obj.AddPropertyF("end", "%" Px "", end());
643 obj.AddProperty("_optimized", false);
644 {
645 // Generate a fake function entry.
646 JSONObject func(&obj, "function");
647 ASSERT(profile_function_ != NULL);
648 profile_function_->PrintToJSONObject(&func);
649 }
650 }
651
652 void PrintToJSONArray(JSONArray* codes) {
653 JSONObject obj(codes);
654 obj.AddProperty("kind", KindToCString(kind()));
655 obj.AddPropertyF("inclusiveTicks", "%" Pd "", inclusive_ticks());
656 obj.AddPropertyF("exclusiveTicks", "%" Pd "", exclusive_ticks());
657 if (kind() == kDartCode) {
658 ASSERT(!code_.IsNull());
659 obj.AddProperty("code", code_);
660 } else if (kind() == kCollectedCode) {
661 PrintCollectedCode(&obj);
662 } else if (kind() == kReusedCode) {
663 PrintOverwrittenCode(&obj);
664 } else if (kind() == kTagCode) {
665 PrintTagCode(&obj);
666 } else {
667 ASSERT(kind() == kNativeCode);
668 PrintNativeCode(&obj);
669 }
670 {
671 JSONArray ticks(&obj, "ticks");
672 for (intptr_t i = 0; i < address_table_.length(); i++) {
673 const AddressEntry& entry = address_table_[i];
674 ticks.AddValueF("%" Px "", entry.pc);
675 ticks.AddValueF("%" Pd "", entry.exclusive_ticks);
676 ticks.AddValueF("%" Pd "", entry.inclusive_ticks);
677 }
678 }
679 }
680
681 private:
682 void TickAddress(uword pc, bool exclusive) {
683 const intptr_t length = address_table_.length();
684 intptr_t i = 0;
685 for (; i < length; i++) {
686 AddressEntry& entry = address_table_[i];
687 if (entry.pc == pc) {
688 // Tick the address entry.
689 entry.tick(exclusive);
690 return;
691 }
692 if (entry.pc > pc) {
693 break;
694 }
695 }
696 // New address, add entry.
697 AddressEntry entry;
698 entry.pc = pc;
699 entry.exclusive_ticks = 0;
700 entry.inclusive_ticks = 0;
701 entry.tick(exclusive);
702 if (i < length) {
703 // Insert at i.
704 address_table_.InsertAt(i, entry);
705 } else {
706 // Add to end.
707 address_table_.Add(entry);
708 }
709 }
710
711 void GenerateAndSetSymbolName(const char* prefix) {
712 const intptr_t kBuffSize = 512;
713 char buff[kBuffSize];
714 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
715 prefix, start(), end());
716 SetName(buff);
717 }
718
719 // CodeRegion kind.
720 const Kind kind_;
721 // CodeRegion start address.
722 uword start_;
723 // CodeRegion end address.
724 uword end_;
725 // Inclusive ticks.
726 intptr_t inclusive_ticks_;
727 // Exclusive ticks.
728 intptr_t exclusive_ticks_;
729 // Inclusive tick serial number, ensures that each CodeRegion is only given
730 // a single inclusive tick per sample.
731 intptr_t inclusive_tick_serial_;
732 // Name of code region.
733 const char* name_;
734 // The compilation timestamp associated with this code region.
735 int64_t compile_timestamp_;
736 // Dart code object (may be null).
737 const Code& code_;
738 // Pointer to ProfileFunction.
739 ProfileFunction* profile_function_;
740 // Final code table index.
741 intptr_t code_table_index_;
742 ZoneGrowableArray<AddressEntry> address_table_;
743 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
744 };
745
746
747 // A sorted table of CodeRegions. Does not allow for overlap.
748 class CodeRegionTable : public ValueObject {
749 public:
750 enum TickResult {
751 kTicked = 0, // CodeRegion found and ticked.
752 kNotFound = -1, // No CodeRegion found.
753 kNewerCode = -2, // CodeRegion found but it was compiled after sample.
754 };
755
756 CodeRegionTable() :
757 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
758 }
759
760 // Ticks the CodeRegion containing pc if it is alive at timestamp.
761 TickResult Tick(uword pc,
762 bool exclusive,
763 intptr_t serial,
764 int64_t timestamp) {
765 intptr_t index = FindIndex(pc);
766 if (index < 0) {
767 // Not found.
768 return kNotFound;
769 }
770 ASSERT(index < code_region_table_->length());
771 CodeRegion* region = At(index);
772 if (region->compile_timestamp() > timestamp) {
773 // Compiled after tick.
774 return kNewerCode;
775 }
776 region->Tick(pc, exclusive, serial);
777 return kTicked;
778 }
779
780 // Table length.
781 intptr_t Length() const { return code_region_table_->length(); }
782
783 // Get the CodeRegion at index.
784 CodeRegion* At(intptr_t index) const {
785 return (*code_region_table_)[index];
786 }
787
788 // Find the table index to the CodeRegion containing pc.
789 // Returns < 0 if not found. 609 // Returns < 0 if not found.
790 intptr_t FindIndex(uword pc) const { 610 intptr_t FindCodeIndexForPC(uword pc) const {
791 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); 611 intptr_t index = FindCodeIndex(pc, &CompareLowerBound);
792 const CodeRegion* code_region = NULL; 612 if (index == length()) {
793 if (index == code_region_table_->length()) {
794 // Not present. 613 // Not present.
795 return -1; 614 return -1;
796 } 615 }
797 code_region = At(index); 616 const ProfileCode* code = At(index);
798 if (code_region->contains(pc)) { 617 if (!code->Contains(pc)) {
799 // Found at index. 618 // Not present.
800 return index; 619 return -1;
801 } 620 }
802 return -2; 621 // Found at index.
622 return index;
803 } 623 }
804 624
805 // Insert code_region into the table. Returns the table index where the 625 ProfileCode* FindCodeForPC(uword pc) const {
806 // CodeRegion was inserted. Will merge with an overlapping CodeRegion if 626 intptr_t index = FindCodeIndexForPC(pc);
807 // one is present. 627 if (index < 0) {
808 intptr_t InsertCodeRegion(CodeRegion* code_region) { 628 return NULL;
809 const uword start = code_region->start(); 629 }
810 const uword end = code_region->end(); 630 return At(index);
811 const intptr_t length = code_region_table_->length(); 631 }
632
633 // Insert |new_code| into the table. Returns the table index where |new_code|
634 // was inserted. Will merge with an overlapping ProfileCode if one is present.
635 intptr_t InsertCode(ProfileCode* new_code) {
636 const uword start = new_code->start();
637 const uword end = new_code->end();
638 const intptr_t length = table_.length();
812 if (length == 0) { 639 if (length == 0) {
813 code_region_table_->Add(code_region); 640 table_.Add(new_code);
814 return length; 641 return length;
815 } 642 }
816 // Determine the correct place to insert or merge code_region into table. 643 // Determine the correct place to insert or merge |new_code| into table.
817 intptr_t lo = FindRegionIndex(start, &CompareLowerBound); 644 intptr_t lo = FindCodeIndex(start, &CompareLowerBound);
818 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound); 645 intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound);
819 // TODO(johnmccutchan): Simplify below logic. 646 // TODO(johnmccutchan): Simplify below logic.
820 if ((lo == length) && (hi == length)) { 647 if ((lo == length) && (hi == length)) {
821 lo = length - 1; 648 lo = length - 1;
822 } 649 }
823 if (lo == length) { 650 if (lo == length) {
824 CodeRegion* region = At(hi); 651 ProfileCode* code = At(hi);
825 if (region->overlaps(code_region)) { 652 if (code->Overlaps(new_code)) {
826 HandleOverlap(region, code_region, start, end); 653 HandleOverlap(code, new_code, start, end);
827 return hi; 654 return hi;
828 } 655 }
829 code_region_table_->Add(code_region); 656 table_.Add(new_code);
830 return length; 657 return length;
831 } else if (hi == length) { 658 } else if (hi == length) {
832 CodeRegion* region = At(lo); 659 ProfileCode* code = At(lo);
833 if (region->overlaps(code_region)) { 660 if (code->Overlaps(new_code)) {
834 HandleOverlap(region, code_region, start, end); 661 HandleOverlap(code, new_code, start, end);
835 return lo; 662 return lo;
836 } 663 }
837 code_region_table_->Add(code_region); 664 table_.Add(new_code);
838 return length; 665 return length;
839 } else if (lo == hi) { 666 } else if (lo == hi) {
840 CodeRegion* region = At(lo); 667 ProfileCode* code = At(lo);
841 if (region->overlaps(code_region)) { 668 if (code->Overlaps(new_code)) {
842 HandleOverlap(region, code_region, start, end); 669 HandleOverlap(code, new_code, start, end);
843 return lo; 670 return lo;
844 } 671 }
845 code_region_table_->InsertAt(lo, code_region); 672 table_.InsertAt(lo, new_code);
846 return lo; 673 return lo;
847 } else { 674 } else {
848 CodeRegion* region = At(lo); 675 ProfileCode* code = At(lo);
849 if (region->overlaps(code_region)) { 676 if (code->Overlaps(new_code)) {
850 HandleOverlap(region, code_region, start, end); 677 HandleOverlap(code, new_code, start, end);
851 return lo; 678 return lo;
852 } 679 }
853 region = At(hi); 680 code = At(hi);
854 if (region->overlaps(code_region)) { 681 if (code->Overlaps(new_code)) {
855 HandleOverlap(region, code_region, start, end); 682 HandleOverlap(code, new_code, start, end);
856 return hi; 683 return hi;
857 } 684 }
858 code_region_table_->InsertAt(hi, code_region); 685 table_.InsertAt(hi, new_code);
859 return hi; 686 return hi;
860 } 687 }
861 UNREACHABLE(); 688 UNREACHABLE();
862 } 689 }
863 690
864 void Verify() {
865 VerifyOrder();
866 VerifyOverlap();
867 }
868
869 void DebugPrint() {
870 OS::Print("Dumping CodeRegionTable:\n");
871 for (intptr_t i = 0; i < code_region_table_->length(); i++) {
872 CodeRegion* region = At(i);
873 region->DebugPrint();
874 }
875 }
876
877 private: 691 private:
878 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const { 692 intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const {
879 ASSERT(comparator != NULL); 693 ASSERT(comparator != NULL);
880 intptr_t count = code_region_table_->length(); 694 intptr_t count = table_.length();
881 intptr_t first = 0; 695 intptr_t first = 0;
882 while (count > 0) { 696 while (count > 0) {
883 intptr_t it = first; 697 intptr_t it = first;
884 intptr_t step = count / 2; 698 intptr_t step = count / 2;
885 it += step; 699 it += step;
886 const CodeRegion* code_region = At(it); 700 const ProfileCode* code = At(it);
887 if (comparator(pc, code_region->start(), code_region->end())) { 701 if (comparator(pc, code->start(), code->end())) {
888 first = ++it; 702 first = ++it;
889 count -= (step + 1); 703 count -= (step + 1);
890 } else { 704 } else {
891 count = step; 705 count = step;
892 } 706 }
893 } 707 }
894 return first; 708 return first;
895 } 709 }
896 710
897 static bool CompareUpperBound(uword pc, uword start, uword end) { 711 static bool CompareUpperBound(uword pc, uword start, uword end) {
898 return pc >= end; 712 return pc >= end;
899 } 713 }
900 714
901 static bool CompareLowerBound(uword pc, uword start, uword end) { 715 static bool CompareLowerBound(uword pc, uword start, uword end) {
902 return end <= pc; 716 return end <= pc;
903 } 717 }
904 718
905 void HandleOverlap(CodeRegion* region, CodeRegion* code_region, 719 void HandleOverlap(ProfileCode* existing, ProfileCode* code,
906 uword start, uword end) { 720 uword start, uword end) {
907 // We should never see overlapping Dart code regions. 721 // We should never see overlapping Dart code regions.
908 ASSERT(region->kind() != CodeRegion::kDartCode); 722 ASSERT(existing->kind() != ProfileCode::kDartCode);
909 // We should never see overlapping Tag code regions. 723 // We should never see overlapping Tag code regions.
910 ASSERT(region->kind() != CodeRegion::kTagCode); 724 ASSERT(existing->kind() != ProfileCode::kTagCode);
911 // When code regions overlap, they should be of the same kind. 725 // When code regions overlap, they should be of the same kind.
912 ASSERT(region->kind() == code_region->kind()); 726 ASSERT(existing->kind() == code->kind());
913 region->AdjustExtent(start, end); 727 existing->AdjustExtent(start, end);
914 } 728 }
915 729
916 void VerifyOrder() { 730 void VerifyOrder() {
917 const intptr_t length = code_region_table_->length(); 731 const intptr_t length = table_.length();
918 if (length == 0) { 732 if (length == 0) {
919 return; 733 return;
920 } 734 }
921 uword last = (*code_region_table_)[0]->end(); 735 uword last = table_[0]->end();
922 for (intptr_t i = 1; i < length; i++) { 736 for (intptr_t i = 1; i < length; i++) {
923 CodeRegion* a = (*code_region_table_)[i]; 737 ProfileCode* a = table_[i];
924 ASSERT(last <= a->start()); 738 ASSERT(last <= a->start());
925 last = a->end(); 739 last = a->end();
926 } 740 }
927 } 741 }
928 742
929 void VerifyOverlap() { 743 void VerifyOverlap() {
930 const intptr_t length = code_region_table_->length(); 744 const intptr_t length = table_.length();
931 for (intptr_t i = 0; i < length; i++) { 745 for (intptr_t i = 0; i < length; i++) {
932 CodeRegion* a = (*code_region_table_)[i]; 746 ProfileCode* a = table_[i];
933 for (intptr_t j = i+1; j < length; j++) { 747 for (intptr_t j = i+1; j < length; j++) {
934 CodeRegion* b = (*code_region_table_)[j]; 748 ProfileCode* b = table_[j];
935 ASSERT(!a->contains(b->start()) && 749 ASSERT(!a->Contains(b->start()) &&
936 !a->contains(b->end() - 1) && 750 !a->Contains(b->end() - 1) &&
937 !b->contains(a->start()) && 751 !b->Contains(a->start()) &&
938 !b->contains(a->end() - 1)); 752 !b->Contains(a->end() - 1));
939 } 753 }
940 } 754 }
941 } 755 }
942 756
943 ZoneGrowableArray<CodeRegion*>* code_region_table_; 757 ZoneGrowableArray<ProfileCode*> table_;
944 }; 758 };
945 759
946 760
947 class CodeRegionTableBuilder { 761 ProfileTrieNode::ProfileTrieNode(intptr_t table_index)
762 : table_index_(table_index),
763 count_(0),
764 children_(0) {
765 ASSERT(table_index_ >= 0);
766 }
767
768
769 ProfileTrieNode::~ProfileTrieNode() {
770 }
771
772
773 void ProfileTrieNode::SortChildren() {
774 children_.Sort(ProfileTrieNodeCompare);
775 // Recurse.
776 for (intptr_t i = 0; i < children_.length(); i++) {
777 children_[i]->SortChildren();
778 }
779 }
780
781
782 class ProfileCodeTrieNode : public ProfileTrieNode {
948 public: 783 public:
949 CodeRegionTableBuilder(Isolate* isolate, 784 explicit ProfileCodeTrieNode(intptr_t table_index)
950 CodeRegionTable* live_code_table, 785 : ProfileTrieNode(table_index) {
951 CodeRegionTable* dead_code_table,
952 CodeRegionTable* tag_code_table,
953 DeoptimizedCodeSet* deoptimized_code)
954 : live_code_table_(live_code_table),
955 dead_code_table_(dead_code_table),
956 tag_code_table_(tag_code_table),
957 isolate_(isolate),
958 vm_isolate_(Dart::vm_isolate()),
959 null_code_(Code::ZoneHandle()),
960 deoptimized_code_(deoptimized_code) {
961 ASSERT(live_code_table_ != NULL);
962 ASSERT(dead_code_table_ != NULL);
963 ASSERT(tag_code_table_ != NULL);
964 ASSERT(isolate_ != NULL);
965 ASSERT(vm_isolate_ != NULL);
966 ASSERT(null_code_.IsNull());
967 frames_ = 0;
968 min_time_ = kMaxInt64;
969 max_time_ = 0;
970 } 786 }
971 787
972 void Build(ProcessedSampleBuffer* buffer) { 788 void PrintToJSONArray(JSONArray* array) const {
973 for (intptr_t i = 0; i < buffer->length(); i++) { 789 ASSERT(array != NULL);
974 ProcessedSample* sample = buffer->At(i); 790 // Write CodeRegion index.
975 VisitSample(i, sample); 791 array->AddValue(table_index());
792 // Write count.
793 array->AddValue(count());
794 // Write number of children.
795 intptr_t child_count = NumChildren();
796 array->AddValue(child_count);
797 // Recurse.
798 for (intptr_t i = 0; i < child_count; i++) {
799 children_[i]->PrintToJSONArray(array);
976 } 800 }
977 } 801 }
978 802
979 intptr_t frames() const { return frames_; } 803 ProfileCodeTrieNode* GetChild(intptr_t child_table_index) {
980 804 const intptr_t length = NumChildren();
981 intptr_t TimeDeltaMicros() const { 805 intptr_t i = 0;
982 return static_cast<intptr_t>(max_time_ - min_time_); 806 while (i < length) {
807 ProfileCodeTrieNode* child =
808 reinterpret_cast<ProfileCodeTrieNode*>(children_[i]);
809 if (child->table_index() == child_table_index) {
810 return child;
811 }
812 if (child->table_index() > child_table_index) {
813 break;
814 }
815 i++;
816 }
817 ProfileCodeTrieNode* child = new ProfileCodeTrieNode(child_table_index);
818 if (i < length) {
819 // Insert at i.
820 children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
821 } else {
822 // Add to end.
823 children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
824 }
825 return child;
983 } 826 }
984 int64_t max_time() const { return max_time_; }
985
986 private:
987 void VisitSample(intptr_t serial, ProcessedSample* sample) {
988 int64_t timestamp = sample->timestamp();
989 if (timestamp > max_time_) {
990 max_time_ = timestamp;
991 }
992 if (timestamp < min_time_) {
993 min_time_ = timestamp;
994 }
995
996 // Make sure VM tag is created.
997 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
998 CreateTag(VMTag::kNativeTagId);
999 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1000 CreateTag(VMTag::kRuntimeTagId);
1001 }
1002 CreateTag(sample->vm_tag());
1003
1004 // Make sure user tag is created.
1005 CreateUserTag(sample->user_tag());
1006
1007 // Exclusive tick for top frame if the first frame was executing.
1008 if (!sample->first_frame_executing()) {
1009 Tick(sample->At(0), true, serial, timestamp);
1010 }
1011
1012 // Inclusive tick for all frames.
1013 for (intptr_t i = 0; i < sample->length(); i++) {
1014 ASSERT(sample->At(i) != 0);
1015 frames_++;
1016 Tick(sample->At(i), false, serial, timestamp);
1017 }
1018 }
1019
1020 void CreateTag(uword tag) {
1021 intptr_t index = tag_code_table_->FindIndex(tag);
1022 if (index >= 0) {
1023 // Already created.
1024 return;
1025 }
1026 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode,
1027 tag,
1028 tag + 1,
1029 0,
1030 null_code_);
1031 index = tag_code_table_->InsertCodeRegion(region);
1032 ASSERT(index >= 0);
1033 }
1034
1035 void CreateUserTag(uword tag) {
1036 if (tag == 0) {
1037 // None set.
1038 return;
1039 }
1040 return CreateTag(tag);
1041 }
1042
1043 void Tick(uword pc, bool exclusive, intptr_t serial, int64_t timestamp) {
1044 CodeRegionTable::TickResult r;
1045 if (exclusive) {
1046 // Exclusive ticks do not have an associated serial.
1047 serial = -1;
1048 }
1049
1050 r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
1051 if (r == CodeRegionTable::kTicked) {
1052 // Live code found and ticked.
1053 return;
1054 }
1055
1056 if (r == CodeRegionTable::kNewerCode) {
1057 // Code has been overwritten by newer code.
1058 // Update shadow table of dead code regions.
1059 r = dead_code_table_->Tick(pc, exclusive, serial, timestamp);
1060 ASSERT(r != CodeRegionTable::kNewerCode);
1061 if (r == CodeRegionTable::kTicked) {
1062 // Dead code found and ticked.
1063 return;
1064 }
1065 ASSERT(r == CodeRegionTable::kNotFound);
1066 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
1067 return;
1068 }
1069
1070 // Create new live CodeRegion.
1071 ASSERT(r == CodeRegionTable::kNotFound);
1072 CodeRegion* region = CreateCodeRegion(pc);
1073 intptr_t index = live_code_table_->InsertCodeRegion(region);
1074 ASSERT(index >= 0);
1075 region = live_code_table_->At(index);
1076 if (region->compile_timestamp() <= timestamp) {
1077 region->Tick(pc, exclusive, serial);
1078 return;
1079 }
1080
1081 // We have created a new code region but it's for a CodeRegion
1082 // compiled after the sample.
1083 ASSERT(region->kind() == CodeRegion::kDartCode);
1084 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
1085 }
1086
1087 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
1088 // Need to create dead code.
1089 CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode,
1090 pc,
1091 pc + 1,
1092 0,
1093 null_code_);
1094 intptr_t index = dead_code_table_->InsertCodeRegion(region);
1095 ASSERT(index >= 0);
1096 dead_code_table_->At(index)->Tick(pc, exclusive, serial);
1097 }
1098
1099 CodeRegion* CreateCodeRegion(uword pc) {
1100 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
1101 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
1102 Code& code = Code::Handle(isolate_);
1103
1104 // Check current isolate for pc.
1105 if (isolate_->heap()->CodeContains(pc)) {
1106 code ^= Code::LookupCode(pc);
1107 if (!code.IsNull()) {
1108 deoptimized_code_->Add(code);
1109 return new CodeRegion(CodeRegion::kDartCode,
1110 code.EntryPoint(),
1111 code.EntryPoint() + code.Size(),
1112 code.compile_timestamp(),
1113 code);
1114 }
1115 return new CodeRegion(CodeRegion::kCollectedCode,
1116 pc,
1117 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1118 0,
1119 code);
1120 }
1121
1122 // Check VM isolate for pc.
1123 if (vm_isolate_->heap()->CodeContains(pc)) {
1124 code ^= Code::LookupCodeInVmIsolate(pc);
1125 if (!code.IsNull()) {
1126 return new CodeRegion(CodeRegion::kDartCode,
1127 code.EntryPoint(),
1128 code.EntryPoint() + code.Size(),
1129 code.compile_timestamp(),
1130 code);
1131 }
1132 return new CodeRegion(CodeRegion::kCollectedCode,
1133 pc,
1134 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1135 0,
1136 code);
1137 }
1138
1139 // Check NativeSymbolResolver for pc.
1140 uintptr_t native_start = 0;
1141 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
1142 &native_start);
1143 if (native_name == NULL) {
1144 // No native name found.
1145 return new CodeRegion(CodeRegion::kNativeCode,
1146 pc,
1147 pc + 1,
1148 0,
1149 code);
1150 }
1151 ASSERT(pc >= native_start);
1152 CodeRegion* code_region =
1153 new CodeRegion(CodeRegion::kNativeCode,
1154 native_start,
1155 pc + 1,
1156 0,
1157 code);
1158 code_region->SetName(native_name);
1159 free(native_name);
1160 return code_region;
1161 }
1162
1163 intptr_t frames_;
1164 int64_t min_time_;
1165 int64_t max_time_;
1166 CodeRegionTable* live_code_table_;
1167 CodeRegionTable* dead_code_table_;
1168 CodeRegionTable* tag_code_table_;
1169 Isolate* isolate_;
1170 Isolate* vm_isolate_;
1171 const Code& null_code_;
1172 DeoptimizedCodeSet* deoptimized_code_;
1173 };
1174
1175
1176 class CodeRegionFunctionMapper : public ValueObject {
1177 public:
1178 CodeRegionFunctionMapper(Isolate* isolate,
1179 CodeRegionTable* live_code_table,
1180 CodeRegionTable* dead_code_table,
1181 CodeRegionTable* tag_code_table,
1182 ProfileFunctionTable* function_table)
1183 : isolate_(isolate),
1184 live_code_table_(live_code_table),
1185 dead_code_table_(dead_code_table),
1186 tag_code_table_(tag_code_table),
1187 function_table_(function_table) {
1188 ASSERT(isolate_ != NULL);
1189 ASSERT(live_code_table_ != NULL);
1190 ASSERT(dead_code_table_ != NULL);
1191 ASSERT(tag_code_table_ != NULL);
1192 dead_code_table_offset_ = live_code_table_->Length();
1193 tag_code_table_offset_ = dead_code_table_offset_ +
1194 dead_code_table_->Length();
1195
1196 const Code& null_code = Code::ZoneHandle();
1197
1198 // Create the truncated tag.
1199 intptr_t truncated_index =
1200 tag_code_table_->FindIndex(VMTag::kTruncatedTagId);
1201 ASSERT(truncated_index < 0);
1202 CodeRegion* truncated =
1203 new CodeRegion(CodeRegion::kTagCode,
1204 VMTag::kTruncatedTagId,
1205 VMTag::kTruncatedTagId + 1,
1206 0,
1207 null_code);
1208 truncated_index = tag_code_table_->InsertCodeRegion(truncated);
1209 ASSERT(truncated_index >= 0);
1210
1211 // Create the root tag.
1212 intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
1213 ASSERT(root_index < 0);
1214 CodeRegion* root = new CodeRegion(CodeRegion::kTagCode,
1215 VMTag::kRootTagId,
1216 VMTag::kRootTagId + 1,
1217 0,
1218 null_code);
1219 root_index = tag_code_table_->InsertCodeRegion(root);
1220 ASSERT(root_index >= 0);
1221 }
1222
1223 void Map() {
1224 // Calculate final indexes in code table for each CodeRegion.
1225 for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
1226 const intptr_t index = i;
1227 CodeRegion* region = live_code_table_->At(i);
1228 ASSERT(region != NULL);
1229 region->set_code_table_index(index);
1230 }
1231
1232 for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
1233 const intptr_t index = dead_code_table_offset_ + i;
1234 CodeRegion* region = dead_code_table_->At(i);
1235 ASSERT(region != NULL);
1236 region->set_code_table_index(index);
1237 }
1238
1239 for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
1240 const intptr_t index = tag_code_table_offset_ + i;
1241 CodeRegion* region = tag_code_table_->At(i);
1242 ASSERT(region != NULL);
1243 region->set_code_table_index(index);
1244 }
1245
1246 // Associate a ProfileFunction with each CodeRegion.
1247 for (intptr_t i = 0; i < live_code_table_->Length(); i++) {
1248 CodeRegion* region = live_code_table_->At(i);
1249 ASSERT(region != NULL);
1250 region->SetFunctionAndName(function_table_);
1251 }
1252
1253 for (intptr_t i = 0; i < dead_code_table_->Length(); i++) {
1254 CodeRegion* region = dead_code_table_->At(i);
1255 ASSERT(region != NULL);
1256 region->SetFunctionAndName(function_table_);
1257 }
1258
1259 for (intptr_t i = 0; i < tag_code_table_->Length(); i++) {
1260 CodeRegion* region = tag_code_table_->At(i);
1261 ASSERT(region != NULL);
1262 region->SetFunctionAndName(function_table_);
1263 }
1264 }
1265
1266 private:
1267 Isolate* isolate_;
1268 CodeRegionTable* live_code_table_;
1269 CodeRegionTable* dead_code_table_;
1270 CodeRegionTable* tag_code_table_;
1271 ProfileFunctionTable* function_table_;
1272 intptr_t dead_code_table_offset_;
1273 intptr_t tag_code_table_offset_;
1274 }; 827 };
1275 828
1276 829
1277 class ProfileFunctionTrieNodeCode { 830 class ProfileFunctionTrieNodeCode {
1278 public: 831 public:
1279 explicit ProfileFunctionTrieNodeCode(intptr_t index) 832 explicit ProfileFunctionTrieNodeCode(intptr_t index)
1280 : code_index_(index), 833 : code_index_(index),
1281 ticks_(0) { 834 ticks_(0) {
1282 } 835 }
1283 836
1284 intptr_t index() const { 837 intptr_t index() const {
1285 return code_index_; 838 return code_index_;
1286 } 839 }
1287 840
1288 void Tick() { 841 void Tick() {
1289 ticks_++; 842 ticks_++;
1290 } 843 }
1291 844
1292 intptr_t ticks() const { 845 intptr_t ticks() const {
1293 return ticks_; 846 return ticks_;
1294 } 847 }
1295 848
1296 private: 849 private:
1297 intptr_t code_index_; 850 intptr_t code_index_;
1298 intptr_t ticks_; 851 intptr_t ticks_;
1299 }; 852 };
1300 853
1301 854
1302 class ProfileFunctionTrieNode : public ZoneAllocated { 855 class ProfileFunctionTrieNode : public ProfileTrieNode {
1303 public: 856 public:
1304 explicit ProfileFunctionTrieNode(intptr_t profile_function_table_index) 857 explicit ProfileFunctionTrieNode(intptr_t table_index)
1305 : profile_function_table_index_(profile_function_table_index), 858 : ProfileTrieNode(table_index),
1306 count_(0), 859 code_objects_(1) {
1307 code_objects_(new ZoneGrowableArray<ProfileFunctionTrieNodeCode>()) {
1308 } 860 }
1309 861
1310 void Tick() { 862 void PrintToJSONArray(JSONArray* array) const {
1311 count_++; 863 ASSERT(array != NULL);
864 // Write CodeRegion index.
865 array->AddValue(table_index());
866 // Write count.
867 array->AddValue(count());
868 // Write number of code objects.
869 intptr_t code_count = code_objects_.length();
870 array->AddValue(code_count);
871 // Write each code object index and ticks.
872 for (intptr_t i = 0; i < code_count; i++) {
873 array->AddValue(code_objects_[i].index());
874 array->AddValue(code_objects_[i].ticks());
875 }
876 // Write number of children.
877 intptr_t child_count = children_.length();
878 array->AddValue(child_count);
879 // Recurse.
880 for (intptr_t i = 0; i < child_count; i++) {
881 children_[i]->PrintToJSONArray(array);
882 }
1312 } 883 }
1313 884
1314 intptr_t count() const { 885 ProfileFunctionTrieNode* GetChild(intptr_t child_table_index) {
1315 return count_; 886 const intptr_t length = NumChildren();
1316 }
1317
1318 intptr_t profile_function_table_index() const {
1319 return profile_function_table_index_;
1320 }
1321
1322
1323 ProfileFunctionTrieNode* GetChild(intptr_t child_index) {
1324 const intptr_t length = children_.length();
1325 intptr_t i = 0; 887 intptr_t i = 0;
1326 while (i < length) { 888 while (i < length) {
1327 ProfileFunctionTrieNode* child = children_[i]; 889 ProfileFunctionTrieNode* child =
1328 if (child->profile_function_table_index() == child_index) { 890 reinterpret_cast<ProfileFunctionTrieNode*>(children_[i]);
891 if (child->table_index() == child_table_index) {
1329 return child; 892 return child;
1330 } 893 }
1331 if (child->profile_function_table_index() > child_index) { 894 if (child->table_index() > child_table_index) {
1332 break; 895 break;
1333 } 896 }
1334 i++; 897 i++;
1335 } 898 }
1336 // Add new ProfileFunctionTrieNode, sorted by index.
1337 ProfileFunctionTrieNode* child = 899 ProfileFunctionTrieNode* child =
1338 new ProfileFunctionTrieNode(child_index); 900 new ProfileFunctionTrieNode(child_table_index);
1339 if (i < length) { 901 if (i < length) {
1340 // Insert at i. 902 // Insert at i.
1341 children_.InsertAt(i, child); 903 children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
1342 } else { 904 } else {
1343 // Add to end. 905 // Add to end.
1344 children_.Add(child); 906 children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
1345 } 907 }
1346 return child; 908 return child;
1347 } 909 }
1348 910
1349 void AddCodeObjectIndex(intptr_t index) { 911 void AddCodeObjectIndex(intptr_t index) {
1350 for (intptr_t i = 0; i < code_objects_->length(); i++) { 912 for (intptr_t i = 0; i < code_objects_.length(); i++) {
1351 ProfileFunctionTrieNodeCode& code_object = (*code_objects_)[i]; 913 ProfileFunctionTrieNodeCode& code_object = code_objects_[i];
1352 if (code_object.index() == index) { 914 if (code_object.index() == index) {
1353 code_object.Tick(); 915 code_object.Tick();
1354 return; 916 return;
1355 } 917 }
1356 } 918 }
1357 ProfileFunctionTrieNodeCode code_object(index); 919 ProfileFunctionTrieNodeCode code_object(index);
1358 code_object.Tick(); 920 code_object.Tick();
1359 code_objects_->Add(code_object); 921 code_objects_.Add(code_object);
1360 }
1361
1362 // This should only be called after the trie is completely built.
1363 void SortByCount() {
1364 code_objects_->Sort(ProfileFunctionTrieNodeCodeCompare);
1365 children_.Sort(ProfileFunctionTrieNodeCompare);
1366 intptr_t child_count = children_.length();
1367 // Recurse.
1368 for (intptr_t i = 0; i < child_count; i++) {
1369 children_[i]->SortByCount();
1370 }
1371 }
1372
1373 void PrintToJSONArray(JSONArray* array) const {
1374 ASSERT(array != NULL);
1375 // Write CodeRegion index.
1376 array->AddValue(profile_function_table_index_);
1377 // Write count.
1378 array->AddValue(count_);
1379 // Write number of code objects.
1380 intptr_t code_count = code_objects_->length();
1381 array->AddValue(code_count);
1382 // Write each code object index and ticks.
1383 for (intptr_t i = 0; i < code_count; i++) {
1384 array->AddValue((*code_objects_)[i].index());
1385 array->AddValue((*code_objects_)[i].ticks());
1386 }
1387 // Write number of children.
1388 intptr_t child_count = children_.length();
1389 array->AddValue(child_count);
1390 // Recurse.
1391 for (intptr_t i = 0; i < child_count; i++) {
1392 children_[i]->PrintToJSONArray(array);
1393 }
1394 } 922 }
1395 923
1396 private: 924 private:
1397 static int ProfileFunctionTrieNodeCodeCompare( 925 ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_;
1398 const ProfileFunctionTrieNodeCode* a,
1399 const ProfileFunctionTrieNodeCode* b) {
1400 ASSERT(a != NULL);
1401 ASSERT(b != NULL);
1402 return b->ticks() - a->ticks();
1403 }
1404
1405 static int ProfileFunctionTrieNodeCompare(ProfileFunctionTrieNode* const* a,
1406 ProfileFunctionTrieNode* const* b) {
1407 ASSERT(a != NULL);
1408 ASSERT(b != NULL);
1409 return (*b)->count() - (*a)->count();
1410 }
1411
1412 const intptr_t profile_function_table_index_;
1413 intptr_t count_;
1414 ZoneGrowableArray<ProfileFunctionTrieNode*> children_;
1415 ZoneGrowableArray<ProfileFunctionTrieNodeCode>* code_objects_;
1416 }; 926 };
1417 927
1418 928
1419 class TrieBuilder : public ValueObject { 929 class ProfileBuilder : public ValueObject {
1420 public: 930 public:
1421 TrieBuilder(CodeRegionTable* live_code_table, 931 ProfileBuilder(Isolate* isolate,
1422 CodeRegionTable* dead_code_table, 932 SampleFilter* filter,
1423 CodeRegionTable* tag_code_table) 933 Profile::TagOrder tag_order,
1424 : live_code_table_(live_code_table), 934 Profile* profile)
1425 dead_code_table_(dead_code_table), 935 : isolate_(isolate),
1426 tag_code_table_(tag_code_table) { 936 vm_isolate_(Dart::vm_isolate()),
1427 ASSERT(live_code_table_ != NULL); 937 filter_(filter),
1428 ASSERT(dead_code_table_ != NULL); 938 tag_order_(tag_order),
1429 ASSERT(tag_code_table_ != NULL); 939 profile_(profile),
1430 } 940 deoptimized_code_(new DeoptimizedCodeSet(isolate)),
1431 941 null_code_(Code::ZoneHandle()),
1432 ProfilerService::TagOrder tag_order() const { 942 null_function_(Function::ZoneHandle()),
1433 return tag_order_; 943 tick_functions_(false),
1434 } 944 samples_(NULL) {
1435 945 ASSERT(profile_ != NULL);
1436 void set_tag_order(ProfilerService::TagOrder tag_order) { 946 }
1437 tag_order_ = tag_order; 947
1438 } 948 void Build() {
1439 949 ScopeTimer sw("ProfileBuilder::Build", FLAG_trace_profiler);
1440 protected: 950 FilterSamples();
1441 intptr_t FindTagIndex(uword tag) const { 951
1442 if (tag == 0) { 952 Setup();
1443 UNREACHABLE(); 953 BuildCodeTable();
1444 return -1; 954 FinalizeCodeIndexes();
1445 } 955 BuildFunctionTable();
1446 intptr_t index = tag_code_table_->FindIndex(tag); 956
1447 if (index < 0) { 957 BuildCodeTrie(Profile::kExclusiveCode);
1448 UNREACHABLE(); 958 BuildCodeTrie(Profile::kInclusiveCode);
1449 return -1; 959
1450 } 960 BuildFunctionTrie(Profile::kExclusiveFunction);
1451 ASSERT(index >= 0); 961 BuildFunctionTrie(Profile::kInclusiveFunction);
1452 CodeRegion* region = tag_code_table_->At(index);
1453 ASSERT(region->contains(tag));
1454 return region->code_table_index();
1455 }
1456
1457 intptr_t FindDeadIndex(uword pc, int64_t timestamp) const {
1458 intptr_t index = dead_code_table_->FindIndex(pc);
1459 if (index < 0) {
1460 OS::Print("%" Px " cannot be found\n", pc);
1461 return -1;
1462 }
1463 CodeRegion* region = dead_code_table_->At(index);
1464 ASSERT(region->contains(pc));
1465 ASSERT(region->compile_timestamp() <= timestamp);
1466 return region->code_table_index();
1467 }
1468
1469 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
1470 intptr_t index = live_code_table_->FindIndex(pc);
1471 if (index < 0) {
1472 // Try dead code table.
1473 return FindDeadIndex(pc, timestamp);
1474 }
1475 CodeRegion* region = live_code_table_->At(index);
1476 ASSERT(region->contains(pc));
1477 if (region->compile_timestamp() > timestamp) {
1478 // Overwritten code, find in dead code table.
1479 return FindDeadIndex(pc, timestamp);
1480 }
1481 ASSERT(region->compile_timestamp() <= timestamp);
1482 return region->code_table_index();
1483 }
1484
1485 bool vm_tags_emitted() const {
1486 return (tag_order_ == ProfilerService::kUserVM) ||
1487 (tag_order_ == ProfilerService::kVMUser) ||
1488 (tag_order_ == ProfilerService::kVM);
1489 }
1490
1491 CodeRegion* FindCodeObject(uword pc, int64_t timestamp) const {
1492 intptr_t index = live_code_table_->FindIndex(pc);
1493 if (index < 0) {
1494 return NULL;
1495 }
1496 CodeRegion* region = live_code_table_->At(index);
1497 ASSERT(region->contains(pc));
1498 if (region->compile_timestamp() > timestamp) {
1499 // Overwritten code, find in dead code table.
1500 index = dead_code_table_->FindIndex(pc);
1501 if (index < 0) {
1502 return NULL;
1503 }
1504 region = dead_code_table_->At(index);
1505 ASSERT(region->contains(pc));
1506 ASSERT(region->compile_timestamp() <= timestamp);
1507 return region;
1508 }
1509 ASSERT(region->compile_timestamp() <= timestamp);
1510 return region;
1511 }
1512
1513 CodeRegionTable* live_code_table_;
1514 CodeRegionTable* dead_code_table_;
1515 CodeRegionTable* tag_code_table_;
1516 ProfilerService::TagOrder tag_order_;
1517 };
1518
1519
1520 class ProfileFunctionTrieBuilder : public TrieBuilder {
1521 public:
1522 ProfileFunctionTrieBuilder(CodeRegionTable* live_code_table,
1523 CodeRegionTable* dead_code_table,
1524 CodeRegionTable* tag_code_table,
1525 ProfileFunctionTable* function_table)
1526 : TrieBuilder(live_code_table, dead_code_table, tag_code_table),
1527 function_table_(function_table),
1528 inclusive_tree_(false) {
1529 ASSERT(function_table_ != NULL);
1530 set_tag_order(ProfilerService::kUserVM);
1531
1532 // Verify that the truncated tag exists.
1533 ASSERT(tag_code_table_->FindIndex(VMTag::kTruncatedTagId) >= 0);
1534
1535 // Verify that the root tag exists.
1536 intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
1537 ASSERT(root_index >= 0);
1538
1539 // Setup root.
1540 CodeRegion* region = tag_code_table_->At(root_index);
1541 ASSERT(region != NULL);
1542 ProfileFunction* function = region->function();
1543 ASSERT(function != NULL);
1544
1545 exclusive_root_ = new ProfileFunctionTrieNode(function->index());
1546 inclusive_root_ = new ProfileFunctionTrieNode(function->index());
1547 }
1548
1549 void VisitSample(intptr_t sample_idx, ProcessedSample* sample) {
1550 inclusive_tree_ = false;
1551 ProcessSampleExclusive(sample_idx, sample);
1552 inclusive_tree_ = true;
1553 ProcessSampleInclusive(sample_idx, sample);
1554 }
1555
1556 void Build(ProcessedSampleBuffer* buffer) {
1557 for (intptr_t i = 0; i < buffer->length(); i++) {
1558 ProcessedSample* sample = buffer->At(i);
1559 VisitSample(i, sample);
1560 }
1561 }
1562
1563 ProfileFunctionTrieNode* exclusive_root() const {
1564 return exclusive_root_;
1565 }
1566
1567 ProfileFunctionTrieNode* inclusive_root() const {
1568 return inclusive_root_;
1569 }
1570
1571 ProfilerService::TagOrder tag_order() const {
1572 return tag_order_;
1573 }
1574
1575 bool vm_tags_emitted() const {
1576 return (tag_order_ == ProfilerService::kUserVM) ||
1577 (tag_order_ == ProfilerService::kVMUser) ||
1578 (tag_order_ == ProfilerService::kVM);
1579 }
1580
1581 void set_tag_order(ProfilerService::TagOrder tag_order) {
1582 tag_order_ = tag_order;
1583 } 962 }
1584 963
1585 private: 964 private:
1586 void ProcessSampleInclusive(intptr_t sample_idx, ProcessedSample* sample) { 965 static bool IsInclusiveTrie(Profile::TrieKind kind) {
1587 // Give the root a tick. 966 return (kind == Profile::kInclusiveFunction) ||
1588 inclusive_root_->Tick(); 967 (kind == Profile::kInclusiveCode);
1589 ProfileFunctionTrieNode* current = inclusive_root_; 968 }
1590 current = AppendTags(sample, current); 969
1591 if (sample->truncated()) { 970 void Setup() {
1592 InclusiveTickTruncatedTag(); 971 profile_->live_code_ = new ProfileCodeTable();
1593 current = AppendTruncatedTag(current); 972 profile_->dead_code_ = new ProfileCodeTable();
1594 } 973 profile_->tag_code_ = new ProfileCodeTable();
1595 // Walk the sampled PCs. 974 profile_->functions_ = new ProfileFunctionTable();
1596 for (intptr_t i = sample->length() - 1; i >= 0; i--) { 975 // Register some synthetic tags.
1597 ASSERT(sample->At(i) != 0); 976 RegisterProfileCodeTag(VMTag::kRootTagId);
1598 current = ProcessPC(sample->At(i), 977 RegisterProfileCodeTag(VMTag::kTruncatedTagId);
1599 sample->timestamp(), 978 }
1600 current, 979
1601 sample_idx, 980 void FilterSamples() {
1602 (i == 0), 981 ScopeTimer sw("ProfileBuilder::FilterSamples", FLAG_trace_profiler);
1603 !sample->first_frame_executing() && (i == 0)); 982 MutexLocker profiler_data_lock(isolate_->profiler_data_mutex());
1604 } 983 IsolateProfilerData* profiler_data = isolate_->profiler_data();
1605 } 984 if (profiler_data == NULL) {
1606 985 return;
1607 void ProcessSampleExclusive(intptr_t sample_idx, ProcessedSample* sample) { 986 }
1608 // Give the root a tick. 987 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1609 exclusive_root_->Tick(); 988 if (sample_buffer == NULL) {
1610 ProfileFunctionTrieNode* current = exclusive_root_; 989 return;
1611 current = AppendTags(sample, current); 990 }
1612 // Walk the sampled PCs. 991 samples_ = sample_buffer->BuildProcessedSampleBuffer(filter_);
1613 for (intptr_t i = 0; i < sample->length(); i++) { 992 profile_->sample_count_ = samples_->length();
1614 ASSERT(sample->At(i) != 0); 993 }
1615 current = ProcessPC(sample->At(i), 994
1616 sample->timestamp(), 995 void UpdateMinMaxTimes(int64_t timestamp) {
1617 current, 996 profile_->min_time_ =
1618 sample_idx, 997 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_;
1619 (i == 0), 998 profile_->max_time_ =
1620 !sample->first_frame_executing() && (i == 0)); 999 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_;
1621 } 1000 }
1622 if (sample->truncated()) { 1001
1623 current = AppendTruncatedTag(current); 1002 void BuildCodeTable() {
1624 } 1003 ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler);
1625 } 1004 for (intptr_t i = 0; i < samples_->length(); i++) {
1626 1005 ProcessedSample* sample = samples_->At(i);
1627 ProfileFunctionTrieNode* AppendUserTag(ProcessedSample* sample, 1006 const int64_t timestamp = sample->timestamp();
1628 ProfileFunctionTrieNode* current) { 1007
1629 intptr_t user_tag_index = FindTagFunctionIndex(sample->user_tag()); 1008 // This is our first pass over the sample buffer, use this as an
1630 if (user_tag_index >= 0) { 1009 // opportunity to determine the min and max time ranges of this profile.
1631 current = current->GetChild(user_tag_index); 1010 UpdateMinMaxTimes(timestamp);
1632 // Give the tag a tick. 1011
1012 // Make sure VM tag exists.
1013 if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
1014 RegisterProfileCodeTag(VMTag::kNativeTagId);
1015 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
1016 RegisterProfileCodeTag(VMTag::kRuntimeTagId);
1017 }
1018 RegisterProfileCodeTag(sample->vm_tag());
1019 // Make sure user tag exists.
1020 RegisterProfileCodeTag(sample->user_tag());
1021
1022 // Make sure that a ProfileCode objects exist for all pcs in the sample
1023 // and tick each one.
1024 for (intptr_t i = 0; i < sample->length(); i++) {
1025 const uword pc = sample->At(i);
1026 ASSERT(pc != 0);
1027 ProfileCode* code = RegisterProfileCode(pc, timestamp);
1028 ASSERT(code != NULL);
1029 code->Tick(pc, (i == 0), i);
1030 }
1031 }
1032 }
1033
1034 void FinalizeCodeIndexes() {
1035 ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler);
1036 ProfileCodeTable* live_table = profile_->live_code_;
1037 ProfileCodeTable* dead_table = profile_->dead_code_;
1038 ProfileCodeTable* tag_table = profile_->tag_code_;
1039 const intptr_t dead_code_index_offset = live_table->length();
1040 const intptr_t tag_code_index_offset =
1041 dead_table->length() + dead_code_index_offset;
1042
1043 profile_->dead_code_index_offset_ = dead_code_index_offset;
1044 profile_->tag_code_index_offset_ = tag_code_index_offset;
1045
1046 for (intptr_t i = 0; i < live_table->length(); i++) {
1047 const intptr_t index = i;
1048 ProfileCode* code = live_table->At(i);
1049 ASSERT(code != NULL);
1050 code->set_code_table_index(index);
1051 }
1052
1053 for (intptr_t i = 0; i < dead_table->length(); i++) {
1054 const intptr_t index = dead_code_index_offset + i;
1055 ProfileCode* code = dead_table->At(i);
1056 ASSERT(code != NULL);
1057 code->set_code_table_index(index);
1058 }
1059
1060 for (intptr_t i = 0; i < tag_table->length(); i++) {
1061 const intptr_t index = tag_code_index_offset + i;
1062 ProfileCode* code = tag_table->At(i);
1063 ASSERT(code != NULL);
1064 code->set_code_table_index(index);
1065 }
1066 }
1067
1068 void BuildFunctionTable() {
1069 ScopeTimer sw("ProfileBuilder::BuildFunctionTable", FLAG_trace_profiler);
1070 ProfileCodeTable* live_table = profile_->live_code_;
1071 ProfileCodeTable* dead_table = profile_->dead_code_;
1072 ProfileCodeTable* tag_table = profile_->tag_code_;
1073 ProfileFunctionTable* function_table = profile_->functions_;
1074 for (intptr_t i = 0; i < live_table->length(); i++) {
1075 ProfileCode* code = live_table->At(i);
1076 ASSERT(code != NULL);
1077 code->SetFunctionAndName(function_table);
1078 }
1079
1080 for (intptr_t i = 0; i < dead_table->length(); i++) {
1081 ProfileCode* code = dead_table->At(i);
1082 ASSERT(code != NULL);
1083 code->SetFunctionAndName(function_table);
1084 }
1085
1086 for (intptr_t i = 0; i < tag_table->length(); i++) {
1087 ProfileCode* code = tag_table->At(i);
1088 ASSERT(code != NULL);
1089 code->SetFunctionAndName(function_table);
1090 }
1091 }
1092
1093 void BuildCodeTrie(Profile::TrieKind kind) {
1094 ProfileCodeTrieNode* root =
1095 new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId));
1096 if (IsInclusiveTrie(kind)) {
1097 BuildInclusiveCodeTrie(root);
1098 } else {
1099 BuildExclusiveCodeTrie(root);
1100 }
1101 root->SortChildren();
1102 profile_->roots_[static_cast<intptr_t>(kind)] = root;
1103 }
1104
1105 void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) {
1106 ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie",
1107 FLAG_trace_profiler);
1108 for (intptr_t i = 0; i < samples_->length(); i++) {
1109 ProcessedSample* sample = samples_->At(i);
1110
1111 // Tick the root.
1112 ProfileCodeTrieNode* current = root;
1633 current->Tick(); 1113 current->Tick();
1634 } 1114
1635 return current; 1115 // VM & User tags.
1636 } 1116 current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
1637 1117
1638 1118 // Truncated tag.
1639 ProfileFunctionTrieNode* AppendTruncatedTag( 1119 if (sample->truncated()) {
1640 ProfileFunctionTrieNode* current) { 1120 current = AppendTruncatedTag(current);
1641 intptr_t truncated_tag_index = FindTagFunctionIndex(VMTag::kTruncatedTagId); 1121 }
1642 ASSERT(truncated_tag_index >= 0); 1122
1643 current = current->GetChild(truncated_tag_index); 1123 // Walk the sampled PCs.
1644 current->Tick(); 1124 for (intptr_t j = sample->length() - 1; j >= 0; j--) {
1645 return current; 1125 ASSERT(sample->At(j) != 0);
1646 } 1126 intptr_t index =
1647 1127 GetProfileCodeIndex(sample->At(j), sample->timestamp());
1648 void InclusiveTickTruncatedTag() { 1128 ASSERT(index >= 0);
1649 intptr_t index = tag_code_table_->FindIndex(VMTag::kTruncatedTagId); 1129 current = current->GetChild(index);
1650 CodeRegion* region = tag_code_table_->At(index); 1130 current->Tick();
1651 ProfileFunction* function = region->function(); 1131 }
1652 function->inc_inclusive_ticks(); 1132 }
1653 } 1133 }
1654 1134
1655 ProfileFunctionTrieNode* AppendVMTag(ProcessedSample* sample, 1135 void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) {
1656 ProfileFunctionTrieNode* current) { 1136 ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie",
1657 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { 1137 FLAG_trace_profiler);
1658 // Insert a dummy kNativeTagId node. 1138 for (intptr_t i = 0; i < samples_->length(); i++) {
1659 intptr_t tag_index = FindTagFunctionIndex(VMTag::kNativeTagId); 1139 ProcessedSample* sample = samples_->At(i);
1660 current = current->GetChild(tag_index); 1140
1661 // Give the tag a tick. 1141 // Tick the root.
1142 ProfileCodeTrieNode* current = root;
1662 current->Tick(); 1143 current->Tick();
1663 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 1144
1664 // Insert a dummy kRuntimeTagId node. 1145 // VM & User tags.
1665 intptr_t tag_index = FindTagFunctionIndex(VMTag::kRuntimeTagId); 1146 current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
1666 current = current->GetChild(tag_index); 1147
1667 // Give the tag a tick. 1148 // Walk the sampled PCs.
1149 for (intptr_t j = 0; j < sample->length(); j++) {
1150 ASSERT(sample->At(j) != 0);
1151 intptr_t index =
1152 GetProfileCodeIndex(sample->At(j), sample->timestamp());
1153 ASSERT(index >= 0);
1154 current = current->GetChild(index);
1155
1156 if (j == 0) {
1157 // Executing PC.
1158 if (!sample->first_frame_executing() || vm_tags_emitted()) {
1159 // Only tick if this isn't an exit frame or VM tags are emitted.
1160 current->Tick();
1161 }
1162 } else {
1163 // Caller PCs.
1164 current->Tick();
1165 }
1166
1167 current->Tick();
1168 }
1169
1170 // Truncated tag.
1171 if (sample->truncated()) {
1172 current = AppendTruncatedTag(current);
1173 }
1174 }
1175 }
1176
1177 void BuildFunctionTrie(Profile::TrieKind kind) {
1178 ProfileFunctionTrieNode* root =
1179 new ProfileFunctionTrieNode(
1180 GetProfileFunctionTagIndex(VMTag::kRootTagId));
1181 // We tick the functions while building the trie, but, we don't want to do
1182 // it for both tries, just one.
1183 tick_functions_ = IsInclusiveTrie(kind);
1184 if (IsInclusiveTrie(kind)) {
1185 BuildInclusiveFunctionTrie(root);
1186 } else {
1187 BuildExclusiveFunctionTrie(root);
1188 }
1189 root->SortChildren();
1190 profile_->roots_[static_cast<intptr_t>(kind)] = root;
1191 }
1192
1193 void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
1194 ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie",
1195 FLAG_trace_profiler);
1196 for (intptr_t i = 0; i < samples_->length(); i++) {
1197 ProcessedSample* sample = samples_->At(i);
1198
1199 // Tick the root.
1200 ProfileFunctionTrieNode* current = root;
1668 current->Tick(); 1201 current->Tick();
1669 } else { 1202
1670 intptr_t tag_index = FindTagFunctionIndex(sample->vm_tag()); 1203 // VM & User tags.
1671 current = current->GetChild(tag_index); 1204 current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
1672 // Give the tag a tick. 1205
1206 // Truncated tag.
1207 if (sample->truncated()) {
1208 current = AppendTruncatedTag(current);
1209 InclusiveTickTruncatedTag();
1210 }
1211
1212 // Walk the sampled PCs.
1213 for (intptr_t j = sample->length() - 1; j >= 0; j--) {
1214 ASSERT(sample->At(j) != 0);
1215 current = ProcessFunctionPC(
1216 sample->At(j),
1217 sample->timestamp(),
1218 current,
1219 i,
1220 (j == 0),
1221 sample->first_frame_executing(),
1222 true);
1223 }
1224 }
1225 }
1226
1227 void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
1228 ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie",
1229 FLAG_trace_profiler);
1230 for (intptr_t i = 0; i < samples_->length(); i++) {
1231 ProcessedSample* sample = samples_->At(i);
1232
1233 // Tick the root.
1234 ProfileFunctionTrieNode* current = root;
1673 current->Tick(); 1235 current->Tick();
1674 } 1236
1675 return current; 1237 // VM & User tags.
1676 } 1238 current = AppendTags(sample->vm_tag(), sample->user_tag(), current);
1677 1239
1678 ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag( 1240 // Walk the sampled PCs.
1679 ProcessedSample* sample, ProfileFunctionTrieNode* current) { 1241 for (intptr_t j = 0; j < sample->length(); j++) {
1680 // Only Native and Runtime entries have a second VM tag. 1242 ASSERT(sample->At(j) != 0);
1681 if (!VMTag::IsNativeEntryTag(sample->vm_tag()) && 1243 current = ProcessFunctionPC(
1682 !VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 1244 sample->At(j),
1683 return current; 1245 sample->timestamp(),
1684 } 1246 current,
1685 intptr_t tag_index = FindTagFunctionIndex(sample->vm_tag()); 1247 i,
1686 current = current->GetChild(tag_index); 1248 (j == 0),
1687 // Give the tag a tick. 1249 sample->first_frame_executing(),
1688 current->Tick(); 1250 false);
1689 return current; 1251 }
1690 } 1252
1691 1253 // Truncated tag.
1692 ProfileFunctionTrieNode* AppendVMTags(ProcessedSample* sample, 1254 if (sample->truncated()) {
1693 ProfileFunctionTrieNode* current) { 1255 current = AppendTruncatedTag(current);
1694 current = AppendVMTag(sample, current); 1256 }
1695 current = AppendSpecificNativeRuntimeEntryVMTag(sample, current); 1257 }
1696 return current; 1258 }
1697 } 1259
1698 1260 ProfileFunctionTrieNode* ProcessFunctionPC(
1699 ProfileFunctionTrieNode* AppendTags(ProcessedSample* sample, 1261 uword pc,
1700 ProfileFunctionTrieNode* current) { 1262 int64_t timestamp,
1701 // None. 1263 ProfileFunctionTrieNode* current,
1702 if (tag_order() == ProfilerService::kNoTags) { 1264 intptr_t inclusive_serial,
1703 return current; 1265 bool top_frame,
1704 } 1266 bool top_frame_executing,
1705 // User first. 1267 bool inclusive_tree) {
1706 if ((tag_order() == ProfilerService::kUserVM) || 1268 ProfileCode* profile_code = GetProfileCode(pc, timestamp);
1707 (tag_order() == ProfilerService::kUser)) { 1269 ASSERT(profile_code != NULL);
1708 current = AppendUserTag(sample, current); 1270 const char* code_name = profile_code->name();
1709 // Only user. 1271 if (code_name == NULL) {
1710 if (tag_order() == ProfilerService::kUser) { 1272 code_name = "";
1711 return current; 1273 }
1712 } 1274 intptr_t code_index = profile_code->code_table_index();
1713 return AppendVMTags(sample, current); 1275 const Code& code = Code::ZoneHandle(profile_code->code());
1714 }
1715 // VM first.
1716 ASSERT((tag_order() == ProfilerService::kVMUser) ||
1717 (tag_order() == ProfilerService::kVM));
1718 current = AppendVMTags(sample, current);
1719 // Only VM.
1720 if (tag_order() == ProfilerService::kVM) {
1721 return current;
1722 }
1723 return AppendUserTag(sample, current);
1724 }
1725
1726 intptr_t FindTagFunctionIndex(uword tag) const {
1727 if (tag == 0) {
1728 UNREACHABLE();
1729 return -1;
1730 }
1731 intptr_t index = tag_code_table_->FindIndex(tag);
1732 if (index < 0) {
1733 UNREACHABLE();
1734 return -1;
1735 }
1736 ASSERT(index >= 0);
1737 CodeRegion* region = tag_code_table_->At(index);
1738 ASSERT(region->contains(tag));
1739 ProfileFunction* function = region->function();
1740 ASSERT(function != NULL);
1741 return function->index();
1742 }
1743
1744 void Dump(ProfileFunctionTrieNode* current) {
1745 int current_index = current->profile_function_table_index();
1746 ProfileFunction* function = function_table_->At(current_index);
1747 function->Dump();
1748 OS::Print("\n");
1749 }
1750
1751 ProfileFunctionTrieNode* ProcessPC(uword pc,
1752 int64_t timestamp,
1753 ProfileFunctionTrieNode* current,
1754 intptr_t inclusive_serial,
1755 bool top_frame,
1756 bool exit_frame) {
1757 CodeRegion* region = FindCodeObject(pc, timestamp);
1758 if (region == NULL) {
1759 return current;
1760 }
1761 const char* region_name = region->name();
1762 if (region_name == NULL) {
1763 region_name = "";
1764 }
1765 intptr_t code_index = region->code_table_index();
1766 const Code& code = Code::ZoneHandle(region->code());
1767 GrowableArray<Function*> inlined_functions; 1276 GrowableArray<Function*> inlined_functions;
1768 if (!code.IsNull()) { 1277 if (!code.IsNull()) {
1769 intptr_t offset = pc - code.EntryPoint(); 1278 intptr_t offset = pc - code.EntryPoint();
1770 code.GetInlinedFunctionsAt(offset, &inlined_functions); 1279 code.GetInlinedFunctionsAt(offset, &inlined_functions);
1771 } 1280 }
1772 if (code.IsNull() || (inlined_functions.length() == 0)) { 1281 if (code.IsNull() || (inlined_functions.length() == 0)) {
1773 // No inlined functions. 1282 // No inlined functions.
1774 ProfileFunction* function = region->function(); 1283 ProfileFunction* function = profile_code->function();
1775 ASSERT(function != NULL); 1284 ASSERT(function != NULL);
1776 current = ProcessFunction(function, 1285 current = ProcessFunction(function,
1777 current, 1286 current,
1778 inclusive_serial, 1287 inclusive_serial,
1779 top_frame, 1288 top_frame,
1780 exit_frame, 1289 top_frame_executing,
1781 code_index); 1290 code_index);
1782 return current; 1291 return current;
1783 } 1292 }
1784 1293
1785 if (inclusive_tree_) { 1294 if (inclusive_tree) {
1786 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) { 1295 for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
1787 Function* inlined_function = inlined_functions[i]; 1296 Function* inlined_function = inlined_functions[i];
1788 ASSERT(inlined_function != NULL); 1297 ASSERT(inlined_function != NULL);
1789 ASSERT(!inlined_function->IsNull()); 1298 ASSERT(!inlined_function->IsNull());
1790 current = ProcessInlinedFunction(inlined_function, 1299 current = ProcessInlinedFunction(inlined_function,
1791 current, 1300 current,
1792 inclusive_serial, 1301 inclusive_serial,
1793 top_frame, 1302 top_frame,
1794 exit_frame, 1303 top_frame_executing,
1795 code_index); 1304 code_index);
1796 top_frame = false; 1305 top_frame = false;
1797 } 1306 }
1798 } else { 1307 } else {
1799 for (intptr_t i = 0; i < inlined_functions.length(); i++) { 1308 for (intptr_t i = 0; i < inlined_functions.length(); i++) {
1800 Function* inlined_function = inlined_functions[i]; 1309 Function* inlined_function = inlined_functions[i];
1801 ASSERT(inlined_function != NULL); 1310 ASSERT(inlined_function != NULL);
1802 ASSERT(!inlined_function->IsNull()); 1311 ASSERT(!inlined_function->IsNull());
1803 current = ProcessInlinedFunction(inlined_function, 1312 current = ProcessInlinedFunction(inlined_function,
1804 current, 1313 current,
1805 inclusive_serial, 1314 inclusive_serial,
1806 top_frame, 1315 top_frame,
1807 exit_frame, 1316 top_frame_executing,
1808 code_index); 1317 code_index);
1809 top_frame = false; 1318 top_frame = false;
1810 } 1319 }
1811 } 1320 }
1812 1321
1813 return current; 1322 return current;
1814 } 1323 }
1815 1324
1816 ProfileFunctionTrieNode* ProcessInlinedFunction( 1325 ProfileFunctionTrieNode* ProcessInlinedFunction(
1817 Function* inlined_function, 1326 Function* inlined_function,
1818 ProfileFunctionTrieNode* current, 1327 ProfileFunctionTrieNode* current,
1819 intptr_t inclusive_serial, 1328 intptr_t inclusive_serial,
1820 bool top_frame, 1329 bool top_frame,
1821 bool exit_frame, 1330 bool top_frame_executing,
1822 intptr_t code_index) { 1331 intptr_t code_index) {
1823 ProfileFunction* function = 1332 ProfileFunctionTable* function_table = profile_->functions_;
1824 function_table_->LookupOrAdd(*inlined_function); 1333 ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
1825 ASSERT(function != NULL); 1334 ASSERT(function != NULL);
1826 return ProcessFunction(function, 1335 return ProcessFunction(function,
1827 current, 1336 current,
1828 inclusive_serial, 1337 inclusive_serial,
1829 top_frame, 1338 top_frame,
1830 exit_frame, 1339 top_frame_executing,
1831 code_index); 1340 code_index);
1832 } 1341 }
1833 1342
1834 ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function, 1343 ProfileFunctionTrieNode* ProcessFunction(ProfileFunction* function,
1835 ProfileFunctionTrieNode* current, 1344 ProfileFunctionTrieNode* current,
1836 intptr_t inclusive_serial, 1345 intptr_t inclusive_serial,
1837 bool top_frame, 1346 bool top_frame,
1838 bool exit_frame, 1347 bool top_frame_executing,
1839 intptr_t code_index) { 1348 intptr_t code_index) {
1840 const bool exclusive = top_frame && !exit_frame; 1349 const bool exclusive = top_frame && top_frame_executing;
1841 if (!inclusive_tree_) { 1350 if (tick_functions_) {
1842 // We process functions for the inclusive and exclusive trees.
1843 // Only tick the function for the exclusive tree.
1844 function->Tick(exclusive, exclusive ? -1 : inclusive_serial); 1351 function->Tick(exclusive, exclusive ? -1 : inclusive_serial);
1845 } 1352 }
1846 function->AddCodeObjectIndex(code_index); 1353 function->AddProfileCode(code_index);
1847 current = current->GetChild(function->index()); 1354 current = current->GetChild(function->table_index());
1848 current->AddCodeObjectIndex(code_index); 1355 current->AddCodeObjectIndex(code_index);
1849 if (top_frame) { 1356 if (top_frame) {
1850 if (!exit_frame || vm_tags_emitted()) { 1357 if (top_frame_executing || vm_tags_emitted()) {
1851 // Only tick if this isn't an exit frame or VM tags are emitted. 1358 // Only tick if this function is using CPU time or VM tags are emitted.
1852 current->Tick(); 1359 current->Tick();
1853 } 1360 }
1854 } else { 1361 } else {
1855 current->Tick(); 1362 current->Tick();
1856 } 1363 }
1857 return current; 1364 return current;
1858 } 1365 }
1859 1366
1860 ProfileFunctionTrieNode* exclusive_root_; 1367 // Tick the truncated tag's inclusive tick count.
1861 ProfileFunctionTrieNode* inclusive_root_; 1368 void InclusiveTickTruncatedTag() {
1862 ProfileFunctionTable* function_table_; 1369 ProfileCodeTable* tag_table = profile_->tag_code_;
1863 bool inclusive_tree_; 1370 intptr_t index = tag_table->FindCodeIndexForPC(VMTag::kTruncatedTagId);
1864 }; 1371 ASSERT(index >= 0);
1372 ProfileCode* code = tag_table->At(index);
1373 code->IncInclusiveTicks();
1374 ASSERT(code != NULL);
1375 ProfileFunction* function = code->function();
1376 function->IncInclusiveTicks();
1377 }
1865 1378
1866 1379
1867 class CodeRegionTrieNode : public ZoneAllocated { 1380 // Tag append functions are overloaded for |ProfileCodeTrieNode| and
1868 public: 1381 // |ProfileFunctionTrieNode| types.
1869 explicit CodeRegionTrieNode(intptr_t code_region_index) 1382
1870 : code_region_index_(code_region_index), 1383 // ProfileCodeTrieNode
1871 count_(0), 1384 ProfileCodeTrieNode* AppendUserTag(uword user_tag,
1872 children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) { 1385 ProfileCodeTrieNode* current) {
1386 intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag);
1387 if (user_tag_index >= 0) {
1388 current = current->GetChild(user_tag_index);
1389 current->Tick();
1390 }
1391 return current;
1873 } 1392 }
1874 1393
1875 void Tick() { 1394 ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current) {
1876 ASSERT(code_region_index_ >= 0); 1395 intptr_t truncated_tag_index =
1877 count_++; 1396 GetProfileCodeTagIndex(VMTag::kTruncatedTagId);
1397 ASSERT(truncated_tag_index >= 0);
1398 current = current->GetChild(truncated_tag_index);
1399 current->Tick();
1400 return current;
1878 } 1401 }
1879 1402
1880 intptr_t count() const { 1403 ProfileCodeTrieNode* AppendVMTag(uword vm_tag,
1881 ASSERT(code_region_index_ >= 0); 1404 ProfileCodeTrieNode* current) {
1882 return count_; 1405 if (VMTag::IsNativeEntryTag(vm_tag)) {
1883 } 1406 // Insert a dummy kNativeTagId node.
1884 1407 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId);
1885 intptr_t code_region_index() const { 1408 current = current->GetChild(tag_index);
1886 return code_region_index_; 1409 // Give the tag a tick.
1887 } 1410 current->Tick();
1888 1411 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
1889 ZoneGrowableArray<CodeRegionTrieNode*>& children() const { 1412 // Insert a dummy kRuntimeTagId node.
1890 return *children_; 1413 intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId);
1891 } 1414 current = current->GetChild(tag_index);
1892 1415 // Give the tag a tick.
1893 CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) { 1416 current->Tick();
1894 const intptr_t length = children_->length();
1895 intptr_t i = 0;
1896 while (i < length) {
1897 CodeRegionTrieNode* child = (*children_)[i];
1898 if (child->code_region_index() == child_code_region_index) {
1899 return child;
1900 }
1901 if (child->code_region_index() > child_code_region_index) {
1902 break;
1903 }
1904 i++;
1905 }
1906 // Add new CodeRegion, sorted by CodeRegionTable index.
1907 CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index);
1908 if (i < length) {
1909 // Insert at i.
1910 children_->InsertAt(i, child);
1911 } else { 1417 } else {
1912 // Add to end. 1418 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
1913 children_->Add(child); 1419 current = current->GetChild(tag_index);
1914 }
1915 return child;
1916 }
1917
1918 // This should only be called after the trie is completely built.
1919 void SortByCount() {
1920 children_->Sort(CodeRegionTrieNodeCompare);
1921 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
1922 intptr_t child_count = kids.length();
1923 // Recurse.
1924 for (intptr_t i = 0; i < child_count; i++) {
1925 kids[i]->SortByCount();
1926 }
1927 }
1928
1929 void PrintToJSONArray(JSONArray* array) const {
1930 ASSERT(array != NULL);
1931 // Write CodeRegion index.
1932 array->AddValue(code_region_index_);
1933 // Write count.
1934 array->AddValue(count_);
1935 // Write number of children.
1936 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children();
1937 intptr_t child_count = kids.length();
1938 array->AddValue(child_count);
1939 // Recurse.
1940 for (intptr_t i = 0; i < child_count; i++) {
1941 kids[i]->PrintToJSONArray(array);
1942 }
1943 }
1944
1945 private:
1946 static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a,
1947 CodeRegionTrieNode* const* b) {
1948 ASSERT(a != NULL);
1949 ASSERT(b != NULL);
1950 return (*b)->count() - (*a)->count();
1951 }
1952
1953 const intptr_t code_region_index_;
1954 intptr_t count_;
1955 ZoneGrowableArray<CodeRegionTrieNode*>* children_;
1956 };
1957
1958
1959 class CodeRegionTrieBuilder : public TrieBuilder {
1960 public:
1961 CodeRegionTrieBuilder(Isolate* isolate,
1962 CodeRegionTable* live_code_table,
1963 CodeRegionTable* dead_code_table,
1964 CodeRegionTable* tag_code_table)
1965 : TrieBuilder(live_code_table, dead_code_table, tag_code_table) {
1966 set_tag_order(ProfilerService::kUserVM);
1967
1968 // Verify that the truncated tag exists.
1969 ASSERT(tag_code_table_->FindIndex(VMTag::kTruncatedTagId) >= 0);
1970
1971 // Verify that the root tag exists.
1972 intptr_t root_index = tag_code_table_->FindIndex(VMTag::kRootTagId);
1973 ASSERT(root_index >= 0);
1974 CodeRegion* region = tag_code_table_->At(root_index);
1975 ASSERT(region != NULL);
1976
1977 exclusive_root_ = new CodeRegionTrieNode(region->code_table_index());
1978 inclusive_root_ = new CodeRegionTrieNode(region->code_table_index());
1979 }
1980
1981 void Build(ProcessedSampleBuffer* buffer) {
1982 for (intptr_t i = 0; i < buffer->length(); i++) {
1983 ProcessedSample* sample = buffer->At(i);
1984 VisitSample(sample);
1985 }
1986 }
1987
1988 CodeRegionTrieNode* inclusive_root() const {
1989 return inclusive_root_;
1990 }
1991
1992 CodeRegionTrieNode* exclusive_root() const {
1993 return exclusive_root_;
1994 }
1995
1996 private:
1997 void VisitSample(ProcessedSample* sample) {
1998 ProcessSampleExclusive(sample);
1999 ProcessSampleInclusive(sample);
2000 }
2001
2002 void ProcessSampleInclusive(ProcessedSample* sample) {
2003 // Give the root a tick.
2004 inclusive_root_->Tick();
2005 CodeRegionTrieNode* current = inclusive_root_;
2006 current = AppendTags(sample, current);
2007 if (sample->truncated()) {
2008 current = AppendTruncatedTag(current);
2009 }
2010 // Walk the sampled PCs.
2011 for (intptr_t i = sample->length() - 1; i >= 0; i--) {
2012 ASSERT(sample->At(i) != 0);
2013 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
2014 if (index < 0) {
2015 continue;
2016 }
2017 current = current->GetChild(index);
2018 current->Tick();
2019 }
2020 }
2021
2022 void ProcessSampleExclusive(ProcessedSample* sample) {
2023 // Give the root a tick.
2024 exclusive_root_->Tick();
2025 CodeRegionTrieNode* current = exclusive_root_;
2026 current = AppendTags(sample, current);
2027 // Walk the sampled PCs.
2028 for (intptr_t i = 0; i < sample->length(); i++) {
2029 ASSERT(sample->At(i) != 0);
2030 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp());
2031 if (index < 0) {
2032 continue;
2033 }
2034 current = current->GetChild(index);
2035 if (i == 0) {
2036 // Executing PC.
2037 if (!sample->first_frame_executing() || vm_tags_emitted()) {
2038 // Only tick if this isn't an exit frame or VM tags are emitted.
2039 current->Tick();
2040 }
2041 } else {
2042 // Caller PCs.
2043 current->Tick();
2044 }
2045 }
2046 if (sample->truncated()) {
2047 current = AppendTruncatedTag(current);
2048 }
2049 }
2050
2051 CodeRegionTrieNode* AppendUserTag(ProcessedSample* sample,
2052 CodeRegionTrieNode* current) {
2053 intptr_t user_tag_index = FindTagIndex(sample->user_tag());
2054 if (user_tag_index >= 0) {
2055 current = current->GetChild(user_tag_index);
2056 // Give the tag a tick. 1420 // Give the tag a tick.
2057 current->Tick(); 1421 current->Tick();
2058 } 1422 }
2059 return current; 1423 return current;
2060 } 1424 }
2061 1425
2062 CodeRegionTrieNode* AppendTruncatedTag(CodeRegionTrieNode* current) { 1426 ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
2063 intptr_t truncated_tag_index = FindTagIndex(VMTag::kTruncatedTagId); 1427 uword vm_tag, ProfileCodeTrieNode* current) {
1428 // Only Native and Runtime entries have a second VM tag.
1429 if (!VMTag::IsNativeEntryTag(vm_tag) &&
1430 !VMTag::IsRuntimeEntryTag(vm_tag)) {
1431 return current;
1432 }
1433 intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
1434 current = current->GetChild(tag_index);
1435 // Give the tag a tick.
1436 current->Tick();
1437 return current;
1438 }
1439
1440 ProfileCodeTrieNode* AppendVMTags(uword vm_tag,
1441 ProfileCodeTrieNode* current) {
1442 current = AppendVMTag(vm_tag, current);
1443 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
1444 return current;
1445 }
1446
1447 ProfileCodeTrieNode* AppendTags(uword vm_tag,
1448 uword user_tag,
1449 ProfileCodeTrieNode* current) {
1450 // None.
1451 if (tag_order() == Profile::kNoTags) {
1452 return current;
1453 }
1454 // User first.
1455 if ((tag_order() == Profile::kUserVM) ||
1456 (tag_order() == Profile::kUser)) {
1457 current = AppendUserTag(user_tag, current);
1458 // Only user.
1459 if (tag_order() == Profile::kUser) {
1460 return current;
1461 }
1462 return AppendVMTags(vm_tag, current);
1463 }
1464 // VM first.
1465 ASSERT((tag_order() == Profile::kVMUser) ||
1466 (tag_order() == Profile::kVM));
1467 current = AppendVMTags(vm_tag, current);
1468 // Only VM.
1469 if (tag_order() == Profile::kVM) {
1470 return current;
1471 }
1472 return AppendUserTag(user_tag, current);
1473 }
1474
1475 // ProfileFunctionTrieNode
1476 ProfileFunctionTrieNode* AppendUserTag(uword user_tag,
1477 ProfileFunctionTrieNode* current) {
1478 intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag);
1479 if (user_tag_index >= 0) {
1480 current = current->GetChild(user_tag_index);
1481 current->Tick();
1482 }
1483 return current;
1484 }
1485
1486 ProfileFunctionTrieNode* AppendTruncatedTag(
1487 ProfileFunctionTrieNode* current) {
1488 intptr_t truncated_tag_index =
1489 GetProfileFunctionTagIndex(VMTag::kTruncatedTagId);
2064 ASSERT(truncated_tag_index >= 0); 1490 ASSERT(truncated_tag_index >= 0);
2065 current = current->GetChild(truncated_tag_index); 1491 current = current->GetChild(truncated_tag_index);
2066 current->Tick(); 1492 current->Tick();
2067 return current; 1493 return current;
2068 } 1494 }
2069 1495
2070 CodeRegionTrieNode* AppendVMTag(ProcessedSample* sample, 1496 ProfileFunctionTrieNode* AppendVMTag(uword vm_tag,
2071 CodeRegionTrieNode* current) { 1497 ProfileFunctionTrieNode* current) {
2072 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { 1498 if (VMTag::IsNativeEntryTag(vm_tag)) {
2073 // Insert a dummy kNativeTagId node. 1499 // Insert a dummy kNativeTagId node.
2074 intptr_t tag_index = FindTagIndex(VMTag::kNativeTagId); 1500 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId);
2075 current = current->GetChild(tag_index); 1501 current = current->GetChild(tag_index);
2076 // Give the tag a tick. 1502 // Give the tag a tick.
2077 current->Tick(); 1503 current->Tick();
2078 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 1504 } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
2079 // Insert a dummy kRuntimeTagId node. 1505 // Insert a dummy kRuntimeTagId node.
2080 intptr_t tag_index = FindTagIndex(VMTag::kRuntimeTagId); 1506 intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId);
2081 current = current->GetChild(tag_index); 1507 current = current->GetChild(tag_index);
2082 // Give the tag a tick. 1508 // Give the tag a tick.
2083 current->Tick(); 1509 current->Tick();
2084 } else { 1510 } else {
2085 intptr_t tag_index = FindTagIndex(sample->vm_tag()); 1511 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
2086 current = current->GetChild(tag_index); 1512 current = current->GetChild(tag_index);
2087 // Give the tag a tick. 1513 // Give the tag a tick.
2088 current->Tick(); 1514 current->Tick();
2089 } 1515 }
2090 return current; 1516 return current;
2091 } 1517 }
2092 1518
2093 CodeRegionTrieNode* AppendSpecificNativeRuntimeEntryVMTag( 1519 ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
2094 ProcessedSample* sample, CodeRegionTrieNode* current) { 1520 uword vm_tag, ProfileFunctionTrieNode* current) {
2095 // Only Native and Runtime entries have a second VM tag. 1521 // Only Native and Runtime entries have a second VM tag.
2096 if (!VMTag::IsNativeEntryTag(sample->vm_tag()) && 1522 if (!VMTag::IsNativeEntryTag(vm_tag) &&
2097 !VMTag::IsRuntimeEntryTag(sample->vm_tag())) { 1523 !VMTag::IsRuntimeEntryTag(vm_tag)) {
2098 return current; 1524 return current;
2099 } 1525 }
2100 intptr_t tag_index = FindTagIndex(sample->vm_tag()); 1526 intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
2101 current = current->GetChild(tag_index); 1527 current = current->GetChild(tag_index);
2102 // Give the tag a tick. 1528 // Give the tag a tick.
2103 current->Tick(); 1529 current->Tick();
2104 return current; 1530 return current;
2105 } 1531 }
2106 1532
2107 CodeRegionTrieNode* AppendVMTags(ProcessedSample* sample, 1533 ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
2108 CodeRegionTrieNode* current) { 1534 ProfileFunctionTrieNode* current) {
2109 current = AppendVMTag(sample, current); 1535 current = AppendVMTag(vm_tag, current);
2110 current = AppendSpecificNativeRuntimeEntryVMTag(sample, current); 1536 current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
2111 return current; 1537 return current;
2112 } 1538 }
2113 1539
2114 CodeRegionTrieNode* AppendTags(ProcessedSample* sample, 1540 ProfileFunctionTrieNode* AppendTags(uword vm_tag,
2115 CodeRegionTrieNode* current) { 1541 uword user_tag,
1542 ProfileFunctionTrieNode* current) {
2116 // None. 1543 // None.
2117 if (tag_order() == ProfilerService::kNoTags) { 1544 if (tag_order() == Profile::kNoTags) {
2118 return current; 1545 return current;
2119 } 1546 }
2120 // User first. 1547 // User first.
2121 if ((tag_order() == ProfilerService::kUserVM) || 1548 if ((tag_order() == Profile::kUserVM) ||
2122 (tag_order() == ProfilerService::kUser)) { 1549 (tag_order() == Profile::kUser)) {
2123 current = AppendUserTag(sample, current); 1550 current = AppendUserTag(user_tag, current);
2124 // Only user. 1551 // Only user.
2125 if (tag_order() == ProfilerService::kUser) { 1552 if (tag_order() == Profile::kUser) {
2126 return current; 1553 return current;
2127 } 1554 }
2128 return AppendVMTags(sample, current); 1555 return AppendVMTags(vm_tag, current);
2129 } 1556 }
2130 // VM first. 1557 // VM first.
2131 ASSERT((tag_order() == ProfilerService::kVMUser) || 1558 ASSERT((tag_order() == Profile::kVMUser) ||
2132 (tag_order() == ProfilerService::kVM)); 1559 (tag_order() == Profile::kVM));
2133 current = AppendVMTags(sample, current); 1560 current = AppendVMTags(vm_tag, current);
2134 // Only VM. 1561 // Only VM.
2135 if (tag_order() == ProfilerService::kVM) { 1562 if (tag_order() == Profile::kVM) {
2136 return current; 1563 return current;
2137 } 1564 }
2138 return AppendUserTag(sample, current); 1565 return AppendUserTag(user_tag, current);
2139 } 1566 }
2140 1567
2141 CodeRegionTrieNode* exclusive_root_; 1568 intptr_t GetProfileCodeTagIndex(uword tag) {
2142 CodeRegionTrieNode* inclusive_root_; 1569 ProfileCodeTable* tag_table = profile_->tag_code_;
1570 intptr_t index = tag_table->FindCodeIndexForPC(tag);
1571 ASSERT(index >= 0);
1572 ProfileCode* code = tag_table->At(index);
1573 ASSERT(code != NULL);
1574 return code->code_table_index();
1575 }
1576
1577 intptr_t GetProfileFunctionTagIndex(uword tag) {
1578 ProfileCodeTable* tag_table = profile_->tag_code_;
1579 intptr_t index = tag_table->FindCodeIndexForPC(tag);
1580 ASSERT(index >= 0);
1581 ProfileCode* code = tag_table->At(index);
1582 ASSERT(code != NULL);
1583 ProfileFunction* function = code->function();
1584 ASSERT(function != NULL);
1585 return function->table_index();
1586 }
1587
1588 intptr_t GetProfileCodeIndex(uword pc, int64_t timestamp) {
1589 return GetProfileCode(pc, timestamp)->code_table_index();
1590 }
1591
1592 ProfileCode* GetProfileCode(uword pc, int64_t timestamp) {
1593 ProfileCodeTable* live_table = profile_->live_code_;
1594 ProfileCodeTable* dead_table = profile_->dead_code_;
1595
1596 intptr_t index = live_table->FindCodeIndexForPC(pc);
1597 ProfileCode* code = NULL;
1598 if (index < 0) {
1599 index = dead_table->FindCodeIndexForPC(pc);
1600 ASSERT(index >= 0);
1601 code = dead_table->At(index);
1602 } else {
1603 code = live_table->At(index);
1604 ASSERT(code != NULL);
1605 if (code->compile_timestamp() > timestamp) {
1606 // Code is newer than sample. Fall back to dead code table.
1607 index = dead_table->FindCodeIndexForPC(pc);
1608 ASSERT(index >= 0);
1609 code = dead_table->At(index);
1610 }
1611 }
1612
1613 ASSERT(code != NULL);
1614 ASSERT(code->Contains(pc));
1615 ASSERT(code->compile_timestamp() <= timestamp);
1616 return code;
1617 }
1618
1619 void RegisterProfileCodeTag(uword tag) {
1620 if (tag == 0) {
1621 // No tag.
1622 return;
1623 }
1624 ProfileCodeTable* tag_table = profile_->tag_code_;
1625 intptr_t index = tag_table->FindCodeIndexForPC(tag);
1626 if (index >= 0) {
1627 // Already created.
1628 return;
1629 }
1630 ProfileCode* code = new ProfileCode(ProfileCode::kTagCode,
1631 tag,
1632 tag + 1,
1633 0,
1634 null_code_);
1635 index = tag_table->InsertCode(code);
1636 ASSERT(index >= 0);
1637 }
1638
1639 ProfileCode* CreateProfileCodeReused(uword pc) {
1640 ProfileCode* code = new ProfileCode(ProfileCode::kReusedCode,
1641 pc,
1642 pc + 1,
1643 0,
1644 null_code_);
1645 return code;
1646 }
1647
1648 ProfileCode* CreateProfileCode(uword pc) {
1649 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
1650 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
1651 Code& code = Code::Handle(isolate_);
1652
1653 // Check current isolate for pc.
1654 if (isolate_->heap()->CodeContains(pc)) {
1655 code ^= Code::LookupCode(pc);
1656 if (!code.IsNull()) {
1657 deoptimized_code_->Add(code);
1658 return new ProfileCode(ProfileCode::kDartCode,
1659 code.EntryPoint(),
1660 code.EntryPoint() + code.Size(),
1661 code.compile_timestamp(),
1662 code);
1663 }
1664 return new ProfileCode(ProfileCode::kCollectedCode,
1665 pc,
1666 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1667 0,
1668 code);
1669 }
1670
1671 // Check VM isolate for pc.
1672 if (vm_isolate_->heap()->CodeContains(pc)) {
1673 code ^= Code::LookupCodeInVmIsolate(pc);
1674 if (!code.IsNull()) {
1675 return new ProfileCode(ProfileCode::kDartCode,
1676 code.EntryPoint(),
1677 code.EntryPoint() + code.Size(),
1678 code.compile_timestamp(),
1679 code);
1680 }
1681 return new ProfileCode(ProfileCode::kCollectedCode,
1682 pc,
1683 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
1684 0,
1685 code);
1686 }
1687
1688 // Check NativeSymbolResolver for pc.
1689 uintptr_t native_start = 0;
1690 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
1691 &native_start);
1692 if (native_name == NULL) {
1693 // No native name found.
1694 return new ProfileCode(ProfileCode::kNativeCode,
1695 pc,
1696 pc + 1,
1697 0,
1698 code);
1699 }
1700 ASSERT(pc >= native_start);
1701 ProfileCode* profile_code =
1702 new ProfileCode(ProfileCode::kNativeCode,
1703 native_start,
1704 pc + 1,
1705 0,
1706 code);
1707 profile_code->SetName(native_name);
1708 free(native_name);
1709 return profile_code;
1710 }
1711
1712 ProfileCode* RegisterProfileCode(uword pc, int64_t timestamp) {
1713 ProfileCodeTable* live_table = profile_->live_code_;
1714 ProfileCodeTable* dead_table = profile_->dead_code_;
1715
1716 ProfileCode* code = live_table->FindCodeForPC(pc);
1717 if (code == NULL) {
1718 // Code not found.
1719 intptr_t index = live_table->InsertCode(CreateProfileCode(pc));
1720 ASSERT(index >= 0);
1721 code = live_table->At(index);
1722 if (code->compile_timestamp() <= timestamp) {
1723 // Code was compiled before sample was taken.
1724 return code;
1725 }
1726 // Code was compiled after the sample was taken. Insert code object into
1727 // the dead code table.
1728 index = dead_table->InsertCode(CreateProfileCodeReused(pc));
1729 ASSERT(index >= 0);
1730 return dead_table->At(index);
1731 }
1732 // Existing code found.
1733 if (code->compile_timestamp() <= timestamp) {
1734 // Code was compiled before sample was taken.
1735 return code;
1736 }
1737 // Code was compiled after the sample was taken. Check if we have an entry
1738 // in the dead code table.
1739 code = dead_table->FindCodeForPC(pc);
1740 if (code != NULL) {
1741 return code;
1742 }
1743 // Create a new dead code entry.
1744 intptr_t index = dead_table->InsertCode(CreateProfileCodeReused(pc));
1745 ASSERT(index >= 0);
1746 return dead_table->At(index);
1747 }
1748
1749 Profile::TagOrder tag_order() const {
1750 return tag_order_;
1751 }
1752
1753 bool vm_tags_emitted() const {
1754 return (tag_order_ == Profile::kUserVM) ||
1755 (tag_order_ == Profile::kVMUser) ||
1756 (tag_order_ == Profile::kVM);
1757 }
1758
1759 Isolate* isolate_;
1760 Isolate* vm_isolate_;
1761 SampleFilter* filter_;
1762 Profile::TagOrder tag_order_;
1763 Profile* profile_;
1764 DeoptimizedCodeSet* deoptimized_code_;
1765 const Code& null_code_;
1766 const Function& null_function_;
1767 bool tick_functions_;
1768
1769 ProcessedSampleBuffer* samples_;
2143 }; 1770 };
2144 1771
2145 1772
1773 Profile::Profile(Isolate* isolate)
1774 : isolate_(isolate),
1775 live_code_(NULL),
1776 dead_code_(NULL),
1777 tag_code_(NULL),
1778 functions_(NULL),
1779 dead_code_index_offset_(-1),
1780 tag_code_index_offset_(-1),
1781 min_time_(kMaxInt64),
1782 max_time_(0) {
1783 ASSERT(isolate_ != NULL);
1784 for (intptr_t i = 0; i < kNumTrieKinds; i++) {
1785 roots_[i] = NULL;
1786 }
1787 }
1788
1789
1790 void Profile::Build(SampleFilter* filter, TagOrder tag_order) {
1791 ProfileBuilder builder(isolate_, filter, tag_order, this);
1792 builder.Build();
1793 }
1794
1795
1796 ProfileFunction* Profile::GetFunction(intptr_t index) {
1797 ASSERT(functions_ != NULL);
1798 return functions_->At(index);
1799 }
1800
1801
1802 ProfileCode* Profile::GetCode(intptr_t index) {
1803 ASSERT(live_code_ != NULL);
1804 ASSERT(dead_code_ != NULL);
1805 ASSERT(tag_code_ != NULL);
1806 ASSERT(dead_code_index_offset_ >= 0);
1807 ASSERT(tag_code_index_offset_ >= 0);
1808
1809 // Code indexes span three arrays.
1810 // 0 ... |live_code|
1811 // |live_code| ... |dead_code|
1812 // |dead_code| ... |tag_code|
1813
1814 if (index < dead_code_index_offset_) {
1815 return live_code_->At(index);
1816 }
1817
1818 if (index < tag_code_index_offset_) {
1819 index -= dead_code_index_offset_;
1820 return dead_code_->At(index);
1821 }
1822
1823 index -= tag_code_index_offset_;
1824 return tag_code_->At(index);
1825 }
1826
1827
1828 ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) {
1829 return roots_[static_cast<intptr_t>(trie_kind)];
1830 }
1831
1832
1833 void Profile::PrintJSON(JSONStream* stream) {
1834 ScopeTimer sw("Profile::PrintJSON", FLAG_trace_profiler);
1835 JSONObject obj(stream);
1836 obj.AddProperty("type", "_CpuProfile");
1837 obj.AddProperty("samplePeriod",
1838 static_cast<intptr_t>(FLAG_profile_period));
1839 obj.AddProperty("stackDepth",
1840 static_cast<intptr_t>(FLAG_profile_depth));
1841 obj.AddProperty("sampleCount", sample_count());
1842 obj.AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
1843 {
1844 JSONArray codes(&obj, "codes");
1845 for (intptr_t i = 0; i < live_code_->length(); i++) {
1846 ProfileCode* code = live_code_->At(i);
1847 ASSERT(code != NULL);
1848 code->PrintToJSONArray(&codes);
1849 }
1850 for (intptr_t i = 0; i < dead_code_->length(); i++) {
1851 ProfileCode* code = dead_code_->At(i);
1852 ASSERT(code != NULL);
1853 code->PrintToJSONArray(&codes);
1854 }
1855 for (intptr_t i = 0; i < tag_code_->length(); i++) {
1856 ProfileCode* code = tag_code_->At(i);
1857 ASSERT(code != NULL);
1858 code->PrintToJSONArray(&codes);
1859 }
1860 }
1861
1862 {
1863 JSONArray functions(&obj, "functions");
1864 for (intptr_t i = 0; i < functions_->length(); i++) {
1865 ProfileFunction* function = functions_->At(i);
1866 ASSERT(function != NULL);
1867 function->PrintToJSONArray(&functions);
1868 }
1869 }
1870 {
1871 JSONArray code_trie(&obj, "exclusiveCodeTrie");
1872 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveCode)];
1873 ASSERT(root != NULL);
1874 root->PrintToJSONArray(&code_trie);
1875 }
1876 {
1877 JSONArray code_trie(&obj, "inclusiveCodeTrie");
1878 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveCode)];
1879 ASSERT(root != NULL);
1880 root->PrintToJSONArray(&code_trie);
1881 }
1882 {
1883 JSONArray function_trie(&obj, "exclusiveFunctionTrie");
1884 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveFunction)];
1885 ASSERT(root != NULL);
1886 root->PrintToJSONArray(&function_trie);
1887 }
1888 {
1889 JSONArray function_trie(&obj, "inclusiveFunctionTrie");
1890 ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)];
1891 ASSERT(root != NULL);
1892 root->PrintToJSONArray(&function_trie);
1893 }
1894 }
1895
1896
2146 class NoAllocationSampleFilter : public SampleFilter { 1897 class NoAllocationSampleFilter : public SampleFilter {
2147 public: 1898 public:
2148 explicit NoAllocationSampleFilter(Isolate* isolate) 1899 explicit NoAllocationSampleFilter(Isolate* isolate)
2149 : SampleFilter(isolate) { 1900 : SampleFilter(isolate) {
2150 } 1901 }
2151 1902
2152 bool FilterSample(Sample* sample) { 1903 bool FilterSample(Sample* sample) {
2153 return !sample->is_allocation_sample(); 1904 return !sample->is_allocation_sample();
2154 } 1905 }
2155 }; 1906 };
2156 1907
2157 1908
2158 void ProfilerService::PrintJSON(JSONStream* stream, TagOrder tag_order) { 1909 void ProfilerService::PrintJSON(JSONStream* stream,
1910 Profile::TagOrder tag_order) {
2159 Isolate* isolate = Isolate::Current(); 1911 Isolate* isolate = Isolate::Current();
2160 // Disable profile interrupts while processing the buffer. 1912 // Disable profile interrupts while processing the buffer.
2161 Profiler::EndExecution(isolate); 1913 Profiler::EndExecution(isolate);
2162 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1914
2163 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1915 {
2164 if (profiler_data == NULL) { 1916 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
2165 stream->PrintError(kFeatureDisabled, NULL); 1917 IsolateProfilerData* profiler_data = isolate->profiler_data();
2166 return; 1918 if (profiler_data == NULL) {
1919 stream->PrintError(kFeatureDisabled, NULL);
1920 return;
1921 }
2167 } 1922 }
2168 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1923
2169 ASSERT(sample_buffer != NULL);
2170 ScopeTimer sw("ProfilerService::PrintJSON", FLAG_trace_profiler);
2171 { 1924 {
2172 StackZone zone(isolate); 1925 StackZone zone(isolate);
2173 HANDLESCOPE(isolate); 1926 HANDLESCOPE(isolate);
1927 Profile profile(isolate);
1928 NoAllocationSampleFilter filter(isolate);
1929 profile.Build(&filter, tag_order);
1930 profile.PrintJSON(stream);
1931 }
2174 1932
2175 ProcessedSampleBuffer* processed_samples = NULL;
2176 {
2177 ScopeTimer sw("BuildProcessedSampleBuffer", FLAG_trace_profiler);
2178 NoAllocationSampleFilter filter(isolate);
2179 processed_samples = sample_buffer->BuildProcessedSampleBuffer(&filter);
2180 }
2181
2182 {
2183 // Live code holds Dart, Native, and Collected CodeRegions.
2184 CodeRegionTable live_code_table;
2185 // Dead code holds Overwritten CodeRegions.
2186 CodeRegionTable dead_code_table;
2187 // Tag code holds Tag CodeRegions.
2188 CodeRegionTable tag_code_table;
2189 // Table holding all ProfileFunctions.
2190 ProfileFunctionTable function_table;
2191 // Set of deoptimized code still referenced by the profiler.
2192 DeoptimizedCodeSet* deoptimized_code = new DeoptimizedCodeSet(isolate);
2193
2194 // Build CodeRegion tables.
2195 CodeRegionTableBuilder builder(isolate,
2196 &live_code_table,
2197 &dead_code_table,
2198 &tag_code_table,
2199 deoptimized_code);
2200 {
2201 ScopeTimer sw("CodeRegionTableBuilder::Build", FLAG_trace_profiler);
2202 builder.Build(processed_samples);
2203 }
2204 intptr_t samples = processed_samples->length();
2205 intptr_t frames = builder.frames();
2206 if (FLAG_trace_profiler) {
2207 intptr_t total_live_code_objects = live_code_table.Length();
2208 intptr_t total_dead_code_objects = dead_code_table.Length();
2209 intptr_t total_tag_code_objects = tag_code_table.Length();
2210 OS::Print(
2211 "Processed %" Pd " samples with %" Pd " frames\n", samples, frames);
2212 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n",
2213 total_live_code_objects,
2214 total_dead_code_objects,
2215 total_tag_code_objects);
2216 }
2217
2218 if (FLAG_trace_profiler) {
2219 ScopeTimer sw("CodeRegionTableVerify", FLAG_trace_profiler);
2220 live_code_table.Verify();
2221 dead_code_table.Verify();
2222 tag_code_table.Verify();
2223 }
2224
2225 {
2226 ScopeTimer st("CodeRegionFunctionMapping", FLAG_trace_profiler);
2227 CodeRegionFunctionMapper mapper(isolate, &live_code_table,
2228 &dead_code_table,
2229 &tag_code_table,
2230 &function_table);
2231 mapper.Map();
2232 }
2233 if (FLAG_trace_profiler) {
2234 intptr_t total_functions = function_table.Length();
2235 OS::Print("FunctionTable: size=%" Pd "\n", total_functions);
2236 }
2237 CodeRegionTrieBuilder code_trie_builder(isolate,
2238 &live_code_table,
2239 &dead_code_table,
2240 &tag_code_table);
2241 code_trie_builder.set_tag_order(tag_order);
2242 {
2243 // Build CodeRegion trie.
2244 ScopeTimer sw("CodeRegionTrieBuilder::Build", FLAG_trace_profiler);
2245 code_trie_builder.Build(processed_samples);
2246 code_trie_builder.exclusive_root()->SortByCount();
2247 code_trie_builder.inclusive_root()->SortByCount();
2248 }
2249 if (FLAG_trace_profiler) {
2250 OS::Print("Code Trie Root Count: E: %" Pd " I: %" Pd "\n",
2251 code_trie_builder.exclusive_root()->count(),
2252 code_trie_builder.inclusive_root()->count());
2253 }
2254 ProfileFunctionTrieBuilder function_trie_builder(&live_code_table,
2255 &dead_code_table,
2256 &tag_code_table,
2257 &function_table);
2258 function_trie_builder.set_tag_order(tag_order);
2259 {
2260 // Build ProfileFunction trie.
2261 ScopeTimer sw("ProfileFunctionTrieBuilder::Build",
2262 FLAG_trace_profiler);
2263 function_trie_builder.Build(processed_samples);
2264 function_trie_builder.exclusive_root()->SortByCount();
2265 function_trie_builder.inclusive_root()->SortByCount();
2266 }
2267 if (FLAG_trace_profiler) {
2268 OS::Print("Function Trie Root Count: E: %" Pd " I: %" Pd "\n",
2269 function_trie_builder.exclusive_root()->count(),
2270 function_trie_builder.inclusive_root()->count());
2271 }
2272 {
2273 ScopeTimer sw("CpuProfileJSONStream", FLAG_trace_profiler);
2274 // Serialize to JSON.
2275 JSONObject obj(stream);
2276 obj.AddProperty("type", "_CpuProfile");
2277 obj.AddProperty("sampleCount", samples);
2278 obj.AddProperty("samplePeriod",
2279 static_cast<intptr_t>(FLAG_profile_period));
2280 obj.AddProperty("stackDepth",
2281 static_cast<intptr_t>(FLAG_profile_depth));
2282 obj.AddProperty("timeSpan",
2283 MicrosecondsToSeconds(builder.TimeDeltaMicros()));
2284 {
2285 JSONArray code_trie(&obj, "exclusiveCodeTrie");
2286 CodeRegionTrieNode* root = code_trie_builder.exclusive_root();
2287 ASSERT(root != NULL);
2288 root->PrintToJSONArray(&code_trie);
2289 }
2290 {
2291 JSONArray code_trie(&obj, "inclusiveCodeTrie");
2292 CodeRegionTrieNode* root = code_trie_builder.inclusive_root();
2293 ASSERT(root != NULL);
2294 root->PrintToJSONArray(&code_trie);
2295 }
2296 {
2297 JSONArray function_trie(&obj, "exclusiveFunctionTrie");
2298 ProfileFunctionTrieNode* root =
2299 function_trie_builder.exclusive_root();
2300 ASSERT(root != NULL);
2301 root->PrintToJSONArray(&function_trie);
2302 }
2303 {
2304 JSONArray function_trie(&obj, "inclusiveFunctionTrie");
2305 ProfileFunctionTrieNode* root =
2306 function_trie_builder.inclusive_root();
2307 ASSERT(root != NULL);
2308 root->PrintToJSONArray(&function_trie);
2309 }
2310 {
2311 JSONArray codes(&obj, "codes");
2312 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
2313 CodeRegion* region = live_code_table.At(i);
2314 ASSERT(region != NULL);
2315 region->PrintToJSONArray(&codes);
2316 }
2317 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
2318 CodeRegion* region = dead_code_table.At(i);
2319 ASSERT(region != NULL);
2320 region->PrintToJSONArray(&codes);
2321 }
2322 for (intptr_t i = 0; i < tag_code_table.Length(); i++) {
2323 CodeRegion* region = tag_code_table.At(i);
2324 ASSERT(region != NULL);
2325 region->PrintToJSONArray(&codes);
2326 }
2327 }
2328 {
2329 JSONArray functions(&obj, "functions");
2330 for (intptr_t i = 0; i < function_table.Length(); i++) {
2331 ProfileFunction* function = function_table.At(i);
2332 ASSERT(function != NULL);
2333 function->PrintToJSONArray(&functions);
2334 }
2335 }
2336 }
2337 // Update the isolates set of dead code.
2338 deoptimized_code->UpdateIsolate(isolate);
2339 }
2340 }
2341 // Enable profile interrupts. 1933 // Enable profile interrupts.
2342 Profiler::BeginExecution(isolate); 1934 Profiler::BeginExecution(isolate);
2343 } 1935 }
2344 1936
2345 1937
2346 void ProfilerService::ClearSamples() { 1938 void ProfilerService::ClearSamples() {
2347 Isolate* isolate = Isolate::Current(); 1939 Isolate* isolate = Isolate::Current();
2348 1940
2349 // Disable profile interrupts while processing the buffer. 1941 // Disable profile interrupts while processing the buffer.
2350 Profiler::EndExecution(isolate); 1942 Profiler::EndExecution(isolate);
2351 1943
2352 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1944 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
2353 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1945 IsolateProfilerData* profiler_data = isolate->profiler_data();
2354 if (profiler_data == NULL) { 1946 if (profiler_data == NULL) {
2355 return; 1947 return;
2356 } 1948 }
2357 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1949 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
2358 ASSERT(sample_buffer != NULL); 1950 ASSERT(sample_buffer != NULL);
2359 1951
2360 ClearProfileVisitor clear_profile(isolate); 1952 ClearProfileVisitor clear_profile(isolate);
2361 sample_buffer->VisitSamples(&clear_profile); 1953 sample_buffer->VisitSamples(&clear_profile);
2362 1954
2363 // Enable profile interrupts. 1955 // Enable profile interrupts.
2364 Profiler::BeginExecution(isolate); 1956 Profiler::BeginExecution(isolate);
2365 } 1957 }
2366 1958
2367 } // namespace dart 1959 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698