Test tracing of string allocations

Also, fix a bug in string allocation tracing.

R=rmacnak@google.com

Review URL: https://codereview.chromium.org//1230063010 .
This commit is contained in:
John McCutchan 2015-07-10 14:30:04 -07:00
parent 13a372eca0
commit 4da11ef37f
6 changed files with 167 additions and 3 deletions

View file

@ -1763,7 +1763,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
Label* failure) {
const Register length_reg = R2;
Label fail;
__ MaybeTraceAllocation(kOneByteStringCid, R0, failure);
__ mov(R6, Operand(length_reg)); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);

View file

@ -1843,7 +1843,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
Label* failure) {
const Register length_reg = R2;
Label fail;
__ MaybeTraceAllocation(kOneByteStringCid, R0, kNoPP, failure);
__ mov(R6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);

View file

@ -1869,6 +1869,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
Label* ok,
Label* failure,
Register length_reg) {
__ MaybeTraceAllocation(kOneByteStringCid, EAX, failure, false);
if (length_reg != EDI) {
__ movl(EDI, length_reg);
}

View file

@ -1883,7 +1883,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
Label* ok,
Label* failure) {
const Register length_reg = T2;
__ MaybeTraceAllocation(kOneByteStringCid, V0, failure);
__ mov(T6, length_reg); // Save the length register.
// TODO(koda): Protect against negative length and overflow here.
__ SmiUntag(length_reg);

View file

@ -1727,6 +1727,7 @@ static void TryAllocateOnebyteString(Assembler* assembler,
Label* ok,
Label* failure,
Register length_reg) {
__ MaybeTraceAllocation(kOneByteStringCid, failure, false);
if (length_reg != RDI) {
__ movq(RDI, length_reg);
}

View file

@ -569,4 +569,166 @@ TEST_CASE(Profiler_TypedArrayAllocation) {
}
}
TEST_CASE(Profiler_StringAllocation) {
const char* kScript = "String foo(String a, String b) => a + b;";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Library& root_library = Library::Handle();
root_library ^= Api::UnwrapHandle(lib);
Isolate* isolate = Isolate::Current();
const Class& one_byte_string_class =
Class::Handle(isolate->object_store()->one_byte_string_class());
EXPECT(!one_byte_string_class.IsNull());
Dart_Handle args[2] = { NewString("a"), NewString("b"), };
Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
one_byte_string_class.SetTraceAllocation(true);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
ProfileTrieWalker walker(&profile);
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
EXPECT_STREQ("_StringBase.+", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
one_byte_string_class.SetTraceAllocation(false);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
one_byte_string_class.SetTraceAllocation(true);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should now have two allocation samples.
EXPECT_EQ(2, profile.sample_count());
}
}
TEST_CASE(Profiler_StringInterpolation) {
const char* kScript = "String foo(String a, String b) => '$a | $b';";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Library& root_library = Library::Handle();
root_library ^= Api::UnwrapHandle(lib);
Isolate* isolate = Isolate::Current();
const Class& one_byte_string_class =
Class::Handle(isolate->object_store()->one_byte_string_class());
EXPECT(!one_byte_string_class.IsNull());
Dart_Handle args[2] = { NewString("a"), NewString("b"), };
Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
one_byte_string_class.SetTraceAllocation(true);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
ProfileTrieWalker walker(&profile);
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
EXPECT_STREQ("_OneByteString._allocate", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_OneByteString._concatAll", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_StringBase._interpolate", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
one_byte_string_class.SetTraceAllocation(false);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
one_byte_string_class.SetTraceAllocation(true);
result = Dart_Invoke(lib, NewString("foo"), 2, &args[0]);
EXPECT_VALID(result);
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
Profile profile(isolate);
AllocationFilter filter(isolate, one_byte_string_class.id());
profile.Build(&filter, Profile::kNoTags);
// We should now have two allocation samples.
EXPECT_EQ(2, profile.sample_count());
}
}
} // namespace dart