[llvm] a4591a6 - [llvm-remarkutil] Add an option to print out function sizes

Jessica Paquette via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 28 15:46:33 PDT 2022


Author: Jessica Paquette
Date: 2022-09-28T15:45:55-07:00
New Revision: a4591a61df9c7d501012fa191ed8bc406836afee

URL: https://github.com/llvm/llvm-project/commit/a4591a61df9c7d501012fa191ed8bc406836afee
DIFF: https://github.com/llvm/llvm-project/commit/a4591a61df9c7d501012fa191ed8bc406836afee.diff

LOG: [llvm-remarkutil] Add an option to print out function sizes

This adds an `instruction-count` command to llvm-remarkutil.

```
llvm-remarkutil instruction-count --parser=<bitstream|yaml> <file>
```

This will, for now, only print out asm-printer `InstructionCount` remarks.

Frequently I need to find out things like "what are the top 10 largest
functions" in a given project.

This makes it so we can find that information quickly and easily from any
format of remarks.

I chose a CSV because I usually want to stick these into a spreadsheet, and
the data is two-dimensional.

In the future, we may want to change this to another format if we add more
complicated data.

Differential Revision: https://reviews.llvm.org/D134765

Added: 
    llvm/test/tools/llvm-remarkutil/Inputs/instruction-count.yaml
    llvm/test/tools/llvm-remarkutil/Inputs/made-up-fake-remarks.yaml
    llvm/test/tools/llvm-remarkutil/instruction-count.test
    llvm/test/tools/llvm-remarkutil/no-instruction-count.test

Modified: 
    llvm/docs/CommandGuide/llvm-remarkutil.rst
    llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
    llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
    llvm/test/tools/llvm-remarkutil/empty-file.test
    llvm/tools/llvm-remarkutil/RemarkUtil.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-remarkutil.rst b/llvm/docs/CommandGuide/llvm-remarkutil.rst
index 401bc00848eed..481774a6bd358 100644
--- a/llvm/docs/CommandGuide/llvm-remarkutil.rst
+++ b/llvm/docs/CommandGuide/llvm-remarkutil.rst
@@ -19,6 +19,7 @@ Subcommands
 
   * :ref:`bitstream2yaml_subcommand` - Reserialize bitstream remarks to YAML.
   * :ref:`yaml2bitstream_subcommand` - Reserialize YAML remarks to bitstream.
+  * :ref:`instruction-count_subcommand` - Output function instruction counts.
 
 .. _bitstream2yaml_subcommand:
 
@@ -48,3 +49,26 @@ Summary
 
 Takes a YAML remark file as input, and reserializes that file in the bitstream
 format.
+
+.. _instruction-count_subcommand:
+
+instruction-count
+~~~~~~~~~~~~~~~~~
+
+.. program:: llvm-remarkutil instruction-count
+
+USAGE: :program:`llvm-remarkutil` instruction-count <input file> --parser=<bitstream|yaml> -o <output file>
+
+Summary
+^^^^^^^
+
+Outputs instruction count remarks for every function. Instruction count remarks
+encode the number of instructions in a function at assembly printing time.
+
+Instruction count remarks require asm-printer remarks.
+
+CSV format is as follows:
+
+::
+  Function,InstructionCount
+  foo,123

diff  --git a/llvm/test/tools/llvm-remarkutil/Inputs/instruction-count.yaml b/llvm/test/tools/llvm-remarkutil/Inputs/instruction-count.yaml
new file mode 100644
index 0000000000000..b6efe16a639f6
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/Inputs/instruction-count.yaml
@@ -0,0 +1,24 @@
+--- !Analysis
+Pass:            asm-printer
+Name:            InstructionCount
+Function:        func1
+Args:
+  - NumInstructions: '1'
+  - String:          ' instructions in function'
+...
+--- !Analysis
+Pass:            asm-printer
+Name:            InstructionCount
+Function:        func2
+Args:
+  - NumInstructions: '2'
+  - String:          ' instructions in function'
+...
+--- !Analysis
+Pass:            asm-printer
+Name:            InstructionCount
+Function:        func3
+Args:
+  - NumInstructions: '3'
+  - String:          ' instructions in function'
+...

