Add show and merge tools for sample PGO profiles.

Summary:
This patch extends the 'show' and 'merge' commands in llvm-profdata to handle
sample PGO formats. Using the 'merge' command it is now possible to convert
one sample PGO format to another.

The only format that is currently not working is 'gcc'. I still need to
implement support for it in lib/ProfileData.

The changes in the sample profile support classes are needed for the
merge operation.

Reviewers: bogner

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D6065

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221032 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Diego Novillo 2014-11-01 00:56:55 +00:00
parent e542d91ee5
commit 9657de5f22
9 changed files with 323 additions and 123 deletions

View File

@ -16,6 +16,8 @@
#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>
@ -30,7 +32,8 @@ enum class sampleprof_error {
unsupported_version,
too_large,
truncated,
malformed
malformed,
unrecognized_format
};
inline std::error_code make_error_code(sampleprof_error E) {
@ -110,27 +113,49 @@ namespace sampleprof {
/// 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;
@ -143,7 +168,7 @@ 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) {
@ -163,10 +188,16 @@ public:
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(); }
@ -181,6 +212,17 @@ public:
/// \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.
///

View File

@ -21,6 +21,7 @@
#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"
@ -64,9 +65,6 @@ public:
virtual ~SampleProfileReader() {}
/// \brief Print all the profiles to dbgs().
void dump();
/// \brief Read and validate the file header.
virtual std::error_code readHeader() = 0;
@ -74,16 +72,19 @@ public:
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(),
@ -91,7 +92,7 @@ public:
}
/// \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);

View File

@ -24,6 +24,8 @@ namespace llvm {
namespace sampleprof {
enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC };
/// \brief Sample-based profile writer. Base class.
class SampleProfileWriter {
public:
@ -32,21 +34,47 @@ 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;
@ -58,7 +86,7 @@ public:
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);
}
@ -69,7 +97,7 @@ class SampleProfileWriterBinary : public SampleProfileWriter {
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);
}

View File

@ -36,6 +36,8 @@ class SampleProfErrorCategoryType : public std::error_category {
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.");
}

View File

@ -95,7 +95,6 @@
//===----------------------------------------------------------------------===//
#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"
@ -112,50 +111,36 @@ using namespace llvm;
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.
@ -245,8 +230,7 @@ std::error_code SampleProfileReaderText::read() {
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);
@ -396,7 +380,7 @@ setupMemoryBuffer(std::string Filename, std::unique_ptr<MemoryBuffer> &Buffer) {
///
/// \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;

View File

@ -30,19 +30,16 @@ using namespace llvm::sampleprof;
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
@ -50,11 +47,8 @@ bool SampleProfileWriterText::write(const Function &F,
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";
}
@ -75,31 +69,26 @@ SampleProfileWriterBinary::SampleProfileWriterBinary(StringRef F,
/// \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);
@ -108,3 +97,28 @@ bool SampleProfileWriterBinary::write(const Function &F,
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;
}

View File

@ -0,0 +1,12 @@
_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

View File

@ -0,0 +1,30 @@
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

View File

@ -14,6 +14,9 @@
#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"
@ -33,18 +36,9 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") {
::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.");
@ -67,50 +61,84 @@ int merge_main(int argc, const char *argv[]) {
exitWithError(Reader->getError().message(), Filename);
}
Writer.write(Output);
}
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);
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::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 merger\n");
if (ProfileKind == instr)
mergeInstrProfile(Inputs, OutputFilename);
else
mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
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::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
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");
@ -150,6 +178,65 @@ int show_main(int argc, const char *argv[]) {
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();