Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Unified Diff: runtime/vm/profiler.cc

Issue 1270003002: Chain samples together to collect long stack traces in profiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_service.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/profiler.cc
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 339caadf11579ee061ea6b6c6f80c8041b7dd034..c470b6a6b6b4743087c713b70376a35596d95853 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -25,6 +25,8 @@
namespace dart {
+static const intptr_t kSampleSize = 8;
+
DECLARE_FLAG(bool, trace_profiler);
DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
@@ -38,7 +40,7 @@ DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
DEFINE_FLAG(int, profile_period, 1000,
"Time between profiler samples in microseconds. Minimum 50.");
#endif
-DEFINE_FLAG(int, profile_depth, 8,
+DEFINE_FLAG(int, max_profile_depth, kSampleSize,
"Maximum number stack frames walked. Minimum 1. Maximum 255.");
#if defined(USING_SIMULATOR)
DEFINE_FLAG(bool, profile_vm, true,
@@ -51,18 +53,11 @@ DEFINE_FLAG(bool, profile_vm, false,
bool Profiler::initialized_ = false;
SampleBuffer* Profiler::sample_buffer_ = NULL;
-static intptr_t NumberOfFramesToCollect() {
- if (FLAG_profile_depth <= 0) {
- return 0;
- }
- // Subtract to reserve space for the possible missing frame.
- return FLAG_profile_depth - 1;
-}
void Profiler::InitOnce() {
// Place some sane restrictions on user controlled flags.
SetSamplePeriod(FLAG_profile_period);
- SetSampleDepth(FLAG_profile_depth);
+ SetSampleDepth(FLAG_max_profile_depth);
Sample::InitOnce();
if (!FLAG_profile) {
return;
@@ -90,11 +85,11 @@ void Profiler::SetSampleDepth(intptr_t depth) {
const int kMinimumDepth = 2;
const int kMaximumDepth = 255;
if (depth < kMinimumDepth) {
- FLAG_profile_depth = kMinimumDepth;
+ FLAG_max_profile_depth = kMinimumDepth;
} else if (depth > kMaximumDepth) {
- FLAG_profile_depth = kMaximumDepth;
+ FLAG_max_profile_depth = kMaximumDepth;
} else {
- FLAG_profile_depth = depth;
+ FLAG_max_profile_depth = depth;
}
}
@@ -228,8 +223,7 @@ intptr_t Sample::instance_size_ = 0;
void Sample::InitOnce() {
- ASSERT(FLAG_profile_depth >= 2);
- pcs_length_ = FLAG_profile_depth;
+ pcs_length_ = kSampleSize;
instance_size_ =
sizeof(Sample) + (sizeof(uword) * pcs_length_); // NOLINT.
}
@@ -265,14 +259,31 @@ Sample* SampleBuffer::At(intptr_t idx) const {
}
-Sample* SampleBuffer::ReserveSample() {
+intptr_t SampleBuffer::ReserveSampleSlot() {
ASSERT(samples_ != NULL);
uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
// Map back into sample buffer range.
cursor = cursor % capacity_;
- return At(cursor);
+ return cursor;
+}
+
+Sample* SampleBuffer::ReserveSample() {
+ return At(ReserveSampleSlot());
}
+
+Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) {
+ ASSERT(previous != NULL);
+ intptr_t next_index = ReserveSampleSlot();
+ Sample* next = At(next_index);
+ next->Init(previous->isolate(), previous->timestamp(), previous->tid());
+ next->set_head_sample(false);
+ // Mark that previous continues at next.
+ previous->SetContinuationIndex(next_index);
+ return next;
+}
+
+
// Attempts to find the true return address when a Dart frame is being setup
// or torn down.
// NOTE: Architecture specific implementations below.
@@ -407,50 +418,96 @@ void ClearProfileVisitor::VisitSample(Sample* sample) {
}
+class ProfilerStackWalker : public ValueObject {
+ public:
+ ProfilerStackWalker(Isolate* isolate,
+ Sample* head_sample,
+ SampleBuffer* sample_buffer)
+ : isolate_(isolate),
+ sample_(head_sample),
+ sample_buffer_(sample_buffer),
+ frame_index_(0),
+ total_frames_(0) {
+ ASSERT(isolate_ != NULL);
+ ASSERT(sample_ != NULL);
+ ASSERT(sample_buffer_ != NULL);
+ ASSERT(sample_->head_sample());
+ }
+
+ bool Append(uword pc) {
+ if (total_frames_ >= FLAG_max_profile_depth) {
+ sample_->set_truncated_trace(true);
+ return false;
+ }
+ ASSERT(sample_ != NULL);
+ if (frame_index_ == kSampleSize) {
+ Sample* new_sample = sample_buffer_->ReserveSampleAndLink(sample_);
+ if (new_sample == NULL) {
+ // Could not reserve new sample- mark this as truncated.
+ sample_->set_truncated_trace(true);
+ return false;
+ }
+ frame_index_ = 0;
+ sample_ = new_sample;
+ }
+ ASSERT(frame_index_ < kSampleSize);
+ sample_->SetAt(frame_index_, pc);
+ frame_index_++;
+ total_frames_++;
+ return true;
+ }
+
+ protected:
+ Isolate* isolate_;
+ Sample* sample_;
+ SampleBuffer* sample_buffer_;
+ intptr_t frame_index_;
+ intptr_t total_frames_;
+};
+
+
// Given an exit frame, walk the Dart stack.
-class ProfilerDartExitStackWalker : public ValueObject {
+class ProfilerDartExitStackWalker : public ProfilerStackWalker {
public:
- ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample)
- : sample_(sample),
+ ProfilerDartExitStackWalker(Isolate* isolate,
+ Sample* sample,
+ SampleBuffer* sample_buffer)
+ : ProfilerStackWalker(isolate, sample, sample_buffer),
frame_iterator_(isolate) {
- ASSERT(sample_ != NULL);
}
void walk() {
// Mark that this sample was collected from an exit frame.
sample_->set_exit_frame_sample(true);
- intptr_t frame_index = 0;
+
StackFrame* frame = frame_iterator_.NextFrame();
while (frame != NULL) {
- sample_->SetAt(frame_index, frame->pc());
- frame_index++;
- if (frame_index >= NumberOfFramesToCollect()) {
- sample_->set_truncated_trace(true);
- break;
+ if (!Append(frame->pc())) {
+ return;
}
frame = frame_iterator_.NextFrame();
}
}
private:
- Sample* sample_;
DartFrameIterator frame_iterator_;
};
// Executing Dart code, walk the stack.
-class ProfilerDartStackWalker : public ValueObject {
+class ProfilerDartStackWalker : public ProfilerStackWalker {
public:
- ProfilerDartStackWalker(Sample* sample,
+ ProfilerDartStackWalker(Isolate* isolate,
+ Sample* sample,
+ SampleBuffer* sample_buffer,
uword stack_lower,
uword stack_upper,
uword pc,
uword fp,
uword sp)
- : sample_(sample),
+ : ProfilerStackWalker(isolate, sample, sample_buffer),
stack_upper_(stack_upper),
stack_lower_(stack_lower) {
- ASSERT(sample_ != NULL);
pc_ = reinterpret_cast<uword*>(pc);
fp_ = reinterpret_cast<uword*>(fp);
sp_ = reinterpret_cast<uword*>(sp);
@@ -474,13 +531,14 @@ class ProfilerDartStackWalker : public ValueObject {
return;
}
}
- for (int i = 0; i < NumberOfFramesToCollect(); i++) {
- sample_->SetAt(i, reinterpret_cast<uword>(pc_));
+ while (true) {
+ if (!Append(reinterpret_cast<uword>(pc_))) {
+ return;
+ }
if (!Next()) {
return;
}
}
- sample_->set_truncated_trace(true);
}
private:
@@ -583,7 +641,6 @@ class ProfilerDartStackWalker : public ValueObject {
uword* pc_;
uword* fp_;
uword* sp_;
- Sample* sample_;
const uword stack_upper_;
uword stack_lower_;
};
@@ -593,27 +650,28 @@ class ProfilerDartStackWalker : public ValueObject {
// recent GCC versions with optimizing enabled) the stack walking code may
// fail.
//
-class ProfilerNativeStackWalker : public ValueObject {
+class ProfilerNativeStackWalker : public ProfilerStackWalker {
public:
- ProfilerNativeStackWalker(Sample* sample,
+ ProfilerNativeStackWalker(Isolate* isolate,
+ Sample* sample,
+ SampleBuffer* sample_buffer,
uword stack_lower,
uword stack_upper,
uword pc,
uword fp,
uword sp)
- : sample_(sample),
+ : ProfilerStackWalker(isolate, sample, sample_buffer),
stack_upper_(stack_upper),
original_pc_(pc),
original_fp_(fp),
original_sp_(sp),
lower_bound_(stack_lower) {
- ASSERT(sample_ != NULL);
}
void walk() {
const uword kMaxStep = VirtualMemory::PageSize();
- sample_->SetAt(0, original_pc_);
+ Append(original_pc_);
uword* pc = reinterpret_cast<uword*>(original_pc_);
uword* fp = reinterpret_cast<uword*>(original_fp_);
@@ -630,8 +688,10 @@ class ProfilerNativeStackWalker : public ValueObject {
return;
}
- for (int i = 0; i < NumberOfFramesToCollect(); i++) {
- sample_->SetAt(i, reinterpret_cast<uword>(pc));
+ while (true) {
+ if (!Append(reinterpret_cast<uword>(pc))) {
+ return;
+ }
pc = CallerPC(fp);
previous_fp = fp;
@@ -660,8 +720,6 @@ class ProfilerNativeStackWalker : public ValueObject {
// Move the lower bound up.
lower_bound_ = reinterpret_cast<uword>(fp);
}
-
- sample_->set_truncated_trace(true);
}
private:
@@ -693,7 +751,6 @@ class ProfilerNativeStackWalker : public ValueObject {
return r;
}
- Sample* sample_;
const uword stack_upper_;
const uword original_pc_;
const uword original_fp_;
@@ -1000,7 +1057,9 @@ void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) {
sample_buffer,
OSThread::GetCurrentThreadId());
sample->SetAllocationCid(cid);
- ProfilerNativeStackWalker native_stack_walker(sample,
+ ProfilerNativeStackWalker native_stack_walker(isolate,
+ sample,
+ sample_buffer,
stack_lower,
stack_upper,
pc,
@@ -1012,7 +1071,9 @@ void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) {
sample_buffer,
OSThread::GetCurrentThreadId());
sample->SetAllocationCid(cid);
- ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample);
+ ProfilerDartExitStackWalker dart_exit_stack_walker(isolate,
+ sample,
+ sample_buffer);
dart_exit_stack_walker.walk();
} else {
// Fall back.
@@ -1102,16 +1163,22 @@ void Profiler::RecordSampleInterruptCallback(
ASSERT(counters != NULL);
counters->Increment(sample->vm_tag());
- ProfilerNativeStackWalker native_stack_walker(sample,
+ ProfilerNativeStackWalker native_stack_walker(isolate,
+ sample,
+ sample_buffer,
stack_lower,
stack_upper,
pc,
fp,
sp);
- ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample);
+ ProfilerDartExitStackWalker dart_exit_stack_walker(isolate,
+ sample,
+ sample_buffer);
- ProfilerDartStackWalker dart_stack_walker(sample,
+ ProfilerDartStackWalker dart_stack_walker(isolate,
+ sample,
+ sample_buffer,
stack_lower,
stack_upper,
pc,
@@ -1147,6 +1214,10 @@ ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer(
// Bad sample.
continue;
}
+ if (!sample->head_sample()) {
+ // An inner sample in a chain of samples.
+ continue;
+ }
if (sample->isolate() != filter->isolate()) {
// Another isolate.
continue;
@@ -1188,7 +1259,7 @@ ProcessedSample* SampleBuffer::BuildProcessedSample(Sample* sample) {
bool truncated = false;
Sample* current = sample;
while (current != NULL) {
- for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
+ for (intptr_t i = 0; i < kSampleSize; i++) {
if (current->At(i) == 0) {
break;
}
@@ -1196,7 +1267,7 @@ ProcessedSample* SampleBuffer::BuildProcessedSample(Sample* sample) {
}
truncated = truncated || current->truncated_trace();
- current = Next(sample);
+ current = Next(current);
}
if (!sample->exit_frame_sample()) {
@@ -1214,13 +1285,27 @@ ProcessedSample* SampleBuffer::BuildProcessedSample(Sample* sample) {
Sample* SampleBuffer::Next(Sample* sample) {
- // TODO(johnmccutchan): Support chaining samples for complete stack traces.
- return NULL;
+ if (!sample->is_continuation_sample())
+ return NULL;
+ Sample* next_sample = At(sample->continuation_index());
+ // Sanity check.
+ ASSERT(sample != next_sample);
+ // Detect invalid chaining.
+ if (sample->isolate() != next_sample->isolate()) {
+ return NULL;
+ }
+ if (sample->timestamp() != next_sample->timestamp()) {
+ return NULL;
+ }
+ if (sample->tid() != next_sample->tid()) {
+ return NULL;
+ }
+ return next_sample;
}
ProcessedSample::ProcessedSample()
- : pcs_(FLAG_profile_depth),
+ : pcs_(kSampleSize),
timestamp_(0),
vm_tag_(0),
user_tag_(0),
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698