[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