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

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

Issue 197803004: Add dead CodeRegionTable for tracking overwritten Dart code (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/object.cc ('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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/utils.h" 5 #include "platform/utils.h"
6 6
7 #include "vm/allocation.h" 7 #include "vm/allocation.h"
8 #include "vm/atomic.h" 8 #include "vm/atomic.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 return; 155 return;
156 } 156 }
157 if (!FLAG_profile) { 157 if (!FLAG_profile) {
158 return; 158 return;
159 } 159 }
160 ASSERT(initialized_); 160 ASSERT(initialized_);
161 ThreadInterrupter::Unregister(); 161 ThreadInterrupter::Unregister();
162 } 162 }
163 163
164 164
165 class ScopeStopwatch : public ValueObject {
166 public:
167 explicit ScopeStopwatch(const char* name) : name_(name) {
168 start_ = FLAG_trace_profiled_isolates ? OS::GetCurrentTimeMillis() : 0;
169 }
170
171 intptr_t GetElapsed() const {
172 intptr_t end = OS::GetCurrentTimeMillis();
173 ASSERT(end >= start_);
174 return end - start_;
175 }
176
177 ~ScopeStopwatch() {
178 if (FLAG_trace_profiled_isolates) {
179 intptr_t elapsed = GetElapsed();
180 OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
181 }
182 }
183
184 private:
185 const char* name_;
186 intptr_t start_;
187 };
188
189
165 struct AddressEntry { 190 struct AddressEntry {
166 uword pc; 191 uword pc;
167 intptr_t exclusive_ticks; 192 intptr_t exclusive_ticks;
168 intptr_t inclusive_ticks; 193 intptr_t inclusive_ticks;
169 194
170 void tick(bool exclusive) { 195 void tick(bool exclusive) {
171 if (exclusive) { 196 if (exclusive) {
172 exclusive_ticks++; 197 exclusive_ticks++;
173 } else { 198 } else {
174 inclusive_ticks++; 199 inclusive_ticks++;
175 } 200 }
176 } 201 }
177 }; 202 };
178 203
179 struct CallEntry { 204 struct CallEntry {
180 intptr_t code_table_index; 205 intptr_t code_table_index;
181 intptr_t count; 206 intptr_t count;
182 }; 207 };
183 208
184 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); 209 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
185 210
186 // A region of code. Each region is a kind of code (Dart, Collected, or Native). 211 // A contiguous address region that holds code. Each CodeRegion has a "kind"
212 // which describes the type of code contained inside the region. Each
213 // region covers the following interval: [start, end).
187 class CodeRegion : public ZoneAllocated { 214 class CodeRegion : public ZoneAllocated {
188 public: 215 public:
189 enum Kind { 216 enum Kind {
190 kDartCode, 217 kDartCode, // Live Dart code.
191 kCollectedCode, 218 kCollectedCode, // Dead Dart code.
192 kNativeCode 219 kNativeCode, // Native code.
220 kReusedCode, // Dead Dart code that has been reused by new kDartCode.
221 kTagCode, // A special kind of code representing a tag.
193 }; 222 };
194 223
195 CodeRegion(Kind kind, uword start, uword end) : 224 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) :
196 kind_(kind), 225 kind_(kind),
197 start_(start), 226 start_(start),
198 end_(end), 227 end_(end),
199 inclusive_ticks_(0), 228 inclusive_ticks_(0),
200 exclusive_ticks_(0), 229 exclusive_ticks_(0),
201 inclusive_tick_serial_(0), 230 inclusive_tick_serial_(0),
202 name_(NULL), 231 name_(NULL),
232 compile_timestamp_(timestamp),
233 creation_serial_(0),
203 address_table_(new ZoneGrowableArray<AddressEntry>()), 234 address_table_(new ZoneGrowableArray<AddressEntry>()),
204 callers_table_(new ZoneGrowableArray<CallEntry>()), 235 callers_table_(new ZoneGrowableArray<CallEntry>()),
205 callees_table_(new ZoneGrowableArray<CallEntry>()) { 236 callees_table_(new ZoneGrowableArray<CallEntry>()) {
206 ASSERT(start_ < end_); 237 ASSERT(start_ < end_);
207 } 238 }
208 239
209 ~CodeRegion() {
210 }
211 240
212 uword start() const { return start_; } 241 uword start() const { return start_; }
213 void set_start(uword start) { 242 void set_start(uword start) {
214 start_ = start; 243 start_ = start;
215 } 244 }
216 245
217 uword end() const { return end_; } 246 uword end() const { return end_; }
218 void set_end(uword end) { 247 void set_end(uword end) {
219 end_ = end; 248 end_ = end;
220 } 249 }
(...skipping 13 matching lines...) Expand all
234 } 263 }
235 264
236 bool overlaps(const CodeRegion* other) const { 265 bool overlaps(const CodeRegion* other) const {
237 ASSERT(other != NULL); 266 ASSERT(other != NULL);
238 return other->contains(start_) || 267 return other->contains(start_) ||
239 other->contains(end_ - 1) || 268 other->contains(end_ - 1) ||
240 contains(other->start()) || 269 contains(other->start()) ||
241 contains(other->end() - 1); 270 contains(other->end() - 1);
242 } 271 }
243 272
273 intptr_t creation_serial() const { return creation_serial_; }
274 void set_creation_serial(intptr_t serial) {
275 creation_serial_ = serial;
276 }
277 int64_t compile_timestamp() const { return compile_timestamp_; }
278 void set_compile_timestamp(int64_t timestamp) {
279 compile_timestamp_ = timestamp;
280 }
281
244 intptr_t inclusive_ticks() const { return inclusive_ticks_; } 282 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
245 void set_inclusive_ticks(intptr_t inclusive_ticks) { 283 void set_inclusive_ticks(intptr_t inclusive_ticks) {
246 inclusive_ticks_ = inclusive_ticks; 284 inclusive_ticks_ = inclusive_ticks;
247 } 285 }
248 286
249 intptr_t exclusive_ticks() const { return exclusive_ticks_; } 287 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
250 void set_exclusive_ticks(intptr_t exclusive_ticks) { 288 void set_exclusive_ticks(intptr_t exclusive_ticks) {
251 exclusive_ticks_ = exclusive_ticks; 289 exclusive_ticks_ = exclusive_ticks;
252 } 290 }
253 291
(...skipping 11 matching lines...) Expand all
265 Kind kind() const { return kind_; } 303 Kind kind() const { return kind_; }
266 304
267 static const char* KindToCString(Kind kind) { 305 static const char* KindToCString(Kind kind) {
268 switch (kind) { 306 switch (kind) {
269 case kDartCode: 307 case kDartCode:
270 return "Dart"; 308 return "Dart";
271 case kCollectedCode: 309 case kCollectedCode:
272 return "Collected"; 310 return "Collected";
273 case kNativeCode: 311 case kNativeCode:
274 return "Native"; 312 return "Native";
313 case kReusedCode:
314 return "Overwritten";
315 case kTagCode:
316 return "Tag";
275 } 317 }
276 UNREACHABLE(); 318 UNREACHABLE();
277 return NULL; 319 return NULL;
278 } 320 }
279 321
280 void DebugPrint() const { 322 void DebugPrint() const {
281 printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(), 323 OS::Print("%s [%" Px ", %" Px ") %"Pd" %"Pd64"\n",
282 name_); 324 KindToCString(kind_),
325 start(),
326 end(),
327 creation_serial_,
328 compile_timestamp_);
283 } 329 }
284 330
285 void AddTickAtAddress(uword pc, bool exclusive, intptr_t serial) { 331 void Tick(uword pc, bool exclusive, intptr_t serial) {
286 // Assert that exclusive ticks are never passed a valid serial number. 332 // Assert that exclusive ticks are never passed a valid serial number.
287 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1))); 333 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
288 if (!exclusive && (inclusive_tick_serial_ == serial)) { 334 if (!exclusive && (inclusive_tick_serial_ == serial)) {
289 // We've already given this code object an inclusive tick for this sample. 335 // We've already given this code object an inclusive tick for this sample.
290 return; 336 return;
291 } 337 }
292 // Tick the code object. 338 // Tick the code object.
293 if (exclusive) { 339 if (exclusive) {
294 exclusive_ticks_++; 340 exclusive_ticks_++;
295 } else { 341 } else {
342 inclusive_ticks_++;
296 // Mark the last serial we ticked the inclusive count. 343 // Mark the last serial we ticked the inclusive count.
297 inclusive_tick_serial_ = serial; 344 inclusive_tick_serial_ = serial;
298 inclusive_ticks_++;
299 } 345 }
300 // Tick the address entry. 346 TickAddress(pc, exclusive);
301 const intptr_t length = address_table_->length();
302 intptr_t i = 0;
303 for (; i < length; i++) {
304 AddressEntry& entry = (*address_table_)[i];
305 if (entry.pc == pc) {
306 entry.tick(exclusive);
307 return;
308 }
309 if (entry.pc > pc) {
310 break;
311 }
312 }
313 AddressEntry entry;
314 entry.pc = pc;
315 entry.exclusive_ticks = 0;
316 entry.inclusive_ticks = 0;
317 entry.tick(exclusive);
318 if (i < length) {
319 // Insert at i.
320 address_table_->InsertAt(i, entry);
321 } else {
322 // Add to end.
323 address_table_->Add(entry);
324 }
325 } 347 }
326 348
327 void AddCaller(intptr_t index) { 349 void AddCaller(intptr_t index) {
328 AddCallEntry(callers_table_, index); 350 AddCallEntry(callers_table_, index);
329 } 351 }
330 352
331 void AddCallee(intptr_t index) { 353 void AddCallee(intptr_t index) {
332 AddCallEntry(callees_table_, index); 354 AddCallEntry(callees_table_, index);
333 } 355 }
334 356
335 void PrintNativeCode(JSONObject* profile_code_obj) { 357 void PrintNativeCode(JSONObject* profile_code_obj) {
336 ASSERT(kind() == kNativeCode); 358 ASSERT(kind() == kNativeCode);
337 JSONObject obj(profile_code_obj, "code"); 359 JSONObject obj(profile_code_obj, "code");
338 obj.AddProperty("type", "@Code"); 360 obj.AddProperty("type", "@Code");
339 obj.AddProperty("kind", "Native"); 361 obj.AddProperty("kind", "Native");
340 obj.AddProperty("name", name()); 362 obj.AddProperty("name", name());
341 obj.AddProperty("user_name", name()); 363 obj.AddProperty("user_name", name());
342 obj.AddPropertyF("start", "%" Px "", start()); 364 obj.AddPropertyF("start", "%" Px "", start());
343 obj.AddPropertyF("end", "%" Px "", end()); 365 obj.AddPropertyF("end", "%" Px "", end());
344 obj.AddPropertyF("id", "code/native/%" Px "", start()); 366 obj.AddPropertyF("id", "code/native-%" Px "", start());
345 { 367 {
346 // Generate a fake function entry. 368 // Generate a fake function entry.
347 JSONObject func(&obj, "function"); 369 JSONObject func(&obj, "function");
348 func.AddProperty("type", "@Function"); 370 func.AddProperty("type", "@Function");
349 func.AddPropertyF("id", "native/functions/%" Pd "", start()); 371 func.AddPropertyF("id", "functions/native-%" Px "", start());
350 func.AddProperty("name", name()); 372 func.AddProperty("name", name());
351 func.AddProperty("user_name", name()); 373 func.AddProperty("user_name", name());
352 func.AddProperty("kind", "Native"); 374 func.AddProperty("kind", "Native");
353 } 375 }
354 } 376 }
355 377
356 void PrintCollectedCode(JSONObject* profile_code_obj) { 378 void PrintCollectedCode(JSONObject* profile_code_obj) {
357 ASSERT(kind() == kCollectedCode); 379 ASSERT(kind() == kCollectedCode);
358 JSONObject obj(profile_code_obj, "code"); 380 JSONObject obj(profile_code_obj, "code");
359 obj.AddProperty("type", "@Code"); 381 obj.AddProperty("type", "@Code");
360 obj.AddProperty("kind", "Collected"); 382 obj.AddProperty("kind", "Collected");
361 obj.AddProperty("name", name()); 383 obj.AddProperty("name", name());
362 obj.AddProperty("user_name", name()); 384 obj.AddProperty("user_name", name());
363 obj.AddPropertyF("start", "%" Px "", start()); 385 obj.AddPropertyF("start", "%" Px "", start());
364 obj.AddPropertyF("end", "%" Px "", end()); 386 obj.AddPropertyF("end", "%" Px "", end());
365 obj.AddPropertyF("id", "code/collected/%" Px "", start()); 387 obj.AddPropertyF("id", "code/collected-%" Px "", start());
366 { 388 {
367 // Generate a fake function entry. 389 // Generate a fake function entry.
368 JSONObject func(&obj, "function"); 390 JSONObject func(&obj, "function");
369 func.AddProperty("type", "@Function"); 391 func.AddProperty("type", "@Function");
370 func.AddPropertyF("id", "collected/functions/%" Pd "", start()); 392 obj.AddPropertyF("id", "functions/collected-%" Px "", start());
371 func.AddProperty("name", name()); 393 func.AddProperty("name", name());
372 func.AddProperty("user_name", name()); 394 func.AddProperty("user_name", name());
373 func.AddProperty("kind", "Collected"); 395 func.AddProperty("kind", "Collected");
374 } 396 }
375 } 397 }
376 398
399 void PrintOverwrittenCode(JSONObject* profile_code_obj) {
400 ASSERT(kind() == kReusedCode);
401 JSONObject obj(profile_code_obj, "code");
402 obj.AddProperty("type", "@Code");
403 obj.AddProperty("kind", "Reused");
404 obj.AddProperty("name", name());
405 obj.AddProperty("user_name", name());
406 obj.AddPropertyF("start", "%" Px "", start());
407 obj.AddPropertyF("end", "%" Px "", end());
408 obj.AddPropertyF("id", "code/reused-%" Px "", start());
409 {
410 // Generate a fake function entry.
411 JSONObject func(&obj, "function");
412 func.AddProperty("type", "@Function");
413 obj.AddPropertyF("id", "functions/reused-%" Px "", start());
414 func.AddProperty("name", name());
415 func.AddProperty("user_name", name());
416 func.AddProperty("kind", "Reused");
417 }
418 }
419
377 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) { 420 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) {
378 JSONObject obj(events); 421 JSONObject obj(events);
379 obj.AddProperty("type", "ProfileCode"); 422 obj.AddProperty("type", "CodeRegion");
380 obj.AddProperty("kind", KindToCString(kind())); 423 obj.AddProperty("kind", KindToCString(kind()));
381 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); 424 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks());
382 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); 425 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks());
383 if (kind() == kDartCode) { 426 if (kind() == kDartCode) {
384 // Look up code in Dart heap. 427 // Look up code in Dart heap.
385 Code& code = Code::Handle(); 428 Code& code = Code::Handle(isolate);
386 code ^= Code::LookupCode(start()); 429 code ^= Code::LookupCode(start());
387 if (code.IsNull()) { 430 if (code.IsNull()) {
388 // Code is a stub in the Vm isolate. 431 // Code is a stub in the Vm isolate.
389 code ^= Code::LookupCodeInVmIsolate(start()); 432 code ^= Code::LookupCodeInVmIsolate(start());
390 } 433 }
391 ASSERT(!code.IsNull()); 434 ASSERT(!code.IsNull());
392 obj.AddProperty("code", code, !full); 435 obj.AddProperty("code", code, !full);
393 } else if (kind() == kCollectedCode) { 436 } else if (kind() == kCollectedCode) {
394 if (name() == NULL) { 437 if (name() == NULL) {
395 // Lazily set generated name. 438 // Lazily set generated name.
396 GenerateAndSetSymbolName("Collected"); 439 GenerateAndSetSymbolName("[Collected]");
397 } 440 }
398 PrintCollectedCode(&obj); 441 PrintCollectedCode(&obj);
442 } else if (kind() == kReusedCode) {
443 if (name() == NULL) {
444 // Lazily set generated name.
445 GenerateAndSetSymbolName("[Reused]");
446 }
447 PrintOverwrittenCode(&obj);
399 } else { 448 } else {
400 ASSERT(kind() == kNativeCode); 449 ASSERT(kind() == kNativeCode);
401 if (name() == NULL) { 450 if (name() == NULL) {
402 // Lazily set generated name. 451 // Lazily set generated name.
403 GenerateAndSetSymbolName("Native"); 452 GenerateAndSetSymbolName("[Native]");
404 } 453 }
405 PrintNativeCode(&obj); 454 PrintNativeCode(&obj);
406 } 455 }
407 { 456 {
408 JSONArray ticks(&obj, "ticks"); 457 JSONArray ticks(&obj, "ticks");
409 for (intptr_t i = 0; i < address_table_->length(); i++) { 458 for (intptr_t i = 0; i < address_table_->length(); i++) {
410 const AddressEntry& entry = (*address_table_)[i]; 459 const AddressEntry& entry = (*address_table_)[i];
411 ticks.AddValueF("%" Px "", entry.pc); 460 ticks.AddValueF("%" Px "", entry.pc);
412 ticks.AddValueF("%" Pd "", entry.exclusive_ticks); 461 ticks.AddValueF("%" Pd "", entry.exclusive_ticks);
413 ticks.AddValueF("%" Pd "", entry.inclusive_ticks); 462 ticks.AddValueF("%" Pd "", entry.inclusive_ticks);
(...skipping 11 matching lines...) Expand all
425 JSONArray callees(&obj, "callees"); 474 JSONArray callees(&obj, "callees");
426 for (intptr_t i = 0; i < callees_table_->length(); i++) { 475 for (intptr_t i = 0; i < callees_table_->length(); i++) {
427 const CallEntry& entry = (*callees_table_)[i]; 476 const CallEntry& entry = (*callees_table_)[i];
428 callees.AddValueF("%" Pd "", entry.code_table_index); 477 callees.AddValueF("%" Pd "", entry.code_table_index);
429 callees.AddValueF("%" Pd "", entry.count); 478 callees.AddValueF("%" Pd "", entry.count);
430 } 479 }
431 } 480 }
432 } 481 }
433 482
434 private: 483 private:
484 void TickAddress(uword pc, bool exclusive) {
485 const intptr_t length = address_table_->length();
486 intptr_t i = 0;
487 for (; i < length; i++) {
488 AddressEntry& entry = (*address_table_)[i];
489 if (entry.pc == pc) {
490 // Tick the address entry.
491 entry.tick(exclusive);
492 return;
493 }
494 if (entry.pc > pc) {
495 break;
496 }
497 }
498 // New address, add entry.
499 AddressEntry entry;
500 entry.pc = pc;
501 entry.exclusive_ticks = 0;
502 entry.inclusive_ticks = 0;
503 entry.tick(exclusive);
504 if (i < length) {
505 // Insert at i.
506 address_table_->InsertAt(i, entry);
507 } else {
508 // Add to end.
509 address_table_->Add(entry);
510 }
511 }
512
513
435 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) { 514 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) {
436 const intptr_t length = table->length(); 515 const intptr_t length = table->length();
437 intptr_t i = 0; 516 intptr_t i = 0;
438 for (; i < length; i++) { 517 for (; i < length; i++) {
439 CallEntry& entry = (*table)[i]; 518 CallEntry& entry = (*table)[i];
440 if (entry.code_table_index == index) { 519 if (entry.code_table_index == index) {
441 entry.count++; 520 entry.count++;
442 return; 521 return;
443 } 522 }
444 if (entry.code_table_index > index) { 523 if (entry.code_table_index > index) {
(...skipping 11 matching lines...) Expand all
456 } 535 }
457 536
458 void GenerateAndSetSymbolName(const char* prefix) { 537 void GenerateAndSetSymbolName(const char* prefix) {
459 const intptr_t kBuffSize = 512; 538 const intptr_t kBuffSize = 512;
460 char buff[kBuffSize]; 539 char buff[kBuffSize];
461 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", 540 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
462 prefix, start(), end()); 541 prefix, start(), end());
463 SetName(buff); 542 SetName(buff);
464 } 543 }
465 544
466 Kind kind_; 545 // CodeRegion kind.
546 const Kind kind_;
547 // CodeRegion start address.
467 uword start_; 548 uword start_;
549 // CodeRegion end address.
468 uword end_; 550 uword end_;
551 // Inclusive ticks.
469 intptr_t inclusive_ticks_; 552 intptr_t inclusive_ticks_;
553 // Exclusive ticks.
470 intptr_t exclusive_ticks_; 554 intptr_t exclusive_ticks_;
555 // Inclusive tick serial number, ensures that each CodeRegion is only given
556 // a single inclusive tick per sample.
471 intptr_t inclusive_tick_serial_; 557 intptr_t inclusive_tick_serial_;
558 // Name of code region.
472 const char* name_; 559 const char* name_;
560 // The compilation timestamp associated with this code region.
561 int64_t compile_timestamp_;
562 // Serial number at which this CodeRegion was created.
563 intptr_t creation_serial_;
473 ZoneGrowableArray<AddressEntry>* address_table_; 564 ZoneGrowableArray<AddressEntry>* address_table_;
474 ZoneGrowableArray<CallEntry>* callers_table_; 565 ZoneGrowableArray<CallEntry>* callers_table_;
475 ZoneGrowableArray<CallEntry>* callees_table_; 566 ZoneGrowableArray<CallEntry>* callees_table_;
476 DISALLOW_COPY_AND_ASSIGN(CodeRegion); 567 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
477 }; 568 };
478 569
570 // A sorted table of CodeRegions. Does not allow for overlap.
571 class CodeRegionTable : public ValueObject {
572 public:
573 enum TickResult {
574 kTicked = 0, // CodeRegion found and ticked.
575 kNotFound = -1, // No CodeRegion found.
576 kNewerCode = -2, // CodeRegion found but it was compiled after sample.
577 };
479 578
480 class ScopeStopwatch : public ValueObject { 579 CodeRegionTable() :
481 public:
482 explicit ScopeStopwatch(const char* name) : name_(name) {
483 start_ = OS::GetCurrentTimeMillis();
484 }
485
486 intptr_t GetElapsed() const {
487 intptr_t end = OS::GetCurrentTimeMillis();
488 ASSERT(end >= start_);
489 return end - start_;
490 }
491
492 ~ScopeStopwatch() {
493 if (FLAG_trace_profiled_isolates) {
494 intptr_t elapsed = GetElapsed();
495 OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
496 }
497 }
498
499 private:
500 const char* name_;
501 intptr_t start_;
502 };
503
504
505 // All code regions. Code region tables are built on demand when a profile
506 // is requested (through the service or on isolate shutdown).
507 class ProfilerCodeRegionTable : public ValueObject {
508 public:
509 explicit ProfilerCodeRegionTable(Isolate* isolate) :
510 heap_(isolate->heap()),
511 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { 580 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
512 } 581 }
513 582
514 ~ProfilerCodeRegionTable() { 583 // Ticks the CodeRegion containing pc if it is alive at timestamp.
584 TickResult Tick(uword pc, bool exclusive, intptr_t serial,
585 int64_t timestamp) {
586 intptr_t index = FindIndex(pc);
587 if (index < 0) {
588 // Not found.
589 return kNotFound;
590 }
591 ASSERT(index < code_region_table_->length());
592 CodeRegion* region = At(index);
593 if (region->compile_timestamp() > timestamp) {
594 // Compiled after tick.
595 return kNewerCode;
596 }
597 region->Tick(pc, exclusive, serial);
598 return kTicked;
515 } 599 }
516 600
517 void AddTick(uword pc, bool exclusive, intptr_t serial) { 601 // Table length.
518 intptr_t index = FindIndex(pc); 602 intptr_t Length() const { return code_region_table_->length(); }
519 if (index < 0) {
520 CodeRegion* code_region = CreateCodeRegion(pc);
521 ASSERT(code_region != NULL);
522 index = InsertCodeRegion(code_region);
523 }
524 ASSERT(index >= 0);
525 ASSERT(index < code_region_table_->length());
526 603
527 // Update code object counters. 604 // Get the CodeRegion at index.
528 (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive, serial); 605 CodeRegion* At(intptr_t index) const {
606 return (*code_region_table_)[index];
529 } 607 }
530 608
531 intptr_t Length() const { return code_region_table_->length(); } 609 // Find the table index to the CodeRegion containing pc.
532 610 // Returns < 0 if not found.
533 CodeRegion* At(intptr_t idx) {
534 return (*code_region_table_)[idx];
535 }
536
537 intptr_t FindIndex(uword pc) const { 611 intptr_t FindIndex(uword pc) const {
538 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); 612 intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
539 const CodeRegion* code_region = NULL; 613 const CodeRegion* code_region = NULL;
540 if (index == code_region_table_->length()) { 614 if (index == code_region_table_->length()) {
541 // Not present. 615 // Not present.
542 return -1; 616 return -1;
543 } 617 }
544 code_region = (*code_region_table_)[index]; 618 code_region = At(index);
545 if (code_region->contains(pc)) { 619 if (code_region->contains(pc)) {
546 // Found at index. 620 // Found at index.
547 return index; 621 return index;
548 } 622 }
549 return -1; 623 return -2;
550 } 624 }
551 625
552 #if defined(DEBUG) 626 // Insert code_region into the table. Returns the table index where the
553 void Verify() { 627 // CodeRegion was inserted. Will merge with an overlapping CodeRegion if
554 VerifyOrder(); 628 // one is present.
555 VerifyOverlap();
556 }
557 #endif
558
559 private:
560 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
561 ASSERT(comparator != NULL);
562 intptr_t count = code_region_table_->length();
563 intptr_t first = 0;
564 while (count > 0) {
565 intptr_t it = first;
566 intptr_t step = count / 2;
567 it += step;
568 const CodeRegion* code_region = (*code_region_table_)[it];
569 if (comparator(pc, code_region->start(), code_region->end())) {
570 first = ++it;
571 count -= (step + 1);
572 } else {
573 count = step;
574 }
575 }
576 return first;
577 }
578
579 static bool CompareUpperBound(uword pc, uword start, uword end) {
580 return pc >= end;
581 }
582
583 static bool CompareLowerBound(uword pc, uword start, uword end) {
584 return end <= pc;
585 }
586
587 CodeRegion* CreateCodeRegion(uword pc) {
588 Code& code = Code::Handle();
589 code ^= Code::LookupCode(pc);
590 if (!code.IsNull()) {
591 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
592 code.EntryPoint() + code.Size());
593 }
594 code ^= Code::LookupCodeInVmIsolate(pc);
595 if (!code.IsNull()) {
596 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
597 code.EntryPoint() + code.Size());
598 }
599 if (heap_->CodeContains(pc)) {
600 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
601 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
602 return new CodeRegion(CodeRegion::kCollectedCode, pc,
603 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment);
604 }
605 uintptr_t native_start = 0;
606 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
607 &native_start);
608 if (native_name == NULL) {
609 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1);
610 }
611 ASSERT(pc >= native_start);
612 CodeRegion* code_region =
613 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1);
614 code_region->SetName(native_name);
615 free(native_name);
616 return code_region;
617 }
618
619 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
620 uword start, uword end) {
621 // We should never see overlapping Dart code regions.
622 ASSERT(region->kind() != CodeRegion::kDartCode);
623 // When code regions overlap, they should be of the same kind.
624 ASSERT(region->kind() == code_region->kind());
625 region->AdjustExtent(start, end);
626 }
627
628 intptr_t InsertCodeRegion(CodeRegion* code_region) { 629 intptr_t InsertCodeRegion(CodeRegion* code_region) {
629 const uword start = code_region->start(); 630 const uword start = code_region->start();
630 const uword end = code_region->end(); 631 const uword end = code_region->end();
631 const intptr_t length = code_region_table_->length(); 632 const intptr_t length = code_region_table_->length();
632 if (length == 0) { 633 if (length == 0) {
633 code_region_table_->Add(code_region); 634 code_region_table_->Add(code_region);
634 return length; 635 return length;
635 } 636 }
636 // Determine the correct place to insert or merge code_region into table. 637 // Determine the correct place to insert or merge code_region into table.
637 intptr_t lo = FindRegionIndex(start, &CompareLowerBound); 638 intptr_t lo = FindRegionIndex(start, &CompareLowerBound);
638 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound); 639 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound);
640 // TODO(johnmccutchan): Simplify below logic.
639 if ((lo == length) && (hi == length)) { 641 if ((lo == length) && (hi == length)) {
640 lo = length - 1; 642 lo = length - 1;
641 } 643 }
642 if (lo == length) { 644 if (lo == length) {
643 CodeRegion* region = (*code_region_table_)[hi]; 645 CodeRegion* region = At(hi);
644 if (region->overlaps(code_region)) { 646 if (region->overlaps(code_region)) {
645 HandleOverlap(region, code_region, start, end); 647 HandleOverlap(region, code_region, start, end);
646 return hi; 648 return hi;
647 } 649 }
648 code_region_table_->Add(code_region); 650 code_region_table_->Add(code_region);
649 return length; 651 return length;
650 } else if (hi == length) { 652 } else if (hi == length) {
651 CodeRegion* region = (*code_region_table_)[lo]; 653 CodeRegion* region = At(lo);
652 if (region->overlaps(code_region)) { 654 if (region->overlaps(code_region)) {
653 HandleOverlap(region, code_region, start, end); 655 HandleOverlap(region, code_region, start, end);
654 return lo; 656 return lo;
655 } 657 }
656 code_region_table_->Add(code_region); 658 code_region_table_->Add(code_region);
657 return length; 659 return length;
658 } else if (lo == hi) { 660 } else if (lo == hi) {
659 CodeRegion* region = (*code_region_table_)[lo]; 661 CodeRegion* region = At(lo);
660 if (region->overlaps(code_region)) { 662 if (region->overlaps(code_region)) {
661 HandleOverlap(region, code_region, start, end); 663 HandleOverlap(region, code_region, start, end);
662 return lo; 664 return lo;
663 } 665 }
664 code_region_table_->InsertAt(lo, code_region); 666 code_region_table_->InsertAt(lo, code_region);
665 return lo; 667 return lo;
666 } else { 668 } else {
667 CodeRegion* region = (*code_region_table_)[lo]; 669 CodeRegion* region = At(lo);
668 if (region->overlaps(code_region)) { 670 if (region->overlaps(code_region)) {
669 HandleOverlap(region, code_region, start, end); 671 HandleOverlap(region, code_region, start, end);
670 return lo; 672 return lo;
671 } 673 }
672 region = (*code_region_table_)[hi]; 674 region = At(hi);
673 if (region->overlaps(code_region)) { 675 if (region->overlaps(code_region)) {
674 HandleOverlap(region, code_region, start, end); 676 HandleOverlap(region, code_region, start, end);
675 return hi; 677 return hi;
676 } 678 }
677 code_region_table_->InsertAt(hi, code_region); 679 code_region_table_->InsertAt(hi, code_region);
678 return hi; 680 return hi;
679 } 681 }
680 UNREACHABLE(); 682 UNREACHABLE();
681 } 683 }
682 684
683 #if defined(DEBUG) 685 #if defined(DEBUG)
686 void Verify() {
687 VerifyOrder();
688 VerifyOverlap();
689 }
690 #endif
691
692 void DebugPrint() {
693 OS::Print("Dumping CodeRegionTable:\n");
694 for (intptr_t i = 0; i < code_region_table_->length(); i++) {
695 CodeRegion* region = At(i);
696 region->DebugPrint();
697 }
698 }
699
700 private:
701 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
702 ASSERT(comparator != NULL);
703 intptr_t count = code_region_table_->length();
704 intptr_t first = 0;
705 while (count > 0) {
706 intptr_t it = first;
707 intptr_t step = count / 2;
708 it += step;
709 const CodeRegion* code_region = At(it);
710 if (comparator(pc, code_region->start(), code_region->end())) {
711 first = ++it;
712 count -= (step + 1);
713 } else {
714 count = step;
715 }
716 }
717 return first;
718 }
719
720 static bool CompareUpperBound(uword pc, uword start, uword end) {
721 return pc >= end;
722 }
723
724 static bool CompareLowerBound(uword pc, uword start, uword end) {
725 return end <= pc;
726 }
727
728 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
729 uword start, uword end) {
730 // We should never see overlapping Dart code regions.
731 ASSERT(region->kind() != CodeRegion::kDartCode);
732 // When code regions overlap, they should be of the same kind.
733 ASSERT(region->kind() == code_region->kind());
734 region->AdjustExtent(start, end);
735 }
736
737 #if defined(DEBUG)
684 void VerifyOrder() { 738 void VerifyOrder() {
685 const intptr_t length = code_region_table_->length(); 739 const intptr_t length = code_region_table_->length();
686 if (length == 0) { 740 if (length == 0) {
687 return; 741 return;
688 } 742 }
689 uword last = (*code_region_table_)[0]->end(); 743 uword last = (*code_region_table_)[0]->end();
690 for (intptr_t i = 1; i < length; i++) { 744 for (intptr_t i = 1; i < length; i++) {
691 CodeRegion* a = (*code_region_table_)[i]; 745 CodeRegion* a = (*code_region_table_)[i];
692 ASSERT(last <= a->start()); 746 ASSERT(last <= a->start());
693 last = a->end(); 747 last = a->end();
694 } 748 }
695 } 749 }
696 750
697 void VerifyOverlap() { 751 void VerifyOverlap() {
698 const intptr_t length = code_region_table_->length(); 752 const intptr_t length = code_region_table_->length();
699 for (intptr_t i = 0; i < length; i++) { 753 for (intptr_t i = 0; i < length; i++) {
700 CodeRegion* a = (*code_region_table_)[i]; 754 CodeRegion* a = (*code_region_table_)[i];
701 for (intptr_t j = i+1; j < length; j++) { 755 for (intptr_t j = i+1; j < length; j++) {
702 CodeRegion* b = (*code_region_table_)[j]; 756 CodeRegion* b = (*code_region_table_)[j];
703 ASSERT(!a->contains(b->start()) && 757 ASSERT(!a->contains(b->start()) &&
704 !a->contains(b->end() - 1) && 758 !a->contains(b->end() - 1) &&
705 !b->contains(a->start()) && 759 !b->contains(a->start()) &&
706 !b->contains(a->end() - 1)); 760 !b->contains(a->end() - 1));
707 } 761 }
708 } 762 }
709 } 763 }
710 #endif 764 #endif
711 765
712 Heap* heap_;
713 ZoneGrowableArray<CodeRegion*>* code_region_table_; 766 ZoneGrowableArray<CodeRegion*>* code_region_table_;
714 }; 767 };
715 768
716 769
717 class CodeRegionTableBuilder : public SampleVisitor { 770 class CodeRegionTableBuilder : public SampleVisitor {
718 public: 771 public:
719 CodeRegionTableBuilder(Isolate* isolate, 772 CodeRegionTableBuilder(Isolate* isolate,
720 ProfilerCodeRegionTable* code_region_table) 773 CodeRegionTable* live_code_table,
721 : SampleVisitor(isolate), code_region_table_(code_region_table) { 774 CodeRegionTable* dead_code_table)
775 : SampleVisitor(isolate),
776 live_code_table_(live_code_table),
777 dead_code_table_(dead_code_table),
778 isolate_(isolate),
779 vm_isolate_(Dart::vm_isolate()) {
780 ASSERT(live_code_table_ != NULL);
781 ASSERT(dead_code_table_ != NULL);
722 frames_ = 0; 782 frames_ = 0;
723 min_time_ = kMaxInt64; 783 min_time_ = kMaxInt64;
724 max_time_ = 0; 784 max_time_ = 0;
785 ASSERT(isolate_ != NULL);
786 ASSERT(vm_isolate_ != NULL);
725 } 787 }
726 788
727 void VisitSample(Sample* sample) { 789 void VisitSample(Sample* sample) {
728 int64_t timestamp = sample->timestamp(); 790 int64_t timestamp = sample->timestamp();
729 if (timestamp > max_time_) { 791 if (timestamp > max_time_) {
730 max_time_ = timestamp; 792 max_time_ = timestamp;
731 } 793 }
732 if (timestamp < min_time_) { 794 if (timestamp < min_time_) {
733 min_time_ = timestamp; 795 min_time_ = timestamp;
734 } 796 }
735 // Give the bottom frame an exclusive tick. 797 // Exclusive tick for bottom frame.
736 code_region_table_->AddTick(sample->At(0), true, -1); 798 Tick(sample->At(0), true, timestamp);
737 // Give all frames (including the bottom) an inclusive tick. 799 // Inclusive tick for all frames.
738 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { 800 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
739 if (sample->At(i) == 0) { 801 if (sample->At(i) == 0) {
740 break; 802 break;
741 } 803 }
742 frames_++; 804 frames_++;
743 code_region_table_->AddTick(sample->At(i), false, visited()); 805 Tick(sample->At(i), false, timestamp);
744 } 806 }
745 } 807 }
746 808
747 intptr_t frames() const { return frames_; } 809 intptr_t frames() const { return frames_; }
810
748 intptr_t TimeDeltaMicros() const { 811 intptr_t TimeDeltaMicros() const {
749 return static_cast<intptr_t>(max_time_ - min_time_); 812 return static_cast<intptr_t>(max_time_ - min_time_);
750 } 813 }
751 int64_t max_time() const { return max_time_; } 814 int64_t max_time() const { return max_time_; }
752 815
753 private: 816 private:
817 void Tick(uword pc, bool exclusive, int64_t timestamp) {
818 CodeRegionTable::TickResult r;
819 intptr_t serial = exclusive ? -1 : visited();
820 r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
821 if (r == CodeRegionTable::kTicked) {
822 // Live code found and ticked.
823 return;
824 }
825 if (r == CodeRegionTable::kNewerCode) {
826 // Code has been overwritten by newer code.
827 // Update shadow table of dead code regions.
828 r = dead_code_table_->Tick(pc, exclusive, serial, timestamp);
829 ASSERT(r != CodeRegionTable::kNewerCode);
830 if (r == CodeRegionTable::kTicked) {
831 // Dead code found and ticked.
832 return;
833 }
834 ASSERT(r == CodeRegionTable::kNotFound);
835 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
836 return;
837 }
838 // Create new live CodeRegion.
839 ASSERT(r == CodeRegionTable::kNotFound);
840 CodeRegion* region = CreateCodeRegion(pc);
841 region->set_creation_serial(visited());
842 intptr_t index = live_code_table_->InsertCodeRegion(region);
843 ASSERT(index >= 0);
844 region = live_code_table_->At(index);
845 if (region->compile_timestamp() <= timestamp) {
846 region->Tick(pc, exclusive, serial);
847 return;
848 }
849 // We have created a new code region but it's for a CodeRegion
850 // compiled after the sample.
851 ASSERT(region->kind() == CodeRegion::kDartCode);
852 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
853 }
854
855 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
856 // Need to create dead code.
857 CodeRegion* region = new CodeRegion(CodeRegion::kReusedCode,
858 pc,
859 pc + 1,
860 0);
861 intptr_t index = dead_code_table_->InsertCodeRegion(region);
862 region->set_creation_serial(visited());
863 ASSERT(index >= 0);
864 dead_code_table_->At(index)->Tick(pc, exclusive, serial);
865 }
866
867 CodeRegion* CreateCodeRegion(uword pc) {
868 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
869 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
870 Code& code = Code::Handle(isolate_);
871 // Check current isolate for pc.
872 if (isolate_->heap()->CodeContains(pc)) {
873 code ^= Code::LookupCode(pc);
874 if (!code.IsNull()) {
875 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
876 code.EntryPoint() + code.Size(),
877 code.compile_timestamp());
878 }
879 return new CodeRegion(CodeRegion::kCollectedCode, pc,
880 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
881 0);
882 }
883 // Check VM isolate for pc.
884 if (vm_isolate_->heap()->CodeContains(pc)) {
885 code ^= Code::LookupCodeInVmIsolate(pc);
886 if (!code.IsNull()) {
887 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
888 code.EntryPoint() + code.Size(),
889 code.compile_timestamp());
890 }
891 return new CodeRegion(CodeRegion::kCollectedCode, pc,
892 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
893 0);
894 }
895 // Check NativeSymbolResolver for pc.
896 uintptr_t native_start = 0;
897 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
898 &native_start);
899 if (native_name == NULL) {
900 // No native name found.
901 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1, 0);
902 }
903 ASSERT(pc >= native_start);
904 CodeRegion* code_region =
905 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1, 0);
906 code_region->SetName(native_name);
907 free(native_name);
908 return code_region;
909 }
910
754 intptr_t frames_; 911 intptr_t frames_;
755 int64_t min_time_; 912 int64_t min_time_;
756 int64_t max_time_; 913 int64_t max_time_;
757 ProfilerCodeRegionTable* code_region_table_; 914 CodeRegionTable* live_code_table_;
915 CodeRegionTable* dead_code_table_;
916 Isolate* isolate_;
917 Isolate* vm_isolate_;
758 }; 918 };
759 919
760 920
761 class CodeRegionTableCallersBuilder : public SampleVisitor { 921 class CodeRegionTableCallersBuilder : public SampleVisitor {
762 public: 922 public:
763 CodeRegionTableCallersBuilder(Isolate* isolate, 923 CodeRegionTableCallersBuilder(Isolate* isolate,
764 ProfilerCodeRegionTable* code_region_table) 924 CodeRegionTable* live_code_table,
765 : SampleVisitor(isolate), code_region_table_(code_region_table) { 925 CodeRegionTable* dead_code_table)
766 ASSERT(code_region_table_ != NULL); 926 : SampleVisitor(isolate),
927 live_code_table_(live_code_table),
928 dead_code_table_(dead_code_table) {
929 ASSERT(live_code_table_ != NULL);
930 ASSERT(dead_code_table_ != NULL);
931 dead_code_table_offset_ = live_code_table_->Length();
767 } 932 }
768 933
769 void VisitSample(Sample* sample) { 934 void VisitSample(Sample* sample) {
770 intptr_t current_index = code_region_table_->FindIndex(sample->At(0)); 935 int64_t timestamp = sample->timestamp();
771 ASSERT(current_index != -1); 936 intptr_t current_index = FindFinalIndex(sample->At(0), timestamp);
772 CodeRegion* current = code_region_table_->At(current_index); 937 ASSERT(current_index >= 0);
938 CodeRegion* current = At(current_index);
773 intptr_t caller_index = -1; 939 intptr_t caller_index = -1;
774 CodeRegion* caller = NULL; 940 CodeRegion* caller = NULL;
775 intptr_t callee_index = -1; 941 intptr_t callee_index = -1;
776 CodeRegion* callee = NULL; 942 CodeRegion* callee = NULL;
777 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { 943 for (intptr_t i = 1; i < FLAG_profile_depth; i++) {
778 if (sample->At(i) == 0) { 944 if (sample->At(i) == 0) {
779 break; 945 break;
780 } 946 }
781 caller_index = code_region_table_->FindIndex(sample->At(i)); 947 caller_index = FindFinalIndex(sample->At(i), timestamp);
782 ASSERT(caller_index != -1); 948 ASSERT(caller_index >= 0);
783 caller = code_region_table_->At(caller_index); 949 caller = At(caller_index);
784 current->AddCaller(caller_index); 950 current->AddCaller(caller_index);
785 if (callee != NULL) { 951 if (callee != NULL) {
786 current->AddCallee(callee_index); 952 current->AddCallee(callee_index);
787 } 953 }
788 // Move cursors. 954 // Move cursors.
789 callee_index = current_index; 955 callee_index = current_index;
790 callee = current; 956 callee = current;
791 current_index = caller_index; 957 current_index = caller_index;
792 current = caller; 958 current = caller;
793 } 959 }
794 } 960 }
795 961
796 private: 962 private:
797 ProfilerCodeRegionTable* code_region_table_; 963 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const {
964 intptr_t index = live_code_table_->FindIndex(pc);
965 ASSERT(index >= 0);
966 CodeRegion* region = live_code_table_->At(index);
967 ASSERT(region->contains(pc));
968 if (region->compile_timestamp() > timestamp) {
969 // Overwritten code, find in dead code table.
970 index = dead_code_table_->FindIndex(pc);
971 ASSERT(index >= 0);
972 region = dead_code_table_->At(index);
973 ASSERT(region->contains(pc));
974 ASSERT(region->compile_timestamp() <= timestamp);
975 return index + dead_code_table_offset_;
976 }
977 ASSERT(region->compile_timestamp() <= timestamp);
978 return index;
979 }
980
981 CodeRegion* At(intptr_t final_index) {
982 ASSERT(final_index >= 0);
983 if (final_index < dead_code_table_offset_) {
984 return live_code_table_->At(final_index);
985 } else {
986 return dead_code_table_->At(final_index - dead_code_table_offset_);
987 }
988 }
989
990 CodeRegionTable* live_code_table_;
991 CodeRegionTable* dead_code_table_;
992 intptr_t dead_code_table_offset_;
798 }; 993 };
799 994
800 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, 995 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
801 bool full) { 996 bool full) {
802 ASSERT(isolate == Isolate::Current()); 997 ASSERT(isolate == Isolate::Current());
803 // Disable profile interrupts while processing the buffer. 998 // Disable profile interrupts while processing the buffer.
804 EndExecution(isolate); 999 EndExecution(isolate);
805 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1000 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
806 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1001 IsolateProfilerData* profiler_data = isolate->profiler_data();
807 if (profiler_data == NULL) { 1002 if (profiler_data == NULL) {
808 JSONObject error(stream); 1003 JSONObject error(stream);
809 error.AddProperty("type", "Error"); 1004 error.AddProperty("type", "Error");
810 error.AddProperty("text", "Isolate does not have profiling enabled."); 1005 error.AddProperty("text", "Isolate does not have profiling enabled.");
811 return; 1006 return;
812 } 1007 }
813 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1008 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
814 ASSERT(sample_buffer != NULL); 1009 ASSERT(sample_buffer != NULL);
815 { 1010 {
816 StackZone zone(isolate); 1011 StackZone zone(isolate);
817 { 1012 {
818 // Build code region table. 1013 // Live code holds Dart, Native, and Collected CodeRegions.
819 ProfilerCodeRegionTable code_region_table(isolate); 1014 CodeRegionTable live_code_table;
820 CodeRegionTableBuilder builder(isolate, &code_region_table); 1015 // Dead code holds Overwritten CodeRegions.
821 CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table); 1016 CodeRegionTable dead_code_table;
1017 CodeRegionTableBuilder builder(isolate,
1018 &live_code_table,
1019 &dead_code_table);
822 { 1020 {
1021 // Build CodeRegion tables.
823 ScopeStopwatch sw("CodeTableBuild"); 1022 ScopeStopwatch sw("CodeTableBuild");
824 sample_buffer->VisitSamples(&builder); 1023 sample_buffer->VisitSamples(&builder);
825 } 1024 }
826 #if defined(DEBUG)
827 code_region_table.Verify();
828 #endif
829 {
830 ScopeStopwatch sw("CodeTableCallersBuild");
831 sample_buffer->VisitSamples(&build_callers);
832 }
833 // Number of samples we processed.
834 intptr_t samples = builder.visited(); 1025 intptr_t samples = builder.visited();
835 intptr_t frames = builder.frames(); 1026 intptr_t frames = builder.frames();
836 if (FLAG_trace_profiled_isolates) { 1027 if (FLAG_trace_profiled_isolates) {
837 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", 1028 intptr_t total_live_code_objects = live_code_table.Length();
838 frames, code_region_table.Length()); 1029 intptr_t total_dead_code_objects = dead_code_table.Length();
1030 OS::Print("Processed %" Pd " frames\n", frames);
1031 OS::Print("CodeTables: live=%" Pd " dead=%" Pd "\n",
1032 total_live_code_objects,
1033 total_dead_code_objects);
1034 }
1035 #if defined(DEBUG)
1036 live_code_table.Verify();
1037 dead_code_table.Verify();
1038 if (FLAG_trace_profiled_isolates) {
1039 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n");
1040 }
1041 #endif
1042 CodeRegionTableCallersBuilder build_callers(isolate,
1043 &live_code_table,
1044 &dead_code_table);
1045 {
1046 // Build CodeRegion callers.
1047 ScopeStopwatch sw("CodeTableCallersBuild");
1048 sample_buffer->VisitSamples(&build_callers);
839 } 1049 }
840 { 1050 {
841 ScopeStopwatch sw("CodeTableStream"); 1051 ScopeStopwatch sw("CodeTableStream");
842 // Serialize to JSON. 1052 // Serialize to JSON.
843 JSONObject obj(stream); 1053 JSONObject obj(stream);
844 obj.AddProperty("type", "Profile"); 1054 obj.AddProperty("type", "Profile");
845 obj.AddProperty("id", "profile"); 1055 obj.AddProperty("id", "profile");
846 obj.AddProperty("samples", samples); 1056 obj.AddProperty("samples", samples);
847 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros()); 1057 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros());
848 JSONArray codes(&obj, "codes"); 1058 JSONArray codes(&obj, "codes");
849 for (intptr_t i = 0; i < code_region_table.Length(); i++) { 1059 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
850 CodeRegion* region = code_region_table.At(i); 1060 CodeRegion* region = live_code_table.At(i);
851 ASSERT(region != NULL); 1061 ASSERT(region != NULL);
852 region->PrintToJSONArray(isolate, &codes, full); 1062 region->PrintToJSONArray(isolate, &codes, full);
853 } 1063 }
1064 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
1065 CodeRegion* region = dead_code_table.At(i);
1066 ASSERT(region != NULL);
1067 region->PrintToJSONArray(isolate, &codes, full);
1068 }
854 } 1069 }
855 } 1070 }
856 } 1071 }
857 // Enable profile interrupts. 1072 // Enable profile interrupts.
858 BeginExecution(isolate); 1073 BeginExecution(isolate);
859 } 1074 }
860 1075
861 1076
862 void Profiler::WriteProfile(Isolate* isolate) { 1077 void Profiler::WriteProfile(Isolate* isolate) {
863 if (isolate == NULL) { 1078 if (isolate == NULL) {
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
1070 stack_lower = 0; 1285 stack_lower = 0;
1071 stack_upper = 0; 1286 stack_upper = 0;
1072 } 1287 }
1073 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, 1288 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
1074 state.pc, state.fp, state.sp); 1289 state.pc, state.fp, state.sp);
1075 stackWalker.walk(isolate->heap()); 1290 stackWalker.walk(isolate->heap());
1076 } 1291 }
1077 1292
1078 1293
1079 } // namespace dart 1294 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/object.cc ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698