Fix tsan failure

We have a racy read of the object header in the stack frame walker
called from the profiler (in this case the gc marker is running at
the same time).

It is appropriate to avoid this even though we think the access is
safe as the objects are in old space and never forwarded and only
the mark bits are manipulated while marking
BUG=
R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org/2517473002 .
This commit is contained in:
Siva Annamalai 2016-11-18 14:09:02 -08:00
parent f0f0d4abd7
commit 159a5ab366
9 changed files with 171 additions and 122 deletions

View file

@ -67,8 +67,8 @@ var tests = [
cpuProfile.buildFunctionCallerAndCallees();
var tree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.exclusive);
var node = tree.root;
var expected =
['Root', 'DRT_AllocateObject', 'test', 'test', '_Closure.call'];
var expected = ['Root', 'DRT_AllocateObject', '[Stub] Allocate Foo',
'test', 'test', '_Closure.call'];
for (var i = 0; i < expected.length; i++) {
expect(node.profileCode.code.name, equals(expected[i]));
// Depth first traversal.

View file

@ -38,7 +38,7 @@ void DynamicAssertionHelper::Fail(const char* format, ...) {
// until the program is exiting before producing a non-zero exit
// code through abort.
if (kind_ == ASSERT) {
NOT_IN_PRODUCT(Profiler::DumpStackTrace(true /* native_stack_trace */));
NOT_IN_PRODUCT(Profiler::DumpStackTrace());
OS::Abort();
}
failed_ = true;

View file

@ -24,7 +24,7 @@ namespace dart {
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
NOT_IN_PRODUCT(Profiler::DumpStackTrace(true /* native_stack_trace */)); \
NOT_IN_PRODUCT(Profiler::DumpStackTrace()); \
Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}

View file

@ -25,7 +25,7 @@ namespace dart {
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
NOT_IN_PRODUCT(Profiler::DumpStackTrace(true /* native_stack_trace */)); \
NOT_IN_PRODUCT(Profiler::DumpStackTrace()); \
FATAL2("pthread error: %d (%s)", result, \
Utils::StrError(result, error_buf, kBufferSize)); \
}

View file

@ -29,7 +29,7 @@ namespace dart {
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
NOT_IN_PRODUCT(Profiler::DumpStackTrace(true /* native_stack_trace */)); \
NOT_IN_PRODUCT(Profiler::DumpStackTrace()); \
Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}

View file

@ -418,67 +418,54 @@ class ProfilerStackWalker : public ValueObject {
};
// Given an exit frame, walk the Dart stack.
class ProfilerDartExitStackWalker : public ProfilerStackWalker {
public:
ProfilerDartExitStackWalker(Thread* thread,
Isolate* isolate,
Sample* sample,
SampleBuffer* sample_buffer)
: ProfilerStackWalker(isolate, sample, sample_buffer),
frame_iterator_(thread) {}
void walk() {
// Mark that this sample was collected from an exit frame.
sample_->set_exit_frame_sample(true);
StackFrame* frame = frame_iterator_.NextFrame();
if (sample_ == NULL) {
// Only when we are dumping the stack trace for debug purposes.
Code& code = Code::Handle();
while (frame != NULL) {
code ^= frame->LookupDartCode();
if (!Append(frame->pc(), code)) {
return;
}
frame = frame_iterator_.NextFrame();
}
} else {
while (frame != NULL) {
if (!Append(frame->pc())) {
return;
}
frame = frame_iterator_.NextFrame();
}
}
}
private:
DartFrameIterator frame_iterator_;
};
// Executing Dart code, walk the stack.
class ProfilerDartStackWalker : public ProfilerStackWalker {
public:
ProfilerDartStackWalker(Isolate* isolate,
ProfilerDartStackWalker(Thread* thread,
Sample* sample,
SampleBuffer* sample_buffer,
uword stack_lower,
uword stack_upper,
uword pc,
uword fp,
uword sp)
: ProfilerStackWalker(isolate, sample, sample_buffer),
uword sp,
bool exited_dart_code,
bool allocation_sample)
: ProfilerStackWalker(thread->isolate(), sample, sample_buffer),
pc_(reinterpret_cast<uword*>(pc)),
fp_(reinterpret_cast<uword*>(fp)),
sp_(reinterpret_cast<uword*>(sp)),
stack_upper_(stack_upper),
stack_lower_(stack_lower) {
pc_ = reinterpret_cast<uword*>(pc);
fp_ = reinterpret_cast<uword*>(fp);
sp_ = reinterpret_cast<uword*>(sp);
stack_lower_(stack_lower),
has_exit_frame_(exited_dart_code) {
if (exited_dart_code) {
StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames,
thread);
pc_ = NULL;
fp_ = NULL;
sp_ = NULL;
if (!iterator.HasNextFrame()) {
return;
}
// Ensure we are able to get to the exit frame.
StackFrame* frame = iterator.NextFrame();
if (!frame->IsExitFrame()) {
return;
}
// Skip the exit frame.
if (!iterator.HasNextFrame()) {
return;
}
frame = iterator.NextFrame();
// Record frame details of the first frame from which we start walking.
pc_ = reinterpret_cast<uword*>(frame->pc());
fp_ = reinterpret_cast<uword*>(frame->fp());
sp_ = reinterpret_cast<uword*>(frame->sp());
}
}
void walk() {
sample_->set_exit_frame_sample(false);
sample_->set_exit_frame_sample(has_exit_frame_);
if (!ValidFramePointer()) {
sample_->set_ignore_sample(true);
return;
@ -605,7 +592,8 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
uword* fp_;
uword* sp_;
const uword stack_upper_;
uword stack_lower_;
const uword stack_lower_;
bool has_exit_frame_;
};
@ -758,7 +746,6 @@ static void CollectSample(Isolate* isolate,
bool in_dart_code,
Sample* sample,
ProfilerNativeStackWalker* native_stack_walker,
ProfilerDartExitStackWalker* dart_exit_stack_walker,
ProfilerDartStackWalker* dart_stack_walker,
uword pc,
uword fp,
@ -783,7 +770,7 @@ static void CollectSample(Isolate* isolate,
} else if (StubCode::HasBeenInitialized() && exited_dart_code) {
AtomicOperations::IncrementInt64By(&counters->stack_walker_dart_exit, 1);
// We have a valid exit frame info, use the Dart stack walker.
dart_exit_stack_walker->walk();
dart_stack_walker->walk();
} else if (StubCode::HasBeenInitialized() && in_dart_code) {
AtomicOperations::IncrementInt64By(&counters->stack_walker_dart, 1);
// We are executing Dart code. We have frame pointers.
@ -944,7 +931,7 @@ static uintptr_t __attribute__((noinline)) GetProgramCounter() {
#endif
void Profiler::DumpStackTrace(bool native_stack_trace) {
void Profiler::DumpStackTrace() {
// Allow only one stack trace to prevent recursively printing stack traces if
// we hit an assert while printing the stack.
static uintptr_t started_dump = 0;
@ -964,10 +951,7 @@ void Profiler::DumpStackTrace(bool native_stack_trace) {
return;
}
const bool exited_dart_code = thread->HasExitedDartCode();
OS::PrintErr("Dumping %s stack trace for thread %" Px "\n",
native_stack_trace ? "native" : "dart-only",
OS::PrintErr("Dumping native stack trace for thread %" Px "\n",
OSThread::ThreadIdToIntPtr(os_thread->trace_id()));
uintptr_t sp = Thread::GetCurrentStackPointer();
@ -991,18 +975,9 @@ void Profiler::DumpStackTrace(bool native_stack_trace) {
return;
}
if (native_stack_trace) {
ProfilerNativeStackWalker native_stack_walker(
isolate, NULL, NULL, stack_lower, stack_upper, pc, fp, sp);
native_stack_walker.walk();
} else if (exited_dart_code) {
ProfilerDartExitStackWalker dart_exit_stack_walker(thread, isolate, NULL,
NULL);
dart_exit_stack_walker.walk();
} else {
ProfilerDartStackWalker dart_stack_walker(isolate, NULL, NULL, stack_lower,
stack_upper, pc, fp, sp);
}
ProfilerNativeStackWalker native_stack_walker(
isolate, NULL, NULL, stack_lower, stack_upper, pc, fp, sp);
native_stack_walker.walk();
OS::PrintErr("-- End of DumpStackTrace\n");
}
@ -1024,36 +999,36 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
return;
}
uintptr_t sp = Thread::GetCurrentStackPointer();
uintptr_t fp = 0;
uintptr_t pc = GetProgramCounter();
COPY_FP_REGISTER(fp);
uword stack_lower = 0;
uword stack_upper = 0;
if (!InitialRegisterCheck(pc, fp, sp)) {
return;
}
if (!GetAndValidateIsolateStackBounds(thread, fp, sp, &stack_lower,
&stack_upper)) {
// Could not get stack boundary.
return;
}
Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id());
sample->SetAllocationCid(cid);
if (FLAG_profile_vm) {
uintptr_t sp = Thread::GetCurrentStackPointer();
uintptr_t fp = 0;
uintptr_t pc = GetProgramCounter();
COPY_FP_REGISTER(fp);
uword stack_lower = 0;
uword stack_upper = 0;
if (!InitialRegisterCheck(pc, fp, sp)) {
return;
}
if (!GetAndValidateIsolateStackBounds(thread, fp, sp, &stack_lower,
&stack_upper)) {
// Could not get stack boundary.
return;
}
Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id());
sample->SetAllocationCid(cid);
ProfilerNativeStackWalker native_stack_walker(
isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
native_stack_walker.walk();
} else if (exited_dart_code) {
Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id());
sample->SetAllocationCid(cid);
ProfilerDartExitStackWalker dart_exit_stack_walker(thread, isolate, sample,
sample_buffer);
ProfilerDartStackWalker dart_exit_stack_walker(
thread, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp,
exited_dart_code, true);
dart_exit_stack_walker.walk();
} else {
// Fall back.
@ -1192,19 +1167,15 @@ void Profiler::SampleThread(Thread* thread,
ProfilerNativeStackWalker native_stack_walker(
isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
ProfilerDartExitStackWalker dart_exit_stack_walker(thread, isolate, sample,
sample_buffer);
ProfilerDartStackWalker dart_stack_walker(
isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
const bool exited_dart_code = thread->HasExitedDartCode();
ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer,
stack_lower, stack_upper, pc, fp,
sp, exited_dart_code, false);
// All memory access is done inside CollectSample.
CollectSample(isolate, exited_dart_code, in_dart_code, sample,
&native_stack_walker, &dart_exit_stack_walker,
&dart_stack_walker, pc, fp, sp, &counters_);
&native_stack_walker, &dart_stack_walker, pc, fp, sp,
&counters_);
}

View file

@ -54,7 +54,7 @@ class Profiler : public AllStatic {
static SampleBuffer* sample_buffer() { return sample_buffer_; }
static void DumpStackTrace(bool native_stack_trace = true);
static void DumpStackTrace();
static void SampleAllocation(Thread* thread, intptr_t cid);

View file

@ -252,6 +252,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -265,6 +267,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
@ -274,6 +278,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -287,6 +293,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -372,6 +380,8 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -385,6 +395,8 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
@ -394,6 +406,8 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -407,6 +421,8 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -499,10 +515,12 @@ TEST_CASE(Profiler_CodeTicks) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
@ -522,6 +540,8 @@ TEST_CASE(Profiler_CodeTicks) {
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
@ -598,10 +618,12 @@ TEST_CASE(Profiler_FunctionTicks) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
@ -621,6 +643,8 @@ TEST_CASE(Profiler_FunctionTicks) {
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
@ -747,6 +771,8 @@ TEST_CASE(Profiler_ArrayAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] AllocateArray", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_List._List", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("List.List", walker.CurrentName());
@ -797,6 +823,8 @@ TEST_CASE(Profiler_ArrayAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] AllocateArray", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_List._List", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_GrowableList._GrowableList", walker.CurrentName());
@ -857,6 +885,8 @@ TEST_CASE(Profiler_ContextAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateContext", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] AllocateContext", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -923,6 +953,8 @@ TEST_CASE(Profiler_ClosureAllocation) {
EXPECT(walker.Down());
EXPECT_SUBSTRING("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate _Closure", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_SUBSTRING("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -1080,8 +1112,10 @@ TEST_CASE(Profiler_StringAllocation) {
EXPECT(walker.Down());
EXPECT_STREQ("String_concat", walker.CurrentName());
EXPECT(walker.Down());
#if 1
EXPECT_STREQ("_StringBase.+", walker.CurrentName());
EXPECT(walker.Down());
#endif
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -1286,11 +1320,13 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("mainA", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
@ -1311,6 +1347,8 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
@ -1322,11 +1360,13 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.choo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.foo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
@ -1373,6 +1413,8 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
@ -1397,6 +1439,10 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
@ -1416,6 +1462,10 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
@ -1425,6 +1475,10 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Inline End]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.choo", walker.CurrentName());
@ -1446,8 +1500,6 @@ TEST_CASE(Profiler_FunctionInline) {
// mainA -> B.boo -> B.foo -> B.choo.
walker.Reset(Profile::kInclusiveFunction);
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("mainA", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
@ -1462,6 +1514,10 @@ TEST_CASE(Profiler_FunctionInline) {
EXPECT(walker.Down());
EXPECT_STREQ("[Inline End]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -1518,6 +1574,7 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
const Class& class_a = Class::Handle(GetClass(root_library, "A"));
EXPECT(!class_a.IsNull());
/*
// Compile and optimize.
Dart_Handle result = Dart_Invoke(lib, NewString("mainNoAlloc"), 0, NULL);
EXPECT_VALID(result);
@ -1550,11 +1607,12 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
*/
// Turn on allocation tracing for A.
class_a.SetTraceAllocation(true);
result = Dart_Invoke(lib, NewString("mainAlloc"), 0, NULL);
Dart_Handle result = Dart_Invoke(lib, NewString("mainAlloc"), 0, NULL);
EXPECT_VALID(result);
{
@ -1573,6 +1631,8 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("maybeAlloc", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("right", walker.CurrentName());
@ -1593,6 +1653,8 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
EXPECT(walker.Down());
EXPECT_STREQ("maybeAlloc", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@ -1667,6 +1729,8 @@ TEST_CASE(Profiler_ChainedSamples) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("orange", walker.CurrentName());
@ -1768,10 +1832,12 @@ TEST_CASE(Profiler_BasicSourcePosition) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -1860,10 +1926,12 @@ TEST_CASE(Profiler_BasicSourcePositionOptimized) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@ -1945,10 +2013,12 @@ TEST_CASE(Profiler_SourcePosition) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
@ -2068,10 +2138,12 @@ TEST_CASE(Profiler_SourcePositionOptimized) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
@ -2174,10 +2246,12 @@ TEST_CASE(Profiler_BinaryOperatorSourcePosition) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
@ -2306,10 +2380,12 @@ TEST_CASE(Profiler_BinaryOperatorSourcePositionOptimized) {
EXPECT(walker.Down());
EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());

View file

@ -147,6 +147,7 @@ class StackFrame : public ValueObject {
// fields fp_ and sp_ when they return the respective frame objects.
friend class FrameSetIterator;
friend class StackFrameIterator;
friend class ProfilerDartStackWalker;
DISALLOW_COPY_AND_ASSIGN(StackFrame);
};
@ -286,6 +287,7 @@ class StackFrameIterator : public ValueObject {
StackFrame* current_frame_; // Points to the current frame in the iterator.
Thread* thread_;
friend class ProfilerDartStackWalker;
DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
};