Home | History | Annotate | Download | only in trace_event
      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 
     16 namespace base {
     17 namespace trace_event {
     18 
     19 TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
     20 }
     21 
     22 TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
     23 }
     24 
     25 void 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 
     43 void 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 
     48 void 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 
     55 void 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 
     64 void TraceEventMemoryOverhead::AddRefCountedString(
     65     const RefCountedString& str) {
     66   Add("RefCountedString", sizeof(RefCountedString));
     67   AddString(str.data());
     68 }
     69 
     70 void 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 
    116 void 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 
    125 size_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 
    132 void 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 
    140 void 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