diff  --git a/llvm/test/tools/llvm-remarkutil/Inputs/made-up-fake-remarks.yaml b/llvm/test/tools/llvm-remarkutil/Inputs/made-up-fake-remarks.yaml
new file mode 100644
index 0000000000000..00abc24f0e675
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/Inputs/made-up-fake-remarks.yaml
@@ -0,0 +1,12 @@
+--- !Analysis
+Pass:            foo0
+Name:            bar0
+Function:        baz0
+Args:
+  - Arg:   'arg'
+--- !Analysis
+Pass:            foo1
+Name:            bar1
+Function:        baz1
+Args:
+  - Arg:   'arg'

diff  --git a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
index 3a81beed03333..9f37c57f4f034 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-bitstream-remark.test
@@ -1,2 +1,3 @@
 RUN: not llvm-remarkutil bitstream2yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
+RUN: not llvm-remarkutil instruction-count --parser=bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 CHECK: error: Unknown magic number: expecting RMRK, got --- .

diff  --git a/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test b/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
index d966725d63ac1..764a839fc0fb8 100644
--- a/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
+++ b/llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test
@@ -1,2 +1,3 @@
 RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
+RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
 CHECK: error: Type, Pass, Name or Function missing

diff  --git a/llvm/test/tools/llvm-remarkutil/empty-file.test b/llvm/test/tools/llvm-remarkutil/empty-file.test
index 96bd1871b2410..67dfea4bc7803 100644
--- a/llvm/test/tools/llvm-remarkutil/empty-file.test
+++ b/llvm/test/tools/llvm-remarkutil/empty-file.test
@@ -1,7 +1,12 @@
-RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAML2BITSTREAM
+RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
+RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
 RUN: llvm-remarkutil bitstream2yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=BITSTREAM2YAML
+RUN: llvm-remarkutil instruction-count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=SIZEBITSTREAM
 
-; YAML2BITSTREAM: error: document root is not of mapping type.
+; YAMLPARSER: error: document root is not of mapping type.
 
 ; An empty bitstream file is valid.
 ; BITSTREAM2YAML-NOT: error
+
+; SIZEBITSTREAM-LABEL: Function,InstructionCount
+; SIZEBITSTREAM-EMPTY

diff  --git a/llvm/test/tools/llvm-remarkutil/instruction-count.test b/llvm/test/tools/llvm-remarkutil/instruction-count.test
new file mode 100644
index 0000000000000..d5f62e36c13ee
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/instruction-count.test
@@ -0,0 +1,7 @@
+RUN: llvm-remarkutil instruction-count --parser=yaml %p/Inputs/instruction-count.yaml | FileCheck %s
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-count.yaml | llvm-remarkutil instruction-count --parser=bitstream | FileCheck %s
+
+; CHECK-LABEL: Function,InstructionCount
+; CHECK: func1,1
+; CHECK: func2,2
+; CHECK: func3,3

diff  --git a/llvm/test/tools/llvm-remarkutil/no-instruction-count.test b/llvm/test/tools/llvm-remarkutil/no-instruction-count.test
new file mode 100644
index 0000000000000..33838796f9cca
--- /dev/null
+++ b/llvm/test/tools/llvm-remarkutil/no-instruction-count.test
@@ -0,0 +1,5 @@
+RUN: llvm-remarkutil instruction-count --parser=yaml %p/Inputs/made-up-fake-remarks.yaml | FileCheck %s
+RUN: llvm-remarkutil yaml2bitstream %p/Inputs/made-up-fake-remarks.yaml | llvm-remarkutil instruction-count --parser=bitstream | FileCheck %s
+
+; CHECK-LABEL: Function,InstructionCount
+; CHECK-EMPTY

diff  --git a/llvm/tools/llvm-remarkutil/RemarkUtil.cpp b/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
index ecd56b5d46cbe..0412eae954ac9 100644
--- a/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
+++ b/llvm/tools/llvm-remarkutil/RemarkUtil.cpp
@@ -35,12 +35,14 @@ static cl::SubCommand
 static cl::SubCommand
     Bitstream2YAML("bitstream2yaml",
                    "Convert bitstream remarks to YAML remarks");
