Skip to content

Commit cb647ec

Browse files
authored
[llvm-remarkutil] Add an instruction-mix tool (#140598)
The new tool constructs a histogram of instruction frequencies, optionally filtered by function name via a regex. It can display in either a human-readable table format, or machine-readable CSV.
1 parent 5a7931f commit cb647ec

File tree

6 files changed

+214
-0
lines changed

6 files changed

+214
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--- !Analysis
2+
Pass: asm-printer
3+
Name: InstructionMix
4+
Function: home
5+
Args:
6+
- INST_nop: '1'
7+
- INST_add: '3'
8+
- INST_mul: '5'
9+
...
10+
--- !Analysis
11+
Pass: asm-printer
12+
Name: InstructionMix
13+
Function: homeowner
14+
Args:
15+
- INST_nop: '2'
16+
- INST_add: '4'
17+
- INST_mul: '6'
18+
...
19+
--- !Analysis
20+
Pass: asm-printer
21+
Name: InstructionMix
22+
Function: meow
23+
Args:
24+
- INST_nop: '7'
25+
- INST_add: '8'
26+
- INST_mul: '9'
27+
...

llvm/test/tools/llvm-remarkutil/broken-yaml-remark.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
22
RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
3+
RUN: not llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
34
RUN: not llvm-remarkutil annotation-count --parser=yaml --annotation-type=remark %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
45
RUN: not llvm-remarkutil count --parser=yaml %p/Inputs/broken-remark -o - 2>&1 | FileCheck %s
56

llvm/test/tools/llvm-remarkutil/empty-file.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
RUN: not llvm-remarkutil yaml2bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
22
RUN: not llvm-remarkutil instruction-count --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
3+
RUN: not llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
34
RUN: not llvm-remarkutil annotation-count --parser=yaml --annotation-type=remark %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
45
RUN: not llvm-remarkutil count --parser=yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --check-prefix=YAMLPARSER
56
RUN: llvm-remarkutil bitstream2yaml %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=BITSTREAM2YAML
67
RUN: llvm-remarkutil instruction-count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=SIZEBITSTREAM
8+
RUN: llvm-remarkutil instruction-mix --parser=bitstream %p/Inputs/empty-file --report_style=csv -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=MIXBITSTREAM
79
RUN: llvm-remarkutil annotation-count --parser=bitstream --annotation-type=remark %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=ANNOTATIONBITSTREAM
810
RUN: llvm-remarkutil count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | FileCheck %s --allow-empty --check-prefix=COUNTBITSTREAM
911

@@ -20,3 +22,6 @@ RUN: llvm-remarkutil count --parser=bitstream %p/Inputs/empty-file -o - 2>&1 | F
2022

2123
; COUNTBITSTREAM-LABEL: Source,Count
2224
; COUNTBITSTREAM-EMPTY:
25+
26+
; MIXBITSTREAM-LABEL: Instruction,Count
27+
; MIXBITSTREAM-EMPTY:
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml | FileCheck %s
2+
RUN: llvm-remarkutil yaml2bitstream %p/Inputs/instruction-mix.yaml | llvm-remarkutil instruction-mix --parser=bitstream | FileCheck %s
3+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --report_style=human | FileCheck %s
4+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --report_style=csv | FileCheck %s --check-prefix=CSV
5+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --rfilter=meow | FileCheck %s --check-prefix=MEOW-RE
6+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --filter=meow | FileCheck %s --check-prefix=MEOW-EXACT
7+
RUN: llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --filter=none | FileCheck %s --check-prefix=NONE-EXACT
8+
RUN: not llvm-remarkutil instruction-mix --parser=yaml %p/Inputs/instruction-mix.yaml --rfilter=* 2>&1 | FileCheck %s --check-prefix=ERROR
9+
10+
; CHECK-LABEL: Instruction Count
11+
; CHECK-NEXT: ----------- -----
12+
; CHECK-NEXT: mul 20
13+
; CHECK-NEXT: add 15
14+
; CHECK-NEXT: nop 10
15+
16+
; CSV-LABEL: Instruction,Count
17+
; CSV-NEXT: mul,20
18+
; CSV-NEXT: add,15
19+
; CSV-NEXT: nop,10
20+
21+
; MEOW-RE: Instruction Count
22+
; MEOW-RE-NEXT: ----------- -----
23+
; MEOW-RE-NEXT: mul 15
24+
; MEOW-RE-NEXT: add 12
25+
; MEOW-RE-NEXT: nop 9
26+
27+
; MEOW-EXACT: Instruction Count
28+
; MEOW-EXACT-NEXT: ----------- -----
29+
; MEOW-EXACT-NEXT: mul 9
30+
; MEOW-EXACT-NEXT: add 8
31+
; MEOW-EXACT-NEXT: nop 7
32+
33+
; NONE-EXACT: Instruction Count
34+
; NONE-EXACT: ----------- -----
35+
; NONE-NOT: {{.*}}
36+
37+
; ERROR: error: invalid argument '--rfilter=*': repetition-operator operand invalid

llvm/tools/llvm-remarkutil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_llvm_tool(llvm-remarkutil
88
RemarkConvert.cpp
99
RemarkCount.cpp
1010
RemarkCounter.cpp
11+
RemarkInstructionMix.cpp
1112
RemarkSizeDiff.cpp
1213
RemarkUtil.cpp
1314
RemarkUtilHelpers.cpp
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//===- RemarkInstructionMix.cpp -------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Generic tool to extract instruction mix from asm-printer remarks.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "RemarkUtilHelpers.h"
14+
#include "RemarkUtilRegistry.h"
15+
16+
#include "llvm/Support/Format.h"
17+
#include "llvm/Support/FormattedStream.h"
18+
#include "llvm/Support/Regex.h"
19+
20+
#include <cmath>
21+
#include <numeric>
22+
23+
using namespace llvm;
24+
using namespace remarks;
25+
using namespace llvm::remarkutil;
26+
27+
namespace instructionmix {
28+
29+
static cl::SubCommand
30+
InstructionMix("instruction-mix",
31+
"Instruction Mix (requires asm-printer remarks)");
32+
33+
static cl::opt<std::string>
34+
FunctionFilter("filter", cl::sub(InstructionMix), cl::ValueOptional,
35+
cl::desc("Optional function name to filter collection by"));
36+
37+
static cl::opt<std::string>
38+
FunctionFilterRE("rfilter", cl::sub(InstructionMix), cl::ValueOptional,
39+
cl::desc("Optional function name to filter collection by "
40+
"(accepts regular expressions)"));
41+
42+
enum ReportStyleOptions { human_output, csv_output };
43+
static cl::opt<ReportStyleOptions> ReportStyle(
44+
"report_style", cl::sub(InstructionMix),
45+
cl::init(ReportStyleOptions::human_output),
46+
cl::desc("Choose the report output format:"),
47+
cl::values(clEnumValN(human_output, "human", "Human-readable format"),
48+
clEnumValN(csv_output, "csv", "CSV format")));
49+
50+
INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionMix)
51+
INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionMix)
52+
53+
static Error tryInstructionMix() {
54+
auto MaybeOF =
55+
getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
56+
if (!MaybeOF)
57+
return MaybeOF.takeError();
58+
59+
auto OF = std::move(*MaybeOF);
60+
auto MaybeBuf = getInputMemoryBuffer(InputFileName);
61+
if (!MaybeBuf)
62+
return MaybeBuf.takeError();
63+
auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
64+
if (!MaybeParser)
65+
return MaybeParser.takeError();
66+
67+
Expected<std::optional<FilterMatcher>> Filter =
68+
FilterMatcher::createExactOrRE(FunctionFilter, FunctionFilterRE);
69+
if (!Filter)
70+
return Filter.takeError();
71+
72+
// Collect the histogram of instruction counts.
73+
llvm::DenseMap<StringRef, unsigned> Histogram;
74+
auto &Parser = **MaybeParser;
75+
auto MaybeRemark = Parser.next();
76+
for (; MaybeRemark; MaybeRemark = Parser.next()) {
77+
Remark &Remark = **MaybeRemark;
78+
if (Remark.RemarkName != "InstructionMix")
79+
continue;
80+
if (*Filter && !(*Filter)->match(Remark.FunctionName))
81+
continue;
82+
for (auto &Arg : Remark.Args) {
83+
StringRef Key = Arg.Key;
84+
if (!Key.consume_front("INST_"))
85+
continue;
86+
unsigned Val = 0;
87+
bool ParseError = Arg.Val.getAsInteger(10, Val);
88+
assert(!ParseError);
89+
(void)ParseError;
90+
Histogram[Key] += Val;
91+
}
92+
}
93+
94+
// Sort it.
95+
using MixEntry = std::pair<StringRef, unsigned>;
96+
llvm::SmallVector<MixEntry> Mix(Histogram.begin(), Histogram.end());
97+
std::sort(Mix.begin(), Mix.end(), [](const auto &LHS, const auto &RHS) {
98+
return LHS.second > RHS.second;
99+
});
100+
101+
// Print the results.
102+
switch (ReportStyle) {
103+
case human_output: {
104+
formatted_raw_ostream FOS(OF->os());
105+
size_t MaxMnemonic =
106+
std::accumulate(Mix.begin(), Mix.end(), StringRef("Instruction").size(),
107+
[](size_t MaxMnemonic, const MixEntry &Elt) {
108+
return std::max(MaxMnemonic, Elt.first.size());
109+
});
110+
unsigned MaxValue = std::accumulate(
111+
Mix.begin(), Mix.end(), 1, [](unsigned MaxValue, const MixEntry &Elt) {
112+
return std::max(MaxValue, Elt.second);
113+
});
114+
unsigned ValueWidth = std::log10(MaxValue) + 1;
115+
FOS << "Instruction";
116+
FOS.PadToColumn(MaxMnemonic + 1) << "Count\n";
117+
FOS << "-----------";
118+
FOS.PadToColumn(MaxMnemonic + 1) << "-----\n";
119+
for (const auto &[Inst, Count] : Mix) {
120+
FOS << Inst;
121+
FOS.PadToColumn(MaxMnemonic + 1)
122+
<< " " << format_decimal(Count, ValueWidth) << "\n";
123+
}
124+
} break;
125+
case csv_output: {
126+
OF->os() << "Instruction,Count\n";
127+
for (const auto &[Inst, Count] : Mix)
128+
OF->os() << Inst << "," << Count << "\n";
129+
} break;
130+
}
131+
132+
auto E = MaybeRemark.takeError();
133+
if (!E.isA<EndOfFileError>())
134+
return E;
135+
consumeError(std::move(E));
136+
OF->keep();
137+
return Error::success();
138+
}
139+
140+
static CommandRegistration InstructionMixReg(&InstructionMix,
141+
tryInstructionMix);
142+
143+
} // namespace instructionmix

0 commit comments

Comments
 (0)