| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/trace_event/memory_allocator_dump.h" |
| |
| #include "base/format_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/memory_allocator_dump_guid.h" |
| #include "base/trace_event/memory_dump_provider.h" |
| #include "base/trace_event/process_memory_dump.h" |
| #include "base/trace_event/trace_event_argument.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "starboard/types.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::ElementsAre; |
| using testing::Eq; |
| using testing::ByRef; |
| using testing::IsEmpty; |
| using testing::Contains; |
| |
| namespace base { |
| namespace trace_event { |
| |
| namespace { |
| |
| class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider { |
| public: |
| bool OnMemoryDump(const MemoryDumpArgs& args, |
| ProcessMemoryDump* pmd) override { |
| MemoryAllocatorDump* root_heap = |
| pmd->CreateAllocatorDump("foobar_allocator"); |
| |
| root_heap->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, 4096); |
| root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
| MemoryAllocatorDump::kUnitsObjects, 42); |
| root_heap->AddScalar("attr1", "units1", 1234); |
| root_heap->AddString("attr2", "units2", "string_value"); |
| |
| MemoryAllocatorDump* sub_heap = |
| pmd->CreateAllocatorDump("foobar_allocator/sub_heap"); |
| sub_heap->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, 1); |
| sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, |
| MemoryAllocatorDump::kUnitsObjects, 3); |
| |
| pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty"); |
| // Leave the rest of sub heap deliberately uninitialized, to check that |
| // CreateAllocatorDump returns a properly zero-initialized object. |
| |
| return true; |
| } |
| }; |
| |
| void CheckString(const MemoryAllocatorDump* dump, |
| const std::string& name, |
| const char* expected_units, |
| const std::string& expected_value) { |
| MemoryAllocatorDump::Entry expected(name, expected_units, expected_value); |
| EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected)))); |
| } |
| |
| void CheckScalar(const MemoryAllocatorDump* dump, |
| const std::string& name, |
| const char* expected_units, |
| uint64_t expected_value) { |
| MemoryAllocatorDump::Entry expected(name, expected_units, expected_value); |
| EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(expected)))); |
| } |
| |
| } // namespace |
| |
| TEST(MemoryAllocatorDumpTest, GuidGeneration) { |
| std::unique_ptr<MemoryAllocatorDump> mad(new MemoryAllocatorDump( |
| "foo", MemoryDumpLevelOfDetail::FIRST, MemoryAllocatorDumpGuid(0x42u))); |
| ASSERT_EQ("42", mad->guid().ToString()); |
| } |
| |
| TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) { |
| FakeMemoryAllocatorDumpProvider fmadp; |
| MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; |
| ProcessMemoryDump pmd(dump_args); |
| |
| fmadp.OnMemoryDump(dump_args, &pmd); |
| |
| ASSERT_EQ(3u, pmd.allocator_dumps().size()); |
| |
| const MemoryAllocatorDump* root_heap = |
| pmd.GetAllocatorDump("foobar_allocator"); |
| ASSERT_NE(nullptr, root_heap); |
| EXPECT_EQ("foobar_allocator", root_heap->absolute_name()); |
| CheckScalar(root_heap, MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, 4096); |
| CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount, |
| MemoryAllocatorDump::kUnitsObjects, 42); |
| CheckScalar(root_heap, "attr1", "units1", 1234); |
| CheckString(root_heap, "attr2", "units2", "string_value"); |
| |
| const MemoryAllocatorDump* sub_heap = |
| pmd.GetAllocatorDump("foobar_allocator/sub_heap"); |
| ASSERT_NE(nullptr, sub_heap); |
| EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name()); |
| CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, 1); |
| CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount, |
| MemoryAllocatorDump::kUnitsObjects, 3); |
| const MemoryAllocatorDump* empty_sub_heap = |
| pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty"); |
| ASSERT_NE(nullptr, empty_sub_heap); |
| EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name()); |
| |
| EXPECT_THAT(empty_sub_heap->entries(), IsEmpty()); |
| |
| // Check that calling serialization routines doesn't cause a crash. |
| std::unique_ptr<TracedValue> traced_value(new TracedValue); |
| pmd.SerializeAllocatorDumpsInto(traced_value.get()); |
| } |
| |
| TEST(MemoryAllocatorDumpTest, GetSize) { |
| MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; |
| ProcessMemoryDump pmd(dump_args); |
| MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size"); |
| dump->AddScalar(MemoryAllocatorDump::kNameSize, |
| MemoryAllocatorDump::kUnitsBytes, 1); |
| dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2); |
| EXPECT_EQ(1u, dump->GetSizeInternal()); |
| } |
| |
| TEST(MemoryAllocatorDumpTest, ReadValues) { |
| MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; |
| ProcessMemoryDump pmd(dump_args); |
| MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size"); |
| dump->AddScalar("one", "byte", 1); |
| dump->AddString("one", "object", "one"); |
| |
| MemoryAllocatorDump::Entry expected_scalar("one", "byte", 1); |
| MemoryAllocatorDump::Entry expected_string("one", "object", "one"); |
| EXPECT_THAT(dump->entries(), ElementsAre(Eq(ByRef(expected_scalar)), |
| Eq(ByRef(expected_string)))); |
| } |
| |
| TEST(MemoryAllocatorDumpTest, MovingAnEntry) { |
| MemoryAllocatorDump::Entry expected_entry("one", "byte", 1); |
| MemoryAllocatorDump::Entry from_entry("one", "byte", 1); |
| MemoryAllocatorDump::Entry to_entry = std::move(from_entry); |
| EXPECT_EQ(expected_entry, to_entry); |
| } |
| |
| // DEATH tests are not supported in Android/iOS/Fuchsia. |
| #if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS) && \ |
| !defined(OS_FUCHSIA) |
| TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) { |
| FakeMemoryAllocatorDumpProvider fmadp; |
| MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; |
| ProcessMemoryDump pmd(dump_args); |
| pmd.CreateAllocatorDump("foo_allocator"); |
| pmd.CreateAllocatorDump("bar_allocator/heap"); |
| ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), ""); |
| ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), ""); |
| ASSERT_DEATH(pmd.CreateAllocatorDump(""), ""); |
| } |
| |
| TEST(MemoryAllocatorDumpTest, ForbidStringsInBackgroundModeDeathTest) { |
| MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::BACKGROUND}; |
| ProcessMemoryDump pmd(dump_args); |
| MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("malloc"); |
| ASSERT_DEATH(dump->AddString("foo", "bar", "baz"), ""); |
| } |
| #endif |
| |
| } // namespace trace_event |
| } // namespace base |