| 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" |
| 11 #include "vm/json_stream.h" | 11 #include "vm/json_stream.h" |
| 12 #include "vm/native_symbol.h" | 12 #include "vm/native_symbol.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 #include "vm/os.h" | 14 #include "vm/os.h" |
| 15 #include "vm/profiler.h" | 15 #include "vm/profiler.h" |
| 16 #include "vm/signal_handler.h" | 16 #include "vm/signal_handler.h" |
| 17 #include "vm/simulator.h" | 17 #include "vm/simulator.h" |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| 20 | 20 |
| 21 | 21 |
| 22 // Notes on stack frame walking: | |
| 23 // | |
| 24 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames | |
| 25 // The stack frame walking code uses the frame pointer to traverse the stack. | |
| 26 // If the VM is compiled without frame pointers (which is the default on | |
| 27 // recent GCC versions with optimizing enabled) the stack walking code may | |
| 28 // fail (sometimes leading to a crash). | |
| 29 // | |
| 30 | |
| 31 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \ | 22 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \ |
| 32 defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID) | 23 defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID) |
| 33 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); | 24 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); |
| 34 #else | 25 #else |
| 35 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); | 26 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); |
| 36 #endif | 27 #endif |
| 37 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); | 28 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); |
| 38 DEFINE_FLAG(charp, profile_dir, NULL, | 29 DEFINE_FLAG(charp, profile_dir, NULL, |
| 39 "Enable writing profile data into specified directory."); | 30 "Enable writing profile data into specified directory."); |
| 40 DEFINE_FLAG(int, profile_period, 1000, | 31 DEFINE_FLAG(int, profile_period, 1000, |
| 41 "Time between profiler samples in microseconds. Minimum 250."); | 32 "Time between profiler samples in microseconds. Minimum 250."); |
| 33 DEFINE_FLAG(int, profile_depth, 8, |
| 34 "Maximum number stack frames walked. Minimum 1. Maximum 128."); |
| 42 | 35 |
| 43 bool Profiler::initialized_ = false; | 36 bool Profiler::initialized_ = false; |
| 44 Monitor* Profiler::monitor_ = NULL; | |
| 45 SampleBuffer* Profiler::sample_buffer_ = NULL; | 37 SampleBuffer* Profiler::sample_buffer_ = NULL; |
| 46 | 38 |
| 47 void Profiler::InitOnce() { | 39 void Profiler::InitOnce() { |
| 48 const int kMinimumProfilePeriod = 250; | 40 const int kMinimumProfilePeriod = 250; |
| 41 const int kMinimumDepth = 1; |
| 42 const int kMaximumDepth = 128; |
| 49 if (!FLAG_profile) { | 43 if (!FLAG_profile) { |
| 50 return; | 44 return; |
| 51 } | 45 } |
| 52 ASSERT(!initialized_); | 46 ASSERT(!initialized_); |
| 53 initialized_ = true; | 47 // Place some sane restrictions on user controlled flags. |
| 54 monitor_ = new Monitor(); | 48 if (FLAG_profile_period < kMinimumProfilePeriod) { |
| 49 FLAG_profile_period = kMinimumProfilePeriod; |
| 50 } |
| 51 if (FLAG_profile_depth < kMinimumDepth) { |
| 52 FLAG_profile_depth = kMinimumDepth; |
| 53 } else if (FLAG_profile_depth > kMaximumDepth) { |
| 54 FLAG_profile_depth = kMaximumDepth; |
| 55 } |
| 56 Sample::InitOnce(); |
| 55 sample_buffer_ = new SampleBuffer(); | 57 sample_buffer_ = new SampleBuffer(); |
| 56 NativeSymbolResolver::InitOnce(); | 58 NativeSymbolResolver::InitOnce(); |
| 57 ThreadInterrupter::InitOnce(); | 59 ThreadInterrupter::InitOnce(); |
| 58 if (FLAG_profile_period < kMinimumProfilePeriod) { | |
| 59 FLAG_profile_period = kMinimumProfilePeriod; | |
| 60 } | |
| 61 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); | 60 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); |
| 61 initialized_ = true; |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 void Profiler::Shutdown() { | 65 void Profiler::Shutdown() { |
| 66 if (!FLAG_profile) { | 66 if (!FLAG_profile) { |
| 67 return; | 67 return; |
| 68 } | 68 } |
| 69 ASSERT(initialized_); | 69 ASSERT(initialized_); |
| 70 ThreadInterrupter::Shutdown(); | 70 ThreadInterrupter::Shutdown(); |
| 71 NativeSymbolResolver::ShutdownOnce(); | 71 NativeSymbolResolver::ShutdownOnce(); |
| 72 } | 72 } |
| 73 | 73 |
| 74 | 74 |
| 75 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) { | 75 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) { |
| 76 if (!FLAG_profile) { | 76 if (!FLAG_profile) { |
| 77 return; | 77 return; |
| 78 } | 78 } |
| 79 ASSERT(isolate != NULL); | 79 ASSERT(isolate != NULL); |
| 80 ASSERT(sample_buffer_ != NULL); | 80 ASSERT(sample_buffer_ != NULL); |
| 81 MonitorLocker ml(monitor_); | |
| 82 { | 81 { |
| 83 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 82 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 84 SampleBuffer* sample_buffer = sample_buffer_; | 83 SampleBuffer* sample_buffer = sample_buffer_; |
| 85 if (!shared_buffer) { | 84 if (!shared_buffer) { |
| 86 sample_buffer = new SampleBuffer(); | 85 sample_buffer = new SampleBuffer(); |
| 87 } | 86 } |
| 88 IsolateProfilerData* profiler_data = | 87 IsolateProfilerData* profiler_data = |
| 89 new IsolateProfilerData(sample_buffer, !shared_buffer); | 88 new IsolateProfilerData(sample_buffer, !shared_buffer); |
| 90 ASSERT(profiler_data != NULL); | 89 ASSERT(profiler_data != NULL); |
| 91 isolate->set_profiler_data(profiler_data); | 90 isolate->set_profiler_data(profiler_data); |
| 92 if (FLAG_trace_profiled_isolates) { | 91 if (FLAG_trace_profiled_isolates) { |
| 93 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name()); | 92 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name()); |
| 94 } | 93 } |
| 95 } | 94 } |
| 96 } | 95 } |
| 97 | 96 |
| 98 | 97 |
| 99 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) { | 98 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) { |
| 100 ASSERT(isolate != NULL); | 99 ASSERT(isolate != NULL); |
| 101 if (!FLAG_profile) { | 100 if (!FLAG_profile) { |
| 102 return; | 101 return; |
| 103 } | 102 } |
| 104 // We do not have a current isolate. | 103 // We do not have a current isolate. |
| 105 ASSERT(Isolate::Current() == NULL); | 104 ASSERT(Isolate::Current() == NULL); |
| 106 MonitorLocker ml(monitor_); | |
| 107 { | 105 { |
| 108 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 106 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 109 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 107 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 110 if (profiler_data == NULL) { | 108 if (profiler_data == NULL) { |
| 111 // Already freed. | 109 // Already freed. |
| 112 return; | 110 return; |
| 113 } | 111 } |
| 114 isolate->set_profiler_data(NULL); | 112 isolate->set_profiler_data(NULL); |
| 115 delete profiler_data; | 113 delete profiler_data; |
| 116 if (FLAG_trace_profiled_isolates) { | 114 if (FLAG_trace_profiled_isolates) { |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 // Enable profile interrupts. | 531 // Enable profile interrupts. |
| 534 BeginExecution(isolate); | 532 BeginExecution(isolate); |
| 535 } | 533 } |
| 536 | 534 |
| 537 | 535 |
| 538 intptr_t Profiler::ProcessSamples(Isolate* isolate, | 536 intptr_t Profiler::ProcessSamples(Isolate* isolate, |
| 539 ProfilerCodeRegionTable* code_region_table, | 537 ProfilerCodeRegionTable* code_region_table, |
| 540 SampleBuffer* sample_buffer) { | 538 SampleBuffer* sample_buffer) { |
| 541 int64_t start = OS::GetCurrentTimeMillis(); | 539 int64_t start = OS::GetCurrentTimeMillis(); |
| 542 intptr_t samples = 0; | 540 intptr_t samples = 0; |
| 541 Sample* sample = Sample::Allocate(); |
| 543 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { | 542 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { |
| 544 Sample sample = sample_buffer->GetSample(i); | 543 sample_buffer->CopySample(i, sample); |
| 545 if (sample.isolate != isolate) { | 544 if (sample->isolate() != isolate) { |
| 546 continue; | 545 continue; |
| 547 } | 546 } |
| 548 if (sample.timestamp == 0) { | 547 if (sample->timestamp() == 0) { |
| 549 continue; | 548 continue; |
| 550 } | 549 } |
| 551 samples += ProcessSample(isolate, code_region_table, &sample); | 550 samples += ProcessSample(isolate, code_region_table, sample); |
| 552 } | 551 } |
| 552 free(sample); |
| 553 int64_t end = OS::GetCurrentTimeMillis(); | 553 int64_t end = OS::GetCurrentTimeMillis(); |
| 554 if (FLAG_trace_profiled_isolates) { | 554 if (FLAG_trace_profiled_isolates) { |
| 555 int64_t delta = end - start; | 555 int64_t delta = end - start; |
| 556 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", | 556 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", |
| 557 samples, | 557 samples, |
| 558 isolate->name(), | 558 isolate->name(), |
| 559 delta); | 559 delta); |
| 560 } | 560 } |
| 561 return samples; | 561 return samples; |
| 562 } | 562 } |
| 563 | 563 |
| 564 | 564 |
| 565 intptr_t Profiler::ProcessSample(Isolate* isolate, | 565 intptr_t Profiler::ProcessSample(Isolate* isolate, |
| 566 ProfilerCodeRegionTable* code_region_table, | 566 ProfilerCodeRegionTable* code_region_table, |
| 567 Sample* sample) { | 567 Sample* sample) { |
| 568 Sample::SampleType type = sample->type; | 568 if (sample->type() != Sample::kIsolateSample) { |
| 569 if (type != Sample::kIsolateSample) { | |
| 570 return 0; | 569 return 0; |
| 571 } | 570 } |
| 572 if (sample->pcs[0] == 0) { | 571 if (sample->At(0) == 0) { |
| 573 // No frames in this sample. | 572 // No frames in this sample. |
| 574 return 0; | 573 return 0; |
| 575 } | 574 } |
| 576 intptr_t i = 0; | |
| 577 // i points to the leaf (exclusive) PC sample. Do not tick the address. | 575 // i points to the leaf (exclusive) PC sample. Do not tick the address. |
| 578 code_region_table->AddTick(sample->pcs[i], true, false); | 576 code_region_table->AddTick(sample->At(0), true, false); |
| 579 // Give all frames an inclusive tick and tick the address. | 577 // Give all frames an inclusive tick and tick the address. |
| 580 for (; i < Sample::kNumStackFrames; i++) { | 578 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 581 if (sample->pcs[i] == 0) { | 579 if (sample->At(i) == 0) { |
| 582 break; | 580 break; |
| 583 } | 581 } |
| 584 code_region_table->AddTick(sample->pcs[i], false, true); | 582 code_region_table->AddTick(sample->At(i), false, true); |
| 585 } | 583 } |
| 586 return 1; | 584 return 1; |
| 587 } | 585 } |
| 588 | 586 |
| 589 | 587 |
| 590 void Profiler::WriteProfile(Isolate* isolate) { | 588 void Profiler::WriteProfile(Isolate* isolate) { |
| 591 if (isolate == NULL) { | 589 if (isolate == NULL) { |
| 592 return; | 590 return; |
| 593 } | 591 } |
| 594 if (!FLAG_profile) { | 592 if (!FLAG_profile) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 | 636 |
| 639 IsolateProfilerData::~IsolateProfilerData() { | 637 IsolateProfilerData::~IsolateProfilerData() { |
| 640 if (own_sample_buffer_) { | 638 if (own_sample_buffer_) { |
| 641 delete sample_buffer_; | 639 delete sample_buffer_; |
| 642 sample_buffer_ = NULL; | 640 sample_buffer_ = NULL; |
| 643 own_sample_buffer_ = false; | 641 own_sample_buffer_ = false; |
| 644 } | 642 } |
| 645 } | 643 } |
| 646 | 644 |
| 647 | 645 |
| 646 intptr_t Sample::instance_size_ = 0; |
| 647 |
| 648 void Sample::InitOnce() { |
| 649 ASSERT(FLAG_profile_depth >= 1); |
| 650 instance_size_ = |
| 651 sizeof(Sample) + (sizeof(intptr_t) * FLAG_profile_depth); // NOLINT. |
| 652 } |
| 653 |
| 654 |
| 655 uintptr_t Sample::At(intptr_t i) const { |
| 656 ASSERT(i >= 0); |
| 657 ASSERT(i < FLAG_profile_depth); |
| 658 return pcs_[i]; |
| 659 } |
| 660 |
| 661 |
| 662 void Sample::SetAt(intptr_t i, uintptr_t pc) { |
| 663 ASSERT(i >= 0); |
| 664 ASSERT(i < FLAG_profile_depth); |
| 665 pcs_[i] = pc; |
| 666 } |
| 667 |
| 668 |
| 648 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, | 669 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, |
| 649 ThreadId tid) { | 670 ThreadId tid) { |
| 650 this->timestamp = timestamp; | 671 timestamp_ = timestamp; |
| 651 this->tid = tid; | 672 tid_ = tid; |
| 652 this->isolate = isolate; | 673 isolate_ = isolate; |
| 653 for (intptr_t i = 0; i < kNumStackFrames; i++) { | 674 type_ = type; |
| 654 pcs[i] = 0; | 675 for (int i = 0; i < FLAG_profile_depth; i++) { |
| 676 pcs_[i] = 0; |
| 655 } | 677 } |
| 656 this->type = type; | |
| 657 vm_tags = 0; | |
| 658 runtime_tags = 0; | |
| 659 } | 678 } |
| 660 | 679 |
| 680 |
| 681 void Sample::CopyInto(Sample* dst) const { |
| 682 ASSERT(dst != NULL); |
| 683 dst->timestamp_ = timestamp_; |
| 684 dst->tid_ = tid_; |
| 685 dst->isolate_ = isolate_; |
| 686 dst->type_ = type_; |
| 687 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 688 dst->pcs_[i] = pcs_[i]; |
| 689 } |
| 690 } |
| 691 |
| 692 |
| 693 Sample* Sample::Allocate() { |
| 694 return reinterpret_cast<Sample*>(malloc(instance_size())); |
| 695 } |
| 696 |
| 697 |
| 661 SampleBuffer::SampleBuffer(intptr_t capacity) { | 698 SampleBuffer::SampleBuffer(intptr_t capacity) { |
| 662 capacity_ = capacity; | 699 capacity_ = capacity; |
| 663 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample))); | 700 samples_ = reinterpret_cast<Sample*>( |
| 701 calloc(capacity, Sample::instance_size())); |
| 664 cursor_ = 0; | 702 cursor_ = 0; |
| 665 } | 703 } |
| 666 | 704 |
| 667 | 705 |
| 668 SampleBuffer::~SampleBuffer() { | 706 SampleBuffer::~SampleBuffer() { |
| 669 if (samples_ != NULL) { | 707 if (samples_ != NULL) { |
| 670 free(samples_); | 708 free(samples_); |
| 671 samples_ = NULL; | 709 samples_ = NULL; |
| 672 cursor_ = 0; | 710 cursor_ = 0; |
| 673 capacity_ = 0; | 711 capacity_ = 0; |
| 674 } | 712 } |
| 675 } | 713 } |
| 676 | 714 |
| 677 | 715 |
| 678 Sample* SampleBuffer::ReserveSample() { | 716 Sample* SampleBuffer::ReserveSample() { |
| 679 ASSERT(samples_ != NULL); | 717 ASSERT(samples_ != NULL); |
| 680 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 718 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
| 681 // Map back into sample buffer range. | 719 // Map back into sample buffer range. |
| 682 cursor = cursor % capacity_; | 720 cursor = cursor % capacity_; |
| 683 return &samples_[cursor]; | 721 return At(cursor); |
| 684 } | 722 } |
| 685 | 723 |
| 686 | 724 |
| 725 void SampleBuffer::CopySample(intptr_t i, Sample* sample) const { |
| 726 At(i)->CopyInto(sample); |
| 727 } |
| 728 |
| 729 |
| 730 Sample* SampleBuffer::At(intptr_t idx) const { |
| 731 ASSERT(idx >= 0); |
| 732 ASSERT(idx < capacity_); |
| 733 intptr_t offset = idx * Sample::instance_size(); |
| 734 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); |
| 735 return reinterpret_cast<Sample*>(samples + offset); |
| 736 } |
| 737 |
| 738 |
| 687 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, | 739 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, |
| 688 uintptr_t stack_lower, | 740 uintptr_t stack_lower, |
| 689 uintptr_t stack_upper, | 741 uintptr_t stack_upper, |
| 690 uintptr_t pc, | 742 uintptr_t pc, |
| 691 uintptr_t fp, | 743 uintptr_t fp, |
| 692 uintptr_t sp) : | 744 uintptr_t sp) : |
| 693 sample_(sample), | 745 sample_(sample), |
| 694 stack_lower_(stack_lower), | 746 stack_lower_(stack_lower), |
| 695 stack_upper_(stack_upper), | 747 stack_upper_(stack_upper), |
| 696 original_pc_(pc), | 748 original_pc_(pc), |
| 697 original_fp_(fp), | 749 original_fp_(fp), |
| 698 original_sp_(sp), | 750 original_sp_(sp), |
| 699 lower_bound_(stack_lower) { | 751 lower_bound_(stack_lower) { |
| 700 ASSERT(sample_ != NULL); | 752 ASSERT(sample_ != NULL); |
| 701 // Zero out the PCs before (re)using the sample. | |
| 702 for (int i = 0; i < Sample::kNumStackFrames; i++) { | |
| 703 sample_->pcs[i] = 0; | |
| 704 } | |
| 705 } | 753 } |
| 706 | 754 |
| 707 | 755 |
| 756 // Notes on stack frame walking: |
| 757 // |
| 758 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames |
| 759 // The stack frame walking code uses the frame pointer to traverse the stack. |
| 760 // If the VM is compiled without frame pointers (which is the default on |
| 761 // recent GCC versions with optimizing enabled) the stack walking code may |
| 762 // fail (sometimes leading to a crash). |
| 763 // |
| 764 |
| 708 int ProfilerSampleStackWalker::walk() { | 765 int ProfilerSampleStackWalker::walk() { |
| 709 const intptr_t kMaxStep = 0x1000; // 4K. | 766 const intptr_t kMaxStep = 0x1000; // 4K. |
| 767 const bool kWalkStack = true; // Walk the stack. |
| 768 // Always store the exclusive PC. |
| 769 sample_->SetAt(0, original_pc_); |
| 770 if (!kWalkStack) { |
| 771 // Not walking the stack, only took exclusive sample. |
| 772 return 1; |
| 773 } |
| 710 uword* pc = reinterpret_cast<uword*>(original_pc_); | 774 uword* pc = reinterpret_cast<uword*>(original_pc_); |
| 711 // Always store the exclusive PC. | |
| 712 sample_->pcs[0] = original_pc_; | |
| 713 #define WALK_STACK | |
| 714 #if defined(WALK_STACK) | |
| 715 uword* fp = reinterpret_cast<uword*>(original_fp_); | 775 uword* fp = reinterpret_cast<uword*>(original_fp_); |
| 716 uword* previous_fp = fp; | 776 uword* previous_fp = fp; |
| 717 if (original_sp_ > original_fp_) { | 777 if (original_sp_ > original_fp_) { |
| 718 // Stack pointer should not be above frame pointer. | 778 // Stack pointer should not be above frame pointer. |
| 719 return 1; | 779 return 1; |
| 720 } | 780 } |
| 721 intptr_t gap = original_fp_ - original_sp_; | 781 intptr_t gap = original_fp_ - original_sp_; |
| 722 if (gap >= kMaxStep) { | 782 if (gap >= kMaxStep) { |
| 723 // Gap between frame pointer and stack pointer is | 783 // Gap between frame pointer and stack pointer is |
| 724 // too large. | 784 // too large. |
| 725 return 1; | 785 return 1; |
| 726 } | 786 } |
| 727 if (original_sp_ < lower_bound_) { | 787 if (original_sp_ < lower_bound_) { |
| 728 // The stack pointer gives us a better lower bound than | 788 // The stack pointer gives us a better lower bound than |
| 729 // the isolates stack limit. | 789 // the isolates stack limit. |
| 730 lower_bound_ = original_sp_; | 790 lower_bound_ = original_sp_; |
| 731 } | 791 } |
| 732 int i = 0; | 792 int i = 0; |
| 733 for (; i < Sample::kNumStackFrames; i++) { | 793 for (; i < FLAG_profile_depth; i++) { |
| 734 sample_->pcs[i] = reinterpret_cast<uintptr_t>(pc); | 794 sample_->SetAt(i, reinterpret_cast<uintptr_t>(pc)); |
| 735 if (!ValidFramePointer(fp)) { | 795 if (!ValidFramePointer(fp)) { |
| 736 return i + 1; | 796 return i + 1; |
| 737 } | 797 } |
| 738 pc = CallerPC(fp); | 798 pc = CallerPC(fp); |
| 739 previous_fp = fp; | 799 previous_fp = fp; |
| 740 fp = CallerFP(fp); | 800 fp = CallerFP(fp); |
| 741 intptr_t step = fp - previous_fp; | 801 intptr_t step = fp - previous_fp; |
| 742 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { | 802 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { |
| 743 // Frame pointer step is too large. | 803 // Frame pointer step is too large. |
| 744 // Frame pointer did not move to a higher address. | 804 // Frame pointer did not move to a higher address. |
| 745 // Frame pointer is outside of isolate stack bounds. | 805 // Frame pointer is outside of isolate stack bounds. |
| 746 return i + 1; | 806 return i + 1; |
| 747 } | 807 } |
| 748 // Move the lower bound up. | 808 // Move the lower bound up. |
| 749 lower_bound_ = reinterpret_cast<uintptr_t>(fp); | 809 lower_bound_ = reinterpret_cast<uintptr_t>(fp); |
| 750 } | 810 } |
| 751 return i; | 811 return i; |
| 752 #else | |
| 753 sample_->pcs[0] = reinterpret_cast<uintptr_t>(pc); | |
| 754 return 0; | |
| 755 #endif | |
| 756 } | 812 } |
| 757 | 813 |
| 758 | 814 |
| 759 uword* ProfilerSampleStackWalker::CallerPC(uword* fp) { | 815 uword* ProfilerSampleStackWalker::CallerPC(uword* fp) { |
| 760 ASSERT(fp != NULL); | 816 ASSERT(fp != NULL); |
| 761 return reinterpret_cast<uword*>(*(fp + 1)); | 817 return reinterpret_cast<uword*>(*(fp + 1)); |
| 762 } | 818 } |
| 763 | 819 |
| 764 | 820 |
| 765 uword* ProfilerSampleStackWalker::CallerFP(uword* fp) { | 821 uword* ProfilerSampleStackWalker::CallerFP(uword* fp) { |
| 766 ASSERT(fp != NULL); | 822 ASSERT(fp != NULL); |
| 767 return reinterpret_cast<uword*>(*fp); | 823 return reinterpret_cast<uword*>(*fp); |
| 768 } | 824 } |
| 769 | 825 |
| 770 | 826 |
| 771 bool ProfilerSampleStackWalker::ValidFramePointer(uword* fp) { | 827 bool ProfilerSampleStackWalker::ValidFramePointer(uword* fp) { |
| 772 if (fp == NULL) { | 828 if (fp == NULL) { |
| 773 return false; | 829 return false; |
| 774 } | 830 } |
| 775 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); | 831 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
| 776 cursor += sizeof(fp); | 832 cursor += sizeof(fp); |
| 777 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 833 bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
| 778 return r; | 834 return r; |
| 779 } | 835 } |
| 780 | 836 |
| 781 | 837 |
| 782 } // namespace dart | 838 } // namespace dart |
| OLD | NEW |