Index: runtime/vm/profiler_test.cc |
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc |
index e9017d89cc45f8baca286bf74ecbee5584f4250b..af0a26d30dbfff2b7ff82ed827fc0222cafd8489 100644 |
--- a/runtime/vm/profiler_test.cc |
+++ b/runtime/vm/profiler_test.cc |
@@ -14,9 +14,10 @@ |
namespace dart { |
DECLARE_FLAG(bool, profile_vm); |
+DECLARE_FLAG(int, max_profile_depth); |
// Some tests are written assuming native stack trace profiling is disabled. |
-class DisableNativeProfileScope { |
+class DisableNativeProfileScope : public ValueObject { |
public: |
DisableNativeProfileScope() |
: FLAG_profile_vm_(FLAG_profile_vm) { |
@@ -32,6 +33,23 @@ class DisableNativeProfileScope { |
}; |
+// Temporarily adjust the maximum profile depth. |
+class MaxProfileDepthScope : public ValueObject { |
+ public: |
+ explicit MaxProfileDepthScope(intptr_t new_max_depth) |
+ : FLAG_max_profile_depth_(FLAG_max_profile_depth) { |
+ Profiler::SetSampleDepth(new_max_depth); |
+ } |
+ |
+ ~MaxProfileDepthScope() { |
+ Profiler::SetSampleDepth(FLAG_max_profile_depth_); |
+ } |
+ |
+ private: |
+ const intptr_t FLAG_max_profile_depth_; |
+}; |
+ |
+ |
class ProfileSampleBufferTestHelper { |
public: |
static intptr_t IterateCount(const Isolate* isolate, |
@@ -186,9 +204,10 @@ TEST_CASE(Profiler_TrivialRecordAllocation) { |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -264,9 +283,10 @@ TEST_CASE(Profiler_ToggleRecordAllocation) { |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -281,9 +301,10 @@ TEST_CASE(Profiler_ToggleRecordAllocation) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -335,9 +356,10 @@ TEST_CASE(Profiler_ToggleRecordAllocation) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -375,9 +397,10 @@ TEST_CASE(Profiler_CodeTicks) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -397,9 +420,10 @@ TEST_CASE(Profiler_CodeTicks) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -468,9 +492,10 @@ TEST_CASE(Profiler_FunctionTicks) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -490,9 +515,10 @@ TEST_CASE(Profiler_FunctionTicks) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -1141,9 +1167,10 @@ TEST_CASE(Profiler_FunctionInline) { |
// At this point B.boo should be optimized and inlined B.foo and B.choo. |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -1159,9 +1186,10 @@ TEST_CASE(Profiler_FunctionInline) { |
EXPECT_VALID(result); |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, Profile::kNoTags); |
@@ -1260,9 +1288,10 @@ TEST_CASE(Profiler_FunctionInline) { |
// Test code transition tags. |
{ |
- Isolate* isolate = Isolate::Current(); |
- StackZone zone(isolate); |
- HANDLESCOPE(isolate); |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
Profile profile(isolate); |
AllocationFilter filter(isolate, class_a.id()); |
profile.Build(&filter, |
@@ -1338,5 +1367,113 @@ TEST_CASE(Profiler_FunctionInline) { |
} |
} |
+ |
+TEST_CASE(Profiler_ChainedSamples) { |
+ MaxProfileDepthScope mpds(32); |
+ // Each sample holds 8 stack frames. |
+ // This chain is 20 stack frames deep. |
+ const char* kScript = |
+ "class A {\n" |
+ " var a;\n" |
+ " var b;\n" |
+ "}\n" |
+ "class B {\n" |
+ " static boo() {\n" |
+ " return new A();\n" |
+ " }\n" |
+ "}\n" |
+ "go() => init();\n" |
+ "init() => secondInit();\n" |
+ "secondInit() => apple();\n" |
+ "apple() => banana();\n" |
+ "banana() => cantaloupe();\n" |
+ "cantaloupe() => dog();\n" |
+ "dog() => elephant();\n" |
+ "elephant() => fred();\n" |
+ "fred() => granola();\n" |
+ "granola() => haystack();\n" |
+ "haystack() => ice();\n" |
+ "ice() => jeep();\n" |
+ "jeep() => kindle();\n" |
+ "kindle() => lemon();\n" |
+ "lemon() => mayo();\n" |
+ "mayo() => napkin();\n" |
+ "napkin() => orange();\n" |
+ "orange() => B.boo();\n" |
+ "main() {\n" |
+ " return go();\n" |
+ "}\n"; |
+ |
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); |
+ EXPECT_VALID(lib); |
+ Library& root_library = Library::Handle(); |
+ root_library ^= Api::UnwrapHandle(lib); |
+ |
+ const Class& class_a = Class::Handle(GetClass(root_library, "A")); |
+ EXPECT(!class_a.IsNull()); |
+ class_a.SetTraceAllocation(true); |
+ |
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
+ EXPECT_VALID(result); |
+ |
+ |
+ { |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
+ Profile profile(isolate); |
+ AllocationFilter filter(isolate, class_a.id()); |
+ profile.Build(&filter, Profile::kNoTags); |
+ // We should have 1 allocation sample. |
+ EXPECT_EQ(1, profile.sample_count()); |
+ ProfileTrieWalker walker(&profile); |
+ |
+ walker.Reset(Profile::kExclusiveCode); |
+ // Move down from the root. |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("B.boo", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("orange", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("napkin", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("mayo", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("lemon", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("kindle", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("jeep", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("ice", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("haystack", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("granola", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("fred", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("elephant", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dog", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("cantaloupe", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("banana", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("apple", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("secondInit", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("init", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("go", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("main", walker.CurrentName()); |
+ EXPECT(!walker.Down()); |
+ } |
+} |
+ |
} // namespace dart |