1 //===- InstrProfWriter.h - Instrumented profiling writer --------*- C++ -*-===// 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 instrumentation 10 // based PGO and coverage. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H 15 #define LLVM_PROFILEDATA_INSTRPROFWRITER_H 16 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/ADT/MapVector.h" 19 #include "llvm/ADT/StringMap.h" 20 #include "llvm/IR/GlobalValue.h" 21 #include "llvm/Object/BuildID.h" 22 #include "llvm/ProfileData/InstrProf.h" 23 #include "llvm/ProfileData/MemProf.h" 24 #include "llvm/Support/Error.h" 25 #include <cstdint> 26 #include <memory> 27 #include <random> 28 29 namespace llvm { 30 31 /// Writer for instrumentation based profile data. 32 class InstrProfRecordWriterTrait; 33 class ProfOStream; 34 class MemoryBuffer; 35 class raw_fd_ostream; 36 37 class InstrProfWriter { 38 public: 39 using ProfilingData = SmallDenseMap<uint64_t, InstrProfRecord>; 40 41 private: 42 bool Sparse; 43 StringMap<ProfilingData> FunctionData; 44 /// The maximum length of a single temporal profile trace. 45 uint64_t MaxTemporalProfTraceLength; 46 /// The maximum number of stored temporal profile traces. 47 uint64_t TemporalProfTraceReservoirSize; 48 /// The total number of temporal profile traces seen. 49 uint64_t TemporalProfTraceStreamSize = 0; 50 /// The list of temporal profile traces. 51 SmallVector<TemporalProfTraceTy> TemporalProfTraces; 52 std::mt19937 RNG; 53 54 // The MemProf data. 55 memprof::IndexedMemProfData MemProfData; 56 57 // List of binary ids. 58 std::vector<llvm::object::BuildID> BinaryIds; 59 60 // Read the vtable names from raw instr profile reader. 61 StringSet<> VTableNames; 62 63 // An enum describing the attributes of the profile. 64 InstrProfKind ProfileKind = InstrProfKind::Unknown; 65 // Use raw pointer here for the incomplete type object. 66 InstrProfRecordWriterTrait *InfoObj; 67 68 // Temporary support for writing the previous version of the format, to enable 69 // some forward compatibility. Currently this suppresses the writing of the 70 // new vtable names section and header fields. 71 // TODO: Consider enabling this with future version changes as well, to ease 72 // deployment of newer versions of llvm-profdata. 73 bool WritePrevVersion = false; 74 75 // The MemProf version we should write. 76 memprof::IndexedVersion MemProfVersionRequested; 77 78 // Whether to serialize the full schema. 79 bool MemProfFullSchema; 80 81 // Whether to generated random memprof hotness for testing. 82 bool MemprofGenerateRandomHotness; 83 84 public: 85 // For memprof testing, random hotness can be assigned to the contexts if 86 // MemprofGenerateRandomHotness is enabled. The random seed can be either 87 // provided by MemprofGenerateRandomHotnessSeed, or if that is 0, one will be 88 // generated in the writer using the current time. 89 InstrProfWriter(bool Sparse = false, 90 uint64_t TemporalProfTraceReservoirSize = 0, 91 uint64_t MaxTemporalProfTraceLength = 0, 92 bool WritePrevVersion = false, 93 memprof::IndexedVersion MemProfVersionRequested = 94 static_cast<memprof::IndexedVersion>( 95 memprof::MinimumSupportedVersion), 96 bool MemProfFullSchema = false, 97 bool MemprofGenerateRandomHotness = false, 98 unsigned MemprofGenerateRandomHotnessSeed = 0); 99 ~InstrProfWriter(); 100 101 StringMap<ProfilingData> &getProfileData() { return FunctionData; } 102 103 /// Add function counts for the given function. If there are already counts 104 /// for this function and the hash and number of counts match, each counter is 105 /// summed. Optionally scale counts by \p Weight. 106 void addRecord(NamedInstrProfRecord &&I, uint64_t Weight, 107 function_ref<void(Error)> Warn); 108 void addRecord(NamedInstrProfRecord &&I, function_ref<void(Error)> Warn) { 109 addRecord(std::move(I), 1, Warn); 110 } 111 void addVTableName(StringRef VTableName) { VTableNames.insert(VTableName); } 112 113 /// Add \p SrcTraces using reservoir sampling where \p SrcStreamSize is the 114 /// total number of temporal profiling traces the source has seen. 115 void addTemporalProfileTraces(SmallVectorImpl<TemporalProfTraceTy> &SrcTraces, 116 uint64_t SrcStreamSize); 117 118 /// Add the entire MemProfData \p Incoming to the writer context. 119 bool addMemProfData(memprof::IndexedMemProfData Incoming, 120 function_ref<void(Error)> Warn); 121 122 // Add a binary id to the binary ids list. 123 void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs); 124 125 /// Merge existing function counts from the given writer. 126 void mergeRecordsFromWriter(InstrProfWriter &&IPW, 127 function_ref<void(Error)> Warn); 128 129 /// Write the profile to \c OS 130 Error write(raw_fd_ostream &OS); 131 132 /// Write the profile to a string output stream \c OS 133 Error write(raw_string_ostream &OS); 134 135 /// Write the profile in text format to \c OS 136 Error writeText(raw_fd_ostream &OS); 137 138 /// Write temporal profile trace data to the header in text format to \c OS 139 void writeTextTemporalProfTraceData(raw_fd_ostream &OS, 140 InstrProfSymtab &Symtab); 141 142 Error validateRecord(const InstrProfRecord &Func); 143 144 /// Write \c Record in text format to \c OS 145 static void writeRecordInText(StringRef Name, uint64_t Hash, 146 const InstrProfRecord &Counters, 147 InstrProfSymtab &Symtab, raw_fd_ostream &OS); 148 149 /// Write the profile, returning the raw data. For testing. 150 std::unique_ptr<MemoryBuffer> writeBuffer(); 151 152 /// Update the attributes of the current profile from the attributes 153 /// specified. An error is returned if IR and FE profiles are mixed. 154 Error mergeProfileKind(const InstrProfKind Other) { 155 // If the kind is unset, this is the first profile we are merging so just 156 // set it to the given type. 157 if (ProfileKind == InstrProfKind::Unknown) { 158 ProfileKind = Other; 159 return Error::success(); 160 } 161 162 // Returns true if merging is should fail assuming A and B are incompatible. 163 auto testIncompatible = [&](InstrProfKind A, InstrProfKind B) { 164 return (static_cast<bool>(ProfileKind & A) && 165 static_cast<bool>(Other & B)) || 166 (static_cast<bool>(ProfileKind & B) && 167 static_cast<bool>(Other & A)); 168 }; 169 170 // Check if the profiles are in-compatible. Clang frontend profiles can't be 171 // merged with other profile types. 172 if (static_cast<bool>( 173 (ProfileKind & InstrProfKind::FrontendInstrumentation) ^ 174 (Other & InstrProfKind::FrontendInstrumentation))) { 175 return make_error<InstrProfError>(instrprof_error::unsupported_version); 176 } 177 if (testIncompatible(InstrProfKind::FunctionEntryOnly, 178 InstrProfKind::FunctionEntryInstrumentation) || 179 testIncompatible(InstrProfKind::FunctionEntryOnly, 180 InstrProfKind::LoopEntriesInstrumentation)) { 181 return make_error<InstrProfError>( 182 instrprof_error::unsupported_version, 183 "cannot merge FunctionEntryOnly profiles and BB profiles together"); 184 } 185 186 // Now we update the profile type with the bits that are set. 187 ProfileKind |= Other; 188 return Error::success(); 189 } 190 191 InstrProfKind getProfileKind() const { return ProfileKind; } 192 193 bool hasSingleByteCoverage() const { 194 return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage); 195 } 196 197 // Internal interfaces for testing purpose only. 198 void setValueProfDataEndianness(llvm::endianness Endianness); 199 void setOutputSparse(bool Sparse); 200 void setMemProfVersionRequested(memprof::IndexedVersion Version) { 201 MemProfVersionRequested = Version; 202 } 203 void setMemProfFullSchema(bool Full) { MemProfFullSchema = Full; } 204 // Compute the overlap b/w this object and Other. Program level result is 205 // stored in Overlap and function level result is stored in FuncLevelOverlap. 206 void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap, 207 OverlapStats &FuncLevelOverlap, 208 const OverlapFuncFilters &FuncFilter); 209 210 private: 211 void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I, 212 uint64_t Weight, function_ref<void(Error)> Warn); 213 bool shouldEncodeData(const ProfilingData &PD); 214 /// Add \p Trace using reservoir sampling. 215 void addTemporalProfileTrace(TemporalProfTraceTy Trace); 216 217 /// Add a memprof record for a function identified by its \p Id. 218 void addMemProfRecord(const GlobalValue::GUID Id, 219 const memprof::IndexedMemProfRecord &Record); 220 221 /// Add a memprof frame identified by the hash of the contents of the frame in 222 /// \p FrameId. 223 bool addMemProfFrame(const memprof::FrameId, const memprof::Frame &F, 224 function_ref<void(Error)> Warn); 225 226 /// Add a call stack identified by the hash of the contents of the call stack 227 /// in \p CallStack. 228 bool addMemProfCallStack(const memprof::CallStackId CSId, 229 const llvm::SmallVector<memprof::FrameId> &CallStack, 230 function_ref<void(Error)> Warn); 231 232 Error writeImpl(ProfOStream &OS); 233 234 // Writes known header fields and reserves space for fields whose value are 235 // known only after payloads are written. Returns the start byte offset for 236 // back patching. 237 uint64_t writeHeader(const IndexedInstrProf::Header &header, 238 const bool WritePrevVersion, ProfOStream &OS); 239 240 // Writes binary IDs. 241 Error writeBinaryIds(ProfOStream &OS); 242 243 // Writes compressed vtable names to profiles. 244 Error writeVTableNames(ProfOStream &OS); 245 }; 246 247 } // end namespace llvm 248 249 #endif // LLVM_PROFILEDATA_INSTRPROFWRITER_H 250