Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nfc][llvm-profdata] Use cl::Subcommand to organize subcommand and options in llvm-profdata #71328

Merged
merged 8 commits into from
Nov 14, 2023

Conversation

minglotus-6
Copy link
Contributor

@minglotus-6 minglotus-6 commented Nov 5, 2023

  • The motivation is to reduce the number of arguments passed around (e.g., from show_main to show*Profile). In order to do this, move function-defined options to global variables, and create cl::SubCommand for {show, merge, overlap, order} to organize options.
    • The side-effect by extracting function local options to a C++ namespace is that the extracted options are no longer (lazily) initialized when the enclosing function runs for the first time.
    • cl::Subcommand support (introduced in https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html) could put options in a per-subcommand namespace.
  • One option could belong to multiple subcommand. This patch defines most of the options once and associates them with multiple subcommands except
    1. overlap and show both has value-cutoff with different default values (former vs latter). Define 'OverlapValueCutoff' and 'ShowValueCutoff' respectively.
    2. show supports three profile formats in ProfileKind while {merge, overlap} supports two. Define separate options.
  • Clean up obsolete code as a result, including -h and --version customizations. These two options are supported for all commands. Results pasted.

This PR should be llvm-profdata only. It depends on #71981

Copy link

github-actions bot commented Nov 5, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@minglotus-6 minglotus-6 marked this pull request as ready for review November 6, 2023 16:48
@llvmbot llvmbot added the PGO Profile Guided Optimizations label Nov 6, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 6, 2023

@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-pgo

Author: Mingming Liu (minglotus-6)

Changes
  • Add struct InstrProfilePerFuncOptions to pass per-function show options to showInstrProfile. New per-function options could be added in this struct. The motivating use case is to show a new type of function value profiles in llvm-profdata.
  • Extract code snippets of showInstrProfile to small helper functions {showFuncPseudoCounters, showFuncInstrProfile, showValueProfileStats}.
  • Rename traverseAllValueSites to traverseAndShowAllValueSites so it's clearer at callsite that this function shows value profiles.

Full diff: https://github.com/llvm/llvm-project/pull/71328.diff

1 Files Affected:

  • (modified) llvm/tools/llvm-profdata/llvm-profdata.cpp (+125-88)
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 7d665a8005b0d62..4d0e1549f7adc80 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -2372,9 +2372,10 @@ struct ValueSitesStats {
 };
 } // namespace
 
-static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
-                                  ValueSitesStats &Stats, raw_fd_ostream &OS,
-                                  InstrProfSymtab *Symtab) {
+static void traverseAndShowAllValueSites(const InstrProfRecord &Func,
+                                         uint32_t VK, ValueSitesStats &Stats,
+                                         raw_fd_ostream &OS,
+                                         InstrProfSymtab *Symtab) {
   uint32_t NS = Func.getNumValueSites(VK);
   Stats.TotalNumValueSites += NS;
   for (size_t I = 0; I < NS; ++I) {
@@ -2406,6 +2407,14 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
   }
 }
 
+namespace {
+struct InstrProfilePerFuncOptions {
+  bool ShowCounts;
+  bool ShowIndirectCallTargets;
+  bool ShowMemOPSizes;
+};
+}; // namespace
+
 static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK,
                                 ValueSitesStats &Stats) {
   OS << "  Total number of sites: " << Stats.TotalNumValueSites << "\n";
@@ -2420,14 +2429,97 @@ static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK,
   }
 }
 
