xref: /aosp_15_r20/external/cronet/base/trace_event/memory_allocator_dump.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 <string.h>
8 
9 #include "base/format_macros.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/notreached.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/trace_event/memory_dump_manager.h"
14 #include "base/trace_event/memory_dump_provider.h"
15 #include "base/trace_event/process_memory_dump.h"
16 #include "base/trace_event/traced_value.h"
17 #include "base/values.h"
18 #include "third_party/perfetto/protos/perfetto/trace/memory_graph.pbzero.h"
19 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
20 
21 namespace base {
22 namespace trace_event {
23 
24 const char MemoryAllocatorDump::kNameSize[] = "size";
25 const char MemoryAllocatorDump::kNameObjectCount[] = "object_count";
26 const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
27 const char MemoryAllocatorDump::kTypeString[] = "string";
28 const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
29 const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
30 
MemoryAllocatorDump(const std::string & absolute_name,MemoryDumpLevelOfDetail level_of_detail,const MemoryAllocatorDumpGuid & guid)31 MemoryAllocatorDump::MemoryAllocatorDump(
32     const std::string& absolute_name,
33     MemoryDumpLevelOfDetail level_of_detail,
34     const MemoryAllocatorDumpGuid& guid)
35     : absolute_name_(absolute_name),
36       guid_(guid),
37       level_of_detail_(level_of_detail),
38       flags_(Flags::DEFAULT) {
39   // The |absolute_name| cannot be empty.
40   DCHECK(!absolute_name.empty());
41 
42   // The |absolute_name| can contain slash separator, but not leading or
43   // trailing ones.
44   DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
45 }
46 
47 MemoryAllocatorDump::~MemoryAllocatorDump() = default;
48 
AddScalar(const char * name,const char * units,uint64_t value)49 void MemoryAllocatorDump::AddScalar(const char* name,
50                                     const char* units,
51                                     uint64_t value) {
52   entries_.emplace_back(name, units, value);
53 }
54 
AddString(const char * name,const char * units,const std::string & value)55 void MemoryAllocatorDump::AddString(const char* name,
56                                     const char* units,
57                                     const std::string& value) {
58   // String attributes are disabled in background mode.
59   if (level_of_detail_ == MemoryDumpLevelOfDetail::kBackground) {
60     NOTREACHED();
61     return;
62   }
63   entries_.emplace_back(name, units, value);
64 }
65 
AsValueInto(TracedValue * value) const66 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
67   value->BeginDictionaryWithCopiedName(absolute_name_);
68   value->SetString("guid", guid_.ToString());
69   value->BeginDictionary("attrs");
70 
71   for (const Entry& entry : entries_) {
72     value->BeginDictionaryWithCopiedName(entry.name);
73     switch (entry.entry_type) {
74       case Entry::kUint64:
75         value->SetString("type", kTypeScalar);
76         value->SetString("units", entry.units);
77         value->SetString("value", StringPrintf("%" PRIx64, entry.value_uint64));
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 
AsProtoInto(perfetto::protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::MemoryNode * memory_node) const93 void MemoryAllocatorDump::AsProtoInto(
94     perfetto::protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::
95         MemoryNode* memory_node) const {
96   memory_node->set_id(guid_.ToUint64());
97   memory_node->set_absolute_name(absolute_name_);
98   if (flags() & WEAK) {
99     memory_node->set_weak(true);
100   }
101 
102   for (const Entry& entry : entries_) {
103     if (entry.name == "size") {
104       DCHECK_EQ(entry.entry_type, Entry::EntryType::kUint64);
105       DCHECK_EQ(entry.units, kUnitsBytes);
106       memory_node->set_size_bytes(entry.value_uint64);
107       continue;
108     }
109 
110     perfetto::protos::pbzero::MemoryTrackerSnapshot_ProcessSnapshot::
111         MemoryNode::MemoryNodeEntry* proto_memory_node_entry =
112             memory_node->add_entries();
113 
114     proto_memory_node_entry->set_name(entry.name);
115     switch (entry.entry_type) {
116       case Entry::EntryType::kUint64:
117         proto_memory_node_entry->set_value_uint64(entry.value_uint64);
118         break;
119       case Entry::EntryType::kString:
120         proto_memory_node_entry->set_value_string(entry.value_string);
121         break;
122     }
123     if (entry.units == kUnitsBytes) {
124       proto_memory_node_entry->set_units(
125           perfetto::protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::
126               MemoryNode::MemoryNodeEntry::BYTES);
127     } else if (entry.units == kUnitsObjects) {
128       proto_memory_node_entry->set_units(
129           perfetto::protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::
130               MemoryNode::MemoryNodeEntry::COUNT);
131     } else {
132       proto_memory_node_entry->set_units(
133           perfetto::protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::
134               MemoryNode::MemoryNodeEntry::UNSPECIFIED);
135     }
136   }
137 }
138 
GetSizeInternal() const139 uint64_t MemoryAllocatorDump::GetSizeInternal() const {
140   if (cached_size_.has_value())
141     return *cached_size_;
142   for (const auto& entry : entries_) {
143     if (entry.entry_type == Entry::kUint64 && entry.units == kUnitsBytes &&
144         strcmp(entry.name.c_str(), kNameSize) == 0) {
145       cached_size_ = entry.value_uint64;
146       return entry.value_uint64;
147     }
148   }
149   return 0;
150 }
151 
Entry()152 MemoryAllocatorDump::Entry::Entry() : entry_type(kString), value_uint64() {}
153 MemoryAllocatorDump::Entry::Entry(MemoryAllocatorDump::Entry&&) noexcept =
154     default;
155 MemoryAllocatorDump::Entry& MemoryAllocatorDump::Entry::operator=(
156     MemoryAllocatorDump::Entry&&) = default;
Entry(std::string name,std::string units,uint64_t value)157 MemoryAllocatorDump::Entry::Entry(std::string name,
158                                   std::string units,
159                                   uint64_t value)
160     : name(name), units(units), entry_type(kUint64), value_uint64(value) {}
Entry(std::string name,std::string units,std::string value)161 MemoryAllocatorDump::Entry::Entry(std::string name,
162                                   std::string units,
163                                   std::string value)
164     : name(name), units(units), entry_type(kString), value_string(value) {}
165 
operator ==(const Entry & rhs) const166 bool MemoryAllocatorDump::Entry::operator==(const Entry& rhs) const {
167   if (!(name == rhs.name && units == rhs.units && entry_type == rhs.entry_type))
168     return false;
169   switch (entry_type) {
170     case EntryType::kUint64:
171       return value_uint64 == rhs.value_uint64;
172     case EntryType::kString:
173       return value_string == rhs.value_string;
174   }
175   NOTREACHED();
176   return false;
177 }
178 
PrintTo(const MemoryAllocatorDump::Entry & entry,std::ostream * out)179 void PrintTo(const MemoryAllocatorDump::Entry& entry, std::ostream* out) {
180   switch (entry.entry_type) {
181     case MemoryAllocatorDump::Entry::EntryType::kUint64:
182       *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", "
183            << entry.value_uint64 << ")>";
184       return;
185     case MemoryAllocatorDump::Entry::EntryType::kString:
186       *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", \""
187            << entry.value_string << "\")>";
188       return;
189   }
190   NOTREACHED();
191 }
192 
193 }  // namespace trace_event
194 }  // namespace base
195