1 //===- Profile.h - XRay Profile Abstraction -------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Defines the XRay Profile class representing the latency profile generated by 10 // XRay's profiling mode. 11 // 12 //===----------------------------------------------------------------------===// 13 #ifndef LLVM_XRAY_PROFILE_H 14 #define LLVM_XRAY_PROFILE_H 15 16 #include "llvm/ADT/DenseMap.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/Support/Compiler.h" 20 #include "llvm/Support/Error.h" 21 #include <list> 22 #include <utility> 23 #include <vector> 24 25 namespace llvm { 26 namespace xray { 27 28 class Profile; 29 30 // We forward declare the Trace type for turning a Trace into a Profile. 31 class Trace; 32 33 /// This function will attempt to load an XRay Profiling Mode profile from the 34 /// provided |Filename|. 35 /// 36 /// For any errors encountered in the loading of the profile data from 37 /// |Filename|, this function will return an Error condition appropriately. 38 LLVM_ABI Expected<Profile> loadProfile(StringRef Filename); 39 40 /// This algorithm will merge two Profile instances into a single Profile 41 /// instance, aggregating blocks by Thread ID. 42 LLVM_ABI Profile mergeProfilesByThread(const Profile &L, const Profile &R); 43 44 /// This algorithm will merge two Profile instances into a single Profile 45 /// instance, aggregating blocks by function call stack. 46 LLVM_ABI Profile mergeProfilesByStack(const Profile &L, const Profile &R); 47 48 /// This function takes a Trace and creates a Profile instance from it. 49 LLVM_ABI Expected<Profile> profileFromTrace(const Trace &T); 50 51 /// Profile instances are thread-compatible. 52 class Profile { 53 public: 54 using ThreadID = uint64_t; 55 using PathID = unsigned; 56 using FuncID = int32_t; 57 58 struct Data { 59 uint64_t CallCount; 60 uint64_t CumulativeLocalTime; 61 }; 62 63 struct Block { 64 ThreadID Thread; 65 std::vector<std::pair<PathID, Data>> PathData; 66 }; 67 68 /// Provides a sequence of function IDs from a previously interned PathID. 69 /// 70 /// Returns an error if |P| had not been interned before into the Profile. 71 /// 72 LLVM_ABI Expected<std::vector<FuncID>> expandPath(PathID P) const; 73 74 /// The stack represented in |P| must be in stack order (leaf to root). This 75 /// will always return the same PathID for |P| that has the same sequence. 76 LLVM_ABI PathID internPath(ArrayRef<FuncID> P); 77 78 /// Appends a fully-formed Block instance into the Profile. 79 /// 80 /// Returns an error condition in the following cases: 81 /// 82 /// - The PathData component of the Block is empty 83 /// 84 LLVM_ABI Error addBlock(Block &&B); 85 86 Profile() = default; 87 ~Profile() = default; 88 Profile(Profile && O)89 Profile(Profile &&O) noexcept 90 : Blocks(std::move(O.Blocks)), NodeStorage(std::move(O.NodeStorage)), 91 Roots(std::move(O.Roots)), PathIDMap(std::move(O.PathIDMap)), 92 NextID(O.NextID) {} 93 94 Profile &operator=(Profile &&O) noexcept { 95 Blocks = std::move(O.Blocks); 96 NodeStorage = std::move(O.NodeStorage); 97 Roots = std::move(O.Roots); 98 PathIDMap = std::move(O.PathIDMap); 99 NextID = O.NextID; 100 return *this; 101 } 102 103 LLVM_ABI Profile(const Profile &); 104 LLVM_ABI Profile &operator=(const Profile &); 105 swap(Profile & L,Profile & R)106 friend void swap(Profile &L, Profile &R) { 107 using std::swap; 108 swap(L.Blocks, R.Blocks); 109 swap(L.NodeStorage, R.NodeStorage); 110 swap(L.Roots, R.Roots); 111 swap(L.PathIDMap, R.PathIDMap); 112 swap(L.NextID, R.NextID); 113 } 114 115 private: 116 using BlockList = std::list<Block>; 117 118 struct TrieNode { 119 FuncID Func = 0; 120 std::vector<TrieNode *> Callees{}; 121 TrieNode *Caller = nullptr; 122 PathID ID = 0; 123 }; 124 125 // List of blocks associated with a Profile. 126 BlockList Blocks; 127 128 // List of TrieNode elements we've seen. 129 std::list<TrieNode> NodeStorage; 130 131 // List of call stack roots. 132 SmallVector<TrieNode *, 4> Roots; 133 134 // Reverse mapping between a PathID to a TrieNode*. 135 DenseMap<PathID, TrieNode *> PathIDMap; 136 137 // Used to identify paths. 138 PathID NextID = 1; 139 140 public: 141 using const_iterator = BlockList::const_iterator; begin()142 const_iterator begin() const { return Blocks.begin(); } end()143 const_iterator end() const { return Blocks.end(); } empty()144 bool empty() const { return Blocks.empty(); } 145 }; 146 147 } // namespace xray 148 } // namespace llvm 149 150 #endif 151