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 16namespace base { 17namespace trace_event { 18 19TraceEventMemoryOverhead::TraceEventMemoryOverhead() { 20} 21 22TraceEventMemoryOverhead::~TraceEventMemoryOverhead() { 23} 24 25void 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 43void 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 48void 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 55void 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 64void TraceEventMemoryOverhead::AddRefCountedString( 65 const RefCountedString& str) { 66 Add("RefCountedString", sizeof(RefCountedString)); 67 AddString(str.data()); 68} 69 70void TraceEventMemoryOverhead::AddValue(const Value& value) { 71 switch (value.GetType()) { 72 case Value::TYPE_NULL: 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 StringValue* string_value = nullptr; 81 value.GetAsString(&string_value); 82 Add("StringValue", sizeof(StringValue)); 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 Value* v : *list_value) 108 AddValue(*v); 109 } break; 110 111 default: 112 NOTREACHED(); 113 } 114} 115 116void 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 125size_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 132void 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 140void 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