1 //===- SampleProfWriter.h - Write LLVM sample profile data ------*- 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 definitions needed for writing sample profiles. 10 // 11 //===----------------------------------------------------------------------===// 12 #ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H 13 #define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H 14 15 #include "llvm/ADT/MapVector.h" 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/IR/ProfileSummary.h" 19 #include "llvm/ProfileData/SampleProf.h" 20 #include "llvm/Support/ErrorOr.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <algorithm> 23 #include <cstdint> 24 #include <memory> 25 #include <set> 26 #include <system_error> 27 28 namespace llvm { 29 namespace sampleprof { 30 31 /// Sample-based profile writer. Base class. 32 class SampleProfileWriter { 33 public: 34 virtual ~SampleProfileWriter() = default; 35 36 /// Write sample profiles in \p S. 37 /// 38 /// \returns status code of the file update operation. 39 virtual std::error_code writeSample(const FunctionSamples &S) = 0; 40 41 /// Write all the sample profiles in the given map of samples. 42 /// 43 /// \returns status code of the file update operation. 44 virtual std::error_code write(const StringMap<FunctionSamples> &ProfileMap); 45 46 raw_ostream &getOutputStream() { return *OutputStream; } 47 48 /// Profile writer factory. 49 /// 50 /// Create a new file writer based on the value of \p Format. 51 static ErrorOr<std::unique_ptr<SampleProfileWriter>> 52 create(StringRef Filename, SampleProfileFormat Format); 53 54 /// Create a new stream writer based on the value of \p Format. 55 /// For testing. 56 static ErrorOr<std::unique_ptr<SampleProfileWriter>> 57 create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format); 58 59 virtual void setProfileSymbolList(ProfileSymbolList *PSL) {} 60 virtual void setToCompressAllSections() {} 61 virtual void setUseMD5() {} 62 63 protected: 64 SampleProfileWriter(std::unique_ptr<raw_ostream> &OS) 65 : OutputStream(std::move(OS)) {} 66 67 /// Write a file header for the profile file. 68 virtual std::error_code 69 writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0; 70 71 // Write function profiles to the profile file. 72 virtual std::error_code 73 writeFuncProfiles(const StringMap<FunctionSamples> &ProfileMap); 74 75 /// Output stream where to emit the profile to. 76 std::unique_ptr<raw_ostream> OutputStream; 77 78 /// Profile summary. 79 std::unique_ptr<ProfileSummary> Summary; 80 81 /// Compute summary for this profile. 82 void computeSummary(const StringMap<FunctionSamples> &ProfileMap); 83 84 /// Profile format. 85 SampleProfileFormat Format = SPF_None; 86 }; 87 88 /// Sample-based profile writer (text format). 89 class SampleProfileWriterText : public SampleProfileWriter { 90 public: 91 std::error_code writeSample(const FunctionSamples &S) override; 92 93 protected: 94 SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS) 95 : SampleProfileWriter(OS), Indent(0) {} 96 97 std::error_code 98 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override { 99 return sampleprof_error::success; 100 } 101 102 private: 103 /// Indent level to use when writing. 104 /// 105 /// This is used when printing inlined callees. 106 unsigned Indent; 107 108 friend ErrorOr<std::unique_ptr<SampleProfileWriter>> 109 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 110 SampleProfileFormat Format); 111 }; 112 113 /// Sample-based profile writer (binary format). 114 class SampleProfileWriterBinary : public SampleProfileWriter { 115 public: 116 SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS) 117 : SampleProfileWriter(OS) {} 118 119 virtual std::error_code writeSample(const FunctionSamples &S) override; 120 121 protected: 122 virtual std::error_code writeMagicIdent(SampleProfileFormat Format); 123 virtual std::error_code writeNameTable(); 124 virtual std::error_code 125 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; 126 std::error_code writeSummary(); 127 std::error_code writeNameIdx(StringRef FName); 128 std::error_code writeBody(const FunctionSamples &S); 129 inline void stablizeNameTable(std::set<StringRef> &V); 130 131 MapVector<StringRef, uint32_t> NameTable; 132 133 void addName(StringRef FName); 134 void addNames(const FunctionSamples &S); 135 136 private: 137 friend ErrorOr<std::unique_ptr<SampleProfileWriter>> 138 SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 139 SampleProfileFormat Format); 140 }; 141 142 class SampleProfileWriterRawBinary : public SampleProfileWriterBinary { 143 using SampleProfileWriterBinary::SampleProfileWriterBinary; 144 }; 145 146 class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary { 147 using SampleProfileWriterBinary::SampleProfileWriterBinary; 148 public: 149 virtual std::error_code 150 write(const StringMap<FunctionSamples> &ProfileMap) override; 151 152 virtual void setToCompressAllSections() override; 153 void setToCompressSection(SecType Type); 154 155 protected: 156 uint64_t markSectionStart(SecType Type); 157 std::error_code addNewSection(SecType Sec, uint64_t SectionStart); 158 template <class SecFlagType> 159 void addSectionFlag(SecType Type, SecFlagType Flag) { 160 for (auto &Entry : SectionHdrLayout) { 161 if (Entry.Type == Type) 162 addSecFlag(Entry, Flag); 163 } 164 } 165 166 virtual void initSectionHdrLayout() = 0; 167 virtual std::error_code 168 writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0; 169 170 // Specifiy the order of sections in section header table. Note 171 // the order of sections in the profile may be different that the 172 // order in SectionHdrLayout. sample Reader will follow the order 173 // in SectionHdrLayout to read each section. 174 SmallVector<SecHdrTableEntry, 8> SectionHdrLayout; 175 176 private: 177 void allocSecHdrTable(); 178 std::error_code writeSecHdrTable(); 179 virtual std::error_code 180 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; 181 SecHdrTableEntry &getEntryInLayout(SecType Type); 182 std::error_code compressAndOutput(); 183 184 // We will swap the raw_ostream held by LocalBufStream and that 185 // held by OutputStream if we try to add a section which needs 186 // compression. After the swap, all the data written to output 187 // will be temporarily buffered into the underlying raw_string_ostream 188 // originally held by LocalBufStream. After the data writing for the 189 // section is completed, compress the data in the local buffer, 190 // swap the raw_ostream back and write the compressed data to the 191 // real output. 192 std::unique_ptr<raw_ostream> LocalBufStream; 193 // The location where the output stream starts. 194 uint64_t FileStart; 195 // The location in the output stream where the SecHdrTable should be 196 // written to. 197 uint64_t SecHdrTableOffset; 198 // Initial Section Flags setting. 199 std::vector<SecHdrTableEntry> SecHdrTable; 200 }; 201 202 class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase { 203 public: 204 SampleProfileWriterExtBinary(std::unique_ptr<raw_ostream> &OS) 205 : SampleProfileWriterExtBinaryBase(OS) { 206 initSectionHdrLayout(); 207 } 208 209 virtual std::error_code writeSample(const FunctionSamples &S) override; 210 virtual void setProfileSymbolList(ProfileSymbolList *PSL) override { 211 ProfSymList = PSL; 212 }; 213 214 // Set to use MD5 to represent string in NameTable. 215 virtual void setUseMD5() override { 216 UseMD5 = true; 217 addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagMD5Name); 218 } 219 220 private: 221 virtual void initSectionHdrLayout() override { 222 // Note that SecFuncOffsetTable section is written after SecLBRProfile 223 // in the profile, but is put before SecLBRProfile in SectionHdrLayout. 224 // 225 // This is because sample reader follows the order of SectionHdrLayout to 226 // read each section, to read function profiles on demand sample reader 227 // need to get the offset of each function profile first. 228 // 229 // SecFuncOffsetTable section is written after SecLBRProfile in the 230 // profile because FuncOffsetTable needs to be populated while section 231 // SecLBRProfile is written. 232 SectionHdrLayout = {{SecProfSummary, 0, 0, 0}, 233 {SecNameTable, 0, 0, 0}, 234 {SecFuncOffsetTable, 0, 0, 0}, 235 {SecLBRProfile, 0, 0, 0}, 236 {SecProfileSymbolList, 0, 0, 0}}; 237 }; 238 virtual std::error_code 239 writeSections(const StringMap<FunctionSamples> &ProfileMap) override; 240 241 std::error_code writeFuncOffsetTable(); 242 virtual std::error_code writeNameTable() override; 243 244 ProfileSymbolList *ProfSymList = nullptr; 245 246 // Save the start of SecLBRProfile so we can compute the offset to the 247 // start of SecLBRProfile for each Function's Profile and will keep it 248 // in FuncOffsetTable. 249 uint64_t SecLBRProfileStart = 0; 250 // FuncOffsetTable maps function name to its profile offset in SecLBRProfile 251 // section. It is used to load function profile on demand. 252 MapVector<StringRef, uint64_t> FuncOffsetTable; 253 // Whether to use MD5 to represent string. 254 bool UseMD5 = false; 255 }; 256 257 // CompactBinary is a compact format of binary profile which both reduces 258 // the profile size and the load time needed when compiling. It has two 259 // major difference with Binary format. 260 // 1. It represents all the strings in name table using md5 hash. 261 // 2. It saves a function offset table which maps function name index to 262 // the offset of its function profile to the start of the binary profile, 263 // so by using the function offset table, for those function profiles which 264 // will not be needed when compiling a module, the profile reader does't 265 // have to read them and it saves compile time if the profile size is huge. 266 // The layout of the compact format is shown as follows: 267 // 268 // Part1: Profile header, the same as binary format, containing magic 269 // number, version, summary, name table... 270 // Part2: Function Offset Table Offset, which saves the position of 271 // Part4. 272 // Part3: Function profile collection 273 // function1 profile start 274 // .... 275 // function2 profile start 276 // .... 277 // function3 profile start 278 // .... 279 // ...... 280 // Part4: Function Offset Table 281 // function1 name index --> function1 profile start 282 // function2 name index --> function2 profile start 283 // function3 name index --> function3 profile start 284 // 285 // We need Part2 because profile reader can use it to find out and read 286 // function offset table without reading Part3 first. 287 class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary { 288 using SampleProfileWriterBinary::SampleProfileWriterBinary; 289 290 public: 291 virtual std::error_code writeSample(const FunctionSamples &S) override; 292 virtual std::error_code 293 write(const StringMap<FunctionSamples> &ProfileMap) override; 294 295 protected: 296 /// The table mapping from function name to the offset of its FunctionSample 297 /// towards profile start. 298 MapVector<StringRef, uint64_t> FuncOffsetTable; 299 /// The offset of the slot to be filled with the offset of FuncOffsetTable 300 /// towards profile start. 301 uint64_t TableOffset; 302 virtual std::error_code writeNameTable() override; 303 virtual std::error_code 304 writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; 305 std::error_code writeFuncOffsetTable(); 306 }; 307 308 } // end namespace sampleprof 309 } // end namespace llvm 310 311 #endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H 312