Index: base/trace_event/trace_event_memory_overhead.cc |
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9aea5c1907176b1fed6d0cf99c72ad0cd81b9940 |
--- /dev/null |
+++ b/base/trace_event/trace_event_memory_overhead.cc |
@@ -0,0 +1,151 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/trace_event/trace_event_memory_overhead.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/memory/ref_counted_memory.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/trace_event/memory_allocator_dump.h" |
+#include "base/trace_event/process_memory_dump.h" |
+#include "base/values.h" |
+ |
+namespace { |
+size_t RoundUp(size_t size, size_t alignment) { |
+ return (size + alignment - 1) & ~(alignment - 1); |
+} |
+} // namespace |
+ |
+namespace base { |
+namespace trace_event { |
+ |
+TraceEventMemoryOverhead::TraceEventMemoryOverhead() {} |
+ |
+TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {} |
+ |
+void TraceEventMemoryOverhead::AddOrCreateInternal( |
+ const char* object_type, |
+ size_t count, |
+ size_t allocated_size_in_bytes, |
+ size_t resident_size_in_bytes) { |
+ auto it = allocated_objects_.find(object_type); |
+ if (it == allocated_objects_.end()) { |
+ allocated_objects_.insert(std::make_pair( |
+ object_type, ObjectCountAndSize({count, allocated_size_in_bytes, |
+ resident_size_in_bytes}))); |
+ return; |
+ } |
+ it->second.count += count; |
+ it->second.allocated_size_in_bytes += allocated_size_in_bytes; |
+ it->second.resident_size_in_bytes += resident_size_in_bytes; |
+} |
+ |
+void TraceEventMemoryOverhead::Add(const char* object_type, |
+ size_t allocated_size_in_bytes) { |
+ Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes); |
+} |
+ |
+void TraceEventMemoryOverhead::Add(const char* object_type, |
+ size_t allocated_size_in_bytes, |
+ size_t resident_size_in_bytes) { |
+ AddOrCreateInternal(object_type, 1, allocated_size_in_bytes, |
+ resident_size_in_bytes); |
+} |
+ |
+void TraceEventMemoryOverhead::AddString(const std::string& str) { |
+ // The number below are empirical and mainly based on profiling of real-world |
+ // std::string implementations: |
+ // - even short string end up malloc()-inc at least 32 bytes. |
+ // - longer stings seem to malloc() multiples of 16 bytes. |
+ Add("std::string", |
+ sizeof(std::string) + std::max<size_t>(RoundUp(str.capacity(), 16), 32u)); |
+} |
+ |
+void TraceEventMemoryOverhead::AddRefCountedString( |
+ const RefCountedString& str) { |
+ Add("RefCountedString", sizeof(RefCountedString)); |
+ AddString(str.data()); |
+} |
+ |
+void TraceEventMemoryOverhead::AddValue(const Value& value) { |
+ switch (value.GetType()) { |
+ case Value::TYPE_NULL: |
+ case Value::TYPE_BOOLEAN: |
+ case Value::TYPE_INTEGER: |
+ case Value::TYPE_DOUBLE: |
+ Add("FundamentalValue", sizeof(Value)); |
+ break; |
+ |
+ case Value::TYPE_STRING: { |
+ const StringValue* string_value = nullptr; |
+ value.GetAsString(&string_value); |
+ Add("StringValue", sizeof(StringValue)); |
+ AddString(string_value->GetString()); |
+ } break; |
+ |
+ case Value::TYPE_BINARY: { |
+ const BinaryValue* binary_value = nullptr; |
+ value.GetAsBinary(&binary_value); |
+ Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize()); |
+ } break; |
+ |
+ case Value::TYPE_DICTIONARY: { |
+ const DictionaryValue* dictionary_value = nullptr; |
+ value.GetAsDictionary(&dictionary_value); |
+ Add("DictionaryValue", sizeof(DictionaryValue)); |
+ for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd(); |
+ it.Advance()) { |
+ AddString(it.key()); |
+ AddValue(it.value()); |
+ } |
+ } break; |
+ |
+ case Value::TYPE_LIST: { |
+ const ListValue* list_value = nullptr; |
+ value.GetAsList(&list_value); |
+ Add("ListValue", sizeof(ListValue)); |
+ for (const Value* v : *list_value) |
+ AddValue(*v); |
+ } break; |
+ |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void TraceEventMemoryOverhead::AddSelf() { |
+ size_t estimated_size = sizeof(*this); |
+ // If the SmallMap did overflow its static capacity, its elements will be |
+ // allocated on the heap and have to be accounted separately. |
+ if (allocated_objects_.UsingFullMap()) |
+ estimated_size += sizeof(map_type::value_type) * allocated_objects_.size(); |
+ Add("TraceEventMemoryOverhead", estimated_size); |
+} |
+ |
+void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) { |
+ for (const auto& it : other.allocated_objects_) { |
+ AddOrCreateInternal(it.first, it.second.count, |
+ it.second.allocated_size_in_bytes, |
+ it.second.resident_size_in_bytes); |
+ } |
+} |
+ |
+void TraceEventMemoryOverhead::DumpInto(const char* base_name, |
+ ProcessMemoryDump* pmd) const { |
+ for (const auto& it : allocated_objects_) { |
+ std::string dump_name = StringPrintf("%s/%s", base_name, it.first); |
+ MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name); |
+ mad->AddScalar(MemoryAllocatorDump::kNameSize, |
+ MemoryAllocatorDump::kUnitsBytes, |
+ it.second.allocated_size_in_bytes); |
+ mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes, |
+ it.second.resident_size_in_bytes); |
+ mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount, |
+ MemoryAllocatorDump::kUnitsObjects, it.second.count); |
+ } |
+} |
+ |
+} // namespace trace_event |
+} // namespace base |