+static cl::SubCommand InstructionCount(
+    "instruction-count",
+    "Function instruction count information (requires asm-printer remarks)");
 } // namespace subopts
 
-// Conversions have the same command line options. AFAIK there is no way to
-// reuse them, so to avoid duplication, let's just stick this in a hideous
-// macro.
-#define CONVERSION_COMMAND_LINE_OPTIONS(SUBOPT)                                \
+// Keep input + output help + names consistent across the various modes via a
+// hideous macro.
+#define INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SUBOPT)                              \
   static cl::opt<std::string> InputFileName(                                   \
       cl::Positional, cl::cat(RemarkUtilCategory), cl::init("-"),              \
       cl::desc("<input file>"), cl::sub(SUBOPT));                              \
@@ -52,7 +54,7 @@ namespace yaml2bitstream {
 static constexpr Format InputFormat = Format::YAML;
 /// Remark format to output.
 static constexpr Format OutputFormat = Format::Bitstream;
-CONVERSION_COMMAND_LINE_OPTIONS(subopts::YAML2Bitstream)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::YAML2Bitstream)
 } // namespace yaml2bitstream
 
 namespace bitstream2yaml {
@@ -60,9 +62,18 @@ namespace bitstream2yaml {
 static constexpr Format InputFormat = Format::Bitstream;
 /// Remark format to output.
 static constexpr Format OutputFormat = Format::YAML;
-CONVERSION_COMMAND_LINE_OPTIONS(subopts::Bitstream2YAML)
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::Bitstream2YAML)
 } // namespace bitstream2yaml
 
+namespace instructioncount {
+static cl::opt<Format> InputFormat(
+    "parser", cl::desc("Input remark format to parse"),
+    cl::values(clEnumValN(Format::YAML, "yaml", "YAML"),
+               clEnumValN(Format::Bitstream, "bitstream", "Bitstream")),
+    cl::sub(subopts::InstructionCount));
+INPUT_OUTPUT_COMMAND_LINE_OPTIONS(subopts::InstructionCount)
+} // namespace instructioncount
+
 /// \returns A MemoryBuffer for the input file on success, and an Error
 /// otherwise.
 static Expected<std::unique_ptr<MemoryBuffer>>
@@ -75,14 +86,15 @@ getInputMemoryBuffer(StringRef InputFileName) {
   return std::move(*MaybeBuf);
 }
 
-/// \returns A ToolOutputFile which can be used for writing remarks on success,
-/// and an Error otherwise.
+/// \returns A ToolOutputFile which can be used for outputting the results of
+/// some tool mode.
+/// \p OutputFileName is the desired destination.
+/// \p Flags controls whether or not the file is opened for writing in text
+/// mode, as a binary, etc. See sys::fs::OpenFlags for more detail.
 static Expected<std::unique_ptr<ToolOutputFile>>
