|  | // 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/memory_allocator_dump.h" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | #include "base/format_macros.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "base/trace_event/memory_dump_manager.h" | 
|  | #include "base/trace_event/memory_dump_provider.h" | 
|  | #include "base/trace_event/process_memory_dump.h" | 
|  | #include "base/trace_event/trace_event_argument.h" | 
|  | #include "base/values.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace trace_event { | 
|  |  | 
|  | const char MemoryAllocatorDump::kNameSize[] = "size"; | 
|  | const char MemoryAllocatorDump::kNameObjectCount[] = "object_count"; | 
|  | const char MemoryAllocatorDump::kTypeScalar[] = "scalar"; | 
|  | const char MemoryAllocatorDump::kTypeString[] = "string"; | 
|  | const char MemoryAllocatorDump::kUnitsBytes[] = "bytes"; | 
|  | const char MemoryAllocatorDump::kUnitsObjects[] = "objects"; | 
|  |  | 
|  | MemoryAllocatorDump::MemoryAllocatorDump( | 
|  | const std::string& absolute_name, | 
|  | MemoryDumpLevelOfDetail level_of_detail, | 
|  | const MemoryAllocatorDumpGuid& guid) | 
|  | : absolute_name_(absolute_name), | 
|  | guid_(guid), | 
|  | level_of_detail_(level_of_detail), | 
|  | flags_(Flags::DEFAULT) { | 
|  | // The |absolute_name| cannot be empty. | 
|  | DCHECK(!absolute_name.empty()); | 
|  |  | 
|  | // The |absolute_name| can contain slash separator, but not leading or | 
|  | // trailing ones. | 
|  | DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/'); | 
|  | } | 
|  |  | 
|  | MemoryAllocatorDump::~MemoryAllocatorDump() = default; | 
|  |  | 
|  | void MemoryAllocatorDump::AddScalar(const char* name, | 
|  | const char* units, | 
|  | uint64_t value) { | 
|  | entries_.emplace_back(name, units, value); | 
|  | } | 
|  |  | 
|  | void MemoryAllocatorDump::AddString(const char* name, | 
|  | const char* units, | 
|  | const std::string& value) { | 
|  | // String attributes are disabled in background mode. | 
|  | if (level_of_detail_ == MemoryDumpLevelOfDetail::BACKGROUND) { | 
|  | NOTREACHED(); | 
|  | return; | 
|  | } | 
|  | entries_.emplace_back(name, units, value); | 
|  | } | 
|  |  | 
|  | void MemoryAllocatorDump::AsValueInto(TracedValue* value) const { | 
|  | std::string string_conversion_buffer; | 
|  | value->BeginDictionaryWithCopiedName(absolute_name_); | 
|  | value->SetString("guid", guid_.ToString()); | 
|  | value->BeginDictionary("attrs"); | 
|  |  | 
|  | for (const Entry& entry : entries_) { | 
|  | value->BeginDictionaryWithCopiedName(entry.name); | 
|  | switch (entry.entry_type) { | 
|  | case Entry::kUint64: | 
|  | SStringPrintf(&string_conversion_buffer, "%" PRIx64, | 
|  | entry.value_uint64); | 
|  | value->SetString("type", kTypeScalar); | 
|  | value->SetString("units", entry.units); | 
|  | value->SetString("value", string_conversion_buffer); | 
|  | break; | 
|  | case Entry::kString: | 
|  | value->SetString("type", kTypeString); | 
|  | value->SetString("units", entry.units); | 
|  | value->SetString("value", entry.value_string); | 
|  | break; | 
|  | } | 
|  | value->EndDictionary(); | 
|  | } | 
|  | value->EndDictionary();  // "attrs": { ... } | 
|  | if (flags_) | 
|  | value->SetInteger("flags", flags_); | 
|  | value->EndDictionary();  // "allocator_name/heap_subheap": { ... } | 
|  | } | 
|  |  | 
|  | uint64_t MemoryAllocatorDump::GetSizeInternal() const { | 
|  | if (cached_size_.has_value()) | 
|  | return *cached_size_; | 
|  | for (const auto& entry : entries_) { | 
|  | if (entry.entry_type == Entry::kUint64 && entry.units == kUnitsBytes && | 
|  | strcmp(entry.name.c_str(), kNameSize) == 0) { | 
|  | cached_size_ = entry.value_uint64; | 
|  | return entry.value_uint64; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | }; | 
|  |  | 
|  | MemoryAllocatorDump::Entry::Entry() : entry_type(kString), value_uint64() {} | 
|  | MemoryAllocatorDump::Entry::Entry(MemoryAllocatorDump::Entry&&) noexcept = | 
|  | default; | 
|  | MemoryAllocatorDump::Entry& MemoryAllocatorDump::Entry::operator=( | 
|  | MemoryAllocatorDump::Entry&&) = default; | 
|  | MemoryAllocatorDump::Entry::Entry(std::string name, | 
|  | std::string units, | 
|  | uint64_t value) | 
|  | : name(name), units(units), entry_type(kUint64), value_uint64(value) {} | 
|  | MemoryAllocatorDump::Entry::Entry(std::string name, | 
|  | std::string units, | 
|  | std::string value) | 
|  | : name(name), units(units), entry_type(kString), value_string(value) {} | 
|  |  | 
|  | bool MemoryAllocatorDump::Entry::operator==(const Entry& rhs) const { | 
|  | if (!(name == rhs.name && units == rhs.units && entry_type == rhs.entry_type)) | 
|  | return false; | 
|  | switch (entry_type) { | 
|  | case EntryType::kUint64: | 
|  | return value_uint64 == rhs.value_uint64; | 
|  | case EntryType::kString: | 
|  | return value_string == rhs.value_string; | 
|  | } | 
|  | NOTREACHED(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void PrintTo(const MemoryAllocatorDump::Entry& entry, std::ostream* out) { | 
|  | switch (entry.entry_type) { | 
|  | case MemoryAllocatorDump::Entry::EntryType::kUint64: | 
|  | *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", " | 
|  | << entry.value_uint64 << ")>"; | 
|  | return; | 
|  | case MemoryAllocatorDump::Entry::EntryType::kString: | 
|  | *out << "<Entry(\"" << entry.name << "\", \"" << entry.units << "\", \"" | 
|  | << entry.value_string << "\")>"; | 
|  | return; | 
|  | } | 
|  | NOTREACHED(); | 
|  | } | 
|  |  | 
|  | }  // namespace trace_event | 
|  | }  // namespace base |