| Index: runtime/vm/profiler.h
|
| diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
|
| index f8107e49d2999e312e3e08ec9340fcb14b137dc1..75d4515e3dee9e43e5618e2d4a49b95fc3ab452b 100644
|
| --- a/runtime/vm/profiler.h
|
| +++ b/runtime/vm/profiler.h
|
| @@ -26,6 +26,7 @@ class ProcessedSample;
|
| class ProcessedSampleBuffer;
|
|
|
| class Sample;
|
| +class AllocationSampleBuffer;
|
| class SampleBuffer;
|
| class ProfileTrieNode;
|
|
|
| @@ -51,12 +52,16 @@ struct ProfilerCounters {
|
| class Profiler : public AllStatic {
|
| public:
|
| static void InitOnce();
|
| + static void InitAllocationSampleBuffer();
|
| static void Shutdown();
|
|
|
| static void SetSampleDepth(intptr_t depth);
|
| static void SetSamplePeriod(intptr_t period);
|
|
|
| static SampleBuffer* sample_buffer() { return sample_buffer_; }
|
| + static AllocationSampleBuffer* allocation_sample_buffer() {
|
| + return allocation_sample_buffer_;
|
| + }
|
|
|
| static void DumpStackTrace(void* context);
|
| static void DumpStackTrace(bool for_crash = true);
|
| @@ -89,6 +94,7 @@ class Profiler : public AllStatic {
|
| static bool initialized_;
|
|
|
| static SampleBuffer* sample_buffer_;
|
| + static AllocationSampleBuffer* allocation_sample_buffer_;
|
|
|
| static ProfilerCounters counters_;
|
|
|
| @@ -192,6 +198,7 @@ class Sample {
|
| native_allocation_address_ = 0;
|
| native_allocation_size_bytes_ = 0;
|
| continuation_index_ = -1;
|
| + next_free_ = NULL;
|
| uword* pcs = GetPCArray();
|
| for (intptr_t i = 0; i < pcs_length_; i++) {
|
| pcs[i] = 0;
|
| @@ -293,21 +300,12 @@ class Sample {
|
| state_ = ClassAllocationSampleBit::update(allocation_sample, state_);
|
| }
|
|
|
| - bool is_native_allocation_sample() const {
|
| - return NativeAllocationSampleBit::decode(state_);
|
| - }
|
| -
|
| - void set_is_native_allocation_sample(bool native_allocation_sample) {
|
| - state_ =
|
| - NativeAllocationSampleBit::update(native_allocation_sample, state_);
|
| - }
|
| + uword native_allocation_address() const { return native_allocation_address_; }
|
|
|
| void set_native_allocation_address(uword address) {
|
| native_allocation_address_ = address;
|
| }
|
|
|
| - uword native_allocation_address() const { return native_allocation_address_; }
|
| -
|
| uintptr_t native_allocation_size_bytes() const {
|
| return native_allocation_size_bytes_;
|
| }
|
| @@ -316,6 +314,9 @@ class Sample {
|
| native_allocation_size_bytes_ = size;
|
| }
|
|
|
| + Sample* next_free() const { return next_free_; }
|
| + void set_next_free(Sample* next_free) { next_free_ = next_free; }
|
| +
|
| Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); }
|
|
|
| void set_thread_task(Thread::TaskKind task) {
|
| @@ -379,8 +380,7 @@ class Sample {
|
| kClassAllocationSampleBit = 6,
|
| kContinuationSampleBit = 7,
|
| kThreadTaskBit = 8, // 5 bits.
|
| - kNativeAllocationSampleBit = 13,
|
| - kNextFreeBit = 14,
|
| + kNextFreeBit = 13,
|
| };
|
| class HeadSampleBit : public BitField<uword, bool, kHeadSampleBit, 1> {};
|
| class LeafFrameIsDart : public BitField<uword, bool, kLeafFrameIsDartBit, 1> {
|
| @@ -397,8 +397,6 @@ class Sample {
|
| : public BitField<uword, bool, kContinuationSampleBit, 1> {};
|
| class ThreadTaskBit
|
| : public BitField<uword, Thread::TaskKind, kThreadTaskBit, 5> {};
|
| - class NativeAllocationSampleBit
|
| - : public BitField<uword, bool, kNativeAllocationSampleBit, 1> {};
|
|
|
| int64_t timestamp_;
|
| ThreadId tid_;
|
| @@ -413,10 +411,10 @@ class Sample {
|
| uword native_allocation_address_;
|
| uintptr_t native_allocation_size_bytes_;
|
| intptr_t continuation_index_;
|
| + Sample* next_free_;
|
|
|
| /* There are a variable number of words that follow, the words hold the
|
| * sampled pc values. Access via GetPCArray() */
|
| -
|
| DISALLOW_COPY_AND_ASSIGN(Sample);
|
| };
|
|
|
| @@ -431,14 +429,12 @@ class NativeAllocationSampleFilter : public SampleFilter {
|
| time_extent_micros) {}
|
|
|
| bool FilterSample(Sample* sample) {
|
| - if (!sample->is_native_allocation_sample()) {
|
| - return false;
|
| - }
|
| // If the sample is an allocation sample, we need to check that the
|
| // memory at the address hasn't been freed, and if the address associated
|
| // with the allocation has been freed and then reissued.
|
| void* alloc_address =
|
| reinterpret_cast<void*>(sample->native_allocation_address());
|
| + ASSERT(alloc_address != NULL);
|
| Sample* recorded_sample = MallocHooks::GetSample(alloc_address);
|
| return (sample == recorded_sample);
|
| }
|
| @@ -521,14 +517,14 @@ class SampleBuffer {
|
| static const intptr_t kDefaultBufferCapacity = 120000; // 2 minutes @ 1000hz.
|
|
|
| explicit SampleBuffer(intptr_t capacity = kDefaultBufferCapacity);
|
| - ~SampleBuffer();
|
| + virtual ~SampleBuffer();
|
|
|
| intptr_t capacity() const { return capacity_; }
|
|
|
| Sample* At(intptr_t idx) const;
|
| intptr_t ReserveSampleSlot();
|
| - Sample* ReserveSample();
|
| - Sample* ReserveSampleAndLink(Sample* previous);
|
| + virtual Sample* ReserveSample();
|
| + virtual Sample* ReserveSampleAndLink(Sample* previous);
|
|
|
| void VisitSamples(SampleVisitor* visitor) {
|
| ASSERT(visitor != NULL);
|
| @@ -562,7 +558,7 @@ class SampleBuffer {
|
|
|
| ProcessedSampleBuffer* BuildProcessedSampleBuffer(SampleFilter* filter);
|
|
|
| - private:
|
| + protected:
|
| ProcessedSample* BuildProcessedSample(Sample* sample,
|
| const CodeLookupTable& clt);
|
| Sample* Next(Sample* sample);
|
| @@ -572,10 +568,29 @@ class SampleBuffer {
|
| intptr_t capacity_;
|
| uintptr_t cursor_;
|
|
|
| + private:
|
| DISALLOW_COPY_AND_ASSIGN(SampleBuffer);
|
| };
|
|
|
|
|
| +class AllocationSampleBuffer : public SampleBuffer {
|
| + public:
|
| + explicit AllocationSampleBuffer(intptr_t capacity = kDefaultBufferCapacity);
|
| + virtual ~AllocationSampleBuffer();
|
| +
|
| + intptr_t ReserveSampleSlotLocked();
|
| + virtual Sample* ReserveSample();
|
| + virtual Sample* ReserveSampleAndLink(Sample* previous);
|
| + void FreeAllocationSample(Sample* sample);
|
| +
|
| + private:
|
| + Mutex* mutex_;
|
| + Sample* free_sample_list_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AllocationSampleBuffer);
|
| +};
|
| +
|
| +
|
| // A |ProcessedSample| is a combination of 1 (or more) |Sample|(s) that have
|
| // been merged into a logical sample. The raw data may have been processed to
|
| // improve the quality of the stack trace.
|
|
|