-getOutputFile(StringRef OutputFileName, Format OutputFormat) {
+getOutputFileWithFlags(StringRef OutputFileName, sys::fs::OpenFlags Flags) {
   if (OutputFileName == "")
     OutputFileName = "-";
-  auto Flags = OutputFormat == Format::YAML ? sys::fs::OF_TextWithCRLF
-                                            : sys::fs::OF_None;
   std::error_code ErrorCode;
   auto OF = std::make_unique<ToolOutputFile>(OutputFileName, ErrorCode, Flags);
   if (ErrorCode)
@@ -90,6 +102,19 @@ getOutputFile(StringRef OutputFileName, Format OutputFormat) {
   return std::move(OF);
 }
 
+/// \returns A ToolOutputFile which can be used for writing remarks on success,
+/// and an Error otherwise.
+/// \p OutputFileName is the desired destination.
+/// \p OutputFormat
+static Expected<std::unique_ptr<ToolOutputFile>>
+getOutputFileForRemarks(StringRef OutputFileName, Format OutputFormat) {
+  assert((OutputFormat == Format::YAML || OutputFormat == Format::Bitstream) &&
+         "Expected one of YAML or Bitstream!");
+  return getOutputFileWithFlags(OutputFileName, OutputFormat == Format::YAML
+                                                    ? sys::fs::OF_TextWithCRLF
+                                                    : sys::fs::OF_None);
+}
+
 namespace yaml2bitstream {
 /// Parses all remarks in the input YAML file.
 /// \p [out] ParsedRemarks - Filled with remarks parsed from the input file.
@@ -125,7 +150,7 @@ tryParseRemarksFromYAMLFile(std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
 static Error tryReserializeYAML2Bitstream(
     const std::vector<std::unique_ptr<Remark>> &ParsedRemarks,
     StringTable &StrTab) {
-  auto MaybeOF = getOutputFile(OutputFileName, OutputFormat);
+  auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
   if (!MaybeOF)
     return MaybeOF.takeError();
   auto OF = std::move(*MaybeOF);
@@ -155,7 +180,7 @@ namespace bitstream2yaml {
 /// \returns An Error if reserialization fails, or Error::success() on success.
 static Error tryBitstream2YAML() {
   // Create the serializer.
-  auto MaybeOF = getOutputFile(OutputFileName, OutputFormat);
+  auto MaybeOF = getOutputFileForRemarks(OutputFileName, OutputFormat);
   if (!MaybeOF)
     return MaybeOF.takeError();
   auto OF = std::move(*MaybeOF);
@@ -186,6 +211,49 @@ static Error tryBitstream2YAML() {
 }
 } // namespace bitstream2yaml
 
+namespace instructioncount {
+/// Outputs all instruction count remarks in the file as a CSV.
+/// \returns Error::success() on success, and an Error otherwise.
+static Error tryInstructionCount() {
+  // Create the output buffer.
+  auto MaybeOF = getOutputFileWithFlags(OutputFileName,
+                                        /*Flags = */ sys::fs::OF_TextWithCRLF);
+  if (!MaybeOF)
+    return MaybeOF.takeError();
+  auto OF = std::move(*MaybeOF);
+  // Create a parser for the user-specified input format.
+  auto MaybeBuf = getInputMemoryBuffer(InputFileName);
+  if (!MaybeBuf)
+    return MaybeBuf.takeError();
+  auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
+  if (!MaybeParser)
+    return MaybeParser.takeError();
+  // Emit CSV header.
+  OF->os() << "Function,InstructionCount\n";
+  // Parse all remarks. Whenever we see an instruction count remark, output
+  // the file name and the number of instructions.
+  auto &Parser = **MaybeParser;
+  auto MaybeRemark = Parser.next();
+  for (; MaybeRemark; MaybeRemark = Parser.next()) {
+    auto &Remark = **MaybeRemark;
+    if (Remark.RemarkName != "InstructionCount")
+      continue;
+    auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
+      return Arg.Key == "NumInstructions";
+    });
+    assert(InstrCountArg != Remark.Args.end() &&
+           "Expected instruction count remarks to have a NumInstructions key?");
+    OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
+  }
+  auto E = MaybeRemark.takeError();
+  if (!E.isA<EndOfFileError>())
+    return E;
+  consumeError(std::move(E));
+  OF->keep();
+  return Error::success();
+}
+} // namespace instructioncount
+
 /// Handle user-specified suboptions (e.g. yaml2bitstream, bitstream2yaml).
 /// \returns An Error if the specified suboption fails or if no suboption was
 /// specified. Otherwise, Error::success().
@@ -194,6 +262,8 @@ static Error handleSuboptions() {
     return bitstream2yaml::tryBitstream2YAML();
   if (subopts::YAML2Bitstream)
     return yaml2bitstream::tryYAML2Bitstream();
+  if (subopts::InstructionCount)
+    return instructioncount::tryInstructionCount();
   return make_error<StringError>(
       "Please specify a subcommand. (See -help for options)",
       inconvertibleErrorCode());


        


More information about the llvm-commits mailing list