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 "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h"
6 
7 #include <stddef.h>
8 #include <string>
9 
10 #include "base/memory/discardable_memory.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/trace_event/process_memory_dump.h"
14 #include "base/trace_event/trace_event_memory_overhead.h"
15 #include "base/trace_event/traced_value.h"
16 #include "skia/ext/skia_trace_memory_dump_impl.h"
17 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
18 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
19 
20 namespace blink {
21 
WebProcessMemoryDump()22 WebProcessMemoryDump::WebProcessMemoryDump()
23     : owned_process_memory_dump_(new base::trace_event::ProcessMemoryDump(
24           {base::trace_event::MemoryDumpLevelOfDetail::DETAILED})),
25       process_memory_dump_(owned_process_memory_dump_.get()),
26       level_of_detail_(base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {}
27 
WebProcessMemoryDump(base::trace_event::MemoryDumpLevelOfDetail level_of_detail,base::trace_event::ProcessMemoryDump * process_memory_dump)28 WebProcessMemoryDump::WebProcessMemoryDump(
29     base::trace_event::MemoryDumpLevelOfDetail level_of_detail,
30     base::trace_event::ProcessMemoryDump* process_memory_dump)
31     : process_memory_dump_(process_memory_dump),
32       level_of_detail_(level_of_detail) {}
33 
34 WebProcessMemoryDump::~WebProcessMemoryDump() = default;
35 
CreateMemoryAllocatorDump(const String & absolute_name)36 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::CreateMemoryAllocatorDump(
37     const String& absolute_name) {
38   // Get a MemoryAllocatorDump from the base/ object.
39   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
40       process_memory_dump_->CreateAllocatorDump(absolute_name.Utf8());
41 
42   return CreateWebMemoryAllocatorDump(memory_allocator_dump);
43 }
44 
CreateMemoryAllocatorDump(const String & absolute_name,blink::WebMemoryAllocatorDumpGuid guid)45 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::CreateMemoryAllocatorDump(
46     const String& absolute_name,
47     blink::WebMemoryAllocatorDumpGuid guid) {
48   // Get a MemoryAllocatorDump from the base/ object with given guid.
49   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
50       process_memory_dump_->CreateAllocatorDump(
51           absolute_name.Utf8(),
52           base::trace_event::MemoryAllocatorDumpGuid(guid));
53   return CreateWebMemoryAllocatorDump(memory_allocator_dump);
54 }
55 
56 blink::WebMemoryAllocatorDump*
CreateWebMemoryAllocatorDump(base::trace_event::MemoryAllocatorDump * memory_allocator_dump)57 WebProcessMemoryDump::CreateWebMemoryAllocatorDump(
58     base::trace_event::MemoryAllocatorDump* memory_allocator_dump) {
59   if (!memory_allocator_dump)
60     return nullptr;
61 
62   // Wrap it and return to blink.
63   WebMemoryAllocatorDump* web_memory_allocator_dump =
64       new WebMemoryAllocatorDump(memory_allocator_dump);
65 
66   // memory_allocator_dumps_ will take ownership of
67   // |web_memory_allocator_dump|.
68   memory_allocator_dumps_.Set(memory_allocator_dump,
69                               base::WrapUnique(web_memory_allocator_dump));
70   return web_memory_allocator_dump;
71 }
72 
GetMemoryAllocatorDump(const String & absolute_name) const73 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::GetMemoryAllocatorDump(
74     const String& absolute_name) const {
75   // Retrieve the base MemoryAllocatorDump object and then reverse lookup
76   // its wrapper.
77   base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
78       process_memory_dump_->GetAllocatorDump(absolute_name.Utf8());
79   if (!memory_allocator_dump)
80     return nullptr;
81 
82   // The only case of (memory_allocator_dump && !web_memory_allocator_dump)
83   // is something from blink trying to get a MAD that was created from chromium,
84   // which is an odd use case.
85   blink::WebMemoryAllocatorDump* web_memory_allocator_dump =
86       memory_allocator_dumps_.at(memory_allocator_dump);
87   DCHECK(web_memory_allocator_dump);
88   return web_memory_allocator_dump;
89 }
90 
Clear()91 void WebProcessMemoryDump::Clear() {
92   // Clear all the WebMemoryAllocatorDump wrappers.
93   memory_allocator_dumps_.clear();
94 
95   // Clear the actual MemoryAllocatorDump objects from the underlying PMD.
96   process_memory_dump_->Clear();
97 }
98 
TakeAllDumpsFrom(blink::WebProcessMemoryDump * other)99 void WebProcessMemoryDump::TakeAllDumpsFrom(
100     blink::WebProcessMemoryDump* other) {
101   // WebProcessMemoryDump is a container of WebMemoryAllocatorDump(s) which
102   // in turn are wrappers of base::trace_event::MemoryAllocatorDump(s).
103   // In order to expose the move and ownership transfer semantics of the
104   // underlying ProcessMemoryDump, we need to:
105 
106   // 1) Move and transfer the ownership of the wrapped
107   // base::trace_event::MemoryAllocatorDump(s) instances.
108   process_memory_dump_->TakeAllDumpsFrom(other->process_memory_dump_);
109 
110   // 2) Move and transfer the ownership of the WebMemoryAllocatorDump wrappers.
111   const size_t expected_final_size =
112       memory_allocator_dumps_.size() + other->memory_allocator_dumps_.size();
113   while (!other->memory_allocator_dumps_.IsEmpty()) {
114     auto first_entry = other->memory_allocator_dumps_.begin();
115     base::trace_event::MemoryAllocatorDump* memory_allocator_dump =
116         first_entry->key;
117     memory_allocator_dumps_.Set(
118         memory_allocator_dump,
119         other->memory_allocator_dumps_.Take(memory_allocator_dump));
120   }
121   DCHECK_EQ(expected_final_size, memory_allocator_dumps_.size());
122   DCHECK(other->memory_allocator_dumps_.IsEmpty());
123 }
124 
AddOwnershipEdge(blink::WebMemoryAllocatorDumpGuid source,blink::WebMemoryAllocatorDumpGuid target,int importance)125 void WebProcessMemoryDump::AddOwnershipEdge(
126     blink::WebMemoryAllocatorDumpGuid source,
127     blink::WebMemoryAllocatorDumpGuid target,
128     int importance) {
129   process_memory_dump_->AddOwnershipEdge(
130       base::trace_event::MemoryAllocatorDumpGuid(source),
131       base::trace_event::MemoryAllocatorDumpGuid(target), importance);
132 }
133 
AddOwnershipEdge(blink::WebMemoryAllocatorDumpGuid source,blink::WebMemoryAllocatorDumpGuid target)134 void WebProcessMemoryDump::AddOwnershipEdge(
135     blink::WebMemoryAllocatorDumpGuid source,
136     blink::WebMemoryAllocatorDumpGuid target) {
137   process_memory_dump_->AddOwnershipEdge(
138       base::trace_event::MemoryAllocatorDumpGuid(source),
139       base::trace_event::MemoryAllocatorDumpGuid(target));
140 }
141 
AddSuballocation(blink::WebMemoryAllocatorDumpGuid source,const String & target_node_name)142 void WebProcessMemoryDump::AddSuballocation(
143     blink::WebMemoryAllocatorDumpGuid source,
144     const String& target_node_name) {
145   process_memory_dump_->AddSuballocation(
146       base::trace_event::MemoryAllocatorDumpGuid(source),
147       target_node_name.Utf8());
148 }
149 
CreateDumpAdapterForSkia(const String & dump_name_prefix)150 SkTraceMemoryDump* WebProcessMemoryDump::CreateDumpAdapterForSkia(
151     const String& dump_name_prefix) {
152   sk_trace_dump_list_.push_back(std::make_unique<skia::SkiaTraceMemoryDumpImpl>(
153       dump_name_prefix.Utf8(), level_of_detail_, process_memory_dump_));
154   return sk_trace_dump_list_.back().get();
155 }
156 
157 blink::WebMemoryAllocatorDump*
CreateDiscardableMemoryAllocatorDump(const std::string & name,base::DiscardableMemory * discardable)158 WebProcessMemoryDump::CreateDiscardableMemoryAllocatorDump(
159     const std::string& name,
160     base::DiscardableMemory* discardable) {
161   base::trace_event::MemoryAllocatorDump* dump =
162       discardable->CreateMemoryAllocatorDump(name.c_str(),
163                                              process_memory_dump_);
164   return CreateWebMemoryAllocatorDump(dump);
165 }
166 
DumpHeapUsage(const std::unordered_map<base::trace_event::AllocationContext,base::trace_event::AllocationMetrics> & metrics_by_context,base::trace_event::TraceEventMemoryOverhead & overhead,const char * allocator_name)167 void WebProcessMemoryDump::DumpHeapUsage(
168     const std::unordered_map<base::trace_event::AllocationContext,
169                              base::trace_event::AllocationMetrics>&
170         metrics_by_context,
171     base::trace_event::TraceEventMemoryOverhead& overhead,
172     const char* allocator_name) {
173   process_memory_dump_->DumpHeapUsage(metrics_by_context, overhead,
174                                       allocator_name);
175 }
176 
177 }  // namespace content
178