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 <string.h>
8
9 #include "base/format_macros.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/trace_event/memory_dump_manager.h"
13 #include "base/trace_event/memory_dump_provider.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
18 namespace base {
19 namespace trace_event {
20
21 const char MemoryAllocatorDump::kNameSize[] = "size";
22 const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
23 const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
24 const char MemoryAllocatorDump::kTypeString[] = "string";
25 const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
26 const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
27
MemoryAllocatorDump(const std::string & absolute_name,MemoryDumpLevelOfDetail level_of_detail,const MemoryAllocatorDumpGuid & guid)28 MemoryAllocatorDump::MemoryAllocatorDump(
29 const std::string& absolute_name,
30 MemoryDumpLevelOfDetail level_of_detail,
31 const MemoryAllocatorDumpGuid& guid)
32 : absolute_name_(absolute_name),
33 guid_(guid),
34 level_of_detail_(level_of_detail),
35 flags_(Flags::DEFAULT) {
36 // The |absolute_name| cannot be empty.
37 DCHECK(!absolute_name.empty());
38
39 // The |absolute_name| can contain slash separator, but not leading or
40 // trailing ones.
41 DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
42 }
43
44 MemoryAllocatorDump::~MemoryAllocatorDump() = default;
45
AddScalar(const char * name,const char * units,uint64_t value)46 void MemoryAllocatorDump::AddScalar(const char* name,
47 const char* units,
48 uint64_t value) {
49 entries_.emplace_back(name, units, value);
50 }
51
AddString(const char * name,const char * units,const std::string & value)52 void MemoryAllocatorDump::AddString(const char* name,
53 const char* units,
54 const std::string& value) {
55 // String attributes are disabled in background mode.
56 if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) {
57 NOTREACHED();
58 return;
59 }
60 entries_.emplace_back(name, units, value);
61 }
62
AsValueInto(TracedValue * value) const63 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
64 std::string string_conversion_buffer;
65 value->BeginDictionaryWithCopiedName(absolute_name_);
66 value->SetString("guid", guid_.ToString());
67 value->BeginDictionary("attrs");
68
69 for (const Entry& entry : entries_) {
70 value->BeginDictionaryWithCopiedName(entry.name);
71 switch (entry.entry_type) {
72 case Entry::kUint64:
73 SStringPrintf(&string_conversion_buffer, "%" PRIx64,
74 entry.value_uint64);
75 value->SetString("type", kTypeScalar);
76 value->SetString("units", entry.units);
77 value->SetString("value", string_conversion_buffer);
78 break;
79 case Entry::kString:
80 value->SetString("type", kTypeString);
81 value->SetString("units", entry.units);
82 value->SetString("value", entry.value_string);
83 break;
84 }
85 value->EndDictionary();
86 }
87 value->EndDictionary(); // "attrs": { ... }
88 if (flags_)
89 value->SetInteger("flags", flags_);
90 value->EndDictionary(); // "allocator_name/heap_subheap": { ... }
91 }
92
GetSizeInternal() const93 uint64_t MemoryAllocatorDump::GetSizeInternal() const {
94 if (cached_size_.has_value())
95 return *cached_size_;
96 for (const auto& entry : entries_) {
97 if (entry.entry_type == Entry::kUint64 && entry.units == kUnitsBytes &&
98 strcmp(entry.name.c_str(), kNameSize) == 0) {
99 cached_size_ = entry.value_uint64;
100 return entry.value_uint64;
101 }
102 }
103 return 0;
104 };
105
Entry()106 MemoryAllocatorDump::Entry::Entry() : entry_type(kString), value_uint64() {}
107 MemoryAllocatorDump::Entry::Entry(MemoryAllocatorDump::Entry&&) noexcept =
108 default;
109 MemoryAllocatorDump::Entry& MemoryAllocatorDump::Entry::operator=(
110 MemoryAllocatorDump::Entry&&) = default;
Entry(std::string name,std::string units,uint64_t value)111 MemoryAllocatorDump::Entry::Entry(std::string name,
112 std::string units,
113 uint64_t value)
114 : name(name), units(units), entry_type(kUint64), value_uint64(value) {}
Entry(std::string name,std::string units,std::string value)115 MemoryAllocatorDump::Entry::Entry(std::string name,
116 std::string units,
117 std::string value)
118 : name(name), units(units), entry_type(kString), value_string(value) {}
119
operator ==(const Entry & rhs) const120 bool MemoryAllocatorDump::Entry::operator==(const Entry& rhs) const {
121 if (!(name == rhs.name && units == rhs.units && entry_type == rhs.entry_type))
122 return false;
123 switch (entry_type) {
124 case EntryType::kUint64:
125 return value_uint64 == rhs.value_uint64;
126 case EntryType::kString:
127 return value_string == rhs.value_string;
128 }
129 NOTREACHED();
130 return false;
131 }
132
PrintTo(const MemoryAllocatorDump::Entry & entry,std::ostream * out)133 void PrintTo(const MemoryAllocatorDump::Entry& entry, std::ostream* out) {
134 switch (entry.entry_type) {
135 case MemoryAllocatorDump::Entry::EntryType::kUint64:
136 *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", "
137 << entry.value_uint64 << ")>";
138 return;
139 case MemoryAllocatorDump::Entry::EntryType::kString:
140 *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", \""
141 << entry.value_string << "\")>";
142 return;
143 }
144 NOTREACHED();
145 }
146
147 } // namespace trace_event
148 } // namespace base
149