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