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
18namespace llvm {
19namespace 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.
23enum 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.
27enum 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.
35inline 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.
50struct 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.
62struct Counter {
63 GroupBy Group = GroupBy::TOTAL;
64 Counter() = default;
65 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 |
97struct 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>
111 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
130private:
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.
144struct RemarkCounter : Counter {
145 std::map<std::string, unsigned> CountedByRemarksMap;
146 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