1 //===- RemarkCounter.h ----------------------------------------------------===//
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 #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"
17
18 namespace llvm {
19 namespace remarks {
20
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 };
24
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.
27 enum class GroupBy {
28 TOTAL,
29 PER_SOURCE,
30 PER_FUNCTION,
31 PER_FUNCTION_WITH_DEBUG_LOC
32 };
33
34 /// Convert \p GroupBy to a std::string.
groupByToStr(GroupBy GroupBy)35 inline std::string groupByToStr(GroupBy GroupBy) {
36 switch (GroupBy) {
37 default:
38 return "Total";
39 case GroupBy::PER_FUNCTION:
40 return "Function";
41 case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:
42 return "FuctionWithDebugLoc";
43 case GroupBy::PER_SOURCE:
44 return "Source";
45 }
46 }
47
48 /// Filter out remarks based on remark properties based on name, pass name,
49 /// argument and type.
50 struct Filters {
51 std::optional<FilterMatcher> RemarkNameFilter;
52 std::optional<FilterMatcher> PassNameFilter;
53 std::optional<FilterMatcher> ArgFilter;
54 std::optional<Type> RemarkTypeFilter;
55
56 /// Returns true if \p Remark satisfies all the provided filters.
57 bool filterRemark(const Remark &Remark);
58 };
59
60 /// Abstract counter class used to define the general required methods for
61 /// counting a remark.
62 struct Counter {
63 GroupBy Group = GroupBy::TOTAL;
64 Counter() = default;
CounterCounter65 Counter(enum GroupBy GroupBy) : Group(GroupBy) {}
66 /// Obtain the field for collecting remark info based on how we are
67 /// collecting. Remarks are grouped by FunctionName, Source, Source and
68 /// Function or collect by file.
69 std::optional<std::string> getGroupByKey(const Remark &Remark);
70
71 /// Collect count information from \p Remark organized based on \p Group
72 /// property.
73 virtual void collect(const Remark &) = 0;
74 /// Output the final count to the file \p OutputFileName
75 virtual Error print(StringRef OutputFileName) = 0;
76 virtual ~Counter() = default;
77 };
78
79 /// Count remarks based on the provided \p Keys argument and summing up the
80 /// value for each matching key organized by source, function or reporting a
81 /// total for the specified remark file.
82 /// Reporting count grouped by source:
83 ///
84 /// | source | key1 | key2 | key3 |
85 /// |---------------|------|------|------|
86 /// | path/to/file1 | 0 | 1 | 3 |
87 /// | path/to/file2 | 1 | 0 | 2 |
88 /// | path/to/file3 | 2 | 3 | 1 |
89 ///
90 /// Reporting count grouped by function:
91 ///
92 /// | Function | key1 | key2 | key3 |
93 /// |---------------|------|------|------|
94 /// | function1 | 0 | 1 | 3 |
95 /// | function2 | 1 | 0 | 2 |
96 /// | function3 | 2 | 3 | 1 |
97 struct ArgumentCounter : Counter {
98 /// The internal object to keep the count for the remarks. The first argument
99 /// corresponds to the property we are collecting for this can be either a
100 /// source or function. The second argument is a row of integers where each
101 /// item in the row is the count for a specified key.
102 std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap;
103 /// A set of all the remark argument found in the remark file. The second
104 /// argument is the index of each of those arguments which can be used in
105 /// `CountByKeysMap` to fill count information for that argument.
106 MapVector<StringRef, unsigned> ArgumentSetIdxMap;
107 /// Create an argument counter. If the provided \p Arguments represent a regex
108 /// vector then we need to check that the provided regular expressions are
109 /// valid if not we return an Error.
110 static Expected<ArgumentCounter>
createArgumentCounterArgumentCounter111 createArgumentCounter(GroupBy Group, ArrayRef<FilterMatcher> Arguments,
112 StringRef Buffer, Filters &Filter) {
113 ArgumentCounter AC;
114 AC.Group = Group;
115 if (auto E = AC.getAllMatchingArgumentsInRemark(Buffer, Arguments, Filter))
116 return std::move(E);
117 return AC;
118 }
119
120 /// Update the internal count map based on the remark integer arguments that
121 /// correspond the the user specified argument keys to collect for.
122 void collect(const Remark &) override;
123
124 /// Print a CSV table consisting of an index which is specified by \p
125 /// `Group` and can be a function name, source file name or function name
126 /// with the full source path and columns of user specified remark arguments
127 /// to collect the count for.
128 Error print(StringRef OutputFileName) override;
129
130 private:
131 /// collect all the arguments that match the list of \p Arguments provided by
132 /// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap
133 /// acting as a row for for all the keys that we are interested in collecting
134 /// information for.
135 Error getAllMatchingArgumentsInRemark(StringRef Buffer,
136 ArrayRef<FilterMatcher> Arguments,
137 Filters &Filter);
138 };
139
140 /// Collect remarks based by counting the existance of individual remarks. The
141 /// reported table will be structured based on the provided \p Group argument
142 /// by reporting count for functions, source or total count for the provided
143 /// remark file.
144 struct RemarkCounter : Counter {
145 std::map<std::string, unsigned> CountedByRemarksMap;
RemarkCounterRemarkCounter146 RemarkCounter(GroupBy Group) : Counter(Group) {}
147
148 /// Advance the internal map count broken by \p Group when
149 /// seeing \p Remark.
150 void collect(const Remark &) override;
151
152 /// Print a CSV table consisting of an index which is specified by \p
153 /// `Group` and can be a function name, source file name or function name
154 /// with the full source path and a counts column corresponding to the count
155 /// of each individual remark at th index.
156 Error print(StringRef OutputFileName) override;
157 };
158 } // namespace remarks
159
160 } // namespace llvm
161 #endif // TOOLS_LLVM_REMARKCOUNTER_H
162