10b57cec5SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the class that writes LLVM sample profiles. It 100b57cec5SDimitry Andric // supports two file formats: text and binary. The textual representation 110b57cec5SDimitry Andric // is useful for debugging and testing purposes. The binary representation 120b57cec5SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can 130b57cec5SDimitry Andric // both be used interchangeably. 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 160b57cec5SDimitry Andric // supported formats. 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h" 210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 220b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 230b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 248bcb0991SDimitry Andric #include "llvm/Support/Compression.h" 250b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 260b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h" 270b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 280b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 290b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 300b57cec5SDimitry Andric #include "llvm/Support/MD5.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric #include <algorithm> 3306c3fb27SDimitry Andric #include <cmath> 340b57cec5SDimitry Andric #include <cstdint> 350b57cec5SDimitry Andric #include <memory> 360b57cec5SDimitry Andric #include <set> 370b57cec5SDimitry Andric #include <system_error> 380b57cec5SDimitry Andric #include <utility> 390b57cec5SDimitry Andric #include <vector> 400b57cec5SDimitry Andric 4106c3fb27SDimitry Andric #define DEBUG_TYPE "llvm-profdata" 4206c3fb27SDimitry Andric 430b57cec5SDimitry Andric using namespace llvm; 440b57cec5SDimitry Andric using namespace sampleprof; 450b57cec5SDimitry Andric 4606c3fb27SDimitry Andric namespace llvm { 4706c3fb27SDimitry Andric namespace support { 4806c3fb27SDimitry Andric namespace endian { 4906c3fb27SDimitry Andric namespace { 5006c3fb27SDimitry Andric 5106c3fb27SDimitry Andric // Adapter class to llvm::support::endian::Writer for pwrite(). 5206c3fb27SDimitry Andric struct SeekableWriter { 5306c3fb27SDimitry Andric raw_pwrite_stream &OS; 5406c3fb27SDimitry Andric endianness Endian; 5506c3fb27SDimitry Andric SeekableWriter(raw_pwrite_stream &OS, endianness Endian) 5606c3fb27SDimitry Andric : OS(OS), Endian(Endian) {} 5706c3fb27SDimitry Andric 5806c3fb27SDimitry Andric template <typename ValueType> 5906c3fb27SDimitry Andric void pwrite(ValueType Val, size_t Offset) { 6006c3fb27SDimitry Andric std::string StringBuf; 6106c3fb27SDimitry Andric raw_string_ostream SStream(StringBuf); 6206c3fb27SDimitry Andric Writer(SStream, Endian).write(Val); 6306c3fb27SDimitry Andric OS.pwrite(StringBuf.data(), StringBuf.size(), Offset); 6406c3fb27SDimitry Andric } 6506c3fb27SDimitry Andric }; 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric } // namespace 6806c3fb27SDimitry Andric } // namespace endian 6906c3fb27SDimitry Andric } // namespace support 7006c3fb27SDimitry Andric } // namespace llvm 7106c3fb27SDimitry Andric 7206c3fb27SDimitry Andric DefaultFunctionPruningStrategy::DefaultFunctionPruningStrategy( 7306c3fb27SDimitry Andric SampleProfileMap &ProfileMap, size_t OutputSizeLimit) 7406c3fb27SDimitry Andric : FunctionPruningStrategy(ProfileMap, OutputSizeLimit) { 7506c3fb27SDimitry Andric sortFuncProfiles(ProfileMap, SortedFunctions); 7606c3fb27SDimitry Andric } 7706c3fb27SDimitry Andric 7806c3fb27SDimitry Andric void DefaultFunctionPruningStrategy::Erase(size_t CurrentOutputSize) { 7906c3fb27SDimitry Andric double D = (double)OutputSizeLimit / CurrentOutputSize; 8006c3fb27SDimitry Andric size_t NewSize = (size_t)round(ProfileMap.size() * D * D); 8106c3fb27SDimitry Andric size_t NumToRemove = ProfileMap.size() - NewSize; 8206c3fb27SDimitry Andric if (NumToRemove < 1) 8306c3fb27SDimitry Andric NumToRemove = 1; 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric assert(NumToRemove <= SortedFunctions.size()); 865f757f3fSDimitry Andric for (const NameFunctionSamples &E : 875f757f3fSDimitry Andric llvm::drop_begin(SortedFunctions, SortedFunctions.size() - NumToRemove)) 885f757f3fSDimitry Andric ProfileMap.erase(E.first); 8906c3fb27SDimitry Andric SortedFunctions.resize(SortedFunctions.size() - NumToRemove); 9006c3fb27SDimitry Andric } 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric std::error_code SampleProfileWriter::writeWithSizeLimitInternal( 9306c3fb27SDimitry Andric SampleProfileMap &ProfileMap, size_t OutputSizeLimit, 9406c3fb27SDimitry Andric FunctionPruningStrategy *Strategy) { 9506c3fb27SDimitry Andric if (OutputSizeLimit == 0) 9606c3fb27SDimitry Andric return write(ProfileMap); 9706c3fb27SDimitry Andric 9806c3fb27SDimitry Andric size_t OriginalFunctionCount = ProfileMap.size(); 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric std::unique_ptr<raw_ostream> OriginalOutputStream; 10106c3fb27SDimitry Andric OutputStream.swap(OriginalOutputStream); 10206c3fb27SDimitry Andric 10306c3fb27SDimitry Andric size_t IterationCount = 0; 10406c3fb27SDimitry Andric size_t TotalSize; 10506c3fb27SDimitry Andric 10606c3fb27SDimitry Andric SmallVector<char> StringBuffer; 10706c3fb27SDimitry Andric do { 10806c3fb27SDimitry Andric StringBuffer.clear(); 10906c3fb27SDimitry Andric OutputStream.reset(new raw_svector_ostream(StringBuffer)); 11006c3fb27SDimitry Andric if (std::error_code EC = write(ProfileMap)) 11106c3fb27SDimitry Andric return EC; 11206c3fb27SDimitry Andric 11306c3fb27SDimitry Andric TotalSize = StringBuffer.size(); 11406c3fb27SDimitry Andric // On Windows every "\n" is actually written as "\r\n" to disk but not to 11506c3fb27SDimitry Andric // memory buffer, this difference should be added when considering the total 11606c3fb27SDimitry Andric // output size. 11706c3fb27SDimitry Andric #ifdef _WIN32 11806c3fb27SDimitry Andric if (Format == SPF_Text) 11906c3fb27SDimitry Andric TotalSize += LineCount; 12006c3fb27SDimitry Andric #endif 12106c3fb27SDimitry Andric if (TotalSize <= OutputSizeLimit) 12206c3fb27SDimitry Andric break; 12306c3fb27SDimitry Andric 12406c3fb27SDimitry Andric Strategy->Erase(TotalSize); 12506c3fb27SDimitry Andric IterationCount++; 12606c3fb27SDimitry Andric } while (ProfileMap.size() != 0); 12706c3fb27SDimitry Andric 12806c3fb27SDimitry Andric if (ProfileMap.size() == 0) 12906c3fb27SDimitry Andric return sampleprof_error::too_large; 13006c3fb27SDimitry Andric 13106c3fb27SDimitry Andric OutputStream.swap(OriginalOutputStream); 13206c3fb27SDimitry Andric OutputStream->write(StringBuffer.data(), StringBuffer.size()); 13306c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Profile originally has " << OriginalFunctionCount 13406c3fb27SDimitry Andric << " functions, reduced to " << ProfileMap.size() << " in " 13506c3fb27SDimitry Andric << IterationCount << " iterations\n"); 13606c3fb27SDimitry Andric // Silence warning on Release build. 13706c3fb27SDimitry Andric (void)OriginalFunctionCount; 13806c3fb27SDimitry Andric (void)IterationCount; 13906c3fb27SDimitry Andric return sampleprof_error::success; 14006c3fb27SDimitry Andric } 14106c3fb27SDimitry Andric 142349cc55cSDimitry Andric std::error_code 143349cc55cSDimitry Andric SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) { 1440b57cec5SDimitry Andric std::vector<NameFunctionSamples> V; 145349cc55cSDimitry Andric sortFuncProfiles(ProfileMap, V); 1460b57cec5SDimitry Andric for (const auto &I : V) { 1478bcb0991SDimitry Andric if (std::error_code EC = writeSample(*I.second)) 1480b57cec5SDimitry Andric return EC; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric return sampleprof_error::success; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 153349cc55cSDimitry Andric std::error_code SampleProfileWriter::write(const SampleProfileMap &ProfileMap) { 1548bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap)) 1558bcb0991SDimitry Andric return EC; 1568bcb0991SDimitry Andric 1578bcb0991SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap)) 1588bcb0991SDimitry Andric return EC; 1598bcb0991SDimitry Andric 1608bcb0991SDimitry Andric return sampleprof_error::success; 1618bcb0991SDimitry Andric } 1628bcb0991SDimitry Andric 1638bcb0991SDimitry Andric /// Return the current position and prepare to use it as the start 164e8d8bef9SDimitry Andric /// position of a section given the section type \p Type and its position 165e8d8bef9SDimitry Andric /// \p LayoutIdx in SectionHdrLayout. 166e8d8bef9SDimitry Andric uint64_t 167e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type, 168e8d8bef9SDimitry Andric uint32_t LayoutIdx) { 1698bcb0991SDimitry Andric uint64_t SectionStart = OutputStream->tell(); 170e8d8bef9SDimitry Andric assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 171e8d8bef9SDimitry Andric const auto &Entry = SectionHdrLayout[LayoutIdx]; 172e8d8bef9SDimitry Andric assert(Entry.Type == Type && "Unexpected section type"); 1738bcb0991SDimitry Andric // Use LocalBuf as a temporary output for writting data. 1745ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 1758bcb0991SDimitry Andric LocalBufStream.swap(OutputStream); 1768bcb0991SDimitry Andric return SectionStart; 1778bcb0991SDimitry Andric } 1788bcb0991SDimitry Andric 1798bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 180753f127fSDimitry Andric if (!llvm::compression::zlib::isAvailable()) 1818bcb0991SDimitry Andric return sampleprof_error::zlib_unavailable; 1828bcb0991SDimitry Andric std::string &UncompressedStrings = 1838bcb0991SDimitry Andric static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 1848bcb0991SDimitry Andric if (UncompressedStrings.size() == 0) 1858bcb0991SDimitry Andric return sampleprof_error::success; 1868bcb0991SDimitry Andric auto &OS = *OutputStream; 187753f127fSDimitry Andric SmallVector<uint8_t, 128> CompressedStrings; 188753f127fSDimitry Andric compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), 189753f127fSDimitry Andric CompressedStrings, 190753f127fSDimitry Andric compression::zlib::BestSizeCompression); 1918bcb0991SDimitry Andric encodeULEB128(UncompressedStrings.size(), OS); 1928bcb0991SDimitry Andric encodeULEB128(CompressedStrings.size(), OS); 193753f127fSDimitry Andric OS << toStringRef(CompressedStrings); 1948bcb0991SDimitry Andric UncompressedStrings.clear(); 1958bcb0991SDimitry Andric return sampleprof_error::success; 1968bcb0991SDimitry Andric } 1978bcb0991SDimitry Andric 198e8d8bef9SDimitry Andric /// Add a new section into section header table given the section type 199e8d8bef9SDimitry Andric /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the 200e8d8bef9SDimitry Andric /// location \p SectionStart where the section should be written to. 201e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::addNewSection( 202e8d8bef9SDimitry Andric SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) { 203e8d8bef9SDimitry Andric assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); 204e8d8bef9SDimitry Andric const auto &Entry = SectionHdrLayout[LayoutIdx]; 205e8d8bef9SDimitry Andric assert(Entry.Type == Type && "Unexpected section type"); 2065ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) { 2078bcb0991SDimitry Andric LocalBufStream.swap(OutputStream); 2088bcb0991SDimitry Andric if (std::error_code EC = compressAndOutput()) 2098bcb0991SDimitry Andric return EC; 2108bcb0991SDimitry Andric } 2118bcb0991SDimitry Andric SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 212e8d8bef9SDimitry Andric OutputStream->tell() - SectionStart, LayoutIdx}); 2138bcb0991SDimitry Andric return sampleprof_error::success; 2148bcb0991SDimitry Andric } 2158bcb0991SDimitry Andric 216349cc55cSDimitry Andric std::error_code 217349cc55cSDimitry Andric SampleProfileWriterExtBinaryBase::write(const SampleProfileMap &ProfileMap) { 21806c3fb27SDimitry Andric // When calling write on a different profile map, existing states should be 21906c3fb27SDimitry Andric // cleared. 22006c3fb27SDimitry Andric NameTable.clear(); 22106c3fb27SDimitry Andric CSNameTable.clear(); 22206c3fb27SDimitry Andric SecHdrTable.clear(); 22306c3fb27SDimitry Andric 2248bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap)) 2258bcb0991SDimitry Andric return EC; 2268bcb0991SDimitry Andric 2278bcb0991SDimitry Andric std::string LocalBuf; 2288bcb0991SDimitry Andric LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 2298bcb0991SDimitry Andric if (std::error_code EC = writeSections(ProfileMap)) 2308bcb0991SDimitry Andric return EC; 2318bcb0991SDimitry Andric 2328bcb0991SDimitry Andric if (std::error_code EC = writeSecHdrTable()) 2338bcb0991SDimitry Andric return EC; 2348bcb0991SDimitry Andric 2358bcb0991SDimitry Andric return sampleprof_error::success; 2368bcb0991SDimitry Andric } 2378bcb0991SDimitry Andric 238349cc55cSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeContextIdx( 239349cc55cSDimitry Andric const SampleContext &Context) { 240349cc55cSDimitry Andric if (Context.hasContext()) 241349cc55cSDimitry Andric return writeCSNameIdx(Context); 242349cc55cSDimitry Andric else 2435f757f3fSDimitry Andric return SampleProfileWriterBinary::writeNameIdx(Context.getFunction()); 244349cc55cSDimitry Andric } 245349cc55cSDimitry Andric 246349cc55cSDimitry Andric std::error_code 247349cc55cSDimitry Andric SampleProfileWriterExtBinaryBase::writeCSNameIdx(const SampleContext &Context) { 248349cc55cSDimitry Andric const auto &Ret = CSNameTable.find(Context); 249349cc55cSDimitry Andric if (Ret == CSNameTable.end()) 250349cc55cSDimitry Andric return sampleprof_error::truncated_name_table; 251349cc55cSDimitry Andric encodeULEB128(Ret->second, *OutputStream); 252349cc55cSDimitry Andric return sampleprof_error::success; 253349cc55cSDimitry Andric } 254349cc55cSDimitry Andric 2558bcb0991SDimitry Andric std::error_code 256e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) { 2578bcb0991SDimitry Andric uint64_t Offset = OutputStream->tell(); 258349cc55cSDimitry Andric auto &Context = S.getContext(); 259349cc55cSDimitry Andric FuncOffsetTable[Context] = Offset - SecLBRProfileStart; 2608bcb0991SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 2618bcb0991SDimitry Andric return writeBody(S); 2628bcb0991SDimitry Andric } 2638bcb0991SDimitry Andric 264e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() { 2658bcb0991SDimitry Andric auto &OS = *OutputStream; 2668bcb0991SDimitry Andric 2678bcb0991SDimitry Andric // Write out the table size. 2688bcb0991SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS); 2698bcb0991SDimitry Andric 2708bcb0991SDimitry Andric // Write out FuncOffsetTable. 271349cc55cSDimitry Andric auto WriteItem = [&](const SampleContext &Context, uint64_t Offset) { 272349cc55cSDimitry Andric if (std::error_code EC = writeContextIdx(Context)) 273fe6060f1SDimitry Andric return EC; 274349cc55cSDimitry Andric encodeULEB128(Offset, OS); 275349cc55cSDimitry Andric return (std::error_code)sampleprof_error::success; 276349cc55cSDimitry Andric }; 277349cc55cSDimitry Andric 27881ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS) { 279349cc55cSDimitry Andric // Sort the contexts before writing them out. This is to help fast load all 280349cc55cSDimitry Andric // context profiles for a function as well as their callee contexts which 281349cc55cSDimitry Andric // can help profile-guided importing for ThinLTO. 282349cc55cSDimitry Andric std::map<SampleContext, uint64_t> OrderedFuncOffsetTable( 283349cc55cSDimitry Andric FuncOffsetTable.begin(), FuncOffsetTable.end()); 284349cc55cSDimitry Andric for (const auto &Entry : OrderedFuncOffsetTable) { 285349cc55cSDimitry Andric if (std::error_code EC = WriteItem(Entry.first, Entry.second)) 286349cc55cSDimitry Andric return EC; 2878bcb0991SDimitry Andric } 288349cc55cSDimitry Andric addSectionFlag(SecFuncOffsetTable, SecFuncOffsetFlags::SecFlagOrdered); 289349cc55cSDimitry Andric } else { 290349cc55cSDimitry Andric for (const auto &Entry : FuncOffsetTable) { 291349cc55cSDimitry Andric if (std::error_code EC = WriteItem(Entry.first, Entry.second)) 292349cc55cSDimitry Andric return EC; 293349cc55cSDimitry Andric } 294349cc55cSDimitry Andric } 295349cc55cSDimitry Andric 296e8d8bef9SDimitry Andric FuncOffsetTable.clear(); 2978bcb0991SDimitry Andric return sampleprof_error::success; 2988bcb0991SDimitry Andric } 2998bcb0991SDimitry Andric 300e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( 3010eae32dcSDimitry Andric const FunctionSamples &FunctionProfile) { 302e8d8bef9SDimitry Andric auto &OS = *OutputStream; 3030eae32dcSDimitry Andric if (std::error_code EC = writeContextIdx(FunctionProfile.getContext())) 304fe6060f1SDimitry Andric return EC; 3050eae32dcSDimitry Andric 306fe6060f1SDimitry Andric if (FunctionSamples::ProfileIsProbeBased) 3070eae32dcSDimitry Andric encodeULEB128(FunctionProfile.getFunctionHash(), OS); 30881ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined) { 3090eae32dcSDimitry Andric encodeULEB128(FunctionProfile.getContext().getAllAttributes(), OS); 3100eae32dcSDimitry Andric } 3110eae32dcSDimitry Andric 31281ad6265SDimitry Andric if (!FunctionSamples::ProfileIsCS) { 3130eae32dcSDimitry Andric // Recursively emit attributes for all callee samples. 3140eae32dcSDimitry Andric uint64_t NumCallsites = 0; 3150eae32dcSDimitry Andric for (const auto &J : FunctionProfile.getCallsiteSamples()) 3160eae32dcSDimitry Andric NumCallsites += J.second.size(); 3170eae32dcSDimitry Andric encodeULEB128(NumCallsites, OS); 3180eae32dcSDimitry Andric for (const auto &J : FunctionProfile.getCallsiteSamples()) { 3190eae32dcSDimitry Andric for (const auto &FS : J.second) { 3200eae32dcSDimitry Andric LineLocation Loc = J.first; 3210eae32dcSDimitry Andric encodeULEB128(Loc.LineOffset, OS); 3220eae32dcSDimitry Andric encodeULEB128(Loc.Discriminator, OS); 3230eae32dcSDimitry Andric if (std::error_code EC = writeFuncMetadata(FS.second)) 3240eae32dcSDimitry Andric return EC; 3250eae32dcSDimitry Andric } 3260eae32dcSDimitry Andric } 3270eae32dcSDimitry Andric } 3280eae32dcSDimitry Andric 3290eae32dcSDimitry Andric return sampleprof_error::success; 3300eae32dcSDimitry Andric } 3310eae32dcSDimitry Andric 3320eae32dcSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeFuncMetadata( 3330eae32dcSDimitry Andric const SampleProfileMap &Profiles) { 33481ad6265SDimitry Andric if (!FunctionSamples::ProfileIsProbeBased && !FunctionSamples::ProfileIsCS && 33581ad6265SDimitry Andric !FunctionSamples::ProfileIsPreInlined) 3360eae32dcSDimitry Andric return sampleprof_error::success; 3370eae32dcSDimitry Andric for (const auto &Entry : Profiles) { 3380eae32dcSDimitry Andric if (std::error_code EC = writeFuncMetadata(Entry.second)) 3390eae32dcSDimitry Andric return EC; 340e8d8bef9SDimitry Andric } 341e8d8bef9SDimitry Andric return sampleprof_error::success; 342e8d8bef9SDimitry Andric } 343e8d8bef9SDimitry Andric 344e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTable() { 3455ffd83dbSDimitry Andric if (!UseMD5) 3465ffd83dbSDimitry Andric return SampleProfileWriterBinary::writeNameTable(); 3475ffd83dbSDimitry Andric 3485ffd83dbSDimitry Andric auto &OS = *OutputStream; 3495f757f3fSDimitry Andric std::set<FunctionId> V; 350349cc55cSDimitry Andric stablizeNameTable(NameTable, V); 3515ffd83dbSDimitry Andric 352e8d8bef9SDimitry Andric // Write out the MD5 name table. We wrote unencoded MD5 so reader can 353e8d8bef9SDimitry Andric // retrieve the name using the name index without having to read the 354e8d8bef9SDimitry Andric // whole name table. 3555ffd83dbSDimitry Andric encodeULEB128(NameTable.size(), OS); 3565f757f3fSDimitry Andric support::endian::Writer Writer(OS, llvm::endianness::little); 357e8d8bef9SDimitry Andric for (auto N : V) 3585f757f3fSDimitry Andric Writer.write(N.getHashCode()); 359e8d8bef9SDimitry Andric return sampleprof_error::success; 3605ffd83dbSDimitry Andric } 361e8d8bef9SDimitry Andric 362e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeNameTableSection( 363349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) { 364e8d8bef9SDimitry Andric for (const auto &I : ProfileMap) { 365349cc55cSDimitry Andric addContext(I.second.getContext()); 366e8d8bef9SDimitry Andric addNames(I.second); 367e8d8bef9SDimitry Andric } 368fe6060f1SDimitry Andric 369fe6060f1SDimitry Andric // If NameTable contains ".__uniq." suffix, set SecFlagUniqSuffix flag 370fe6060f1SDimitry Andric // so compiler won't strip the suffix during profile matching after 371fe6060f1SDimitry Andric // seeing the flag in the profile. 3725f757f3fSDimitry Andric // Original names are unavailable if using MD5, so this option has no use. 3735f757f3fSDimitry Andric if (!UseMD5) { 374fe6060f1SDimitry Andric for (const auto &I : NameTable) { 3755f757f3fSDimitry Andric if (I.first.stringRef().contains(FunctionSamples::UniqSuffix)) { 376fe6060f1SDimitry Andric addSectionFlag(SecNameTable, SecNameTableFlags::SecFlagUniqSuffix); 377fe6060f1SDimitry Andric break; 378fe6060f1SDimitry Andric } 379fe6060f1SDimitry Andric } 3805f757f3fSDimitry Andric } 381fe6060f1SDimitry Andric 382e8d8bef9SDimitry Andric if (auto EC = writeNameTable()) 383e8d8bef9SDimitry Andric return EC; 384e8d8bef9SDimitry Andric return sampleprof_error::success; 385e8d8bef9SDimitry Andric } 386e8d8bef9SDimitry Andric 387349cc55cSDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeCSNameTableSection() { 388349cc55cSDimitry Andric // Sort the names to make CSNameTable deterministic. 389349cc55cSDimitry Andric std::set<SampleContext> OrderedContexts; 390349cc55cSDimitry Andric for (const auto &I : CSNameTable) 391349cc55cSDimitry Andric OrderedContexts.insert(I.first); 392349cc55cSDimitry Andric assert(OrderedContexts.size() == CSNameTable.size() && 393349cc55cSDimitry Andric "Unmatched ordered and unordered contexts"); 394349cc55cSDimitry Andric uint64_t I = 0; 395349cc55cSDimitry Andric for (auto &Context : OrderedContexts) 396349cc55cSDimitry Andric CSNameTable[Context] = I++; 397349cc55cSDimitry Andric 398349cc55cSDimitry Andric auto &OS = *OutputStream; 399349cc55cSDimitry Andric encodeULEB128(OrderedContexts.size(), OS); 4005f757f3fSDimitry Andric support::endian::Writer Writer(OS, llvm::endianness::little); 401349cc55cSDimitry Andric for (auto Context : OrderedContexts) { 402349cc55cSDimitry Andric auto Frames = Context.getContextFrames(); 403349cc55cSDimitry Andric encodeULEB128(Frames.size(), OS); 404349cc55cSDimitry Andric for (auto &Callsite : Frames) { 4055f757f3fSDimitry Andric if (std::error_code EC = writeNameIdx(Callsite.Func)) 406349cc55cSDimitry Andric return EC; 407349cc55cSDimitry Andric encodeULEB128(Callsite.Location.LineOffset, OS); 408349cc55cSDimitry Andric encodeULEB128(Callsite.Location.Discriminator, OS); 409349cc55cSDimitry Andric } 410349cc55cSDimitry Andric } 411349cc55cSDimitry Andric 412349cc55cSDimitry Andric return sampleprof_error::success; 413349cc55cSDimitry Andric } 414349cc55cSDimitry Andric 415e8d8bef9SDimitry Andric std::error_code 416e8d8bef9SDimitry Andric SampleProfileWriterExtBinaryBase::writeProfileSymbolListSection() { 417e8d8bef9SDimitry Andric if (ProfSymList && ProfSymList->size() > 0) 418e8d8bef9SDimitry Andric if (std::error_code EC = ProfSymList->write(*OutputStream)) 419e8d8bef9SDimitry Andric return EC; 420e8d8bef9SDimitry Andric 421e8d8bef9SDimitry Andric return sampleprof_error::success; 422e8d8bef9SDimitry Andric } 423e8d8bef9SDimitry Andric 424e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeOneSection( 425349cc55cSDimitry Andric SecType Type, uint32_t LayoutIdx, const SampleProfileMap &ProfileMap) { 426e8d8bef9SDimitry Andric // The setting of SecFlagCompress should happen before markSectionStart. 427e8d8bef9SDimitry Andric if (Type == SecProfileSymbolList && ProfSymList && ProfSymList->toCompress()) 428e8d8bef9SDimitry Andric setToCompressSection(SecProfileSymbolList); 429e8d8bef9SDimitry Andric if (Type == SecFuncMetadata && FunctionSamples::ProfileIsProbeBased) 430e8d8bef9SDimitry Andric addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagIsProbeBased); 4310eae32dcSDimitry Andric if (Type == SecFuncMetadata && 43281ad6265SDimitry Andric (FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsPreInlined)) 433fe6060f1SDimitry Andric addSectionFlag(SecFuncMetadata, SecFuncMetadataFlags::SecFlagHasAttribute); 43481ad6265SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsCS) 4350eae32dcSDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFullContext); 43681ad6265SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsPreInlined) 43781ad6265SDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagIsPreInlined); 438fe6060f1SDimitry Andric if (Type == SecProfSummary && FunctionSamples::ProfileIsFS) 439fe6060f1SDimitry Andric addSectionFlag(SecProfSummary, SecProfSummaryFlags::SecFlagFSDiscriminator); 440e8d8bef9SDimitry Andric 441e8d8bef9SDimitry Andric uint64_t SectionStart = markSectionStart(Type, LayoutIdx); 442e8d8bef9SDimitry Andric switch (Type) { 443e8d8bef9SDimitry Andric case SecProfSummary: 444e8d8bef9SDimitry Andric computeSummary(ProfileMap); 445e8d8bef9SDimitry Andric if (auto EC = writeSummary()) 446e8d8bef9SDimitry Andric return EC; 447e8d8bef9SDimitry Andric break; 448e8d8bef9SDimitry Andric case SecNameTable: 449e8d8bef9SDimitry Andric if (auto EC = writeNameTableSection(ProfileMap)) 450e8d8bef9SDimitry Andric return EC; 451e8d8bef9SDimitry Andric break; 452349cc55cSDimitry Andric case SecCSNameTable: 453349cc55cSDimitry Andric if (auto EC = writeCSNameTableSection()) 454349cc55cSDimitry Andric return EC; 455349cc55cSDimitry Andric break; 456e8d8bef9SDimitry Andric case SecLBRProfile: 457e8d8bef9SDimitry Andric SecLBRProfileStart = OutputStream->tell(); 458e8d8bef9SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap)) 459e8d8bef9SDimitry Andric return EC; 460e8d8bef9SDimitry Andric break; 461e8d8bef9SDimitry Andric case SecFuncOffsetTable: 462e8d8bef9SDimitry Andric if (auto EC = writeFuncOffsetTable()) 463e8d8bef9SDimitry Andric return EC; 464e8d8bef9SDimitry Andric break; 465e8d8bef9SDimitry Andric case SecFuncMetadata: 466e8d8bef9SDimitry Andric if (std::error_code EC = writeFuncMetadata(ProfileMap)) 467e8d8bef9SDimitry Andric return EC; 468e8d8bef9SDimitry Andric break; 469e8d8bef9SDimitry Andric case SecProfileSymbolList: 470e8d8bef9SDimitry Andric if (auto EC = writeProfileSymbolListSection()) 471e8d8bef9SDimitry Andric return EC; 472e8d8bef9SDimitry Andric break; 473e8d8bef9SDimitry Andric default: 474e8d8bef9SDimitry Andric if (auto EC = writeCustomSection(Type)) 475e8d8bef9SDimitry Andric return EC; 476e8d8bef9SDimitry Andric break; 477e8d8bef9SDimitry Andric } 478e8d8bef9SDimitry Andric if (std::error_code EC = addNewSection(Type, LayoutIdx, SectionStart)) 479e8d8bef9SDimitry Andric return EC; 480e8d8bef9SDimitry Andric return sampleprof_error::success; 481e8d8bef9SDimitry Andric } 482e8d8bef9SDimitry Andric 483e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeDefaultLayout( 484349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) { 485e8d8bef9SDimitry Andric // The const indices passed to writeOneSection below are specifying the 486e8d8bef9SDimitry Andric // positions of the sections in SectionHdrLayout. Look at 487e8d8bef9SDimitry Andric // initSectionHdrLayout to find out where each section is located in 488e8d8bef9SDimitry Andric // SectionHdrLayout. 489e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 490e8d8bef9SDimitry Andric return EC; 491e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 492e8d8bef9SDimitry Andric return EC; 493349cc55cSDimitry Andric if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap)) 494e8d8bef9SDimitry Andric return EC; 495349cc55cSDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap)) 496e8d8bef9SDimitry Andric return EC; 497349cc55cSDimitry Andric if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap)) 498e8d8bef9SDimitry Andric return EC; 499349cc55cSDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap)) 500349cc55cSDimitry Andric return EC; 501349cc55cSDimitry Andric if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap)) 502e8d8bef9SDimitry Andric return EC; 503e8d8bef9SDimitry Andric return sampleprof_error::success; 504e8d8bef9SDimitry Andric } 505e8d8bef9SDimitry Andric 506349cc55cSDimitry Andric static void splitProfileMapToTwo(const SampleProfileMap &ProfileMap, 507349cc55cSDimitry Andric SampleProfileMap &ContextProfileMap, 508349cc55cSDimitry Andric SampleProfileMap &NoContextProfileMap) { 509e8d8bef9SDimitry Andric for (const auto &I : ProfileMap) { 510e8d8bef9SDimitry Andric if (I.second.getCallsiteSamples().size()) 511349cc55cSDimitry Andric ContextProfileMap.insert({I.first, I.second}); 512e8d8bef9SDimitry Andric else 513349cc55cSDimitry Andric NoContextProfileMap.insert({I.first, I.second}); 514e8d8bef9SDimitry Andric } 515e8d8bef9SDimitry Andric } 516e8d8bef9SDimitry Andric 517e8d8bef9SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout( 518349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) { 519349cc55cSDimitry Andric SampleProfileMap ContextProfileMap, NoContextProfileMap; 520e8d8bef9SDimitry Andric splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap); 521e8d8bef9SDimitry Andric 522e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap)) 523e8d8bef9SDimitry Andric return EC; 524e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap)) 525e8d8bef9SDimitry Andric return EC; 526e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap)) 527e8d8bef9SDimitry Andric return EC; 528e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap)) 529e8d8bef9SDimitry Andric return EC; 530e8d8bef9SDimitry Andric // Mark the section to have no context. Note section flag needs to be set 531e8d8bef9SDimitry Andric // before writing the section. 532e8d8bef9SDimitry Andric addSectionFlag(5, SecCommonFlags::SecFlagFlat); 533e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap)) 534e8d8bef9SDimitry Andric return EC; 535e8d8bef9SDimitry Andric // Mark the section to have no context. Note section flag needs to be set 536e8d8bef9SDimitry Andric // before writing the section. 537e8d8bef9SDimitry Andric addSectionFlag(4, SecCommonFlags::SecFlagFlat); 538e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap)) 539e8d8bef9SDimitry Andric return EC; 540e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap)) 541e8d8bef9SDimitry Andric return EC; 542e8d8bef9SDimitry Andric if (auto EC = writeOneSection(SecFuncMetadata, 7, ProfileMap)) 543e8d8bef9SDimitry Andric return EC; 544e8d8bef9SDimitry Andric 5455ffd83dbSDimitry Andric return sampleprof_error::success; 5465ffd83dbSDimitry Andric } 5475ffd83dbSDimitry Andric 5488bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeSections( 549349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) { 550e8d8bef9SDimitry Andric std::error_code EC; 551e8d8bef9SDimitry Andric if (SecLayout == DefaultLayout) 552e8d8bef9SDimitry Andric EC = writeDefaultLayout(ProfileMap); 553e8d8bef9SDimitry Andric else if (SecLayout == CtxSplitLayout) 554e8d8bef9SDimitry Andric EC = writeCtxSplitLayout(ProfileMap); 555e8d8bef9SDimitry Andric else 556e8d8bef9SDimitry Andric llvm_unreachable("Unsupported layout"); 5578bcb0991SDimitry Andric return EC; 5588bcb0991SDimitry Andric } 5598bcb0991SDimitry Andric 5600b57cec5SDimitry Andric /// Write samples to a text file. 5610b57cec5SDimitry Andric /// 5620b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of 5630b57cec5SDimitry Andric /// FunctionSamples::print(). Please don't. The dump functionality is intended 5640b57cec5SDimitry Andric /// for debugging and has no specified form. 5650b57cec5SDimitry Andric /// 5660b57cec5SDimitry Andric /// The format used here is more structured and deliberate because 5670b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class. 5688bcb0991SDimitry Andric std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 5690b57cec5SDimitry Andric auto &OS = *OutputStream; 57081ad6265SDimitry Andric if (FunctionSamples::ProfileIsCS) 571349cc55cSDimitry Andric OS << "[" << S.getContext().toString() << "]:" << S.getTotalSamples(); 572fe6060f1SDimitry Andric else 5735f757f3fSDimitry Andric OS << S.getFunction() << ":" << S.getTotalSamples(); 574fe6060f1SDimitry Andric 5750b57cec5SDimitry Andric if (Indent == 0) 5760b57cec5SDimitry Andric OS << ":" << S.getHeadSamples(); 5770b57cec5SDimitry Andric OS << "\n"; 57806c3fb27SDimitry Andric LineCount++; 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 5810b57cec5SDimitry Andric for (const auto &I : SortedSamples.get()) { 5820b57cec5SDimitry Andric LineLocation Loc = I->first; 5830b57cec5SDimitry Andric const SampleRecord &Sample = I->second; 5840b57cec5SDimitry Andric OS.indent(Indent + 1); 5850b57cec5SDimitry Andric if (Loc.Discriminator == 0) 5860b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 5870b57cec5SDimitry Andric else 5880b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric OS << Sample.getSamples(); 5910b57cec5SDimitry Andric 5928bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets()) 5938bcb0991SDimitry Andric OS << " " << J.first << ":" << J.second; 5940b57cec5SDimitry Andric OS << "\n"; 59506c3fb27SDimitry Andric LineCount++; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 5990b57cec5SDimitry Andric S.getCallsiteSamples()); 6000b57cec5SDimitry Andric Indent += 1; 6010b57cec5SDimitry Andric for (const auto &I : SortedCallsiteSamples.get()) 6020b57cec5SDimitry Andric for (const auto &FS : I->second) { 6030b57cec5SDimitry Andric LineLocation Loc = I->first; 6040b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 6050b57cec5SDimitry Andric OS.indent(Indent); 6060b57cec5SDimitry Andric if (Loc.Discriminator == 0) 6070b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 6080b57cec5SDimitry Andric else 6090b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 6108bcb0991SDimitry Andric if (std::error_code EC = writeSample(CalleeSamples)) 6110b57cec5SDimitry Andric return EC; 6120b57cec5SDimitry Andric } 6130b57cec5SDimitry Andric Indent -= 1; 6140b57cec5SDimitry Andric 615e8d8bef9SDimitry Andric if (FunctionSamples::ProfileIsProbeBased) { 616e8d8bef9SDimitry Andric OS.indent(Indent + 1); 617e8d8bef9SDimitry Andric OS << "!CFGChecksum: " << S.getFunctionHash() << "\n"; 61806c3fb27SDimitry Andric LineCount++; 619e8d8bef9SDimitry Andric } 6200eae32dcSDimitry Andric 6210eae32dcSDimitry Andric if (S.getContext().getAllAttributes()) { 622fe6060f1SDimitry Andric OS.indent(Indent + 1); 623fe6060f1SDimitry Andric OS << "!Attributes: " << S.getContext().getAllAttributes() << "\n"; 62406c3fb27SDimitry Andric LineCount++; 625fe6060f1SDimitry Andric } 626e8d8bef9SDimitry Andric 6270b57cec5SDimitry Andric return sampleprof_error::success; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 630349cc55cSDimitry Andric std::error_code 631349cc55cSDimitry Andric SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) { 632349cc55cSDimitry Andric assert(!Context.hasContext() && "cs profile is not supported"); 6335f757f3fSDimitry Andric return writeNameIdx(Context.getFunction()); 634fe6060f1SDimitry Andric } 635fe6060f1SDimitry Andric 6365f757f3fSDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(FunctionId FName) { 637349cc55cSDimitry Andric auto &NTable = getNameTable(); 638349cc55cSDimitry Andric const auto &Ret = NTable.find(FName); 639349cc55cSDimitry Andric if (Ret == NTable.end()) 6400b57cec5SDimitry Andric return sampleprof_error::truncated_name_table; 641fe6060f1SDimitry Andric encodeULEB128(Ret->second, *OutputStream); 6420b57cec5SDimitry Andric return sampleprof_error::success; 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric 6455f757f3fSDimitry Andric void SampleProfileWriterBinary::addName(FunctionId FName) { 646349cc55cSDimitry Andric auto &NTable = getNameTable(); 647349cc55cSDimitry Andric NTable.insert(std::make_pair(FName, 0)); 648fe6060f1SDimitry Andric } 649349cc55cSDimitry Andric 650349cc55cSDimitry Andric void SampleProfileWriterBinary::addContext(const SampleContext &Context) { 6515f757f3fSDimitry Andric addName(Context.getFunction()); 6520b57cec5SDimitry Andric } 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 6550b57cec5SDimitry Andric // Add all the names in indirect call targets. 6560b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 6570b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 6580b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets()) 6595f757f3fSDimitry Andric addName(J.first); 6600b57cec5SDimitry Andric } 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric // Recursively add all the names for inlined callsites. 6630b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 6640b57cec5SDimitry Andric for (const auto &FS : J.second) { 6650b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 6665f757f3fSDimitry Andric addName(CalleeSamples.getFunction()); 6670b57cec5SDimitry Andric addNames(CalleeSamples); 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric } 6700b57cec5SDimitry Andric 671349cc55cSDimitry Andric void SampleProfileWriterExtBinaryBase::addContext( 672349cc55cSDimitry Andric const SampleContext &Context) { 673349cc55cSDimitry Andric if (Context.hasContext()) { 674349cc55cSDimitry Andric for (auto &Callsite : Context.getContextFrames()) 6755f757f3fSDimitry Andric SampleProfileWriterBinary::addName(Callsite.Func); 676349cc55cSDimitry Andric CSNameTable.insert(std::make_pair(Context, 0)); 677349cc55cSDimitry Andric } else { 6785f757f3fSDimitry Andric SampleProfileWriterBinary::addName(Context.getFunction()); 679349cc55cSDimitry Andric } 680349cc55cSDimitry Andric } 681349cc55cSDimitry Andric 682349cc55cSDimitry Andric void SampleProfileWriterBinary::stablizeNameTable( 6835f757f3fSDimitry Andric MapVector<FunctionId, uint32_t> &NameTable, std::set<FunctionId> &V) { 6840b57cec5SDimitry Andric // Sort the names to make NameTable deterministic. 6850b57cec5SDimitry Andric for (const auto &I : NameTable) 6860b57cec5SDimitry Andric V.insert(I.first); 6870b57cec5SDimitry Andric int i = 0; 6885f757f3fSDimitry Andric for (const FunctionId &N : V) 6890b57cec5SDimitry Andric NameTable[N] = i++; 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric 6928bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() { 6930b57cec5SDimitry Andric auto &OS = *OutputStream; 6945f757f3fSDimitry Andric std::set<FunctionId> V; 695349cc55cSDimitry Andric stablizeNameTable(NameTable, V); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric // Write out the name table. 6980b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS); 6990b57cec5SDimitry Andric for (auto N : V) { 7000b57cec5SDimitry Andric OS << N; 7010b57cec5SDimitry Andric encodeULEB128(0, OS); 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric return sampleprof_error::success; 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric 7068bcb0991SDimitry Andric std::error_code 7078bcb0991SDimitry Andric SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 7080b57cec5SDimitry Andric auto &OS = *OutputStream; 7090b57cec5SDimitry Andric // Write file magic identifier. 7108bcb0991SDimitry Andric encodeULEB128(SPMagic(Format), OS); 7110b57cec5SDimitry Andric encodeULEB128(SPVersion(), OS); 7120b57cec5SDimitry Andric return sampleprof_error::success; 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric 715349cc55cSDimitry Andric std::error_code 716349cc55cSDimitry Andric SampleProfileWriterBinary::writeHeader(const SampleProfileMap &ProfileMap) { 71706c3fb27SDimitry Andric // When calling write on a different profile map, existing names should be 71806c3fb27SDimitry Andric // cleared. 71906c3fb27SDimitry Andric NameTable.clear(); 72006c3fb27SDimitry Andric 7218bcb0991SDimitry Andric writeMagicIdent(Format); 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric computeSummary(ProfileMap); 7240b57cec5SDimitry Andric if (auto EC = writeSummary()) 7250b57cec5SDimitry Andric return EC; 7260b57cec5SDimitry Andric 7270b57cec5SDimitry Andric // Generate the name table for all the functions referenced in the profile. 7280b57cec5SDimitry Andric for (const auto &I : ProfileMap) { 7295f757f3fSDimitry Andric addContext(I.second.getContext()); 7300b57cec5SDimitry Andric addNames(I.second); 7310b57cec5SDimitry Andric } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric writeNameTable(); 7340b57cec5SDimitry Andric return sampleprof_error::success; 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7378bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 7388bcb0991SDimitry Andric for (auto &Entry : SectionHdrLayout) 7395ffd83dbSDimitry Andric addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 7408bcb0991SDimitry Andric } 7418bcb0991SDimitry Andric 7428bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 7435ffd83dbSDimitry Andric addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 7448bcb0991SDimitry Andric } 7458bcb0991SDimitry Andric 7468bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 7475f757f3fSDimitry Andric support::endian::Writer Writer(*OutputStream, llvm::endianness::little); 7488bcb0991SDimitry Andric 7498bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 7508bcb0991SDimitry Andric SecHdrTableOffset = OutputStream->tell(); 7518bcb0991SDimitry Andric for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 7528bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 7538bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 7548bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 7558bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 7568bcb0991SDimitry Andric } 7578bcb0991SDimitry Andric } 7588bcb0991SDimitry Andric 7598bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 760e8d8bef9SDimitry Andric assert(SecHdrTable.size() == SectionHdrLayout.size() && 761e8d8bef9SDimitry Andric "SecHdrTable entries doesn't match SectionHdrLayout"); 762e8d8bef9SDimitry Andric SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); 763e8d8bef9SDimitry Andric for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { 764e8d8bef9SDimitry Andric IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; 7658bcb0991SDimitry Andric } 7668bcb0991SDimitry Andric 7678bcb0991SDimitry Andric // Write the section header table in the order specified in 768e8d8bef9SDimitry Andric // SectionHdrLayout. SectionHdrLayout specifies the sections 769e8d8bef9SDimitry Andric // order in which profile reader expect to read, so the section 770e8d8bef9SDimitry Andric // header table should be written in the order in SectionHdrLayout. 771e8d8bef9SDimitry Andric // Note that the section order in SecHdrTable may be different 772e8d8bef9SDimitry Andric // from the order in SectionHdrLayout, for example, SecFuncOffsetTable 773e8d8bef9SDimitry Andric // needs to be computed after SecLBRProfile (the order in SecHdrTable), 774e8d8bef9SDimitry Andric // but it needs to be read before SecLBRProfile (the order in 775e8d8bef9SDimitry Andric // SectionHdrLayout). So we use IndexMap above to switch the order. 77606c3fb27SDimitry Andric support::endian::SeekableWriter Writer( 7775f757f3fSDimitry Andric static_cast<raw_pwrite_stream &>(*OutputStream), 7785f757f3fSDimitry Andric llvm::endianness::little); 779e8d8bef9SDimitry Andric for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); 780e8d8bef9SDimitry Andric LayoutIdx++) { 781e8d8bef9SDimitry Andric assert(IndexMap[LayoutIdx] < SecHdrTable.size() && 782e8d8bef9SDimitry Andric "Incorrect LayoutIdx in SecHdrTable"); 783e8d8bef9SDimitry Andric auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; 78406c3fb27SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Type), 78506c3fb27SDimitry Andric SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t)); 78606c3fb27SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Flags), 78706c3fb27SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t)); 78806c3fb27SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Offset), 78906c3fb27SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t)); 79006c3fb27SDimitry Andric Writer.pwrite(static_cast<uint64_t>(Entry.Size), 79106c3fb27SDimitry Andric SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t)); 7928bcb0991SDimitry Andric } 7938bcb0991SDimitry Andric 7948bcb0991SDimitry Andric return sampleprof_error::success; 7958bcb0991SDimitry Andric } 7968bcb0991SDimitry Andric 7978bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 798349cc55cSDimitry Andric const SampleProfileMap &ProfileMap) { 7998bcb0991SDimitry Andric auto &OS = *OutputStream; 8008bcb0991SDimitry Andric FileStart = OS.tell(); 8018bcb0991SDimitry Andric writeMagicIdent(Format); 8028bcb0991SDimitry Andric 8038bcb0991SDimitry Andric allocSecHdrTable(); 8048bcb0991SDimitry Andric return sampleprof_error::success; 8058bcb0991SDimitry Andric } 8068bcb0991SDimitry Andric 8070b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() { 8080b57cec5SDimitry Andric auto &OS = *OutputStream; 8090b57cec5SDimitry Andric encodeULEB128(Summary->getTotalCount(), OS); 8100b57cec5SDimitry Andric encodeULEB128(Summary->getMaxCount(), OS); 8110b57cec5SDimitry Andric encodeULEB128(Summary->getMaxFunctionCount(), OS); 8120b57cec5SDimitry Andric encodeULEB128(Summary->getNumCounts(), OS); 8130b57cec5SDimitry Andric encodeULEB128(Summary->getNumFunctions(), OS); 814*0fca6ea1SDimitry Andric ArrayRef<ProfileSummaryEntry> Entries = Summary->getDetailedSummary(); 8150b57cec5SDimitry Andric encodeULEB128(Entries.size(), OS); 8160b57cec5SDimitry Andric for (auto Entry : Entries) { 8170b57cec5SDimitry Andric encodeULEB128(Entry.Cutoff, OS); 8180b57cec5SDimitry Andric encodeULEB128(Entry.MinCount, OS); 8190b57cec5SDimitry Andric encodeULEB128(Entry.NumCounts, OS); 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric return sampleprof_error::success; 8220b57cec5SDimitry Andric } 8230b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 8240b57cec5SDimitry Andric auto &OS = *OutputStream; 825349cc55cSDimitry Andric if (std::error_code EC = writeContextIdx(S.getContext())) 8260b57cec5SDimitry Andric return EC; 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric encodeULEB128(S.getTotalSamples(), OS); 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric // Emit all the body samples. 8310b57cec5SDimitry Andric encodeULEB128(S.getBodySamples().size(), OS); 8320b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 8330b57cec5SDimitry Andric LineLocation Loc = I.first; 8340b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 8350b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 8360b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 8370b57cec5SDimitry Andric encodeULEB128(Sample.getSamples(), OS); 8380b57cec5SDimitry Andric encodeULEB128(Sample.getCallTargets().size(), OS); 8398bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets()) { 8405f757f3fSDimitry Andric FunctionId Callee = J.first; 8410b57cec5SDimitry Andric uint64_t CalleeSamples = J.second; 8420b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(Callee)) 8430b57cec5SDimitry Andric return EC; 8440b57cec5SDimitry Andric encodeULEB128(CalleeSamples, OS); 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric 8480b57cec5SDimitry Andric // Recursively emit all the callsite samples. 8490b57cec5SDimitry Andric uint64_t NumCallsites = 0; 8500b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 8510b57cec5SDimitry Andric NumCallsites += J.second.size(); 8520b57cec5SDimitry Andric encodeULEB128(NumCallsites, OS); 8530b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 8540b57cec5SDimitry Andric for (const auto &FS : J.second) { 8550b57cec5SDimitry Andric LineLocation Loc = J.first; 8560b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 8570b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 8580b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 8590b57cec5SDimitry Andric if (std::error_code EC = writeBody(CalleeSamples)) 8600b57cec5SDimitry Andric return EC; 8610b57cec5SDimitry Andric } 8620b57cec5SDimitry Andric 8630b57cec5SDimitry Andric return sampleprof_error::success; 8640b57cec5SDimitry Andric } 8650b57cec5SDimitry Andric 8660b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file. 8670b57cec5SDimitry Andric /// 8680b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise. 8698bcb0991SDimitry Andric std::error_code 8708bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 8710b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 8720b57cec5SDimitry Andric return writeBody(S); 8730b57cec5SDimitry Andric } 8740b57cec5SDimitry Andric 8750b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format. 8760b57cec5SDimitry Andric /// 8770b57cec5SDimitry Andric /// \param Filename The file to create. 8780b57cec5SDimitry Andric /// 8790b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 8800b57cec5SDimitry Andric /// 8810b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 8820b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 8830b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 8840b57cec5SDimitry Andric std::error_code EC; 8850b57cec5SDimitry Andric std::unique_ptr<raw_ostream> OS; 88606c3fb27SDimitry Andric if (Format == SPF_Binary || Format == SPF_Ext_Binary) 8878bcb0991SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 8880b57cec5SDimitry Andric else 889fe6060f1SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_TextWithCRLF)); 8900b57cec5SDimitry Andric if (EC) 8910b57cec5SDimitry Andric return EC; 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric return create(OS, Format); 8940b57cec5SDimitry Andric } 8950b57cec5SDimitry Andric 8960b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format. 8970b57cec5SDimitry Andric /// 8980b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to. 8990b57cec5SDimitry Andric /// 9000b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 9010b57cec5SDimitry Andric /// 9020b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 9030b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 9040b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 9050b57cec5SDimitry Andric SampleProfileFormat Format) { 9060b57cec5SDimitry Andric std::error_code EC; 9070b57cec5SDimitry Andric std::unique_ptr<SampleProfileWriter> Writer; 9080b57cec5SDimitry Andric 909fe6060f1SDimitry Andric // Currently only Text and Extended Binary format are supported for CSSPGO. 91081ad6265SDimitry Andric if ((FunctionSamples::ProfileIsCS || FunctionSamples::ProfileIsProbeBased) && 91106c3fb27SDimitry Andric Format == SPF_Binary) 912fe6060f1SDimitry Andric return sampleprof_error::unsupported_writing_format; 913fe6060f1SDimitry Andric 9140b57cec5SDimitry Andric if (Format == SPF_Binary) 9150b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterRawBinary(OS)); 9168bcb0991SDimitry Andric else if (Format == SPF_Ext_Binary) 9178bcb0991SDimitry Andric Writer.reset(new SampleProfileWriterExtBinary(OS)); 9180b57cec5SDimitry Andric else if (Format == SPF_Text) 9190b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterText(OS)); 9200b57cec5SDimitry Andric else if (Format == SPF_GCC) 9210b57cec5SDimitry Andric EC = sampleprof_error::unsupported_writing_format; 9220b57cec5SDimitry Andric else 9230b57cec5SDimitry Andric EC = sampleprof_error::unrecognized_format; 9240b57cec5SDimitry Andric 9250b57cec5SDimitry Andric if (EC) 9260b57cec5SDimitry Andric return EC; 9270b57cec5SDimitry Andric 9288bcb0991SDimitry Andric Writer->Format = Format; 9290b57cec5SDimitry Andric return std::move(Writer); 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric 932349cc55cSDimitry Andric void SampleProfileWriter::computeSummary(const SampleProfileMap &ProfileMap) { 9330b57cec5SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 934d409305fSDimitry Andric Summary = Builder.computeSummaryForProfiles(ProfileMap); 9350b57cec5SDimitry Andric } 936