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/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/notreached.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/trace_event/memory_allocator_dump.h"
14 #include "base/trace_event/memory_usage_estimator.h"
15 #include "base/trace_event/process_memory_dump.h"
16 #include "base/values.h"
17
18 namespace base::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 Add(kBaseValue, sizeof(Value));
108 AddString(value.GetString());
109 break;
110
111 case Value::Type::BINARY:
112 Add(kBaseValue, sizeof(Value) + value.GetBlob().size());
113 break;
114
115 case Value::Type::DICT:
116 Add(kBaseValue, sizeof(Value));
117 for (const auto pair : value.GetDict()) {
118 AddString(pair.first);
119 AddValue(pair.second);
120 }
121 break;
122
123 case Value::Type::LIST:
124 Add(kBaseValue, sizeof(Value));
125 for (const auto& v : value.GetList())
126 AddValue(v);
127 break;
128 }
129 }
130
AddSelf()131 void TraceEventMemoryOverhead::AddSelf() {
132 Add(kTraceEventMemoryOverhead, sizeof(*this));
133 }
134
GetCount(ObjectType object_type) const135 size_t TraceEventMemoryOverhead::GetCount(ObjectType object_type) const {
136 CHECK(object_type < kLast);
137 return allocated_objects_[static_cast<uint32_t>(object_type)].count;
138 }
139
Update(const TraceEventMemoryOverhead & other)140 void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
141 for (uint32_t i = 0; i < kLast; i++) {
142 const ObjectCountAndSize& other_entry = other.allocated_objects_[i];
143 AddInternal(static_cast<ObjectType>(i), other_entry.count,
144 other_entry.allocated_size_in_bytes,
145 other_entry.resident_size_in_bytes);
146 }
147 }
148
DumpInto(const char * base_name,ProcessMemoryDump * pmd) const149 void TraceEventMemoryOverhead::DumpInto(const char* base_name,
150 ProcessMemoryDump* pmd) const {
151 for (uint32_t i = 0; i < kLast; i++) {
152 const ObjectCountAndSize& count_and_size = allocated_objects_[i];
153 if (count_and_size.allocated_size_in_bytes == 0)
154 continue;
155 std::string dump_name = StringPrintf(
156 "%s/%s", base_name, ObjectTypeToString(static_cast<ObjectType>(i)));
157 MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
158 mad->AddScalar(MemoryAllocatorDump::kNameSize,
159 MemoryAllocatorDump::kUnitsBytes,
160 count_and_size.allocated_size_in_bytes);
161 mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
162 count_and_size.resident_size_in_bytes);
163 mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
164 MemoryAllocatorDump::kUnitsObjects, count_and_size.count);
165 }
166 }
167
168 } // namespace base::trace_event
169