1 //===- RemarkCounter.h ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Generic tool to count remarks based on properties
11 //===----------------------------------------------------------------------===//
12 #ifndef TOOLS_LLVM_REMARKCOUNTER_H
13 #define TOOLS_LLVM_REMARKCOUNTER_H
14 #include "RemarkUtilHelpers.h"
15 #include "llvm/ADT/MapVector.h"
16 #include "llvm/Support/Regex.h"
21 /// Collect remarks by counting the existance of a remark or by looking through
22 /// the keys and summing through the total count.
23 enum class CountBy
{ REMARK
, ARGUMENT
};
25 /// Summarize the count by either emitting one count for the remark file, or
26 /// grouping the count by source file or by function name.
31 PER_FUNCTION_WITH_DEBUG_LOC
34 /// Convert \p GroupBy to a std::string.
35 inline std::string
groupByToStr(GroupBy GroupBy
) {
39 case GroupBy::PER_FUNCTION
:
41 case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC
:
42 return "FuctionWithDebugLoc";
43 case GroupBy::PER_SOURCE
:
48 /// Filter object which can be either a string or a regex to match with the
49 /// remark properties.
50 struct FilterMatcher
{
52 std::string FilterStr
;
54 FilterMatcher(std::string Filter
, bool IsRegex
) : IsRegex(IsRegex
) {
56 FilterRE
= Regex(Filter
);
61 bool match(StringRef StringToMatch
) const {
63 return FilterRE
.match(StringToMatch
);
64 return FilterStr
== StringToMatch
.trim().str();
68 /// Filter out remarks based on remark properties based on name, pass name,
69 /// argument and type.
71 std::optional
<FilterMatcher
> RemarkNameFilter
;
72 std::optional
<FilterMatcher
> PassNameFilter
;
73 std::optional
<FilterMatcher
> ArgFilter
;
74 std::optional
<Type
> RemarkTypeFilter
;
75 /// Returns a filter object if all the arguments provided are valid regex
76 /// types otherwise return an error.
77 static Expected
<Filters
>
78 createRemarkFilter(std::optional
<FilterMatcher
> RemarkNameFilter
,
79 std::optional
<FilterMatcher
> PassNameFilter
,
80 std::optional
<FilterMatcher
> ArgFilter
,
81 std::optional
<Type
> RemarkTypeFilter
) {
83 Filter
.RemarkNameFilter
= std::move(RemarkNameFilter
);
84 Filter
.PassNameFilter
= std::move(PassNameFilter
);
85 Filter
.ArgFilter
= std::move(ArgFilter
);
86 Filter
.RemarkTypeFilter
= std::move(RemarkTypeFilter
);
87 if (auto E
= Filter
.regexArgumentsValid())
89 return std::move(Filter
);
91 /// Returns true if \p Remark satisfies all the provided filters.
92 bool filterRemark(const Remark
&Remark
);
95 /// Check if arguments can be parsed as valid regex types.
96 Error
regexArgumentsValid();
99 /// Convert Regex string error to an error object.
100 inline Error
checkRegex(const Regex
&Regex
) {
102 if (!Regex
.isValid(Error
))
103 return createStringError(make_error_code(std::errc::invalid_argument
),
104 Twine("Regex: ", Error
));
105 return Error::success();
108 /// Abstract counter class used to define the general required methods for
109 /// counting a remark.
111 GroupBy Group
= GroupBy::TOTAL
;
113 Counter(enum GroupBy GroupBy
) : Group(GroupBy
) {}
114 /// Obtain the field for collecting remark info based on how we are
115 /// collecting. Remarks are grouped by FunctionName, Source, Source and
116 /// Function or collect by file.
117 std::optional
<std::string
> getGroupByKey(const Remark
&Remark
);
119 /// Collect count information from \p Remark organized based on \p Group
121 virtual void collect(const Remark
&) = 0;
122 /// Output the final count to the file \p OutputFileName
123 virtual Error
print(StringRef OutputFileName
) = 0;
124 virtual ~Counter() = default;
127 /// Count remarks based on the provided \p Keys argument and summing up the
128 /// value for each matching key organized by source, function or reporting a
129 /// total for the specified remark file.
130 /// Reporting count grouped by source:
132 /// | source | key1 | key2 | key3 |
133 /// |---------------|------|------|------|
134 /// | path/to/file1 | 0 | 1 | 3 |
135 /// | path/to/file2 | 1 | 0 | 2 |
136 /// | path/to/file3 | 2 | 3 | 1 |
138 /// Reporting count grouped by function:
140 /// | Function | key1 | key2 | key3 |
141 /// |---------------|------|------|------|
142 /// | function1 | 0 | 1 | 3 |
143 /// | function2 | 1 | 0 | 2 |
144 /// | function3 | 2 | 3 | 1 |
145 struct ArgumentCounter
: Counter
{
146 /// The internal object to keep the count for the remarks. The first argument
147 /// corresponds to the property we are collecting for this can be either a
148 /// source or function. The second argument is a row of integers where each
149 /// item in the row is the count for a specified key.
150 std::map
<std::string
, SmallVector
<unsigned, 4>> CountByKeysMap
;
151 /// A set of all the remark argument found in the remark file. The second
152 /// argument is the index of each of those arguments which can be used in
153 /// `CountByKeysMap` to fill count information for that argument.
154 MapVector
<StringRef
, unsigned> ArgumentSetIdxMap
;
155 /// Create an argument counter. If the provided \p Arguments represent a regex
156 /// vector then we need to check that the provided regular expressions are
157 /// valid if not we return an Error.
158 static Expected
<ArgumentCounter
>
159 createArgumentCounter(GroupBy Group
, ArrayRef
<FilterMatcher
> Arguments
,
160 StringRef Buffer
, Filters
&Filter
) {
163 for (auto &Arg
: Arguments
) {
165 if (auto E
= checkRegex(Arg
.FilterRE
))
169 if (auto E
= AC
.getAllMatchingArgumentsInRemark(Buffer
, Arguments
, Filter
))
174 /// Update the internal count map based on the remark integer arguments that
175 /// correspond the the user specified argument keys to collect for.
176 void collect(const Remark
&) override
;
178 /// Print a CSV table consisting of an index which is specified by \p
179 /// `Group` and can be a function name, source file name or function name
180 /// with the full source path and columns of user specified remark arguments
181 /// to collect the count for.
182 Error
print(StringRef OutputFileName
) override
;
185 /// collect all the arguments that match the list of \p Arguments provided by
186 /// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap
187 /// acting as a row for for all the keys that we are interested in collecting
189 Error
getAllMatchingArgumentsInRemark(StringRef Buffer
,
190 ArrayRef
<FilterMatcher
> Arguments
,
194 /// Collect remarks based by counting the existance of individual remarks. The
195 /// reported table will be structured based on the provided \p Group argument
196 /// by reporting count for functions, source or total count for the provided
198 struct RemarkCounter
: Counter
{
199 std::map
<std::string
, unsigned> CountedByRemarksMap
;
200 RemarkCounter(GroupBy Group
) : Counter(Group
) {}
202 /// Advance the internal map count broken by \p Group when
203 /// seeing \p Remark.
204 void collect(const Remark
&) override
;
206 /// Print a CSV table consisting of an index which is specified by \p
207 /// `Group` and can be a function name, source file name or function name
208 /// with the full source path and a counts column corresponding to the count
209 /// of each individual remark at th index.
210 Error
print(StringRef OutputFileName
) override
;
212 } // namespace remarks
215 #endif // TOOLS_LLVM_REMARKCOUNTER_H