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