-static int showInstrProfile(
-    const std::string &Filename, bool ShowCounts, uint32_t TopN,
-    bool ShowIndirectCallTargets, bool ShowMemOPSizes, bool ShowDetailedSummary,
-    std::vector<uint32_t> DetailedSummaryCutoffs, bool ShowAllFunctions,
-    bool ShowCS, uint64_t ValueCutoff, bool OnlyListBelow,
-    const std::string &ShowFunction, bool TextFormat, bool ShowBinaryIds,
-    bool ShowCovered, bool ShowProfileVersion, bool ShowTemporalProfTraces,
-    ShowFormat SFormat, raw_fd_ostream &OS) {
+static void
+showFuncPseudoCounters(const NamedInstrProfRecord &FuncRecord,
+                       const InstrProfRecord::CountPseudoKind PseudoKind,
+                       size_t &ShownFunctions, raw_fd_ostream &OS) {
+  if (!ShownFunctions)
+    OS << "Counters:\n";
+  ++ShownFunctions;
+  OS << "  " << FuncRecord.Name << ":\n"
+     << "    Hash: " << format("0x%016" PRIx64, FuncRecord.Hash) << "\n"
+     << "    Counters: " << FuncRecord.Counts.size();
+  if (PseudoKind == InstrProfRecord::PseudoHot)
+    OS << "    <PseudoHot>\n";
+  else if (PseudoKind == InstrProfRecord::PseudoWarm)
+    OS << "    <PseudoWarm>\n";
+  else
+    llvm_unreachable("Unknown PseudoKind");
+}
+
+static void showFuncInstrProfile(const NamedInstrProfRecord &Func,
+                                 const bool IsIRInstr,
+                                 const InstrProfilePerFuncOptions &Options,
+                                 InstrProfSymtab *Symtab,
+                                 std::vector<ValueSitesStats> &VPStats,
+                                 size_t &ShownFunctions, raw_fd_ostream &OS) {
+  if (!ShownFunctions)
+    OS << "Counters:\n";
+
+  ++ShownFunctions;
+
+  OS << "  " << Func.Name << ":\n"
+     << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
+     << "    Counters: " << Func.Counts.size() << "\n";
+  if (!IsIRInstr)
+    OS << "    Function count: " << Func.Counts[0] << "\n";
+
+  if (Options.ShowIndirectCallTargets)
+    OS << "    Indirect Call Site Count: "
+       << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
+
+  uint32_t NumMemOPCalls = Func.getNumValueSites(IPVK_MemOPSize);
+  if (Options.ShowMemOPSizes && NumMemOPCalls > 0)
+    OS << "    Number of Memory Intrinsics Calls: " << NumMemOPCalls << "\n";
+
+  if (Options.ShowCounts) {
+    OS << "    Block counts: [";
+    size_t Start = (IsIRInstr ? 0 : 1);
+    for (size_t I = Start, E = Func.Counts.size(); I < E; ++I) {
+      OS << (I == Start ? "" : ", ") << Func.Counts[I];
+    }
+    OS << "]\n";
+  }
+
+  if (Options.ShowIndirectCallTargets) {
+    OS << "    Indirect Target Results:\n";
+    traverseAndShowAllValueSites(Func, IPVK_IndirectCallTarget,
+                                 VPStats[IPVK_IndirectCallTarget], OS, Symtab);
+  }
+
+  if (Options.ShowMemOPSizes && NumMemOPCalls > 0) {
+    OS << "    Memory Intrinsic Size Results:\n";
+    traverseAndShowAllValueSites(Func, IPVK_MemOPSize, VPStats[IPVK_MemOPSize],
+                                 OS, nullptr);
+  }
+}
+
+static void showValueProfileStats(size_t ShownFunctions,
+                                  bool ShowIndirectCallTargets,
+                                  bool ShowMemOPSizes,
+                                  std::vector<ValueSitesStats> &VPStats,
+                                  raw_fd_ostream &OS) {
+  if (ShownFunctions && ShowIndirectCallTargets) {
+    OS << "Statistics for indirect call sites profile:\n";
+    showValueSitesStats(OS, IPVK_IndirectCallTarget,
+                        VPStats[IPVK_IndirectCallTarget]);
+  }
+
+  if (ShownFunctions && ShowMemOPSizes) {
+    OS << "Statistics for memory intrinsic calls sizes profile:\n";
+    showValueSitesStats(OS, IPVK_MemOPSize, VPStats[IPVK_MemOPSize]);
+  }
+}
+
+static int
+showInstrProfile(const std::string &Filename, uint32_t TopN,
+                 InstrProfilePerFuncOptions Options, bool ShowDetailedSummary,
+                 std::vector<uint32_t> DetailedSummaryCutoffs,
+                 bool ShowAllFunctions, bool ShowCS, uint64_t ValueCutoff,
+                 bool OnlyListBelow, const std::string &ShowFunction,
+                 bool TextFormat, bool ShowBinaryIds, bool ShowCovered,
+                 bool ShowProfileVersion, bool ShowTemporalProfTraces,
+                 ShowFormat SFormat, raw_fd_ostream &OS) {
   if (SFormat == ShowFormat::Json)
     exitWithError("JSON output is not supported for instr profiles");
   if (SFormat == ShowFormat::Yaml)
@@ -2468,21 +2560,21 @@ static int showInstrProfile(
   if (TextFormat && IsIRInstr)
     OS << ":ir\n";
 
+  const bool IsIRLevelProfile = Reader->isIRLevelProfile();
+
   for (const auto &Func : *Reader) {
-    if (Reader->isIRLevelProfile()) {
-      bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
-      if (FuncIsCS != ShowCS)
+    if (IsIRLevelProfile) {
+      if (NamedInstrProfRecord::hasCSFlagInHash(Func.Hash) != ShowCS)
         continue;
     }
     bool Show = ShowAllFunctions ||
                 (!ShowFunction.empty() && Func.Name.contains(ShowFunction));
 
-    bool doTextFormatDump = (Show && TextFormat);
+    const bool doTextFormatDump = (Show && TextFormat);
 
     if (doTextFormatDump) {
-      InstrProfSymtab &Symtab = Reader->getSymtab();
-      InstrProfWriter::writeRecordInText(Func.Name, Func.Hash, Func, Symtab,
-                                         OS);
+      InstrProfWriter::writeRecordInText(Func.Name, Func.Hash, Func,
+                                         Reader->getSymtab(), OS);
       continue;
     }
 
@@ -2500,20 +2592,9 @@ static int showInstrProfile(
 
     auto PseudoKind = Func.getCountPseudoKind();
     if (PseudoKind != InstrProfRecord::NotPseudo) {
-      if (Show) {
-        if (!ShownFunctions)
-          OS << "Counters:\n";
-        ++ShownFunctions;
-        OS << "  " << Func.Name << ":\n"
-           << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
-           << "    Counters: " << Func.Counts.size();
-        if (PseudoKind == InstrProfRecord::PseudoHot)
-          OS << "    <PseudoHot>\n";
-        else if (PseudoKind == InstrProfRecord::PseudoWarm)
-          OS << "    <PseudoWarm>\n";
-        else
-          llvm_unreachable("Unknown PseudoKind");
-      }
+      if (Show)
+        showFuncPseudoCounters(Func, PseudoKind, ShownFunctions, OS);
+
       continue;
     }
 
@@ -2543,47 +2624,8 @@ static int showInstrProfile(
     }
 
     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";
-      if (!IsIRInstr)
-        OS << "    Function count: " << Func.Counts[0] << "\n";
-
-      if (ShowIndirectCallTargets)
-        OS << "    Indirect Call Site Count: "
-           << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
-
-      uint32_t NumMemOPCalls = Func.getNumValueSites(IPVK_MemOPSize);
-      if (ShowMemOPSizes && NumMemOPCalls > 0)
-        OS << "    Number of Memory Intrinsics Calls: " << NumMemOPCalls
-           << "\n";
-
-      if (ShowCounts) {
-        OS << "    Block counts: [";
-        size_t Start = (IsIRInstr ? 0 : 1);
-        for (size_t I = Start, E = Func.Counts.size(); I < E; ++I) {
-          OS << (I == Start ? "" : ", ") << Func.Counts[I];
-        }
-        OS << "]\n";
-      }
-
-      if (ShowIndirectCallTargets) {
-        OS << "    Indirect Target Results:\n";
-        traverseAllValueSites(Func, IPVK_IndirectCallTarget,
-                              VPStats[IPVK_IndirectCallTarget], OS,
-                              &(Reader->getSymtab()));
-      }
-
-      if (ShowMemOPSizes && NumMemOPCalls > 0) {
-        OS << "    Memory Intrinsic Size Results:\n";
-        traverseAllValueSites(Func, IPVK_MemOPSize, VPStats[IPVK_MemOPSize], OS,
-                              nullptr);
-      }
+      showFuncInstrProfile(Func, IsIRInstr, Options, , &(Reader->getSymtab()),
+                           VPStats, ShownFunctions, OS);
     }
   }
   if (Reader->hasError())
@@ -2621,16 +2663,8 @@ static int showInstrProfile(
       OS << "  " << hotfunc.first << ", max count = " << hotfunc.second << "\n";
   }
 
-  if (ShownFunctions && ShowIndirectCallTargets) {
-    OS << "Statistics for indirect call sites profile:\n";
-    showValueSitesStats(OS, IPVK_IndirectCallTarget,
-                        VPStats[IPVK_IndirectCallTarget]);
-  }
-
-  if (ShownFunctions && ShowMemOPSizes) {
-    OS << "Statistics for memory intrinsic calls sizes profile:\n";
-    showValueSitesStats(OS, IPVK_MemOPSize, VPStats[IPVK_MemOPSize]);
-  }
+  showValueProfileStats(ShownFunctions, ShowIndirectCallTargets, ShowMemOPSizes,
+                        VPStats, OS);
 
   if (ShowDetailedSummary) {
     OS << "Total number of blocks: " << PS->getNumCounts() << "\n";
@@ -3044,11 +3078,14 @@ static int show_main(int argc, const char *argv[]) {
 
   if (ProfileKind == instr)
     return showInstrProfile(
-        Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets,
-        ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs,
-        ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction,
-        TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion,
-        ShowTemporalProfTraces, SFormat, OS);
+        Filename, TopNFunctions,
+        InstrProfilePerFuncOptions{.ShowCounts = ShowCounts,
+                                   .ShowIndirectCallTargets =
+                                       ShowIndirectCallTargets,
+                                   .ShowMemOPSizes = ShowMemOPSizes},
+        ShowDetailedSummary, DetailedSummaryCutoffs, ShowAllFunctions, ShowCS,
+        ValueCutoff, OnlyListBelow, ShowFunction, TextFormat, ShowBinaryIds,
+        ShowCovered, ShowProfileVersion, ShowTemporalProfTraces, SFormat, OS);
   if (ProfileKind == sample)
     return showSampleProfile(Filename, ShowCounts, TopNFunctions,
                              ShowAllFunctions, ShowDetailedSummary,

@@ -2406,6 +2407,14 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
}
}

namespace {
struct InstrProfilePerFuncOptions {
bool ShowCounts;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please initialize scalars at declaration (i.e. bool ShowCounts = false), it's very easy to later write code that forgets to initialize a field, and while maybe noticing compiler warnings can highlight this, it's so much easier to just initialize at declaration and avoid undefined behavior!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

size_t &ShownFunctions, raw_fd_ostream &OS) {
if (!ShownFunctions)
OS << "Counters:\n";
++ShownFunctions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not return this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same below)

Copy link
Contributor Author

@minglotus-6 minglotus-6 Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's currently an input and output parameter. If I understand correctly, "returning it" means the following code sequence

in caller of `showFuncPseudoCounters`
ShownFunctions = showFuncPseudoCounters(ShownFunctions)

`showFuncPseudoCounters` takes 'ShownFunctions' as const input parameter and returns its 'increment-by-one' value

Is this generally more preferred in llvm codebase than using an input & output parameter?

static void showValueProfileStats(size_t ShownFunctions,
bool ShowIndirectCallTargets,
bool ShowMemOPSizes,
std::vector<ValueSitesStats> &VPStats,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is VPStats not const-ed because of the use of operator[]? If so, is the desired behavior to insert a default value if IPVK_MemOpSize isn't a key?

Copy link
Contributor Author

@minglotus-6 minglotus-6 Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vector 'VPStats' is initialized as std::vector<ValueSitesStats> VPStats(NumVPKind); code, and out-of-bound access from operator [] is undefined behavior.

I updated this new function and its callee to take a constant vector.

}

static int
showInstrProfile(const std::string &Filename, uint32_t TopN,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if factoring all the show... APIs into a class would make more sense - do some of the parameters make sense as shared state between these functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if factoring all the show... APIs into a class would make more sense - do some of the parameters make sense as shared state between these functions?

To share some context of this NFC, the immediate (and motivating) use case InstrProfilePerFuncOptions is to allow showing one new type of value profiles without increasing the length of function arguments.

InstrProfileShowOptions (a profile-level show options) would make sense as a separate patch. How to factor them is a more open-ended question. With all (nearly scalar) options, some options could be used together (e.g., TopN is meaningful to show function profiles but not meaningful in temporal profile traces) while other options are more independent of each other.

@@ -2406,6 +2407,14 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
}
}

namespace {
struct InstrProfilePerFuncOptions {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it be limited to InstrProfile? Perhaps just name it "PerFuncOptions"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Showing indirect call targets seems implicit currently; showSampleProfile doesn't take an option to suppress indirect call targets.

A minor thing is, functions in sample profiles doesn't have mem-op size; so passing 'PerFuncOptions' in showSampleProfile static function would require an option invalidation

if (PerFuncOptions.ShowMemOPSizes)
  emit error with message "mem-op size is not supported in sample profiles"

The struct is in anonymous namespace which makes it easier for renames if necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of mem-op size is just a missing feature. Adding a warning and ignore would be fine.

@minglotus-6
Copy link
Contributor Author

The patch is currently adding new C++ structs to reduce the number of arguments.

Another option is to move option definitions (

cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"));
cl::opt<bool> ShowCounts("counts", cl::init(false),
cl::desc("Show counter values for shown functions"));
cl::opt<ShowFormat> SFormat(
"show-format", cl::init(ShowFormat::Text),
cl::desc("Emit output in the selected format if supported"),
cl::values(clEnumValN(ShowFormat::Text, "text",
"emit normal text output (default)"),
clEnumValN(ShowFormat::Json, "json", "emit JSON"),
clEnumValN(ShowFormat::Yaml, "yaml", "emit YAML")));
// TODO: Consider replacing this with `--show-format=text-encoding`.
cl::opt<bool> TextFormat(
"text", cl::init(false),
cl::desc("Show instr profile data in text dump format"));
cl::opt<bool> JsonFormat(
"json", cl::desc("Show sample profile data in the JSON format "
"(deprecated, please use --show-format=json)"));
cl::opt<bool> ShowIndirectCallTargets(
"ic-targets", cl::init(false),
cl::desc("Show indirect call site target values for shown functions"));
cl::opt<bool> ShowMemOPSizes(
"memop-sizes", cl::init(false),
cl::desc("Show the profiled sizes of the memory intrinsic calls "
"for shown functions"));
cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
cl::desc("Show detailed profile summary"));
cl::list<uint32_t> DetailedSummaryCutoffs(
cl::CommaSeparated, "detailed-summary-cutoffs",
cl::desc(
"Cutoff percentages (times 10000) for generating detailed summary"),
cl::value_desc("800000,901000,999999"));
cl::opt<bool> ShowHotFuncList(
"hot-func-list", cl::init(false),
cl::desc("Show profile summary of a list of hot functions"));
cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
cl::desc("Details for every function"));
cl::opt<bool> ShowCS("showcs", cl::init(false),
cl::desc("Show context sensitive counts"));
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"),
clEnumVal(memory, "MemProf memory access profile")));
cl::opt<uint32_t> TopNFunctions(
"topn", cl::init(0),
cl::desc("Show the list of functions with the largest internal counts"));
cl::opt<uint32_t> 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<bool> 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<bool> ShowProfileSymbolList(
"show-prof-sym-list", cl::init(false),
cl::desc("Show profile symbol list if it exists in the profile. "));
cl::opt<bool> 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<bool> ShowBinaryIds("binary-ids", cl::init(false),
cl::desc("Show binary ids in the profile. "));
cl::opt<bool> ShowTemporalProfTraces(
"temporal-profile-traces",
cl::desc("Show temporal profile traces in the profile."));
cl::opt<std::string> DebugInfoFilename(
"debug-info", cl::init(""),
cl::desc("Read and extract profile metadata from debug info and show "
"the functions it found."));
cl::opt<unsigned> MaxDbgCorrelationWarnings(
"max-debug-info-correlation-warnings",
cl::desc("The maximum number of warnings to emit when correlating "
"profile from debug info (0 = no limit)"),
cl::init(5));
cl::opt<bool> ShowCovered(
"covered", cl::init(false),
cl::desc("Show only the functions that have been executed."));
cl::opt<std::string> ProfiledBinary(
"profiled-binary", cl::init(""),
) from function scope to a namespace (like namespace show_prof{), so the option definitions are visible to showInstrProfile and showSampleProfile (no need to pass long list of parameters) . The downside is that, not all options apply to both functions.

Thoughts about these two options?

@david-xl
Copy link
Contributor

david-xl commented Nov 7, 2023

The patch is currently adding new C++ structs to reduce the number of arguments.

Another option is to move option definitions (

cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"));
cl::opt<bool> ShowCounts("counts", cl::init(false),
cl::desc("Show counter values for shown functions"));
cl::opt<ShowFormat> SFormat(
"show-format", cl::init(ShowFormat::Text),
cl::desc("Emit output in the selected format if supported"),
cl::values(clEnumValN(ShowFormat::Text, "text",
"emit normal text output (default)"),
clEnumValN(ShowFormat::Json, "json", "emit JSON"),
clEnumValN(ShowFormat::Yaml, "yaml", "emit YAML")));
// TODO: Consider replacing this with `--show-format=text-encoding`.
cl::opt<bool> TextFormat(
"text", cl::init(false),
cl::desc("Show instr profile data in text dump format"));
cl::opt<bool> JsonFormat(
"json", cl::desc("Show sample profile data in the JSON format "
"(deprecated, please use --show-format=json)"));
cl::opt<bool> ShowIndirectCallTargets(
"ic-targets", cl::init(false),
cl::desc("Show indirect call site target values for shown functions"));
cl::opt<bool> ShowMemOPSizes(
"memop-sizes", cl::init(false),
cl::desc("Show the profiled sizes of the memory intrinsic calls "
"for shown functions"));
cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
cl::desc("Show detailed profile summary"));
cl::list<uint32_t> DetailedSummaryCutoffs(
cl::CommaSeparated, "detailed-summary-cutoffs",
cl::desc(
"Cutoff percentages (times 10000) for generating detailed summary"),
cl::value_desc("800000,901000,999999"));
cl::opt<bool> ShowHotFuncList(
"hot-func-list", cl::init(false),
cl::desc("Show profile summary of a list of hot functions"));
cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
cl::desc("Details for every function"));
cl::opt<bool> ShowCS("showcs", cl::init(false),
cl::desc("Show context sensitive counts"));
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"),
clEnumVal(memory, "MemProf memory access profile")));
cl::opt<uint32_t> TopNFunctions(
"topn", cl::init(0),
cl::desc("Show the list of functions with the largest internal counts"));
cl::opt<uint32_t> 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<bool> 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<bool> ShowProfileSymbolList(
"show-prof-sym-list", cl::init(false),
cl::desc("Show profile symbol list if it exists in the profile. "));
cl::opt<bool> 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<bool> ShowBinaryIds("binary-ids", cl::init(false),
cl::desc("Show binary ids in the profile. "));
cl::opt<bool> ShowTemporalProfTraces(
"temporal-profile-traces",
cl::desc("Show temporal profile traces in the profile."));
cl::opt<std::string> DebugInfoFilename(
"debug-info", cl::init(""),
cl::desc("Read and extract profile metadata from debug info and show "
"the functions it found."));
cl::opt<unsigned> MaxDbgCorrelationWarnings(
"max-debug-info-correlation-warnings",
cl::desc("The maximum number of warnings to emit when correlating "
"profile from debug info (0 = no limit)"),
cl::init(5));
cl::opt<bool> ShowCovered(
"covered", cl::init(false),
cl::desc("Show only the functions that have been executed."));
cl::opt<std::string> ProfiledBinary(
"profiled-binary", cl::init(""),

) from function scope to a namespace (like namespace show_prof{), so the option definitions are visible to showInstrProfile and showSampleProfile (no need to pass long list of parameters) . The downside is that, not all options apply to both functions.
Thoughts about these two options?

Moving show options to show_prof namespace looks reasonable to me. Need to make sure the --help option for the 'show' command works properly though.

@minglotus-6 minglotus-6 changed the title [nfc][llvm-profdata]Refactor llvm-profdata showInstrProfile [nfc][llvm-profdata]Refactor llvm-profdata show* code, by moving function-scope options to a show_llvmprofdata namespace Nov 7, 2023
@minglotus-6
Copy link
Contributor Author

I updated the PR to exemplify the change for show_main and show options. After the refactor pattern is closer to what it should look like eventually, I could apply it to other static *main functions

Copy link
Contributor

@david-xl david-xl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better put the options into its own name space "namespace show_options {}. In the follow up patch, options for other commands can be done similarly.

@@ -2406,6 +2407,14 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
}
}

