Index: runtime/vm/profiler_test.cc |
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc |
index 08d3980cb74327a8544f11615c85330e43ec050d..ccada84dc3b8c8812b8727ed8832a4cabac97a60 100644 |
--- a/runtime/vm/profiler_test.cc |
+++ b/runtime/vm/profiler_test.cc |
@@ -316,6 +316,217 @@ TEST_CASE(Profiler_TrivialRecordAllocation) { |
} |
} |
+#if defined(DART_USE_TCMALLOC) && defined(HOST_OS_LINUX) && defined(DEBUG) && \ |
+ defined(HOST_ARCH_x64) |
+ |
+DART_NOINLINE static void NativeAllocationSampleHelper(char** result) { |
+ ASSERT(result != NULL); |
+ *result = static_cast<char*>(malloc(sizeof(char) * 1024)); |
+} |
+ |
+ |
+ISOLATE_UNIT_TEST_CASE(Profiler_NativeAllocation) { |
+ bool enable_malloc_hooks_saved = FLAG_enable_malloc_hooks; |
+ FLAG_enable_malloc_hooks = true; |
+ |
+ MallocHooks::InitOnce(); |
+ MallocHooks::ResetStats(); |
+ bool stack_trace_collection_enabled = |
+ MallocHooks::stack_trace_collection_enabled(); |
+ MallocHooks::set_stack_trace_collection_enabled(true); |
+ |
+ char* result = NULL; |
+ const int64_t before_allocations_micros = Dart_TimelineGetMicros(); |
+ NativeAllocationSampleHelper(&result); |
+ |
+ // Disable stack allocation stack trace collection to avoid muddying up |
+ // results. |
+ MallocHooks::set_stack_trace_collection_enabled(false); |
+ const int64_t after_allocations_micros = Dart_TimelineGetMicros(); |
+ const int64_t allocation_extent_micros = |
+ after_allocations_micros - before_allocations_micros; |
+ |
+ // Walk the trie and do a sanity check of the allocation values associated |
+ // with each node. |
+ { |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
+ Profile profile(isolate); |
+ |
+ // Filter for the class in the time range. |
+ NativeAllocationSampleFilter filter(before_allocations_micros, |
+ allocation_extent_micros); |
+ profile.Build(thread, &filter, Profile::kNoTags); |
+ // We should have 1 allocation sample. |
+ EXPECT_EQ(1, profile.sample_count()); |
+ ProfileTrieWalker walker(&profile); |
+ |
+ // Exclusive code: NativeAllocationSampleHelper -> main. |
+ walker.Reset(Profile::kExclusiveCode); |
+ // Move down from the root. |
+ EXPECT(walker.Down()); |
+ EXPECT_SUBSTRING("[Native]", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()", |
+ walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("main", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(!walker.Down()); |
+ |
+ // Inclusive code: main -> NativeAllocationSampleHelper. |
+ walker.Reset(Profile::kInclusiveCode); |
+ // Move down from the root. |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("main", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()", |
+ walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_SUBSTRING("[Native]", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024); |
+ EXPECT(!walker.Down()); |
+ |
+ // Exclusive function: NativeAllocationSampleHelper -> main. |
+ walker.Reset(Profile::kExclusiveFunction); |
+ // Move down from the root. |
+ EXPECT(walker.Down()); |
+ EXPECT_SUBSTRING("[Native]", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()", |
+ walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("main", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(!walker.Down()); |
+ |
+ // Inclusive function: main -> NativeAllocationSampleHelper. |
+ walker.Reset(Profile::kInclusiveFunction); |
+ // Move down from the root. |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("main", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()", |
+ walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0); |
+ EXPECT(walker.Down()); |
+ EXPECT_SUBSTRING("[Native]", walker.CurrentName()); |
+ EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024); |
+ EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024); |
+ EXPECT(!walker.Down()); |
+ } |
+ |
+ MallocHooks::set_stack_trace_collection_enabled(true); |
+ free(result); |
+ MallocHooks::set_stack_trace_collection_enabled(false); |
+ |
+ // Check to see that the native allocation sample associated with the memory |
+ // freed above is marked as free and is no longer reported. |
+ { |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
+ Profile profile(isolate); |
+ |
+ // Filter for the class in the time range. |
+ NativeAllocationSampleFilter filter(before_allocations_micros, |
+ allocation_extent_micros); |
+ profile.Build(thread, &filter, Profile::kNoTags); |
+ // We should have 0 allocation samples since we freed the memory. |
+ EXPECT_EQ(0, profile.sample_count()); |
+ } |
+ |
+ // Query with a time filter where no allocations occurred. |
+ { |
+ Thread* thread = Thread::Current(); |
+ Isolate* isolate = thread->isolate(); |
+ StackZone zone(thread); |
+ HANDLESCOPE(thread); |
+ Profile profile(isolate); |
+ NativeAllocationSampleFilter filter(Dart_TimelineGetMicros(), 16000); |
+ profile.Build(thread, &filter, Profile::kNoTags); |
+ // We should have no allocation samples because none occured within |
+ // the specified time range. |
+ EXPECT_EQ(0, profile.sample_count()); |
+ } |
+ |
+ MallocHooks::set_stack_trace_collection_enabled( |
+ stack_trace_collection_enabled); |
+ MallocHooks::TearDown(); |
+ FLAG_enable_malloc_hooks = enable_malloc_hooks_saved; |
+} |
+#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) && |
+ // !defined(TARGET_ARCH_DBC) && !defined(HOST_OS_FUCHSIA) |
+ |
TEST_CASE(Profiler_ToggleRecordAllocation) { |
DisableNativeProfileScope dnps; |