#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
unsupported_version,
too_large,
truncated,
- malformed
+ malformed,
+ unrecognized_format
};
inline std::error_code make_error_code(sampleprof_error E) {
/// will be a list of one or more functions.
class SampleRecord {
public:
- typedef SmallVector<std::pair<std::string, unsigned>, 8> CallTargetList;
+ typedef StringMap<unsigned> CallTargetMap;
SampleRecord() : NumSamples(0), CallTargets() {}
/// \brief Increment the number of samples for this record by \p S.
- void addSamples(unsigned S) { NumSamples += S; }
+ ///
+ /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+ /// around unsigned integers.
+ void addSamples(unsigned S) {
+ if (NumSamples <= std::numeric_limits<unsigned>::max() - S)
+ NumSamples += S;
+ else
+ NumSamples = std::numeric_limits<unsigned>::max();
+ }
/// \brief Add called function \p F with samples \p S.
- void addCalledTarget(std::string F, unsigned S) {
- CallTargets.push_back(std::make_pair(F, S));
+ ///
+ /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+ /// around unsigned integers.
+ void addCalledTarget(StringRef F, unsigned S) {
+ unsigned &TargetSamples = CallTargets[F];
+ if (TargetSamples <= std::numeric_limits<unsigned>::max() - S)
+ TargetSamples += S;
+ else
+ TargetSamples = std::numeric_limits<unsigned>::max();
}
/// \brief Return true if this sample record contains function calls.
bool hasCalls() const { return CallTargets.size() > 0; }
unsigned getSamples() const { return NumSamples; }
- const CallTargetList &getCallTargets() const { return CallTargets; }
+ const CallTargetMap &getCallTargets() const { return CallTargets; }
+
+ /// \brief Merge the samples in \p Other into this record.
+ void merge(const SampleRecord &Other) {
+ addSamples(Other.getSamples());
+ for (const auto &I : Other.getCallTargets())
+ addCalledTarget(I.first(), I.second);
+ }
private:
unsigned NumSamples;
- CallTargetList CallTargets;
+ CallTargetMap CallTargets;
};
typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
class FunctionSamples {
public:
FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
- void print(raw_ostream &OS);
+ void print(raw_ostream &OS = dbgs());
void addTotalSamples(unsigned Num) { TotalSamples += Num; }
void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
Num);
}
+ /// \brief Return the sample record at the given location.
+ /// Each location is specified by \p LineOffset and \p Discriminator.
+ SampleRecord &sampleRecordAt(const LineLocation &Loc) {
+ return BodySamples[Loc];
+ }
+
/// \brief Return the number of samples collected at the given location.
/// Each location is specified by \p LineOffset and \p Discriminator.
unsigned samplesAt(int LineOffset, unsigned Discriminator) {
- return BodySamples[LineLocation(LineOffset, Discriminator)].getSamples();
+ return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples();
}
bool empty() const { return BodySamples.empty(); }
/// \brief Return all the samples collected in the body of the function.
const BodySampleMap &getBodySamples() const { return BodySamples; }
+ /// \brief Merge the samples in \p Other into this one.
+ void merge(const FunctionSamples &Other) {
+ addTotalSamples(Other.getTotalSamples());
+ addHeadSamples(Other.getHeadSamples());
+ for (const auto &I : Other.getBodySamples()) {
+ const LineLocation &Loc = I.first;
+ const SampleRecord &Rec = I.second;
+ sampleRecordAt(Loc).merge(Rec);
+ }
+ }
+
private:
/// \brief Total number of samples collected inside this function.
///
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ProfileData/SampleProf.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
virtual ~SampleProfileReader() {}
- /// \brief Print all the profiles to dbgs().
- void dump();
-
/// \brief Read and validate the file header.
virtual std::error_code readHeader() = 0;
virtual std::error_code read() = 0;
/// \brief Print the profile for \p FName on stream \p OS.
- void printFunctionProfile(raw_ostream &OS, StringRef FName);
+ void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());
- /// \brief Print the profile for \p FName on dbgs().
- void dumpFunctionProfile(StringRef FName);
+ /// \brief Print all the profiles on stream \p OS.
+ void dump(raw_ostream &OS = dbgs());
/// \brief Return the samples collected for function \p F.
FunctionSamples *getSamplesFor(const Function &F) {
return &Profiles[F.getName()];
}
+ /// \brief Return all the profiles.
+ StringMap<FunctionSamples> &getProfiles() { return Profiles; }
+
/// \brief Report a parse error message.
void reportParseError(int64_t LineNumber, Twine Msg) const {
Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
}
/// \brief Create a sample profile reader appropriate to the file format.
- static std::error_code create(std::string Filename,
+ static std::error_code create(StringRef Filename,
std::unique_ptr<SampleProfileReader> &Reader,
LLVMContext &C);
namespace sampleprof {
+enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC };
+
/// \brief Sample-based profile writer. Base class.
class SampleProfileWriter {
public:
: OS(Filename, EC, Flags) {}
virtual ~SampleProfileWriter() {}
- /// \brief Write sample profiles in \p S for function \p F.
+ /// \brief Write sample profiles in \p S for function \p FName.
///
/// \returns true if the file was updated successfully. False, otherwise.
- virtual bool write(const Function &F, const FunctionSamples &S) = 0;
+ virtual bool write(StringRef FName, const FunctionSamples &S) = 0;
+
+ /// \brief Write sample profiles in \p S for function \p F.
+ bool write(const Function &F, const FunctionSamples &S) {
+ return write(F.getName(), S);
+ }
/// \brief Write all the sample profiles for all the functions in \p M.
///
/// \returns true if the file was updated successfully. False, otherwise.
bool write(const Module &M, StringMap<FunctionSamples> &P) {
- for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!write((*I), P[I->getName()]))
+ for (const auto &F : M) {
+ StringRef Name = F.getName();
+ if (!write(Name, P[Name]))
+ return false;
+ }
+ return true;
+ }
+
+ /// \brief Write all the sample profiles in the given map of samples.
+ ///
+ /// \returns true if the file was updated successfully. False, otherwise.
+ bool write(StringMap<FunctionSamples> &ProfileMap) {
+ for (auto &I : ProfileMap) {
+ StringRef FName = I.first();
+ FunctionSamples &Profile = I.second;
+ if (!write(FName, Profile))
return false;
+ }
return true;
}
+ /// \brief Profile writer factory. Create a new writer based on the value of
+ /// \p Format.
+ static std::error_code create(StringRef Filename,
+ std::unique_ptr<SampleProfileWriter> &Result,
+ SampleProfileFormat Format);
+
protected:
/// \brief Output stream where to emit the profile to.
raw_fd_ostream OS;
SampleProfileWriterText(StringRef F, std::error_code &EC)
: SampleProfileWriter(F, EC, sys::fs::F_Text) {}
- bool write(const Function &F, const FunctionSamples &S) override;
+ bool write(StringRef FName, const FunctionSamples &S) override;
bool write(const Module &M, StringMap<FunctionSamples> &P) {
return SampleProfileWriter::write(M, P);
}
public:
SampleProfileWriterBinary(StringRef F, std::error_code &EC);
- bool write(const Function &F, const FunctionSamples &S) override;
+ bool write(StringRef F, const FunctionSamples &S) override;
bool write(const Module &M, StringMap<FunctionSamples> &P) {
return SampleProfileWriter::write(M, P);
}
return "Truncated profile data";
case sampleprof_error::malformed:
return "Malformed profile data";
+ case sampleprof_error::unrecognized_format:
+ return "Unrecognized profile encoding format";
}
llvm_unreachable("A value of sampleprof_error has no message.");
}
//===----------------------------------------------------------------------===//
#include "llvm/ProfileData/SampleProfReader.h"
-#include "llvm/ProfileData/SampleProfWriter.h" // REMOVE
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/LEB128.h"
void FunctionSamples::print(raw_ostream &OS) {
OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
<< " sampled lines\n";
- for (BodySampleMap::const_iterator SI = BodySamples.begin(),
- SE = BodySamples.end();
- SI != SE; ++SI) {
- LineLocation Loc = SI->first;
- SampleRecord Sample = SI->second;
+ for (const auto &SI : BodySamples) {
+ LineLocation Loc = SI.first;
+ const SampleRecord &Sample = SI.second;
OS << "\tline offset: " << Loc.LineOffset
<< ", discriminator: " << Loc.Discriminator
<< ", number of samples: " << Sample.getSamples();
if (Sample.hasCalls()) {
OS << ", calls:";
- for (SampleRecord::CallTargetList::const_iterator
- I = Sample.getCallTargets().begin(),
- E = Sample.getCallTargets().end();
- I != E; ++I)
- OS << " " << (*I).first << ":" << (*I).second;
+ for (const auto &I : Sample.getCallTargets())
+ OS << " " << I.first() << ":" << I.second;
}
OS << "\n";
}
OS << "\n";
}
-/// \brief Print the function profile for \p FName on stream \p OS.
+/// \brief Dump the function profile for \p FName.
///
-/// \param OS Stream to emit the output to.
/// \param FName Name of the function to print.
-void SampleProfileReader::printFunctionProfile(raw_ostream &OS,
- StringRef FName) {
+/// \param OS Stream to emit the output to.
+void SampleProfileReader::dumpFunctionProfile(StringRef FName,
+ raw_ostream &OS) {
OS << "Function: " << FName << ": ";
Profiles[FName].print(OS);
}
-/// \brief Dump the function profile for \p FName.
-///
-/// \param FName Name of the function to print.
-void SampleProfileReader::dumpFunctionProfile(StringRef FName) {
- printFunctionProfile(dbgs(), FName);
-}
-
-/// \brief Dump all the function profiles found.
-void SampleProfileReader::dump() {
- for (StringMap<FunctionSamples>::const_iterator I = Profiles.begin(),
- E = Profiles.end();
- I != E; ++I)
- dumpFunctionProfile(I->getKey());
+/// \brief Dump all the function profiles found on stream \p OS.
+void SampleProfileReader::dump(raw_ostream &OS) {
+ for (const auto &I : Profiles)
+ dumpFunctionProfile(I.getKey(), OS);
}
/// \brief Load samples from a text file.
return sampleprof_error::success;
}
-template <typename T>
-ErrorOr<T> SampleProfileReaderBinary::readNumber() {
+template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
unsigned NumBytesRead = 0;
std::error_code EC;
uint64_t Val = decodeULEB128(Data, &NumBytesRead);
///
/// \returns an error code indicating the status of the created reader.
std::error_code
-SampleProfileReader::create(std::string Filename,
+SampleProfileReader::create(StringRef Filename,
std::unique_ptr<SampleProfileReader> &Reader,
LLVMContext &C) {
std::unique_ptr<MemoryBuffer> Buffer;
using namespace llvm;
/// \brief Write samples to a text file.
-bool SampleProfileWriterText::write(const Function &F,
- const FunctionSamples &S) {
+bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
if (S.empty())
return true;
- OS << F.getName() << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
+ OS << FName << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
<< "\n";
- for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
- E = S.getBodySamples().end();
- I != E; ++I) {
- LineLocation Loc = I->first;
- SampleRecord Sample = I->second;
+ for (const auto &I : S.getBodySamples()) {
+ LineLocation Loc = I.first;
+ const SampleRecord &Sample = I.second;
if (Loc.Discriminator == 0)
OS << Loc.LineOffset << ": ";
else
OS << Sample.getSamples();
- for (SampleRecord::CallTargetList::const_iterator
- I = Sample.getCallTargets().begin(),
- E = Sample.getCallTargets().end();
- I != E; ++I)
- OS << " " << (*I).first << ":" << (*I).second;
+ for (const auto &J : Sample.getCallTargets())
+ OS << " " << J.first() << ":" << J.second;
OS << "\n";
}
/// \brief Write samples to a binary file.
///
/// \returns true if the samples were written successfully, false otherwise.
-bool SampleProfileWriterBinary::write(const Function &F,
+bool SampleProfileWriterBinary::write(StringRef FName,
const FunctionSamples &S) {
if (S.empty())
return true;
- OS << F.getName();
+ OS << FName;
encodeULEB128(0, OS);
encodeULEB128(S.getTotalSamples(), OS);
encodeULEB128(S.getHeadSamples(), OS);
encodeULEB128(S.getBodySamples().size(), OS);
- for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
- E = S.getBodySamples().end();
- I != E; ++I) {
- LineLocation Loc = I->first;
- SampleRecord Sample = I->second;
+ for (const auto &I : S.getBodySamples()) {
+ LineLocation Loc = I.first;
+ const SampleRecord &Sample = I.second;
encodeULEB128(Loc.LineOffset, OS);
encodeULEB128(Loc.Discriminator, OS);
encodeULEB128(Sample.getSamples(), OS);
encodeULEB128(Sample.getCallTargets().size(), OS);
- for (SampleRecord::CallTargetList::const_iterator
- I = Sample.getCallTargets().begin(),
- E = Sample.getCallTargets().end();
- I != E; ++I) {
- std::string Callee = (*I).first;
- unsigned CalleeSamples = (*I).second;
+ for (const auto &J : Sample.getCallTargets()) {
+ std::string Callee = J.first();
+ unsigned CalleeSamples = J.second;
OS << Callee;
encodeULEB128(0, OS);
encodeULEB128(CalleeSamples, OS);
return true;
}
+
+/// \brief Create a sample profile writer based on the specified format.
+///
+/// \param Filename The file to create.
+///
+/// \param Writer The writer to instantiate according to the specified format.
+///
+/// \param Format Encoding format for the profile file.
+///
+/// \returns an error code indicating the status of the created writer.
+std::error_code
+SampleProfileWriter::create(StringRef Filename,
+ std::unique_ptr<SampleProfileWriter> &Writer,
+ SampleProfileFormat Format) {
+ std::error_code EC;
+
+ if (Format == SPF_Binary)
+ Writer.reset(new SampleProfileWriterBinary(Filename, EC));
+ else if (Format == SPF_Text)
+ Writer.reset(new SampleProfileWriterText(Filename, EC));
+ else
+ EC = sampleprof_error::unrecognized_format;
+
+ return EC;
+}
--- /dev/null
+_Z3bari:20301:1437
+1: 1437
+_Z3fooi:7711:610
+1: 610
+main:184019:0
+4: 534
+4.2: 534
+5: 1075
+5.1: 1075
+6: 2080
+7: 534
+9: 2064 _Z3bari:1471 _Z3fooi:631
--- /dev/null
+Basic tests for sample profiles.
+
+1- Show all functions
+RUN: llvm-profdata show --sample %p/Inputs/sample-profile.proftext | FileCheck %s --check-prefix=SHOW1
+SHOW1: Function: main: 184019, 0, 7 sampled lines
+SHOW1: line offset: 9, discriminator: 0, number of samples: 2064, calls: _Z3fooi:631 _Z3bari:1471
+SHOW1: Function: _Z3fooi: 7711, 610, 1 sampled lines
+SHOW1: Function: _Z3bari: 20301, 1437, 1 sampled lines
+SHOW1: line offset: 1, discriminator: 0, number of samples: 1437
+
+2- Show only bar
+RUN: llvm-profdata show --sample --function=_Z3bari %p/Inputs/sample-profile.proftext | FileCheck %s --check-prefix=SHOW2
+SHOW2: Function: _Z3bari: 20301, 1437, 1 sampled lines
+SHOW2: line offset: 1, discriminator: 0, number of samples: 1437
+SHOW2-NOT: Function: main: 184019, 0, 7 sampled lines
+SHOW2-NOT: Function: _Z3fooi: 7711, 610, 1 sampled lines
+
+3- Convert the profile to binary encoding and check that they are both
+ identical.
+RUN: llvm-profdata merge --sample %p/Inputs/sample-profile.proftext --binary -o - | llvm-profdata show --sample - -o %t-binary
+RUN: llvm-profdata show --sample %p/Inputs/sample-profile.proftext -o %t-text
+RUN: diff %t-binary %t-text
+
+4- Merge the binary and text encodings of the profile and check that the
+ counters have doubled.
+RUN: llvm-profdata merge --sample %p/Inputs/sample-profile.proftext -o %t-binprof
+RUN: llvm-profdata merge --sample --text %p/Inputs/sample-profile.proftext %t-binprof -o - | FileCheck %s --check-prefix=MERGE1
+MERGE1: main:368038:0
+MERGE1: 9: 4128 _Z3fooi:1262 _Z3bari:2942
+MERGE1: _Z3fooi:15422:1220
#include "llvm/ADT/StringRef.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ProfileData/SampleProfWriter.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
::exit(1);
}
-int merge_main(int argc, const char *argv[]) {
- cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
- cl::desc("<filenames...>"));
-
- cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::Required,
- cl::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
-
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+enum ProfileKinds { instr, sample };
+void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
if (OutputFilename.compare("-") == 0)
exitWithError("Cannot write indexed profdata format to stdout.");
exitWithError(Reader->getError().message(), Filename);
}
Writer.write(Output);
-
- return 0;
}
-int show_main(int argc, const char *argv[]) {
- cl::opt<std::string> Filename(cl::Positional, cl::Required,
- cl::desc("<profdata-file>"));
+void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
+ sampleprof::SampleProfileFormat OutputFormat) {
+ using namespace sampleprof;
+ std::unique_ptr<SampleProfileWriter> Writer;
+ if (std::error_code EC = SampleProfileWriter::create(OutputFilename.data(),
+ Writer, OutputFormat))
+ exitWithError(EC.message(), OutputFilename);
- cl::opt<bool> ShowCounts("counts", cl::init(false),
- cl::desc("Show counter values for shown functions"));
- cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
- cl::desc("Details for every function"));
- cl::opt<std::string> ShowFunction("function",
- cl::desc("Details for matching functions"));
+ StringMap<FunctionSamples> ProfileMap;
+ for (const auto &Filename : Inputs) {
+ std::unique_ptr<SampleProfileReader> Reader;
+ if (std::error_code EC =
+ SampleProfileReader::create(Filename, Reader, getGlobalContext()))
+ exitWithError(EC.message(), Filename);
+
+ if (std::error_code EC = Reader->read())
+ exitWithError(EC.message(), Filename);
+
+ StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
+ for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
+ E = Profiles.end();
+ I != E; ++I) {
+ StringRef FName = I->first();
+ FunctionSamples &Samples = I->second;
+ ProfileMap[FName].merge(Samples);
+ }
+ }
+ Writer->write(ProfileMap);
+}
+
+int merge_main(int argc, const char *argv[]) {
+ cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
+ cl::desc("<filenames...>"));
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"),
+ cl::init("-"), cl::Required,
cl::desc("Output file"));
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+ cl::opt<sampleprof::SampleProfileFormat> OutputFormat(
+ cl::desc("Format of output profile (only meaningful with --sample)"),
+ cl::init(sampleprof::SPF_Binary),
+ cl::values(clEnumValN(sampleprof::SPF_Binary, "binary",
+ "Binary encoding (default)"),
+ clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"),
+ clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"),
+ clEnumValEnd));
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+
+ if (ProfileKind == instr)
+ mergeInstrProfile(Inputs, OutputFilename);
+ else
+ mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
+
+ return 0;
+}
+int showInstrProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
std::unique_ptr<InstrProfReader> Reader;
if (std::error_code EC = InstrProfReader::create(Filename, Reader))
exitWithError(EC.message(), Filename);
- if (OutputFilename.empty())
- OutputFilename = "-";
-
- std::error_code EC;
- raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
- if (EC)
- exitWithError(EC.message(), OutputFilename);
-
- if (ShowAllFunctions && !ShowFunction.empty())
- errs() << "warning: -function argument ignored: showing all functions\n";
-
uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
size_t ShownFunctions = 0, TotalFunctions = 0;
for (const auto &Func : *Reader) {
- bool Show = ShowAllFunctions ||
- (!ShowFunction.empty() &&
- Func.Name.find(ShowFunction) != Func.Name.npos);
+ bool Show =
+ ShowAllFunctions || (!ShowFunction.empty() &&
+ Func.Name.find(ShowFunction) != Func.Name.npos);
++TotalFunctions;
assert(Func.Counts.size() > 0 && "function missing entry counter");
return 0;
}
+int showSampleProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
+ using namespace sampleprof;
+ std::unique_ptr<SampleProfileReader> Reader;
+ if (std::error_code EC =
+ SampleProfileReader::create(Filename, Reader, getGlobalContext()))
+ exitWithError(EC.message(), Filename);
+
+ Reader->read();
+ if (ShowAllFunctions || ShowFunction.empty())
+ Reader->dump(OS);
+ else
+ Reader->dumpFunctionProfile(ShowFunction, OS);
+
+ return 0;
+}
+
+int show_main(int argc, const char *argv[]) {
+ cl::opt<std::string> Filename(cl::Positional, cl::Required,
+ cl::desc("<profdata-file>"));
+
+ cl::opt<bool> ShowCounts("counts", cl::init(false),
+ cl::desc("Show counter values for shown functions"));
+ cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
+ cl::desc("Details for every function"));
+ cl::opt<std::string> ShowFunction("function",
+ cl::desc("Details for matching functions"));
+
+ cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+ cl::init("-"), cl::desc("Output file"));
+ cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+ cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+
+ if (OutputFilename.empty())
+ OutputFilename = "-";
+
+ std::error_code EC;
+ raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
+ if (EC)
+ exitWithError(EC.message(), OutputFilename);
+
+ if (ShowAllFunctions && !ShowFunction.empty())
+ errs() << "warning: -function argument ignored: showing all functions\n";
+
+ if (ProfileKind == instr)
+ return showInstrProfile(Filename, ShowCounts, ShowAllFunctions,
+ ShowFunction, OS);
+ else
+ return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
+ ShowFunction, OS);
+}
+
int main(int argc, const char *argv[]) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();