1*6dbdd20aSAndroid Build Coastguard Worker /* 2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker * 4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker * 8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker * 10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker */ 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_PROFILING_COMMON_CALLSTACK_TRIE_H_ 18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_PROFILING_COMMON_CALLSTACK_TRIE_H_ 19*6dbdd20aSAndroid Build Coastguard Worker 20*6dbdd20aSAndroid Build Coastguard Worker #include <set> 21*6dbdd20aSAndroid Build Coastguard Worker #include <string> 22*6dbdd20aSAndroid Build Coastguard Worker #include <typeindex> 23*6dbdd20aSAndroid Build Coastguard Worker #include <vector> 24*6dbdd20aSAndroid Build Coastguard Worker 25*6dbdd20aSAndroid Build Coastguard Worker #include <unwindstack/Unwinder.h> 26*6dbdd20aSAndroid Build Coastguard Worker 27*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/interner.h" 28*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/unwind_support.h" 29*6dbdd20aSAndroid Build Coastguard Worker 30*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto { 31*6dbdd20aSAndroid Build Coastguard Worker namespace profiling { 32*6dbdd20aSAndroid Build Coastguard Worker 33*6dbdd20aSAndroid Build Coastguard Worker struct Mapping { MappingMapping34*6dbdd20aSAndroid Build Coastguard Worker explicit Mapping(Interned<std::string> b) : build_id(std::move(b)) {} 35*6dbdd20aSAndroid Build Coastguard Worker 36*6dbdd20aSAndroid Build Coastguard Worker Interned<std::string> build_id; 37*6dbdd20aSAndroid Build Coastguard Worker uint64_t exact_offset = 0; 38*6dbdd20aSAndroid Build Coastguard Worker uint64_t start_offset = 0; 39*6dbdd20aSAndroid Build Coastguard Worker uint64_t start = 0; 40*6dbdd20aSAndroid Build Coastguard Worker uint64_t end = 0; 41*6dbdd20aSAndroid Build Coastguard Worker uint64_t load_bias = 0; 42*6dbdd20aSAndroid Build Coastguard Worker std::vector<Interned<std::string>> path_components{}; 43*6dbdd20aSAndroid Build Coastguard Worker 44*6dbdd20aSAndroid Build Coastguard Worker bool operator<(const Mapping& other) const { 45*6dbdd20aSAndroid Build Coastguard Worker return std::tie(build_id, exact_offset, start_offset, start, end, load_bias, 46*6dbdd20aSAndroid Build Coastguard Worker path_components) < 47*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.build_id, other.exact_offset, other.start_offset, 48*6dbdd20aSAndroid Build Coastguard Worker other.start, other.end, other.load_bias, 49*6dbdd20aSAndroid Build Coastguard Worker other.path_components); 50*6dbdd20aSAndroid Build Coastguard Worker } 51*6dbdd20aSAndroid Build Coastguard Worker bool operator==(const Mapping& other) const { 52*6dbdd20aSAndroid Build Coastguard Worker return std::tie(build_id, exact_offset, start_offset, start, end, load_bias, 53*6dbdd20aSAndroid Build Coastguard Worker path_components) == 54*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.build_id, other.exact_offset, other.start_offset, 55*6dbdd20aSAndroid Build Coastguard Worker other.start, other.end, other.load_bias, 56*6dbdd20aSAndroid Build Coastguard Worker other.path_components); 57*6dbdd20aSAndroid Build Coastguard Worker } 58*6dbdd20aSAndroid Build Coastguard Worker }; 59*6dbdd20aSAndroid Build Coastguard Worker 60*6dbdd20aSAndroid Build Coastguard Worker struct Frame { FrameFrame61*6dbdd20aSAndroid Build Coastguard Worker Frame(Interned<Mapping> m, Interned<std::string> fn_name, uint64_t pc) 62*6dbdd20aSAndroid Build Coastguard Worker : mapping(m), function_name(fn_name), rel_pc(pc) {} 63*6dbdd20aSAndroid Build Coastguard Worker Interned<Mapping> mapping; 64*6dbdd20aSAndroid Build Coastguard Worker Interned<std::string> function_name; 65*6dbdd20aSAndroid Build Coastguard Worker uint64_t rel_pc; 66*6dbdd20aSAndroid Build Coastguard Worker 67*6dbdd20aSAndroid Build Coastguard Worker bool operator<(const Frame& other) const { 68*6dbdd20aSAndroid Build Coastguard Worker return std::tie(mapping, function_name, rel_pc) < 69*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.mapping, other.function_name, other.rel_pc); 70*6dbdd20aSAndroid Build Coastguard Worker } 71*6dbdd20aSAndroid Build Coastguard Worker 72*6dbdd20aSAndroid Build Coastguard Worker bool operator==(const Frame& other) const { 73*6dbdd20aSAndroid Build Coastguard Worker return std::tie(mapping, function_name, rel_pc) == 74*6dbdd20aSAndroid Build Coastguard Worker std::tie(other.mapping, other.function_name, other.rel_pc); 75*6dbdd20aSAndroid Build Coastguard Worker } 76*6dbdd20aSAndroid Build Coastguard Worker }; 77*6dbdd20aSAndroid Build Coastguard Worker 78*6dbdd20aSAndroid Build Coastguard Worker // Graph of function callsites. A single instance can be used for callsites from 79*6dbdd20aSAndroid Build Coastguard Worker // different processes. Each call site is represented by a 80*6dbdd20aSAndroid Build Coastguard Worker // GlobalCallstackTrie::Node that is owned by the parent callsite. Each node has 81*6dbdd20aSAndroid Build Coastguard Worker // a pointer to its parent, which means the function call-graph can be 82*6dbdd20aSAndroid Build Coastguard Worker // reconstructed from a GlobalCallstackTrie::Node by walking down the parent 83*6dbdd20aSAndroid Build Coastguard Worker // chain. 84*6dbdd20aSAndroid Build Coastguard Worker // 85*6dbdd20aSAndroid Build Coastguard Worker // For the following two callstacks: 86*6dbdd20aSAndroid Build Coastguard Worker // * libc_init -> main -> foo -> alloc_buf 87*6dbdd20aSAndroid Build Coastguard Worker // * libc_init -> main -> bar -> alloc_buf 88*6dbdd20aSAndroid Build Coastguard Worker // The tree looks as following: 89*6dbdd20aSAndroid Build Coastguard Worker // alloc_buf alloc_buf 90*6dbdd20aSAndroid Build Coastguard Worker // | | 91*6dbdd20aSAndroid Build Coastguard Worker // foo bar 92*6dbdd20aSAndroid Build Coastguard Worker // \ / 93*6dbdd20aSAndroid Build Coastguard Worker // main 94*6dbdd20aSAndroid Build Coastguard Worker // | 95*6dbdd20aSAndroid Build Coastguard Worker // libc_init 96*6dbdd20aSAndroid Build Coastguard Worker // | 97*6dbdd20aSAndroid Build Coastguard Worker // [root_] 98*6dbdd20aSAndroid Build Coastguard Worker class GlobalCallstackTrie { 99*6dbdd20aSAndroid Build Coastguard Worker public: 100*6dbdd20aSAndroid Build Coastguard Worker // Optionally, Nodes can be externally refcounted via |IncrementNode| and 101*6dbdd20aSAndroid Build Coastguard Worker // |DecrementNode|. In which case, the orphaned nodes are deleted when the 102*6dbdd20aSAndroid Build Coastguard Worker // last reference is decremented. 103*6dbdd20aSAndroid Build Coastguard Worker class Node { 104*6dbdd20aSAndroid Build Coastguard Worker public: 105*6dbdd20aSAndroid Build Coastguard Worker // This is opaque except to GlobalCallstackTrie. 106*6dbdd20aSAndroid Build Coastguard Worker friend class GlobalCallstackTrie; 107*6dbdd20aSAndroid Build Coastguard Worker 108*6dbdd20aSAndroid Build Coastguard Worker // Allow building a node out of a frame for GetChild. Node(Interned<Frame> frame)109*6dbdd20aSAndroid Build Coastguard Worker explicit Node(Interned<Frame> frame) : Node(frame, 0, nullptr) {} 110*6dbdd20aSAndroid Build Coastguard Worker Node(const Node&) = default; 111*6dbdd20aSAndroid Build Coastguard Worker Node(Node&&) = default; 112*6dbdd20aSAndroid Build Coastguard Worker Node(Interned<Frame> frame,uint64_t id)113*6dbdd20aSAndroid Build Coastguard Worker Node(Interned<Frame> frame, uint64_t id) 114*6dbdd20aSAndroid Build Coastguard Worker : Node(std::move(frame), id, nullptr) {} Node(Interned<Frame> frame,uint64_t id,Node * parent)115*6dbdd20aSAndroid Build Coastguard Worker Node(Interned<Frame> frame, uint64_t id, Node* parent) 116*6dbdd20aSAndroid Build Coastguard Worker : id_(id), parent_(parent), location_(frame) {} 117*6dbdd20aSAndroid Build Coastguard Worker ~Node()118*6dbdd20aSAndroid Build Coastguard Worker ~Node() { PERFETTO_DCHECK(!ref_count_); } 119*6dbdd20aSAndroid Build Coastguard Worker id()120*6dbdd20aSAndroid Build Coastguard Worker uint64_t id() const { return id_; } 121*6dbdd20aSAndroid Build Coastguard Worker 122*6dbdd20aSAndroid Build Coastguard Worker private: 123*6dbdd20aSAndroid Build Coastguard Worker Node* GetOrCreateChild(const Interned<Frame>& loc); 124*6dbdd20aSAndroid Build Coastguard Worker // Deletes all descendant nodes, regardless of |ref_count_|. DeleteChildren()125*6dbdd20aSAndroid Build Coastguard Worker void DeleteChildren() { children_.clear(); } 126*6dbdd20aSAndroid Build Coastguard Worker 127*6dbdd20aSAndroid Build Coastguard Worker uint64_t ref_count_ = 0; 128*6dbdd20aSAndroid Build Coastguard Worker uint64_t id_; 129*6dbdd20aSAndroid Build Coastguard Worker Node* const parent_; 130*6dbdd20aSAndroid Build Coastguard Worker const Interned<Frame> location_; 131*6dbdd20aSAndroid Build Coastguard Worker 132*6dbdd20aSAndroid Build Coastguard Worker class NodeComparator { 133*6dbdd20aSAndroid Build Coastguard Worker public: operator()134*6dbdd20aSAndroid Build Coastguard Worker bool operator()(const Node& one, const Node& other) const { 135*6dbdd20aSAndroid Build Coastguard Worker return one.location_ < other.location_; 136*6dbdd20aSAndroid Build Coastguard Worker } 137*6dbdd20aSAndroid Build Coastguard Worker }; 138*6dbdd20aSAndroid Build Coastguard Worker Node* AddChild(const Interned<Frame>& loc, 139*6dbdd20aSAndroid Build Coastguard Worker uint64_t next_callstack_id_, 140*6dbdd20aSAndroid Build Coastguard Worker Node* parent); 141*6dbdd20aSAndroid Build Coastguard Worker void RemoveChild(Node* node); 142*6dbdd20aSAndroid Build Coastguard Worker Node* GetChild(const Interned<Frame>& loc); 143*6dbdd20aSAndroid Build Coastguard Worker 144*6dbdd20aSAndroid Build Coastguard Worker std::set<Node, NodeComparator> children_; 145*6dbdd20aSAndroid Build Coastguard Worker }; 146*6dbdd20aSAndroid Build Coastguard Worker 147*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie() = default; 148*6dbdd20aSAndroid Build Coastguard Worker ~GlobalCallstackTrie() = default; 149*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie(const GlobalCallstackTrie&) = delete; 150*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie& operator=(const GlobalCallstackTrie&) = delete; 151*6dbdd20aSAndroid Build Coastguard Worker 152*6dbdd20aSAndroid Build Coastguard Worker // Moving this would invalidate the back pointers to the root_ node. 153*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie(GlobalCallstackTrie&&) = delete; 154*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie& operator=(GlobalCallstackTrie&&) = delete; 155*6dbdd20aSAndroid Build Coastguard Worker 156*6dbdd20aSAndroid Build Coastguard Worker Interned<Frame> InternCodeLocation(const unwindstack::FrameData& loc, 157*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id); 158*6dbdd20aSAndroid Build Coastguard Worker 159*6dbdd20aSAndroid Build Coastguard Worker Node* CreateCallsite(const std::vector<unwindstack::FrameData>& callstack, 160*6dbdd20aSAndroid Build Coastguard Worker const std::vector<std::string>& build_ids); 161*6dbdd20aSAndroid Build Coastguard Worker Node* CreateCallsite(const std::vector<Interned<Frame>>& callstack); 162*6dbdd20aSAndroid Build Coastguard Worker 163*6dbdd20aSAndroid Build Coastguard Worker static void IncrementNode(Node* node); 164*6dbdd20aSAndroid Build Coastguard Worker static void DecrementNode(Node* node); 165*6dbdd20aSAndroid Build Coastguard Worker 166*6dbdd20aSAndroid Build Coastguard Worker std::vector<Interned<Frame>> BuildInverseCallstack(const Node* node) const; 167*6dbdd20aSAndroid Build Coastguard Worker 168*6dbdd20aSAndroid Build Coastguard Worker // Purges all interned callstacks (and the associated internings), without 169*6dbdd20aSAndroid Build Coastguard Worker // restarting any interning sequences. Incompatible with external refcounting 170*6dbdd20aSAndroid Build Coastguard Worker // of nodes (Node.ref_count_). ClearTrie()171*6dbdd20aSAndroid Build Coastguard Worker void ClearTrie() { 172*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("Clearing trie"); 173*6dbdd20aSAndroid Build Coastguard Worker root_.DeleteChildren(); 174*6dbdd20aSAndroid Build Coastguard Worker } 175*6dbdd20aSAndroid Build Coastguard Worker 176*6dbdd20aSAndroid Build Coastguard Worker private: 177*6dbdd20aSAndroid Build Coastguard Worker Node* GetOrCreateChild(Node* self, const Interned<Frame>& loc); 178*6dbdd20aSAndroid Build Coastguard Worker 179*6dbdd20aSAndroid Build Coastguard Worker Interned<Frame> MakeRootFrame(); 180*6dbdd20aSAndroid Build Coastguard Worker 181*6dbdd20aSAndroid Build Coastguard Worker Interner<std::string> string_interner_; 182*6dbdd20aSAndroid Build Coastguard Worker Interner<Mapping> mapping_interner_; 183*6dbdd20aSAndroid Build Coastguard Worker Interner<Frame> frame_interner_; 184*6dbdd20aSAndroid Build Coastguard Worker 185*6dbdd20aSAndroid Build Coastguard Worker uint64_t next_callstack_id_ = 0; 186*6dbdd20aSAndroid Build Coastguard Worker 187*6dbdd20aSAndroid Build Coastguard Worker // Note: profile_module in trace processor relies on the value of this root 188*6dbdd20aSAndroid Build Coastguard Worker // callsite being exactly "1". See the perf_sample parsing code. 189*6dbdd20aSAndroid Build Coastguard Worker Node root_{MakeRootFrame(), ++next_callstack_id_}; 190*6dbdd20aSAndroid Build Coastguard Worker }; 191*6dbdd20aSAndroid Build Coastguard Worker 192*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling 193*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto 194*6dbdd20aSAndroid Build Coastguard Worker 195*6dbdd20aSAndroid Build Coastguard Worker template <> 196*6dbdd20aSAndroid Build Coastguard Worker struct std::hash<::perfetto::profiling::Mapping> { 197*6dbdd20aSAndroid Build Coastguard Worker using argument_type = ::perfetto::profiling::Mapping; 198*6dbdd20aSAndroid Build Coastguard Worker using result_type = size_t; 199*6dbdd20aSAndroid Build Coastguard Worker result_type operator()(const argument_type& mapping) { 200*6dbdd20aSAndroid Build Coastguard Worker size_t h = 201*6dbdd20aSAndroid Build Coastguard Worker std::hash<::perfetto::profiling::InternID>{}(mapping.build_id.id()); 202*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(mapping.exact_offset); 203*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(mapping.start_offset); 204*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(mapping.start); 205*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(mapping.end); 206*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(mapping.load_bias); 207*6dbdd20aSAndroid Build Coastguard Worker for (const auto& path : mapping.path_components) 208*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(path.id()); 209*6dbdd20aSAndroid Build Coastguard Worker return h; 210*6dbdd20aSAndroid Build Coastguard Worker } 211*6dbdd20aSAndroid Build Coastguard Worker }; 212*6dbdd20aSAndroid Build Coastguard Worker 213*6dbdd20aSAndroid Build Coastguard Worker template <> 214*6dbdd20aSAndroid Build Coastguard Worker struct std::hash<::perfetto::profiling::Frame> { 215*6dbdd20aSAndroid Build Coastguard Worker using argument_type = ::perfetto::profiling::Frame; 216*6dbdd20aSAndroid Build Coastguard Worker using result_type = size_t; 217*6dbdd20aSAndroid Build Coastguard Worker result_type operator()(const argument_type& frame) { 218*6dbdd20aSAndroid Build Coastguard Worker size_t h = std::hash<::perfetto::profiling::InternID>{}(frame.mapping.id()); 219*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<::perfetto::profiling::InternID>{}(frame.function_name.id()); 220*6dbdd20aSAndroid Build Coastguard Worker h ^= std::hash<uint64_t>{}(frame.rel_pc); 221*6dbdd20aSAndroid Build Coastguard Worker return h; 222*6dbdd20aSAndroid Build Coastguard Worker } 223*6dbdd20aSAndroid Build Coastguard Worker }; 224*6dbdd20aSAndroid Build Coastguard Worker 225*6dbdd20aSAndroid Build Coastguard Worker #endif // SRC_PROFILING_COMMON_CALLSTACK_TRIE_H_ 226