Chromium Code Reviews| Index: runtime/vm/profiler.cc |
| diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc |
| index 6c6b19d5177c29befe3feab34b66ecef9e7f4277..217bb47ad568571bc06df16164e5525224ae5398 100644 |
| --- a/runtime/vm/profiler.cc |
| +++ b/runtime/vm/profiler.cc |
| @@ -148,57 +148,6 @@ void Profiler::EndExecution(Isolate* isolate) { |
| } |
| -void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state, |
| - void* data) { |
| - Isolate* isolate = reinterpret_cast<Isolate*>(data); |
| - if (isolate == NULL) { |
| - return; |
| - } |
| - IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| - if (profiler_data == NULL) { |
| - return; |
| - } |
| - SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| - if (sample_buffer == NULL) { |
| - return; |
| - } |
| - Sample* sample = sample_buffer->ReserveSample(); |
| - sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(), |
| - state.tid); |
| -} |
| - |
| - |
| -void Profiler::RecordSampleInterruptCallback( |
| - const InterruptedThreadState& state, |
| - void* data) { |
| - Isolate* isolate = reinterpret_cast<Isolate*>(data); |
| - if (isolate == NULL) { |
| - return; |
| - } |
| - IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| - if (profiler_data == NULL) { |
| - return; |
| - } |
| - SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| - if (sample_buffer == NULL) { |
| - return; |
| - } |
| - Sample* sample = sample_buffer->ReserveSample(); |
| - sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(), |
| - state.tid); |
| - uintptr_t stack_lower = 0; |
| - uintptr_t stack_upper = 0; |
| - isolate->GetStackBounds(&stack_lower, &stack_upper); |
| - if ((stack_lower == 0) || (stack_upper == 0)) { |
| - stack_lower = 0; |
| - stack_upper = 0; |
| - } |
| - ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| - state.pc, state.fp, state.sp); |
| - stackWalker.walk(); |
| -} |
| - |
| - |
| struct AddressEntry { |
| uintptr_t pc; |
| uintptr_t ticks; |
| @@ -222,6 +171,7 @@ class CodeRegion : public ZoneAllocated { |
| exclusive_ticks_(0), |
| name_(NULL), |
| address_table_(new ZoneGrowableArray<AddressEntry>()) { |
| + ASSERT(start_ < end_); |
| } |
| ~CodeRegion() { |
| @@ -244,12 +194,22 @@ class CodeRegion : public ZoneAllocated { |
| if (end > end_) { |
| end_ = end; |
| } |
| + ASSERT(start_ < end_); |
| } |
| bool contains(uintptr_t pc) const { |
| return (pc >= start_) && (pc < end_); |
| } |
| + bool overlaps(const CodeRegion* other) const { |
| + ASSERT(other != NULL); |
| + bool a = other->contains(start_); |
| + bool b = other->contains(end_ - 1); |
| + bool c = contains(other->start()); |
| + bool d = contains(other->end() - 1); |
| + return a || b || c || d; |
|
siva
2014/02/12 00:58:52
There is no short circuiting of calls to contains
Cutch
2014/02/13 23:13:19
Done.
|
| + } |
| + |
| intptr_t inclusive_ticks() const { return inclusive_ticks_; } |
| void set_inclusive_ticks(intptr_t inclusive_ticks) { |
| inclusive_ticks_ = inclusive_ticks; |
| @@ -294,9 +254,9 @@ class CodeRegion : public ZoneAllocated { |
| } |
| } |
| - void DebugPrint() { |
| - printf("%s [%" Px ", %" Px ") %s\n", name_, start(), end(), |
| - KindToCString(kind_)); |
| + void DebugPrint() const { |
| + printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(), |
| + name_); |
| } |
| void AddTickAtAddress(uintptr_t pc) { |
| @@ -394,6 +354,31 @@ class CodeRegion : public ZoneAllocated { |
| }; |
| +class ScopeStopwatch { |
| + public: |
| + explicit ScopeStopwatch(const char* name) : name_(name) { |
| + start_ = OS::GetCurrentTimeMillis(); |
| + } |
| + |
| + intptr_t GetElapsed() { |
|
siva
2014/02/12 00:58:52
const {
Cutch
2014/02/13 23:13:19
Done.
|
| + intptr_t end = OS::GetCurrentTimeMillis(); |
| + ASSERT(end >= start_); |
| + return end - start_; |
| + } |
| + |
| + ~ScopeStopwatch() { |
| + if (FLAG_trace_profiled_isolates) { |
| + intptr_t elapsed = GetElapsed(); |
| + OS::Print("%s took %" Pd " millis.\n", name_, elapsed); |
| + } |
| + } |
| + |
| + private: |
| + const char* name_; |
| + intptr_t start_; |
|
siva
2014/02/12 00:58:52
DISALLOW stuff..... or make this a ValueObject. Pr
Cutch
2014/02/13 23:13:19
Done.
|
| +}; |
| + |
| + |
| // All code regions. Code region tables are built on demand when a profile |
| // is requested (through the service or on isolate shutdown). |
| class ProfilerCodeRegionTable : public ValueObject { |
| @@ -427,15 +412,72 @@ class ProfilerCodeRegionTable : public ValueObject { |
| return (*code_region_table_)[idx]; |
| } |
| +#if defined(DEBUG) |
| + void Verify() { |
| + VerifyOrder(); |
| + VerifyOverlap(); |
| + } |
| +#endif |
| + |
| private: |
| + intptr_t FindUpperBound(uintptr_t pc) { |
|
siva
2014/02/12 00:58:52
we usually use uword for address types.
Cutch
2014/02/13 23:13:19
Done here and elsewhere.
|
| + intptr_t count = code_region_table_->length(); |
| + intptr_t first = 0; |
| + while (count > 0) { |
| + intptr_t it = first; |
| + intptr_t step = count / 2; |
| + it += step; |
| + const CodeRegion* code_region = (*code_region_table_)[it]; |
| + if (pc >= code_region->end()) { |
| + first = ++it; |
| + count -= (step + 1); |
| + } else { |
| + count = step; |
| + } |
| + } |
| + return first; |
| + } |
| + |
| + |
| + intptr_t FindLowerBound(uintptr_t pc) { |
| + intptr_t count = code_region_table_->length(); |
| + intptr_t first = 0; |
| + while (count > 0) { |
| + intptr_t it = first; |
| + intptr_t step = count / 2; |
| + it += step; |
| + const CodeRegion* code_region = (*code_region_table_)[it]; |
| + if (code_region->start() < pc) { |
| + first = ++it; |
| + count -= (step + 1); |
| + } else { |
| + count = step; |
| + } |
| + } |
| + return first; |
| + } |
|
siva
2014/02/12 00:58:52
Would it make sense to combine FindUpperBound and
Cutch
2014/02/13 23:13:19
Done.
|
| + |
| + |
| intptr_t FindIndex(uintptr_t pc) { |
| - const intptr_t length = code_region_table_->length(); |
| - for (intptr_t i = 0; i < length; i++) { |
| - const CodeRegion* code_region = (*code_region_table_)[i]; |
| + intptr_t index = FindLowerBound(pc); |
| + const CodeRegion* code_region = NULL; |
| + if (index > 0) { |
| + // We may have overshot by 1. Check previous entry. |
|
siva
2014/02/12 00:58:52
Not sure how this happens?
Cutch
2014/02/13 23:13:19
It doesn't anymore.
|
| + code_region = (*code_region_table_)[index - 1]; |
| if (code_region->contains(pc)) { |
| - return i; |
| + // Found at index - 1. |
| + return index - 1; |
| } |
| } |
| + if (index == code_region_table_->length()) { |
| + // Not present. |
| + return -1; |
| + } |
| + code_region = (*code_region_table_)[index]; |
| + if (code_region->contains(pc)) { |
| + // Found at index. |
| + return index; |
| + } |
| return -1; |
| } |
| @@ -448,8 +490,7 @@ class ProfilerCodeRegionTable : public ValueObject { |
| if (heap_->CodeContains(pc)) { |
| const intptr_t kDartCodeAlignment = 0x10; |
| const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); |
| - return new CodeRegion(CodeRegion::kCollectedCode, |
| - (pc & kDartCodeAlignmentMask), |
| + return new CodeRegion(CodeRegion::kCollectedCode, pc, |
| (pc & kDartCodeAlignmentMask) + kDartCodeAlignment); |
| } |
| uintptr_t native_start = 0; |
| @@ -466,39 +507,131 @@ class ProfilerCodeRegionTable : public ValueObject { |
| return code_region; |
| } |
| + void HandleOverlap(CodeRegion* region, CodeRegion* code_region, |
| + uintptr_t start, uintptr_t end) { |
| + // We should never see overlapping Dart code regions. |
| + ASSERT(region->kind() != CodeRegion::kDartCode); |
| + // When code regions overlap, they should be of the same kind. |
| + ASSERT(region->kind() == code_region->kind()); |
| + region->AdjustExtent(start, end); |
| + } |
| + |
| intptr_t InsertCodeRegion(CodeRegion* code_region) { |
| - const intptr_t length = code_region_table_->length(); |
| const uintptr_t start = code_region->start(); |
| const uintptr_t end = code_region->end(); |
| - intptr_t i = 0; |
| - for (; i < length; i++) { |
| - CodeRegion* region = (*code_region_table_)[i]; |
| - if (region->contains(start) || region->contains(end - 1)) { |
| - // We should only see overlapping native code regions. |
| - ASSERT(region->kind() == CodeRegion::kNativeCode); |
| - // When code regions overlap, they should be of the same kind. |
| - ASSERT(region->kind() == code_region->kind()); |
| - // Overlapping code region. |
| - region->AdjustExtent(start, end); |
| - return i; |
| - } else if (start >= region->end()) { |
| - // Insert here. |
| - break; |
| + const intptr_t length = code_region_table_->length(); |
| + if (length == 0) { |
| + code_region_table_->Add(code_region); |
| + return length; |
| + } |
| + // Determine the correct place to insert or merge code_region into table. |
| + intptr_t lo = FindLowerBound(start); |
| + intptr_t hi = FindUpperBound(end - 1); |
| + if ((lo == length) && (hi == length)) { |
| + lo = length - 1; |
| + } |
| + if (lo == length) { |
| + CodeRegion* region = (*code_region_table_)[hi]; |
| + if (region->overlaps(code_region)) { |
| + HandleOverlap(region, code_region, start, end); |
| + return hi; |
| + } |
| + code_region_table_->Add(code_region); |
| + return length; |
| + } else if (hi == length) { |
| + CodeRegion* region = (*code_region_table_)[lo]; |
| + if (region->overlaps(code_region)) { |
| + HandleOverlap(region, code_region, start, end); |
| + return lo; |
| + } |
| + code_region_table_->Add(code_region); |
| + return length; |
| + } else if (lo == hi) { |
| + CodeRegion* region = (*code_region_table_)[lo]; |
| + if (region->overlaps(code_region)) { |
| + HandleOverlap(region, code_region, start, end); |
| + return lo; |
| + } |
| + code_region_table_->InsertAt(lo, code_region); |
| + return lo; |
| + } else { |
| + CodeRegion* region = (*code_region_table_)[lo]; |
| + if (region->overlaps(code_region)) { |
| + HandleOverlap(region, code_region, start, end); |
| + return lo; |
| } |
| + region = (*code_region_table_)[hi]; |
| + if (region->overlaps(code_region)) { |
| + HandleOverlap(region, code_region, start, end); |
| + return hi; |
| + } |
| + code_region_table_->InsertAt(hi, code_region); |
| + return hi; |
| + } |
| + UNREACHABLE(); |
| + } |
| + |
| +#if defined(DEBUG) |
| + void VerifyOrder() { |
| + const intptr_t length = code_region_table_->length(); |
| + if (length == 0) { |
| + return; |
| } |
| - if (i != length) { |
| - code_region_table_->InsertAt(i, code_region); |
| - return i; |
| + uintptr_t last = (*code_region_table_)[0]->end(); |
| + for (intptr_t i = 1; i < length; i++) { |
| + CodeRegion* a = (*code_region_table_)[i]; |
| + ASSERT(last <= a->start()); |
| + last = a->end(); |
| } |
| - code_region_table_->Add(code_region); |
| - return code_region_table_->length() - 1; |
| } |
| + void VerifyOverlap() { |
| + const intptr_t length = code_region_table_->length(); |
| + for (intptr_t i = 0; i < length; i++) { |
| + CodeRegion* a = (*code_region_table_)[i]; |
| + for (intptr_t j = i+1; j < length; j++) { |
| + CodeRegion* b = (*code_region_table_)[j]; |
| + ASSERT(!a->contains(b->start()) && |
| + !a->contains(b->end() - 1) && |
| + !b->contains(a->start()) && |
| + !b->contains(a->end() - 1)); |
| + } |
| + } |
| + } |
| +#endif |
| + |
| Heap* heap_; |
| ZoneGrowableArray<CodeRegion*>* code_region_table_; |
| }; |
| +class CodeRegionTableBuilder : public SampleVisitor { |
| + public: |
| + CodeRegionTableBuilder(Isolate* isolate, |
| + ProfilerCodeRegionTable* code_region_table) |
| + : SampleVisitor(isolate), code_region_table_(code_region_table) { |
| + frames_ = 0; |
| + } |
| + |
| + void VisitSample(Sample* sample) { |
| + code_region_table_->AddTick(sample->At(0), true, false); |
| + // Give all frames an inclusive tick and tick the address. |
| + for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| + if (sample->At(i) == 0) { |
| + break; |
| + } |
| + frames_++; |
| + code_region_table_->AddTick(sample->At(i), false, true); |
| + } |
| + } |
| + |
| + intptr_t frames() const { return frames_; } |
| + private: |
| + intptr_t frames_; |
| + ProfilerCodeRegionTable* code_region_table_; |
| +}; |
| + |
| + |
| void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| bool full) { |
| ASSERT(isolate == Isolate::Current()); |
| @@ -519,9 +652,23 @@ void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| { |
| // Build code region table. |
| ProfilerCodeRegionTable code_region_table(isolate); |
| - intptr_t samples = |
| - ProcessSamples(isolate, &code_region_table, sample_buffer); |
| + CodeRegionTableBuilder builder(isolate, &code_region_table); |
| { |
| + ScopeStopwatch sw("CodeTableBuild"); |
| + sample_buffer->VisitSamples(&builder); |
| + } |
| +#if defined(DEBUG) |
| + code_region_table.Verify(); |
| +#endif |
| + // Number of samples we processed. |
| + intptr_t samples = builder.visited(); |
| + intptr_t frames = builder.frames(); |
| + if (FLAG_trace_profiled_isolates) { |
| + OS::Print("%" Pd " frames produced %" Pd " code objects.\n", |
| + frames, code_region_table.Length()); |
| + } |
| + { |
| + ScopeStopwatch sw("CodeTableStream"); |
| // Serialize to JSON. |
| JSONObject obj(stream); |
| obj.AddProperty("type", "Profile"); |
| @@ -530,7 +677,7 @@ void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| for (intptr_t i = 0; i < code_region_table.Length(); i++) { |
| CodeRegion* region = code_region_table.At(i); |
| ASSERT(region != NULL); |
| - region->PrintToJSONArray(&codes, full); |
| + region->PrintToJSONArray(&codes, false); |
| } |
| } |
| } |
| @@ -540,58 +687,6 @@ void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| } |
| -intptr_t Profiler::ProcessSamples(Isolate* isolate, |
| - ProfilerCodeRegionTable* code_region_table, |
| - SampleBuffer* sample_buffer) { |
| - int64_t start = OS::GetCurrentTimeMillis(); |
| - intptr_t samples = 0; |
| - Sample* sample = Sample::Allocate(); |
| - for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { |
| - sample_buffer->CopySample(i, sample); |
| - if (sample->isolate() != isolate) { |
| - continue; |
| - } |
| - if (sample->timestamp() == 0) { |
| - continue; |
| - } |
| - samples += ProcessSample(isolate, code_region_table, sample); |
| - } |
| - free(sample); |
| - int64_t end = OS::GetCurrentTimeMillis(); |
| - if (FLAG_trace_profiled_isolates) { |
| - int64_t delta = end - start; |
| - OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", |
| - samples, |
| - isolate->name(), |
| - delta); |
| - } |
| - return samples; |
| -} |
| - |
| - |
| -intptr_t Profiler::ProcessSample(Isolate* isolate, |
| - ProfilerCodeRegionTable* code_region_table, |
| - Sample* sample) { |
| - if (sample->type() != Sample::kIsolateSample) { |
| - return 0; |
| - } |
| - if (sample->At(0) == 0) { |
| - // No frames in this sample. |
| - return 0; |
| - } |
| - // i points to the leaf (exclusive) PC sample. Do not tick the address. |
| - code_region_table->AddTick(sample->At(0), true, false); |
| - // Give all frames an inclusive tick and tick the address. |
| - for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| - if (sample->At(i) == 0) { |
| - break; |
| - } |
| - code_region_table->AddTick(sample->At(i), false, true); |
| - } |
| - return 1; |
| -} |
| - |
| - |
| void Profiler::WriteProfile(Isolate* isolate) { |
| if (isolate == NULL) { |
| return; |
| @@ -702,6 +797,11 @@ Sample* Sample::Allocate() { |
| } |
| +SampleVisitor::SampleVisitor(Isolate* isolate) |
| + : isolate_(isolate), visited_(0) { |
| +} |
|
siva
2014/02/12 00:58:52
Why not move this to the header file itself, seems
Cutch
2014/02/13 23:13:19
Done.
|
| + |
| + |
| SampleBuffer::SampleBuffer(intptr_t capacity) { |
| capacity_ = capacity; |
| samples_ = reinterpret_cast<Sample*>( |
| @@ -743,20 +843,28 @@ Sample* SampleBuffer::At(intptr_t idx) const { |
| } |
| -ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, |
| - uintptr_t stack_lower, |
| - uintptr_t stack_upper, |
| - uintptr_t pc, |
| - uintptr_t fp, |
| - uintptr_t sp) : |
| - sample_(sample), |
| - stack_lower_(stack_lower), |
| - stack_upper_(stack_upper), |
| - original_pc_(pc), |
| - original_fp_(fp), |
| - original_sp_(sp), |
| - lower_bound_(stack_lower) { |
| - ASSERT(sample_ != NULL); |
| +void SampleBuffer::VisitSamples(SampleVisitor* visitor) { |
| + ASSERT(visitor != NULL); |
| + Sample* sample = Sample::Allocate(); |
| + const intptr_t length = capacity(); |
| + for (intptr_t i = 0; i < length; i++) { |
| + CopySample(i, sample); |
| + if (sample->isolate() != visitor->isolate()) { |
| + // Another isolate. |
| + continue; |
| + } |
| + if (sample->timestamp() == 0) { |
| + // Empty. |
| + continue; |
| + } |
| + if (sample->At(0) == 0) { |
| + // No frames. |
| + continue; |
| + } |
| + visitor->IncrementVisited(); |
| + visitor->VisitSample(sample); |
| + } |
| + free(sample); |
| } |
| @@ -768,77 +876,131 @@ ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, |
| // recent GCC versions with optimizing enabled) the stack walking code may |
| // fail (sometimes leading to a crash). |
| // |
| +class ProfilerSampleStackWalker : public ValueObject { |
| + public: |
| + ProfilerSampleStackWalker(Sample* sample, |
| + uintptr_t stack_lower, |
| + uintptr_t stack_upper, |
| + uintptr_t pc, |
| + uintptr_t fp, |
| + uintptr_t sp) |
| + : sample_(sample), |
| + stack_lower_(stack_lower), |
| + stack_upper_(stack_upper), |
| + original_pc_(pc), |
| + original_fp_(fp), |
| + original_sp_(sp), |
| + lower_bound_(stack_lower) { |
| + ASSERT(sample_ != NULL); |
| + } |
| + |
| + int walk() { |
| + const intptr_t kMaxStep = 0x1000; // 4K. |
| + const bool kWalkStack = true; // Walk the stack. |
| + // Always store the exclusive PC. |
| + sample_->SetAt(0, original_pc_); |
| + if (!kWalkStack) { |
| + // Not walking the stack, only took exclusive sample. |
| + return 1; |
| + } |
| + uword* pc = reinterpret_cast<uword*>(original_pc_); |
| + uword* fp = reinterpret_cast<uword*>(original_fp_); |
| + uword* previous_fp = fp; |
| + if (original_sp_ > original_fp_) { |
| + // Stack pointer should not be above frame pointer. |
| + return 1; |
| + } |
| + intptr_t gap = original_fp_ - original_sp_; |
| + if (gap >= kMaxStep) { |
| + // Gap between frame pointer and stack pointer is |
| + // too large. |
| + return 1; |
| + } |
| + if (original_sp_ < lower_bound_) { |
| + // The stack pointer gives us a better lower bound than |
| + // the isolates stack limit. |
| + lower_bound_ = original_sp_; |
| + } |
| + int i = 0; |
| + for (; i < FLAG_profile_depth; i++) { |
| + sample_->SetAt(i, reinterpret_cast<uintptr_t>(pc)); |
| + if (!ValidFramePointer(fp)) { |
| + return i + 1; |
| + } |
| + pc = CallerPC(fp); |
| + previous_fp = fp; |
| + fp = CallerFP(fp); |
| + intptr_t step = fp - previous_fp; |
| + if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { |
| + // Frame pointer step is too large. |
| + // Frame pointer did not move to a higher address. |
| + // Frame pointer is outside of isolate stack bounds. |
| + return i + 1; |
| + } |
| + // Move the lower bound up. |
| + lower_bound_ = reinterpret_cast<uintptr_t>(fp); |
| + } |
| + return i; |
| + } |
| -int ProfilerSampleStackWalker::walk() { |
| - const intptr_t kMaxStep = 0x1000; // 4K. |
| - const bool kWalkStack = true; // Walk the stack. |
| - // Always store the exclusive PC. |
| - sample_->SetAt(0, original_pc_); |
| - if (!kWalkStack) { |
| - // Not walking the stack, only took exclusive sample. |
| - return 1; |
| - } |
| - uword* pc = reinterpret_cast<uword*>(original_pc_); |
| - uword* fp = reinterpret_cast<uword*>(original_fp_); |
| - uword* previous_fp = fp; |
| - if (original_sp_ > original_fp_) { |
| - // Stack pointer should not be above frame pointer. |
| - return 1; |
| - } |
| - intptr_t gap = original_fp_ - original_sp_; |
| - if (gap >= kMaxStep) { |
| - // Gap between frame pointer and stack pointer is |
| - // too large. |
| - return 1; |
| - } |
| - if (original_sp_ < lower_bound_) { |
| - // The stack pointer gives us a better lower bound than |
| - // the isolates stack limit. |
| - lower_bound_ = original_sp_; |
| - } |
| - int i = 0; |
| - for (; i < FLAG_profile_depth; i++) { |
| - sample_->SetAt(i, reinterpret_cast<uintptr_t>(pc)); |
| - if (!ValidFramePointer(fp)) { |
| - return i + 1; |
| - } |
| - pc = CallerPC(fp); |
| - previous_fp = fp; |
| - fp = CallerFP(fp); |
| - intptr_t step = fp - previous_fp; |
| - if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { |
| - // Frame pointer step is too large. |
| - // Frame pointer did not move to a higher address. |
| - // Frame pointer is outside of isolate stack bounds. |
| - return i + 1; |
| - } |
| - // Move the lower bound up. |
| - lower_bound_ = reinterpret_cast<uintptr_t>(fp); |
| - } |
| - return i; |
| -} |
| - |
| - |
| -uword* ProfilerSampleStackWalker::CallerPC(uword* fp) { |
| - ASSERT(fp != NULL); |
| - return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp)); |
| -} |
| - |
| + private: |
| + uword* CallerPC(uword* fp) { |
|
siva
2014/02/12 00:58:52
const {
Cutch
2014/02/13 23:13:19
Done.
|
| + ASSERT(fp != NULL); |
| + return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp)); |
| + } |
| -uword* ProfilerSampleStackWalker::CallerFP(uword* fp) { |
| - ASSERT(fp != NULL); |
| - return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); |
| -} |
| + uword* CallerFP(uword* fp) { |
|
siva
2014/02/12 00:58:52
const {
Cutch
2014/02/13 23:13:19
Done.
|
| + ASSERT(fp != NULL); |
| + return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); |
| + } |
| + bool ValidFramePointer(uword* fp) { |
|
siva
2014/02/12 00:58:52
const {
Cutch
2014/02/13 23:13:19
Done.
|
| + if (fp == NULL) { |
| + return false; |
| + } |
| + uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
| + cursor += sizeof(fp); |
| + bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
| + return r; |
| + } |
| + |
| + Sample* sample_; |
| + const uintptr_t stack_lower_; |
| + const uintptr_t stack_upper_; |
| + const uintptr_t original_pc_; |
| + const uintptr_t original_fp_; |
| + const uintptr_t original_sp_; |
| + uintptr_t lower_bound_; |
| +}; |
| -bool ProfilerSampleStackWalker::ValidFramePointer(uword* fp) { |
| - if (fp == NULL) { |
| - return false; |
| +void Profiler::RecordSampleInterruptCallback( |
| + const InterruptedThreadState& state, |
| + void* data) { |
| + Isolate* isolate = reinterpret_cast<Isolate*>(data); |
| + if (isolate == NULL) { |
| + return; |
| } |
| - uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
| - cursor += sizeof(fp); |
| - bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
| - return r; |
| + IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| + if (profiler_data == NULL) { |
| + return; |
| + } |
| + SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| + if (sample_buffer == NULL) { |
| + return; |
| + } |
| + Sample* sample = sample_buffer->ReserveSample(); |
| + sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(), |
| + state.tid); |
| + uintptr_t stack_lower = 0; |
| + uintptr_t stack_upper = 0; |
| + isolate->GetStackBounds(&stack_lower, &stack_upper); |
| + if ((stack_lower == 0) || (stack_upper == 0)) { |
| + stack_lower = 0; |
| + stack_upper = 0; |
| + } |
| + ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| + state.pc, state.fp, state.sp); |
| + stackWalker.walk(); |
| } |