• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/trace_processor/importers/memory_tracker/graph.h"
18 
19 namespace perfetto {
20 namespace trace_processor {
21 
22 namespace {
23 
24 using Edge = GlobalNodeGraph::Edge;
25 using PostOrderIterator = GlobalNodeGraph::PostOrderIterator;
26 using PreOrderIterator = GlobalNodeGraph::PreOrderIterator;
27 using Process = GlobalNodeGraph::Process;
28 using Node = GlobalNodeGraph::Node;
29 using perfetto::base::SplitString;
30 
31 }  // namespace
32 
GlobalNodeGraph()33 GlobalNodeGraph::GlobalNodeGraph()
34     : shared_memory_graph_(
35           std::unique_ptr<Process>(new Process(kNullProcessId, this))) {}
~GlobalNodeGraph()36 GlobalNodeGraph::~GlobalNodeGraph() {}
37 
CreateGraphForProcess(base::PlatformProcessId process_id)38 Process* GlobalNodeGraph::CreateGraphForProcess(
39     base::PlatformProcessId process_id) {
40   auto id_to_node_iterator = process_node_graphs_.emplace(
41       process_id, std::unique_ptr<Process>(new Process(process_id, this)));
42   return id_to_node_iterator.first->second.get();
43 }
44 
AddNodeOwnershipEdge(Node * owner,Node * owned,int importance)45 void GlobalNodeGraph::AddNodeOwnershipEdge(Node* owner,
46                                            Node* owned,
47                                            int importance) {
48   all_edges_.emplace_front(owner, owned, importance);
49   Edge* edge = &*all_edges_.begin();
50   owner->SetOwnsEdge(edge);
51   owned->AddOwnedByEdge(edge);
52 }
53 
CreateNode(Process * process_graph,Node * parent)54 Node* GlobalNodeGraph::CreateNode(Process* process_graph, Node* parent) {
55   all_nodes_.emplace_front(process_graph, parent);
56   return &*all_nodes_.begin();
57 }
58 
VisitInDepthFirstPreOrder()59 PreOrderIterator GlobalNodeGraph::VisitInDepthFirstPreOrder() {
60   std::vector<Node*> roots;
61   for (auto it = process_node_graphs_.rbegin();
62        it != process_node_graphs_.rend(); it++) {
63     roots.push_back(it->second->root());
64   }
65   roots.push_back(shared_memory_graph_->root());
66   return PreOrderIterator{std::move(roots)};
67 }
68 
VisitInDepthFirstPostOrder()69 PostOrderIterator GlobalNodeGraph::VisitInDepthFirstPostOrder() {
70   std::vector<Node*> roots;
71   for (auto it = process_node_graphs_.rbegin();
72        it != process_node_graphs_.rend(); it++) {
73     roots.push_back(it->second->root());
74   }
75   roots.push_back(shared_memory_graph_->root());
76   return PostOrderIterator(std::move(roots));
77 }
78 
Process(base::PlatformProcessId pid,GlobalNodeGraph * global_graph)79 Process::Process(base::PlatformProcessId pid, GlobalNodeGraph* global_graph)
80     : pid_(pid),
81       global_graph_(global_graph),
82       root_(global_graph->CreateNode(this, nullptr)) {}
~Process()83 Process::~Process() {}
84 
CreateNode(MemoryAllocatorNodeId id,const std::string & path,bool weak)85 Node* Process::CreateNode(MemoryAllocatorNodeId id,
86                           const std::string& path,
87                           bool weak) {
88   auto tokens = base::SplitString(path, "/");
89 
90   // Perform a tree traversal, creating the nodes if they do not
91   // already exist on the path to the child.
92   Node* current = root_;
93   for (const auto& key : tokens) {
94     Node* parent = current;
95     current = current->GetChild(key);
96     if (!current) {
97       current = global_graph_->CreateNode(this, parent);
98       parent->InsertChild(key, current);
99     }
100   }
101 
102   // The final node should have the weakness specified by the
103   // argument and also be considered explicit.
104   current->set_weak(weak);
105   current->set_explicit(true);
106 
107   // The final node should also have the associated |id|.
108   current->set_id(id);
109 
110   // Add to the global id map as well if it exists.
111   if (!id.empty())
112     global_graph_->nodes_by_id_.emplace(id, current);
113 
114   return current;
115 }
116 
FindNode(const std::string & path)117 Node* Process::FindNode(const std::string& path) {
118   auto tokens = base::SplitString(path, "/");
119 
120   Node* current = root_;
121   for (const auto& key : tokens) {
122     current = current->GetChild(key);
123     if (!current)
124       return nullptr;
125   }
126   return current;
127 }
128 
Node(Process * node_graph,Node * parent)129 Node::Node(Process* node_graph, Node* parent)
130     : node_graph_(node_graph), parent_(parent), owns_edge_(nullptr) {}
~Node()131 Node::~Node() {}
132 
GetChild(const std::string & name) const133 Node* Node::GetChild(const std::string& name) const {
134   auto child = children_.find(name);
135   return child == children_.end() ? nullptr : child->second;
136 }
137 
InsertChild(const std::string & name,Node * node)138 void Node::InsertChild(const std::string& name, Node* node) {
139   PERFETTO_DCHECK(node);
140   children_.emplace(name, node);
141 }
142 
CreateChild(const std::string & name)143 Node* Node::CreateChild(const std::string& name) {
144   Node* new_child = node_graph_->global_graph()->CreateNode(node_graph_, this);
145   InsertChild(name, new_child);
146   return new_child;
147 }
148 
IsDescendentOf(const Node & possible_parent) const149 bool Node::IsDescendentOf(const Node& possible_parent) const {
150   const Node* current = this;
151   while (current != nullptr) {
152     if (current == &possible_parent)
153       return true;
154     current = current->parent();
155   }
156   return false;
157 }
158 
AddOwnedByEdge(Edge * edge)159 void Node::AddOwnedByEdge(Edge* edge) {
160   owned_by_edges_.push_back(edge);
161 }
162 
SetOwnsEdge(Edge * owns_edge)163 void Node::SetOwnsEdge(Edge* owns_edge) {
164   owns_edge_ = owns_edge;
165 }
166 
AddEntry(const std::string & name,Node::Entry::ScalarUnits units,uint64_t value)167 void Node::AddEntry(const std::string& name,
168                     Node::Entry::ScalarUnits units,
169                     uint64_t value) {
170   entries_.emplace(name, Node::Entry(units, value));
171 }
172 
AddEntry(const std::string & name,const std::string & value)173 void Node::AddEntry(const std::string& name, const std::string& value) {
174   entries_.emplace(name, Node::Entry(value));
175 }
176 
Entry(Entry::ScalarUnits units2,uint64_t value)177 Node::Entry::Entry(Entry::ScalarUnits units2, uint64_t value)
178     : type(Node::Entry::Type::kUInt64), units(units2), value_uint64(value) {}
179 
Entry(const std::string & value)180 Node::Entry::Entry(const std::string& value)
181     : type(Node::Entry::Type::kString),
182       units(Node::Entry::ScalarUnits::kObjects),
183       value_string(value),
184       value_uint64(0) {}
185 
Edge(Node * source,Node * target,int priority)186 Edge::Edge(Node* source, Node* target, int priority)
187     : source_(source), target_(target), priority_(priority) {}
188 
PreOrderIterator(std::vector<Node * > && roots)189 PreOrderIterator::PreOrderIterator(std::vector<Node*>&& roots)
190     : to_visit_(std::move(roots)) {}
191 PreOrderIterator::PreOrderIterator(PreOrderIterator&& other) = default;
~PreOrderIterator()192 PreOrderIterator::~PreOrderIterator() {}
193 
194 // Yields the next node in the DFS post-order traversal.
next()195 Node* PreOrderIterator::next() {
196   while (!to_visit_.empty()) {
197     // Retain a pointer to the node at the top and remove it from stack.
198     Node* node = to_visit_.back();
199     to_visit_.pop_back();
200 
201     // If the node has already been visited, don't visit it again.
202     if (visited_.count(node) != 0)
203       continue;
204 
205     // If we haven't visited the node which this node owns then wait for that.
206     if (node->owns_edge() && visited_.count(node->owns_edge()->target()) == 0)
207       continue;
208 
209     // If we haven't visited the node's parent then wait for that.
210     if (node->parent() && visited_.count(node->parent()) == 0)
211       continue;
212 
213     // Visit all children of this node.
214     for (auto it = node->children()->rbegin(); it != node->children()->rend();
215          it++) {
216       to_visit_.push_back(it->second);
217     }
218 
219     // Visit all owners of this node.
220     for (auto it = node->owned_by_edges()->rbegin();
221          it != node->owned_by_edges()->rend(); it++) {
222       to_visit_.push_back((*it)->source());
223     }
224 
225     // Add this node to the visited set.
226     visited_.insert(node);
227     return node;
228   }
229   return nullptr;
230 }
231 
PostOrderIterator(std::vector<Node * > && roots)232 PostOrderIterator::PostOrderIterator(std::vector<Node*>&& roots)
233     : to_visit_(std::move(roots)) {}
234 PostOrderIterator::PostOrderIterator(PostOrderIterator&& other) = default;
235 PostOrderIterator::~PostOrderIterator() = default;
236 
237 // Yields the next node in the DFS post-order traversal.
next()238 Node* PostOrderIterator::next() {
239   while (!to_visit_.empty()) {
240     // Retain a pointer to the node at the top and remove it from stack.
241     Node* node = to_visit_.back();
242     to_visit_.pop_back();
243 
244     // If the node has already been visited, don't visit it again.
245     if (visited_.count(node) != 0)
246       continue;
247 
248     // If the node is at the top of the path, we have already looked
249     // at its children and owners.
250     if (!path_.empty() && path_.back() == node) {
251       // Mark the current node as visited so we don't visit again.
252       visited_.insert(node);
253 
254       // The current node is no longer on the path.
255       path_.pop_back();
256 
257       return node;
258     }
259 
260     // If the node is not at the front, it should also certainly not be
261     // anywhere else in the path. If it is, there is a cycle in the graph.
262     path_.push_back(node);
263 
264     // Add this node back to the queue of nodes to visit.
265     to_visit_.push_back(node);
266 
267     // Visit all children of this node.
268     for (auto it = node->children()->rbegin(); it != node->children()->rend();
269          it++) {
270       to_visit_.push_back(it->second);
271     }
272 
273     // Visit all owners of this node.
274     for (auto it = node->owned_by_edges()->rbegin();
275          it != node->owned_by_edges()->rend(); it++) {
276       to_visit_.push_back((*it)->source());
277     }
278   }
279   return nullptr;
280 }
281 
282 }  // namespace trace_processor
283 }  // namespace perfetto
284