| 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 14 matching lines...) Expand all Loading... |
| 25 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); | 25 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); |
| 26 #else | 26 #else |
| 27 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); | 27 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); |
| 28 #endif | 28 #endif |
| 29 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); | 29 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); |
| 30 DEFINE_FLAG(charp, profile_dir, NULL, | 30 DEFINE_FLAG(charp, profile_dir, NULL, |
| 31 "Enable writing profile data into specified directory."); | 31 "Enable writing profile data into specified directory."); |
| 32 DEFINE_FLAG(int, profile_period, 1000, | 32 DEFINE_FLAG(int, profile_period, 1000, |
| 33 "Time between profiler samples in microseconds. Minimum 250."); | 33 "Time between profiler samples in microseconds. Minimum 250."); |
| 34 DEFINE_FLAG(int, profile_depth, 8, | 34 DEFINE_FLAG(int, profile_depth, 8, |
| 35 "Maximum number stack frames walked. Minimum 1. Maximum 128."); | 35 "Maximum number stack frames walked. Minimum 1. Maximum 255."); |
| 36 | 36 |
| 37 bool Profiler::initialized_ = false; | 37 bool Profiler::initialized_ = false; |
| 38 SampleBuffer* Profiler::sample_buffer_ = NULL; | 38 SampleBuffer* Profiler::sample_buffer_ = NULL; |
| 39 | 39 |
| 40 void Profiler::InitOnce() { | 40 void Profiler::InitOnce() { |
| 41 const int kMinimumProfilePeriod = 250; | |
| 42 const int kMinimumDepth = 1; | |
| 43 const int kMaximumDepth = 128; | |
| 44 // Place some sane restrictions on user controlled flags. | 41 // Place some sane restrictions on user controlled flags. |
| 45 if (FLAG_profile_period < kMinimumProfilePeriod) { | 42 SetSamplePeriod(FLAG_profile_period); |
| 46 FLAG_profile_period = kMinimumProfilePeriod; | 43 SetSampleDepth(FLAG_profile_depth); |
| 47 } | |
| 48 if (FLAG_profile_depth < kMinimumDepth) { | |
| 49 FLAG_profile_depth = kMinimumDepth; | |
| 50 } else if (FLAG_profile_depth > kMaximumDepth) { | |
| 51 FLAG_profile_depth = kMaximumDepth; | |
| 52 } | |
| 53 // We must always initialize the Sample, even when the profiler is disabled. | |
| 54 Sample::InitOnce(); | |
| 55 if (!FLAG_profile) { | 44 if (!FLAG_profile) { |
| 56 return; | 45 return; |
| 57 } | 46 } |
| 58 ASSERT(!initialized_); | 47 ASSERT(!initialized_); |
| 59 sample_buffer_ = new SampleBuffer(); | 48 sample_buffer_ = new SampleBuffer(); |
| 60 NativeSymbolResolver::InitOnce(); | 49 NativeSymbolResolver::InitOnce(); |
| 61 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); | 50 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); |
| 62 ThreadInterrupter::Startup(); | 51 ThreadInterrupter::Startup(); |
| 63 initialized_ = true; | 52 initialized_ = true; |
| 64 } | 53 } |
| 65 | 54 |
| 66 | 55 |
| 67 void Profiler::Shutdown() { | 56 void Profiler::Shutdown() { |
| 68 if (!FLAG_profile) { | 57 if (!FLAG_profile) { |
| 69 return; | 58 return; |
| 70 } | 59 } |
| 71 ASSERT(initialized_); | 60 ASSERT(initialized_); |
| 72 ThreadInterrupter::Shutdown(); | 61 ThreadInterrupter::Shutdown(); |
| 73 NativeSymbolResolver::ShutdownOnce(); | 62 NativeSymbolResolver::ShutdownOnce(); |
| 74 } | 63 } |
| 75 | 64 |
| 76 | 65 |
| 66 void Profiler::SetSampleDepth(intptr_t depth) { |
| 67 const int kMinimumDepth = 1; |
| 68 const int kMaximumDepth = kSampleFramesSize - 1; |
| 69 if (depth < kMinimumDepth) { |
| 70 FLAG_profile_depth = kMinimumDepth; |
| 71 } else if (depth > kMaximumDepth) { |
| 72 FLAG_profile_depth = kMaximumDepth; |
| 73 } else { |
| 74 FLAG_profile_depth = depth; |
| 75 } |
| 76 } |
| 77 |
| 78 |
| 79 void Profiler::SetSamplePeriod(intptr_t period) { |
| 80 const int kMinimumProfilePeriod = 250; |
| 81 if (period < kMinimumProfilePeriod) { |
| 82 FLAG_profile_period = kMinimumProfilePeriod; |
| 83 } else { |
| 84 FLAG_profile_period = period; |
| 85 } |
| 86 } |
| 87 |
| 88 |
| 77 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) { | 89 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) { |
| 78 if (!FLAG_profile) { | 90 if (!FLAG_profile) { |
| 79 return; | 91 return; |
| 80 } | 92 } |
| 81 ASSERT(isolate != NULL); | 93 ASSERT(isolate != NULL); |
| 82 ASSERT(sample_buffer_ != NULL); | 94 ASSERT(sample_buffer_ != NULL); |
| 83 { | 95 { |
| 84 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | 96 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 85 SampleBuffer* sample_buffer = sample_buffer_; | 97 SampleBuffer* sample_buffer = sample_buffer_; |
| 86 if (!shared_buffer) { | 98 if (!shared_buffer) { |
| (...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 | 731 |
| 720 IsolateProfilerData::~IsolateProfilerData() { | 732 IsolateProfilerData::~IsolateProfilerData() { |
| 721 if (own_sample_buffer_) { | 733 if (own_sample_buffer_) { |
| 722 delete sample_buffer_; | 734 delete sample_buffer_; |
| 723 sample_buffer_ = NULL; | 735 sample_buffer_ = NULL; |
| 724 own_sample_buffer_ = false; | 736 own_sample_buffer_ = false; |
| 725 } | 737 } |
| 726 } | 738 } |
| 727 | 739 |
| 728 | 740 |
| 729 intptr_t Sample::instance_size_ = 0; | |
| 730 | |
| 731 void Sample::InitOnce() { | |
| 732 ASSERT(FLAG_profile_depth >= 1); | |
| 733 instance_size_ = | |
| 734 sizeof(Sample) + (sizeof(intptr_t) * FLAG_profile_depth); // NOLINT. | |
| 735 } | |
| 736 | |
| 737 | |
| 738 uword Sample::At(intptr_t i) const { | |
| 739 ASSERT(i >= 0); | |
| 740 ASSERT(i < FLAG_profile_depth); | |
| 741 return pcs_[i]; | |
| 742 } | |
| 743 | |
| 744 | |
| 745 void Sample::SetAt(intptr_t i, uword pc) { | |
| 746 ASSERT(i >= 0); | |
| 747 ASSERT(i < FLAG_profile_depth); | |
| 748 pcs_[i] = pc; | |
| 749 } | |
| 750 | |
| 751 | |
| 752 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, | |
| 753 ThreadId tid) { | |
| 754 timestamp_ = timestamp; | |
| 755 tid_ = tid; | |
| 756 isolate_ = isolate; | |
| 757 type_ = type; | |
| 758 for (int i = 0; i < FLAG_profile_depth; i++) { | |
| 759 pcs_[i] = 0; | |
| 760 } | |
| 761 } | |
| 762 | |
| 763 | |
| 764 void Sample::CopyInto(Sample* dst) const { | |
| 765 ASSERT(dst != NULL); | |
| 766 dst->timestamp_ = timestamp_; | |
| 767 dst->tid_ = tid_; | |
| 768 dst->isolate_ = isolate_; | |
| 769 dst->type_ = type_; | |
| 770 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { | |
| 771 dst->pcs_[i] = pcs_[i]; | |
| 772 } | |
| 773 } | |
| 774 | |
| 775 | |
| 776 Sample* Sample::Allocate() { | |
| 777 return reinterpret_cast<Sample*>(malloc(instance_size())); | |
| 778 } | |
| 779 | |
| 780 | |
| 781 SampleBuffer::SampleBuffer(intptr_t capacity) { | |
| 782 capacity_ = capacity; | |
| 783 samples_ = reinterpret_cast<Sample*>( | |
| 784 calloc(capacity, Sample::instance_size())); | |
| 785 cursor_ = 0; | |
| 786 } | |
| 787 | |
| 788 | |
| 789 SampleBuffer::~SampleBuffer() { | |
| 790 if (samples_ != NULL) { | |
| 791 free(samples_); | |
| 792 samples_ = NULL; | |
| 793 cursor_ = 0; | |
| 794 capacity_ = 0; | |
| 795 } | |
| 796 } | |
| 797 | |
| 798 | |
| 799 Sample* SampleBuffer::ReserveSample() { | 741 Sample* SampleBuffer::ReserveSample() { |
| 800 ASSERT(samples_ != NULL); | 742 ASSERT(samples_ != NULL); |
| 801 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 743 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
| 802 // Map back into sample buffer range. | 744 // Map back into sample buffer range. |
| 803 cursor = cursor % capacity_; | 745 cursor = cursor % capacity_; |
| 804 return At(cursor); | 746 return At(cursor); |
| 805 } | 747 } |
| 806 | 748 |
| 807 | |
| 808 void SampleBuffer::CopySample(intptr_t i, Sample* sample) const { | |
| 809 At(i)->CopyInto(sample); | |
| 810 } | |
| 811 | |
| 812 | |
| 813 Sample* SampleBuffer::At(intptr_t idx) const { | |
| 814 ASSERT(idx >= 0); | |
| 815 ASSERT(idx < capacity_); | |
| 816 intptr_t offset = idx * Sample::instance_size(); | |
| 817 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); | |
| 818 return reinterpret_cast<Sample*>(samples + offset); | |
| 819 } | |
| 820 | |
| 821 | |
| 822 void SampleBuffer::VisitSamples(SampleVisitor* visitor) { | |
| 823 ASSERT(visitor != NULL); | |
| 824 Sample* sample = Sample::Allocate(); | |
| 825 const intptr_t length = capacity(); | |
| 826 for (intptr_t i = 0; i < length; i++) { | |
| 827 CopySample(i, sample); | |
| 828 if (sample->isolate() != visitor->isolate()) { | |
| 829 // Another isolate. | |
| 830 continue; | |
| 831 } | |
| 832 if (sample->timestamp() == 0) { | |
| 833 // Empty. | |
| 834 continue; | |
| 835 } | |
| 836 if (sample->At(0) == 0) { | |
| 837 // No frames. | |
| 838 continue; | |
| 839 } | |
| 840 visitor->IncrementVisited(); | |
| 841 visitor->VisitSample(sample); | |
| 842 } | |
| 843 free(sample); | |
| 844 } | |
| 845 | |
| 846 | |
| 847 // Notes on stack frame walking: | 749 // Notes on stack frame walking: |
| 848 // | 750 // |
| 849 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames | 751 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames |
| 850 // The stack frame walking code uses the frame pointer to traverse the stack. | 752 // The stack frame walking code uses the frame pointer to traverse the stack. |
| 851 // If the VM is compiled without frame pointers (which is the default on | 753 // If the VM is compiled without frame pointers (which is the default on |
| 852 // recent GCC versions with optimizing enabled) the stack walking code may | 754 // recent GCC versions with optimizing enabled) the stack walking code may |
| 853 // fail (sometimes leading to a crash). | 755 // fail (sometimes leading to a crash). |
| 854 // | 756 // |
| 855 class ProfilerSampleStackWalker : public ValueObject { | 757 class ProfilerSampleStackWalker : public ValueObject { |
| 856 public: | 758 public: |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 956 } | 858 } |
| 957 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 859 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 958 if (profiler_data == NULL) { | 860 if (profiler_data == NULL) { |
| 959 return; | 861 return; |
| 960 } | 862 } |
| 961 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | 863 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 962 if (sample_buffer == NULL) { | 864 if (sample_buffer == NULL) { |
| 963 return; | 865 return; |
| 964 } | 866 } |
| 965 Sample* sample = sample_buffer->ReserveSample(); | 867 Sample* sample = sample_buffer->ReserveSample(); |
| 966 sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(), | 868 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| 967 state.tid); | |
| 968 uword stack_lower = 0; | 869 uword stack_lower = 0; |
| 969 uword stack_upper = 0; | 870 uword stack_upper = 0; |
| 970 isolate->GetStackBounds(&stack_lower, &stack_upper); | 871 isolate->GetStackBounds(&stack_lower, &stack_upper); |
| 971 if ((stack_lower == 0) || (stack_upper == 0)) { | 872 if ((stack_lower == 0) || (stack_upper == 0)) { |
| 972 stack_lower = 0; | 873 stack_lower = 0; |
| 973 stack_upper = 0; | 874 stack_upper = 0; |
| 974 } | 875 } |
| 975 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 876 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 976 state.pc, state.fp, state.sp); | 877 state.pc, state.fp, state.sp); |
| 977 stackWalker.walk(); | 878 stackWalker.walk(); |
| 978 } | 879 } |
| 979 | 880 |
| 980 | 881 |
| 981 } // namespace dart | 882 } // namespace dart |
| OLD | NEW |