//===- Profile.h - XRay Profile Abstraction -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Defines the XRay Profile class representing the latency profile generated by // XRay's profiling mode. // //===----------------------------------------------------------------------===// #ifndef LLVM_XRAY_PROFILE_H #define LLVM_XRAY_PROFILE_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include #include #include namespace llvm { namespace xray { class Profile; // We forward declare the Trace type for turning a Trace into a Profile. class Trace; /// This function will attempt to load an XRay Profiling Mode profile from the /// provided |Filename|. /// /// For any errors encountered in the loading of the profile data from /// |Filename|, this function will return an Error condition appropriately. Expected loadProfile(StringRef Filename); /// This algorithm will merge two Profile instances into a single Profile /// instance, aggregating blocks by Thread ID. Profile mergeProfilesByThread(const Profile &L, const Profile &R); /// This algorithm will merge two Profile instances into a single Profile /// instance, aggregating blocks by function call stack. Profile mergeProfilesByStack(const Profile &L, const Profile &R); /// This function takes a Trace and creates a Profile instance from it. Expected profileFromTrace(const Trace &T); /// Profile instances are thread-compatible. class Profile { public: using ThreadID = uint64_t; using PathID = unsigned; using FuncID = int32_t; struct Data { uint64_t CallCount; uint64_t CumulativeLocalTime; }; struct Block { ThreadID Thread; std::vector> PathData; }; /// Provides a sequence of function IDs from a previously interned PathID. /// /// Returns an error if |P| had not been interned before into the Profile. /// Expected> expandPath(PathID P) const; /// The stack represented in |P| must be in stack order (leaf to root). This /// will always return the same PathID for |P| that has the same sequence. PathID internPath(ArrayRef P); /// Appends a fully-formed Block instance into the Profile. /// /// Returns an error condition in the following cases: /// /// - The PathData component of the Block is empty /// Error addBlock(Block &&B); Profile() = default; ~Profile() = default; Profile(Profile &&O) noexcept : Blocks(std::move(O.Blocks)), NodeStorage(std::move(O.NodeStorage)), Roots(std::move(O.Roots)), PathIDMap(std::move(O.PathIDMap)), NextID(O.NextID) {} Profile &operator=(Profile &&O) noexcept { Blocks = std::move(O.Blocks); NodeStorage = std::move(O.NodeStorage); Roots = std::move(O.Roots); PathIDMap = std::move(O.PathIDMap); NextID = O.NextID; return *this; } Profile(const Profile &); Profile &operator=(const Profile &); friend void swap(Profile &L, Profile &R) { using std::swap; swap(L.Blocks, R.Blocks); swap(L.NodeStorage, R.NodeStorage); swap(L.Roots, R.Roots); swap(L.PathIDMap, R.PathIDMap); swap(L.NextID, R.NextID); } private: using BlockList = std::list; struct TrieNode { FuncID Func = 0; std::vector Callees{}; TrieNode *Caller = nullptr; PathID ID = 0; }; // List of blocks associated with a Profile. BlockList Blocks; // List of TrieNode elements we've seen. std::list NodeStorage; // List of call stack roots. SmallVector Roots; // Reverse mapping between a PathID to a TrieNode*. DenseMap PathIDMap; // Used to identify paths. PathID NextID = 1; public: using const_iterator = BlockList::const_iterator; const_iterator begin() const { return Blocks.begin(); } const_iterator end() const { return Blocks.end(); } bool empty() const { return Blocks.empty(); } }; } // namespace xray } // namespace llvm #endif