Skip to content

Commit e0dce31

Browse files
committed
[llvm-remarkutil] Add an instruction-mix tool
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 0f38543 commit e0dce31

File tree

6 files changed

+181
-0
lines changed

6 files changed

+181
-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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 --filter=meow | FileCheck %s --check-prefix=MEOW
6+
7+
; CHECK-LABEL: Instruction Count
8+
; CHECK-NEXT: ----------- -----
9+
; CHECK-NEXT: mul 20
10+
; CHECK-NEXT: add 15
11+
; CHECK-NEXT: nop 10
12+
13+
; CSV-LABEL: Instruction,Count
14+
; CSV-NEXT: mul,20
15+
; CSV-NEXT: add,15
16+
; CSV-NEXT: nop,10
17+
18+
; MEOW: Instruction Count
19+
; MEOW-NEXT: ----------- -----
20+
; MEOW-NEXT: mul 15
21+
; MEOW-NEXT: add 12
22+
; MEOW-NEXT: nop 9

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: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
2+
#include "RemarkUtilHelpers.h"
3+
#include "RemarkUtilRegistry.h"
4+
5+
#include "llvm/Support/Format.h"
6+
#include "llvm/Support/FormattedStream.h"
7+
#include "llvm/Support/Regex.h"
8+
9+
#include <numeric>
10+
11+
using namespace llvm;
12+
using namespace remarks;
13+
using namespace llvm::remarkutil;
14+
15+
namespace instructionmix {
16+
17+
static cl::SubCommand
18+
InstructionMix("instruction-mix",
19+
"Instruction Mix (requires asm-printer remarks)");
20+
21+
static cl::opt<std::string>
22+
FunctionFilter("filter", cl::sub(InstructionMix), cl::init(".*"),
23+
cl::value_desc("filter_regex"),
24+
cl::desc("regex to filter functions with"));
25+
26+
enum ReportStyleOptions { human_output, csv_output };
27+
static cl::opt<ReportStyleOptions> ReportStyle(
28+
"report_style", cl::sub(InstructionMix),
29+
cl::init(ReportStyleOptions::human_output),
30+
cl::desc("Choose the report output format:"),
31+
cl::values(clEnumValN(human_output, "human", "Human-readable format"),
32+
clEnumValN(csv_output, "csv", "CSV format")));
33+
34+
INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionMix)
35+
INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionMix)
36+
DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionMix)
37+
38+
static Error tryInstructionMix() {
39+
auto MaybeOF =
40+
getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
41+
if (!MaybeOF)
42+
return MaybeOF.takeError();
43+
44+
auto OF = std::move(*MaybeOF);
45+
auto MaybeBuf = getInputMemoryBuffer(InputFileName);
46+
if (!MaybeBuf)
47+
return MaybeBuf.takeError();
48+
auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
49+
if (!MaybeParser)
50+
return MaybeParser.takeError();
51+
52+
Regex Filter(FunctionFilter);
53+
54+
// Collect the histogram of instruction counts.
55+
std::unordered_map<std::string, unsigned> Histogram;
56+
auto &Parser = **MaybeParser;
57+
auto MaybeRemark = Parser.next();
58+
for (; MaybeRemark; MaybeRemark = Parser.next()) {
59+
auto &Remark = **MaybeRemark;
60+
if (Remark.RemarkName != "InstructionMix")
61+
continue;
62+
if (!Filter.match(Remark.FunctionName))
63+
continue;
64+
for (auto &Arg : Remark.Args) {
65+
StringRef Key = Arg.Key;
66+
if (!Key.consume_front("INST_"))
67+
continue;
68+
unsigned Val = 0;
69+
bool ParseError = Arg.Val.getAsInteger(10, Val);
70+
assert(!ParseError);
71+
(void)ParseError;
72+
Histogram[std::string(Key)] += Val;
73+
}
74+
}
75+
76+
// Sort it.
77+
using MixEntry = std::pair<std::string, unsigned>;
78+
llvm::SmallVector<MixEntry> Mix(Histogram.begin(), Histogram.end());
79+
std::sort(Mix.begin(), Mix.end(), [](const auto &LHS, const auto &RHS) {
80+
return LHS.second > RHS.second;
81+
});
82+
83+
// Print the results.
84+
switch (ReportStyle) {
85+
case human_output: {
86+
formatted_raw_ostream FOS(OF->os());
87+
size_t MaxMnemonic =
88+
std::accumulate(Mix.begin(), Mix.end(), StringRef("Instruction").size(),
89+
[](size_t MaxMnemonic, const MixEntry &Elt) {
90+
return std::max(MaxMnemonic, Elt.first.length());
91+
});
92+
unsigned MaxValue = std::accumulate(
93+
Mix.begin(), Mix.end(), 0, [](unsigned MaxValue, const MixEntry &Elt) {
94+
return std::max(MaxValue, Elt.second);
95+
});
96+
unsigned ValueWidth = log10(MaxValue) + 1;
97+
FOS << "Instruction";
98+
FOS.PadToColumn(MaxMnemonic + 1) << "Count\n";
99+
FOS << "-----------";
100+
FOS.PadToColumn(MaxMnemonic + 1) << "-----\n";
101+
for (const auto &[Inst, Count] : Mix) {
102+
FOS << Inst;
103+
FOS.PadToColumn(MaxMnemonic + 1)
104+
<< " " << format_decimal(Count, ValueWidth) << "\n";
105+
}
106+
} break;
107+
case csv_output: {
108+
OF->os() << "Instruction,Count\n";
109+
for (const auto &[Inst, Count] : Mix)
110+
OF->os() << Inst << "," << Count << "\n";
111+
} break;
112+
}
113+
114+
auto E = MaybeRemark.takeError();
115+
if (!E.isA<EndOfFileError>())
116+
return E;
117+
consumeError(std::move(E));
118+
OF->keep();
119+
return Error::success();
120+
}
121+
122+
static CommandRegistration InstructionMixReg(&InstructionMix,
123+
tryInstructionMix);
124+
125+
} // namespace instructionmix

0 commit comments

Comments
 (0)