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