mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-03 08:51:43 +00:00
[PGO] Add --text option for llvm-profdata show|merge commands
The new option is similar to the SampleProfile dump option. - dump raw/indexed format into text profile format - merge the profile and output into text profile format. Note that Value Profiling data text format is not yet designed. That functionality will be added later. Differential Revision: http://reviews.llvm.org/D14894 llvm-svn: 253913
This commit is contained in:
parent
d28d079aa7
commit
0f29a15199
@ -51,7 +51,17 @@ OPTIONS
|
||||
|
||||
.. option:: -instr (default)
|
||||
|
||||
Specify that the input profile is an instrumentation-based profile.
|
||||
Specify that the input profile is an instrumentation-based profile. When
|
||||
using instrumentation-based profiles, the format of the generated file
|
||||
can be generated in one of the two ways:
|
||||
|
||||
.. option:: -binary (default)
|
||||
|
||||
Emit the profile using a binary encoding in indexed profile format.
|
||||
|
||||
.. option:: -text
|
||||
|
||||
Emit the profile in text format.
|
||||
|
||||
.. option:: -sample
|
||||
|
||||
@ -121,6 +131,13 @@ OPTIONS
|
||||
|
||||
Specify that the input profile is an instrumentation-based profile.
|
||||
|
||||
.. option:: -text
|
||||
|
||||
Instruct the profile dumper to show profile counts in the text format of the
|
||||
instrumentation-based profile data representation. By default, the profile
|
||||
information is dumped in a more human readable form (also in text) with
|
||||
annotations.
|
||||
|
||||
.. option:: -sample
|
||||
|
||||
Specify that the input profile is a sample-based profile.
|
||||
|
@ -43,6 +43,11 @@ public:
|
||||
std::error_code addRecord(InstrProfRecord &&I);
|
||||
/// Write the profile to \c OS
|
||||
void write(raw_fd_ostream &OS);
|
||||
/// Write the profile in text format to \c OS
|
||||
void writeText(raw_fd_ostream &OS);
|
||||
/// Write \c Record in text format to \c OS
|
||||
static void writeRecordInText(const InstrProfRecord &Record,
|
||||
raw_fd_ostream &OS);
|
||||
/// Write the profile, returning the raw data. For testing.
|
||||
std::unique_ptr<MemoryBuffer> writeBuffer();
|
||||
|
||||
|
@ -171,6 +171,21 @@ void InstrProfWriter::write(raw_fd_ostream &OS) {
|
||||
endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
|
||||
}
|
||||
|
||||
void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func,
|
||||
raw_fd_ostream &OS) {
|
||||
OS << Func.Name << "\n" << Func.Hash << "\n" << Func.Counts.size() << "\n";
|
||||
for (uint64_t Count : Func.Counts)
|
||||
OS << Count << "\n";
|
||||
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
void InstrProfWriter::writeText(raw_fd_ostream &OS) {
|
||||
for (const auto &I : FunctionData)
|
||||
for (const auto &Func : I.getValue())
|
||||
writeRecordInText(Func.second, OS);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
|
||||
std::string Data;
|
||||
llvm::raw_string_ostream OS(Data);
|
||||
|
40
test/tools/llvm-profdata/Inputs/basic.proftext
Normal file
40
test/tools/llvm-profdata/Inputs/basic.proftext
Normal file
@ -0,0 +1,40 @@
|
||||
foo
|
||||
10
|
||||
2
|
||||
499500
|
||||
179900
|
||||
|
||||
main
|
||||
16650
|
||||
4
|
||||
1
|
||||
1000
|
||||
1000000
|
||||
499500
|
||||
|
||||
foo2
|
||||
10
|
||||
2
|
||||
500500
|
||||
180100
|
||||
|
||||
foo
|
||||
10
|
||||
2
|
||||
499500
|
||||
179900
|
||||
|
||||
main
|
||||
16650
|
||||
4
|
||||
1
|
||||
1000
|
||||
1000000
|
||||
499500
|
||||
|
||||
foo2
|
||||
10
|
||||
2
|
||||
500500
|
||||
180100
|
||||
|
21
test/tools/llvm-profdata/text-dump.test
Normal file
21
test/tools/llvm-profdata/text-dump.test
Normal file
@ -0,0 +1,21 @@
|
||||
Basic tests for testing text dump functions.
|
||||
|
||||
RUN: llvm-profdata show --all-functions -counts --text %p/Inputs/basic.proftext > %t-basic.proftext1
|
||||
RUN: llvm-profdata merge -o %t-basic.proftext2 --text %p/Inputs/basic.proftext
|
||||
|
||||
RUN: llvm-profdata merge -binary -o %t-basic.profdata1 %t-basic.proftext1
|
||||
RUN: llvm-profdata merge -o %t-basic.profdata2 %t-basic.proftext2
|
||||
|
||||
RUN: llvm-profdata show --all-functions -counts %t-basic.profdata1 > %t-basic.dump3
|
||||
RUN: llvm-profdata show --all-functions -counts %t-basic.profdata2 > %t-basic.dump4
|
||||
|
||||
RUN: llvm-profdata merge -text -o %t-basic.proftext5 %t-basic.profdata1
|
||||
RUN: llvm-profdata merge -text -o %t-basic.proftext6 %t-basic.profdata2
|
||||
|
||||
RUN: diff %t-basic.dump3 %t-basic.dump4
|
||||
RUN: diff %t-basic.proftext5 %t-basic.proftext6
|
||||
|
||||
RUN: not llvm-profdata merge -gcc -o %t-basic-profdata3 %t-basic.proftext2 2>&1 | FileCheck %s --check-prefix=UNKNOWN
|
||||
UNKNOWN: Unknown
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
enum ProfileFormat { PF_None = 0, PF_Text, PF_Binary, PF_GCC };
|
||||
|
||||
static void exitWithError(const Twine &Message,
|
||||
StringRef Whence = "",
|
||||
StringRef Hint = "") {
|
||||
@ -92,10 +94,14 @@ static void handleMergeWriterError(std::error_code &Error,
|
||||
}
|
||||
|
||||
static void mergeInstrProfile(const cl::list<std::string> &Inputs,
|
||||
StringRef OutputFilename) {
|
||||
StringRef OutputFilename,
|
||||
ProfileFormat OutputFormat) {
|
||||
if (OutputFilename.compare("-") == 0)
|
||||
exitWithError("Cannot write indexed profdata format to stdout.");
|
||||
|
||||
if (OutputFormat != PF_Binary && OutputFormat != PF_Text)
|
||||
exitWithError("Unknown format is specified.");
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
|
||||
if (EC)
|
||||
@ -119,14 +125,22 @@ static void mergeInstrProfile(const cl::list<std::string> &Inputs,
|
||||
if (Reader->hasError())
|
||||
exitWithErrorCode(Reader->getError(), Filename);
|
||||
}
|
||||
Writer.write(Output);
|
||||
if (OutputFormat == PF_Text)
|
||||
Writer.writeText(Output);
|
||||
else
|
||||
Writer.write(Output);
|
||||
}
|
||||
|
||||
static sampleprof::SampleProfileFormat FormatMap[] = {
|
||||
sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary,
|
||||
sampleprof::SPF_GCC};
|
||||
|
||||
static void mergeSampleProfile(const cl::list<std::string> &Inputs,
|
||||
StringRef OutputFilename,
|
||||
sampleprof::SampleProfileFormat OutputFormat) {
|
||||
ProfileFormat OutputFormat) {
|
||||
using namespace sampleprof;
|
||||
auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat);
|
||||
auto WriterOrErr =
|
||||
SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
|
||||
if (std::error_code EC = WriterOrErr.getError())
|
||||
exitWithErrorCode(EC, OutputFilename);
|
||||
|
||||
@ -174,19 +188,18 @@ static int merge_main(int argc, const char *argv[]) {
|
||||
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"),
|
||||
cl::opt<ProfileFormat> OutputFormat(
|
||||
cl::desc("Format of output profile"), cl::init(PF_Binary),
|
||||
cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
|
||||
clEnumValN(PF_Text, "text", "Text encoding"),
|
||||
clEnumValN(PF_GCC, "gcc",
|
||||
"GCC encoding (only meaningful for -sample)"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
|
||||
|
||||
if (ProfileKind == instr)
|
||||
mergeInstrProfile(Inputs, OutputFilename);
|
||||
mergeInstrProfile(Inputs, OutputFilename, OutputFormat);
|
||||
else
|
||||
mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
|
||||
|
||||
@ -195,7 +208,8 @@ static int merge_main(int argc, const char *argv[]) {
|
||||
|
||||
static int showInstrProfile(std::string Filename, bool ShowCounts,
|
||||
bool ShowIndirectCallTargets, bool ShowAllFunctions,
|
||||
std::string ShowFunction, raw_fd_ostream &OS) {
|
||||
std::string ShowFunction, bool TextFormat,
|
||||
raw_fd_ostream &OS) {
|
||||
auto ReaderOrErr = InstrProfReader::create(Filename);
|
||||
if (std::error_code EC = ReaderOrErr.getError())
|
||||
exitWithErrorCode(EC, Filename);
|
||||
@ -208,53 +222,69 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
|
||||
ShowAllFunctions || (!ShowFunction.empty() &&
|
||||
Func.Name.find(ShowFunction) != Func.Name.npos);
|
||||
|
||||
bool doTextFormatDump = (Show && ShowCounts && TextFormat);
|
||||
|
||||
if (doTextFormatDump) {
|
||||
InstrProfWriter::writeRecordInText(Func, OS);
|
||||
continue;
|
||||
}
|
||||
|
||||
++TotalFunctions;
|
||||
assert(Func.Counts.size() > 0 && "function missing entry counter");
|
||||
if (Func.Counts[0] > MaxFunctionCount)
|
||||
MaxFunctionCount = Func.Counts[0];
|
||||
|
||||
for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
|
||||
if (Func.Counts[I] > MaxBlockCount)
|
||||
MaxBlockCount = Func.Counts[I];
|
||||
}
|
||||
|
||||
if (Show) {
|
||||
|
||||
if (!ShownFunctions)
|
||||
OS << "Counters:\n";
|
||||
|
||||
++ShownFunctions;
|
||||
|
||||
OS << " " << Func.Name << ":\n"
|
||||
<< " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
|
||||
<< " Counters: " << Func.Counts.size() << "\n"
|
||||
<< " Function count: " << Func.Counts[0] << "\n";
|
||||
|
||||
if (ShowIndirectCallTargets)
|
||||
OS << " Indirect Call Site Count: "
|
||||
<< Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
|
||||
}
|
||||
|
||||
if (Show && ShowCounts)
|
||||
OS << " Block counts: [";
|
||||
for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
|
||||
if (Func.Counts[I] > MaxBlockCount)
|
||||
MaxBlockCount = Func.Counts[I];
|
||||
if (Show && ShowCounts)
|
||||
OS << (I == 1 ? "" : ", ") << Func.Counts[I];
|
||||
}
|
||||
if (Show && ShowCounts)
|
||||
OS << "]\n";
|
||||
if (ShowCounts) {
|
||||
OS << " Block counts: [";
|
||||
for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) {
|
||||
OS << (I == 1 ? "" : ", ") << Func.Counts[I];
|
||||
}
|
||||
OS << "]\n";
|
||||
}
|
||||
|
||||
if (Show && ShowIndirectCallTargets) {
|
||||
uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
|
||||
OS << " Indirect Target Results: \n";
|
||||
for (size_t I = 0; I < NS; ++I) {
|
||||
uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
|
||||
std::unique_ptr<InstrProfValueData[]> VD =
|
||||
Func.getValueForSite(IPVK_IndirectCallTarget, I);
|
||||
for (uint32_t V = 0; V < NV; V++) {
|
||||
OS << "\t[ " << I << ", ";
|
||||
OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n";
|
||||
if (ShowIndirectCallTargets) {
|
||||
uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
|
||||
OS << " Indirect Target Results: \n";
|
||||
for (size_t I = 0; I < NS; ++I) {
|
||||
uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
|
||||
std::unique_ptr<InstrProfValueData[]> VD =
|
||||
Func.getValueForSite(IPVK_IndirectCallTarget, I);
|
||||
for (uint32_t V = 0; V < NV; V++) {
|
||||
OS << "\t[ " << I << ", ";
|
||||
OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Reader->hasError())
|
||||
exitWithErrorCode(Reader->getError(), Filename);
|
||||
|
||||
if (ShowCounts && TextFormat)
|
||||
return 0;
|
||||
|
||||
if (ShowAllFunctions || !ShowFunction.empty())
|
||||
OS << "Functions shown: " << ShownFunctions << "\n";
|
||||
OS << "Total functions: " << TotalFunctions << "\n";
|
||||
@ -289,6 +319,9 @@ static int show_main(int argc, const char *argv[]) {
|
||||
|
||||
cl::opt<bool> ShowCounts("counts", cl::init(false),
|
||||
cl::desc("Show counter values for shown functions"));
|
||||
cl::opt<bool> TextFormat(
|
||||
"text", cl::init(false),
|
||||
cl::desc("Show instr profile data in text dump format"));
|
||||
cl::opt<bool> ShowIndirectCallTargets(
|
||||
"ic-targets", cl::init(false),
|
||||
cl::desc("Show indirect call site target values for shown functions"));
|
||||
@ -314,14 +347,14 @@ static int show_main(int argc, const char *argv[]) {
|
||||
std::error_code EC;
|
||||
raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
|
||||
if (EC)
|
||||
exitWithErrorCode(EC, OutputFilename);
|
||||
exitWithErrorCode(EC, OutputFilename);
|
||||
|
||||
if (ShowAllFunctions && !ShowFunction.empty())
|
||||
errs() << "warning: -function argument ignored: showing all functions\n";
|
||||
|
||||
if (ProfileKind == instr)
|
||||
return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets,
|
||||
ShowAllFunctions, ShowFunction, OS);
|
||||
ShowAllFunctions, ShowFunction, TextFormat, OS);
|
||||
else
|
||||
return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
|
||||
ShowFunction, OS);
|
||||
|
Loading…
Reference in New Issue
Block a user