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