1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/trace_event/memory_allocator_dump.h"
6
7 #include <stdint.h>
8
9 #include "base/format_macros.h"
10 #include "base/trace_event/memory_allocator_dump_guid.h"
11 #include "base/trace_event/memory_dump_provider.h"
12 #include "base/trace_event/process_memory_dump.h"
13 #include "base/trace_event/traced_value.h"
14 #include "base/values.h"
15 #include "build/build_config.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 using testing::ElementsAre;
20 using testing::Eq;
21 using testing::ByRef;
22 using testing::IsEmpty;
23
24 namespace base {
25 namespace trace_event {
26
27 namespace {
28
29 class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
30 public:
OnMemoryDump(const MemoryDumpArgs & args,ProcessMemoryDump * pmd)31 bool OnMemoryDump(const MemoryDumpArgs& args,
32 ProcessMemoryDump* pmd) override {
33 MemoryAllocatorDump* root_heap =
34 pmd->CreateAllocatorDump("foobar_allocator");
35
36 root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
37 MemoryAllocatorDump::kUnitsBytes, 4096);
38 root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
39 MemoryAllocatorDump::kUnitsObjects, 42);
40 root_heap->AddScalar("attr1", "units1", 1234);
41 root_heap->AddString("attr2", "units2", "string_value");
42
43 MemoryAllocatorDump* sub_heap =
44 pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
45 sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
46 MemoryAllocatorDump::kUnitsBytes, 1);
47 sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
48 MemoryAllocatorDump::kUnitsObjects, 3);
49
50 pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
51 // Leave the rest of sub heap deliberately uninitialized, to check that
52 // CreateAllocatorDump returns a properly zero-initialized object.
53
54 return true;
55 }
56 };
57
CheckString(const MemoryAllocatorDump * dump,const std::string & name,const char * expected_units,const std::string & expected_value)58 void CheckString(const MemoryAllocatorDump* dump,
59 const std::string& name,
60 const char* expected_units,
61 const std::string& expected_value) {
62 MemoryAllocatorDump::Entry expected(name, expected_units, expected_value);
63 EXPECT_THAT(dump->entries(), testing::Contains(Eq(ByRef(expected))));
64 }
65
CheckScalar(const MemoryAllocatorDump * dump,const std::string & name,const char * expected_units,uint64_t expected_value)66 void CheckScalar(const MemoryAllocatorDump* dump,
67 const std::string& name,
68 const char* expected_units,
69 uint64_t expected_value) {
70 MemoryAllocatorDump::Entry expected(name, expected_units, expected_value);
71 EXPECT_THAT(dump->entries(), testing::Contains(Eq(ByRef(expected))));
72 }
73
74 } // namespace
75
TEST(MemoryAllocatorDumpTest,GuidGeneration)76 TEST(MemoryAllocatorDumpTest, GuidGeneration) {
77 std::unique_ptr<MemoryAllocatorDump> mad(new MemoryAllocatorDump(
78 "foo", MemoryDumpLevelOfDetail::kFirst, MemoryAllocatorDumpGuid(0x42u)));
79 ASSERT_EQ("42", mad->guid().ToString());
80 }
81
TEST(MemoryAllocatorDumpTest,DumpIntoProcessMemoryDump)82 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
83 FakeMemoryAllocatorDumpProvider fmadp;
84 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::kDetailed};
85 ProcessMemoryDump pmd(dump_args);
86
87 fmadp.OnMemoryDump(dump_args, &pmd);
88
89 ASSERT_EQ(3u, pmd.allocator_dumps().size());
90
91 const MemoryAllocatorDump* root_heap =
92 pmd.GetAllocatorDump("foobar_allocator");
93 ASSERT_NE(nullptr, root_heap);
94 EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
95 CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
96 MemoryAllocatorDump::kUnitsBytes, 4096);
97 CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount,
98 MemoryAllocatorDump::kUnitsObjects, 42);
99 CheckScalar(root_heap, "attr1", "units1", 1234);
100 CheckString(root_heap, "attr2", "units2", "string_value");
101
102 const MemoryAllocatorDump* sub_heap =
103 pmd.GetAllocatorDump("foobar_allocator/sub_heap");
104 ASSERT_NE(nullptr, sub_heap);
105 EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
106 CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
107 MemoryAllocatorDump::kUnitsBytes, 1);
108 CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount,
109 MemoryAllocatorDump::kUnitsObjects, 3);
110 const MemoryAllocatorDump* empty_sub_heap =
111 pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
112 ASSERT_NE(nullptr, empty_sub_heap);
113 EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
114
115 EXPECT_THAT(empty_sub_heap->entries(), IsEmpty());
116
117 // Check that calling serialization routines doesn't cause a crash.
118 std::unique_ptr<TracedValue> traced_value(new TracedValue);
119 pmd.SerializeAllocatorDumpsInto(traced_value.get());
120 }
121
TEST(MemoryAllocatorDumpTest,GetSize)122 TEST(MemoryAllocatorDumpTest, GetSize) {
123 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::kDetailed};
124 ProcessMemoryDump pmd(dump_args);
125 MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size");
126 dump->AddScalar(MemoryAllocatorDump::kNameSize,
127 MemoryAllocatorDump::kUnitsBytes, 1);
128 dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2);
129 EXPECT_EQ(1u, dump->GetSizeInternal());
130 }
131
TEST(MemoryAllocatorDumpTest,ReadValues)132 TEST(MemoryAllocatorDumpTest, ReadValues) {
133 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::kDetailed};
134 ProcessMemoryDump pmd(dump_args);
135 MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size");
136 dump->AddScalar("one", "byte", 1);
137 dump->AddString("one", "object", "one");
138
139 MemoryAllocatorDump::Entry expected_scalar("one", "byte", 1);
140 MemoryAllocatorDump::Entry expected_string("one", "object", "one");
141 EXPECT_THAT(dump->entries(), ElementsAre(Eq(ByRef(expected_scalar)),
142 Eq(ByRef(expected_string))));
143 }
144
TEST(MemoryAllocatorDumpTest,MovingAnEntry)145 TEST(MemoryAllocatorDumpTest, MovingAnEntry) {
146 MemoryAllocatorDump::Entry expected_entry("one", "byte", 1);
147 MemoryAllocatorDump::Entry from_entry("one", "byte", 1);
148 MemoryAllocatorDump::Entry to_entry = std::move(from_entry);
149 EXPECT_EQ(expected_entry, to_entry);
150 }
151
152 // DEATH tests are not supported in Android/iOS/Fuchsia.
153 #if !defined(NDEBUG) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && \
154 !BUILDFLAG(IS_FUCHSIA)
TEST(MemoryAllocatorDumpTest,ForbidDuplicatesDeathTest)155 TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
156 FakeMemoryAllocatorDumpProvider fmadp;
157 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::kDetailed};
158 ProcessMemoryDump pmd(dump_args);
159 pmd.CreateAllocatorDump("foo_allocator");
160 pmd.CreateAllocatorDump("bar_allocator/heap");
161 ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
162 ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
163 ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
164 }
165
TEST(MemoryAllocatorDumpTest,ForbidStringsInBackgroundModeDeathTest)166 TEST(MemoryAllocatorDumpTest, ForbidStringsInBackgroundModeDeathTest) {
167 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::kBackground};
168 ProcessMemoryDump pmd(dump_args);
169 MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("malloc");
170 ASSERT_DEATH(dump->AddString("foo", "bar", "baz"), "");
171 }
172 #endif
173
174 } // namespace trace_event
175 } // namespace base
176