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_COMPONENT 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_COMPONENT 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_COMPONENT 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_COMPONENT 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_COMPONENT 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_COMPONENT 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_COMPONENT 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 // |process_graph| and for the given |parent|. 301 Node* CreateNode(GlobalNodeGraph::Process* process_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