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/memory_dump_session_state.h" 14 #include "base/trace_event/process_memory_dump.h" 15 #include "base/trace_event/trace_event_argument.h" 16 #include "base/values.h" 17 #include "build/build_config.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace base { 21 namespace trace_event { 22 23 namespace { 24 25 class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider { 26 public: 27 bool OnMemoryDump(const MemoryDumpArgs& args, 28 ProcessMemoryDump* pmd) override { 29 MemoryAllocatorDump* root_heap = 30 pmd->CreateAllocatorDump("foobar_allocator"); 31 32 root_heap->AddScalar(MemoryAllocatorDump::kNameSize, 33 MemoryAllocatorDump::kUnitsBytes, 4096); 34 root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, 35 MemoryAllocatorDump::kUnitsObjects, 42); 36 root_heap->AddScalar("attr1", "units1", 1234); 37 root_heap->AddString("attr2", "units2", "string_value"); 38 root_heap->AddScalarF("attr3", "units3", 42.5f); 39 40 MemoryAllocatorDump* sub_heap = 41 pmd->CreateAllocatorDump("foobar_allocator/sub_heap"); 42 sub_heap->AddScalar(MemoryAllocatorDump::kNameSize, 43 MemoryAllocatorDump::kUnitsBytes, 1); 44 sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount, 45 MemoryAllocatorDump::kUnitsObjects, 3); 46 47 pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty"); 48 // Leave the rest of sub heap deliberately uninitialized, to check that 49 // CreateAllocatorDump returns a properly zero-initialized object. 50 51 return true; 52 } 53 }; 54 55 std::unique_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump, 56 const std::string& name, 57 const char* expected_type, 58 const char* expected_units) { 59 std::unique_ptr<Value> raw_attrs = 60 dump->attributes_for_testing()->ToBaseValue(); 61 DictionaryValue* args = nullptr; 62 DictionaryValue* arg = nullptr; 63 std::string arg_value; 64 const Value* out_value = nullptr; 65 EXPECT_TRUE(raw_attrs->GetAsDictionary(&args)); 66 EXPECT_TRUE(args->GetDictionary(name, &arg)); 67 EXPECT_TRUE(arg->GetString("type", &arg_value)); 68 EXPECT_EQ(expected_type, arg_value); 69 EXPECT_TRUE(arg->GetString("units", &arg_value)); 70 EXPECT_EQ(expected_units, arg_value); 71 EXPECT_TRUE(arg->Get("value", &out_value)); 72 return out_value ? out_value->CreateDeepCopy() : std::unique_ptr<Value>(); 73 } 74 75 void CheckString(const MemoryAllocatorDump* dump, 76 const std::string& name, 77 const char* expected_type, 78 const char* expected_units, 79 const std::string& expected_value) { 80 std::string attr_str_value; 81 auto attr_value = CheckAttribute(dump, name, expected_type, expected_units); 82 EXPECT_TRUE(attr_value->GetAsString(&attr_str_value)); 83 EXPECT_EQ(expected_value, attr_str_value); 84 } 85 86 void CheckScalar(const MemoryAllocatorDump* dump, 87 const std::string& name, 88 const char* expected_units, 89 uint64_t expected_value) { 90 CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units, 91 StringPrintf("%" PRIx64, expected_value)); 92 } 93 94 void CheckScalarF(const MemoryAllocatorDump* dump, 95 const std::string& name, 96 const char* expected_units, 97 double expected_value) { 98 auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar, 99 expected_units); 100 double attr_double_value; 101 EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value)); 102 EXPECT_EQ(expected_value, attr_double_value); 103 } 104 105 } // namespace 106 107 TEST(MemoryAllocatorDumpTest, GuidGeneration) { 108 std::unique_ptr<MemoryAllocatorDump> mad( 109 new MemoryAllocatorDump("foo", nullptr, MemoryAllocatorDumpGuid(0x42u))); 110 ASSERT_EQ("42", mad->guid().ToString()); 111 112 // If the dumper does not provide a Guid, the MAD will make one up on the 113 // flight. Furthermore that Guid will stay stable across across multiple 114 // snapshots if the |absolute_name| of the dump doesn't change 115 mad.reset(new MemoryAllocatorDump("bar", nullptr)); 116 const MemoryAllocatorDumpGuid guid_bar = mad->guid(); 117 ASSERT_FALSE(guid_bar.empty()); 118 ASSERT_FALSE(guid_bar.ToString().empty()); 119 ASSERT_EQ(guid_bar, mad->guid()); 120 121 mad.reset(new MemoryAllocatorDump("bar", nullptr)); 122 const MemoryAllocatorDumpGuid guid_bar_2 = mad->guid(); 123 ASSERT_EQ(guid_bar, guid_bar_2); 124 125 mad.reset(new MemoryAllocatorDump("baz", nullptr)); 126 const MemoryAllocatorDumpGuid guid_baz = mad->guid(); 127 ASSERT_NE(guid_bar, guid_baz); 128 } 129 130 TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) { 131 FakeMemoryAllocatorDumpProvider fmadp; 132 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; 133 ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args); 134 135 fmadp.OnMemoryDump(dump_args, &pmd); 136 137 ASSERT_EQ(3u, pmd.allocator_dumps().size()); 138 139 const MemoryAllocatorDump* root_heap = 140 pmd.GetAllocatorDump("foobar_allocator"); 141 ASSERT_NE(nullptr, root_heap); 142 EXPECT_EQ("foobar_allocator", root_heap->absolute_name()); 143 CheckScalar(root_heap, MemoryAllocatorDump::kNameSize, 144 MemoryAllocatorDump::kUnitsBytes, 4096); 145 CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectCount, 146 MemoryAllocatorDump::kUnitsObjects, 42); 147 CheckScalar(root_heap, "attr1", "units1", 1234); 148 CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2", 149 "string_value"); 150 CheckScalarF(root_heap, "attr3", "units3", 42.5f); 151 152 const MemoryAllocatorDump* sub_heap = 153 pmd.GetAllocatorDump("foobar_allocator/sub_heap"); 154 ASSERT_NE(nullptr, sub_heap); 155 EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name()); 156 CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize, 157 MemoryAllocatorDump::kUnitsBytes, 1); 158 CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectCount, 159 MemoryAllocatorDump::kUnitsObjects, 3); 160 const MemoryAllocatorDump* empty_sub_heap = 161 pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty"); 162 ASSERT_NE(nullptr, empty_sub_heap); 163 EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name()); 164 auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue(); 165 DictionaryValue* attrs = nullptr; 166 ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs)); 167 ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize)); 168 ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectCount)); 169 170 // Check that the AsValueInfo doesn't hit any DCHECK. 171 std::unique_ptr<TracedValue> traced_value(new TracedValue); 172 pmd.AsValueInto(traced_value.get()); 173 } 174 175 TEST(MemoryAllocatorDumpTest, GetSize) { 176 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; 177 ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args); 178 MemoryAllocatorDump* dump = pmd.CreateAllocatorDump("allocator_for_size"); 179 dump->AddScalar(MemoryAllocatorDump::kNameSize, 180 MemoryAllocatorDump::kUnitsBytes, 1); 181 dump->AddScalar("foo", MemoryAllocatorDump::kUnitsBytes, 2); 182 EXPECT_EQ(1u, dump->GetSize()); 183 } 184 185 // DEATH tests are not supported in Android / iOS. 186 #if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS) 187 TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) { 188 FakeMemoryAllocatorDumpProvider fmadp; 189 MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED}; 190 ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args); 191 pmd.CreateAllocatorDump("foo_allocator"); 192 pmd.CreateAllocatorDump("bar_allocator/heap"); 193 ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), ""); 194 ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), ""); 195 ASSERT_DEATH(pmd.CreateAllocatorDump(""), ""); 196 } 197 #endif 198 199 } // namespace trace_event 200 } // namespace base 201