| OLD | NEW |
| 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 194 |
| 195 void tick(bool exclusive) { | 195 void tick(bool exclusive) { |
| 196 if (exclusive) { | 196 if (exclusive) { |
| 197 exclusive_ticks++; | 197 exclusive_ticks++; |
| 198 } else { | 198 } else { |
| 199 inclusive_ticks++; | 199 inclusive_ticks++; |
| 200 } | 200 } |
| 201 } | 201 } |
| 202 }; | 202 }; |
| 203 | 203 |
| 204 |
| 204 struct CallEntry { | 205 struct CallEntry { |
| 205 intptr_t code_table_index; | 206 intptr_t code_table_index; |
| 206 intptr_t count; | 207 intptr_t count; |
| 207 }; | 208 }; |
| 208 | 209 |
| 210 |
| 209 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); | 211 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); |
| 210 | 212 |
| 213 |
| 214 class CodeRegionTrieNode : public ZoneAllocated { |
| 215 public: |
| 216 explicit CodeRegionTrieNode(intptr_t code_region_index) |
| 217 : code_region_index_(code_region_index), |
| 218 count_(0), |
| 219 children_(new ZoneGrowableArray<CodeRegionTrieNode*>()) { |
| 220 } |
| 221 |
| 222 void Tick() { |
| 223 ASSERT(code_region_index_ >= 0); |
| 224 count_++; |
| 225 } |
| 226 |
| 227 intptr_t count() const { |
| 228 ASSERT(code_region_index_ >= 0); |
| 229 return count_; |
| 230 } |
| 231 |
| 232 intptr_t code_region_index() const { |
| 233 return code_region_index_; |
| 234 } |
| 235 |
| 236 ZoneGrowableArray<CodeRegionTrieNode*>& children() const { |
| 237 return *children_; |
| 238 } |
| 239 |
| 240 CodeRegionTrieNode* GetChild(intptr_t child_code_region_index) { |
| 241 const intptr_t length = children_->length(); |
| 242 intptr_t i = 0; |
| 243 while (i < length) { |
| 244 CodeRegionTrieNode* child = (*children_)[i]; |
| 245 if (child->code_region_index() == child_code_region_index) { |
| 246 return child; |
| 247 } |
| 248 if (child->code_region_index() > child_code_region_index) { |
| 249 break; |
| 250 } |
| 251 i++; |
| 252 } |
| 253 // Add new CodeRegion, sorted by CodeRegionTable index. |
| 254 CodeRegionTrieNode* child = new CodeRegionTrieNode(child_code_region_index); |
| 255 if (i < length) { |
| 256 // Insert at i. |
| 257 children_->InsertAt(i, child); |
| 258 } else { |
| 259 // Add to end. |
| 260 children_->Add(child); |
| 261 } |
| 262 return child; |
| 263 } |
| 264 |
| 265 // Sort this's children and (recursively) all descendants by count. |
| 266 // This should only be called after the trie is completely built. |
| 267 void SortByCount() { |
| 268 children_->Sort(CodeRegionTrieNodeCompare); |
| 269 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children(); |
| 270 intptr_t child_count = kids.length(); |
| 271 // Recurse. |
| 272 for (intptr_t i = 0; i < child_count; i++) { |
| 273 kids[i]->SortByCount(); |
| 274 } |
| 275 } |
| 276 |
| 277 void PrintToJSONArray(JSONArray* array) const { |
| 278 ASSERT(array != NULL); |
| 279 // Write CodeRegion index. |
| 280 array->AddValue(code_region_index_); |
| 281 // Write count. |
| 282 array->AddValue(count_); |
| 283 // Write number of children. |
| 284 ZoneGrowableArray<CodeRegionTrieNode*>& kids = children(); |
| 285 intptr_t child_count = kids.length(); |
| 286 array->AddValue(child_count); |
| 287 // Recurse. |
| 288 for (intptr_t i = 0; i < child_count; i++) { |
| 289 kids[i]->PrintToJSONArray(array); |
| 290 } |
| 291 } |
| 292 |
| 293 private: |
| 294 static int CodeRegionTrieNodeCompare(CodeRegionTrieNode* const* a, |
| 295 CodeRegionTrieNode* const* b) { |
| 296 ASSERT(a != NULL); |
| 297 ASSERT(b != NULL); |
| 298 return (*b)->count() - (*a)->count(); |
| 299 } |
| 300 |
| 301 const intptr_t code_region_index_; |
| 302 intptr_t count_; |
| 303 ZoneGrowableArray<CodeRegionTrieNode*>* children_; |
| 304 }; |
| 305 |
| 306 |
| 211 // A contiguous address region that holds code. Each CodeRegion has a "kind" | 307 // A contiguous address region that holds code. Each CodeRegion has a "kind" |
| 212 // which describes the type of code contained inside the region. Each | 308 // which describes the type of code contained inside the region. Each |
| 213 // region covers the following interval: [start, end). | 309 // region covers the following interval: [start, end). |
| 214 class CodeRegion : public ZoneAllocated { | 310 class CodeRegion : public ZoneAllocated { |
| 215 public: | 311 public: |
| 216 enum Kind { | 312 enum Kind { |
| 217 kDartCode, // Live Dart code. | 313 kDartCode, // Live Dart code. |
| 218 kCollectedCode, // Dead Dart code. | 314 kCollectedCode, // Dead Dart code. |
| 219 kNativeCode, // Native code. | 315 kNativeCode, // Native code. |
| 220 kReusedCode, // Dead Dart code that has been reused by new kDartCode. | 316 kReusedCode, // Dead Dart code that has been reused by new kDartCode. |
| 221 kTagCode, // A special kind of code representing a tag. | 317 kTagCode, // A special kind of code representing a tag. |
| 222 }; | 318 }; |
| 223 | 319 |
| 224 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) : | 320 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) |
| 225 kind_(kind), | 321 : kind_(kind), |
| 226 start_(start), | 322 start_(start), |
| 227 end_(end), | 323 end_(end), |
| 228 inclusive_ticks_(0), | 324 inclusive_ticks_(0), |
| 229 exclusive_ticks_(0), | 325 exclusive_ticks_(0), |
| 230 inclusive_tick_serial_(0), | 326 inclusive_tick_serial_(0), |
| 231 name_(NULL), | 327 name_(NULL), |
| 232 compile_timestamp_(timestamp), | 328 compile_timestamp_(timestamp), |
| 233 creation_serial_(0), | 329 creation_serial_(0), |
| 234 address_table_(new ZoneGrowableArray<AddressEntry>()), | 330 address_table_(new ZoneGrowableArray<AddressEntry>()), |
| 235 callers_table_(new ZoneGrowableArray<CallEntry>()), | 331 callers_table_(new ZoneGrowableArray<CallEntry>()), |
| 236 callees_table_(new ZoneGrowableArray<CallEntry>()) { | 332 callees_table_(new ZoneGrowableArray<CallEntry>()) { |
| 237 ASSERT(start_ < end_); | 333 ASSERT(start_ < end_); |
| 238 } | 334 } |
| 239 | 335 |
| 240 | 336 |
| 241 uword start() const { return start_; } | 337 uword start() const { return start_; } |
| 242 void set_start(uword start) { | 338 void set_start(uword start) { |
| 243 start_ = start; | 339 start_ = start; |
| 244 } | 340 } |
| 245 | 341 |
| 246 uword end() const { return end_; } | 342 uword end() const { return end_; } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 if (exclusive) { | 435 if (exclusive) { |
| 340 exclusive_ticks_++; | 436 exclusive_ticks_++; |
| 341 } else { | 437 } else { |
| 342 inclusive_ticks_++; | 438 inclusive_ticks_++; |
| 343 // Mark the last serial we ticked the inclusive count. | 439 // Mark the last serial we ticked the inclusive count. |
| 344 inclusive_tick_serial_ = serial; | 440 inclusive_tick_serial_ = serial; |
| 345 } | 441 } |
| 346 TickAddress(pc, exclusive); | 442 TickAddress(pc, exclusive); |
| 347 } | 443 } |
| 348 | 444 |
| 349 void AddCaller(intptr_t index) { | 445 void AddCaller(intptr_t index, intptr_t count) { |
| 350 AddCallEntry(callers_table_, index); | 446 AddCallEntry(callers_table_, index, count); |
| 351 } | 447 } |
| 352 | 448 |
| 353 void AddCallee(intptr_t index) { | 449 void AddCallee(intptr_t index, intptr_t count) { |
| 354 AddCallEntry(callees_table_, index); | 450 AddCallEntry(callees_table_, index, count); |
| 355 } | 451 } |
| 356 | 452 |
| 357 void PrintNativeCode(JSONObject* profile_code_obj) { | 453 void PrintNativeCode(JSONObject* profile_code_obj) { |
| 358 ASSERT(kind() == kNativeCode); | 454 ASSERT(kind() == kNativeCode); |
| 359 JSONObject obj(profile_code_obj, "code"); | 455 JSONObject obj(profile_code_obj, "code"); |
| 360 obj.AddProperty("type", "@Code"); | 456 obj.AddProperty("type", "@Code"); |
| 361 obj.AddProperty("kind", "Native"); | 457 obj.AddProperty("kind", "Native"); |
| 362 obj.AddProperty("name", name()); | 458 obj.AddProperty("name", name()); |
| 363 obj.AddProperty("user_name", name()); | 459 obj.AddProperty("user_name", name()); |
| 364 obj.AddPropertyF("start", "%" Px "", start()); | 460 obj.AddPropertyF("start", "%" Px "", start()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 // Generate a fake function entry. | 506 // Generate a fake function entry. |
| 411 JSONObject func(&obj, "function"); | 507 JSONObject func(&obj, "function"); |
| 412 func.AddProperty("type", "@Function"); | 508 func.AddProperty("type", "@Function"); |
| 413 obj.AddPropertyF("id", "functions/reused-%" Px "", start()); | 509 obj.AddPropertyF("id", "functions/reused-%" Px "", start()); |
| 414 func.AddProperty("name", name()); | 510 func.AddProperty("name", name()); |
| 415 func.AddProperty("user_name", name()); | 511 func.AddProperty("user_name", name()); |
| 416 func.AddProperty("kind", "Reused"); | 512 func.AddProperty("kind", "Reused"); |
| 417 } | 513 } |
| 418 } | 514 } |
| 419 | 515 |
| 516 void PrintTagCode(JSONObject* profile_code_obj) { |
| 517 ASSERT(kind() == kTagCode); |
| 518 JSONObject obj(profile_code_obj, "code"); |
| 519 obj.AddProperty("type", "@Code"); |
| 520 obj.AddProperty("kind", "Tag"); |
| 521 obj.AddPropertyF("id", "code/tag-%" Px "", start()); |
| 522 obj.AddProperty("name", name()); |
| 523 obj.AddProperty("user_name", name()); |
| 524 obj.AddPropertyF("start", "%" Px "", start()); |
| 525 obj.AddPropertyF("end", "%" Px "", end()); |
| 526 { |
| 527 // Generate a fake function entry. |
| 528 JSONObject func(&obj, "function"); |
| 529 func.AddProperty("type", "@Function"); |
| 530 func.AddProperty("kind", "Tag"); |
| 531 obj.AddPropertyF("id", "functions/tag-%" Px "", start()); |
| 532 func.AddProperty("name", name()); |
| 533 func.AddProperty("user_name", name()); |
| 534 } |
| 535 } |
| 536 |
| 420 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) { | 537 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) { |
| 421 JSONObject obj(events); | 538 JSONObject obj(events); |
| 422 obj.AddProperty("type", "CodeRegion"); | 539 obj.AddProperty("type", "CodeRegion"); |
| 423 obj.AddProperty("kind", KindToCString(kind())); | 540 obj.AddProperty("kind", KindToCString(kind())); |
| 424 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); | 541 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); |
| 425 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); | 542 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); |
| 426 if (kind() == kDartCode) { | 543 if (kind() == kDartCode) { |
| 427 // Look up code in Dart heap. | 544 // Look up code in Dart heap. |
| 428 Code& code = Code::Handle(isolate); | 545 Code& code = Code::Handle(isolate); |
| 429 code ^= Code::LookupCode(start()); | 546 code ^= Code::LookupCode(start()); |
| 430 if (code.IsNull()) { | 547 if (code.IsNull()) { |
| 431 // Code is a stub in the Vm isolate. | 548 // Code is a stub in the Vm isolate. |
| 432 code ^= Code::LookupCodeInVmIsolate(start()); | 549 code ^= Code::LookupCodeInVmIsolate(start()); |
| 433 } | 550 } |
| 434 ASSERT(!code.IsNull()); | 551 ASSERT(!code.IsNull()); |
| 435 obj.AddProperty("code", code, !full); | 552 obj.AddProperty("code", code, !full); |
| 436 } else if (kind() == kCollectedCode) { | 553 } else if (kind() == kCollectedCode) { |
| 437 if (name() == NULL) { | 554 if (name() == NULL) { |
| 438 // Lazily set generated name. | 555 // Lazily set generated name. |
| 439 GenerateAndSetSymbolName("[Collected]"); | 556 GenerateAndSetSymbolName("[Collected]"); |
| 440 } | 557 } |
| 441 PrintCollectedCode(&obj); | 558 PrintCollectedCode(&obj); |
| 442 } else if (kind() == kReusedCode) { | 559 } else if (kind() == kReusedCode) { |
| 443 if (name() == NULL) { | 560 if (name() == NULL) { |
| 444 // Lazily set generated name. | 561 // Lazily set generated name. |
| 445 GenerateAndSetSymbolName("[Reused]"); | 562 GenerateAndSetSymbolName("[Reused]"); |
| 446 } | 563 } |
| 447 PrintOverwrittenCode(&obj); | 564 PrintOverwrittenCode(&obj); |
| 565 } else if (kind() == kTagCode) { |
| 566 if (name() == NULL) { |
| 567 const char* tag_name = start() == 0 ? "root" : VMTag::TagName(start()); |
| 568 ASSERT(tag_name != NULL); |
| 569 SetName(tag_name); |
| 570 } |
| 571 PrintTagCode(&obj); |
| 448 } else { | 572 } else { |
| 449 ASSERT(kind() == kNativeCode); | 573 ASSERT(kind() == kNativeCode); |
| 450 if (name() == NULL) { | 574 if (name() == NULL) { |
| 451 // Lazily set generated name. | 575 // Lazily set generated name. |
| 452 GenerateAndSetSymbolName("[Native]"); | 576 GenerateAndSetSymbolName("[Native]"); |
| 453 } | 577 } |
| 454 PrintNativeCode(&obj); | 578 PrintNativeCode(&obj); |
| 455 } | 579 } |
| 456 { | 580 { |
| 457 JSONArray ticks(&obj, "ticks"); | 581 JSONArray ticks(&obj, "ticks"); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 if (i < length) { | 628 if (i < length) { |
| 505 // Insert at i. | 629 // Insert at i. |
| 506 address_table_->InsertAt(i, entry); | 630 address_table_->InsertAt(i, entry); |
| 507 } else { | 631 } else { |
| 508 // Add to end. | 632 // Add to end. |
| 509 address_table_->Add(entry); | 633 address_table_->Add(entry); |
| 510 } | 634 } |
| 511 } | 635 } |
| 512 | 636 |
| 513 | 637 |
| 514 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) { | 638 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index, |
| 639 intptr_t count) { |
| 515 const intptr_t length = table->length(); | 640 const intptr_t length = table->length(); |
| 516 intptr_t i = 0; | 641 intptr_t i = 0; |
| 517 for (; i < length; i++) { | 642 for (; i < length; i++) { |
| 518 CallEntry& entry = (*table)[i]; | 643 CallEntry& entry = (*table)[i]; |
| 519 if (entry.code_table_index == index) { | 644 if (entry.code_table_index == index) { |
| 520 entry.count++; | 645 entry.count += count; |
| 521 return; | 646 return; |
| 522 } | 647 } |
| 523 if (entry.code_table_index > index) { | 648 if (entry.code_table_index > index) { |
| 524 break; | 649 break; |
| 525 } | 650 } |
| 526 } | 651 } |
| 527 CallEntry entry; | 652 CallEntry entry; |
| 528 entry.code_table_index = index; | 653 entry.code_table_index = index; |
| 529 entry.count = 1; | 654 entry.count = count; |
| 530 if (i < length) { | 655 if (i < length) { |
| 531 table->InsertAt(i, entry); | 656 table->InsertAt(i, entry); |
| 532 } else { | 657 } else { |
| 533 table->Add(entry); | 658 table->Add(entry); |
| 534 } | 659 } |
| 535 } | 660 } |
| 536 | 661 |
| 537 void GenerateAndSetSymbolName(const char* prefix) { | 662 void GenerateAndSetSymbolName(const char* prefix) { |
| 538 const intptr_t kBuffSize = 512; | 663 const intptr_t kBuffSize = 512; |
| 539 char buff[kBuffSize]; | 664 char buff[kBuffSize]; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 560 // The compilation timestamp associated with this code region. | 685 // The compilation timestamp associated with this code region. |
| 561 int64_t compile_timestamp_; | 686 int64_t compile_timestamp_; |
| 562 // Serial number at which this CodeRegion was created. | 687 // Serial number at which this CodeRegion was created. |
| 563 intptr_t creation_serial_; | 688 intptr_t creation_serial_; |
| 564 ZoneGrowableArray<AddressEntry>* address_table_; | 689 ZoneGrowableArray<AddressEntry>* address_table_; |
| 565 ZoneGrowableArray<CallEntry>* callers_table_; | 690 ZoneGrowableArray<CallEntry>* callers_table_; |
| 566 ZoneGrowableArray<CallEntry>* callees_table_; | 691 ZoneGrowableArray<CallEntry>* callees_table_; |
| 567 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | 692 DISALLOW_COPY_AND_ASSIGN(CodeRegion); |
| 568 }; | 693 }; |
| 569 | 694 |
| 695 |
| 570 // A sorted table of CodeRegions. Does not allow for overlap. | 696 // A sorted table of CodeRegions. Does not allow for overlap. |
| 571 class CodeRegionTable : public ValueObject { | 697 class CodeRegionTable : public ValueObject { |
| 572 public: | 698 public: |
| 573 enum TickResult { | 699 enum TickResult { |
| 574 kTicked = 0, // CodeRegion found and ticked. | 700 kTicked = 0, // CodeRegion found and ticked. |
| 575 kNotFound = -1, // No CodeRegion found. | 701 kNotFound = -1, // No CodeRegion found. |
| 576 kNewerCode = -2, // CodeRegion found but it was compiled after sample. | 702 kNewerCode = -2, // CodeRegion found but it was compiled after sample. |
| 577 }; | 703 }; |
| 578 | 704 |
| 579 CodeRegionTable() : | 705 CodeRegionTable() : |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 } | 848 } |
| 723 | 849 |
| 724 static bool CompareLowerBound(uword pc, uword start, uword end) { | 850 static bool CompareLowerBound(uword pc, uword start, uword end) { |
| 725 return end <= pc; | 851 return end <= pc; |
| 726 } | 852 } |
| 727 | 853 |
| 728 void HandleOverlap(CodeRegion* region, CodeRegion* code_region, | 854 void HandleOverlap(CodeRegion* region, CodeRegion* code_region, |
| 729 uword start, uword end) { | 855 uword start, uword end) { |
| 730 // We should never see overlapping Dart code regions. | 856 // We should never see overlapping Dart code regions. |
| 731 ASSERT(region->kind() != CodeRegion::kDartCode); | 857 ASSERT(region->kind() != CodeRegion::kDartCode); |
| 858 // We should never see overlapping Tag code regions. |
| 859 ASSERT(region->kind() != CodeRegion::kTagCode); |
| 732 // When code regions overlap, they should be of the same kind. | 860 // When code regions overlap, they should be of the same kind. |
| 733 ASSERT(region->kind() == code_region->kind()); | 861 ASSERT(region->kind() == code_region->kind()); |
| 734 region->AdjustExtent(start, end); | 862 region->AdjustExtent(start, end); |
| 735 } | 863 } |
| 736 | 864 |
| 737 #if defined(DEBUG) | 865 #if defined(DEBUG) |
| 738 void VerifyOrder() { | 866 void VerifyOrder() { |
| 739 const intptr_t length = code_region_table_->length(); | 867 const intptr_t length = code_region_table_->length(); |
| 740 if (length == 0) { | 868 if (length == 0) { |
| 741 return; | 869 return; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 764 #endif | 892 #endif |
| 765 | 893 |
| 766 ZoneGrowableArray<CodeRegion*>* code_region_table_; | 894 ZoneGrowableArray<CodeRegion*>* code_region_table_; |
| 767 }; | 895 }; |
| 768 | 896 |
| 769 | 897 |
| 770 class CodeRegionTableBuilder : public SampleVisitor { | 898 class CodeRegionTableBuilder : public SampleVisitor { |
| 771 public: | 899 public: |
| 772 CodeRegionTableBuilder(Isolate* isolate, | 900 CodeRegionTableBuilder(Isolate* isolate, |
| 773 CodeRegionTable* live_code_table, | 901 CodeRegionTable* live_code_table, |
| 774 CodeRegionTable* dead_code_table) | 902 CodeRegionTable* dead_code_table, |
| 903 CodeRegionTable* tag_code_table) |
| 775 : SampleVisitor(isolate), | 904 : SampleVisitor(isolate), |
| 776 live_code_table_(live_code_table), | 905 live_code_table_(live_code_table), |
| 777 dead_code_table_(dead_code_table), | 906 dead_code_table_(dead_code_table), |
| 907 tag_code_table_(tag_code_table), |
| 778 isolate_(isolate), | 908 isolate_(isolate), |
| 779 vm_isolate_(Dart::vm_isolate()) { | 909 vm_isolate_(Dart::vm_isolate()) { |
| 780 ASSERT(live_code_table_ != NULL); | 910 ASSERT(live_code_table_ != NULL); |
| 781 ASSERT(dead_code_table_ != NULL); | 911 ASSERT(dead_code_table_ != NULL); |
| 912 ASSERT(tag_code_table_ != NULL); |
| 782 frames_ = 0; | 913 frames_ = 0; |
| 783 min_time_ = kMaxInt64; | 914 min_time_ = kMaxInt64; |
| 784 max_time_ = 0; | 915 max_time_ = 0; |
| 785 ASSERT(isolate_ != NULL); | 916 ASSERT(isolate_ != NULL); |
| 786 ASSERT(vm_isolate_ != NULL); | 917 ASSERT(vm_isolate_ != NULL); |
| 787 } | 918 } |
| 788 | 919 |
| 789 void VisitSample(Sample* sample) { | 920 void VisitSample(Sample* sample) { |
| 790 int64_t timestamp = sample->timestamp(); | 921 int64_t timestamp = sample->timestamp(); |
| 791 if (timestamp > max_time_) { | 922 if (timestamp > max_time_) { |
| 792 max_time_ = timestamp; | 923 max_time_ = timestamp; |
| 793 } | 924 } |
| 794 if (timestamp < min_time_) { | 925 if (timestamp < min_time_) { |
| 795 min_time_ = timestamp; | 926 min_time_ = timestamp; |
| 796 } | 927 } |
| 928 // Make sure VM tag is created. |
| 929 CreateTag(sample->vm_tag()); |
| 797 // Exclusive tick for bottom frame. | 930 // Exclusive tick for bottom frame. |
| 798 Tick(sample->At(0), true, timestamp); | 931 Tick(sample->At(0), true, timestamp); |
| 799 // Inclusive tick for all frames. | 932 // Inclusive tick for all frames. |
| 800 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | 933 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 801 if (sample->At(i) == 0) { | 934 if (sample->At(i) == 0) { |
| 802 break; | 935 break; |
| 803 } | 936 } |
| 804 frames_++; | 937 frames_++; |
| 805 Tick(sample->At(i), false, timestamp); | 938 Tick(sample->At(i), false, timestamp); |
| 806 } | 939 } |
| 807 } | 940 } |
| 808 | 941 |
| 809 intptr_t frames() const { return frames_; } | 942 intptr_t frames() const { return frames_; } |
| 810 | 943 |
| 811 intptr_t TimeDeltaMicros() const { | 944 intptr_t TimeDeltaMicros() const { |
| 812 return static_cast<intptr_t>(max_time_ - min_time_); | 945 return static_cast<intptr_t>(max_time_ - min_time_); |
| 813 } | 946 } |
| 814 int64_t max_time() const { return max_time_; } | 947 int64_t max_time() const { return max_time_; } |
| 815 | 948 |
| 816 private: | 949 private: |
| 950 void CreateTag(uword tag) { |
| 951 intptr_t index = tag_code_table_->FindIndex(tag); |
| 952 if (index >= 0) { |
| 953 // Already created. |
| 954 return; |
| 955 } |
| 956 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, |
| 957 tag, |
| 958 tag + 1, |
| 959 0); |
| 960 index = tag_code_table_->InsertCodeRegion(region); |
| 961 ASSERT(index >= 0); |
| 962 region->set_creation_serial(visited()); |
| 963 } |
| 964 |
| 965 void TickTag(uword tag, bool exclusive) { |
| 966 CodeRegionTable::TickResult r; |
| 967 intptr_t serial = exclusive ? -1 : visited(); |
| 968 r = tag_code_table_->Tick(tag, exclusive, serial, 0); |
| 969 if (r == CodeRegionTable::kTicked) { |
| 970 // Live code found and ticked. |
| 971 return; |
| 972 } |
| 973 ASSERT(r == CodeRegionTable::kNotFound); |
| 974 CreateAndTickTagCodeRegion(tag, exclusive, serial); |
| 975 } |
| 976 |
| 977 void CreateAndTickTagCodeRegion(uword tag, bool exclusive, intptr_t serial) { |
| 978 // Need to create tag code. |
| 979 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, |
| 980 tag, |
| 981 tag + 1, |
| 982 0); |
| 983 intptr_t index = tag_code_table_->InsertCodeRegion(region); |
| 984 region->set_creation_serial(visited()); |
| 985 ASSERT(index >= 0); |
| 986 tag_code_table_->At(index)->Tick(tag, exclusive, serial); |
| 987 } |
| 988 |
| 817 void Tick(uword pc, bool exclusive, int64_t timestamp) { | 989 void Tick(uword pc, bool exclusive, int64_t timestamp) { |
| 818 CodeRegionTable::TickResult r; | 990 CodeRegionTable::TickResult r; |
| 819 intptr_t serial = exclusive ? -1 : visited(); | 991 intptr_t serial = exclusive ? -1 : visited(); |
| 820 r = live_code_table_->Tick(pc, exclusive, serial, timestamp); | 992 r = live_code_table_->Tick(pc, exclusive, serial, timestamp); |
| 821 if (r == CodeRegionTable::kTicked) { | 993 if (r == CodeRegionTable::kTicked) { |
| 822 // Live code found and ticked. | 994 // Live code found and ticked. |
| 823 return; | 995 return; |
| 824 } | 996 } |
| 825 if (r == CodeRegionTable::kNewerCode) { | 997 if (r == CodeRegionTable::kNewerCode) { |
| 826 // Code has been overwritten by newer code. | 998 // Code has been overwritten by newer code. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 906 code_region->SetName(native_name); | 1078 code_region->SetName(native_name); |
| 907 free(native_name); | 1079 free(native_name); |
| 908 return code_region; | 1080 return code_region; |
| 909 } | 1081 } |
| 910 | 1082 |
| 911 intptr_t frames_; | 1083 intptr_t frames_; |
| 912 int64_t min_time_; | 1084 int64_t min_time_; |
| 913 int64_t max_time_; | 1085 int64_t max_time_; |
| 914 CodeRegionTable* live_code_table_; | 1086 CodeRegionTable* live_code_table_; |
| 915 CodeRegionTable* dead_code_table_; | 1087 CodeRegionTable* dead_code_table_; |
| 1088 CodeRegionTable* tag_code_table_; |
| 916 Isolate* isolate_; | 1089 Isolate* isolate_; |
| 917 Isolate* vm_isolate_; | 1090 Isolate* vm_isolate_; |
| 918 }; | 1091 }; |
| 919 | 1092 |
| 920 | 1093 |
| 921 class CodeRegionTableCallersBuilder : public SampleVisitor { | 1094 class CodeRegionExclusiveTrieBuilder : public SampleVisitor { |
| 922 public: | 1095 public: |
| 923 CodeRegionTableCallersBuilder(Isolate* isolate, | 1096 CodeRegionExclusiveTrieBuilder(Isolate* isolate, |
| 924 CodeRegionTable* live_code_table, | 1097 CodeRegionTable* live_code_table, |
| 925 CodeRegionTable* dead_code_table) | 1098 CodeRegionTable* dead_code_table, |
| 1099 CodeRegionTable* tag_code_table) |
| 926 : SampleVisitor(isolate), | 1100 : SampleVisitor(isolate), |
| 927 live_code_table_(live_code_table), | 1101 live_code_table_(live_code_table), |
| 928 dead_code_table_(dead_code_table) { | 1102 dead_code_table_(dead_code_table), |
| 1103 tag_code_table_(tag_code_table) { |
| 929 ASSERT(live_code_table_ != NULL); | 1104 ASSERT(live_code_table_ != NULL); |
| 930 ASSERT(dead_code_table_ != NULL); | 1105 ASSERT(dead_code_table_ != NULL); |
| 1106 ASSERT(tag_code_table_ != NULL); |
| 931 dead_code_table_offset_ = live_code_table_->Length(); | 1107 dead_code_table_offset_ = live_code_table_->Length(); |
| 1108 tag_code_table_offset_ = dead_code_table_offset_ + |
| 1109 dead_code_table_->Length(); |
| 1110 intptr_t root_index = tag_code_table_->FindIndex(0); |
| 1111 // Verify that the "0" tag does not exist. |
| 1112 ASSERT(root_index < 0); |
| 1113 // Insert the dummy tag CodeRegion that is used for the Trie root. |
| 1114 CodeRegion* region = new CodeRegion(CodeRegion::kTagCode, 0, 1, 0); |
| 1115 root_index = tag_code_table_->InsertCodeRegion(region); |
| 1116 ASSERT(root_index >= 0); |
| 1117 region->set_creation_serial(0); |
| 1118 root_ = new CodeRegionTrieNode(tag_code_table_offset_ + root_index); |
| 1119 // Use tags by default. |
| 1120 set_use_tags(true); |
| 932 } | 1121 } |
| 933 | 1122 |
| 934 void VisitSample(Sample* sample) { | 1123 void VisitSample(Sample* sample) { |
| 935 int64_t timestamp = sample->timestamp(); | 1124 // Give the root a tick. |
| 936 intptr_t current_index = FindFinalIndex(sample->At(0), timestamp); | 1125 root_->Tick(); |
| 937 ASSERT(current_index >= 0); | 1126 CodeRegionTrieNode* current = root_; |
| 938 CodeRegion* current = At(current_index); | 1127 if (use_tags()) { |
| 939 intptr_t caller_index = -1; | 1128 intptr_t tag_index = FindTagIndex(sample->vm_tag()); |
| 940 CodeRegion* caller = NULL; | 1129 current = current->GetChild(tag_index); |
| 941 intptr_t callee_index = -1; | 1130 // Give the tag a tick. |
| 942 CodeRegion* callee = NULL; | 1131 current->Tick(); |
| 943 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { | 1132 } |
| 1133 // Walk the sampled PCs. |
| 1134 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 944 if (sample->At(i) == 0) { | 1135 if (sample->At(i) == 0) { |
| 945 break; | 1136 break; |
| 946 } | 1137 } |
| 947 caller_index = FindFinalIndex(sample->At(i), timestamp); | 1138 intptr_t index = FindFinalIndex(sample->At(i), sample->timestamp()); |
| 948 ASSERT(caller_index >= 0); | 1139 current = current->GetChild(index); |
| 949 caller = At(caller_index); | 1140 current->Tick(); |
| 950 current->AddCaller(caller_index); | |
| 951 if (callee != NULL) { | |
| 952 current->AddCallee(callee_index); | |
| 953 } | |
| 954 // Move cursors. | |
| 955 callee_index = current_index; | |
| 956 callee = current; | |
| 957 current_index = caller_index; | |
| 958 current = caller; | |
| 959 } | 1141 } |
| 960 } | 1142 } |
| 961 | 1143 |
| 1144 CodeRegionTrieNode* root() const { |
| 1145 return root_; |
| 1146 } |
| 1147 |
| 1148 bool use_tags() const { |
| 1149 return use_tags_; |
| 1150 } |
| 1151 |
| 1152 void set_use_tags(bool use_tags) { |
| 1153 use_tags_ = use_tags; |
| 1154 } |
| 1155 |
| 962 private: | 1156 private: |
| 1157 intptr_t FindTagIndex(uword tag) const { |
| 1158 intptr_t index = tag_code_table_->FindIndex(tag); |
| 1159 ASSERT(index >= 0); |
| 1160 ASSERT((tag_code_table_->At(index))->contains(tag)); |
| 1161 return tag_code_table_offset_ + index; |
| 1162 } |
| 1163 |
| 963 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const { | 1164 intptr_t FindFinalIndex(uword pc, int64_t timestamp) const { |
| 964 intptr_t index = live_code_table_->FindIndex(pc); | 1165 intptr_t index = live_code_table_->FindIndex(pc); |
| 965 ASSERT(index >= 0); | 1166 ASSERT(index >= 0); |
| 966 CodeRegion* region = live_code_table_->At(index); | 1167 CodeRegion* region = live_code_table_->At(index); |
| 967 ASSERT(region->contains(pc)); | 1168 ASSERT(region->contains(pc)); |
| 968 if (region->compile_timestamp() > timestamp) { | 1169 if (region->compile_timestamp() > timestamp) { |
| 969 // Overwritten code, find in dead code table. | 1170 // Overwritten code, find in dead code table. |
| 970 index = dead_code_table_->FindIndex(pc); | 1171 index = dead_code_table_->FindIndex(pc); |
| 971 ASSERT(index >= 0); | 1172 ASSERT(index >= 0); |
| 972 region = dead_code_table_->At(index); | 1173 region = dead_code_table_->At(index); |
| 973 ASSERT(region->contains(pc)); | 1174 ASSERT(region->contains(pc)); |
| 974 ASSERT(region->compile_timestamp() <= timestamp); | 1175 ASSERT(region->compile_timestamp() <= timestamp); |
| 975 return index + dead_code_table_offset_; | 1176 return index + dead_code_table_offset_; |
| 976 } | 1177 } |
| 977 ASSERT(region->compile_timestamp() <= timestamp); | 1178 ASSERT(region->compile_timestamp() <= timestamp); |
| 978 return index; | 1179 return index; |
| 979 } | 1180 } |
| 980 | 1181 |
| 1182 bool use_tags_; |
| 1183 CodeRegionTrieNode* root_; |
| 1184 CodeRegionTable* live_code_table_; |
| 1185 CodeRegionTable* dead_code_table_; |
| 1186 CodeRegionTable* tag_code_table_; |
| 1187 intptr_t dead_code_table_offset_; |
| 1188 intptr_t tag_code_table_offset_; |
| 1189 }; |
| 1190 |
| 1191 |
| 1192 class CodeRegionTableCallersBuilder { |
| 1193 public: |
| 1194 CodeRegionTableCallersBuilder(CodeRegionTrieNode* exclusive_root, |
| 1195 CodeRegionTable* live_code_table, |
| 1196 CodeRegionTable* dead_code_table, |
| 1197 CodeRegionTable* tag_code_table) |
| 1198 : exclusive_root_(exclusive_root), |
| 1199 live_code_table_(live_code_table), |
| 1200 dead_code_table_(dead_code_table), |
| 1201 tag_code_table_(tag_code_table) { |
| 1202 ASSERT(exclusive_root_ != NULL); |
| 1203 ASSERT(live_code_table_ != NULL); |
| 1204 ASSERT(dead_code_table_ != NULL); |
| 1205 ASSERT(tag_code_table_ != NULL); |
| 1206 dead_code_table_offset_ = live_code_table_->Length(); |
| 1207 tag_code_table_offset_ = dead_code_table_offset_ + |
| 1208 dead_code_table_->Length(); |
| 1209 } |
| 1210 |
| 1211 void Build() { |
| 1212 ProcessNode(exclusive_root_); |
| 1213 } |
| 1214 |
| 1215 private: |
| 1216 void ProcessNode(CodeRegionTrieNode* parent) { |
| 1217 const ZoneGrowableArray<CodeRegionTrieNode*>& children = parent->children(); |
| 1218 intptr_t parent_index = parent->code_region_index(); |
| 1219 ASSERT(parent_index >= 0); |
| 1220 CodeRegion* parent_region = At(parent_index); |
| 1221 ASSERT(parent_region != NULL); |
| 1222 for (intptr_t i = 0; i < children.length(); i++) { |
| 1223 CodeRegionTrieNode* node = children[i]; |
| 1224 ProcessNode(node); |
| 1225 intptr_t index = node->code_region_index(); |
| 1226 ASSERT(index >= 0); |
| 1227 CodeRegion* region = At(index); |
| 1228 ASSERT(region != NULL); |
| 1229 region->AddCallee(parent_index, node->count()); |
| 1230 parent_region->AddCaller(index, node->count()); |
| 1231 } |
| 1232 } |
| 1233 |
| 981 CodeRegion* At(intptr_t final_index) { | 1234 CodeRegion* At(intptr_t final_index) { |
| 982 ASSERT(final_index >= 0); | 1235 ASSERT(final_index >= 0); |
| 983 if (final_index < dead_code_table_offset_) { | 1236 if (final_index < dead_code_table_offset_) { |
| 984 return live_code_table_->At(final_index); | 1237 return live_code_table_->At(final_index); |
| 1238 } else if (final_index < tag_code_table_offset_) { |
| 1239 return dead_code_table_->At(final_index - dead_code_table_offset_); |
| 985 } else { | 1240 } else { |
| 986 return dead_code_table_->At(final_index - dead_code_table_offset_); | 1241 return tag_code_table_->At(final_index - tag_code_table_offset_); |
| 987 } | 1242 } |
| 988 } | 1243 } |
| 989 | 1244 |
| 1245 CodeRegionTrieNode* exclusive_root_; |
| 990 CodeRegionTable* live_code_table_; | 1246 CodeRegionTable* live_code_table_; |
| 991 CodeRegionTable* dead_code_table_; | 1247 CodeRegionTable* dead_code_table_; |
| 1248 CodeRegionTable* tag_code_table_; |
| 992 intptr_t dead_code_table_offset_; | 1249 intptr_t dead_code_table_offset_; |
| 1250 intptr_t tag_code_table_offset_; |
| 993 }; | 1251 }; |
| 994 | 1252 |
| 1253 |
| 995 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | 1254 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 996 bool full) { | 1255 bool full, bool use_tags) { |
| 997 ASSERT(isolate == Isolate::Current()); | 1256 ASSERT(isolate == Isolate::Current()); |
| 998 // Disable profile interrupts while processing the buffer. | 1257 // Disable profile interrupts while processing the buffer. |
| 999 EndExecution(isolate); | 1258 EndExecution(isolate); |
| 1000 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 1259 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 1001 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 1260 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 1002 if (profiler_data == NULL) { | 1261 if (profiler_data == NULL) { |
| 1003 JSONObject error(stream); | 1262 JSONObject error(stream); |
| 1004 error.AddProperty("type", "Error"); | 1263 error.AddProperty("type", "Error"); |
| 1005 error.AddProperty("text", "Isolate does not have profiling enabled."); | 1264 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 1006 return; | 1265 return; |
| 1007 } | 1266 } |
| 1008 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 1267 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 1009 ASSERT(sample_buffer != NULL); | 1268 ASSERT(sample_buffer != NULL); |
| 1010 { | 1269 { |
| 1011 StackZone zone(isolate); | 1270 StackZone zone(isolate); |
| 1012 { | 1271 { |
| 1013 // Live code holds Dart, Native, and Collected CodeRegions. | 1272 // Live code holds Dart, Native, and Collected CodeRegions. |
| 1014 CodeRegionTable live_code_table; | 1273 CodeRegionTable live_code_table; |
| 1015 // Dead code holds Overwritten CodeRegions. | 1274 // Dead code holds Overwritten CodeRegions. |
| 1016 CodeRegionTable dead_code_table; | 1275 CodeRegionTable dead_code_table; |
| 1276 // Tag code holds Tag CodeRegions. |
| 1277 CodeRegionTable tag_code_table; |
| 1017 CodeRegionTableBuilder builder(isolate, | 1278 CodeRegionTableBuilder builder(isolate, |
| 1018 &live_code_table, | 1279 &live_code_table, |
| 1019 &dead_code_table); | 1280 &dead_code_table, |
| 1281 &tag_code_table); |
| 1020 { | 1282 { |
| 1021 // Build CodeRegion tables. | 1283 // Build CodeRegion tables. |
| 1022 ScopeStopwatch sw("CodeTableBuild"); | 1284 ScopeStopwatch sw("CodeRegionTableBuilder"); |
| 1023 sample_buffer->VisitSamples(&builder); | 1285 sample_buffer->VisitSamples(&builder); |
| 1024 } | 1286 } |
| 1025 intptr_t samples = builder.visited(); | 1287 intptr_t samples = builder.visited(); |
| 1026 intptr_t frames = builder.frames(); | 1288 intptr_t frames = builder.frames(); |
| 1027 if (FLAG_trace_profiled_isolates) { | 1289 if (FLAG_trace_profiled_isolates) { |
| 1028 intptr_t total_live_code_objects = live_code_table.Length(); | 1290 intptr_t total_live_code_objects = live_code_table.Length(); |
| 1029 intptr_t total_dead_code_objects = dead_code_table.Length(); | 1291 intptr_t total_dead_code_objects = dead_code_table.Length(); |
| 1292 intptr_t total_tag_code_objects = tag_code_table.Length(); |
| 1030 OS::Print("Processed %" Pd " frames\n", frames); | 1293 OS::Print("Processed %" Pd " frames\n", frames); |
| 1031 OS::Print("CodeTables: live=%" Pd " dead=%" Pd "\n", | 1294 OS::Print("CodeTables: live=%" Pd " dead=%" Pd " tag=%" Pd "\n", |
| 1032 total_live_code_objects, | 1295 total_live_code_objects, |
| 1033 total_dead_code_objects); | 1296 total_dead_code_objects, |
| 1297 total_tag_code_objects); |
| 1034 } | 1298 } |
| 1035 #if defined(DEBUG) | 1299 #if defined(DEBUG) |
| 1036 live_code_table.Verify(); | 1300 live_code_table.Verify(); |
| 1037 dead_code_table.Verify(); | 1301 dead_code_table.Verify(); |
| 1302 tag_code_table.Verify(); |
| 1038 if (FLAG_trace_profiled_isolates) { | 1303 if (FLAG_trace_profiled_isolates) { |
| 1039 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); | 1304 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n"); |
| 1040 } | 1305 } |
| 1041 #endif | 1306 #endif |
| 1042 CodeRegionTableCallersBuilder build_callers(isolate, | 1307 CodeRegionExclusiveTrieBuilder build_trie(isolate, |
| 1308 &live_code_table, |
| 1309 &dead_code_table, |
| 1310 &tag_code_table); |
| 1311 build_trie.set_use_tags(use_tags); |
| 1312 { |
| 1313 // Build CodeRegion trie. |
| 1314 ScopeStopwatch sw("CodeRegionExclusiveTrieBuilder"); |
| 1315 sample_buffer->VisitSamples(&build_trie); |
| 1316 build_trie.root()->SortByCount(); |
| 1317 } |
| 1318 CodeRegionTableCallersBuilder build_callers(build_trie.root(), |
| 1043 &live_code_table, | 1319 &live_code_table, |
| 1044 &dead_code_table); | 1320 &dead_code_table, |
| 1321 &tag_code_table); |
| 1045 { | 1322 { |
| 1046 // Build CodeRegion callers. | 1323 // Build CodeRegion callers. |
| 1047 ScopeStopwatch sw("CodeTableCallersBuild"); | 1324 ScopeStopwatch sw("CodeRegionTableCallersBuilder"); |
| 1048 sample_buffer->VisitSamples(&build_callers); | 1325 build_callers.Build(); |
| 1049 } | 1326 } |
| 1050 { | 1327 { |
| 1051 ScopeStopwatch sw("CodeTableStream"); | 1328 ScopeStopwatch sw("CodeTableStream"); |
| 1052 // Serialize to JSON. | 1329 // Serialize to JSON. |
| 1053 JSONObject obj(stream); | 1330 JSONObject obj(stream); |
| 1054 obj.AddProperty("type", "Profile"); | 1331 obj.AddProperty("type", "Profile"); |
| 1055 obj.AddProperty("id", "profile"); | 1332 obj.AddProperty("id", "profile"); |
| 1056 obj.AddProperty("samples", samples); | 1333 obj.AddProperty("samples", samples); |
| 1334 obj.AddProperty("depth", static_cast<intptr_t>(FLAG_profile_depth)); |
| 1335 obj.AddProperty("period", static_cast<intptr_t>(FLAG_profile_period)); |
| 1057 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros()); | 1336 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros()); |
| 1337 { |
| 1338 JSONArray exclusive_trie(&obj, "exclusive_trie"); |
| 1339 CodeRegionTrieNode* root = build_trie.root(); |
| 1340 ASSERT(root != NULL); |
| 1341 root->PrintToJSONArray(&exclusive_trie); |
| 1342 } |
| 1058 JSONArray codes(&obj, "codes"); | 1343 JSONArray codes(&obj, "codes"); |
| 1059 for (intptr_t i = 0; i < live_code_table.Length(); i++) { | 1344 for (intptr_t i = 0; i < live_code_table.Length(); i++) { |
| 1060 CodeRegion* region = live_code_table.At(i); | 1345 CodeRegion* region = live_code_table.At(i); |
| 1061 ASSERT(region != NULL); | 1346 ASSERT(region != NULL); |
| 1062 region->PrintToJSONArray(isolate, &codes, full); | 1347 region->PrintToJSONArray(isolate, &codes, full); |
| 1063 } | 1348 } |
| 1064 for (intptr_t i = 0; i < dead_code_table.Length(); i++) { | 1349 for (intptr_t i = 0; i < dead_code_table.Length(); i++) { |
| 1065 CodeRegion* region = dead_code_table.At(i); | 1350 CodeRegion* region = dead_code_table.At(i); |
| 1066 ASSERT(region != NULL); | 1351 ASSERT(region != NULL); |
| 1067 region->PrintToJSONArray(isolate, &codes, full); | 1352 region->PrintToJSONArray(isolate, &codes, full); |
| 1068 } | 1353 } |
| 1354 for (intptr_t i = 0; i < tag_code_table.Length(); i++) { |
| 1355 CodeRegion* region = tag_code_table.At(i); |
| 1356 ASSERT(region != NULL); |
| 1357 region->PrintToJSONArray(isolate, &codes, full); |
| 1358 } |
| 1069 } | 1359 } |
| 1070 } | 1360 } |
| 1071 } | 1361 } |
| 1072 // Enable profile interrupts. | 1362 // Enable profile interrupts. |
| 1073 BeginExecution(isolate); | 1363 BeginExecution(isolate); |
| 1074 } | 1364 } |
| 1075 | 1365 |
| 1076 | 1366 |
| 1077 void Profiler::WriteProfile(Isolate* isolate) { | 1367 void Profiler::WriteProfile(Isolate* isolate) { |
| 1078 if (isolate == NULL) { | 1368 if (isolate == NULL) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1089 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 1379 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
| 1090 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 1380 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
| 1091 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { | 1381 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { |
| 1092 // Embedder has not provided necessary callbacks. | 1382 // Embedder has not provided necessary callbacks. |
| 1093 return; | 1383 return; |
| 1094 } | 1384 } |
| 1095 // We will be looking up code objects within the isolate. | 1385 // We will be looking up code objects within the isolate. |
| 1096 ASSERT(Isolate::Current() == isolate); | 1386 ASSERT(Isolate::Current() == isolate); |
| 1097 JSONStream stream(10 * MB); | 1387 JSONStream stream(10 * MB); |
| 1098 intptr_t pid = OS::ProcessId(); | 1388 intptr_t pid = OS::ProcessId(); |
| 1099 PrintToJSONStream(isolate, &stream, true); | 1389 PrintToJSONStream(isolate, &stream, true, false); |
| 1100 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; | 1390 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; |
| 1101 intptr_t len = OS::SNPrint(NULL, 0, format, | 1391 intptr_t len = OS::SNPrint(NULL, 0, format, |
| 1102 FLAG_profile_dir, pid, isolate->main_port()); | 1392 FLAG_profile_dir, pid, isolate->main_port()); |
| 1103 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 1393 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 1104 OS::SNPrint(filename, len + 1, format, | 1394 OS::SNPrint(filename, len + 1, format, |
| 1105 FLAG_profile_dir, pid, isolate->main_port()); | 1395 FLAG_profile_dir, pid, isolate->main_port()); |
| 1106 void* f = file_open(filename, true); | 1396 void* f = file_open(filename, true); |
| 1107 if (f == NULL) { | 1397 if (f == NULL) { |
| 1108 // Cannot write. | 1398 // Cannot write. |
| 1109 return; | 1399 return; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 uword sp) | 1448 uword sp) |
| 1159 : sample_(sample), | 1449 : sample_(sample), |
| 1160 stack_upper_(stack_upper), | 1450 stack_upper_(stack_upper), |
| 1161 original_pc_(pc), | 1451 original_pc_(pc), |
| 1162 original_fp_(fp), | 1452 original_fp_(fp), |
| 1163 original_sp_(sp), | 1453 original_sp_(sp), |
| 1164 lower_bound_(stack_lower) { | 1454 lower_bound_(stack_lower) { |
| 1165 ASSERT(sample_ != NULL); | 1455 ASSERT(sample_ != NULL); |
| 1166 } | 1456 } |
| 1167 | 1457 |
| 1168 int walk(Heap* heap) { | 1458 int walk(Heap* heap, uword vm_tag) { |
| 1169 const intptr_t kMaxStep = 0x1000; // 4K. | 1459 const intptr_t kMaxStep = 0x1000; // 4K. |
| 1170 const bool kWalkStack = true; // Walk the stack. | 1460 const bool kWalkStack = true; // Walk the stack. |
| 1171 // Always store the exclusive PC. | 1461 // Always store the exclusive PC. |
| 1172 sample_->SetAt(0, original_pc_); | 1462 sample_->SetAt(0, original_pc_); |
| 1463 // Always store the vm tag. |
| 1464 sample_->set_vm_tag(vm_tag); |
| 1173 if (!kWalkStack) { | 1465 if (!kWalkStack) { |
| 1174 // Not walking the stack, only took exclusive sample. | 1466 // Not walking the stack, only took exclusive sample. |
| 1175 return 1; | 1467 return 1; |
| 1176 } | 1468 } |
| 1177 uword* pc = reinterpret_cast<uword*>(original_pc_); | 1469 uword* pc = reinterpret_cast<uword*>(original_pc_); |
| 1178 uword* fp = reinterpret_cast<uword*>(original_fp_); | 1470 uword* fp = reinterpret_cast<uword*>(original_fp_); |
| 1179 uword* previous_fp = fp; | 1471 uword* previous_fp = fp; |
| 1180 if (original_sp_ > original_fp_) { | 1472 if (original_sp_ > original_fp_) { |
| 1181 // Stack pointer should not be above frame pointer. | 1473 // Stack pointer should not be above frame pointer. |
| 1182 return 1; | 1474 return 1; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1280 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 1572 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| 1281 uword stack_lower = 0; | 1573 uword stack_lower = 0; |
| 1282 uword stack_upper = 0; | 1574 uword stack_upper = 0; |
| 1283 isolate->GetStackBounds(&stack_lower, &stack_upper); | 1575 isolate->GetStackBounds(&stack_lower, &stack_upper); |
| 1284 if ((stack_lower == 0) || (stack_upper == 0)) { | 1576 if ((stack_lower == 0) || (stack_upper == 0)) { |
| 1285 stack_lower = 0; | 1577 stack_lower = 0; |
| 1286 stack_upper = 0; | 1578 stack_upper = 0; |
| 1287 } | 1579 } |
| 1288 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 1580 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 1289 state.pc, state.fp, state.sp); | 1581 state.pc, state.fp, state.sp); |
| 1290 stackWalker.walk(isolate->heap()); | 1582 stackWalker.walk(isolate->heap(), isolate->vm_tag()); |
| 1291 } | 1583 } |
| 1292 | 1584 |
| 1293 | 1585 |
| 1294 } // namespace dart | 1586 } // namespace dart |
| OLD | NEW |