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