Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.cpp
35231 views
1
//===- RemarkCounter.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 count remarks based on properties
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "RemarkCounter.h"
14
#include "RemarkUtilRegistry.h"
15
#include "llvm/Support/CommandLine.h"
16
#include "llvm/Support/Regex.h"
17
18
using namespace llvm;
19
using namespace remarks;
20
using namespace llvm::remarkutil;
21
22
static cl::SubCommand CountSub("count",
23
"Collect remarks based on specified criteria.");
24
25
INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub)
26
INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub)
27
28
static cl::list<std::string>
29
Keys("args", cl::desc("Specify remark argument/s to count by."),
30
cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
31
static cl::list<std::string> RKeys(
32
"rargs",
33
cl::desc(
34
"Specify remark argument/s to count (accepts regular expressions)."),
35
cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);
36
static cl::opt<std::string>
37
RemarkNameOpt("remark-name",
38
cl::desc("Optional remark name to filter collection by."),
39
cl::ValueOptional, cl::sub(CountSub));
40
static cl::opt<std::string>
41
PassNameOpt("pass-name", cl::ValueOptional,
42
cl::desc("Optional remark pass name to filter collection by."),
43
cl::sub(CountSub));
44
45
static cl::opt<std::string> RemarkFilterArgByOpt(
46
"filter-arg-by", cl::desc("Optional remark arg to filter collection by."),
47
cl::ValueOptional, cl::sub(CountSub));
48
static cl::opt<std::string>
49
RemarkNameOptRE("rremark-name",
50
cl::desc("Optional remark name to filter collection by "
51
"(accepts regular expressions)."),
52
cl::ValueOptional, cl::sub(CountSub));
53
static cl::opt<std::string>
54
RemarkArgFilterOptRE("rfilter-arg-by",
55
cl::desc("Optional remark arg to filter collection by "
56
"(accepts regular expressions)."),
57
cl::sub(CountSub), cl::ValueOptional);
58
static cl::opt<std::string>
59
PassNameOptRE("rpass-name", cl::ValueOptional,
60
cl::desc("Optional remark pass name to filter collection "
61
"by (accepts regular expressions)."),
62
cl::sub(CountSub));
63
static cl::opt<Type> RemarkTypeOpt(
64
"remark-type", cl::desc("Optional remark type to filter collection by."),
65
cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"),
66
clEnumValN(Type::Passed, "passed", "PASSED"),
67
clEnumValN(Type::Missed, "missed", "MISSED"),
68
clEnumValN(Type::Analysis, "analysis", "ANALYSIS"),
69
clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute",
70
"ANALYSIS_FP_COMMUTE"),
71
clEnumValN(Type::AnalysisAliasing, "analysis-aliasing",
72
"ANALYSIS_ALIASING"),
73
clEnumValN(Type::Failure, "failure", "FAILURE")),
74
cl::init(Type::Failure), cl::sub(CountSub));
75
static cl::opt<CountBy> CountByOpt(
76
"count-by", cl::desc("Specify the property to collect remarks by."),
77
cl::values(
78
clEnumValN(CountBy::REMARK, "remark-name",
79
"Counts individual remarks based on how many of the remark "
80
"exists."),
81
clEnumValN(CountBy::ARGUMENT, "arg",
82
"Counts based on the value each specified argument has. The "
83
"argument has to have a number value to be considered.")),
84
cl::init(CountBy::REMARK), cl::sub(CountSub));
85
static cl::opt<GroupBy> GroupByOpt(
86
"group-by", cl::desc("Specify the property to group remarks by."),
87
cl::values(
88
clEnumValN(
89
GroupBy::PER_SOURCE, "source",
90
"Display the count broken down by the filepath of each remark "
91
"emitted. Requires remarks to have DebugLoc information."),
92
clEnumValN(GroupBy::PER_FUNCTION, "function",
93
"Breakdown the count by function name."),
94
clEnumValN(
95
GroupBy::PER_FUNCTION_WITH_DEBUG_LOC, "function-with-loc",
96
"Breakdown the count by function name taking into consideration "
97
"the filepath info from the DebugLoc of the remark."),
98
clEnumValN(GroupBy::TOTAL, "total",
99
"Output the total number corresponding to the count for the "
100
"provided input file.")),
101
cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub));
102
103
/// Look for matching argument with \p Key in \p Remark and return the parsed
104
/// integer value or 0 if it is has no integer value.
105
static unsigned getValForKey(StringRef Key, const Remark &Remark) {
106
auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {
107
return Arg.Key == Key && Arg.isValInt();
108
});
109
if (RemarkArg == Remark.Args.end())
110
return 0;
111
return *RemarkArg->getValAsInt();
112
}
113
114
Error Filters::regexArgumentsValid() {
115
if (RemarkNameFilter && RemarkNameFilter->IsRegex)
116
if (auto E = checkRegex(RemarkNameFilter->FilterRE))
117
return E;
118
if (PassNameFilter && PassNameFilter->IsRegex)
119
if (auto E = checkRegex(PassNameFilter->FilterRE))
120
return E;
121
if (ArgFilter && ArgFilter->IsRegex)
122
if (auto E = checkRegex(ArgFilter->FilterRE))
123
return E;
124
return Error::success();
125
}
126
127
bool Filters::filterRemark(const Remark &Remark) {
128
if (RemarkNameFilter && !RemarkNameFilter->match(Remark.RemarkName))
129
return false;
130
if (PassNameFilter && !PassNameFilter->match(Remark.PassName))
131
return false;
132
if (RemarkTypeFilter)
133
return *RemarkTypeFilter == Remark.RemarkType;
134
if (ArgFilter) {
135
if (!any_of(Remark.Args,
136
[this](Argument Arg) { return ArgFilter->match(Arg.Val); }))
137
return false;
138
}
139
return true;
140
}
141
142
Error ArgumentCounter::getAllMatchingArgumentsInRemark(
143
StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) {
144
auto MaybeParser = createRemarkParser(InputFormat, Buffer);
145
if (!MaybeParser)
146
return MaybeParser.takeError();
147
auto &Parser = **MaybeParser;
148
auto MaybeRemark = Parser.next();
149
for (; MaybeRemark; MaybeRemark = Parser.next()) {
150
auto &Remark = **MaybeRemark;
151
// Only collect keys from remarks included in the filter.
152
if (!Filter.filterRemark(Remark))
153
continue;
154
for (auto &Key : Arguments) {
155
for (Argument Arg : Remark.Args)
156
if (Key.match(Arg.Key) && Arg.isValInt())
157
ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()});
158
}
159
}
160
161
auto E = MaybeRemark.takeError();
162
if (!E.isA<EndOfFileError>())
163
return E;
164
consumeError(std::move(E));
165
return Error::success();
166
}
167
168
std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {
169
switch (Group) {
170
case GroupBy::PER_FUNCTION:
171
return Remark.FunctionName.str();
172
case GroupBy::TOTAL:
173
return "Total";
174
case GroupBy::PER_SOURCE:
175
case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
176
if (!Remark.Loc.has_value())
177
return std::nullopt;
178
179
if (Group == GroupBy::PER_FUNCTION_WITH_DEBUG_LOC)
180
return Remark.Loc->SourceFilePath.str() + ":" + Remark.FunctionName.str();
181
return Remark.Loc->SourceFilePath.str();
182
}
183
llvm_unreachable("Fully covered switch above!");
184
}
185
186
void ArgumentCounter::collect(const Remark &Remark) {
187
SmallVector<unsigned, 4> Row(ArgumentSetIdxMap.size());
188
std::optional<std::string> GroupByKey = getGroupByKey(Remark);
189
// Early return if we don't have a value
190
if (!GroupByKey)
191
return;
192
auto GroupVal = *GroupByKey;
193
CountByKeysMap.insert({GroupVal, Row});
194
for (auto [Key, Idx] : ArgumentSetIdxMap) {
195
auto Count = getValForKey(Key, Remark);
196
CountByKeysMap[GroupVal][Idx] += Count;
197
}
198
}
199
200
void RemarkCounter::collect(const Remark &Remark) {
201
std::optional<std::string> Key = getGroupByKey(Remark);
202
if (!Key.has_value())
203
return;
204
auto Iter = CountedByRemarksMap.insert({*Key, 1});
205
if (!Iter.second)
206
Iter.first->second += 1;
207
}
208
209
Error ArgumentCounter::print(StringRef OutputFileName) {
210
auto MaybeOF =
211
getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
212
if (!MaybeOF)
213
return MaybeOF.takeError();
214
215
auto OF = std::move(*MaybeOF);
216
OF->os() << groupByToStr(Group) << ",";
217
unsigned Idx = 0;
218
for (auto [Key, _] : ArgumentSetIdxMap) {
219
OF->os() << Key;
220
if (Idx != ArgumentSetIdxMap.size() - 1)
221
OF->os() << ",";
222
Idx++;
223
}
224
OF->os() << "\n";
225
for (auto [Header, CountVector] : CountByKeysMap) {
226
OF->os() << Header << ",";
227
unsigned Idx = 0;
228
for (auto Count : CountVector) {
229
OF->os() << Count;
230
if (Idx != ArgumentSetIdxMap.size() - 1)
231
OF->os() << ",";
232
Idx++;
233
}
234
OF->os() << "\n";
235
}
236
return Error::success();
237
}
238
239
Error RemarkCounter::print(StringRef OutputFileName) {
240
auto MaybeOF =
241
getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);
242
if (!MaybeOF)
243
return MaybeOF.takeError();
244
245
auto OF = std::move(*MaybeOF);
246
OF->os() << groupByToStr(Group) << ","
247
<< "Count\n";
248
for (auto [Key, Count] : CountedByRemarksMap)
249
OF->os() << Key << "," << Count << "\n";
250
OF->keep();
251
return Error::success();
252
}
253
254
Expected<Filters> getRemarkFilter() {
255
// Create Filter properties.
256
std::optional<FilterMatcher> RemarkNameFilter;
257
std::optional<FilterMatcher> PassNameFilter;
258
std::optional<FilterMatcher> RemarkArgFilter;
259
std::optional<Type> RemarkType;
260
if (!RemarkNameOpt.empty())
261
RemarkNameFilter = {RemarkNameOpt, false};
262
else if (!RemarkNameOptRE.empty())
263
RemarkNameFilter = {RemarkNameOptRE, true};
264
if (!PassNameOpt.empty())
265
PassNameFilter = {PassNameOpt, false};
266
else if (!PassNameOptRE.empty())
267
PassNameFilter = {PassNameOptRE, true};
268
if (RemarkTypeOpt != Type::Failure)
269
RemarkType = RemarkTypeOpt;
270
if (!RemarkFilterArgByOpt.empty())
271
RemarkArgFilter = {RemarkFilterArgByOpt, false};
272
else if (!RemarkArgFilterOptRE.empty())
273
RemarkArgFilter = {RemarkArgFilterOptRE, true};
274
// Create RemarkFilter.
275
return Filters::createRemarkFilter(std::move(RemarkNameFilter),
276
std::move(PassNameFilter),
277
std::move(RemarkArgFilter), RemarkType);
278
}
279
280
Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) {
281
// Create Parser.
282
auto MaybeParser = createRemarkParser(InputFormat, Buffer);
283
if (!MaybeParser)
284
return MaybeParser.takeError();
285
auto &Parser = **MaybeParser;
286
auto MaybeRemark = Parser.next();
287
for (; MaybeRemark; MaybeRemark = Parser.next()) {
288
const Remark &Remark = **MaybeRemark;
289
if (Filter.filterRemark(Remark))
290
Counter.collect(Remark);
291
}
292
293
if (auto E = Counter.print(OutputFileName))
294
return E;
295
auto E = MaybeRemark.takeError();
296
if (!E.isA<EndOfFileError>())
297
return E;
298
consumeError(std::move(E));
299
return Error::success();
300
}
301
302
static Error collectRemarks() {
303
// Create a parser for the user-specified input format.
304
auto MaybeBuf = getInputMemoryBuffer(InputFileName);
305
if (!MaybeBuf)
306
return MaybeBuf.takeError();
307
StringRef Buffer = (*MaybeBuf)->getBuffer();
308
auto MaybeFilter = getRemarkFilter();
309
if (!MaybeFilter)
310
return MaybeFilter.takeError();
311
auto &Filter = *MaybeFilter;
312
if (CountByOpt == CountBy::REMARK) {
313
RemarkCounter RC(GroupByOpt);
314
if (auto E = useCollectRemark(Buffer, RC, Filter))
315
return E;
316
} else if (CountByOpt == CountBy::ARGUMENT) {
317
SmallVector<FilterMatcher, 4> ArgumentsVector;
318
if (!Keys.empty()) {
319
for (auto &Key : Keys)
320
ArgumentsVector.push_back({Key, false});
321
} else if (!RKeys.empty())
322
for (auto Key : RKeys)
323
ArgumentsVector.push_back({Key, true});
324
else
325
ArgumentsVector.push_back({".*", true});
326
327
Expected<ArgumentCounter> AC = ArgumentCounter::createArgumentCounter(
328
GroupByOpt, ArgumentsVector, Buffer, Filter);
329
if (!AC)
330
return AC.takeError();
331
if (auto E = useCollectRemark(Buffer, *AC, Filter))
332
return E;
333
}
334
return Error::success();
335
}
336
337
static CommandRegistration CountReg(&CountSub, collectRemarks);
338
339