Index: runtime/vm/profiler_test.cc |
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc |
index 35338515d72ce136f2b84980f8cf35e66228e8cc..f224a68736b5f00a4acd23d9adce0d264c58079d 100644 |
--- a/runtime/vm/profiler_test.cc |
+++ b/runtime/vm/profiler_test.cc |
@@ -139,6 +139,7 @@ TEST_CASE(Profiler_AllocationSampleTest) { |
delete sample_buffer; |
} |
+ |
static RawClass* GetClass(const Library& lib, const char* name) { |
const Class& cls = Class::Handle( |
lib.LookupClassAllowPrivate(String::Handle(Symbols::New(name)))); |
@@ -147,6 +148,14 @@ static RawClass* GetClass(const Library& lib, const char* name) { |
} |
+static RawFunction* GetFunction(const Library& lib, const char* name) { |
+ const Function& func = Function::Handle( |
+ lib.LookupFunctionAllowPrivate(String::Handle(Symbols::New(name)))); |
+ EXPECT(!func.IsNull()); // No ambiguity error expected. |
+ return func.raw(); |
+} |
+ |
+ |
class AllocationFilter : public SampleFilter { |
public: |
AllocationFilter(Isolate* isolate, |
@@ -1402,6 +1411,131 @@ TEST_CASE(Profiler_FunctionInline) { |
} |
+TEST_CASE(Profiler_InliningIntervalBoundry) { |
Cutch
2016/01/12 22:27:50
Add a comment here and point out the code in profi
rmacnak
2016/01/13 00:40:49
Done.
|
+ DisableNativeProfileScope dnps; |
+ const char* kScript = |
+ "class A {\n" |
+ "}\n" |
+ "bool alloc = false;" |
+ "maybeAlloc() {\n" |
+ " try {\n" |
+ " if (alloc) new A();\n" |
+ " } catch (e) {\n" |
+ " }\n" |
+ "}\n" |
+ "right() => maybeAlloc();\n" |
+ "doNothing() {\n" |
+ " try {\n" |
+ " } catch (e) {\n" |
+ " }\n" |
+ "}\n" |
+ "wrong() => doNothing();\n" |
+ "a() {\n" |
+ " try {\n" |
+ " right();\n" |
+ " wrong();\n" |
+ " } catch (e) {\n" |
+ " }\n" |
+ "}\n" |
+ "mainNoAlloc() {\n" |
+ " for (var i = 0; i < 20000; i++) {\n" |
+ " a();\n" |
+ " }\n" |
+ "}\n" |
+ "mainAlloc() {\n" |
+ " alloc = true;\n" |
+ " a();\n" |
+ "}\n"; |
+ |
+ const bool old_flag = FLAG_background_compilation; |
+ FLAG_background_compilation = false; |
Cutch
2016/01/12 22:27:50
Might want to introduce a Scope object like Disabl
rmacnak
2016/01/13 00:40:49
Done, here and Profiler_FunctionInline
|
+ 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()); |
+ |
+ // Compile and optimize. |
+ Dart_Handle result = Dart_Invoke(lib, NewString("mainNoAlloc"), 0, NULL); |
+ EXPECT_VALID(result); |
+ result = Dart_Invoke(lib, NewString("mainAlloc"), 0, NULL); |
+ EXPECT_VALID(result); |
+ |
+ // At this point a should be optimized and have inlined both right and wrong, |
+ // but not maybeAllocate or doNothing. |
+ Function& func = Function::Handle(); |
+ func = GetFunction(root_library, "a"); |
+ EXPECT(!func.is_inlinable()); |
+ EXPECT(func.HasOptimizedCode()); |
+ func = GetFunction(root_library, "right"); |
+ EXPECT(func.is_inlinable()); |
+ func = GetFunction(root_library, "wrong"); |
+ EXPECT(func.is_inlinable()); |
+ func = GetFunction(root_library, "doNothing"); |
+ EXPECT(!func.is_inlinable()); |
+ func = GetFunction(root_library, "maybeAlloc"); |
+ EXPECT(!func.is_inlinable()); |
+ |
+ { |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
+ Profile profile(isolate); |
+ AllocationFilter filter(isolate, class_a.id()); |
+ profile.Build(thread, &filter, Profile::kNoTags); |
+ // 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); |
+ 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(thread, &filter, Profile::kNoTags); |
+ EXPECT_EQ(1, profile.sample_count()); |
+ ProfileTrieWalker walker(&profile); |
+ |
+ // Inline expansion should show us the complete call chain: |
+ walker.Reset(Profile::kExclusiveFunction); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("maybeAlloc", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("right", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("a", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("mainAlloc", walker.CurrentName()); |
+ EXPECT(!walker.Down()); |
+ |
+ // Inline expansion should show us the complete call chain: |
+ walker.Reset(Profile::kInclusiveFunction); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("mainAlloc", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("a", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("right", walker.CurrentName()); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("maybeAlloc", walker.CurrentName()); |
+ EXPECT(!walker.Down()); |
+ } |
+ |
+ FLAG_background_compilation = old_flag; |
+} |
+ |
+ |
TEST_CASE(Profiler_ChainedSamples) { |
MaxProfileDepthScope mpds(32); |
DisableNativeProfileScope dnps; |