1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright 2015 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event_memory_overhead.h"
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <algorithm>
8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
90d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/bits.h"
10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/memory/ref_counted_memory.h"
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/stringprintf.h"
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/memory_allocator_dump.h"
13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/process_memory_dump.h"
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/values.h"
15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace trace_event {
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTraceEventMemoryOverhead::TraceEventMemoryOverhead() {
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::AddOrCreateInternal(
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const char* object_type,
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    size_t count,
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    size_t allocated_size_in_bytes,
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    size_t resident_size_in_bytes) {
30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  auto it = allocated_objects_.find(object_type);
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (it == allocated_objects_.end()) {
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    allocated_objects_.insert(std::make_pair(
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        object_type,
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        ObjectCountAndSize(
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat            {count, allocated_size_in_bytes, resident_size_in_bytes})));
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  it->second.count += count;
39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  it->second.allocated_size_in_bytes += allocated_size_in_bytes;
40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  it->second.resident_size_in_bytes += resident_size_in_bytes;
41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::Add(const char* object_type,
44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                   size_t allocated_size_in_bytes) {
45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::Add(const char* object_type,
49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                   size_t allocated_size_in_bytes,
50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                   size_t resident_size_in_bytes) {
51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                      resident_size_in_bytes);
53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::AddString(const std::string& str) {
56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The number below are empirical and mainly based on profiling of real-world
57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // std::string implementations:
58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //  - even short string end up malloc()-inc at least 32 bytes.
590d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  //  - longer strings seem to malloc() multiples of 16 bytes.
600d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  const size_t capacity = bits::Align(str.capacity(), 16);
610d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 32u));
62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::AddRefCountedString(
65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const RefCountedString& str) {
66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Add("RefCountedString", sizeof(RefCountedString));
67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  AddString(str.data());
68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::AddValue(const Value& value) {
71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  switch (value.GetType()) {
723a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::NONE:
733a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::BOOLEAN:
743a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::INTEGER:
753a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::DOUBLE:
76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Add("FundamentalValue", sizeof(Value));
77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      break;
78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
793a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::STRING: {
803a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli      const Value* string_value = nullptr;
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      value.GetAsString(&string_value);
823a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli      Add("StringValue", sizeof(Value));
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      AddString(string_value->GetString());
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } break;
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
863a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::BINARY: {
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const BinaryValue* binary_value = nullptr;
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      value.GetAsBinary(&binary_value);
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } break;
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
923a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::DICTIONARY: {
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const DictionaryValue* dictionary_value = nullptr;
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      value.GetAsDictionary(&dictionary_value);
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Add("DictionaryValue", sizeof(DictionaryValue));
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat           it.Advance()) {
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        AddString(it.key());
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        AddValue(it.value());
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } break;
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
1033a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    case Value::Type::LIST: {
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const ListValue* list_value = nullptr;
105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      value.GetAsList(&list_value);
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Add("ListValue", sizeof(ListValue));
1070c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez      for (const auto& v : *list_value)
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        AddValue(*v);
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } break;
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    default:
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      NOTREACHED();
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::AddSelf() {
117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  size_t estimated_size = sizeof(*this);
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // If the SmallMap did overflow its static capacity, its elements will be
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // allocated on the heap and have to be accounted separately.
120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (allocated_objects_.UsingFullMap())
121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Add("TraceEventMemoryOverhead", estimated_size);
123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
1250d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkosize_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
1260d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  const auto& it = allocated_objects_.find(object_type);
1270d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (it == allocated_objects_.end())
1280d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return 0u;
1290d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  return it->second.count;
1300d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko}
1310d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const auto& it : other.allocated_objects_) {
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    AddOrCreateInternal(it.first, it.second.count,
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                        it.second.allocated_size_in_bytes,
136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                        it.second.resident_size_in_bytes);
137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEventMemoryOverhead::DumpInto(const char* base_name,
141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                        ProcessMemoryDump* pmd) const {
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const auto& it : allocated_objects_) {
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    mad->AddScalar(MemoryAllocatorDump::kNameSize,
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   MemoryAllocatorDump::kUnitsBytes,
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   it.second.allocated_size_in_bytes);
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   it.second.resident_size_in_bytes);
1500d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    mad->AddScalar(MemoryAllocatorDump::kNameObjectCount,
151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace trace_event
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
157