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/trace_event_memory_overhead.h"
6 
7 #include <algorithm>
8 
9 #include "base/bits.h"
10 #include "base/memory/ref_counted_memory.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/trace_event/memory_allocator_dump.h"
13 #include "base/trace_event/memory_usage_estimator.h"
14 #include "base/trace_event/process_memory_dump.h"
15 #include "base/values.h"
16 
17 namespace base {
18 namespace trace_event {
19 
20 namespace {
21 
ObjectTypeToString(TraceEventMemoryOverhead::ObjectType type)22 const char* ObjectTypeToString(TraceEventMemoryOverhead::ObjectType type) {
23   switch (type) {
24     case TraceEventMemoryOverhead::kOther:
25       return "(Other)";
26     case TraceEventMemoryOverhead::kTraceBuffer:
27       return "TraceBuffer";
28     case TraceEventMemoryOverhead::kTraceBufferChunk:
29       return "TraceBufferChunk";
30     case TraceEventMemoryOverhead::kTraceEvent:
31       return "TraceEvent";
32     case TraceEventMemoryOverhead::kUnusedTraceEvent:
33       return "TraceEvent(Unused)";
34     case TraceEventMemoryOverhead::kTracedValue:
35       return "TracedValue";
36     case TraceEventMemoryOverhead::kConvertableToTraceFormat:
37       return "ConvertableToTraceFormat";
38     case TraceEventMemoryOverhead::kHeapProfilerAllocationRegister:
39       return "AllocationRegister";
40     case TraceEventMemoryOverhead::kHeapProfilerTypeNameDeduplicator:
41       return "TypeNameDeduplicator";
42     case TraceEventMemoryOverhead::kHeapProfilerStackFrameDeduplicator:
43       return "StackFrameDeduplicator";
44     case TraceEventMemoryOverhead::kStdString:
45       return "std::string";
46     case TraceEventMemoryOverhead::kBaseValue:
47       return "base::Value";
48     case TraceEventMemoryOverhead::kTraceEventMemoryOverhead:
49       return "TraceEventMemoryOverhead";
50     case TraceEventMemoryOverhead::kFrameMetrics:
51       return "FrameMetrics";
52     case TraceEventMemoryOverhead::kLast:
53       NOTREACHED();
54   }
55   NOTREACHED();
56   return "BUG";
57 }
58 
59 }  // namespace
60 
TraceEventMemoryOverhead()61 TraceEventMemoryOverhead::TraceEventMemoryOverhead() : allocated_objects_() {}
62 
63 TraceEventMemoryOverhead::~TraceEventMemoryOverhead() = default;
64 
AddInternal(ObjectType object_type,size_t count,size_t allocated_size_in_bytes,size_t resident_size_in_bytes)65 void TraceEventMemoryOverhead::AddInternal(ObjectType object_type,
66                                            size_t count,
67                                            size_t allocated_size_in_bytes,
68                                            size_t resident_size_in_bytes) {
69   ObjectCountAndSize& count_and_size =
70       allocated_objects_[static_cast<uint32_t>(object_type)];
71   count_and_size.count += count;
72   count_and_size.allocated_size_in_bytes += allocated_size_in_bytes;
73   count_and_size.resident_size_in_bytes += resident_size_in_bytes;
74 }
75 
Add(ObjectType object_type,size_t allocated_size_in_bytes)76 void TraceEventMemoryOverhead::Add(ObjectType object_type,
77                                    size_t allocated_size_in_bytes) {
78   Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
79 }
80 
Add(ObjectType object_type,size_t allocated_size_in_bytes,size_t resident_size_in_bytes)81 void TraceEventMemoryOverhead::Add(ObjectType object_type,
82                                    size_t allocated_size_in_bytes,
83                                    size_t resident_size_in_bytes) {
84   AddInternal(object_type, 1, allocated_size_in_bytes, resident_size_in_bytes);
85 }
86 
AddString(const std::string & str)87 void TraceEventMemoryOverhead::AddString(const std::string& str) {
88   Add(kStdString, EstimateMemoryUsage(str));
89 }
90 
AddRefCountedString(const RefCountedString & str)91 void TraceEventMemoryOverhead::AddRefCountedString(
92     const RefCountedString& str) {
93   Add(kOther, sizeof(RefCountedString));
94   AddString(str.data());
95 }
96 
AddValue(const Value & value)97 void TraceEventMemoryOverhead::AddValue(const Value& value) {
98   switch (value.type()) {
99     case Value::Type::NONE:
100     case Value::Type::BOOLEAN:
101     case Value::Type::INTEGER:
102     case Value::Type::DOUBLE:
103       Add(kBaseValue, sizeof(Value));
104       break;
105 
106     case Value::Type::STRING: {
107       const Value* string_value = nullptr;
108       value.GetAsString(&string_value);
109       Add(kBaseValue, sizeof(Value));
110       AddString(string_value->GetString());
111     } break;
112 
113     case Value::Type::BINARY: {
114       Add(kBaseValue, sizeof(Value) + value.GetBlob().size());
115     } break;
116 
117     case Value::Type::DICTIONARY: {
118       const DictionaryValue* dictionary_value = nullptr;
119       value.GetAsDictionary(&dictionary_value);
120       Add(kBaseValue, sizeof(DictionaryValue));
121       for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
122            it.Advance()) {
123         AddString(it.key());
124         AddValue(it.value());
125       }
126     } break;
127 
128     case Value::Type::LIST: {
129       const ListValue* list_value = nullptr;
130       value.GetAsList(&list_value);
131       Add(kBaseValue, sizeof(ListValue));
132       for (const auto& v : *list_value)
133         AddValue(v);
134     } break;
135 
136     default:
137       NOTREACHED();
138   }
139 }
140 
AddSelf()141 void TraceEventMemoryOverhead::AddSelf() {
142   Add(kTraceEventMemoryOverhead, sizeof(*this));
143 }
144 
GetCount(ObjectType object_type) const145 size_t TraceEventMemoryOverhead::GetCount(ObjectType object_type) const {
146   CHECK(object_type < kLast);
147   return allocated_objects_[static_cast<uint32_t>(object_type)].count;
148 }
149 
Update(const TraceEventMemoryOverhead & other)150 void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
151   for (uint32_t i = 0; i < kLast; i++) {
152     const ObjectCountAndSize& other_entry = other.allocated_objects_[i];
153     AddInternal(static_cast<ObjectType>(i), other_entry.count,
154                 other_entry.allocated_size_in_bytes,
155                 other_entry.resident_size_in_bytes);
156   }
157 }
158 
DumpInto(const char * base_name,ProcessMemoryDump * pmd) const159 void TraceEventMemoryOverhead::DumpInto(const char* base_name,
160                                         ProcessMemoryDump* pmd) const {
161   for (uint32_t i = 0; i < kLast; i++) {
162     const ObjectCountAndSize& count_and_size = allocated_objects_[i];
163     if (count_and_size.allocated_size_in_bytes == 0)
164       continue;
165     std::string dump_name = StringPrintf(
166         "%s/%s", base_name, ObjectTypeToString(static_cast<ObjectType>(i)));
167     MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
168     mad->AddScalar(MemoryAllocatorDump::kNameSize,
169                    MemoryAllocatorDump::kUnitsBytes,
170                    count_and_size.allocated_size_in_bytes);
171     mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
172                    count_and_size.resident_size_in_bytes);
173     mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
174                    MemoryAllocatorDump::kUnitsObjects, count_and_size.count);
175   }
176 }
177 
178 }  // namespace trace_event
179 }  // namespace base
180