Chromium Code Reviews| 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; |