LLVM: lib/XRay/Profile.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
14
19#include
20
21using namespace llvm;
23
25
26
27 for (const auto &Block : O) {
29 auto &B = Blocks.back();
32 PathData.second});
33 }
34}
35
38 *this = std::move(P);
39 return *this;
40}
41
42namespace {
43
44struct BlockHeader {
48};
49}
50
53 BlockHeader H;
55 H.Size = Extractor.getU32(&Offset);
56 if (Offset == CurrentOffset)
58 Twine("Error parsing block header size at offset '") +
59 Twine(CurrentOffset) + "'",
60 std::make_error_code(std::errc::invalid_argument));
61 CurrentOffset = Offset;
62 H.Number = Extractor.getU32(&Offset);
63 if (Offset == CurrentOffset)
65 Twine("Error parsing block header number at offset '") +
66 Twine(CurrentOffset) + "'",
67 std::make_error_code(std::errc::invalid_argument));
68 CurrentOffset = Offset;
69 H.Thread = Extractor.getU64(&Offset);
70 if (Offset == CurrentOffset)
72 Twine("Error parsing block header thread id at offset '") +
73 Twine(CurrentOffset) + "'",
74 std::make_error_code(std::errc::invalid_argument));
75 return H;
76}
77
80
81 std::vectorProfile::FuncID Path;
82 auto CurrentOffset = Offset;
83 int32_t FuncId;
84 do {
85 FuncId = Extractor.getSigned(&Offset, 4);
86 if (CurrentOffset == Offset)
88 Twine("Error parsing path at offset '") + Twine(CurrentOffset) + "'",
89 std::make_error_code(std::errc::invalid_argument));
90 CurrentOffset = Offset;
91 Path.push_back(FuncId);
92 } while (FuncId != 0);
93 return std::move(Path);
94}
95
98
99
100
102 auto CurrentOffset = Offset;
103 D.CallCount = Extractor.getU64(&Offset);
104 if (CurrentOffset == Offset)
106 Twine("Error parsing call counts at offset '") + Twine(CurrentOffset) +
107 "'",
108 std::make_error_code(std::errc::invalid_argument));
109 CurrentOffset = Offset;
110 D.CumulativeLocalTime = Extractor.getU64(&Offset);
111 if (CurrentOffset == Offset)
113 Twine("Error parsing cumulative local time at offset '") +
114 Twine(CurrentOffset) + "'",
115 std::make_error_code(std::errc::invalid_argument));
116 return D;
117}
118
120 if (B.PathData.empty())
122 "Block may not have empty path data.",
123 std::make_error_code(std::errc::invalid_argument));
124
125 Blocks.emplace_back(std::move(B));
127}
128
130 auto It = PathIDMap.find(P);
131 if (It == PathIDMap.end())
134 std::make_error_code(std::errc::invalid_argument));
135 std::vectorProfile::FuncID Path;
137 Path.push_back(Node->Func);
138 return std::move(Path);
139}
140
142 if (P.empty())
143 return 0;
144
145 auto RootToLeafPath = reverse(P);
146
147
148 auto It = RootToLeafPath.begin();
149 auto PathRoot = *It++;
150 auto RootIt =
151 find_if(Roots, [PathRoot](TrieNode *N) { return N->Func == PathRoot; });
152
153
154 TrieNode *Node = nullptr;
155 if (RootIt == Roots.end()) {
156 NodeStorage.emplace_back();
157 Node = &NodeStorage.back();
158 Node->Func = PathRoot;
159 Roots.push_back(Node);
160 } else {
161 Node = *RootIt;
162 }
163
164
165 while (It != RootToLeafPath.end()) {
166 auto NodeFuncID = *It++;
167 auto CalleeIt = find_if(Node->Callees, [NodeFuncID](TrieNode *N) {
168 return N->Func == NodeFuncID;
169 });
170 if (CalleeIt == Node->Callees.end()) {
171 NodeStorage.emplace_back();
172 auto NewNode = &NodeStorage.back();
173 NewNode->Func = NodeFuncID;
174 NewNode->Caller = Node;
175 Node->Callees.push_back(NewNode);
176 Node = NewNode;
177 } else {
178 Node = *CalleeIt;
179 }
180 }
181
182
184 if (Node->ID == 0) {
185 Node->ID = NextID++;
186 PathIDMap.insert({Node->ID, Node});
187 }
188 return Node->ID;
189}
190
194 using PathDataMapPtr = std::unique_ptr;
197 ThreadProfileIndexMap ThreadProfileIndex;
198
199 for (const auto &P : {std::ref(L), std::ref(R)})
200 for (const auto &Block : P.get()) {
201 ThreadProfileIndexMap::iterator It;
202 std::tie(It, std::ignore) = ThreadProfileIndex.insert(
203 {Block.Thread, std::make_unique()});
204 for (const auto &PathAndData : Block.PathData) {
205 auto &PathID = PathAndData.first;
206 auto &Data = PathAndData.second;
207 auto NewPathID =
209 PathDataMap::iterator PathDataIt;
210 bool Inserted;
211 std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID, Data});
212 if (!Inserted) {
213 auto &ExistingData = PathDataIt->second;
214 ExistingData.CallCount += Data.CallCount;
215 ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
216 }
217 }
218 }
219
220 for (const auto &IndexedThreadBlock : ThreadProfileIndex) {
221 PathDataVector PathAndData;
222 PathAndData.reserve(IndexedThreadBlock.second->size());
223 copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));
225 Merged.addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));
226 }
227 return Merged;
228}
229
233 PathDataMap PathData;
235 for (const auto &P : {std::ref(L), std::ref(R)})
236 for (const auto &Block : P.get())
237 for (const auto &PathAndData : Block.PathData) {
238 auto &PathId = PathAndData.first;
239 auto &Data = PathAndData.second;
240 auto NewPathID =
242 PathDataMap::iterator PathDataIt;
243 bool Inserted;
244 std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID, Data});
245 if (!Inserted) {
246 auto &ExistingData = PathDataIt->second;
247 ExistingData.CallCount += Data.CallCount;
248 ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
249 }
250 }
251
252
253 PathDataVector Block;
254 Block.reserve(PathData.size());
255 copy(PathData, std::back_inserter(Block));
257 return Merged;
258}
259
262 if (!FdOrErr)
264
268 Twine("Cannot get filesize of '") + Filename + "'", EC);
269
270 std::error_code EC;
273 EC);
275 if (EC)
277 Twine("Cannot mmap profile '") + Filename + "'", EC);
279
283
284
285 while (Offset != MappedFile.size()) {
287 if (!HeaderOrError)
288 return HeaderOrError.takeError();
289
290
291
292 const auto &Header = HeaderOrError.get();
293
294
296 if (!PathOrError)
297 return PathOrError.takeError();
298 const auto &Path = PathOrError.get();
299
300
302 if (!DataOrError)
303 return DataOrError.takeError();
304 auto &Data = DataOrError.get();
305
306 if (auto E =
307 P.addBlock(Profile::Block{Profile::ThreadID{Header.Thread},
308 {{P.internPath(Path), std::move(Data)}}}))
309 return std::move(E);
310 }
311
312 return P;
313}
314
315namespace {
316
317struct StackEntry {
318 uint64_t Timestamp;
319 Profile::FuncID FuncId;
320};
321
322}
323
326
327
328
329
330
333 ThreadPathData;
334
335
336 for (const auto &E : T) {
337 auto &TSD = ThreadStacks[E.TId];
338 switch (E.Type) {
341
342
343 TSD.push_back({E.TSC, E.FuncId});
344 break;
345
348
349
350
351
352
353 while (!TSD.empty()) {
354 auto Top = TSD.back();
358 std::mem_fn(&StackEntry::FuncId));
359 auto InternedPath = P.internPath(Path);
360 auto &TPD = ThreadPathData[E.TId][InternedPath];
361 ++TPD.CallCount;
362 TPD.CumulativeLocalTime += FunctionLocalTime;
363 TSD.pop_back();
364
365
366
367 if (Top.FuncId == E.FuncId)
368 break;
369
370
371
372 }
373
374 break;
375
378
379
380 break;
381 }
382 }
383
384
385
386 for (const auto &ThreadPaths : ThreadPathData) {
387 const auto &TID = ThreadPaths.first;
388 const auto &PathsData = ThreadPaths.second;
389 if (auto E = P.addBlock({
390 TID,
391 std::vector<std::pair<Profile::PathID, Profile::Data>>(
392 PathsData.begin(), PathsData.end()),
393 }))
394 return std::move(E);
395 }
396
397 return P;
398}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static Expected< BlockHeader > readBlockHeader(DataExtractor &Extractor, uint64_t &Offset)
Definition Profile.cpp:51
static Expected< Profile::Data > readData(DataExtractor &Extractor, uint64_t &Offset)
Definition Profile.cpp:96
static Expected< std::vector< Profile::FuncID > > readPath(DataExtractor &Extractor, uint64_t &Offset)
Definition Profile.cpp:78
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class represents a memory mapped file.
LLVM_ABI size_t size() const
@ readonly
May only access map via const_data as read only.
LLVM_ABI char * data() const
Profile instances are thread-compatible.
Profile & operator=(Profile &&O) noexcept
LLVM_ABI PathID internPath(ArrayRef< FuncID > P)
The stack represented in |P| must be in stack order (leaf to root).
Definition Profile.cpp:141
LLVM_ABI Expected< std::vector< FuncID > > expandPath(PathID P) const
Provides a sequence of function IDs from a previously interned PathID.
Definition Profile.cpp:129
LLVM_ABI Error addBlock(Block &&B)
Appends a fully-formed Block instance into the Profile.
Definition Profile.cpp:119
A Trace object represents the records that have been loaded from XRay log files generated by instrume...
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
LLVM_ABI Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code file_size(const Twine &Path, uint64_t &Result)
Get file size.
LLVM_ABI Profile mergeProfilesByStack(const Profile &L, const Profile &R)
This algorithm will merge two Profile instances into a single Profile instance, aggregating blocks by...
Definition Profile.cpp:230
LLVM_ABI Expected< Profile > profileFromTrace(const Trace &T)
This function takes a Trace and creates a Profile instance from it.
Definition Profile.cpp:324
LLVM_ABI Expected< Profile > loadProfile(StringRef Filename)
This function will attempt to load an XRay Profiling Mode profile from the provided |Filename|.
Definition Profile.cpp:260
LLVM_ABI Profile mergeProfilesByThread(const Profile &L, const Profile &R)
This algorithm will merge two Profile instances into a single Profile instance, aggregating blocks by...
Definition Profile.cpp:191
This is an optimization pass for GlobalISel generic memory operations.
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
auto reverse(ContainerTy &&C)
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
constexpr T AbsoluteDifference(U X, V Y)
Subtract two unsigned integers, X and Y, of type T and return the absolute value of the result.
OutputIt copy(R &&Range, OutputIt Out)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
std::vector< std::pair< PathID, Data > > PathData