Profile.h revision 353358
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 24namespace llvm { 25namespace xray { 26 27class Profile; 28 29// We forward declare the Trace type for turning a Trace into a Profile. 30class 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. 37Expected<Profile> loadProfile(StringRef Filename); 38 39/// This algorithm will merge two Profile instances into a single Profile 40/// instance, aggregating blocks by Thread ID. 41Profile 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. 45Profile mergeProfilesByStack(const Profile &L, const Profile &R); 46 47/// This function takes a Trace and creates a Profile instance from it. 48Expected<Profile> profileFromTrace(const Trace &T); 49 50/// Profile instances are thread-compatible. 51class Profile { 52public: 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 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 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 114private: 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 139public: 140 using const_iterator = BlockList::const_iterator; 141 const_iterator begin() const { return Blocks.begin(); } 142 const_iterator end() const { return Blocks.end(); } 143 bool empty() const { return Blocks.empty(); } 144}; 145 146} // namespace xray 147} // namespace llvm 148 149#endif 150