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/process_memory_dump.h"
14 #include "base/values.h"
15 
16 namespace base {
17 namespace trace_event {
18 
TraceEventMemoryOverhead()19 TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
20 }
21 
~TraceEventMemoryOverhead()22 TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
23 }
24 
AddOrCreateInternal(const char * object_type,size_t count,size_t allocated_size_in_bytes,size_t resident_size_in_bytes)25 void TraceEventMemoryOverhead::AddOrCreateInternal(
26     const char* object_type,
27     size_t count,
28     size_t allocated_size_in_bytes,
29     size_t resident_size_in_bytes) {
30   auto it = allocated_objects_.find(object_type);
31   if (it == allocated_objects_.end()) {
32     allocated_objects_.insert(std::make_pair(
33         object_type,
34         ObjectCountAndSize(
35             {count, allocated_size_in_bytes, resident_size_in_bytes})));
36     return;
37   }
38   it->second.count += count;
39   it->second.allocated_size_in_bytes += allocated_size_in_bytes;
40   it->second.resident_size_in_bytes += resident_size_in_bytes;
41 }
42 
Add(const char * object_type,size_t allocated_size_in_bytes)43 void TraceEventMemoryOverhead::Add(const char* object_type,
44                                    size_t allocated_size_in_bytes) {
45   Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
46 }
47 
Add(const char * object_type,size_t allocated_size_in_bytes,size_t resident_size_in_bytes)48 void TraceEventMemoryOverhead::Add(const char* object_type,
49                                    size_t allocated_size_in_bytes,
50                                    size_t resident_size_in_bytes) {
51   AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
52                       resident_size_in_bytes);
53 }
54 
AddString(const std::string & str)55 void TraceEventMemoryOverhead::AddString(const std::string& str) {
56   // The number below are empirical and mainly based on profiling of real-world
57   // std::string implementations:
58   //  - even short string end up malloc()-inc at least 32 bytes.
59   //  - longer strings seem to malloc() multiples of 16 bytes.
60   const size_t capacity = bits::Align(str.capacity(), 16);
61   Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 32u));
62 }
63 
AddRefCountedString(const RefCountedString & str)64 void TraceEventMemoryOverhead::AddRefCountedString(
65     const RefCountedString& str) {
66   Add("RefCountedString", sizeof(RefCountedString));
67   AddString(str.data());
68 }
69 
AddValue(const Value & value)70 void TraceEventMemoryOverhead::AddValue(const Value& value) {
71   switch (value.GetType()) {
72     case Value::Type::NONE:
73     case Value::Type::BOOLEAN:
74     case Value::Type::INTEGER:
75     case Value::Type::DOUBLE:
76       Add("FundamentalValue", sizeof(Value));
77       break;
78 
79     case Value::Type::STRING: {
80       const Value* string_value = nullptr;
81       value.GetAsString(&string_value);
82       Add("StringValue", sizeof(Value));
83       AddString(string_value->GetString());
84     } break;
85 
86     case Value::Type::BINARY: {
87       const BinaryValue* binary_value = nullptr;
88       value.GetAsBinary(&binary_value);
89       Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
90     } break;
91 
92     case Value::Type::DICTIONARY: {
93       const DictionaryValue* dictionary_value = nullptr;
94       value.GetAsDictionary(&dictionary_value);
95       Add("DictionaryValue", sizeof(DictionaryValue));
96       for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
97            it.Advance()) {
98         AddString(it.key());
99         AddValue(it.value());
100       }
101     } break;
102 
103     case Value::Type::LIST: {
104       const ListValue* list_value = nullptr;
105       value.GetAsList(&list_value);
106       Add("ListValue", sizeof(ListValue));
107       for (const auto& v : *list_value)
108         AddValue(*v);
109     } break;
110 
111     default:
112       NOTREACHED();
113   }
114 }
115 
AddSelf()116 void TraceEventMemoryOverhead::AddSelf() {
117   size_t estimated_size = sizeof(*this);
118   // If the SmallMap did overflow its static capacity, its elements will be
119   // allocated on the heap and have to be accounted separately.
120   if (allocated_objects_.UsingFullMap())
121     estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
122   Add("TraceEventMemoryOverhead", estimated_size);
123 }
124 
GetCount(const char * object_type) const125 size_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
126   const auto& it = allocated_objects_.find(object_type);
127   if (it == allocated_objects_.end())
128     return 0u;
129   return it->second.count;
130 }
131 
Update(const TraceEventMemoryOverhead & other)132 void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
133   for (const auto& it : other.allocated_objects_) {
134     AddOrCreateInternal(it.first, it.second.count,
135                         it.second.allocated_size_in_bytes,
136                         it.second.resident_size_in_bytes);
137   }
138 }
139 
DumpInto(const char * base_name,ProcessMemoryDump * pmd) const140 void TraceEventMemoryOverhead::DumpInto(const char* base_name,
141                                         ProcessMemoryDump* pmd) const {
142   for (const auto& it : allocated_objects_) {
143     std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
144     MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
145     mad->AddScalar(MemoryAllocatorDump::kNameSize,
146                    MemoryAllocatorDump::kUnitsBytes,
147                    it.second.allocated_size_in_bytes);
148     mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
149                    it.second.resident_size_in_bytes);
150     mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
151                    MemoryAllocatorDump::kUnitsObjects, it.second.count);
152   }
153 }
154 
155 }  // namespace trace_event
156 }  // namespace base
157