139d628a0SDimitry Andric //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
239d628a0SDimitry Andric //
339d628a0SDimitry Andric // The LLVM Compiler Infrastructure
439d628a0SDimitry Andric //
539d628a0SDimitry Andric // This file is distributed under the University of Illinois Open Source
639d628a0SDimitry Andric // License. See LICENSE.TXT for details.
739d628a0SDimitry Andric //
839d628a0SDimitry Andric //===----------------------------------------------------------------------===//
939d628a0SDimitry Andric //
1039d628a0SDimitry Andric // This file implements the class that writes LLVM sample profiles. It
1139d628a0SDimitry Andric // supports two file formats: text and binary. The textual representation
1239d628a0SDimitry Andric // is useful for debugging and testing purposes. The binary representation
1339d628a0SDimitry Andric // is more compact, resulting in smaller file sizes. However, they can
1439d628a0SDimitry Andric // both be used interchangeably.
1539d628a0SDimitry Andric //
1639d628a0SDimitry Andric // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
1739d628a0SDimitry Andric // supported formats.
1839d628a0SDimitry Andric //
1939d628a0SDimitry Andric //===----------------------------------------------------------------------===//
2039d628a0SDimitry Andric
21db17bf38SDimitry Andric #include "llvm/ProfileData/SampleProfWriter.h"
227a7e6055SDimitry Andric #include "llvm/ADT/StringRef.h"
237a7e6055SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h"
247a7e6055SDimitry Andric #include "llvm/ProfileData/SampleProf.h"
25*b5893f02SDimitry Andric #include "llvm/Support/Endian.h"
26*b5893f02SDimitry Andric #include "llvm/Support/EndianStream.h"
2739d628a0SDimitry Andric #include "llvm/Support/ErrorOr.h"
287a7e6055SDimitry Andric #include "llvm/Support/FileSystem.h"
2939d628a0SDimitry Andric #include "llvm/Support/LEB128.h"
304ba319b5SDimitry Andric #include "llvm/Support/MD5.h"
317a7e6055SDimitry Andric #include "llvm/Support/raw_ostream.h"
327a7e6055SDimitry Andric #include <algorithm>
337a7e6055SDimitry Andric #include <cstdint>
347a7e6055SDimitry Andric #include <memory>
355517e702SDimitry Andric #include <set>
367a7e6055SDimitry Andric #include <system_error>
377a7e6055SDimitry Andric #include <utility>
387a7e6055SDimitry Andric #include <vector>
3939d628a0SDimitry Andric
4039d628a0SDimitry Andric using namespace llvm;
417a7e6055SDimitry Andric using namespace sampleprof;
4239d628a0SDimitry Andric
435517e702SDimitry Andric std::error_code
write(const StringMap<FunctionSamples> & ProfileMap)445517e702SDimitry Andric SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
455517e702SDimitry Andric if (std::error_code EC = writeHeader(ProfileMap))
465517e702SDimitry Andric return EC;
475517e702SDimitry Andric
485517e702SDimitry Andric // Sort the ProfileMap by total samples.
495517e702SDimitry Andric typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
505517e702SDimitry Andric std::vector<NameFunctionSamples> V;
515517e702SDimitry Andric for (const auto &I : ProfileMap)
525517e702SDimitry Andric V.push_back(std::make_pair(I.getKey(), &I.second));
535517e702SDimitry Andric
545517e702SDimitry Andric std::stable_sort(
555517e702SDimitry Andric V.begin(), V.end(),
565517e702SDimitry Andric [](const NameFunctionSamples &A, const NameFunctionSamples &B) {
575517e702SDimitry Andric if (A.second->getTotalSamples() == B.second->getTotalSamples())
585517e702SDimitry Andric return A.first > B.first;
595517e702SDimitry Andric return A.second->getTotalSamples() > B.second->getTotalSamples();
605517e702SDimitry Andric });
615517e702SDimitry Andric
625517e702SDimitry Andric for (const auto &I : V) {
635517e702SDimitry Andric if (std::error_code EC = write(*I.second))
645517e702SDimitry Andric return EC;
655517e702SDimitry Andric }
665517e702SDimitry Andric return sampleprof_error::success;
675517e702SDimitry Andric }
685517e702SDimitry Andric
write(const StringMap<FunctionSamples> & ProfileMap)69*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::write(
70*b5893f02SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) {
71*b5893f02SDimitry Andric if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
72*b5893f02SDimitry Andric return EC;
73*b5893f02SDimitry Andric if (std::error_code EC = writeFuncOffsetTable())
74*b5893f02SDimitry Andric return EC;
75*b5893f02SDimitry Andric return sampleprof_error::success;
76*b5893f02SDimitry Andric }
77*b5893f02SDimitry Andric
784ba319b5SDimitry Andric /// Write samples to a text file.
797d523365SDimitry Andric ///
807d523365SDimitry Andric /// Note: it may be tempting to implement this in terms of
817d523365SDimitry Andric /// FunctionSamples::print(). Please don't. The dump functionality is intended
827d523365SDimitry Andric /// for debugging and has no specified form.
837d523365SDimitry Andric ///
847d523365SDimitry Andric /// The format used here is more structured and deliberate because
857d523365SDimitry Andric /// it needs to be parsed by the SampleProfileReaderText class.
write(const FunctionSamples & S)863ca95b02SDimitry Andric std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
877d523365SDimitry Andric auto &OS = *OutputStream;
883ca95b02SDimitry Andric OS << S.getName() << ":" << S.getTotalSamples();
897d523365SDimitry Andric if (Indent == 0)
907d523365SDimitry Andric OS << ":" << S.getHeadSamples();
917d523365SDimitry Andric OS << "\n";
9239d628a0SDimitry Andric
937d523365SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedSamples(S.getBodySamples());
947d523365SDimitry Andric for (const auto &I : SortedSamples.get()) {
957d523365SDimitry Andric LineLocation Loc = I->first;
967d523365SDimitry Andric const SampleRecord &Sample = I->second;
977d523365SDimitry Andric OS.indent(Indent + 1);
9839d628a0SDimitry Andric if (Loc.Discriminator == 0)
9939d628a0SDimitry Andric OS << Loc.LineOffset << ": ";
10039d628a0SDimitry Andric else
10139d628a0SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
10239d628a0SDimitry Andric
10339d628a0SDimitry Andric OS << Sample.getSamples();
10439d628a0SDimitry Andric
10539d628a0SDimitry Andric for (const auto &J : Sample.getCallTargets())
10639d628a0SDimitry Andric OS << " " << J.first() << ":" << J.second;
10739d628a0SDimitry Andric OS << "\n";
10839d628a0SDimitry Andric }
10939d628a0SDimitry Andric
1107a7e6055SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples(
1117d523365SDimitry Andric S.getCallsiteSamples());
1127d523365SDimitry Andric Indent += 1;
1137a7e6055SDimitry Andric for (const auto &I : SortedCallsiteSamples.get())
1147a7e6055SDimitry Andric for (const auto &FS : I->second) {
1153ca95b02SDimitry Andric LineLocation Loc = I->first;
1167a7e6055SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
1177d523365SDimitry Andric OS.indent(Indent);
1187d523365SDimitry Andric if (Loc.Discriminator == 0)
1197d523365SDimitry Andric OS << Loc.LineOffset << ": ";
1207d523365SDimitry Andric else
1217d523365SDimitry Andric OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
1223ca95b02SDimitry Andric if (std::error_code EC = write(CalleeSamples))
1237d523365SDimitry Andric return EC;
1247d523365SDimitry Andric }
1257d523365SDimitry Andric Indent -= 1;
1267d523365SDimitry Andric
1277d523365SDimitry Andric return sampleprof_error::success;
12839d628a0SDimitry Andric }
12939d628a0SDimitry Andric
writeNameIdx(StringRef FName)1307d523365SDimitry Andric std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
1317d523365SDimitry Andric const auto &ret = NameTable.find(FName);
1327d523365SDimitry Andric if (ret == NameTable.end())
1337d523365SDimitry Andric return sampleprof_error::truncated_name_table;
1347d523365SDimitry Andric encodeULEB128(ret->second, *OutputStream);
1357d523365SDimitry Andric return sampleprof_error::success;
1367d523365SDimitry Andric }
13739d628a0SDimitry Andric
addName(StringRef FName)1387d523365SDimitry Andric void SampleProfileWriterBinary::addName(StringRef FName) {
1395517e702SDimitry Andric NameTable.insert(std::make_pair(FName, 0));
1407d523365SDimitry Andric }
1417d523365SDimitry Andric
addNames(const FunctionSamples & S)1427d523365SDimitry Andric void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
1437d523365SDimitry Andric // Add all the names in indirect call targets.
1447d523365SDimitry Andric for (const auto &I : S.getBodySamples()) {
1457d523365SDimitry Andric const SampleRecord &Sample = I.second;
1467d523365SDimitry Andric for (const auto &J : Sample.getCallTargets())
1477d523365SDimitry Andric addName(J.first());
1487d523365SDimitry Andric }
1497d523365SDimitry Andric
1507d523365SDimitry Andric // Recursively add all the names for inlined callsites.
1517a7e6055SDimitry Andric for (const auto &J : S.getCallsiteSamples())
1527a7e6055SDimitry Andric for (const auto &FS : J.second) {
1537a7e6055SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
1543ca95b02SDimitry Andric addName(CalleeSamples.getName());
1557d523365SDimitry Andric addNames(CalleeSamples);
1567d523365SDimitry Andric }
1577d523365SDimitry Andric }
1587d523365SDimitry Andric
stablizeNameTable(std::set<StringRef> & V)1594ba319b5SDimitry Andric void SampleProfileWriterBinary::stablizeNameTable(std::set<StringRef> &V) {
1604ba319b5SDimitry Andric // Sort the names to make NameTable deterministic.
1614ba319b5SDimitry Andric for (const auto &I : NameTable)
1624ba319b5SDimitry Andric V.insert(I.first);
1634ba319b5SDimitry Andric int i = 0;
1644ba319b5SDimitry Andric for (const StringRef &N : V)
1654ba319b5SDimitry Andric NameTable[N] = i++;
1664ba319b5SDimitry Andric }
1677d523365SDimitry Andric
writeNameTable()1684ba319b5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeNameTable() {
1694ba319b5SDimitry Andric auto &OS = *OutputStream;
1704ba319b5SDimitry Andric std::set<StringRef> V;
1714ba319b5SDimitry Andric stablizeNameTable(V);
1724ba319b5SDimitry Andric
1734ba319b5SDimitry Andric // Write out the name table.
1744ba319b5SDimitry Andric encodeULEB128(NameTable.size(), OS);
1754ba319b5SDimitry Andric for (auto N : V) {
1764ba319b5SDimitry Andric OS << N;
1774ba319b5SDimitry Andric encodeULEB128(0, OS);
1784ba319b5SDimitry Andric }
1794ba319b5SDimitry Andric return sampleprof_error::success;
1804ba319b5SDimitry Andric }
1814ba319b5SDimitry Andric
writeFuncOffsetTable()182*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() {
183*b5893f02SDimitry Andric auto &OS = *OutputStream;
184*b5893f02SDimitry Andric
185*b5893f02SDimitry Andric // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable.
186*b5893f02SDimitry Andric auto &OFS = static_cast<raw_fd_ostream &>(OS);
187*b5893f02SDimitry Andric uint64_t FuncOffsetTableStart = OS.tell();
188*b5893f02SDimitry Andric if (OFS.seek(TableOffset) == (uint64_t)-1)
189*b5893f02SDimitry Andric return sampleprof_error::ostream_seek_unsupported;
190*b5893f02SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little);
191*b5893f02SDimitry Andric Writer.write(FuncOffsetTableStart);
192*b5893f02SDimitry Andric if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1)
193*b5893f02SDimitry Andric return sampleprof_error::ostream_seek_unsupported;
194*b5893f02SDimitry Andric
195*b5893f02SDimitry Andric // Write out the table size.
196*b5893f02SDimitry Andric encodeULEB128(FuncOffsetTable.size(), OS);
197*b5893f02SDimitry Andric
198*b5893f02SDimitry Andric // Write out FuncOffsetTable.
199*b5893f02SDimitry Andric for (auto entry : FuncOffsetTable) {
200*b5893f02SDimitry Andric writeNameIdx(entry.first);
201*b5893f02SDimitry Andric encodeULEB128(entry.second, OS);
202*b5893f02SDimitry Andric }
203*b5893f02SDimitry Andric return sampleprof_error::success;
204*b5893f02SDimitry Andric }
205*b5893f02SDimitry Andric
writeNameTable()2064ba319b5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeNameTable() {
2074ba319b5SDimitry Andric auto &OS = *OutputStream;
2084ba319b5SDimitry Andric std::set<StringRef> V;
2094ba319b5SDimitry Andric stablizeNameTable(V);
2104ba319b5SDimitry Andric
2114ba319b5SDimitry Andric // Write out the name table.
2124ba319b5SDimitry Andric encodeULEB128(NameTable.size(), OS);
2134ba319b5SDimitry Andric for (auto N : V) {
2144ba319b5SDimitry Andric encodeULEB128(MD5Hash(N), OS);
2154ba319b5SDimitry Andric }
2164ba319b5SDimitry Andric return sampleprof_error::success;
2174ba319b5SDimitry Andric }
2184ba319b5SDimitry Andric
writeMagicIdent()2194ba319b5SDimitry Andric std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
2204ba319b5SDimitry Andric auto &OS = *OutputStream;
2217d523365SDimitry Andric // Write file magic identifier.
22239d628a0SDimitry Andric encodeULEB128(SPMagic(), OS);
22339d628a0SDimitry Andric encodeULEB128(SPVersion(), OS);
2244ba319b5SDimitry Andric return sampleprof_error::success;
2254ba319b5SDimitry Andric }
2264ba319b5SDimitry Andric
writeMagicIdent()2274ba319b5SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
2284ba319b5SDimitry Andric auto &OS = *OutputStream;
2294ba319b5SDimitry Andric // Write file magic identifier.
2304ba319b5SDimitry Andric encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
2314ba319b5SDimitry Andric encodeULEB128(SPVersion(), OS);
2324ba319b5SDimitry Andric return sampleprof_error::success;
2334ba319b5SDimitry Andric }
2344ba319b5SDimitry Andric
writeHeader(const StringMap<FunctionSamples> & ProfileMap)2354ba319b5SDimitry Andric std::error_code SampleProfileWriterBinary::writeHeader(
2364ba319b5SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) {
2374ba319b5SDimitry Andric writeMagicIdent();
2387d523365SDimitry Andric
2393ca95b02SDimitry Andric computeSummary(ProfileMap);
2403ca95b02SDimitry Andric if (auto EC = writeSummary())
2413ca95b02SDimitry Andric return EC;
2423ca95b02SDimitry Andric
2437d523365SDimitry Andric // Generate the name table for all the functions referenced in the profile.
2447d523365SDimitry Andric for (const auto &I : ProfileMap) {
2457d523365SDimitry Andric addName(I.first());
2467d523365SDimitry Andric addNames(I.second);
24739d628a0SDimitry Andric }
24839d628a0SDimitry Andric
2494ba319b5SDimitry Andric writeNameTable();
2507d523365SDimitry Andric return sampleprof_error::success;
2517d523365SDimitry Andric }
2527d523365SDimitry Andric
writeHeader(const StringMap<FunctionSamples> & ProfileMap)253*b5893f02SDimitry Andric std::error_code SampleProfileWriterCompactBinary::writeHeader(
254*b5893f02SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) {
255*b5893f02SDimitry Andric support::endian::Writer Writer(*OutputStream, support::little);
256*b5893f02SDimitry Andric if (auto EC = SampleProfileWriterBinary::writeHeader(ProfileMap))
257*b5893f02SDimitry Andric return EC;
258*b5893f02SDimitry Andric
259*b5893f02SDimitry Andric // Reserve a slot for the offset of function offset table. The slot will
260*b5893f02SDimitry Andric // be populated with the offset of FuncOffsetTable later.
261*b5893f02SDimitry Andric TableOffset = OutputStream->tell();
262*b5893f02SDimitry Andric Writer.write(static_cast<uint64_t>(-2));
263*b5893f02SDimitry Andric return sampleprof_error::success;
264*b5893f02SDimitry Andric }
265*b5893f02SDimitry Andric
writeSummary()2663ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::writeSummary() {
2673ca95b02SDimitry Andric auto &OS = *OutputStream;
2683ca95b02SDimitry Andric encodeULEB128(Summary->getTotalCount(), OS);
2693ca95b02SDimitry Andric encodeULEB128(Summary->getMaxCount(), OS);
2703ca95b02SDimitry Andric encodeULEB128(Summary->getMaxFunctionCount(), OS);
2713ca95b02SDimitry Andric encodeULEB128(Summary->getNumCounts(), OS);
2723ca95b02SDimitry Andric encodeULEB128(Summary->getNumFunctions(), OS);
2733ca95b02SDimitry Andric std::vector<ProfileSummaryEntry> &Entries = Summary->getDetailedSummary();
2743ca95b02SDimitry Andric encodeULEB128(Entries.size(), OS);
2753ca95b02SDimitry Andric for (auto Entry : Entries) {
2763ca95b02SDimitry Andric encodeULEB128(Entry.Cutoff, OS);
2773ca95b02SDimitry Andric encodeULEB128(Entry.MinCount, OS);
2783ca95b02SDimitry Andric encodeULEB128(Entry.NumCounts, OS);
2793ca95b02SDimitry Andric }
2803ca95b02SDimitry Andric return sampleprof_error::success;
2813ca95b02SDimitry Andric }
writeBody(const FunctionSamples & S)2823ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
2837d523365SDimitry Andric auto &OS = *OutputStream;
2847d523365SDimitry Andric
2853ca95b02SDimitry Andric if (std::error_code EC = writeNameIdx(S.getName()))
2867d523365SDimitry Andric return EC;
2877d523365SDimitry Andric
28839d628a0SDimitry Andric encodeULEB128(S.getTotalSamples(), OS);
2897d523365SDimitry Andric
2907d523365SDimitry Andric // Emit all the body samples.
29139d628a0SDimitry Andric encodeULEB128(S.getBodySamples().size(), OS);
29239d628a0SDimitry Andric for (const auto &I : S.getBodySamples()) {
29339d628a0SDimitry Andric LineLocation Loc = I.first;
29439d628a0SDimitry Andric const SampleRecord &Sample = I.second;
29539d628a0SDimitry Andric encodeULEB128(Loc.LineOffset, OS);
29639d628a0SDimitry Andric encodeULEB128(Loc.Discriminator, OS);
29739d628a0SDimitry Andric encodeULEB128(Sample.getSamples(), OS);
29839d628a0SDimitry Andric encodeULEB128(Sample.getCallTargets().size(), OS);
29939d628a0SDimitry Andric for (const auto &J : Sample.getCallTargets()) {
3007d523365SDimitry Andric StringRef Callee = J.first();
3017d523365SDimitry Andric uint64_t CalleeSamples = J.second;
3027d523365SDimitry Andric if (std::error_code EC = writeNameIdx(Callee))
3037d523365SDimitry Andric return EC;
30439d628a0SDimitry Andric encodeULEB128(CalleeSamples, OS);
30539d628a0SDimitry Andric }
30639d628a0SDimitry Andric }
30739d628a0SDimitry Andric
3087d523365SDimitry Andric // Recursively emit all the callsite samples.
3092cab237bSDimitry Andric uint64_t NumCallsites = 0;
3102cab237bSDimitry Andric for (const auto &J : S.getCallsiteSamples())
3112cab237bSDimitry Andric NumCallsites += J.second.size();
3122cab237bSDimitry Andric encodeULEB128(NumCallsites, OS);
3137a7e6055SDimitry Andric for (const auto &J : S.getCallsiteSamples())
3147a7e6055SDimitry Andric for (const auto &FS : J.second) {
3153ca95b02SDimitry Andric LineLocation Loc = J.first;
3167a7e6055SDimitry Andric const FunctionSamples &CalleeSamples = FS.second;
3177d523365SDimitry Andric encodeULEB128(Loc.LineOffset, OS);
3187d523365SDimitry Andric encodeULEB128(Loc.Discriminator, OS);
3193ca95b02SDimitry Andric if (std::error_code EC = writeBody(CalleeSamples))
3207d523365SDimitry Andric return EC;
32139d628a0SDimitry Andric }
32239d628a0SDimitry Andric
3237d523365SDimitry Andric return sampleprof_error::success;
3247d523365SDimitry Andric }
3257d523365SDimitry Andric
3264ba319b5SDimitry Andric /// Write samples of a top-level function to a binary file.
3277d523365SDimitry Andric ///
3287d523365SDimitry Andric /// \returns true if the samples were written successfully, false otherwise.
write(const FunctionSamples & S)3293ca95b02SDimitry Andric std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
3307d523365SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream);
3313ca95b02SDimitry Andric return writeBody(S);
3327d523365SDimitry Andric }
3337d523365SDimitry Andric
334*b5893f02SDimitry Andric std::error_code
write(const FunctionSamples & S)335*b5893f02SDimitry Andric SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
336*b5893f02SDimitry Andric uint64_t Offset = OutputStream->tell();
337*b5893f02SDimitry Andric StringRef Name = S.getName();
338*b5893f02SDimitry Andric FuncOffsetTable[Name] = Offset;
339*b5893f02SDimitry Andric encodeULEB128(S.getHeadSamples(), *OutputStream);
340*b5893f02SDimitry Andric return writeBody(S);
341*b5893f02SDimitry Andric }
342*b5893f02SDimitry Andric
3434ba319b5SDimitry Andric /// Create a sample profile file writer based on the specified format.
34439d628a0SDimitry Andric ///
34539d628a0SDimitry Andric /// \param Filename The file to create.
34639d628a0SDimitry Andric ///
34739d628a0SDimitry Andric /// \param Format Encoding format for the profile file.
34839d628a0SDimitry Andric ///
34939d628a0SDimitry Andric /// \returns an error code indicating the status of the created writer.
35039d628a0SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(StringRef Filename,SampleProfileFormat Format)35139d628a0SDimitry Andric SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
35239d628a0SDimitry Andric std::error_code EC;
3537d523365SDimitry Andric std::unique_ptr<raw_ostream> OS;
3544ba319b5SDimitry Andric if (Format == SPF_Binary || Format == SPF_Compact_Binary)
3557d523365SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_None));
3567d523365SDimitry Andric else
3577d523365SDimitry Andric OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::F_Text));
3587d523365SDimitry Andric if (EC)
3597d523365SDimitry Andric return EC;
3607d523365SDimitry Andric
3617d523365SDimitry Andric return create(OS, Format);
3627d523365SDimitry Andric }
3637d523365SDimitry Andric
3644ba319b5SDimitry Andric /// Create a sample profile stream writer based on the specified format.
3657d523365SDimitry Andric ///
3667d523365SDimitry Andric /// \param OS The output stream to store the profile data to.
3677d523365SDimitry Andric ///
3687d523365SDimitry Andric /// \param Format Encoding format for the profile file.
3697d523365SDimitry Andric ///
3707d523365SDimitry Andric /// \returns an error code indicating the status of the created writer.
3717d523365SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileWriter>>
create(std::unique_ptr<raw_ostream> & OS,SampleProfileFormat Format)3727d523365SDimitry Andric SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
3737d523365SDimitry Andric SampleProfileFormat Format) {
3747d523365SDimitry Andric std::error_code EC;
37539d628a0SDimitry Andric std::unique_ptr<SampleProfileWriter> Writer;
37639d628a0SDimitry Andric
37739d628a0SDimitry Andric if (Format == SPF_Binary)
3784ba319b5SDimitry Andric Writer.reset(new SampleProfileWriterRawBinary(OS));
3794ba319b5SDimitry Andric else if (Format == SPF_Compact_Binary)
3804ba319b5SDimitry Andric Writer.reset(new SampleProfileWriterCompactBinary(OS));
38139d628a0SDimitry Andric else if (Format == SPF_Text)
3827d523365SDimitry Andric Writer.reset(new SampleProfileWriterText(OS));
3837d523365SDimitry Andric else if (Format == SPF_GCC)
3847d523365SDimitry Andric EC = sampleprof_error::unsupported_writing_format;
38539d628a0SDimitry Andric else
38639d628a0SDimitry Andric EC = sampleprof_error::unrecognized_format;
38739d628a0SDimitry Andric
38839d628a0SDimitry Andric if (EC)
38939d628a0SDimitry Andric return EC;
39039d628a0SDimitry Andric
39139d628a0SDimitry Andric return std::move(Writer);
39239d628a0SDimitry Andric }
3933ca95b02SDimitry Andric
computeSummary(const StringMap<FunctionSamples> & ProfileMap)3943ca95b02SDimitry Andric void SampleProfileWriter::computeSummary(
3953ca95b02SDimitry Andric const StringMap<FunctionSamples> &ProfileMap) {
3963ca95b02SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
3973ca95b02SDimitry Andric for (const auto &I : ProfileMap) {
3983ca95b02SDimitry Andric const FunctionSamples &Profile = I.second;
3993ca95b02SDimitry Andric Builder.addRecord(Profile);
4003ca95b02SDimitry Andric }
4013ca95b02SDimitry Andric Summary = Builder.getSummary();
4023ca95b02SDimitry Andric }
403