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