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
llvm-svn: 221032
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 3229d4d..22acedc 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -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 @@
::exit(1);
}
-int merge_main(int argc, const char *argv[]) {
- cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
- cl::desc("<filenames...>"));
+enum ProfileKinds { instr, sample };
- 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");
-
+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 @@
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 @@
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();