diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -59,6 +59,11 @@ #include "llvm/ProfileData/InstrProfData.inc" }; +namespace llvm_profdata { +extern cl::SubCommand MergeSubCommand; +extern cl::SubCommand ShowSubCommand; +} // namespace llvm_profdata + /// Return the name of the profile section corresponding to \p IPSK. /// /// The name of the section depends on the object format type \p OF. If diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -56,6 +56,15 @@ using namespace llvm; +namespace llvm { +namespace llvm_profdata { +// We define these llvm-profdata subcommands here so that we can add them to the +// top-level options that they depend on, which are outside of llvm-profdata.cpp +cl::SubCommand MergeSubCommand("merge", "LLVM profile data merger tool"); +cl::SubCommand ShowSubCommand("show", "LLVM profile data summary tool"); +} // namespace llvm_profdata +} // namespace llvm + static cl::opt StaticFuncFullModulePrefix( "static-func-full-module-prefix", cl::init(true), cl::Hidden, cl::desc("Use full module build paths in the profile counter names for " diff --git a/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp b/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp --- a/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp +++ b/llvm/lib/ProfileData/ProfileSummaryBuilder.cpp @@ -24,6 +24,7 @@ cl::opt UseContextLessSummary( "profile-summary-contextless", cl::Hidden, cl::init(false), cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("Merge context profiles before calculating thresholds.")); // The following two parameters determine the threshold for a count to be @@ -35,24 +36,28 @@ // considered cold). cl::opt ProfileSummaryCutoffHot( "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("A count is hot if it exceeds the minimum count to" " reach this percentile of total counts.")); cl::opt ProfileSummaryCutoffCold( "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("A count is cold if it is below the minimum count" " to reach this percentile of total counts.")); cl::opt ProfileSummaryHugeWorkingSetSizeThreshold( "profile-summary-huge-working-set-size-threshold", cl::Hidden, - cl::init(15000), cl::ZeroOrMore, + cl::init(15000), cl::ZeroOrMore, cl::sub(*cl::TopLevelSubCommand), + cl::sub(llvm_profdata::MergeSubCommand), cl::desc("The code working set size is considered huge if the number of" " blocks required to reach the -profile-summary-cutoff-hot" " percentile exceeds this count.")); cl::opt ProfileSummaryLargeWorkingSetSizeThreshold( "profile-summary-large-working-set-size-threshold", cl::Hidden, - cl::init(12500), cl::ZeroOrMore, + cl::init(12500), cl::ZeroOrMore, cl::sub(*cl::TopLevelSubCommand), + cl::sub(llvm_profdata::MergeSubCommand), cl::desc("The code working set size is considered large if the number of" " blocks required to reach the -profile-summary-cutoff-hot" " percentile exceeds this count.")); @@ -61,11 +66,13 @@ // are useful for debugging purposes. cl::opt ProfileSummaryHotCount( "profile-summary-hot-count", cl::ReallyHidden, cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("A fixed hot count that overrides the count derived from" " profile-summary-cutoff-hot")); cl::opt ProfileSummaryColdCount( "profile-summary-cold-count", cl::ReallyHidden, cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("A fixed cold count that overrides the count derived from" " profile-summary-cutoff-cold")); diff --git a/llvm/lib/ProfileData/SampleProf.cpp b/llvm/lib/ProfileData/SampleProf.cpp --- a/llvm/lib/ProfileData/SampleProf.cpp +++ b/llvm/lib/ProfileData/SampleProf.cpp @@ -15,6 +15,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/PseudoProbe.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -32,11 +33,14 @@ static cl::opt ProfileSymbolListCutOff( "profile-symbol-list-cutoff", cl::Hidden, cl::init(-1), cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), + cl::sub(llvm_profdata::ShowSubCommand), cl::desc("Cutoff value about how many symbols in profile symbol list " "will be used. This is very useful for performance debugging")); cl::opt GenerateMergedBaseProfiles( "generate-merged-base-profiles", cl::init(true), cl::ZeroOrMore, + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), cl::desc("When generating nested context-sensitive profiles, always " "generate extra base profile for function with all its context " "profiles merged into it.")); diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -53,6 +53,8 @@ // For ext-binary format profiles, the flag is set in the summary. static cl::opt ProfileIsFSDisciminator( "profile-isfs", cl::Hidden, cl::init(false), + cl::sub(*cl::TopLevelSubCommand), cl::sub(llvm_profdata::MergeSubCommand), + cl::sub(llvm_profdata::ShowSubCommand), cl::desc("Profile uses flow sensitive discriminators")); /// Dump the function profile for \p FName. diff --git a/llvm/test/tools/llvm-profdata/same-filename.test b/llvm/test/tools/llvm-profdata/same-filename.test --- a/llvm/test/tools/llvm-profdata/same-filename.test +++ b/llvm/test/tools/llvm-profdata/same-filename.test @@ -13,7 +13,7 @@ We report error for the show command. RUN: not llvm-profdata show -o %t.1.profdata %t.1.profdata 2>&1 | FileCheck %s -CHECK: llvm-profdata{{.*}} show: Input file name cannot be the same as the output file name! +CHECK: Input file name cannot be the same as the output file name! This is OK for merging sample fdo profiles. RUN: cp %S/Inputs/same-name-3.proftext %t.3.proftext diff --git a/llvm/test/tools/llvm-profdata/weight-instr.test b/llvm/test/tools/llvm-profdata/weight-instr.test --- a/llvm/test/tools/llvm-profdata/weight-instr.test +++ b/llvm/test/tools/llvm-profdata/weight-instr.test @@ -78,4 +78,4 @@ 5- No inputs RUN: not llvm-profdata merge -instr -o %t.out 2>&1 | FileCheck %s -check-prefix=NO_INPUT -NO_INPUT: error: no input files specified. See llvm-profdata{{(\.EXE|\.exe)?}} merge -help +NO_INPUT: error: no input files specified. See --help option. diff --git a/llvm/test/tools/llvm-profdata/weight-sample.test b/llvm/test/tools/llvm-profdata/weight-sample.test --- a/llvm/test/tools/llvm-profdata/weight-sample.test +++ b/llvm/test/tools/llvm-profdata/weight-sample.test @@ -53,4 +53,4 @@ 5- No inputs RUN: not llvm-profdata merge -sample -o %t.out 2>&1 | FileCheck %s -check-prefix=NO_INPUT -NO_INPUT: {{.*}}: no input files specified. See llvm-profdata{{(\.EXE|\.exe)?}} merge -help +NO_INPUT: {{.*}}: no input files specified. See --help option. diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -39,7 +39,11 @@ #include using namespace llvm; +using namespace llvm_profdata; +namespace { +enum ProfileKinds { instr, sample, memory }; +enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid }; enum ProfileFormat { PF_None = 0, PF_Text, @@ -48,6 +52,234 @@ PF_GCC, PF_Binary }; +} // namespace + +cl::SubCommand OverlapSubCommand("overlap", "LLVM profile data overlap tool"); + +// Shared options. +cl::opt OutputFilename("output", cl::value_desc("output"), + cl::sub(MergeSubCommand), + cl::sub(ShowSubCommand), + cl::sub(OverlapSubCommand), cl::init("-"), + cl::desc("Output file")); +cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); +cl::opt ProfileKind( + cl::desc("Profile kind:"), cl::init(instr), cl::sub(MergeSubCommand), + cl::sub(ShowSubCommand), cl::sub(OverlapSubCommand), + cl::values(clEnumVal(instr, "Instrumentation profile (default)"), + clEnumVal(sample, "Sample profile"), + clEnumVal(memory, "MemProf memory access profile"))); +// Internal options to set FSDiscriminatorPass. Used in merge and show +// commands. +static cl::opt FSDiscriminatorPassOption( + "fs-discriminator-pass", cl::init(PassLast), cl::Hidden, + cl::sub(MergeSubCommand), cl::sub(ShowSubCommand), + cl::desc("Zero out the discriminator bits for the FS discrimiantor " + "pass beyond this value. The enum values are defined in " + "Support/Discriminator.h"), + cl::values(clEnumVal(Base, "Use base discriminators only"), + clEnumVal(Pass1, "Use base and pass 1 discriminators"), + clEnumVal(Pass2, "Use base and pass 1-2 discriminators"), + clEnumVal(Pass3, "Use base and pass 1-3 discriminators"), + clEnumVal(PassLast, "Use all discriminator bits (default)"))); + +// Merge options. +cl::list InputFilenames(cl::Positional, cl::sub(MergeSubCommand), + cl::desc("")); +cl::list WeightedInputFilenames("weighted-input", + cl::sub(MergeSubCommand), + cl::desc(",")); +cl::opt + InputFilenamesFile("input-files", cl::init(""), cl::sub(MergeSubCommand), + cl::desc("Path to file containing newline-separated " + "[,] entries")); +cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"), + cl::aliasopt(InputFilenamesFile)); +cl::opt DumpInputFileList( + "dump-input-file-list", cl::init(false), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("Dump the list of input files and their weights, then exit")); +cl::opt RemappingFile("remapping-file", cl::value_desc("file"), + cl::sub(MergeSubCommand), + cl::desc("Symbol remapping file")); +cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"), + cl::aliasopt(RemappingFile)); +cl::opt OutputFormat( + cl::sub(MergeSubCommand), cl::desc("Format of output profile"), + cl::init(PF_Binary), + cl::values( + clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), + clEnumValN(PF_Compact_Binary, "compbinary", "Compact binary encoding"), + clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"), + clEnumValN(PF_Text, "text", "Text encoding"), + clEnumValN(PF_GCC, "gcc", + "GCC encoding (only meaningful for -sample)"))); +cl::opt FailureModeOption( + "failure-mode", cl::init(failIfAnyAreInvalid), cl::sub(MergeSubCommand), + cl::desc("Failure mode:"), + cl::values(clEnumValN(failIfAnyAreInvalid, "any", + "Fail if any profile is invalid."), + clEnumValN(failIfAllAreInvalid, "all", + "Fail only if all profiles are invalid."))); +cl::opt OutputSparse( + "sparse", cl::init(false), cl::sub(MergeSubCommand), + cl::desc("Generate a sparse profile (only meaningful for -instr)")); +cl::opt NumThreads( + "num-threads", cl::init(0), cl::sub(MergeSubCommand), + cl::desc("Number of merge threads to use (default: autodetect)")); +cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), + cl::aliasopt(NumThreads)); +cl::opt ProfileSymbolListFile( + "prof-sym-list", cl::init(""), cl::sub(MergeSubCommand), + cl::desc("Path to file containing the list of function symbols " + "used to populate profile symbol list")); +cl::opt CompressAllSections( + "compress-all-sections", cl::init(false), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("Compress all sections when writing the profile (only " + "meaningful for -extbinary)")); +cl::opt + UseMD5("use-md5", cl::init(false), cl::Hidden, cl::sub(MergeSubCommand), + cl::desc("Choose to use MD5 to represent string in name table (only " + "meaningful for -extbinary)")); +cl::opt SampleMergeColdContext( + "sample-merge-cold-context", cl::init(false), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc( + "Merge context sample profiles whose count is below cold threshold")); +cl::opt SampleTrimColdContext( + "sample-trim-cold-context", cl::init(false), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc( + "Trim context sample profiles whose count is below cold threshold")); +cl::opt SampleColdContextFrameDepth( + "sample-frame-depth-for-cold-context", cl::init(1), cl::ZeroOrMore, + cl::sub(MergeSubCommand), + cl::desc("Keep the last K frames while merging cold profile. 1 means the " + "context-less base profile")); +cl::opt GenPartialProfile( + "gen-partial-profile", cl::init(false), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("Generate a partial profile (only meaningful for -extbinary)")); +cl::opt SupplInstrWithSample( + "supplement-instr-with-sample", cl::init(""), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("Supplement an instr profile with sample profile, to correct " + "the profile unrepresentativeness issue. The sample " + "profile is the input of the flag. Output will be in instr " + "format (The flag only works with -instr)")); +cl::opt ZeroCounterThreshold( + "zero-counter-threshold", cl::init(0.7), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("For the function which is cold in instr profile but hot in " + "sample profile, if the ratio of the number of zero counters " + "divided by the the total number of counters is above the " + "threshold, the profile of the function will be regarded as " + "being harmful for performance and will be dropped.")); +cl::opt SupplMinSizeThreshold( + "suppl-min-size-threshold", cl::init(10), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("If the size of a function is smaller than the threshold, " + "assume it can be inlined by PGO early inliner and it won't " + "be adjusted based on sample profile.")); +cl::opt InstrProfColdThreshold( + "instr-prof-cold-threshold", cl::init(0), cl::Hidden, + cl::sub(MergeSubCommand), + cl::desc("User specified cold threshold for instr profile which will " + "override the cold threshold got from profile summary. ")); +cl::opt GenCSNestedProfile( + "gen-cs-nested-profile", cl::Hidden, cl::init(false), + cl::sub(MergeSubCommand), + cl::desc("Generate nested function profiles for CSSPGO")); +cl::opt DebugInfoFilename( + "debug-info", cl::init(""), cl::sub(MergeSubCommand), + cl::desc("Use the provided debug info to correlate the raw profile.")); + +// Show options. +cl::opt Filename(cl::Positional, cl::Required, + cl::sub(ShowSubCommand), + cl::desc("")); + +cl::opt ShowCounts("counts", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show counter values for shown functions")); +cl::opt + TextFormat("text", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show instr profile data in text dump format")); +cl::opt ShowIndirectCallTargets( + "ic-targets", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show indirect call site target values for shown functions")); +cl::opt ShowMemOPSizes( + "memop-sizes", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show the profiled sizes of the memory intrinsic calls " + "for shown functions")); +cl::opt ShowDetailedSummary("detailed-summary", cl::init(false), + cl::sub(ShowSubCommand), + cl::desc("Show detailed profile summary")); +cl::list DetailedSummaryCutoffs( + cl::CommaSeparated, "detailed-summary-cutoffs", cl::sub(ShowSubCommand), + cl::desc( + "Cutoff percentages (times 10000) for generating detailed summary"), + cl::value_desc("800000,901000,999999")); +cl::opt ShowHotFuncList( + "hot-func-list", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show profile summary of a list of hot functions")); +cl::opt ShowAllFunctions("all-functions", cl::init(false), + cl::sub(ShowSubCommand), + cl::desc("Details for every function")); +cl::opt ShowCS("showcs", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show context sensitive counts")); +cl::opt ShowFunction("function", cl::sub(ShowSubCommand), + cl::desc("Details for matching functions")); + +cl::opt TopNFunctions( + "topn", cl::init(0), cl::sub(ShowSubCommand), + cl::desc("Show the list of functions with the largest internal counts")); +cl::opt ValueCutoff( + "value-cutoff", cl::init(0), cl::sub(ShowSubCommand), + cl::desc("Set the count value cutoff. Functions with the maximum count " + "less than this value will not be printed out. (Default is 0)")); +cl::opt OnlyListBelow( + "list-below-cutoff", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Only output names of functions whose max count values are " + "below the cutoff value")); +cl::opt ShowProfileSymbolList( + "show-prof-sym-list", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show profile symbol list if it exists in the profile. ")); +cl::opt ShowSectionInfoOnly( + "show-sec-info-only", cl::init(false), cl::sub(ShowSubCommand), + cl::desc("Show the information of each section in the sample profile. " + "The flag is only usable when the sample profile is in " + "extbinary format")); +cl::opt ShowBinaryIds("binary-ids", cl::init(false), + cl::sub(ShowSubCommand), + cl::desc("Show binary ids in the profile. ")); + +// Overlap options. +cl::opt BaseFilename(cl::Positional, cl::Required, + cl::sub(OverlapSubCommand), + cl::desc("")); +cl::opt TestFilename(cl::Positional, cl::Required, + cl::sub(OverlapSubCommand), + cl::desc("")); +cl::opt IsCS( + "cs", cl::init(false), cl::sub(OverlapSubCommand), + cl::desc("For context sensitive PGO counts. Does not work with CSSPGO.")); +cl::opt OverlapValueCutoff( + "value-cutoff", cl::init(-1), cl::sub(OverlapSubCommand), + cl::desc( + "Function level overlap information for every function (with calling " + "context for csspgo) in test " + "profile with max count value greater then the parameter value")); +cl::opt FuncNameFilter( + "function", cl::sub(OverlapSubCommand), + cl::desc("Function level overlap information for matching functions. For " + "CSSPGO this takes a a function name with calling context")); +cl::opt SimilarityCutoff( + "similarity-cutoff", cl::init(0), cl::sub(OverlapSubCommand), + cl::desc("For sample profiles, list function names (with calling context " + "for csspgo) for overlapped functions " + "with similarities below the cutoff (percentage times 10000).")); static void warn(Twine Message, std::string Whence = "", std::string Hint = "") { @@ -98,11 +330,6 @@ exitWithError(EC.message(), std::string(Whence)); } -namespace { -enum ProfileKinds { instr, sample, memory }; -enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid }; -} - static void warnOrExitGivenError(FailureMode FailMode, std::error_code EC, StringRef Whence = "") { if (FailMode == failIfAnyAreInvalid) @@ -467,21 +694,6 @@ const uint64_t ColdPercentileIdx = 15; const uint64_t HotPercentileIdx = 11; -using sampleprof::FSDiscriminatorPass; - -// Internal options to set FSDiscriminatorPass. Used in merge and show -// commands. -static cl::opt FSDiscriminatorPassOption( - "fs-discriminator-pass", cl::init(PassLast), cl::Hidden, - cl::desc("Zero out the discriminator bits for the FS discrimiantor " - "pass beyond this value. The enum values are defined in " - "Support/Discriminator.h"), - cl::values(clEnumVal(Base, "Use base discriminators only"), - clEnumVal(Pass1, "Use base and pass 1 discriminators"), - clEnumVal(Pass2, "Use base and pass 1-2 discriminators"), - clEnumVal(Pass3, "Use base and pass 1-3 discriminators"), - clEnumVal(PassLast, "Use all discriminator bits (default)"))); - static unsigned getDiscriminatorMask() { return getN1Bits(getFSPassBitEnd(FSDiscriminatorPassOption.getValue())); } @@ -866,113 +1078,7 @@ } } -static int merge_main(int argc, const char *argv[]) { - cl::list InputFilenames(cl::Positional, - cl::desc("")); - cl::list WeightedInputFilenames("weighted-input", - cl::desc(",")); - cl::opt InputFilenamesFile( - "input-files", cl::init(""), - cl::desc("Path to file containing newline-separated " - "[,] entries")); - cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"), - cl::aliasopt(InputFilenamesFile)); - cl::opt DumpInputFileList( - "dump-input-file-list", cl::init(false), cl::Hidden, - cl::desc("Dump the list of input files and their weights, then exit")); - cl::opt RemappingFile("remapping-file", cl::value_desc("file"), - cl::desc("Symbol remapping file")); - cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"), - cl::aliasopt(RemappingFile)); - cl::opt 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 ProfileKind( - cl::desc("Profile kind:"), cl::init(instr), - cl::values(clEnumVal(instr, "Instrumentation profile (default)"), - clEnumVal(sample, "Sample profile"))); - cl::opt OutputFormat( - cl::desc("Format of output profile"), cl::init(PF_Binary), - cl::values( - clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), - clEnumValN(PF_Compact_Binary, "compbinary", - "Compact binary encoding"), - clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"), - clEnumValN(PF_Text, "text", "Text encoding"), - clEnumValN(PF_GCC, "gcc", - "GCC encoding (only meaningful for -sample)"))); - cl::opt FailureMode( - "failure-mode", cl::init(failIfAnyAreInvalid), cl::desc("Failure mode:"), - cl::values(clEnumValN(failIfAnyAreInvalid, "any", - "Fail if any profile is invalid."), - clEnumValN(failIfAllAreInvalid, "all", - "Fail only if all profiles are invalid."))); - cl::opt OutputSparse("sparse", cl::init(false), - cl::desc("Generate a sparse profile (only meaningful for -instr)")); - cl::opt NumThreads( - "num-threads", cl::init(0), - cl::desc("Number of merge threads to use (default: autodetect)")); - cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), - cl::aliasopt(NumThreads)); - cl::opt ProfileSymbolListFile( - "prof-sym-list", cl::init(""), - cl::desc("Path to file containing the list of function symbols " - "used to populate profile symbol list")); - cl::opt CompressAllSections( - "compress-all-sections", cl::init(false), cl::Hidden, - cl::desc("Compress all sections when writing the profile (only " - "meaningful for -extbinary)")); - cl::opt UseMD5( - "use-md5", cl::init(false), cl::Hidden, - cl::desc("Choose to use MD5 to represent string in name table (only " - "meaningful for -extbinary)")); - cl::opt SampleMergeColdContext( - "sample-merge-cold-context", cl::init(false), cl::Hidden, - cl::desc( - "Merge context sample profiles whose count is below cold threshold")); - cl::opt SampleTrimColdContext( - "sample-trim-cold-context", cl::init(false), cl::Hidden, - cl::desc( - "Trim context sample profiles whose count is below cold threshold")); - cl::opt SampleColdContextFrameDepth( - "sample-frame-depth-for-cold-context", cl::init(1), cl::ZeroOrMore, - cl::desc("Keep the last K frames while merging cold profile. 1 means the " - "context-less base profile")); - cl::opt GenPartialProfile( - "gen-partial-profile", cl::init(false), cl::Hidden, - cl::desc("Generate a partial profile (only meaningful for -extbinary)")); - cl::opt SupplInstrWithSample( - "supplement-instr-with-sample", cl::init(""), cl::Hidden, - cl::desc("Supplement an instr profile with sample profile, to correct " - "the profile unrepresentativeness issue. The sample " - "profile is the input of the flag. Output will be in instr " - "format (The flag only works with -instr)")); - cl::opt ZeroCounterThreshold( - "zero-counter-threshold", cl::init(0.7), cl::Hidden, - cl::desc("For the function which is cold in instr profile but hot in " - "sample profile, if the ratio of the number of zero counters " - "divided by the the total number of counters is above the " - "threshold, the profile of the function will be regarded as " - "being harmful for performance and will be dropped.")); - cl::opt SupplMinSizeThreshold( - "suppl-min-size-threshold", cl::init(10), cl::Hidden, - cl::desc("If the size of a function is smaller than the threshold, " - "assume it can be inlined by PGO early inliner and it won't " - "be adjusted based on sample profile.")); - cl::opt InstrProfColdThreshold( - "instr-prof-cold-threshold", cl::init(0), cl::Hidden, - cl::desc("User specified cold threshold for instr profile which will " - "override the cold threshold got from profile summary. ")); - cl::opt GenCSNestedProfile( - "gen-cs-nested-profile", cl::Hidden, cl::init(false), - cl::desc("Generate nested function profiles for CSSPGO")); - cl::opt DebugInfoFilename( - "debug-info", cl::init(""), - cl::desc("Use the provided debug info to correlate the raw profile.")); - - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); - +static int merge_main() { WeightedFileVector WeightedInputs; for (StringRef Filename : InputFilenames) addWeightedInput(WeightedInputs, {std::string(Filename), 1}); @@ -985,8 +1091,7 @@ parseInputFilenamesFile(Buffer.get(), WeightedInputs); if (WeightedInputs.empty()) - exitWithError("no input files specified. See " + - sys::path::filename(argv[0]) + " -help"); + exitWithError("no input files specified. See --help option."); if (DumpInputFileList) { for (auto &WF : WeightedInputs) @@ -1012,13 +1117,15 @@ if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), OutputFilename, OutputFormat, OutputSparse, NumThreads, - FailureMode); - else + FailureModeOption); + else if (ProfileKind == sample) mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename, OutputFormat, ProfileSymbolListFile, CompressAllSections, UseMD5, GenPartialProfile, GenCSNestedProfile, SampleMergeColdContext, SampleTrimColdContext, - SampleColdContextFrameDepth, FailureMode); + SampleColdContextFrameDepth, FailureModeOption); + else + exitWithError("Unsupported ProfileKind"); return 0; } @@ -1979,50 +2086,19 @@ OverlapAggr.dumpFuncSimilarity(OS); } -static int overlap_main(int argc, const char *argv[]) { - cl::opt BaseFilename(cl::Positional, cl::Required, - cl::desc("")); - cl::opt TestFilename(cl::Positional, cl::Required, - cl::desc("")); - cl::opt Output("output", cl::value_desc("output"), cl::init("-"), - cl::desc("Output file")); - cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output)); - cl::opt IsCS( - "cs", cl::init(false), - cl::desc("For context sensitive PGO counts. Does not work with CSSPGO.")); - cl::opt ValueCutoff( - "value-cutoff", cl::init(-1), - cl::desc( - "Function level overlap information for every function (with calling " - "context for csspgo) in test " - "profile with max count value greater then the parameter value")); - cl::opt FuncNameFilter( - "function", - cl::desc("Function level overlap information for matching functions. For " - "CSSPGO this takes a a function name with calling context")); - cl::opt SimilarityCutoff( - "similarity-cutoff", cl::init(0), - cl::desc("For sample profiles, list function names (with calling context " - "for csspgo) for overlapped functions " - "with similarities below the cutoff (percentage times 10000).")); - cl::opt ProfileKind( - cl::desc("Profile kind:"), cl::init(instr), - cl::values(clEnumVal(instr, "Instrumentation profile (default)"), - clEnumVal(sample, "Sample profile"))); - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n"); - +static int overlap_main() { std::error_code EC; - raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_TextWithCRLF); + raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF); if (EC) - exitWithErrorCode(EC, Output); + exitWithErrorCode(EC, OutputFilename); if (ProfileKind == instr) overlapInstrProfile(BaseFilename, TestFilename, - OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS, - IsCS); + OverlapFuncFilters{OverlapValueCutoff, FuncNameFilter}, + OS, IsCS); else overlapSampleProfile(BaseFilename, TestFilename, - OverlapFuncFilters{ValueCutoff, FuncNameFilter}, + OverlapFuncFilters{OverlapValueCutoff, FuncNameFilter}, SimilarityCutoff, OS); return 0; @@ -2486,75 +2562,9 @@ return 0; } -static int show_main(int argc, const char *argv[]) { - cl::opt Filename(cl::Positional, cl::Required, - cl::desc("")); - - cl::opt ShowCounts("counts", cl::init(false), - cl::desc("Show counter values for shown functions")); - cl::opt TextFormat( - "text", cl::init(false), - cl::desc("Show instr profile data in text dump format")); - cl::opt ShowIndirectCallTargets( - "ic-targets", cl::init(false), - cl::desc("Show indirect call site target values for shown functions")); - cl::opt ShowMemOPSizes( - "memop-sizes", cl::init(false), - cl::desc("Show the profiled sizes of the memory intrinsic calls " - "for shown functions")); - cl::opt ShowDetailedSummary("detailed-summary", cl::init(false), - cl::desc("Show detailed profile summary")); - cl::list DetailedSummaryCutoffs( - cl::CommaSeparated, "detailed-summary-cutoffs", - cl::desc( - "Cutoff percentages (times 10000) for generating detailed summary"), - cl::value_desc("800000,901000,999999")); - cl::opt ShowHotFuncList( - "hot-func-list", cl::init(false), - cl::desc("Show profile summary of a list of hot functions")); - cl::opt ShowAllFunctions("all-functions", cl::init(false), - cl::desc("Details for every function")); - cl::opt ShowCS("showcs", cl::init(false), - cl::desc("Show context sensitive counts")); - cl::opt ShowFunction("function", - cl::desc("Details for matching functions")); - - cl::opt 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 ProfileKind( - cl::desc("Profile kind:"), cl::init(instr), - cl::values(clEnumVal(instr, "Instrumentation profile (default)"), - clEnumVal(sample, "Sample profile"), - clEnumVal(memory, "MemProf memory access profile"))); - cl::opt TopNFunctions( - "topn", cl::init(0), - cl::desc("Show the list of functions with the largest internal counts")); - cl::opt ValueCutoff( - "value-cutoff", cl::init(0), - cl::desc("Set the count value cutoff. Functions with the maximum count " - "less than this value will not be printed out. (Default is 0)")); - cl::opt OnlyListBelow( - "list-below-cutoff", cl::init(false), - cl::desc("Only output names of functions whose max count values are " - "below the cutoff value")); - cl::opt ShowProfileSymbolList( - "show-prof-sym-list", cl::init(false), - cl::desc("Show profile symbol list if it exists in the profile. ")); - cl::opt ShowSectionInfoOnly( - "show-sec-info-only", cl::init(false), - cl::desc("Show the information of each section in the sample profile. " - "The flag is only usable when the sample profile is in " - "extbinary format")); - cl::opt ShowBinaryIds("binary-ids", cl::init(false), - cl::desc("Show binary ids in the profile. ")); - - cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); - +static int show_main() { if (Filename == OutputFilename) { - errs() << sys::path::filename(argv[0]) - << ": Input file name cannot be the same as the output file name!\n"; + errs() << "Input file name cannot be the same as the output file name!\n"; return 1; } @@ -2582,41 +2592,17 @@ int main(int argc, const char *argv[]) { InitLLVM X(argc, argv); + cl::ParseCommandLineOptions(argc, argv, "LLVM profile data tools"); - StringRef ProgName(sys::path::filename(argv[0])); - if (argc > 1) { - int (*func)(int, const char *[]) = nullptr; - - if (strcmp(argv[1], "merge") == 0) - func = merge_main; - else if (strcmp(argv[1], "show") == 0) - func = show_main; - else if (strcmp(argv[1], "overlap") == 0) - func = overlap_main; - - if (func) { - std::string Invocation(ProgName.str() + " " + argv[1]); - argv[1] = Invocation.c_str(); - return func(argc - 1, argv + 1); - } - - if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-help") == 0 || - strcmp(argv[1], "--help") == 0) { - - errs() << "OVERVIEW: LLVM profile data tools\n\n" - << "USAGE: " << ProgName << " [args...]\n" - << "USAGE: " << ProgName << " -help\n\n" - << "See each individual command --help for more details.\n" - << "Available commands: merge, show, overlap\n"; - return 0; - } + if (MergeSubCommand) { + return merge_main(); + } else if (ShowSubCommand) { + return show_main(); + } else if (OverlapSubCommand) { + return overlap_main(); } - if (argc < 2) - errs() << ProgName << ": No command specified!\n"; - else - errs() << ProgName << ": Unknown command!\n"; - - errs() << "USAGE: " << ProgName << " [args...]\n"; + WithColor::error() << "No command specified!\n"; + cl::PrintHelpMessage(); return 1; }