| // 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/bits.h" | 
 | #include "base/memory/ref_counted_memory.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "base/trace_event/memory_allocator_dump.h" | 
 | #include "base/trace_event/memory_usage_estimator.h" | 
 | #include "base/trace_event/process_memory_dump.h" | 
 | #include "base/values.h" | 
 |  | 
 | namespace base { | 
 | namespace trace_event { | 
 |  | 
 | namespace { | 
 |  | 
 | const char* ObjectTypeToString(TraceEventMemoryOverhead::ObjectType type) { | 
 |   switch (type) { | 
 |     case TraceEventMemoryOverhead::kOther: | 
 |       return "(Other)"; | 
 |     case TraceEventMemoryOverhead::kTraceBuffer: | 
 |       return "TraceBuffer"; | 
 |     case TraceEventMemoryOverhead::kTraceBufferChunk: | 
 |       return "TraceBufferChunk"; | 
 |     case TraceEventMemoryOverhead::kTraceEvent: | 
 |       return "TraceEvent"; | 
 |     case TraceEventMemoryOverhead::kUnusedTraceEvent: | 
 |       return "TraceEvent(Unused)"; | 
 |     case TraceEventMemoryOverhead::kTracedValue: | 
 |       return "TracedValue"; | 
 |     case TraceEventMemoryOverhead::kConvertableToTraceFormat: | 
 |       return "ConvertableToTraceFormat"; | 
 |     case TraceEventMemoryOverhead::kHeapProfilerAllocationRegister: | 
 |       return "AllocationRegister"; | 
 |     case TraceEventMemoryOverhead::kHeapProfilerTypeNameDeduplicator: | 
 |       return "TypeNameDeduplicator"; | 
 |     case TraceEventMemoryOverhead::kHeapProfilerStackFrameDeduplicator: | 
 |       return "StackFrameDeduplicator"; | 
 |     case TraceEventMemoryOverhead::kStdString: | 
 |       return "std::string"; | 
 |     case TraceEventMemoryOverhead::kBaseValue: | 
 |       return "base::Value"; | 
 |     case TraceEventMemoryOverhead::kTraceEventMemoryOverhead: | 
 |       return "TraceEventMemoryOverhead"; | 
 |     case TraceEventMemoryOverhead::kLast: | 
 |       NOTREACHED(); | 
 |   } | 
 |   NOTREACHED(); | 
 |   return "BUG"; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | TraceEventMemoryOverhead::TraceEventMemoryOverhead() : allocated_objects_() {} | 
 |  | 
 | TraceEventMemoryOverhead::~TraceEventMemoryOverhead() = default; | 
 |  | 
 | void TraceEventMemoryOverhead::AddInternal(ObjectType object_type, | 
 |                                            size_t count, | 
 |                                            size_t allocated_size_in_bytes, | 
 |                                            size_t resident_size_in_bytes) { | 
 |   ObjectCountAndSize& count_and_size = | 
 |       allocated_objects_[static_cast<uint32_t>(object_type)]; | 
 |   count_and_size.count += count; | 
 |   count_and_size.allocated_size_in_bytes += allocated_size_in_bytes; | 
 |   count_and_size.resident_size_in_bytes += resident_size_in_bytes; | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::Add(ObjectType object_type, | 
 |                                    size_t allocated_size_in_bytes) { | 
 |   Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes); | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::Add(ObjectType object_type, | 
 |                                    size_t allocated_size_in_bytes, | 
 |                                    size_t resident_size_in_bytes) { | 
 |   AddInternal(object_type, 1, allocated_size_in_bytes, resident_size_in_bytes); | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::AddString(const std::string& str) { | 
 |   Add(kStdString, EstimateMemoryUsage(str)); | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::AddRefCountedString( | 
 |     const RefCountedString& str) { | 
 |   Add(kOther, sizeof(RefCountedString)); | 
 |   AddString(str.data()); | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::AddValue(const Value& value) { | 
 |   switch (value.type()) { | 
 |     case Value::Type::NONE: | 
 |     case Value::Type::BOOLEAN: | 
 |     case Value::Type::INTEGER: | 
 |     case Value::Type::DOUBLE: | 
 |       Add(kBaseValue, sizeof(Value)); | 
 |       break; | 
 |  | 
 |     case Value::Type::STRING: { | 
 |       const Value* string_value = nullptr; | 
 |       value.GetAsString(&string_value); | 
 |       Add(kBaseValue, sizeof(Value)); | 
 |       AddString(string_value->GetString()); | 
 |     } break; | 
 |  | 
 |     case Value::Type::BINARY: { | 
 |       Add(kBaseValue, sizeof(Value) + value.GetBlob().size()); | 
 |     } break; | 
 |  | 
 |     case Value::Type::DICTIONARY: { | 
 |       const DictionaryValue* dictionary_value = nullptr; | 
 |       value.GetAsDictionary(&dictionary_value); | 
 |       Add(kBaseValue, 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(kBaseValue, sizeof(ListValue)); | 
 |       for (const auto& v : *list_value) | 
 |         AddValue(v); | 
 |     } break; | 
 |  | 
 |     default: | 
 |       NOTREACHED(); | 
 |   } | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::AddSelf() { | 
 |   Add(kTraceEventMemoryOverhead, sizeof(*this)); | 
 | } | 
 |  | 
 | size_t TraceEventMemoryOverhead::GetCount(ObjectType object_type) const { | 
 |   CHECK(object_type < kLast); | 
 |   return allocated_objects_[static_cast<uint32_t>(object_type)].count; | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) { | 
 |   for (uint32_t i = 0; i < kLast; i++) { | 
 |     const ObjectCountAndSize& other_entry = other.allocated_objects_[i]; | 
 |     AddInternal(static_cast<ObjectType>(i), other_entry.count, | 
 |                 other_entry.allocated_size_in_bytes, | 
 |                 other_entry.resident_size_in_bytes); | 
 |   } | 
 | } | 
 |  | 
 | void TraceEventMemoryOverhead::DumpInto(const char* base_name, | 
 |                                         ProcessMemoryDump* pmd) const { | 
 |   for (uint32_t i = 0; i < kLast; i++) { | 
 |     const ObjectCountAndSize& count_and_size = allocated_objects_[i]; | 
 |     if (count_and_size.allocated_size_in_bytes == 0) | 
 |       continue; | 
 |     std::string dump_name = StringPrintf( | 
 |         "%s/%s", base_name, ObjectTypeToString(static_cast<ObjectType>(i))); | 
 |     MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name); | 
 |     mad->AddScalar(MemoryAllocatorDump::kNameSize, | 
 |                    MemoryAllocatorDump::kUnitsBytes, | 
 |                    count_and_size.allocated_size_in_bytes); | 
 |     mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes, | 
 |                    count_and_size.resident_size_in_bytes); | 
 |     mad->AddScalar(MemoryAllocatorDump::kNameObjectCount, | 
 |                    MemoryAllocatorDump::kUnitsObjects, count_and_size.count); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace trace_event | 
 | }  // namespace base |