namespace {
struct InstrProfilePerFuncOptions {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of mem-op size is just a missing feature. Adding a warning and ignore would be fine.

@minglotus-6
Copy link
Contributor Author

minglotus-6 commented Nov 7, 2023

Better put the options into its own name space "namespace show_options {}. In the follow up patch, options for other commands can be done similarly.

Sounds good. (Learnt from failed error message) I should probably register show of llvm-profdata show as a subcommand, and make the show options associated with this subcommand (something like this example

cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
cl::sub(DiaDumpSubcommand));
);

Without that, I'm getting runtime registration errors Option 'output' registered more than once! when extracting output option out of a per-function scope.

namespace.
- The change uses cl::SubCommand feature that allow to register options
  under a subcommand.
  - Without using cl::SubCommand, the options in the show name namespace will
    take a registered name as global variables, causing runtime errors when a
    function-scope static option tries to add a function of a same name.
  - Make changes in the CommandLine library accordingly.
@minglotus-6 minglotus-6 changed the title [nfc][llvm-profdata]Refactor llvm-profdata show* code, by moving function-scope options to a show_llvmprofdata namespace [llvm-support][llvm-profdata] Use cl::Subcommand to organize show options. And look up in top-level as a fallback if a special subcommand doesn't have an option. Nov 8, 2023
static int showInstrProfile(const std::string &Filename, ShowFormat SFormat,
raw_fd_ostream &OS) {
static int showInstrProfile(
const std::string &Filename, bool ShowCounts, uint32_t TopN,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why still passing the options as parameters ? They can be referenced as show_options:: in the function body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated {showInstrProfile, showSampleProfile, showMemProfProfile, showDebugInfoCorrelation} to use options directly.

Copy link
Contributor

@david-xl david-xl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the options are now attached to ShowSubCommand, there is no longer the need to use show_options namespace.

@minglotus-6
Copy link
Contributor Author

Since the options are now attached to ShowSubCommand, there is no longer the need to use show_options namespace.

Different subcommand could have cl::opt variables of the same name. While cl::SubCommand could put registered option strings in a sub-command "namespace", , the cl::opt variables are put in per-subcommand namespaces.

Copy link
Contributor

@snehasish snehasish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall direction looks reasonable to me. Thanks for taking the time to improve the code here!

llvm/lib/Support/CommandLine.cpp Outdated Show resolved Hide resolved
@minglotus-6
Copy link
Contributor Author

The patch is currently adding new C++ structs to reduce the number of arguments.
Another option is to move option definitions (

cl::opt<std::string> Filename(cl::Positional, cl::desc("<profdata-file>"));
cl::opt<bool> ShowCounts("counts", cl::init(false),
cl::desc("Show counter values for shown functions"));
cl::opt<ShowFormat> SFormat(
"show-format", cl::init(ShowFormat::Text),
cl::desc("Emit output in the selected format if supported"),
cl::values(clEnumValN(ShowFormat::Text, "text",
"emit normal text output (default)"),
clEnumValN(ShowFormat::Json, "json", "emit JSON"),
clEnumValN(ShowFormat::Yaml, "yaml", "emit YAML")));
// TODO: Consider replacing this with `--show-format=text-encoding`.
cl::opt<bool> TextFormat(
"text", cl::init(false),
cl::desc("Show instr profile data in text dump format"));
cl::opt<bool> JsonFormat(
"json", cl::desc("Show sample profile data in the JSON format "
"(deprecated, please use --show-format=json)"));
cl::opt<bool> ShowIndirectCallTargets(
"ic-targets", cl::init(false),
cl::desc("Show indirect call site target values for shown functions"));
cl::opt<bool> ShowMemOPSizes(
"memop-sizes", cl::init(false),
cl::desc("Show the profiled sizes of the memory intrinsic calls "
"for shown functions"));
cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
cl::desc("Show detailed profile summary"));
cl::list<uint32_t> DetailedSummaryCutoffs(
cl::CommaSeparated, "detailed-summary-cutoffs",
cl::desc(
"Cutoff percentages (times 10000) for generating detailed summary"),
cl::value_desc("800000,901000,999999"));
cl::opt<bool> ShowHotFuncList(
"hot-func-list", cl::init(false),
cl::desc("Show profile summary of a list of hot functions"));
cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
cl::desc("Details for every function"));
cl::opt<bool> ShowCS("showcs", cl::init(false),
cl::desc("Show context sensitive counts"));
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"),
clEnumVal(memory, "MemProf memory access profile")));
cl::opt<uint32_t> TopNFunctions(
"topn", cl::init(0),
cl::desc("Show the list of functions with the largest internal counts"));
cl::opt<uint32_t> 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<bool> 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<bool> ShowProfileSymbolList(
"show-prof-sym-list", cl::init(false),
cl::desc("Show profile symbol list if it exists in the profile. "));
cl::opt<bool> 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<bool> ShowBinaryIds("binary-ids", cl::init(false),
cl::desc("Show binary ids in the profile. "));
cl::opt<bool> ShowTemporalProfTraces(
"temporal-profile-traces",
cl::desc("Show temporal profile traces in the profile."));
cl::opt<std::string> DebugInfoFilename(
"debug-info", cl::init(""),
cl::desc("Read and extract profile metadata from debug info and show "
"the functions it found."));
cl::opt<unsigned> MaxDbgCorrelationWarnings(
"max-debug-info-correlation-warnings",
cl::desc("The maximum number of warnings to emit when correlating "
"profile from debug info (0 = no limit)"),
cl::init(5));
cl::opt<bool> ShowCovered(
"covered", cl::init(false),
cl::desc("Show only the functions that have been executed."));
cl::opt<std::string> ProfiledBinary(
"profiled-binary", cl::init(""),

) from function scope to a namespace (like namespace show_prof{), so the option definitions are visible to showInstrProfile and showSampleProfile (no need to pass long list of parameters) . The downside is that, not all options apply to both functions.
Thoughts about these two options?

Moving show options to show_prof namespace looks reasonable to me. Need to make sure the --help option for the 'show' command works properly though.

With the usage of cl::Subcommand, --help should work out of the box. This gist is the output.

Since the options are now attached to ShowSubCommand, there is no longer the need to use show_options namespace.

Different subcommand could have cl::opt variables of the same name. While cl::SubCommand could put registered option strings in a sub-command "namespace", , the cl::opt variables are put in per-subcommand namespaces.

I might need to take this back. It seems plausible to associate one cl::opt with multiple subcommands based on how registration works. I will try it out.

@minglotus-6 minglotus-6 marked this pull request as draft November 9, 2023 05:52
minglotus-6 added a commit that referenced this pull request Nov 10, 2023
…ptions for a custom subcommand. (#71776)

**Context:**

- In https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html and commit 07670b3, `cl::SubCommand` is introduced.
- Options that don't specify subcommand goes into a special 'top level' subcommand.

**Motivating Use Case:**
- The motivating use case is to refactor `llvm-profdata` to use `cl::SubCommand` to organize subcommands. See
#71328. A valid use case that's not supported before this patch is shown below

```
  // show-option{1,2} are associated with 'show' subcommand.
  // top-level-option3 is in top-level subcomand (e.g., `profile-isfs` in SampleProfReader.cpp)
  llvm-profdata show --show-option1 --show-option2 --top-level-option3
```

- Before this patch, option handler look-up will fail with the following error message "Unknown command line argument --top-level-option3".
- After this patch, option handler look-up will look up in sub-command options first, and use top-level subcommand as a fallback, so 'top-level-option3' is parsed correctly.
@minglotus-6 minglotus-6 marked this pull request as ready for review November 11, 2023 00:22
@minglotus-6
Copy link
Contributor Author

This is ready for review again!

Some options are sub-command specific and I tried to keep these options closer to where they are used. Common options are moved ahead at the very beginning.

@minglotus-6 minglotus-6 changed the title [llvm-support][llvm-profdata] Use cl::Subcommand to organize show options. And look up in top-level as a fallback if a special subcommand doesn't have an option. [nfc][llvm-profdata] Use cl::Subcommand to organize subcommand and options in llvm-profdata Nov 11, 2023
@minglotus-6
Copy link
Contributor Author

minglotus-6 commented Nov 11, 2023

To ensure options are not deleted mistakenly, I run llvm-profdata <subcommand> --help with and without the patch, and got the diff links [1]. Two kinds of options are gone in emitted message with this patch, which I think is benign.

  1. --version is not in --help message. note llvm-profdata --version still works but doesn't emit llvm-profdata anymore (see updated regression test)
  2. Options that are not defined in llvm-profdata.cpp before this patch. {disable-i2p-p2i-opt, disable-auto-upgrade-debug-info, enable-name-compression, generate-merged-base-profiles} are defined in dependent libraries. experimental-debuginfo-iterators is shown before but I didn't see where this option is defined in the llvm-repo, so consider this fine without a deeper look..

[1]

minglotus-6 added a commit that referenced this pull request Nov 13, 2023
…ooking options for a custom subcommand (#71981)

Fixed build bot errors. 

- Use `StackOption<std::string>` type for the top level option. This
way, a per test-case option is unregistered when destructor of
`StackOption` cleans up state for subsequent test cases.
- Repro the crash with no test sharding `/usr/bin/python3
/path/to/llvm-project/build/./bin/llvm-lit -vv --no-gtest-sharding -j128
/path/to/llvm-project/llvm/test/Unit`. The crash is gone with the fix
(same no-sharding repro)

**Original commit message:**
**Context:**

- In https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html and
commit
07670b3,
`cl::SubCommand` is introduced.
- Options that don't specify subcommand goes into a special 'top level'
subcommand.

**Motivating Use Case:**
- The motivating use case is to refactor `llvm-profdata` to use
`cl::SubCommand` to organize subcommands. See
#71328. A valid use case that's
not supported before this patch is shown below

```
  // show-option{1,2} are associated with 'show' subcommand.
  // top-level-option3 is in top-level subcomand (e.g., `profile-isfs` in SampleProfReader.cpp)
  llvm-profdata show --show-option1 --show-option2 --top-level-option3
```

- Before this patch, option handler look-up will fail with the following
error message "Unknown command line argument --top-level-option3".
- After this patch, option handler look-up will look up in sub-command
options first, and use top-level subcommand as a fallback, so
'top-level-option3' is parsed correctly.
Copy link
Contributor

@snehasish snehasish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with some minor comments.

cl::SubCommand
OverlapSubcommand("overlap",
"Computes and displays the overlap between two profiles");
cl::SubCommand MergeSubcommand("merge", "Merges profiles");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A link to the relevant documentation would be a helpful to users who don't look at the source: For example, for merge you can add a link to https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge

Same for the others. Also drop the comment on L50 if you choose to adopt this suggestion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

uint64_t MaxTraceLength, int MaxDbgCorrelationWarnings,
bool OutputSparse, unsigned NumThreads, FailureMode FailMode,
const StringRef ProfiledBinary) {
// Common options.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can move the common and 2-common set of options to the top of the file, right under subcommands. Since the options are documented (i.e. "options unique to show" etc) I also wouldn't mind moving everything to the top of the file. I don't see a particular reason to keep them near the methods which implement the functionality, particularly since we always parse all options now. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to me. I moved options definitions right after cl::Subcommand.

cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."),
cl::sub(OverlapSubcommand));

cl::opt<std::string> FuncNameFilter(
Copy link
Contributor

@snehasish snehasish Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in 2-common options since it's used by show and overlap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. I moved it to the 2-common options section.

Copy link
Contributor Author

@minglotus-6 minglotus-6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the reviews!

cl::SubCommand
OverlapSubcommand("overlap",
"Computes and displays the overlap between two profiles");
cl::SubCommand MergeSubcommand("merge", "Merges profiles");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

uint64_t MaxTraceLength, int MaxDbgCorrelationWarnings,
bool OutputSparse, unsigned NumThreads, FailureMode FailMode,
const StringRef ProfiledBinary) {
// Common options.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable to me. I moved options definitions right after cl::Subcommand.

cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."),
cl::sub(OverlapSubcommand));

cl::opt<std::string> FuncNameFilter(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. I moved it to the 2-common options section.

@minglotus-6 minglotus-6 merged commit 493e240 into llvm:main Nov 14, 2023
3 checks passed
@minglotus-6 minglotus-6 deleted the llvm-profdata branch November 14, 2023 18:19
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…ptions for a custom subcommand. (llvm#71776)

**Context:**

- In https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html and commit 07670b3, `cl::SubCommand` is introduced.
- Options that don't specify subcommand goes into a special 'top level' subcommand.

**Motivating Use Case:**
- The motivating use case is to refactor `llvm-profdata` to use `cl::SubCommand` to organize subcommands. See
llvm#71328. A valid use case that's not supported before this patch is shown below

```
  // show-option{1,2} are associated with 'show' subcommand.
  // top-level-option3 is in top-level subcomand (e.g., `profile-isfs` in SampleProfReader.cpp)
  llvm-profdata show --show-option1 --show-option2 --top-level-option3
```

- Before this patch, option handler look-up will fail with the following error message "Unknown command line argument --top-level-option3".
- After this patch, option handler look-up will look up in sub-command options first, and use top-level subcommand as a fallback, so 'top-level-option3' is parsed correctly.
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…ooking options for a custom subcommand (llvm#71981)

Fixed build bot errors. 

- Use `StackOption<std::string>` type for the top level option. This
way, a per test-case option is unregistered when destructor of
`StackOption` cleans up state for subsequent test cases.
- Repro the crash with no test sharding `/usr/bin/python3
/path/to/llvm-project/build/./bin/llvm-lit -vv --no-gtest-sharding -j128
/path/to/llvm-project/llvm/test/Unit`. The crash is gone with the fix
(same no-sharding repro)

**Original commit message:**
**Context:**

- In https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html and
commit
llvm@07670b3,
`cl::SubCommand` is introduced.
- Options that don't specify subcommand goes into a special 'top level'
subcommand.

**Motivating Use Case:**
- The motivating use case is to refactor `llvm-profdata` to use
`cl::SubCommand` to organize subcommands. See
llvm#71328. A valid use case that's
not supported before this patch is shown below

```
  // show-option{1,2} are associated with 'show' subcommand.
  // top-level-option3 is in top-level subcomand (e.g., `profile-isfs` in SampleProfReader.cpp)
  llvm-profdata show --show-option1 --show-option2 --top-level-option3
```

- Before this patch, option handler look-up will fail with the following
error message "Unknown command line argument --top-level-option3".
- After this patch, option handler look-up will look up in sub-command
options first, and use top-level subcommand as a fallback, so
'top-level-option3' is parsed correctly.
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…tions in llvm-profdata (llvm#71328)

- The motivation is to reduce the number of arguments passed around
(e.g., from `show_main` to `show*Profile`). In order to do this, move
function-defined options to global variables, and create
`cl::SubCommand` for {show, merge, overlap, order} to organize options.
- The side-effect by extracting function local options to a C++
namespace is that the extracted options are no longer (lazily)
initialized when the enclosing function runs for the first time.
- `cl::Subcommand` support (introduced in
https://lists.llvm.org/pipermail/llvm-dev/2016-June/101804.html) could
put options in a per-subcommand namespace.
- One option could belong to multiple subcommand. This patch defines
most of the options once and associates them with multiple subcommands
except
1. `overlap` and `show` both has `value-cutoff` with different default
values
([former](https://github.com/llvm/llvm-project/blob/64f62de96609dc3ea9a8a914a9e9445b7f4d625d/llvm/tools/llvm-profdata/llvm-profdata.cpp#L2352)
vs
[latter](https://github.com/llvm/llvm-project/blob/64f62de96609dc3ea9a8a914a9e9445b7f4d625d/llvm/tools/llvm-profdata/llvm-profdata.cpp#L3009)).
Define 'OverlapValueCutoff' and 'ShowValueCutoff' respectively.
2. `show` supports three profile formats in `ProfileKind` while
{`merge`, `overlap`} supports two. Define separate options.
- Clean up obsolete code as a result, including `-h` and `--version`
customizations. These two options are supported for all commands.
Results pasted.
- [-h and
--help](https://gist.github.com/minglotus-6/387490e5eeda2dd2f9c440a424d6f360)
output.
-
[--version](https://gist.github.com/minglotus-6/f905abcc3a346957bd797f2f84c18c1b)
- [llvm-profdata show
--help](https://gist.github.com/minglotus-6/f143079f02af243a94758138c0af471a)

This PR should be `llvm-profdata` only. It depends on
llvm#71981
ellishg added a commit that referenced this pull request May 16, 2024
#71328 refactored
`llvm-profdata.cpp` to use subcommands (which is super nice), but left
many unused `argv` variables. This opts to use `ProgName` where
necessary, and removes `argv` otherwise.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants