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 #ifndef INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_IMPORTERS_MEMORY_TRACKER_GRAPH_H_
18 #define INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_IMPORTERS_MEMORY_TRACKER_GRAPH_H_
19 
20 #include <sys/types.h>
21 
22 #include <forward_list>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <string>
27 #include <vector>
28 
29 #include "perfetto/base/export.h"
30 #include "perfetto/base/proc_utils.h"
31 #include "perfetto/ext/base/string_utils.h"
32 #include "perfetto/ext/trace_processor/importers/memory_tracker/memory_allocator_node_id.h"
33 
34 namespace perfetto {
35 namespace trace_processor {
36 
37 const base::PlatformProcessId kNullProcessId = 0;
38 
39 // Contains processed node graphs for each process and in the global space.
40 // This class is also the arena which owns the nodes of the graph.
41 class PERFETTO_EXPORT GlobalNodeGraph {
42  public:
43   class Node;
44   class Edge;
45   class PreOrderIterator;
46   class PostOrderIterator;
47 
48   // Graph of nodes either associated with a process or with
49   // the shared space.
50   class PERFETTO_EXPORT Process {
51    public:
52     Process(base::PlatformProcessId pid, GlobalNodeGraph* global_graph);
53     ~Process();
54 
55     // Creates a node in the node graph which is associated with the
56     // given |id|, |path| and |weak|ness and returns it.
57     GlobalNodeGraph::Node* CreateNode(MemoryAllocatorNodeId id,
58                                       const std::string& path,
59                                       bool weak);
60 
61     // Returns the node in the graph at the given |path| or nullptr
62     // if no such node exists in the provided |graph|.
63     GlobalNodeGraph::Node* FindNode(const std::string& path);
64 
pid()65     base::PlatformProcessId pid() const { return pid_; }
global_graph()66     GlobalNodeGraph* global_graph() const { return global_graph_; }
root()67     GlobalNodeGraph::Node* root() const { return root_; }
68 
69    private:
70     base::PlatformProcessId pid_;
71     GlobalNodeGraph* global_graph_;
72     GlobalNodeGraph::Node* root_;
73     Process(const Process&) = delete;
74     Process& operator=(const Process&) = delete;
75   };
76 
77   // A single node in the graph of allocator nodes associated with a
78   // certain path and containing the entries for this path.
79   class PERFETTO_EXPORT Node {
80    public:
81     // Auxilary data (a scalar number or a string) about this node each
82     // associated with a key.
83     struct PERFETTO_EXPORT Entry {
84       enum Type {
85         kUInt64,
86         kString,
87       };
88 
89       // The units of the entry if the entry is a scalar. The scalar
90       // refers to either a number of objects or a size in bytes.
91       enum ScalarUnits {
92         kObjects,
93         kBytes,
94       };
95 
96       // Creates the entry with the appropriate type.
97       Entry(ScalarUnits units, uint64_t value);
98       explicit Entry(const std::string& value);
99 
100       const Type type;
101       const ScalarUnits units;
102 
103       // The value of the entry if this entry has a string type.
104       const std::string value_string;
105 
106       // The value of the entry if this entry has a integer type.
107       const uint64_t value_uint64;
108     };
109 
110     explicit Node(GlobalNodeGraph::Process* node_graph, Node* parent);
111     ~Node();
112 
113     // Gets the direct child of a node for the given |subpath|.
114     Node* GetChild(const std::string& name) const;
115 
116     // Inserts the given |node| as a child of the current node
117     // with the given |subpath| as the key.
118     void InsertChild(const std::string& name, Node* node);
119 
120     // Creates a child for this node with the given |name| as the key.
121     Node* CreateChild(const std::string& name);
122 
123     // Checks if the current node is a descendent (i.e. exists as a child,
124     // child of a child, etc.) of the given node |possible_parent|.
125     bool IsDescendentOf(const Node& possible_parent) const;
126 
127     // Adds an entry for this node node with the given |name|, |units| and
128     // type.
129     void AddEntry(const std::string& name,
130                   Entry::ScalarUnits units,
131                   uint64_t value);
132     void AddEntry(const std::string& name, const std::string& value);
133 
134     // Adds an edge which indicates that this node is owned by
135     // another node.
136     void AddOwnedByEdge(Edge* edge);
137 
138     // Sets the edge indicates that this node owns another node.
139     void SetOwnsEdge(Edge* edge);
140 
is_weak()141     bool is_weak() const { return weak_; }
set_weak(bool weak)142     void set_weak(bool weak) { weak_ = weak; }
is_explicit()143     bool is_explicit() const { return explicit_; }
set_explicit(bool explicit_node)144     void set_explicit(bool explicit_node) { explicit_ = explicit_node; }
not_owned_sub_size()145     uint64_t not_owned_sub_size() const { return not_owned_sub_size_; }
add_not_owned_sub_size(uint64_t addition)146     void add_not_owned_sub_size(uint64_t addition) {
147       not_owned_sub_size_ += addition;
148     }
not_owning_sub_size()149     uint64_t not_owning_sub_size() const { return not_owning_sub_size_; }
add_not_owning_sub_size(uint64_t addition)150     void add_not_owning_sub_size(uint64_t addition) {
151       not_owning_sub_size_ += addition;
152     }
owned_coefficient()153     double owned_coefficient() const { return owned_coefficient_; }
set_owned_coefficient(double owned_coefficient)154     void set_owned_coefficient(double owned_coefficient) {
155       owned_coefficient_ = owned_coefficient;
156     }
owning_coefficient()157     double owning_coefficient() const { return owning_coefficient_; }
set_owning_coefficient(double owning_coefficient)158     void set_owning_coefficient(double owning_coefficient) {
159       owning_coefficient_ = owning_coefficient;
160     }
cumulative_owned_coefficient()161     double cumulative_owned_coefficient() const {
162       return cumulative_owned_coefficient_;
163     }
set_cumulative_owned_coefficient(double cumulative_owned_coefficient)164     void set_cumulative_owned_coefficient(double cumulative_owned_coefficient) {
165       cumulative_owned_coefficient_ = cumulative_owned_coefficient;
166     }
cumulative_owning_coefficient()167     double cumulative_owning_coefficient() const {
168       return cumulative_owning_coefficient_;
169     }
set_cumulative_owning_coefficient(double cumulative_owning_coefficient)170     void set_cumulative_owning_coefficient(
171         double cumulative_owning_coefficient) {
172       cumulative_owning_coefficient_ = cumulative_owning_coefficient;
173     }
id()174     MemoryAllocatorNodeId id() const { return id_; }
set_id(MemoryAllocatorNodeId id)175     void set_id(MemoryAllocatorNodeId id) { id_ = id; }
owns_edge()176     GlobalNodeGraph::Edge* owns_edge() const { return owns_edge_; }
children()177     std::map<std::string, Node*>* children() { return &children_; }
const_children()178     const std::map<std::string, Node*>& const_children() const {
179       return children_;
180     }
owned_by_edges()181     std::vector<GlobalNodeGraph::Edge*>* owned_by_edges() {
182       return &owned_by_edges_;
183     }
parent()184     const Node* parent() const { return parent_; }
node_graph()185     const GlobalNodeGraph::Process* node_graph() const { return node_graph_; }
entries()186     std::map<std::string, Entry>* entries() { return &entries_; }
const_entries()187     const std::map<std::string, Entry>& const_entries() const {
188       return entries_;
189     }
190 
191    private:
192     GlobalNodeGraph::Process* node_graph_;
193     Node* const parent_;
194     MemoryAllocatorNodeId id_;
195     std::map<std::string, Entry> entries_;
196     std::map<std::string, Node*> children_;
197     bool explicit_ = false;
198     bool weak_ = false;
199     uint64_t not_owning_sub_size_ = 0;
200     uint64_t not_owned_sub_size_ = 0;
201     double owned_coefficient_ = 1;
202     double owning_coefficient_ = 1;
203     double cumulative_owned_coefficient_ = 1;
204     double cumulative_owning_coefficient_ = 1;
205 
206     GlobalNodeGraph::Edge* owns_edge_;
207     std::vector<GlobalNodeGraph::Edge*> owned_by_edges_;
208 
209     Node(const Node&) = delete;
210     Node& operator=(const Node&) = delete;
211   };
212 
213   // An edge in the node graph which indicates ownership between the
214   // source and target nodes.
215   class PERFETTO_EXPORT Edge {
216    public:
217     Edge(GlobalNodeGraph::Node* source,
218          GlobalNodeGraph::Node* target,
219          int priority);
220 
source()221     GlobalNodeGraph::Node* source() const { return source_; }
target()222     GlobalNodeGraph::Node* target() const { return target_; }
priority()223     int priority() const { return priority_; }
224 
225    private:
226     GlobalNodeGraph::Node* const source_;
227     GlobalNodeGraph::Node* const target_;
228     const int priority_;
229   };
230 
231   // An iterator-esque class which yields nodes in a depth-first pre order.
232   class PERFETTO_EXPORT PreOrderIterator {
233    public:
234     explicit PreOrderIterator(std::vector<Node*>&& root_nodes);
235     PreOrderIterator(PreOrderIterator&& other);
236     ~PreOrderIterator();
237 
238     // Yields the next node in the DFS post-order traversal.
239     Node* next();
240 
241    private:
242     std::vector<Node*> to_visit_;
243     std::set<const Node*> visited_;
244   };
245 
246   // An iterator-esque class which yields nodes in a depth-first post order.
247   class PERFETTO_EXPORT PostOrderIterator {
248    public:
249     explicit PostOrderIterator(std::vector<Node*>&& root_nodes);
250     PostOrderIterator(PostOrderIterator&& other);
251     ~PostOrderIterator();
252 
253     // Yields the next node in the DFS post-order traversal.
254     Node* next();
255 
256    private:
257     std::vector<Node*> to_visit_;
258     std::set<Node*> visited_;
259     std::vector<Node*> path_;
260   };
261 
262   using ProcessNodeGraphMap =
263       std::map<base::PlatformProcessId,
264                std::unique_ptr<GlobalNodeGraph::Process>>;
265   using IdNodeMap = std::map<MemoryAllocatorNodeId, Node*>;
266 
267   GlobalNodeGraph();
268   ~GlobalNodeGraph();
269 
270   // Creates a container for all the node graphs for the process given
271   // by the given |process_id|.
272   GlobalNodeGraph::Process* CreateGraphForProcess(
273       base::PlatformProcessId process_id);
274 
275   // Adds an edge in the node graph with the given source and target nodes
276   // and edge priority.
277   void AddNodeOwnershipEdge(Node* owner, Node* owned, int priority);
278 
279   // Returns an iterator which yields nodes in the nodes in this graph in
280   // pre-order. That is, children and owners of nodes are returned after the
281   // node itself.
282   PreOrderIterator VisitInDepthFirstPreOrder();
283 
284   // Returns an iterator which yields nodes in the nodes in this graph in
285   // post-order. That is, children and owners of nodes are returned before the
286   // node itself.
287   PostOrderIterator VisitInDepthFirstPostOrder();
288 
nodes_by_id()289   const IdNodeMap& nodes_by_id() const { return nodes_by_id_; }
shared_memory_graph()290   GlobalNodeGraph::Process* shared_memory_graph() const {
291     return shared_memory_graph_.get();
292   }
process_node_graphs()293   const ProcessNodeGraphMap& process_node_graphs() const {
294     return process_node_graphs_;
295   }
edges()296   const std::forward_list<Edge>& edges() const { return all_edges_; }
297 
298  private:
299   // Creates a node in the arena which is associated with the given
300   // |node_graph| and for the given |parent|.
301   Node* CreateNode(GlobalNodeGraph::Process* node_graph,
302                    GlobalNodeGraph::Node* parent);
303 
304   std::forward_list<Node> all_nodes_;
305   std::forward_list<Edge> all_edges_;
306   IdNodeMap nodes_by_id_;
307   std::unique_ptr<GlobalNodeGraph::Process> shared_memory_graph_;
308   ProcessNodeGraphMap process_node_graphs_;
309   GlobalNodeGraph(const GlobalNodeGraph&) = delete;
310   GlobalNodeGraph& operator=(const GlobalNodeGraph&) = delete;
311 };
312 
313 }  // namespace trace_processor
314 }  // namespace perfetto
315 
316 #endif  // INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_IMPORTERS_MEMORY_TRACKER_GRAPH_H_
317