1*0b57cec5SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements the class that writes LLVM sample profiles. It 10*0b57cec5SDimitry Andric // supports two file formats: text and binary. The textual representation 11*0b57cec5SDimitry Andric // is useful for debugging and testing purposes. The binary representation 12*0b57cec5SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can 13*0b57cec5SDimitry Andric // both be used interchangeably. 14*0b57cec5SDimitry Andric // 15*0b57cec5SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 16*0b57cec5SDimitry Andric // supported formats. 17*0b57cec5SDimitry Andric // 18*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 22*0b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 23*0b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 248bcb0991SDimitry Andric #include "llvm/Support/Compression.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 29*0b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 30*0b57cec5SDimitry Andric #include "llvm/Support/MD5.h" 31*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 32*0b57cec5SDimitry Andric #include <algorithm> 33*0b57cec5SDimitry Andric #include <cstdint> 34*0b57cec5SDimitry Andric #include <memory> 35*0b57cec5SDimitry Andric #include <set> 36*0b57cec5SDimitry Andric #include <system_error> 37*0b57cec5SDimitry Andric #include <utility> 38*0b57cec5SDimitry Andric #include <vector> 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric using namespace llvm; 41*0b57cec5SDimitry Andric using namespace sampleprof; 42*0b57cec5SDimitry Andric 438bcb0991SDimitry Andric std::error_code SampleProfileWriter::writeFuncProfiles( 448bcb0991SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 45*0b57cec5SDimitry Andric // Sort the ProfileMap by total samples. 46*0b57cec5SDimitry Andric typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 47*0b57cec5SDimitry Andric std::vector<NameFunctionSamples> V; 48*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) 49*0b57cec5SDimitry Andric V.push_back(std::make_pair(I.getKey(), &I.second)); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric llvm::stable_sort( 52*0b57cec5SDimitry Andric V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 53*0b57cec5SDimitry Andric if (A.second->getTotalSamples() == B.second->getTotalSamples()) 54*0b57cec5SDimitry Andric return A.first > B.first; 55*0b57cec5SDimitry Andric return A.second->getTotalSamples() > B.second->getTotalSamples(); 56*0b57cec5SDimitry Andric }); 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric for (const auto &I : V) { 598bcb0991SDimitry Andric if (std::error_code EC = writeSample(*I.second)) 60*0b57cec5SDimitry Andric return EC; 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric return sampleprof_error::success; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 658bcb0991SDimitry Andric std::error_code 668bcb0991SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 678bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap)) 688bcb0991SDimitry Andric return EC; 698bcb0991SDimitry Andric 708bcb0991SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap)) 718bcb0991SDimitry Andric return EC; 728bcb0991SDimitry Andric 738bcb0991SDimitry Andric return sampleprof_error::success; 748bcb0991SDimitry Andric } 758bcb0991SDimitry Andric 768bcb0991SDimitry Andric SecHdrTableEntry & 778bcb0991SDimitry Andric SampleProfileWriterExtBinaryBase::getEntryInLayout(SecType Type) { 788bcb0991SDimitry Andric auto SecIt = std::find_if( 798bcb0991SDimitry Andric SectionHdrLayout.begin(), SectionHdrLayout.end(), 808bcb0991SDimitry Andric [=](const auto &Entry) -> bool { return Entry.Type == Type; }); 818bcb0991SDimitry Andric return *SecIt; 828bcb0991SDimitry Andric } 838bcb0991SDimitry Andric 848bcb0991SDimitry Andric /// Return the current position and prepare to use it as the start 858bcb0991SDimitry Andric /// position of a section. 868bcb0991SDimitry Andric uint64_t SampleProfileWriterExtBinaryBase::markSectionStart(SecType Type) { 878bcb0991SDimitry Andric uint64_t SectionStart = OutputStream->tell(); 888bcb0991SDimitry Andric auto &Entry = getEntryInLayout(Type); 898bcb0991SDimitry Andric // Use LocalBuf as a temporary output for writting data. 905ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 918bcb0991SDimitry Andric LocalBufStream.swap(OutputStream); 928bcb0991SDimitry Andric return SectionStart; 938bcb0991SDimitry Andric } 948bcb0991SDimitry Andric 958bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { 968bcb0991SDimitry Andric if (!llvm::zlib::isAvailable()) 978bcb0991SDimitry Andric return sampleprof_error::zlib_unavailable; 988bcb0991SDimitry Andric std::string &UncompressedStrings = 998bcb0991SDimitry Andric static_cast<raw_string_ostream *>(LocalBufStream.get())->str(); 1008bcb0991SDimitry Andric if (UncompressedStrings.size() == 0) 1018bcb0991SDimitry Andric return sampleprof_error::success; 1028bcb0991SDimitry Andric auto &OS = *OutputStream; 1038bcb0991SDimitry Andric SmallString<128> CompressedStrings; 1048bcb0991SDimitry Andric llvm::Error E = zlib::compress(UncompressedStrings, CompressedStrings, 1058bcb0991SDimitry Andric zlib::BestSizeCompression); 1068bcb0991SDimitry Andric if (E) 1078bcb0991SDimitry Andric return sampleprof_error::compress_failed; 1088bcb0991SDimitry Andric encodeULEB128(UncompressedStrings.size(), OS); 1098bcb0991SDimitry Andric encodeULEB128(CompressedStrings.size(), OS); 1108bcb0991SDimitry Andric OS << CompressedStrings.str(); 1118bcb0991SDimitry Andric UncompressedStrings.clear(); 1128bcb0991SDimitry Andric return sampleprof_error::success; 1138bcb0991SDimitry Andric } 1148bcb0991SDimitry Andric 1158bcb0991SDimitry Andric /// Add a new section into section header table. 1168bcb0991SDimitry Andric std::error_code 1178bcb0991SDimitry Andric SampleProfileWriterExtBinaryBase::addNewSection(SecType Type, 1188bcb0991SDimitry Andric uint64_t SectionStart) { 1198bcb0991SDimitry Andric auto Entry = getEntryInLayout(Type); 1205ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) { 1218bcb0991SDimitry Andric LocalBufStream.swap(OutputStream); 1228bcb0991SDimitry Andric if (std::error_code EC = compressAndOutput()) 1238bcb0991SDimitry Andric return EC; 1248bcb0991SDimitry Andric } 1258bcb0991SDimitry Andric SecHdrTable.push_back({Type, Entry.Flags, SectionStart - FileStart, 1268bcb0991SDimitry Andric OutputStream->tell() - SectionStart}); 1278bcb0991SDimitry Andric return sampleprof_error::success; 1288bcb0991SDimitry Andric } 1298bcb0991SDimitry Andric 1308bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::write( 1318bcb0991SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 1328bcb0991SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap)) 1338bcb0991SDimitry Andric return EC; 1348bcb0991SDimitry Andric 1358bcb0991SDimitry Andric std::string LocalBuf; 1368bcb0991SDimitry Andric LocalBufStream = std::make_unique<raw_string_ostream>(LocalBuf); 1378bcb0991SDimitry Andric if (std::error_code EC = writeSections(ProfileMap)) 1388bcb0991SDimitry Andric return EC; 1398bcb0991SDimitry Andric 1408bcb0991SDimitry Andric if (std::error_code EC = writeSecHdrTable()) 1418bcb0991SDimitry Andric return EC; 1428bcb0991SDimitry Andric 1438bcb0991SDimitry Andric return sampleprof_error::success; 1448bcb0991SDimitry Andric } 1458bcb0991SDimitry Andric 1468bcb0991SDimitry Andric std::error_code 1478bcb0991SDimitry Andric SampleProfileWriterExtBinary::writeSample(const FunctionSamples &S) { 1488bcb0991SDimitry Andric uint64_t Offset = OutputStream->tell(); 1498bcb0991SDimitry Andric StringRef Name = S.getName(); 1508bcb0991SDimitry Andric FuncOffsetTable[Name] = Offset - SecLBRProfileStart; 1518bcb0991SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 1528bcb0991SDimitry Andric return writeBody(S); 1538bcb0991SDimitry Andric } 1548bcb0991SDimitry Andric 1558bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeFuncOffsetTable() { 1568bcb0991SDimitry Andric auto &OS = *OutputStream; 1578bcb0991SDimitry Andric 1588bcb0991SDimitry Andric // Write out the table size. 1598bcb0991SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS); 1608bcb0991SDimitry Andric 1618bcb0991SDimitry Andric // Write out FuncOffsetTable. 1628bcb0991SDimitry Andric for (auto entry : FuncOffsetTable) { 1638bcb0991SDimitry Andric writeNameIdx(entry.first); 1648bcb0991SDimitry Andric encodeULEB128(entry.second, OS); 1658bcb0991SDimitry Andric } 1668bcb0991SDimitry Andric return sampleprof_error::success; 1678bcb0991SDimitry Andric } 1688bcb0991SDimitry Andric 1695ffd83dbSDimitry Andric std::error_code SampleProfileWriterExtBinary::writeNameTable() { 1705ffd83dbSDimitry Andric if (!UseMD5) 1715ffd83dbSDimitry Andric return SampleProfileWriterBinary::writeNameTable(); 1725ffd83dbSDimitry Andric 1735ffd83dbSDimitry Andric auto &OS = *OutputStream; 1745ffd83dbSDimitry Andric std::set<StringRef> V; 1755ffd83dbSDimitry Andric stablizeNameTable(V); 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric // Write out the name table. 1785ffd83dbSDimitry Andric encodeULEB128(NameTable.size(), OS); 1795ffd83dbSDimitry Andric for (auto N : V) { 1805ffd83dbSDimitry Andric encodeULEB128(MD5Hash(N), OS); 1815ffd83dbSDimitry Andric } 1825ffd83dbSDimitry Andric return sampleprof_error::success; 1835ffd83dbSDimitry Andric } 1845ffd83dbSDimitry Andric 1858bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinary::writeSections( 1868bcb0991SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 1878bcb0991SDimitry Andric uint64_t SectionStart = markSectionStart(SecProfSummary); 1888bcb0991SDimitry Andric computeSummary(ProfileMap); 1898bcb0991SDimitry Andric if (auto EC = writeSummary()) 1908bcb0991SDimitry Andric return EC; 1918bcb0991SDimitry Andric if (std::error_code EC = addNewSection(SecProfSummary, SectionStart)) 1928bcb0991SDimitry Andric return EC; 1938bcb0991SDimitry Andric 1948bcb0991SDimitry Andric // Generate the name table for all the functions referenced in the profile. 1958bcb0991SDimitry Andric SectionStart = markSectionStart(SecNameTable); 1968bcb0991SDimitry Andric for (const auto &I : ProfileMap) { 1978bcb0991SDimitry Andric addName(I.first()); 1988bcb0991SDimitry Andric addNames(I.second); 1998bcb0991SDimitry Andric } 2008bcb0991SDimitry Andric writeNameTable(); 2018bcb0991SDimitry Andric if (std::error_code EC = addNewSection(SecNameTable, SectionStart)) 2028bcb0991SDimitry Andric return EC; 2038bcb0991SDimitry Andric 2048bcb0991SDimitry Andric SectionStart = markSectionStart(SecLBRProfile); 2058bcb0991SDimitry Andric SecLBRProfileStart = OutputStream->tell(); 2068bcb0991SDimitry Andric if (std::error_code EC = writeFuncProfiles(ProfileMap)) 2078bcb0991SDimitry Andric return EC; 2088bcb0991SDimitry Andric if (std::error_code EC = addNewSection(SecLBRProfile, SectionStart)) 2098bcb0991SDimitry Andric return EC; 2108bcb0991SDimitry Andric 2118bcb0991SDimitry Andric if (ProfSymList && ProfSymList->toCompress()) 2128bcb0991SDimitry Andric setToCompressSection(SecProfileSymbolList); 2138bcb0991SDimitry Andric 2148bcb0991SDimitry Andric SectionStart = markSectionStart(SecProfileSymbolList); 2158bcb0991SDimitry Andric if (ProfSymList && ProfSymList->size() > 0) 2168bcb0991SDimitry Andric if (std::error_code EC = ProfSymList->write(*OutputStream)) 2178bcb0991SDimitry Andric return EC; 2188bcb0991SDimitry Andric if (std::error_code EC = addNewSection(SecProfileSymbolList, SectionStart)) 2198bcb0991SDimitry Andric return EC; 2208bcb0991SDimitry Andric 2218bcb0991SDimitry Andric SectionStart = markSectionStart(SecFuncOffsetTable); 2228bcb0991SDimitry Andric if (std::error_code EC = writeFuncOffsetTable()) 2238bcb0991SDimitry Andric return EC; 2248bcb0991SDimitry Andric if (std::error_code EC = addNewSection(SecFuncOffsetTable, SectionStart)) 2258bcb0991SDimitry Andric return EC; 2268bcb0991SDimitry Andric 2278bcb0991SDimitry Andric return sampleprof_error::success; 2288bcb0991SDimitry Andric } 2298bcb0991SDimitry Andric 230*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write( 231*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 232*0b57cec5SDimitry Andric if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 233*0b57cec5SDimitry Andric return EC; 234*0b57cec5SDimitry Andric if (std::error_code EC = writeFuncOffsetTable()) 235*0b57cec5SDimitry Andric return EC; 236*0b57cec5SDimitry Andric return sampleprof_error::success; 237*0b57cec5SDimitry Andric } 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric /// Write samples to a text file. 240*0b57cec5SDimitry Andric /// 241*0b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of 242*0b57cec5SDimitry Andric /// FunctionSamples::print(). Please don't. The dump functionality is intended 243*0b57cec5SDimitry Andric /// for debugging and has no specified form. 244*0b57cec5SDimitry Andric /// 245*0b57cec5SDimitry Andric /// The format used here is more structured and deliberate because 246*0b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class. 2478bcb0991SDimitry Andric std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) { 248*0b57cec5SDimitry Andric auto &OS = *OutputStream; 249*0b57cec5SDimitry Andric OS << S.getName() << ":" << S.getTotalSamples(); 250*0b57cec5SDimitry Andric if (Indent == 0) 251*0b57cec5SDimitry Andric OS << ":" << S.getHeadSamples(); 252*0b57cec5SDimitry Andric OS << "\n"; 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 255*0b57cec5SDimitry Andric for (const auto &I : SortedSamples.get()) { 256*0b57cec5SDimitry Andric LineLocation Loc = I->first; 257*0b57cec5SDimitry Andric const SampleRecord &Sample = I->second; 258*0b57cec5SDimitry Andric OS.indent(Indent + 1); 259*0b57cec5SDimitry Andric if (Loc.Discriminator == 0) 260*0b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 261*0b57cec5SDimitry Andric else 262*0b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric OS << Sample.getSamples(); 265*0b57cec5SDimitry Andric 2668bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets()) 2678bcb0991SDimitry Andric OS << " " << J.first << ":" << J.second; 268*0b57cec5SDimitry Andric OS << "\n"; 269*0b57cec5SDimitry Andric } 270*0b57cec5SDimitry Andric 271*0b57cec5SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 272*0b57cec5SDimitry Andric S.getCallsiteSamples()); 273*0b57cec5SDimitry Andric Indent += 1; 274*0b57cec5SDimitry Andric for (const auto &I : SortedCallsiteSamples.get()) 275*0b57cec5SDimitry Andric for (const auto &FS : I->second) { 276*0b57cec5SDimitry Andric LineLocation Loc = I->first; 277*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 278*0b57cec5SDimitry Andric OS.indent(Indent); 279*0b57cec5SDimitry Andric if (Loc.Discriminator == 0) 280*0b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 281*0b57cec5SDimitry Andric else 282*0b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 2838bcb0991SDimitry Andric if (std::error_code EC = writeSample(CalleeSamples)) 284*0b57cec5SDimitry Andric return EC; 285*0b57cec5SDimitry Andric } 286*0b57cec5SDimitry Andric Indent -= 1; 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric return sampleprof_error::success; 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 292*0b57cec5SDimitry Andric const auto &ret = NameTable.find(FName); 293*0b57cec5SDimitry Andric if (ret == NameTable.end()) 294*0b57cec5SDimitry Andric return sampleprof_error::truncated_name_table; 295*0b57cec5SDimitry Andric encodeULEB128(ret->second, *OutputStream); 296*0b57cec5SDimitry Andric return sampleprof_error::success; 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric 299*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) { 300*0b57cec5SDimitry Andric NameTable.insert(std::make_pair(FName, 0)); 301*0b57cec5SDimitry Andric } 302*0b57cec5SDimitry Andric 303*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 304*0b57cec5SDimitry Andric // Add all the names in indirect call targets. 305*0b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 306*0b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 307*0b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets()) 308*0b57cec5SDimitry Andric addName(J.first()); 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric // Recursively add all the names for inlined callsites. 312*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 313*0b57cec5SDimitry Andric for (const auto &FS : J.second) { 314*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 315*0b57cec5SDimitry Andric addName(CalleeSamples.getName()); 316*0b57cec5SDimitry Andric addNames(CalleeSamples); 317*0b57cec5SDimitry Andric } 318*0b57cec5SDimitry Andric } 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 321*0b57cec5SDimitry Andric // Sort the names to make NameTable deterministic. 322*0b57cec5SDimitry Andric for (const auto &I : NameTable) 323*0b57cec5SDimitry Andric V.insert(I.first); 324*0b57cec5SDimitry Andric int i = 0; 325*0b57cec5SDimitry Andric for (const StringRef &N : V) 326*0b57cec5SDimitry Andric NameTable[N] = i++; 327*0b57cec5SDimitry Andric } 328*0b57cec5SDimitry Andric 3298bcb0991SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameTable() { 330*0b57cec5SDimitry Andric auto &OS = *OutputStream; 331*0b57cec5SDimitry Andric std::set<StringRef> V; 332*0b57cec5SDimitry Andric stablizeNameTable(V); 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric // Write out the name table. 335*0b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS); 336*0b57cec5SDimitry Andric for (auto N : V) { 337*0b57cec5SDimitry Andric OS << N; 338*0b57cec5SDimitry Andric encodeULEB128(0, OS); 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric return sampleprof_error::success; 341*0b57cec5SDimitry Andric } 342*0b57cec5SDimitry Andric 343*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 344*0b57cec5SDimitry Andric auto &OS = *OutputStream; 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 347*0b57cec5SDimitry Andric auto &OFS = static_cast<raw_fd_ostream &>(OS); 348*0b57cec5SDimitry Andric uint64_t FuncOffsetTableStart = OS.tell(); 349*0b57cec5SDimitry Andric if (OFS.seek(TableOffset) == (uint64_t)-1) 350*0b57cec5SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 351*0b57cec5SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 352*0b57cec5SDimitry Andric Writer.write(FuncOffsetTableStart); 353*0b57cec5SDimitry Andric if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 354*0b57cec5SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // Write out the table size. 357*0b57cec5SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS); 358*0b57cec5SDimitry Andric 359*0b57cec5SDimitry Andric // Write out FuncOffsetTable. 360*0b57cec5SDimitry Andric for (auto entry : FuncOffsetTable) { 361*0b57cec5SDimitry Andric writeNameIdx(entry.first); 362*0b57cec5SDimitry Andric encodeULEB128(entry.second, OS); 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric return sampleprof_error::success; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 368*0b57cec5SDimitry Andric auto &OS = *OutputStream; 369*0b57cec5SDimitry Andric std::set<StringRef> V; 370*0b57cec5SDimitry Andric stablizeNameTable(V); 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric // Write out the name table. 373*0b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS); 374*0b57cec5SDimitry Andric for (auto N : V) { 375*0b57cec5SDimitry Andric encodeULEB128(MD5Hash(N), OS); 376*0b57cec5SDimitry Andric } 377*0b57cec5SDimitry Andric return sampleprof_error::success; 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 3808bcb0991SDimitry Andric std::error_code 3818bcb0991SDimitry Andric SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) { 382*0b57cec5SDimitry Andric auto &OS = *OutputStream; 383*0b57cec5SDimitry Andric // Write file magic identifier. 3848bcb0991SDimitry Andric encodeULEB128(SPMagic(Format), OS); 385*0b57cec5SDimitry Andric encodeULEB128(SPVersion(), OS); 386*0b57cec5SDimitry Andric return sampleprof_error::success; 387*0b57cec5SDimitry Andric } 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader( 390*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 3918bcb0991SDimitry Andric writeMagicIdent(Format); 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric computeSummary(ProfileMap); 394*0b57cec5SDimitry Andric if (auto EC = writeSummary()) 395*0b57cec5SDimitry Andric return EC; 396*0b57cec5SDimitry Andric 397*0b57cec5SDimitry Andric // Generate the name table for all the functions referenced in the profile. 398*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) { 399*0b57cec5SDimitry Andric addName(I.first()); 400*0b57cec5SDimitry Andric addNames(I.second); 401*0b57cec5SDimitry Andric } 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric writeNameTable(); 404*0b57cec5SDimitry Andric return sampleprof_error::success; 405*0b57cec5SDimitry Andric } 406*0b57cec5SDimitry Andric 4078bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressAllSections() { 4088bcb0991SDimitry Andric for (auto &Entry : SectionHdrLayout) 4095ffd83dbSDimitry Andric addSecFlag(Entry, SecCommonFlags::SecFlagCompress); 4108bcb0991SDimitry Andric } 4118bcb0991SDimitry Andric 4128bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::setToCompressSection(SecType Type) { 4135ffd83dbSDimitry Andric addSectionFlag(Type, SecCommonFlags::SecFlagCompress); 4148bcb0991SDimitry Andric } 4158bcb0991SDimitry Andric 4168bcb0991SDimitry Andric void SampleProfileWriterExtBinaryBase::allocSecHdrTable() { 4178bcb0991SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 4188bcb0991SDimitry Andric 4198bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SectionHdrLayout.size())); 4208bcb0991SDimitry Andric SecHdrTableOffset = OutputStream->tell(); 4218bcb0991SDimitry Andric for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 4228bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 4238bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 4248bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 4258bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(-1)); 4268bcb0991SDimitry Andric } 4278bcb0991SDimitry Andric } 4288bcb0991SDimitry Andric 4298bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { 4308bcb0991SDimitry Andric auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); 4318bcb0991SDimitry Andric uint64_t Saved = OutputStream->tell(); 4328bcb0991SDimitry Andric 4338bcb0991SDimitry Andric // Set OutputStream to the location saved in SecHdrTableOffset. 4348bcb0991SDimitry Andric if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) 4358bcb0991SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 4368bcb0991SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 4378bcb0991SDimitry Andric 4388bcb0991SDimitry Andric DenseMap<uint32_t, uint32_t> IndexMap; 4398bcb0991SDimitry Andric for (uint32_t i = 0; i < SecHdrTable.size(); i++) { 4408bcb0991SDimitry Andric IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i}); 4418bcb0991SDimitry Andric } 4428bcb0991SDimitry Andric 4438bcb0991SDimitry Andric // Write the section header table in the order specified in 4448bcb0991SDimitry Andric // SectionHdrLayout. That is the sections order Reader will see. 4458bcb0991SDimitry Andric // Note that the sections order in which Reader expects to read 4468bcb0991SDimitry Andric // may be different from the order in which Writer is able to 4478bcb0991SDimitry Andric // write, so we need to adjust the order in SecHdrTable to be 4488bcb0991SDimitry Andric // consistent with SectionHdrLayout when we write SecHdrTable 4498bcb0991SDimitry Andric // to the memory. 4508bcb0991SDimitry Andric for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { 4518bcb0991SDimitry Andric uint32_t idx = IndexMap[static_cast<uint32_t>(SectionHdrLayout[i].Type)]; 4528bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type)); 4538bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flags)); 4548bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset)); 4558bcb0991SDimitry Andric Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size)); 4568bcb0991SDimitry Andric } 4578bcb0991SDimitry Andric 4588bcb0991SDimitry Andric // Reset OutputStream. 4598bcb0991SDimitry Andric if (OFS.seek(Saved) == (uint64_t)-1) 4608bcb0991SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 4618bcb0991SDimitry Andric 4628bcb0991SDimitry Andric return sampleprof_error::success; 4638bcb0991SDimitry Andric } 4648bcb0991SDimitry Andric 4658bcb0991SDimitry Andric std::error_code SampleProfileWriterExtBinaryBase::writeHeader( 4668bcb0991SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 4678bcb0991SDimitry Andric auto &OS = *OutputStream; 4688bcb0991SDimitry Andric FileStart = OS.tell(); 4698bcb0991SDimitry Andric writeMagicIdent(Format); 4708bcb0991SDimitry Andric 4718bcb0991SDimitry Andric allocSecHdrTable(); 4728bcb0991SDimitry Andric return sampleprof_error::success; 4738bcb0991SDimitry Andric } 4748bcb0991SDimitry Andric 475*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader( 476*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 477*0b57cec5SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 478*0b57cec5SDimitry Andric if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 479*0b57cec5SDimitry Andric return EC; 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric // Reserve a slot for the offset of function offset table. The slot will 482*0b57cec5SDimitry Andric // be populated with the offset of FuncOffsetTable later. 483*0b57cec5SDimitry Andric TableOffset = OutputStream->tell(); 484*0b57cec5SDimitry Andric Writer.write(static_cast<uint64_t>(-2)); 485*0b57cec5SDimitry Andric return sampleprof_error::success; 486*0b57cec5SDimitry Andric } 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() { 489*0b57cec5SDimitry Andric auto &OS = *OutputStream; 490*0b57cec5SDimitry Andric encodeULEB128(Summary->getTotalCount(), OS); 491*0b57cec5SDimitry Andric encodeULEB128(Summary->getMaxCount(), OS); 492*0b57cec5SDimitry Andric encodeULEB128(Summary->getMaxFunctionCount(), OS); 493*0b57cec5SDimitry Andric encodeULEB128(Summary->getNumCounts(), OS); 494*0b57cec5SDimitry Andric encodeULEB128(Summary->getNumFunctions(), OS); 495*0b57cec5SDimitry Andric std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 496*0b57cec5SDimitry Andric encodeULEB128(Entries.size(), OS); 497*0b57cec5SDimitry Andric for (auto Entry : Entries) { 498*0b57cec5SDimitry Andric encodeULEB128(Entry.Cutoff, OS); 499*0b57cec5SDimitry Andric encodeULEB128(Entry.MinCount, OS); 500*0b57cec5SDimitry Andric encodeULEB128(Entry.NumCounts, OS); 501*0b57cec5SDimitry Andric } 502*0b57cec5SDimitry Andric return sampleprof_error::success; 503*0b57cec5SDimitry Andric } 504*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 505*0b57cec5SDimitry Andric auto &OS = *OutputStream; 506*0b57cec5SDimitry Andric 507*0b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(S.getName())) 508*0b57cec5SDimitry Andric return EC; 509*0b57cec5SDimitry Andric 510*0b57cec5SDimitry Andric encodeULEB128(S.getTotalSamples(), OS); 511*0b57cec5SDimitry Andric 512*0b57cec5SDimitry Andric // Emit all the body samples. 513*0b57cec5SDimitry Andric encodeULEB128(S.getBodySamples().size(), OS); 514*0b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 515*0b57cec5SDimitry Andric LineLocation Loc = I.first; 516*0b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 517*0b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 518*0b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 519*0b57cec5SDimitry Andric encodeULEB128(Sample.getSamples(), OS); 520*0b57cec5SDimitry Andric encodeULEB128(Sample.getCallTargets().size(), OS); 5218bcb0991SDimitry Andric for (const auto &J : Sample.getSortedCallTargets()) { 5228bcb0991SDimitry Andric StringRef Callee = J.first; 523*0b57cec5SDimitry Andric uint64_t CalleeSamples = J.second; 524*0b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(Callee)) 525*0b57cec5SDimitry Andric return EC; 526*0b57cec5SDimitry Andric encodeULEB128(CalleeSamples, OS); 527*0b57cec5SDimitry Andric } 528*0b57cec5SDimitry Andric } 529*0b57cec5SDimitry Andric 530*0b57cec5SDimitry Andric // Recursively emit all the callsite samples. 531*0b57cec5SDimitry Andric uint64_t NumCallsites = 0; 532*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 533*0b57cec5SDimitry Andric NumCallsites += J.second.size(); 534*0b57cec5SDimitry Andric encodeULEB128(NumCallsites, OS); 535*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 536*0b57cec5SDimitry Andric for (const auto &FS : J.second) { 537*0b57cec5SDimitry Andric LineLocation Loc = J.first; 538*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 539*0b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 540*0b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 541*0b57cec5SDimitry Andric if (std::error_code EC = writeBody(CalleeSamples)) 542*0b57cec5SDimitry Andric return EC; 543*0b57cec5SDimitry Andric } 544*0b57cec5SDimitry Andric 545*0b57cec5SDimitry Andric return sampleprof_error::success; 546*0b57cec5SDimitry Andric } 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file. 549*0b57cec5SDimitry Andric /// 550*0b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise. 5518bcb0991SDimitry Andric std::error_code 5528bcb0991SDimitry Andric SampleProfileWriterBinary::writeSample(const FunctionSamples &S) { 553*0b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 554*0b57cec5SDimitry Andric return writeBody(S); 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric 557*0b57cec5SDimitry Andric std::error_code 5588bcb0991SDimitry Andric SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) { 559*0b57cec5SDimitry Andric uint64_t Offset = OutputStream->tell(); 560*0b57cec5SDimitry Andric StringRef Name = S.getName(); 561*0b57cec5SDimitry Andric FuncOffsetTable[Name] = Offset; 562*0b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 563*0b57cec5SDimitry Andric return writeBody(S); 564*0b57cec5SDimitry Andric } 565*0b57cec5SDimitry Andric 566*0b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format. 567*0b57cec5SDimitry Andric /// 568*0b57cec5SDimitry Andric /// \param Filename The file to create. 569*0b57cec5SDimitry Andric /// 570*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 571*0b57cec5SDimitry Andric /// 572*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 573*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 574*0b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 575*0b57cec5SDimitry Andric std::error_code EC; 576*0b57cec5SDimitry Andric std::unique_ptr<raw_ostream> OS; 5778bcb0991SDimitry Andric if (Format == SPF_Binary || Format == SPF_Ext_Binary || 5788bcb0991SDimitry Andric Format == SPF_Compact_Binary) 5798bcb0991SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None)); 580*0b57cec5SDimitry Andric else 5818bcb0991SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text)); 582*0b57cec5SDimitry Andric if (EC) 583*0b57cec5SDimitry Andric return EC; 584*0b57cec5SDimitry Andric 585*0b57cec5SDimitry Andric return create(OS, Format); 586*0b57cec5SDimitry Andric } 587*0b57cec5SDimitry Andric 588*0b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format. 589*0b57cec5SDimitry Andric /// 590*0b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to. 591*0b57cec5SDimitry Andric /// 592*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 593*0b57cec5SDimitry Andric /// 594*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 595*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 596*0b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 597*0b57cec5SDimitry Andric SampleProfileFormat Format) { 598*0b57cec5SDimitry Andric std::error_code EC; 599*0b57cec5SDimitry Andric std::unique_ptr<SampleProfileWriter> Writer; 600*0b57cec5SDimitry Andric 601*0b57cec5SDimitry Andric if (Format == SPF_Binary) 602*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterRawBinary(OS)); 6038bcb0991SDimitry Andric else if (Format == SPF_Ext_Binary) 6048bcb0991SDimitry Andric Writer.reset(new SampleProfileWriterExtBinary(OS)); 605*0b57cec5SDimitry Andric else if (Format == SPF_Compact_Binary) 606*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterCompactBinary(OS)); 607*0b57cec5SDimitry Andric else if (Format == SPF_Text) 608*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterText(OS)); 609*0b57cec5SDimitry Andric else if (Format == SPF_GCC) 610*0b57cec5SDimitry Andric EC = sampleprof_error::unsupported_writing_format; 611*0b57cec5SDimitry Andric else 612*0b57cec5SDimitry Andric EC = sampleprof_error::unrecognized_format; 613*0b57cec5SDimitry Andric 614*0b57cec5SDimitry Andric if (EC) 615*0b57cec5SDimitry Andric return EC; 616*0b57cec5SDimitry Andric 6178bcb0991SDimitry Andric Writer->Format = Format; 618*0b57cec5SDimitry Andric return std::move(Writer); 619*0b57cec5SDimitry Andric } 620*0b57cec5SDimitry Andric 621*0b57cec5SDimitry Andric void SampleProfileWriter::computeSummary( 622*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 623*0b57cec5SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 624*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) { 625*0b57cec5SDimitry Andric const FunctionSamples &Profile = I.second; 626*0b57cec5SDimitry Andric Builder.addRecord(Profile); 627*0b57cec5SDimitry Andric } 628*0b57cec5SDimitry Andric Summary = Builder.getSummary(); 629*0b57cec5SDimitry Andric } 630