// 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 #include "base/bits.h" #include "base/memory/ref_counted_memory.h" #include "base/notreached.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::kFrameMetrics: return "FrameMetrics"; 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(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: Add(kBaseValue, sizeof(Value)); AddString(value.GetString()); break; case Value::Type::BINARY: Add(kBaseValue, sizeof(Value) + value.GetBlob().size()); break; case Value::Type::DICTIONARY: Add(kBaseValue, sizeof(Value)); for (const auto pair : value.DictItems()) { AddString(pair.first); AddValue(pair.second); } break; case Value::Type::LIST: Add(kBaseValue, sizeof(Value)); for (const auto& v : value.GetListDeprecated()) 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(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(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(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