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" 24*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 29*0b57cec5SDimitry Andric #include "llvm/Support/MD5.h" 30*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 31*0b57cec5SDimitry Andric #include <algorithm> 32*0b57cec5SDimitry Andric #include <cstdint> 33*0b57cec5SDimitry Andric #include <memory> 34*0b57cec5SDimitry Andric #include <set> 35*0b57cec5SDimitry Andric #include <system_error> 36*0b57cec5SDimitry Andric #include <utility> 37*0b57cec5SDimitry Andric #include <vector> 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric using namespace llvm; 40*0b57cec5SDimitry Andric using namespace sampleprof; 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric std::error_code 43*0b57cec5SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) { 44*0b57cec5SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap)) 45*0b57cec5SDimitry Andric return EC; 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric // Sort the ProfileMap by total samples. 48*0b57cec5SDimitry Andric typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples; 49*0b57cec5SDimitry Andric std::vector<NameFunctionSamples> V; 50*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) 51*0b57cec5SDimitry Andric V.push_back(std::make_pair(I.getKey(), &I.second)); 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric llvm::stable_sort( 54*0b57cec5SDimitry Andric V, [](const NameFunctionSamples &A, const NameFunctionSamples &B) { 55*0b57cec5SDimitry Andric if (A.second->getTotalSamples() == B.second->getTotalSamples()) 56*0b57cec5SDimitry Andric return A.first > B.first; 57*0b57cec5SDimitry Andric return A.second->getTotalSamples() > B.second->getTotalSamples(); 58*0b57cec5SDimitry Andric }); 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric for (const auto &I : V) { 61*0b57cec5SDimitry Andric if (std::error_code EC = write(*I.second)) 62*0b57cec5SDimitry Andric return EC; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric return sampleprof_error::success; 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write( 68*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 69*0b57cec5SDimitry Andric if (std::error_code EC = SampleProfileWriter::write(ProfileMap)) 70*0b57cec5SDimitry Andric return EC; 71*0b57cec5SDimitry Andric if (std::error_code EC = writeFuncOffsetTable()) 72*0b57cec5SDimitry Andric return EC; 73*0b57cec5SDimitry Andric return sampleprof_error::success; 74*0b57cec5SDimitry Andric } 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric /// Write samples to a text file. 77*0b57cec5SDimitry Andric /// 78*0b57cec5SDimitry Andric /// Note: it may be tempting to implement this in terms of 79*0b57cec5SDimitry Andric /// FunctionSamples::print(). Please don't. The dump functionality is intended 80*0b57cec5SDimitry Andric /// for debugging and has no specified form. 81*0b57cec5SDimitry Andric /// 82*0b57cec5SDimitry Andric /// The format used here is more structured and deliberate because 83*0b57cec5SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class. 84*0b57cec5SDimitry Andric std::error_code SampleProfileWriterText::write(const FunctionSamples &S) { 85*0b57cec5SDimitry Andric auto &OS = *OutputStream; 86*0b57cec5SDimitry Andric OS << S.getName() << ":" << S.getTotalSamples(); 87*0b57cec5SDimitry Andric if (Indent == 0) 88*0b57cec5SDimitry Andric OS << ":" << S.getHeadSamples(); 89*0b57cec5SDimitry Andric OS << "\n"; 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples()); 92*0b57cec5SDimitry Andric for (const auto &I : SortedSamples.get()) { 93*0b57cec5SDimitry Andric LineLocation Loc = I->first; 94*0b57cec5SDimitry Andric const SampleRecord &Sample = I->second; 95*0b57cec5SDimitry Andric OS.indent(Indent + 1); 96*0b57cec5SDimitry Andric if (Loc.Discriminator == 0) 97*0b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 98*0b57cec5SDimitry Andric else 99*0b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric OS << Sample.getSamples(); 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets()) 104*0b57cec5SDimitry Andric OS << " " << J.first() << ":" << J.second; 105*0b57cec5SDimitry Andric OS << "\n"; 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 109*0b57cec5SDimitry Andric S.getCallsiteSamples()); 110*0b57cec5SDimitry Andric Indent += 1; 111*0b57cec5SDimitry Andric for (const auto &I : SortedCallsiteSamples.get()) 112*0b57cec5SDimitry Andric for (const auto &FS : I->second) { 113*0b57cec5SDimitry Andric LineLocation Loc = I->first; 114*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 115*0b57cec5SDimitry Andric OS.indent(Indent); 116*0b57cec5SDimitry Andric if (Loc.Discriminator == 0) 117*0b57cec5SDimitry Andric OS << Loc.LineOffset << ": "; 118*0b57cec5SDimitry Andric else 119*0b57cec5SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 120*0b57cec5SDimitry Andric if (std::error_code EC = write(CalleeSamples)) 121*0b57cec5SDimitry Andric return EC; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric Indent -= 1; 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric return sampleprof_error::success; 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 129*0b57cec5SDimitry Andric const auto &ret = NameTable.find(FName); 130*0b57cec5SDimitry Andric if (ret == NameTable.end()) 131*0b57cec5SDimitry Andric return sampleprof_error::truncated_name_table; 132*0b57cec5SDimitry Andric encodeULEB128(ret->second, *OutputStream); 133*0b57cec5SDimitry Andric return sampleprof_error::success; 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) { 137*0b57cec5SDimitry Andric NameTable.insert(std::make_pair(FName, 0)); 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 141*0b57cec5SDimitry Andric // Add all the names in indirect call targets. 142*0b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 143*0b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 144*0b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets()) 145*0b57cec5SDimitry Andric addName(J.first()); 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric // Recursively add all the names for inlined callsites. 149*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 150*0b57cec5SDimitry Andric for (const auto &FS : J.second) { 151*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 152*0b57cec5SDimitry Andric addName(CalleeSamples.getName()); 153*0b57cec5SDimitry Andric addNames(CalleeSamples); 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric } 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) { 158*0b57cec5SDimitry Andric // Sort the names to make NameTable deterministic. 159*0b57cec5SDimitry Andric for (const auto &I : NameTable) 160*0b57cec5SDimitry Andric V.insert(I.first); 161*0b57cec5SDimitry Andric int i = 0; 162*0b57cec5SDimitry Andric for (const StringRef &N : V) 163*0b57cec5SDimitry Andric NameTable[N] = i++; 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeNameTable() { 167*0b57cec5SDimitry Andric auto &OS = *OutputStream; 168*0b57cec5SDimitry Andric std::set<StringRef> V; 169*0b57cec5SDimitry Andric stablizeNameTable(V); 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric // Write out the name table. 172*0b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS); 173*0b57cec5SDimitry Andric for (auto N : V) { 174*0b57cec5SDimitry Andric OS << N; 175*0b57cec5SDimitry Andric encodeULEB128(0, OS); 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric return sampleprof_error::success; 178*0b57cec5SDimitry Andric } 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { 181*0b57cec5SDimitry Andric auto &OS = *OutputStream; 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. 184*0b57cec5SDimitry Andric auto &OFS = static_cast<raw_fd_ostream &>(OS); 185*0b57cec5SDimitry Andric uint64_t FuncOffsetTableStart = OS.tell(); 186*0b57cec5SDimitry Andric if (OFS.seek(TableOffset) == (uint64_t)-1) 187*0b57cec5SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 188*0b57cec5SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 189*0b57cec5SDimitry Andric Writer.write(FuncOffsetTableStart); 190*0b57cec5SDimitry Andric if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) 191*0b57cec5SDimitry Andric return sampleprof_error::ostream_seek_unsupported; 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric // Write out the table size. 194*0b57cec5SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS); 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric // Write out FuncOffsetTable. 197*0b57cec5SDimitry Andric for (auto entry : FuncOffsetTable) { 198*0b57cec5SDimitry Andric writeNameIdx(entry.first); 199*0b57cec5SDimitry Andric encodeULEB128(entry.second, OS); 200*0b57cec5SDimitry Andric } 201*0b57cec5SDimitry Andric return sampleprof_error::success; 202*0b57cec5SDimitry Andric } 203*0b57cec5SDimitry Andric 204*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() { 205*0b57cec5SDimitry Andric auto &OS = *OutputStream; 206*0b57cec5SDimitry Andric std::set<StringRef> V; 207*0b57cec5SDimitry Andric stablizeNameTable(V); 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric // Write out the name table. 210*0b57cec5SDimitry Andric encodeULEB128(NameTable.size(), OS); 211*0b57cec5SDimitry Andric for (auto N : V) { 212*0b57cec5SDimitry Andric encodeULEB128(MD5Hash(N), OS); 213*0b57cec5SDimitry Andric } 214*0b57cec5SDimitry Andric return sampleprof_error::success; 215*0b57cec5SDimitry Andric } 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeMagicIdent() { 218*0b57cec5SDimitry Andric auto &OS = *OutputStream; 219*0b57cec5SDimitry Andric // Write file magic identifier. 220*0b57cec5SDimitry Andric encodeULEB128(SPMagic(), OS); 221*0b57cec5SDimitry Andric encodeULEB128(SPVersion(), OS); 222*0b57cec5SDimitry Andric return sampleprof_error::success; 223*0b57cec5SDimitry Andric } 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() { 226*0b57cec5SDimitry Andric auto &OS = *OutputStream; 227*0b57cec5SDimitry Andric // Write file magic identifier. 228*0b57cec5SDimitry Andric encodeULEB128(SPMagic(SPF_Compact_Binary), OS); 229*0b57cec5SDimitry Andric encodeULEB128(SPVersion(), OS); 230*0b57cec5SDimitry Andric return sampleprof_error::success; 231*0b57cec5SDimitry Andric } 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader( 234*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 235*0b57cec5SDimitry Andric writeMagicIdent(); 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric computeSummary(ProfileMap); 238*0b57cec5SDimitry Andric if (auto EC = writeSummary()) 239*0b57cec5SDimitry Andric return EC; 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric // Generate the name table for all the functions referenced in the profile. 242*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) { 243*0b57cec5SDimitry Andric addName(I.first()); 244*0b57cec5SDimitry Andric addNames(I.second); 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric writeNameTable(); 248*0b57cec5SDimitry Andric return sampleprof_error::success; 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader( 252*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 253*0b57cec5SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little); 254*0b57cec5SDimitry Andric if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap)) 255*0b57cec5SDimitry Andric return EC; 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric // Reserve a slot for the offset of function offset table. The slot will 258*0b57cec5SDimitry Andric // be populated with the offset of FuncOffsetTable later. 259*0b57cec5SDimitry Andric TableOffset = OutputStream->tell(); 260*0b57cec5SDimitry Andric Writer.write(static_cast<uint64_t>(-2)); 261*0b57cec5SDimitry Andric return sampleprof_error::success; 262*0b57cec5SDimitry Andric } 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() { 265*0b57cec5SDimitry Andric auto &OS = *OutputStream; 266*0b57cec5SDimitry Andric encodeULEB128(Summary->getTotalCount(), OS); 267*0b57cec5SDimitry Andric encodeULEB128(Summary->getMaxCount(), OS); 268*0b57cec5SDimitry Andric encodeULEB128(Summary->getMaxFunctionCount(), OS); 269*0b57cec5SDimitry Andric encodeULEB128(Summary->getNumCounts(), OS); 270*0b57cec5SDimitry Andric encodeULEB128(Summary->getNumFunctions(), OS); 271*0b57cec5SDimitry Andric std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary(); 272*0b57cec5SDimitry Andric encodeULEB128(Entries.size(), OS); 273*0b57cec5SDimitry Andric for (auto Entry : Entries) { 274*0b57cec5SDimitry Andric encodeULEB128(Entry.Cutoff, OS); 275*0b57cec5SDimitry Andric encodeULEB128(Entry.MinCount, OS); 276*0b57cec5SDimitry Andric encodeULEB128(Entry.NumCounts, OS); 277*0b57cec5SDimitry Andric } 278*0b57cec5SDimitry Andric return sampleprof_error::success; 279*0b57cec5SDimitry Andric } 280*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) { 281*0b57cec5SDimitry Andric auto &OS = *OutputStream; 282*0b57cec5SDimitry Andric 283*0b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(S.getName())) 284*0b57cec5SDimitry Andric return EC; 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric encodeULEB128(S.getTotalSamples(), OS); 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric // Emit all the body samples. 289*0b57cec5SDimitry Andric encodeULEB128(S.getBodySamples().size(), OS); 290*0b57cec5SDimitry Andric for (const auto &I : S.getBodySamples()) { 291*0b57cec5SDimitry Andric LineLocation Loc = I.first; 292*0b57cec5SDimitry Andric const SampleRecord &Sample = I.second; 293*0b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 294*0b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 295*0b57cec5SDimitry Andric encodeULEB128(Sample.getSamples(), OS); 296*0b57cec5SDimitry Andric encodeULEB128(Sample.getCallTargets().size(), OS); 297*0b57cec5SDimitry Andric for (const auto &J : Sample.getCallTargets()) { 298*0b57cec5SDimitry Andric StringRef Callee = J.first(); 299*0b57cec5SDimitry Andric uint64_t CalleeSamples = J.second; 300*0b57cec5SDimitry Andric if (std::error_code EC = writeNameIdx(Callee)) 301*0b57cec5SDimitry Andric return EC; 302*0b57cec5SDimitry Andric encodeULEB128(CalleeSamples, OS); 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric } 305*0b57cec5SDimitry Andric 306*0b57cec5SDimitry Andric // Recursively emit all the callsite samples. 307*0b57cec5SDimitry Andric uint64_t NumCallsites = 0; 308*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 309*0b57cec5SDimitry Andric NumCallsites += J.second.size(); 310*0b57cec5SDimitry Andric encodeULEB128(NumCallsites, OS); 311*0b57cec5SDimitry Andric for (const auto &J : S.getCallsiteSamples()) 312*0b57cec5SDimitry Andric for (const auto &FS : J.second) { 313*0b57cec5SDimitry Andric LineLocation Loc = J.first; 314*0b57cec5SDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 315*0b57cec5SDimitry Andric encodeULEB128(Loc.LineOffset, OS); 316*0b57cec5SDimitry Andric encodeULEB128(Loc.Discriminator, OS); 317*0b57cec5SDimitry Andric if (std::error_code EC = writeBody(CalleeSamples)) 318*0b57cec5SDimitry Andric return EC; 319*0b57cec5SDimitry Andric } 320*0b57cec5SDimitry Andric 321*0b57cec5SDimitry Andric return sampleprof_error::success; 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric /// Write samples of a top-level function to a binary file. 325*0b57cec5SDimitry Andric /// 326*0b57cec5SDimitry Andric /// \returns true if the samples were written successfully, false otherwise. 327*0b57cec5SDimitry Andric std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) { 328*0b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 329*0b57cec5SDimitry Andric return writeBody(S); 330*0b57cec5SDimitry Andric } 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric std::error_code 333*0b57cec5SDimitry Andric SampleProfileWriterCompactBinary::write(const FunctionSamples &S) { 334*0b57cec5SDimitry Andric uint64_t Offset = OutputStream->tell(); 335*0b57cec5SDimitry Andric StringRef Name = S.getName(); 336*0b57cec5SDimitry Andric FuncOffsetTable[Name] = Offset; 337*0b57cec5SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream); 338*0b57cec5SDimitry Andric return writeBody(S); 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric /// Create a sample profile file writer based on the specified format. 342*0b57cec5SDimitry Andric /// 343*0b57cec5SDimitry Andric /// \param Filename The file to create. 344*0b57cec5SDimitry Andric /// 345*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 346*0b57cec5SDimitry Andric /// 347*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 348*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 349*0b57cec5SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 350*0b57cec5SDimitry Andric std::error_code EC; 351*0b57cec5SDimitry Andric std::unique_ptr<raw_ostream> OS; 352*0b57cec5SDimitry Andric if (Format == SPF_Binary || Format == SPF_Compact_Binary) 353*0b57cec5SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None)); 354*0b57cec5SDimitry Andric else 355*0b57cec5SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text)); 356*0b57cec5SDimitry Andric if (EC) 357*0b57cec5SDimitry Andric return EC; 358*0b57cec5SDimitry Andric 359*0b57cec5SDimitry Andric return create(OS, Format); 360*0b57cec5SDimitry Andric } 361*0b57cec5SDimitry Andric 362*0b57cec5SDimitry Andric /// Create a sample profile stream writer based on the specified format. 363*0b57cec5SDimitry Andric /// 364*0b57cec5SDimitry Andric /// \param OS The output stream to store the profile data to. 365*0b57cec5SDimitry Andric /// 366*0b57cec5SDimitry Andric /// \param Format Encoding format for the profile file. 367*0b57cec5SDimitry Andric /// 368*0b57cec5SDimitry Andric /// \returns an error code indicating the status of the created writer. 369*0b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>> 370*0b57cec5SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, 371*0b57cec5SDimitry Andric SampleProfileFormat Format) { 372*0b57cec5SDimitry Andric std::error_code EC; 373*0b57cec5SDimitry Andric std::unique_ptr<SampleProfileWriter> Writer; 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric if (Format == SPF_Binary) 376*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterRawBinary(OS)); 377*0b57cec5SDimitry Andric else if (Format == SPF_Compact_Binary) 378*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterCompactBinary(OS)); 379*0b57cec5SDimitry Andric else if (Format == SPF_Text) 380*0b57cec5SDimitry Andric Writer.reset(new SampleProfileWriterText(OS)); 381*0b57cec5SDimitry Andric else if (Format == SPF_GCC) 382*0b57cec5SDimitry Andric EC = sampleprof_error::unsupported_writing_format; 383*0b57cec5SDimitry Andric else 384*0b57cec5SDimitry Andric EC = sampleprof_error::unrecognized_format; 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric if (EC) 387*0b57cec5SDimitry Andric return EC; 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric return std::move(Writer); 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric void SampleProfileWriter::computeSummary( 393*0b57cec5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) { 394*0b57cec5SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 395*0b57cec5SDimitry Andric for (const auto &I : ProfileMap) { 396*0b57cec5SDimitry Andric const FunctionSamples &Profile = I.second; 397*0b57cec5SDimitry Andric Builder.addRecord(Profile); 398*0b57cec5SDimitry Andric } 399*0b57cec5SDimitry Andric Summary = Builder.getSummary(); 400*0b57cec5SDimitry Andric } 401