1 // Copyright 2020 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 "services/resource_coordinator/memory_instrumentation/memory_dump_map_converter.h"
6 
7 #include <list>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/trace_event/process_memory_dump.h"
14 #include "third_party/perfetto/include/perfetto/ext/trace_processor/importers/memory_tracker/graph_processor.h"
15 
16 namespace memory_instrumentation {
17 
18 MemoryDumpMapConverter::MemoryDumpMapConverter() = default;
19 MemoryDumpMapConverter::~MemoryDumpMapConverter() = default;
20 
21 perfetto::trace_processor::GraphProcessor::RawMemoryNodeMap
Convert(const MemoryDumpMap & input)22 MemoryDumpMapConverter::Convert(const MemoryDumpMap& input) {
23   perfetto::trace_processor::GraphProcessor::RawMemoryNodeMap output;
24 
25   for (const auto& entry : input) {
26     const base::ProcessId process_id = entry.first;
27     const base::trace_event::ProcessMemoryDump* process_dump = entry.second;
28 
29     if (process_dump == nullptr)
30       continue;
31 
32     output.emplace(process_id, ConvertProcessMemoryDump(*process_dump));
33   }
34 
35   return output;
36 }
37 
38 std::unique_ptr<MemoryDumpMapConverter::PerfettoProcessMemoryNode>
ConvertProcessMemoryDump(const base::trace_event::ProcessMemoryDump & input)39 MemoryDumpMapConverter::ConvertProcessMemoryDump(
40     const base::trace_event::ProcessMemoryDump& input) {
41   const perfetto::trace_processor::LevelOfDetail level_of_detail =
42       ConvertLevelOfDetail(input.dump_args().level_of_detail);
43 
44   MemoryDumpMapConverter::PerfettoProcessMemoryNode::MemoryNodesMap nodes_map =
45       ConvertAllocatorDumps(input);
46   MemoryDumpMapConverter::PerfettoProcessMemoryNode::AllocatorNodeEdgesMap
47       edges_map = ConvertAllocatorDumpEdges(input);
48 
49   return std::make_unique<PerfettoProcessMemoryNode>(
50       level_of_detail, std::move(edges_map), std::move(nodes_map));
51 }
52 
53 perfetto::trace_processor::LevelOfDetail
ConvertLevelOfDetail(const base::trace_event::MemoryDumpLevelOfDetail & input) const54 MemoryDumpMapConverter::ConvertLevelOfDetail(
55     const base::trace_event::MemoryDumpLevelOfDetail& input) const {
56   switch (input) {
57     case base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND:
58       return perfetto::trace_processor::LevelOfDetail::kBackground;
59     case base::trace_event::MemoryDumpLevelOfDetail::LIGHT:
60       return perfetto::trace_processor::LevelOfDetail::kLight;
61     case base::trace_event::MemoryDumpLevelOfDetail::DETAILED:
62       return perfetto::trace_processor::LevelOfDetail::kDetailed;
63   }
64   return perfetto::trace_processor::LevelOfDetail::kDetailed;
65 }
66 
67 std::vector<perfetto::trace_processor::RawMemoryGraphNode::MemoryNodeEntry>
ConvertAllocatorDumpEntries(const base::trace_event::MemoryAllocatorDump & input) const68 MemoryDumpMapConverter::ConvertAllocatorDumpEntries(
69     const base::trace_event::MemoryAllocatorDump& input) const {
70   std::vector<perfetto::trace_processor::RawMemoryGraphNode::MemoryNodeEntry>
71       output;
72 
73   for (const auto& entry : input.entries()) {
74     if (entry.entry_type ==
75         base::trace_event::MemoryAllocatorDump::Entry::kUint64) {
76       output.emplace_back(entry.name, entry.units, entry.value_uint64);
77     } else {
78       output.emplace_back(entry.name, entry.units, entry.value_string);
79     }
80   }
81   return output;
82 }
83 
84 std::unique_ptr<perfetto::trace_processor::RawMemoryGraphNode>
ConvertMemoryAllocatorDump(const base::trace_event::MemoryAllocatorDump & input) const85 MemoryDumpMapConverter::ConvertMemoryAllocatorDump(
86     const base::trace_event::MemoryAllocatorDump& input) const {
87   auto output = std::make_unique<perfetto::trace_processor::RawMemoryGraphNode>(
88       input.absolute_name(), ConvertLevelOfDetail(input.level_of_detail()),
89       ConvertMemoryAllocatorDumpGuid(input.guid()),
90       ConvertAllocatorDumpEntries(input));
91 
92   CopyAndConvertAllocatorDumpFlags(input, output.get());
93 
94   return output;
95 }
96 
CopyAndConvertAllocatorDumpFlags(const base::trace_event::MemoryAllocatorDump & input,perfetto::trace_processor::RawMemoryGraphNode * output) const97 void MemoryDumpMapConverter::CopyAndConvertAllocatorDumpFlags(
98     const base::trace_event::MemoryAllocatorDump& input,
99     perfetto::trace_processor::RawMemoryGraphNode* output) const {
100   output->clear_flags(output->flags());
101   output->set_flags(
102       input.flags() & base::trace_event::MemoryAllocatorDump::WEAK
103           ? perfetto::trace_processor::RawMemoryGraphNode::kWeak
104           : perfetto::trace_processor::RawMemoryGraphNode::kDefault);
105 }
106 
107 MemoryDumpMapConverter::PerfettoProcessMemoryNode::MemoryNodesMap
ConvertAllocatorDumps(const base::trace_event::ProcessMemoryDump & input) const108 MemoryDumpMapConverter::ConvertAllocatorDumps(
109     const base::trace_event::ProcessMemoryDump& input) const {
110   MemoryDumpMapConverter::PerfettoProcessMemoryNode::MemoryNodesMap output;
111   for (const auto& entry : input.allocator_dumps()) {
112     const std::unique_ptr<base::trace_event::MemoryAllocatorDump>& dump =
113         entry.second;
114 
115     output.emplace(entry.first, ConvertMemoryAllocatorDump(*dump));
116   }
117   return output;
118 }
119 
120 MemoryDumpMapConverter::PerfettoProcessMemoryNode::AllocatorNodeEdgesMap
ConvertAllocatorDumpEdges(const base::trace_event::ProcessMemoryDump & input) const121 MemoryDumpMapConverter::ConvertAllocatorDumpEdges(
122     const base::trace_event::ProcessMemoryDump& input) const {
123   MemoryDumpMapConverter::PerfettoProcessMemoryNode::AllocatorNodeEdgesMap
124       output;
125   for (const auto& entry : input.allocator_dumps_edges()) {
126     std::unique_ptr<perfetto::trace_processor::MemoryGraphEdge> edge =
127         ConvertAllocatorDumpEdge(entry.second);
128     const perfetto::trace_processor::MemoryAllocatorNodeId source =
129         edge->source;
130     output.emplace(source, std::move(edge));
131   }
132   return output;
133 }
134 
135 std::unique_ptr<perfetto::trace_processor::MemoryGraphEdge>
ConvertAllocatorDumpEdge(const base::trace_event::ProcessMemoryDump::MemoryAllocatorDumpEdge & input) const136 MemoryDumpMapConverter::ConvertAllocatorDumpEdge(
137     const base::trace_event::ProcessMemoryDump::MemoryAllocatorDumpEdge& input)
138     const {
139   return std::make_unique<perfetto::trace_processor::MemoryGraphEdge>(
140       ConvertMemoryAllocatorDumpGuid(input.source),
141       ConvertMemoryAllocatorDumpGuid(input.target), input.importance,
142       input.overridable);
143 }
144 
145 perfetto::trace_processor::MemoryAllocatorNodeId
ConvertMemoryAllocatorDumpGuid(const base::trace_event::MemoryAllocatorDumpGuid & input) const146 MemoryDumpMapConverter::ConvertMemoryAllocatorDumpGuid(
147     const base::trace_event::MemoryAllocatorDumpGuid& input) const {
148   return perfetto::trace_processor::MemoryAllocatorNodeId(input.ToUint64());
149 }
150 
151 }  // namespace memory_instrumentation
152