1 //===- trie-node.h - XRay Call Stack Data Structure -----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides a data structure and routines for working with call stacks 11 // of instrumented functions. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H 16 #define LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H 17 18 #include <forward_list> 19 #include <numeric> 20 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/STLExtras.h" 23 #include "llvm/ADT/SmallVector.h" 24 25 /// A type to represent a trie of invocations. It is useful to construct a 26 /// graph of these nodes from reading an XRay trace, such that each function 27 /// call can be placed in a larger context. 28 /// 29 /// The template parameter allows users of the template to attach their own 30 /// data elements to each node in the invocation graph. 31 template <typename AssociatedData> struct TrieNode { 32 /// The function ID. 33 int32_t FuncId; 34 35 /// The caller of this function. 36 TrieNode<AssociatedData> *Parent; 37 38 /// The callees from this function. 39 llvm::SmallVector<TrieNode<AssociatedData> *, 4> Callees; 40 41 /// Additional parameterized data on each node. 42 AssociatedData ExtraData; 43 }; 44 45 /// Merges together two TrieNodes with like function ids, aggregating their 46 /// callee lists and durations. The caller must provide storage where new merged 47 /// nodes can be allocated in the form of a linked list. 48 template <typename T, typename Callable> 49 TrieNode<T> * 50 mergeTrieNodes(const TrieNode<T> &Left, const TrieNode<T> &Right, 51 /*Non-deduced pointer type for nullptr compatibility*/ 52 typename std::remove_reference<TrieNode<T> *>::type NewParent, 53 std::forward_list<TrieNode<T>> &NodeStore, 54 Callable &&MergeCallable) { 55 llvm::function_ref<T(const T &, const T &)> MergeFn( 56 std::forward<Callable>(MergeCallable)); 57 assert(Left.FuncId == Right.FuncId); 58 NodeStore.push_front(TrieNode<T>{ 59 Left.FuncId, NewParent, {}, MergeFn(Left.ExtraData, Right.ExtraData)}); 60 auto I = NodeStore.begin(); 61 auto *Node = &*I; 62 63 // Build a map of callees from the left side. 64 llvm::DenseMap<int32_t, TrieNode<T> *> LeftCalleesByFuncId; 65 for (auto *Callee : Left.Callees) { 66 LeftCalleesByFuncId[Callee->FuncId] = Callee; 67 } 68 69 // Iterate through the right side, either merging with the map values or 70 // directly adding to the Callees vector. The iteration also removes any 71 // merged values from the left side map. 72 // TODO: Unroll into iterative and explicit stack for efficiency. 73 for (auto *Callee : Right.Callees) { 74 auto iter = LeftCalleesByFuncId.find(Callee->FuncId); 75 if (iter != LeftCalleesByFuncId.end()) { 76 Node->Callees.push_back( 77 mergeTrieNodes(*(iter->second), *Callee, Node, NodeStore, MergeFn)); 78 LeftCalleesByFuncId.erase(iter); 79 } else { 80 Node->Callees.push_back(Callee); 81 } 82 } 83 84 // Add any callees that weren't found in the right side. 85 for (auto MapPairIter : LeftCalleesByFuncId) { 86 Node->Callees.push_back(MapPairIter.second); 87 } 88 89 return Node; 90 } 91 92 #endif // LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H 93