| Index: runtime/vm/profiler.cc
|
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
|
| index b416aeb5095f7de3cee46e1c4e3a521c57c5e33a..840f438359bb62e7f0aca86a650467282959d987 100644
|
| --- a/runtime/vm/profiler.cc
|
| +++ b/runtime/vm/profiler.cc
|
| @@ -57,6 +57,7 @@ DEFINE_FLAG(bool, profile_vm, false, "Always collect native stack traces.");
|
|
|
| bool Profiler::initialized_ = false;
|
| SampleBuffer* Profiler::sample_buffer_ = NULL;
|
| +AllocationSampleBuffer* Profiler::allocation_sample_buffer_ = NULL;
|
| ProfilerCounters Profiler::counters_;
|
|
|
| void Profiler::InitOnce() {
|
| @@ -69,6 +70,7 @@ void Profiler::InitOnce() {
|
| }
|
| ASSERT(!initialized_);
|
| sample_buffer_ = new SampleBuffer();
|
| + Profiler::InitAllocationSampleBuffer();
|
| // Zero counters.
|
| memset(&counters_, 0, sizeof(counters_));
|
| NativeSymbolResolver::InitOnce();
|
| @@ -78,6 +80,14 @@ void Profiler::InitOnce() {
|
| }
|
|
|
|
|
| +void Profiler::InitAllocationSampleBuffer() {
|
| + if (FLAG_profiler_native_memory &&
|
| + (Profiler::allocation_sample_buffer_ == NULL)) {
|
| + Profiler::allocation_sample_buffer_ = new AllocationSampleBuffer();
|
| + }
|
| +}
|
| +
|
| +
|
| void Profiler::Shutdown() {
|
| if (!FLAG_profiler) {
|
| return;
|
| @@ -150,11 +160,20 @@ SampleBuffer::SampleBuffer(intptr_t capacity) {
|
| }
|
|
|
|
|
| +AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity)
|
| + : SampleBuffer(capacity), mutex_(new Mutex()) {}
|
| +
|
| +
|
| SampleBuffer::~SampleBuffer() {
|
| delete memory_;
|
| }
|
|
|
|
|
| +AllocationSampleBuffer::~AllocationSampleBuffer() {
|
| + delete mutex_;
|
| +}
|
| +
|
| +
|
| Sample* SampleBuffer::At(intptr_t idx) const {
|
| ASSERT(idx >= 0);
|
| ASSERT(idx < capacity_);
|
| @@ -172,6 +191,7 @@ intptr_t SampleBuffer::ReserveSampleSlot() {
|
| return cursor;
|
| }
|
|
|
| +
|
| Sample* SampleBuffer::ReserveSample() {
|
| return At(ReserveSampleSlot());
|
| }
|
| @@ -189,6 +209,73 @@ Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) {
|
| }
|
|
|
|
|
| +void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) {
|
| + MutexLocker ml(mutex_);
|
| + while (sample != NULL) {
|
| + intptr_t continuation_index = -1;
|
| + if (sample->is_continuation_sample()) {
|
| + continuation_index = sample->continuation_index();
|
| + }
|
| + sample->Clear();
|
| + sample->set_next_free(free_sample_list_);
|
| + free_sample_list_ = sample;
|
| +
|
| + if (continuation_index != -1) {
|
| + sample = At(continuation_index);
|
| + } else {
|
| + sample = NULL;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +intptr_t AllocationSampleBuffer::ReserveSampleSlotLocked() {
|
| + if (free_sample_list_ != NULL) {
|
| + Sample* free_sample = free_sample_list_;
|
| + free_sample_list_ = free_sample->next_free();
|
| + free_sample->set_next_free(NULL);
|
| + uint8_t* samples_array_ptr = reinterpret_cast<uint8_t*>(samples_);
|
| + uint8_t* free_sample_ptr = reinterpret_cast<uint8_t*>(free_sample);
|
| + return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) /
|
| + Sample::instance_size());
|
| + } else if (cursor_ < static_cast<uintptr_t>(capacity_ - 1)) {
|
| + return cursor_++;
|
| + } else {
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +
|
| +Sample* AllocationSampleBuffer::ReserveSampleAndLink(Sample* previous) {
|
| + MutexLocker ml(mutex_);
|
| + ASSERT(previous != NULL);
|
| + intptr_t next_index = ReserveSampleSlotLocked();
|
| + if (next_index < 0) {
|
| + // Could not find a free sample.
|
| + return NULL;
|
| + }
|
| + Sample* next = At(next_index);
|
| + next->Init(previous->port(), previous->timestamp(), previous->tid());
|
| + next->set_native_allocation_address(previous->native_allocation_address());
|
| + next->set_native_allocation_size_bytes(
|
| + previous->native_allocation_size_bytes());
|
| + next->set_head_sample(false);
|
| + // Mark that previous continues at next.
|
| + previous->SetContinuationIndex(next_index);
|
| + return next;
|
| +}
|
| +
|
| +
|
| +Sample* AllocationSampleBuffer::ReserveSample() {
|
| + MutexLocker ml(mutex_);
|
| + intptr_t index = ReserveSampleSlotLocked();
|
| + if (index < 0) {
|
| + return NULL;
|
| + }
|
| + return At(index);
|
| +}
|
| +
|
| +
|
| // Attempts to find the true return address when a Dart frame is being setup
|
| // or torn down.
|
| // NOTE: Architecture specific implementations below.
|
| @@ -956,8 +1043,10 @@ static Sample* SetupSample(Thread* thread,
|
|
|
| static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) {
|
| Sample* sample = sample_buffer->ReserveSample();
|
| + if (sample == NULL) {
|
| + return NULL;
|
| + }
|
| sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid);
|
| - sample->set_is_native_allocation_sample(true);
|
| Thread* thread = Thread::Current();
|
|
|
| // Note: setting thread task in order to be consistent with other samples. The
|
| @@ -1116,7 +1205,7 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
| Sample* Profiler::SampleNativeAllocation(intptr_t skip_count,
|
| uword address,
|
| uintptr_t allocation_size) {
|
| - SampleBuffer* sample_buffer = Profiler::sample_buffer();
|
| + AllocationSampleBuffer* sample_buffer = Profiler::allocation_sample_buffer();
|
| if (sample_buffer == NULL) {
|
| return NULL;
|
| }
|
| @@ -1145,6 +1234,16 @@ Sample* Profiler::SampleNativeAllocation(intptr_t skip_count,
|
|
|
| OSThread* os_thread = OSThread::Current();
|
| Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id());
|
| + if (sample == NULL) {
|
| + OS::PrintErr(
|
| + "Native memory profile sample buffer is full because there are more "
|
| + "than %" Pd
|
| + " outstanding allocations. Not recording allocation "
|
| + "0x%" Px " with size: %" Pu " bytes.\n",
|
| + sample_buffer->capacity(), address, allocation_size);
|
| + return NULL;
|
| + }
|
| +
|
| sample->set_native_allocation_address(address);
|
| sample->set_native_allocation_size_bytes(allocation_size);
|
|
|
| @@ -1153,6 +1252,7 @@ Sample* Profiler::SampleNativeAllocation(intptr_t skip_count,
|
| skip_count);
|
|
|
| native_stack_walker.walk();
|
| +
|
| return sample;
|
| }
|
|
|
|
|