Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:46

0001 //===- Profile.h - XRay Profile Abstraction -------------------------------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Defines the XRay Profile class representing the latency profile generated by
0010 // XRay's profiling mode.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 #ifndef LLVM_XRAY_PROFILE_H
0014 #define LLVM_XRAY_PROFILE_H
0015 
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/SmallVector.h"
0018 #include "llvm/ADT/StringRef.h"
0019 #include "llvm/Support/Error.h"
0020 #include <list>
0021 #include <utility>
0022 #include <vector>
0023 
0024 namespace llvm {
0025 namespace xray {
0026 
0027 class Profile;
0028 
0029 // We forward declare the Trace type for turning a Trace into a Profile.
0030 class Trace;
0031 
0032 /// This function will attempt to load an XRay Profiling Mode profile from the
0033 /// provided |Filename|.
0034 ///
0035 /// For any errors encountered in the loading of the profile data from
0036 /// |Filename|, this function will return an Error condition appropriately.
0037 Expected<Profile> loadProfile(StringRef Filename);
0038 
0039 /// This algorithm will merge two Profile instances into a single Profile
0040 /// instance, aggregating blocks by Thread ID.
0041 Profile mergeProfilesByThread(const Profile &L, const Profile &R);
0042 
0043 /// This algorithm will merge two Profile instances into a single Profile
0044 /// instance, aggregating blocks by function call stack.
0045 Profile mergeProfilesByStack(const Profile &L, const Profile &R);
0046 
0047 /// This function takes a Trace and creates a Profile instance from it.
0048 Expected<Profile> profileFromTrace(const Trace &T);
0049 
0050 /// Profile instances are thread-compatible.
0051 class Profile {
0052 public:
0053   using ThreadID = uint64_t;
0054   using PathID = unsigned;
0055   using FuncID = int32_t;
0056 
0057   struct Data {
0058     uint64_t CallCount;
0059     uint64_t CumulativeLocalTime;
0060   };
0061 
0062   struct Block {
0063     ThreadID Thread;
0064     std::vector<std::pair<PathID, Data>> PathData;
0065   };
0066 
0067   /// Provides a sequence of function IDs from a previously interned PathID.
0068   ///
0069   /// Returns an error if |P| had not been interned before into the Profile.
0070   ///
0071   Expected<std::vector<FuncID>> expandPath(PathID P) const;
0072 
0073   /// The stack represented in |P| must be in stack order (leaf to root). This
0074   /// will always return the same PathID for |P| that has the same sequence.
0075   PathID internPath(ArrayRef<FuncID> P);
0076 
0077   /// Appends a fully-formed Block instance into the Profile.
0078   ///
0079   /// Returns an error condition in the following cases:
0080   ///
0081   ///    - The PathData component of the Block is empty
0082   ///
0083   Error addBlock(Block &&B);
0084 
0085   Profile() = default;
0086   ~Profile() = default;
0087 
0088   Profile(Profile &&O) noexcept
0089       : Blocks(std::move(O.Blocks)), NodeStorage(std::move(O.NodeStorage)),
0090         Roots(std::move(O.Roots)), PathIDMap(std::move(O.PathIDMap)),
0091         NextID(O.NextID) {}
0092 
0093   Profile &operator=(Profile &&O) noexcept {
0094     Blocks = std::move(O.Blocks);
0095     NodeStorage = std::move(O.NodeStorage);
0096     Roots = std::move(O.Roots);
0097     PathIDMap = std::move(O.PathIDMap);
0098     NextID = O.NextID;
0099     return *this;
0100   }
0101 
0102   Profile(const Profile &);
0103   Profile &operator=(const Profile &);
0104 
0105   friend void swap(Profile &L, Profile &R) {
0106     using std::swap;
0107     swap(L.Blocks, R.Blocks);
0108     swap(L.NodeStorage, R.NodeStorage);
0109     swap(L.Roots, R.Roots);
0110     swap(L.PathIDMap, R.PathIDMap);
0111     swap(L.NextID, R.NextID);
0112   }
0113 
0114 private:
0115   using BlockList = std::list<Block>;
0116 
0117   struct TrieNode {
0118     FuncID Func = 0;
0119     std::vector<TrieNode *> Callees{};
0120     TrieNode *Caller = nullptr;
0121     PathID ID = 0;
0122   };
0123 
0124   // List of blocks associated with a Profile.
0125   BlockList Blocks;
0126 
0127   // List of TrieNode elements we've seen.
0128   std::list<TrieNode> NodeStorage;
0129 
0130   // List of call stack roots.
0131   SmallVector<TrieNode *, 4> Roots;
0132 
0133   // Reverse mapping between a PathID to a TrieNode*.
0134   DenseMap<PathID, TrieNode *> PathIDMap;
0135 
0136   // Used to identify paths.
0137   PathID NextID = 1;
0138 
0139 public:
0140   using const_iterator = BlockList::const_iterator;
0141   const_iterator begin() const { return Blocks.begin(); }
0142   const_iterator end() const { return Blocks.end(); }
0143   bool empty() const { return Blocks.empty(); }
0144 };
0145 
0146 } // namespace xray
0147 } // namespace llvm
0148 
0149 #endif