147
|
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
|
|
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
|
|
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;
|
|
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
|