LLVM 19.0.0git
InstrProfWriter.cpp
Go to the documentation of this file.
1//===- InstrProfWriter.cpp - Instrumented profiling writer ----------------===//
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// This file contains support for writing profiling data for clang's
10// instrumentation based PGO and coverage.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/SetVector.h"
17#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Endian.h"
25#include "llvm/Support/Error.h"
30#include <cstdint>
31#include <memory>
32#include <string>
33#include <tuple>
34#include <utility>
35#include <vector>
36
37using namespace llvm;
38
39// A struct to define how the data stream should be patched. For Indexed
40// profiling, only uint64_t data type is needed.
41struct PatchItem {
42 uint64_t Pos; // Where to patch.
43 uint64_t *D; // Pointer to an array of source data.
44 int N; // Number of elements in \c D array.
45};
46
47namespace llvm {
48
49// A wrapper class to abstract writer stream with support of bytes
50// back patching.
52public:
54 : IsFDOStream(true), OS(FD), LE(FD, llvm::endianness::little) {}
56 : IsFDOStream(false), OS(STR), LE(STR, llvm::endianness::little) {}
57
58 [[nodiscard]] uint64_t tell() const { return OS.tell(); }
59 void write(uint64_t V) { LE.write<uint64_t>(V); }
60 void write32(uint32_t V) { LE.write<uint32_t>(V); }
61 void writeByte(uint8_t V) { LE.write<uint8_t>(V); }
62
63 // \c patch can only be called when all data is written and flushed.
64 // For raw_string_ostream, the patch is done on the target string
65 // directly and it won't be reflected in the stream's internal buffer.
67 using namespace support;
68
69 if (IsFDOStream) {
70 raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
71 const uint64_t LastPos = FDOStream.tell();
72 for (const auto &K : P) {
73 FDOStream.seek(K.Pos);
74 for (int I = 0; I < K.N; I++)
75 write(K.D[I]);
76 }
77 // Reset the stream to the last position after patching so that users
78 // don't accidentally overwrite data. This makes it consistent with
79 // the string stream below which replaces the data directly.
80 FDOStream.seek(LastPos);
81 } else {
82 raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
83 std::string &Data = SOStream.str(); // with flush
84 for (const auto &K : P) {
85 for (int I = 0; I < K.N; I++) {
86 uint64_t Bytes =
87 endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
88 Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),
89 (const char *)&Bytes, sizeof(uint64_t));
90 }
91 }
92 }
93 }
94
95 // If \c OS is an instance of \c raw_fd_ostream, this field will be
96 // true. Otherwise, \c OS will be an raw_string_ostream.
100};
101
103public:
106
109
112
116
118
121 }
122
123 static std::pair<offset_type, offset_type>
125 using namespace support;
126
128
129 offset_type N = K.size();
130 LE.write<offset_type>(N);
131
132 offset_type M = 0;
133 for (const auto &ProfileData : *V) {
134 const InstrProfRecord &ProfRecord = ProfileData.second;
135 M += sizeof(uint64_t); // The function hash
136 M += sizeof(uint64_t); // The size of the Counts vector
137 M += ProfRecord.Counts.size() * sizeof(uint64_t);
138 M += sizeof(uint64_t); // The size of the Bitmap vector
139 M += ProfRecord.BitmapBytes.size() * sizeof(uint64_t);
140
141 // Value data
142 M += ValueProfData::getSize(ProfileData.second);
143 }
144 LE.write<offset_type>(M);
145
146 return std::make_pair(N, M);
147 }
148
150 Out.write(K.data(), N);
151 }
152
154 using namespace support;
155
157 for (const auto &ProfileData : *V) {
158 const InstrProfRecord &ProfRecord = ProfileData.second;
159 if (NamedInstrProfRecord::hasCSFlagInHash(ProfileData.first))
160 CSSummaryBuilder->addRecord(ProfRecord);
161 else
162 SummaryBuilder->addRecord(ProfRecord);
163
164 LE.write<uint64_t>(ProfileData.first); // Function hash
165 LE.write<uint64_t>(ProfRecord.Counts.size());
166 for (uint64_t I : ProfRecord.Counts)
167 LE.write<uint64_t>(I);
168
169 LE.write<uint64_t>(ProfRecord.BitmapBytes.size());
170 for (uint64_t I : ProfRecord.BitmapBytes)
171 LE.write<uint64_t>(I);
172
173 // Write value data
174 std::unique_ptr<ValueProfData> VDataPtr =
175 ValueProfData::serializeFrom(ProfileData.second);
176 uint32_t S = VDataPtr->getSize();
177 VDataPtr->swapBytesFromHost(ValueProfDataEndianness);
178 Out.write((const char *)VDataPtr.get(), S);
179 }
180 }
181};
182
183} // end namespace llvm
184
186 bool Sparse, uint64_t TemporalProfTraceReservoirSize,
187 uint64_t MaxTemporalProfTraceLength, bool WritePrevVersion,
188 memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema)
189 : Sparse(Sparse), MaxTemporalProfTraceLength(MaxTemporalProfTraceLength),
190 TemporalProfTraceReservoirSize(TemporalProfTraceReservoirSize),
191 InfoObj(new InstrProfRecordWriterTrait()),
192 WritePrevVersion(WritePrevVersion),
193 MemProfVersionRequested(MemProfVersionRequested),
194 MemProfFullSchema(MemProfFullSchema) {}
195
197
198// Internal interface for testing purpose only.
200 InfoObj->ValueProfDataEndianness = Endianness;
201}
202
204 this->Sparse = Sparse;
205}
206
208 function_ref<void(Error)> Warn) {
209 auto Name = I.Name;
210 auto Hash = I.Hash;
211 addRecord(Name, Hash, std::move(I), Weight, Warn);
212}
213
215 OverlapStats &Overlap,
216 OverlapStats &FuncLevelOverlap,
217 const OverlapFuncFilters &FuncFilter) {
218 auto Name = Other.Name;
219 auto Hash = Other.Hash;
220 Other.accumulateCounts(FuncLevelOverlap.Test);
221 if (!FunctionData.contains(Name)) {
222 Overlap.addOneUnique(FuncLevelOverlap.Test);
223 return;
224 }
225 if (FuncLevelOverlap.Test.CountSum < 1.0f) {
226 Overlap.Overlap.NumEntries += 1;
227 return;
228 }
229 auto &ProfileDataMap = FunctionData[Name];
230 bool NewFunc;
232 std::tie(Where, NewFunc) =
233 ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
234 if (NewFunc) {
235 Overlap.addOneMismatch(FuncLevelOverlap.Test);
236 return;
237 }
238 InstrProfRecord &Dest = Where->second;
239
240 uint64_t ValueCutoff = FuncFilter.ValueCutoff;
241 if (!FuncFilter.NameFilter.empty() && Name.contains(FuncFilter.NameFilter))
242 ValueCutoff = 0;
243
244 Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
245}
246
248 InstrProfRecord &&I, uint64_t Weight,
249 function_ref<void(Error)> Warn) {
250 auto &ProfileDataMap = FunctionData[Name];
251
252 bool NewFunc;
254 std::tie(Where, NewFunc) =
255 ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
256 InstrProfRecord &Dest = Where->second;
257
258 auto MapWarn = [&](instrprof_error E) {
259 Warn(make_error<InstrProfError>(E));
260 };
261
262 if (NewFunc) {
263 // We've never seen a function with this name and hash, add it.
264 Dest = std::move(I);
265 if (Weight > 1)
266 Dest.scale(Weight, 1, MapWarn);
267 } else {
268 // We're updating a function we've seen before.
269 Dest.merge(I, Weight, MapWarn);
270 }
271
272 Dest.sortValueData();
273}
274
277 auto [Iter, Inserted] = MemProfData.Records.insert({Id, Record});
278 // If we inserted a new record then we are done.
279 if (Inserted) {
280 return;
281 }
282 memprof::IndexedMemProfRecord &Existing = Iter->second;
283 Existing.merge(Record);
284}
285
287 const memprof::Frame &Frame,
288 function_ref<void(Error)> Warn) {
289 auto [Iter, Inserted] = MemProfData.Frames.insert({Id, Frame});
290 // If a mapping already exists for the current frame id and it does not
291 // match the new mapping provided then reset the existing contents and bail
292 // out. We don't support the merging of memprof data whose Frame -> Id
293 // mapping across profiles is inconsistent.
294 if (!Inserted && Iter->second != Frame) {
295 Warn(make_error<InstrProfError>(instrprof_error::malformed,
296 "frame to id mapping mismatch"));
297 return false;
298 }
299 return true;
300}
301
303 const memprof::CallStackId CSId,
305 function_ref<void(Error)> Warn) {
306 auto [Iter, Inserted] = MemProfData.CallStacks.insert({CSId, CallStack});
307 // If a mapping already exists for the current call stack id and it does not
308 // match the new mapping provided then reset the existing contents and bail
309 // out. We don't support the merging of memprof data whose CallStack -> Id
310 // mapping across profiles is inconsistent.
311 if (!Inserted && Iter->second != CallStack) {
312 Warn(make_error<InstrProfError>(instrprof_error::malformed,
313 "call stack to id mapping mismatch"));
314 return false;
315 }
316 return true;
317}
318
320 llvm::append_range(BinaryIds, BIs);
321}
322
323void InstrProfWriter::addTemporalProfileTrace(TemporalProfTraceTy Trace) {
324 assert(Trace.FunctionNameRefs.size() <= MaxTemporalProfTraceLength);
325 assert(!Trace.FunctionNameRefs.empty());
326 if (TemporalProfTraceStreamSize < TemporalProfTraceReservoirSize) {
327 // Simply append the trace if we have not yet hit our reservoir size limit.
328 TemporalProfTraces.push_back(std::move(Trace));
329 } else {
330 // Otherwise, replace a random trace in the stream.
331 std::uniform_int_distribution<uint64_t> Distribution(
332 0, TemporalProfTraceStreamSize);
333 uint64_t RandomIndex = Distribution(RNG);
334 if (RandomIndex < TemporalProfTraces.size())
335 TemporalProfTraces[RandomIndex] = std::move(Trace);
336 }
337 ++TemporalProfTraceStreamSize;
338}
339
341 SmallVectorImpl<TemporalProfTraceTy> &SrcTraces, uint64_t SrcStreamSize) {
342 for (auto &Trace : SrcTraces)
343 if (Trace.FunctionNameRefs.size() > MaxTemporalProfTraceLength)
344 Trace.FunctionNameRefs.resize(MaxTemporalProfTraceLength);
345 llvm::erase_if(SrcTraces, [](auto &T) { return T.FunctionNameRefs.empty(); });
346 // Assume that the source has the same reservoir size as the destination to
347 // avoid needing to record it in the indexed profile format.
348 bool IsDestSampled =
349 (TemporalProfTraceStreamSize > TemporalProfTraceReservoirSize);
350 bool IsSrcSampled = (SrcStreamSize > TemporalProfTraceReservoirSize);
351 if (!IsDestSampled && IsSrcSampled) {
352 // If one of the traces are sampled, ensure that it belongs to Dest.
353 std::swap(TemporalProfTraces, SrcTraces);
354 std::swap(TemporalProfTraceStreamSize, SrcStreamSize);
355 std::swap(IsDestSampled, IsSrcSampled);
356 }
357 if (!IsSrcSampled) {
358 // If the source stream is not sampled, we add each source trace normally.
359 for (auto &Trace : SrcTraces)
360 addTemporalProfileTrace(std::move(Trace));
361 return;
362 }
363 // Otherwise, we find the traces that would have been removed if we added
364 // the whole source stream.
365 SmallSetVector<uint64_t, 8> IndicesToReplace;
366 for (uint64_t I = 0; I < SrcStreamSize; I++) {
367 std::uniform_int_distribution<uint64_t> Distribution(
368 0, TemporalProfTraceStreamSize);
369 uint64_t RandomIndex = Distribution(RNG);
370 if (RandomIndex < TemporalProfTraces.size())
371 IndicesToReplace.insert(RandomIndex);
372 ++TemporalProfTraceStreamSize;
373 }
374 // Then we insert a random sample of the source traces.
375 llvm::shuffle(SrcTraces.begin(), SrcTraces.end(), RNG);
376 for (const auto &[Index, Trace] : llvm::zip(IndicesToReplace, SrcTraces))
377 TemporalProfTraces[Index] = std::move(Trace);
378}
379
381 function_ref<void(Error)> Warn) {
382 for (auto &I : IPW.FunctionData)
383 for (auto &Func : I.getValue())
384 addRecord(I.getKey(), Func.first, std::move(Func.second), 1, Warn);
385
386 BinaryIds.reserve(BinaryIds.size() + IPW.BinaryIds.size());
387 for (auto &I : IPW.BinaryIds)
389
390 addTemporalProfileTraces(IPW.TemporalProfTraces,
391 IPW.TemporalProfTraceStreamSize);
392
393 MemProfData.Frames.reserve(IPW.MemProfData.Frames.size());
394 for (auto &[FrameId, Frame] : IPW.MemProfData.Frames) {
395 // If we weren't able to add the frame mappings then it doesn't make sense
396 // to try to merge the records from this profile.
397 if (!addMemProfFrame(FrameId, Frame, Warn))
398 return;
399 }
400
401 MemProfData.CallStacks.reserve(IPW.MemProfData.CallStacks.size());
402 for (auto &[CSId, CallStack] : IPW.MemProfData.CallStacks) {
403 if (!addMemProfCallStack(CSId, CallStack, Warn))
404 return;
405 }
406
407 MemProfData.Records.reserve(IPW.MemProfData.Records.size());
408 for (auto &[GUID, Record] : IPW.MemProfData.Records) {
410 }
411}
412
413bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
414 if (!Sparse)
415 return true;
416 for (const auto &Func : PD) {
417 const InstrProfRecord &IPR = Func.second;
418 if (llvm::any_of(IPR.Counts, [](uint64_t Count) { return Count > 0; }))
419 return true;
420 if (llvm::any_of(IPR.BitmapBytes, [](uint8_t Byte) { return Byte > 0; }))
421 return true;
422 }
423 return false;
424}
425
426static void setSummary(IndexedInstrProf::Summary *TheSummary,
427 ProfileSummary &PS) {
428 using namespace IndexedInstrProf;
429
430 const std::vector<ProfileSummaryEntry> &Res = PS.getDetailedSummary();
431 TheSummary->NumSummaryFields = Summary::NumKinds;
432 TheSummary->NumCutoffEntries = Res.size();
433 TheSummary->set(Summary::MaxFunctionCount, PS.getMaxFunctionCount());
434 TheSummary->set(Summary::MaxBlockCount, PS.getMaxCount());
435 TheSummary->set(Summary::MaxInternalBlockCount, PS.getMaxInternalCount());
436 TheSummary->set(Summary::TotalBlockCount, PS.getTotalCount());
437 TheSummary->set(Summary::TotalNumBlocks, PS.getNumCounts());
438 TheSummary->set(Summary::TotalNumFunctions, PS.getNumFunctions());
439 for (unsigned I = 0; I < Res.size(); I++)
440 TheSummary->setEntry(I, Res[I]);
441}
442
443// Serialize Schema.
445 const memprof::MemProfSchema &Schema) {
446 OS.write(static_cast<uint64_t>(Schema.size()));
447 for (const auto Id : Schema)
448 OS.write(static_cast<uint64_t>(Id));
449}
450
451// Serialize MemProfRecordData. Return RecordTableOffset.
455 &MemProfRecordData,
458 *MemProfCallStackIndexes = nullptr) {
459 memprof::RecordWriterTrait RecordWriter(Schema, Version,
460 MemProfCallStackIndexes);
462 RecordTableGenerator;
463 for (auto &[GUID, Record] : MemProfRecordData) {
464 // Insert the key (func hash) and value (memprof record).
465 RecordTableGenerator.insert(GUID, Record, RecordWriter);
466 }
467 // Release the memory of this MapVector as it is no longer needed.
468 MemProfRecordData.clear();
469
470 // The call to Emit invokes RecordWriterTrait::EmitData which destructs
471 // the memprof record copies owned by the RecordTableGenerator. This works
472 // because the RecordTableGenerator is not used after this point.
473 return RecordTableGenerator.Emit(OS.OS, RecordWriter);
474}
475
476// Serialize MemProfFrameData. Return FrameTableOffset.
481 FrameTableGenerator;
482 for (auto &[FrameId, Frame] : MemProfFrameData) {
483 // Insert the key (frame id) and value (frame contents).
484 FrameTableGenerator.insert(FrameId, Frame);
485 }
486 // Release the memory of this MapVector as it is no longer needed.
487 MemProfFrameData.clear();
488
489 return FrameTableGenerator.Emit(OS.OS);
490}
491
492// Serialize MemProfFrameData. Return the mapping from FrameIds to their
493// indexes within the frame array.
499 // Mappings from FrameIds to array indexes.
501
502 // Compute the order in which we serialize Frames. The order does not matter
503 // in terms of correctness, but we still compute it for deserialization
504 // performance. Specifically, if we serialize frequently used Frames one
505 // after another, we have better cache utilization. For two Frames that
506 // appear equally frequently, we break a tie by serializing the one that tends
507 // to appear earlier in call stacks. We implement the tie-breaking mechanism
508 // by computing the sum of indexes within call stacks for each Frame. If we
509 // still have a tie, then we just resort to compare two FrameIds, which is
510 // just for stability of output.
511 std::vector<std::pair<memprof::FrameId, const memprof::Frame *>> FrameIdOrder;
512 FrameIdOrder.reserve(MemProfFrameData.size());
513 for (const auto &[Id, Frame] : MemProfFrameData)
514 FrameIdOrder.emplace_back(Id, &Frame);
515 assert(MemProfFrameData.size() == FrameIdOrder.size());
516 llvm::sort(FrameIdOrder,
517 [&](const std::pair<memprof::FrameId, const memprof::Frame *> &L,
518 const std::pair<memprof::FrameId, const memprof::Frame *> &R) {
519 const auto &SL = FrameHistogram[L.first];
520 const auto &SR = FrameHistogram[R.first];
521 // Popular FrameIds should come first.
522 if (SL.Count != SR.Count)
523 return SL.Count > SR.Count;
524 // If they are equally popular, then the one that tends to appear
525 // earlier in call stacks should come first.
526 if (SL.PositionSum != SR.PositionSum)
527 return SL.PositionSum < SR.PositionSum;
528 // Compare their FrameIds for sort stability.
529 return L.first < R.first;
530 });
531
532 // Serialize all frames while creating mappings from linear IDs to FrameIds.
533 uint64_t Index = 0;
534 MemProfFrameIndexes.reserve(FrameIdOrder.size());
535 for (const auto &[Id, F] : FrameIdOrder) {
536 F->serialize(OS.OS);
537 MemProfFrameIndexes.insert({Id, Index});
538 ++Index;
539 }
540 assert(MemProfFrameData.size() == Index);
541 assert(MemProfFrameData.size() == MemProfFrameIndexes.size());
542
543 // Release the memory of this MapVector as it is no longer needed.
544 MemProfFrameData.clear();
545
546 return MemProfFrameIndexes;
547}
548
552 &MemProfCallStackData) {
554 CallStackTableGenerator;
555 for (auto &[CSId, CallStack] : MemProfCallStackData)
556 CallStackTableGenerator.insert(CSId, CallStack);
557 // Release the memory of this vector as it is no longer needed.
558 MemProfCallStackData.clear();
559
560 return CallStackTableGenerator.Emit(OS.OS);
561}
562
567 &MemProfCallStackData,
569 &MemProfFrameIndexes,
572 MemProfCallStackIndexes;
573
575 Builder.build(std::move(MemProfCallStackData), MemProfFrameIndexes,
576 FrameHistogram);
577 for (auto I : Builder.getRadixArray())
578 OS.write32(I);
579 MemProfCallStackIndexes = Builder.takeCallStackPos();
580
581 // Release the memory of this vector as it is no longer needed.
582 MemProfCallStackData.clear();
583
584 return MemProfCallStackIndexes;
585}
586
587// Write out MemProf Version0 as follows:
588// uint64_t RecordTableOffset = RecordTableGenerator.Emit
589// uint64_t FramePayloadOffset = Offset for the frame payload
590// uint64_t FrameTableOffset = FrameTableGenerator.Emit
591// uint64_t Num schema entries
592// uint64_t Schema entry 0
593// uint64_t Schema entry 1
594// ....
595// uint64_t Schema entry N - 1
596// OnDiskChainedHashTable MemProfRecordData
597// OnDiskChainedHashTable MemProfFrameData
599 memprof::IndexedMemProfData &MemProfData) {
600 uint64_t HeaderUpdatePos = OS.tell();
601 OS.write(0ULL); // Reserve space for the memprof record table offset.
602 OS.write(0ULL); // Reserve space for the memprof frame payload offset.
603 OS.write(0ULL); // Reserve space for the memprof frame table offset.
604
605 auto Schema = memprof::getFullSchema();
606 writeMemProfSchema(OS, Schema);
607
608 uint64_t RecordTableOffset =
609 writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version0);
610
611 uint64_t FramePayloadOffset = OS.tell();
612 uint64_t FrameTableOffset = writeMemProfFrames(OS, MemProfData.Frames);
613
614 uint64_t Header[] = {RecordTableOffset, FramePayloadOffset, FrameTableOffset};
615 OS.patch({{HeaderUpdatePos, Header, std::size(Header)}});
616
617 return Error::success();
618}
619
620// Write out MemProf Version1 as follows:
621// uint64_t Version (NEW in V1)
622// uint64_t RecordTableOffset = RecordTableGenerator.Emit
623// uint64_t FramePayloadOffset = Offset for the frame payload
624// uint64_t FrameTableOffset = FrameTableGenerator.Emit
625// uint64_t Num schema entries
626// uint64_t Schema entry 0
627// uint64_t Schema entry 1
628// ....
629// uint64_t Schema entry N - 1
630// OnDiskChainedHashTable MemProfRecordData
631// OnDiskChainedHashTable MemProfFrameData
633 memprof::IndexedMemProfData &MemProfData) {
635 uint64_t HeaderUpdatePos = OS.tell();
636 OS.write(0ULL); // Reserve space for the memprof record table offset.
637 OS.write(0ULL); // Reserve space for the memprof frame payload offset.
638 OS.write(0ULL); // Reserve space for the memprof frame table offset.
639
640 auto Schema = memprof::getFullSchema();
641 writeMemProfSchema(OS, Schema);
642
643 uint64_t RecordTableOffset =
644 writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version1);
645
646 uint64_t FramePayloadOffset = OS.tell();
647 uint64_t FrameTableOffset = writeMemProfFrames(OS, MemProfData.Frames);
648
649 uint64_t Header[] = {RecordTableOffset, FramePayloadOffset, FrameTableOffset};
650 OS.patch({{HeaderUpdatePos, Header, std::size(Header)}});
651
652 return Error::success();
653}
654
655// Write out MemProf Version2 as follows:
656// uint64_t Version
657// uint64_t RecordTableOffset = RecordTableGenerator.Emit
658// uint64_t FramePayloadOffset = Offset for the frame payload
659// uint64_t FrameTableOffset = FrameTableGenerator.Emit
660// uint64_t CallStackPayloadOffset = Offset for the call stack payload (NEW V2)
661// uint64_t CallStackTableOffset = CallStackTableGenerator.Emit (NEW in V2)
662// uint64_t Num schema entries
663// uint64_t Schema entry 0
664// uint64_t Schema entry 1
665// ....
666// uint64_t Schema entry N - 1
667// OnDiskChainedHashTable MemProfRecordData
668// OnDiskChainedHashTable MemProfFrameData
669// OnDiskChainedHashTable MemProfCallStackData (NEW in V2)
671 memprof::IndexedMemProfData &MemProfData,
672 bool MemProfFullSchema) {
674 uint64_t HeaderUpdatePos = OS.tell();
675 OS.write(0ULL); // Reserve space for the memprof record table offset.
676 OS.write(0ULL); // Reserve space for the memprof frame payload offset.
677 OS.write(0ULL); // Reserve space for the memprof frame table offset.
678 OS.write(0ULL); // Reserve space for the memprof call stack payload offset.
679 OS.write(0ULL); // Reserve space for the memprof call stack table offset.
680
681 auto Schema = memprof::getHotColdSchema();
682 if (MemProfFullSchema)
683 Schema = memprof::getFullSchema();
684 writeMemProfSchema(OS, Schema);
685
686 uint64_t RecordTableOffset =
687 writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version2);
688
689 uint64_t FramePayloadOffset = OS.tell();
690 uint64_t FrameTableOffset = writeMemProfFrames(OS, MemProfData.Frames);
691
692 uint64_t CallStackPayloadOffset = OS.tell();
693 uint64_t CallStackTableOffset =
695
696 uint64_t Header[] = {
697 RecordTableOffset, FramePayloadOffset, FrameTableOffset,
698 CallStackPayloadOffset, CallStackTableOffset,
699 };
700 OS.patch({{HeaderUpdatePos, Header, std::size(Header)}});
701
702 return Error::success();
703}
704
705// Write out MemProf Version3 as follows:
706// uint64_t Version
707// uint64_t CallStackPayloadOffset = Offset for the call stack payload
708// uint64_t RecordPayloadOffset = Offset for the record payload
709// uint64_t RecordTableOffset = RecordTableGenerator.Emit
710// uint64_t Num schema entries
711// uint64_t Schema entry 0
712// uint64_t Schema entry 1
713// ....
714// uint64_t Schema entry N - 1
715// Frames serialized one after another
716// Call stacks encoded as a radix tree
717// OnDiskChainedHashTable MemProfRecordData
719 memprof::IndexedMemProfData &MemProfData,
720 bool MemProfFullSchema) {
722 uint64_t HeaderUpdatePos = OS.tell();
723 OS.write(0ULL); // Reserve space for the memprof call stack payload offset.
724 OS.write(0ULL); // Reserve space for the memprof record payload offset.
725 OS.write(0ULL); // Reserve space for the memprof record table offset.
726
727 auto Schema = memprof::getHotColdSchema();
728 if (MemProfFullSchema)
729 Schema = memprof::getFullSchema();
730 writeMemProfSchema(OS, Schema);
731
734 assert(MemProfData.Frames.size() == FrameHistogram.size());
735
737 writeMemProfFrameArray(OS, MemProfData.Frames, FrameHistogram);
738
739 uint64_t CallStackPayloadOffset = OS.tell();
741 MemProfCallStackIndexes = writeMemProfCallStackArray(
742 OS, MemProfData.CallStacks, MemProfFrameIndexes, FrameHistogram);
743
744 uint64_t RecordPayloadOffset = OS.tell();
745 uint64_t RecordTableOffset =
746 writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version3,
747 &MemProfCallStackIndexes);
748
749 uint64_t Header[] = {
750 CallStackPayloadOffset,
751 RecordPayloadOffset,
752 RecordTableOffset,
753 };
754 OS.patch({{HeaderUpdatePos, Header, std::size(Header)}});
755
756 return Error::success();
757}
758
759// Write out the MemProf data in a requested version.
761 memprof::IndexedMemProfData &MemProfData,
762 memprof::IndexedVersion MemProfVersionRequested,
763 bool MemProfFullSchema) {
764 switch (MemProfVersionRequested) {
766 return writeMemProfV0(OS, MemProfData);
768 return writeMemProfV1(OS, MemProfData);
770 return writeMemProfV2(OS, MemProfData, MemProfFullSchema);
772 return writeMemProfV3(OS, MemProfData, MemProfFullSchema);
773 }
774
775 return make_error<InstrProfError>(
777 formatv("MemProf version {} not supported; "
778 "requires version between {} and {}, inclusive",
779 MemProfVersionRequested, memprof::MinimumSupportedVersion,
781}
782
783uint64_t InstrProfWriter::writeHeader(const IndexedInstrProf::Header &Header,
784 const bool WritePrevVersion,
785 ProfOStream &OS) {
786 // Only write out the first four fields.
787 for (int I = 0; I < 4; I++)
788 OS.write(reinterpret_cast<const uint64_t *>(&Header)[I]);
789
790 // Remember the offset of the remaining fields to allow back patching later.
791 auto BackPatchStartOffset = OS.tell();
792
793 // Reserve the space for back patching later.
794 OS.write(0); // HashOffset
795 OS.write(0); // MemProfOffset
796 OS.write(0); // BinaryIdOffset
797 OS.write(0); // TemporalProfTracesOffset
798 if (!WritePrevVersion)
799 OS.write(0); // VTableNamesOffset
800
801 return BackPatchStartOffset;
802}
803
804Error InstrProfWriter::writeVTableNames(ProfOStream &OS) {
805 std::vector<std::string> VTableNameStrs;
806 for (StringRef VTableName : VTableNames.keys())
807 VTableNameStrs.push_back(VTableName.str());
808
809 std::string CompressedVTableNames;
810 if (!VTableNameStrs.empty())
812 VTableNameStrs, compression::zlib::isAvailable(),
813 CompressedVTableNames))
814 return E;
815
816 const uint64_t CompressedStringLen = CompressedVTableNames.length();
817
818 // Record the length of compressed string.
819 OS.write(CompressedStringLen);
820
821 // Write the chars in compressed strings.
822 for (auto &c : CompressedVTableNames)
823 OS.writeByte(static_cast<uint8_t>(c));
824
825 // Pad up to a multiple of 8.
826 // InstrProfReader could read bytes according to 'CompressedStringLen'.
827 const uint64_t PaddedLength = alignTo(CompressedStringLen, 8);
828
829 for (uint64_t K = CompressedStringLen; K < PaddedLength; K++)
830 OS.writeByte(0);
831
832 return Error::success();
833}
834
835Error InstrProfWriter::writeImpl(ProfOStream &OS) {
836 using namespace IndexedInstrProf;
837 using namespace support;
838
840
842 InfoObj->SummaryBuilder = &ISB;
844 InfoObj->CSSummaryBuilder = &CSISB;
845
846 // Populate the hash table generator.
848 for (const auto &I : FunctionData)
849 if (shouldEncodeData(I.getValue()))
850 OrderedData.emplace_back((I.getKey()), &I.getValue());
851 llvm::sort(OrderedData, less_first());
852 for (const auto &I : OrderedData)
853 Generator.insert(I.first, I.second);
854
855 // Write the header.
857 Header.Version = WritePrevVersion
860 // The WritePrevVersion handling will either need to be removed or updated
861 // if the version is advanced beyond 12.
864 if (static_cast<bool>(ProfileKind & InstrProfKind::IRInstrumentation))
865 Header.Version |= VARIANT_MASK_IR_PROF;
866 if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive))
867 Header.Version |= VARIANT_MASK_CSIR_PROF;
868 if (static_cast<bool>(ProfileKind &
870 Header.Version |= VARIANT_MASK_INSTR_ENTRY;
871 if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
872 Header.Version |= VARIANT_MASK_BYTE_COVERAGE;
873 if (static_cast<bool>(ProfileKind & InstrProfKind::FunctionEntryOnly))
874 Header.Version |= VARIANT_MASK_FUNCTION_ENTRY_ONLY;
875 if (static_cast<bool>(ProfileKind & InstrProfKind::MemProf))
876 Header.Version |= VARIANT_MASK_MEMPROF;
877 if (static_cast<bool>(ProfileKind & InstrProfKind::TemporalProfile))
878 Header.Version |= VARIANT_MASK_TEMPORAL_PROF;
879
880 const uint64_t BackPatchStartOffset =
881 writeHeader(Header, WritePrevVersion, OS);
882
883 // Reserve space to write profile summary data.
885 uint32_t SummarySize = Summary::getSize(Summary::NumKinds, NumEntries);
886 // Remember the summary offset.
887 uint64_t SummaryOffset = OS.tell();
888 for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++)
889 OS.write(0);
890 uint64_t CSSummaryOffset = 0;
891 uint64_t CSSummarySize = 0;
892 if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive)) {
893 CSSummaryOffset = OS.tell();
894 CSSummarySize = SummarySize / sizeof(uint64_t);
895 for (unsigned I = 0; I < CSSummarySize; I++)
896 OS.write(0);
897 }
898
899 // Write the hash table.
900 uint64_t HashTableStart = Generator.Emit(OS.OS, *InfoObj);
901
902 // Write the MemProf profile data if we have it.
903 uint64_t MemProfSectionStart = 0;
904 if (static_cast<bool>(ProfileKind & InstrProfKind::MemProf)) {
905 MemProfSectionStart = OS.tell();
906 if (auto E = writeMemProf(OS, MemProfData, MemProfVersionRequested,
907 MemProfFullSchema))
908 return E;
909 }
910
911 // BinaryIdSection has two parts:
912 // 1. uint64_t BinaryIdsSectionSize
913 // 2. list of binary ids that consist of:
914 // a. uint64_t BinaryIdLength
915 // b. uint8_t BinaryIdData
916 // c. uint8_t Padding (if necessary)
917 uint64_t BinaryIdSectionStart = OS.tell();
918 // Calculate size of binary section.
919 uint64_t BinaryIdsSectionSize = 0;
920
921 // Remove duplicate binary ids.
922 llvm::sort(BinaryIds);
923 BinaryIds.erase(llvm::unique(BinaryIds), BinaryIds.end());
924
925 for (const auto &BI : BinaryIds) {
926 // Increment by binary id length data type size.
927 BinaryIdsSectionSize += sizeof(uint64_t);
928 // Increment by binary id data length, aligned to 8 bytes.
929 BinaryIdsSectionSize += alignToPowerOf2(BI.size(), sizeof(uint64_t));
930 }
931 // Write binary ids section size.
932 OS.write(BinaryIdsSectionSize);
933
934 for (const auto &BI : BinaryIds) {
935 uint64_t BILen = BI.size();
936 // Write binary id length.
937 OS.write(BILen);
938 // Write binary id data.
939 for (unsigned K = 0; K < BILen; K++)
940 OS.writeByte(BI[K]);
941 // Write padding if necessary.
942 uint64_t PaddingSize = alignToPowerOf2(BILen, sizeof(uint64_t)) - BILen;
943 for (unsigned K = 0; K < PaddingSize; K++)
944 OS.writeByte(0);
945 }
946
947 uint64_t VTableNamesSectionStart = OS.tell();
948
949 if (!WritePrevVersion)
950 if (Error E = writeVTableNames(OS))
951 return E;
952
953 uint64_t TemporalProfTracesSectionStart = 0;
954 if (static_cast<bool>(ProfileKind & InstrProfKind::TemporalProfile)) {
955 TemporalProfTracesSectionStart = OS.tell();
956 OS.write(TemporalProfTraces.size());
957 OS.write(TemporalProfTraceStreamSize);
958 for (auto &Trace : TemporalProfTraces) {
959 OS.write(Trace.Weight);
960 OS.write(Trace.FunctionNameRefs.size());
961 for (auto &NameRef : Trace.FunctionNameRefs)
962 OS.write(NameRef);
963 }
964 }
965
966 // Allocate space for data to be serialized out.
967 std::unique_ptr<IndexedInstrProf::Summary> TheSummary =
969 // Compute the Summary and copy the data to the data
970 // structure to be serialized out (to disk or buffer).
971 std::unique_ptr<ProfileSummary> PS = ISB.getSummary();
972 setSummary(TheSummary.get(), *PS);
973 InfoObj->SummaryBuilder = nullptr;
974
975 // For Context Sensitive summary.
976 std::unique_ptr<IndexedInstrProf::Summary> TheCSSummary = nullptr;
977 if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive)) {
978 TheCSSummary = IndexedInstrProf::allocSummary(SummarySize);
979 std::unique_ptr<ProfileSummary> CSPS = CSISB.getSummary();
980 setSummary(TheCSSummary.get(), *CSPS);
981 }
982 InfoObj->CSSummaryBuilder = nullptr;
983
984 SmallVector<uint64_t, 8> HeaderOffsets = {HashTableStart, MemProfSectionStart,
985 BinaryIdSectionStart,
986 TemporalProfTracesSectionStart};
987 if (!WritePrevVersion)
988 HeaderOffsets.push_back(VTableNamesSectionStart);
989
990 PatchItem PatchItems[] = {
991 // Patch the Header fields
992 {BackPatchStartOffset, HeaderOffsets.data(), (int)HeaderOffsets.size()},
993 // Patch the summary data.
994 {SummaryOffset, reinterpret_cast<uint64_t *>(TheSummary.get()),
995 (int)(SummarySize / sizeof(uint64_t))},
996 {CSSummaryOffset, reinterpret_cast<uint64_t *>(TheCSSummary.get()),
997 (int)CSSummarySize}};
998
999 OS.patch(PatchItems);
1000
1001 for (const auto &I : FunctionData)
1002 for (const auto &F : I.getValue())
1003 if (Error E = validateRecord(F.second))
1004 return E;
1005
1006 return Error::success();
1007}
1008
1010 // Write the hash table.
1011 ProfOStream POS(OS);
1012 return writeImpl(POS);
1013}
1014
1016 ProfOStream POS(OS);
1017 return writeImpl(POS);
1018}
1019
1020std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
1021 std::string Data;
1023 // Write the hash table.
1024 if (Error E = write(OS))
1025 return nullptr;
1026 // Return this in an aligned memory buffer.
1028}
1029
1030static const char *ValueProfKindStr[] = {
1031#define VALUE_PROF_KIND(Enumerator, Value, Descr) #Enumerator,
1033};
1034
1036 for (uint32_t VK = 0; VK <= IPVK_Last; VK++) {
1037 if (VK == IPVK_IndirectCallTarget || VK == IPVK_VTableTarget)
1038 continue;
1039 uint32_t NS = Func.getNumValueSites(VK);
1040 for (uint32_t S = 0; S < NS; S++) {
1041 DenseSet<uint64_t> SeenValues;
1042 for (const auto &V : Func.getValueArrayForSite(VK, S))
1043 if (!SeenValues.insert(V.Value).second)
1044 return make_error<InstrProfError>(instrprof_error::invalid_prof);
1045 }
1046 }
1047
1048 return Error::success();
1049}
1050
1052 const InstrProfRecord &Func,
1053 InstrProfSymtab &Symtab,
1054 raw_fd_ostream &OS) {
1055 OS << Name << "\n";
1056 OS << "# Func Hash:\n" << Hash << "\n";
1057 OS << "# Num Counters:\n" << Func.Counts.size() << "\n";
1058 OS << "# Counter Values:\n";
1059 for (uint64_t Count : Func.Counts)
1060 OS << Count << "\n";
1061
1062 if (Func.BitmapBytes.size() > 0) {
1063 OS << "# Num Bitmap Bytes:\n$" << Func.BitmapBytes.size() << "\n";
1064 OS << "# Bitmap Byte Values:\n";
1065 for (uint8_t Byte : Func.BitmapBytes) {
1066 OS << "0x";
1067 OS.write_hex(Byte);
1068 OS << "\n";
1069 }
1070 OS << "\n";
1071 }
1072
1073 uint32_t NumValueKinds = Func.getNumValueKinds();
1074 if (!NumValueKinds) {
1075 OS << "\n";
1076 return;
1077 }
1078
1079 OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n";
1080 for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) {
1081 uint32_t NS = Func.getNumValueSites(VK);
1082 if (!NS)
1083 continue;
1084 OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n";
1085 OS << "# NumValueSites:\n" << NS << "\n";
1086 for (uint32_t S = 0; S < NS; S++) {
1087 auto VD = Func.getValueArrayForSite(VK, S);
1088 OS << VD.size() << "\n";
1089 for (const auto &V : VD) {
1090 if (VK == IPVK_IndirectCallTarget || VK == IPVK_VTableTarget)
1091 OS << Symtab.getFuncOrVarNameIfDefined(V.Value) << ":" << V.Count
1092 << "\n";
1093 else
1094 OS << V.Value << ":" << V.Count << "\n";
1095 }
1096 }
1097 }
1098
1099 OS << "\n";
1100}
1101
1103 // Check CS first since it implies an IR level profile.
1104 if (static_cast<bool>(ProfileKind & InstrProfKind::ContextSensitive))
1105 OS << "# CSIR level Instrumentation Flag\n:csir\n";
1106 else if (static_cast<bool>(ProfileKind & InstrProfKind::IRInstrumentation))
1107 OS << "# IR level Instrumentation Flag\n:ir\n";
1108
1109 if (static_cast<bool>(ProfileKind &
1111 OS << "# Always instrument the function entry block\n:entry_first\n";
1112 if (static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage))
1113 OS << "# Instrument block coverage\n:single_byte_coverage\n";
1114 InstrProfSymtab Symtab;
1115
1117 using RecordType = std::pair<StringRef, FuncPair>;
1118 SmallVector<RecordType, 4> OrderedFuncData;
1119
1120 for (const auto &I : FunctionData) {
1121 if (shouldEncodeData(I.getValue())) {
1122 if (Error E = Symtab.addFuncName(I.getKey()))
1123 return E;
1124 for (const auto &Func : I.getValue())
1125 OrderedFuncData.push_back(std::make_pair(I.getKey(), Func));
1126 }
1127 }
1128
1129 for (const auto &VTableName : VTableNames)
1130 if (Error E = Symtab.addVTableName(VTableName.getKey()))
1131 return E;
1132
1133 if (static_cast<bool>(ProfileKind & InstrProfKind::TemporalProfile))
1135
1136 llvm::sort(OrderedFuncData, [](const RecordType &A, const RecordType &B) {
1137 return std::tie(A.first, A.second.first) <
1138 std::tie(B.first, B.second.first);
1139 });
1140
1141 for (const auto &record : OrderedFuncData) {
1142 const StringRef &Name = record.first;
1143 const FuncPair &Func = record.second;
1144 writeRecordInText(Name, Func.first, Func.second, Symtab, OS);
1145 }
1146
1147 for (const auto &record : OrderedFuncData) {
1148 const FuncPair &Func = record.second;
1149 if (Error E = validateRecord(Func.second))
1150 return E;
1151 }
1152
1153 return Error::success();
1154}
1155
1157 InstrProfSymtab &Symtab) {
1158 OS << ":temporal_prof_traces\n";
1159 OS << "# Num Temporal Profile Traces:\n" << TemporalProfTraces.size() << "\n";
1160 OS << "# Temporal Profile Trace Stream Size:\n"
1161 << TemporalProfTraceStreamSize << "\n";
1162 for (auto &Trace : TemporalProfTraces) {
1163 OS << "# Weight:\n" << Trace.Weight << "\n";
1164 for (auto &NameRef : Trace.FunctionNameRefs)
1165 OS << Symtab.getFuncOrVarName(NameRef) << ",";
1166 OS << "\n";
1167 }
1168 OS << "\n";
1169}
basic Basic Alias true
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
std::string Name
static Error writeMemProfV0(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData)
static uint64_t writeMemProfRecords(ProfOStream &OS, llvm::MapVector< GlobalValue::GUID, memprof::IndexedMemProfRecord > &MemProfRecordData, memprof::MemProfSchema *Schema, memprof::IndexedVersion Version, llvm::DenseMap< memprof::CallStackId, memprof::LinearCallStackId > *MemProfCallStackIndexes=nullptr)
static Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema)
static uint64_t writeMemProfCallStacks(ProfOStream &OS, llvm::MapVector< memprof::CallStackId, llvm::SmallVector< memprof::FrameId > > &MemProfCallStackData)
static Error writeMemProfV1(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData)
static Error writeMemProfV3(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, bool MemProfFullSchema)
static uint64_t writeMemProfFrames(ProfOStream &OS, llvm::MapVector< memprof::FrameId, memprof::Frame > &MemProfFrameData)
static Error writeMemProfV2(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, bool MemProfFullSchema)
static void setSummary(IndexedInstrProf::Summary *TheSummary, ProfileSummary &PS)
static const char * ValueProfKindStr[]
static llvm::DenseMap< memprof::FrameId, memprof::LinearFrameId > writeMemProfFrameArray(ProfOStream &OS, llvm::MapVector< memprof::FrameId, memprof::Frame > &MemProfFrameData, llvm::DenseMap< memprof::FrameId, memprof::FrameStat > &FrameHistogram)
static llvm::DenseMap< memprof::CallStackId, memprof::LinearCallStackId > writeMemProfCallStackArray(ProfOStream &OS, llvm::MapVector< memprof::CallStackId, llvm::SmallVector< memprof::FrameId > > &MemProfCallStackData, llvm::DenseMap< memprof::FrameId, memprof::LinearFrameId > &MemProfFrameIndexes, llvm::DenseMap< memprof::FrameId, memprof::FrameStat > &FrameHistogram)
static void writeMemProfSchema(ProfOStream &OS, const memprof::MemProfSchema &Schema)
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Defines facilities for reading and writing on-disk hash tables.
#define P(N)
if(VerifyEach)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file implements a set that has insertion order iteration characteristics.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
DenseMapIterator< KeyT, ValueT, KeyInfoT, BucketT > iterator
Definition: DenseMap.h:71
unsigned size() const
Definition: DenseMap.h:99
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:220
void reserve(size_type NumEntries)
Grow the densemap so that it can contain at least NumEntries items before resizing again.
Definition: DenseMap.h:103
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
static std::pair< offset_type, offset_type > EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V)
const InstrProfWriter::ProfilingData *const data_type_ref
InstrProfSummaryBuilder * SummaryBuilder
static hash_value_type ComputeHash(key_type_ref K)
InstrProfSummaryBuilder * CSSummaryBuilder
void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N)
void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V, offset_type)
const InstrProfWriter::ProfilingData *const data_type
void addRecord(const InstrProfRecord &)
A symbol table used for function [IR]PGO name look-up with keys (such as pointers,...
Definition: InstrProf.h:450
StringRef getFuncOrVarName(uint64_t ValMD5Hash)
Return name of functions or global variables from the name's md5 hash value.
Definition: InstrProf.h:707
Error addVTableName(StringRef VTableName)
Adds VTableName as a known symbol, and inserts it to a map that tracks all vtable names.
Definition: InstrProf.h:592
Error addFuncName(StringRef FuncName)
The method name is kept since there are many callers.
Definition: InstrProf.h:588
StringRef getFuncOrVarNameIfDefined(uint64_t ValMD5Hash)
Just like getFuncOrVarName, except that it will return literal string 'External Symbol' if the functi...
Definition: InstrProf.h:700
Error write(raw_fd_ostream &OS)
Write the profile to OS.
void addTemporalProfileTraces(SmallVectorImpl< TemporalProfTraceTy > &SrcTraces, uint64_t SrcStreamSize)
Add SrcTraces using reservoir sampling where SrcStreamSize is the total number of temporal profiling ...
void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap, OverlapStats &FuncLevelOverlap, const OverlapFuncFilters &FuncFilter)
Error writeText(raw_fd_ostream &OS)
Write the profile in text format to OS.
void addBinaryIds(ArrayRef< llvm::object::BuildID > BIs)
void addMemProfRecord(const GlobalValue::GUID Id, const memprof::IndexedMemProfRecord &Record)
Add a memprof record for a function identified by its Id.
static void writeRecordInText(StringRef Name, uint64_t Hash, const InstrProfRecord &Counters, InstrProfSymtab &Symtab, raw_fd_ostream &OS)
Write Record in text format to OS.
void setValueProfDataEndianness(llvm::endianness Endianness)
bool addMemProfCallStack(const memprof::CallStackId CSId, const llvm::SmallVector< memprof::FrameId > &CallStack, function_ref< void(Error)> Warn)
Add a call stack identified by the hash of the contents of the call stack in CallStack.
void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, function_ref< void(Error)> Warn)
Add function counts for the given function.
InstrProfWriter(bool Sparse=false, uint64_t TemporalProfTraceReservoirSize=0, uint64_t MaxTemporalProfTraceLength=0, bool WritePrevVersion=false, memprof::IndexedVersion MemProfVersionRequested=memprof::Version0, bool MemProfFullSchema=false)
void mergeRecordsFromWriter(InstrProfWriter &&IPW, function_ref< void(Error)> Warn)
Merge existing function counts from the given writer.
void writeTextTemporalProfTraceData(raw_fd_ostream &OS, InstrProfSymtab &Symtab)
Write temporal profile trace data to the header in text format to OS.
std::unique_ptr< MemoryBuffer > writeBuffer()
Write the profile, returning the raw data. For testing.
bool addMemProfFrame(const memprof::FrameId, const memprof::Frame &F, function_ref< void(Error)> Warn)
Add a memprof frame identified by the hash of the contents of the frame in FrameId.
void setOutputSparse(bool Sparse)
Error validateRecord(const InstrProfRecord &Func)
This class implements a map that also provides access to all stored values in a deterministic order.
Definition: MapVector.h:36
size_type size() const
Definition: MapVector.h:60
void clear()
Definition: MapVector.h:88
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Generates an on disk hash table.
offset_type Emit(raw_ostream &Out)
Emit the table to Out, which must not be at offset 0.
uint64_t tell() const
void writeByte(uint8_t V)
void patch(ArrayRef< PatchItem > P)
void write32(uint32_t V)
ProfOStream(raw_string_ostream &STR)
support::endian::Writer LE
ProfOStream(raw_fd_ostream &FD)
void write(uint64_t V)
static const ArrayRef< uint32_t > DefaultCutoffs
A vector of useful cutoff values for detailed summary.
Definition: ProfileCommon.h:70
uint64_t getTotalCount() const
uint64_t getMaxCount() const
const SummaryEntryVector & getDetailedSummary()
uint32_t getNumCounts() const
uint64_t getMaxInternalCount() const
uint64_t getMaxFunctionCount() const
uint32_t getNumFunctions() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:162
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:370
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:950
void push_back(const T &Elt)
Definition: SmallVector.h:426
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:299
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
iterator_range< StringMapKeyIterator< ValueTy > > keys() const
Definition: StringMap.h:228
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
bool empty() const
Definition: Trace.h:96
unsigned size() const
Definition: Trace.h:95
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
An efficient, type-erasing, non-owning reference to a callable.
void build(llvm::MapVector< CallStackId, llvm::SmallVector< FrameId > > &&MemProfCallStackData, const llvm::DenseMap< FrameId, LinearFrameId > &MemProfFrameIndexes, llvm::DenseMap< FrameId, FrameStat > &FrameHistogram)
Definition: MemProf.cpp:486
llvm::DenseMap< CallStackId, LinearCallStackId > takeCallStackPos()
Definition: MemProf.h:1056
const std::vector< LinearFrameId > & getRadixArray() const
Definition: MemProf.h:1054
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:471
uint64_t seek(uint64_t off)
Flushes the stream and repositions the underlying file descriptor position to the offset specified fr...
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:151
raw_ostream & write_hex(unsigned long long N)
Output N in hexadecimal, without any prefix or padding.
raw_ostream & write(unsigned char C)
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:679
std::unique_ptr< Summary > allocSummary(uint32_t TotalSize)
Definition: InstrProf.h:1231
uint64_t ComputeHash(StringRef K)
Definition: InstrProf.h:1112
constexpr uint64_t MaximumSupportedVersion
Definition: MemProf.h:37
MemProfSchema getHotColdSchema()
Definition: MemProf.cpp:21
llvm::DenseMap< FrameId, FrameStat > computeFrameHistogram(llvm::MapVector< CallStackId, llvm::SmallVector< FrameId > > &MemProfCallStackData)
Definition: MemProf.cpp:616
constexpr uint64_t MinimumSupportedVersion
Definition: MemProf.h:36
MemProfSchema getFullSchema()
Definition: MemProf.cpp:13
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition: STLExtras.h:853
uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align)
Definition: MathExtras.h:395
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2067
void shuffle(Iterator first, Iterator last, RNG &&g)
Definition: STLExtras.h:1541
auto unique(Range &&R, Predicate P)
Definition: STLExtras.h:2013
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1729
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1647
@ Other
Any other memory.
instrprof_error
Definition: InstrProf.h:344
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
Error collectGlobalObjectNameStrings(ArrayRef< std::string > NameStrs, bool doCompression, std::string &Result)
Given a vector of strings (names of global objects like functions or, virtual tables) NameStrs,...
Definition: InstrProf.cpp:658
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition: STLExtras.h:2051
endianness
Definition: bit.h:70
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
#define N
uint64_t Pos
uint64_t * D
Helper object to track which of three possible relocation mechanisms are used for a particular value ...
void set(SummaryFieldKind K, uint64_t V)
Definition: InstrProf.h:1217
void setEntry(uint32_t I, const ProfileSummaryEntry &E)
Definition: InstrProf.h:1223
Profiling information for a single function.
Definition: InstrProf.h:824
std::vector< uint64_t > Counts
Definition: InstrProf.h:825
void merge(InstrProfRecord &Other, uint64_t Weight, function_ref< void(instrprof_error)> Warn)
Merge the counts in Other into this one.
Definition: InstrProf.cpp:901
void overlap(InstrProfRecord &Other, OverlapStats &Overlap, OverlapStats &FuncLevelOverlap, uint64_t ValueCutoff)
Compute the overlap b/w this IntrprofRecord and Other.
Definition: InstrProf.cpp:790
void sortValueData()
Sort value profile data (per site) by count.
Definition: InstrProf.h:886
std::vector< uint8_t > BitmapBytes
Definition: InstrProf.h:826
void scale(uint64_t N, uint64_t D, function_ref< void(instrprof_error)> Warn)
Scale up profile counts (including value profile data) by a factor of (N / D).
Definition: InstrProf.cpp:964
static bool hasCSFlagInHash(uint64_t FuncHash)
Definition: InstrProf.h:1002
const std::string NameFilter
Definition: InstrProf.h:789
void addOneMismatch(const CountSumOrPercent &MismatchFunc)
Definition: InstrProf.cpp:1556
CountSumOrPercent Overlap
Definition: InstrProf.h:753
void addOneUnique(const CountSumOrPercent &UniqueFunc)
Definition: InstrProf.cpp:1566
CountSumOrPercent Test
Definition: InstrProf.h:751
An ordered list of functions identified by their NameRef found in INSTR_PROF_DATA.
Definition: InstrProf.h:375
Function object to check whether the first component of a container supported by std::get (like std::...
Definition: STLExtras.h:1450
llvm::MapVector< CallStackId, llvm::SmallVector< FrameId > > CallStacks
Definition: MemProf.h:939
llvm::MapVector< GlobalValue::GUID, IndexedMemProfRecord > Records
Definition: MemProf.h:931
llvm::MapVector< FrameId, Frame > Frames
Definition: MemProf.h:936
void merge(const IndexedMemProfRecord &Other)
Definition: MemProf.h:427
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:67
void write(ArrayRef< value_type > Val)
Definition: EndianStream.h:71