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/traced_value.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