| //===- RemarkCounter.h ----------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Generic tool to count remarks based on properties |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef TOOLS_LLVM_REMARKCOUNTER_H |
| #define TOOLS_LLVM_REMARKCOUNTER_H |
| #include "RemarkUtilHelpers.h" |
| #include "llvm/ADT/MapVector.h" |
| #include "llvm/Support/Regex.h" |
| |
| namespace llvm { |
| namespace remarks { |
| |
| /// Collect remarks by counting the existance of a remark or by looking through |
| /// the keys and summing through the total count. |
| enum class CountBy { REMARK, ARGUMENT }; |
| |
| /// Summarize the count by either emitting one count for the remark file, or |
| /// grouping the count by source file or by function name. |
| enum class GroupBy { |
| TOTAL, |
| PER_SOURCE, |
| PER_FUNCTION, |
| PER_FUNCTION_WITH_DEBUG_LOC |
| }; |
| |
| /// Convert \p GroupBy to a std::string. |
| inline std::string groupByToStr(GroupBy GroupBy) { |
| switch (GroupBy) { |
| default: |
| return "Total"; |
| case GroupBy::PER_FUNCTION: |
| return "Function"; |
| case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC: |
| return "FuctionWithDebugLoc"; |
| case GroupBy::PER_SOURCE: |
| return "Source"; |
| } |
| } |
| |
| /// Filter object which can be either a string or a regex to match with the |
| /// remark properties. |
| struct FilterMatcher { |
| Regex FilterRE; |
| std::string FilterStr; |
| bool IsRegex; |
| FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) { |
| if (IsRegex) |
| FilterRE = Regex(Filter); |
| else |
| FilterStr = Filter; |
| } |
| |
| bool match(StringRef StringToMatch) const { |
| if (IsRegex) |
| return FilterRE.match(StringToMatch); |
| return FilterStr == StringToMatch.trim().str(); |
| } |
| }; |
| |
| /// Filter out remarks based on remark properties based on name, pass name, |
| /// argument and type. |
| struct Filters { |
| std::optional<FilterMatcher> RemarkNameFilter; |
| std::optional<FilterMatcher> PassNameFilter; |
| std::optional<FilterMatcher> ArgFilter; |
| std::optional<Type> RemarkTypeFilter; |
| /// Returns a filter object if all the arguments provided are valid regex |
| /// types otherwise return an error. |
| static Expected<Filters> |
| createRemarkFilter(std::optional<FilterMatcher> RemarkNameFilter, |
| std::optional<FilterMatcher> PassNameFilter, |
| std::optional<FilterMatcher> ArgFilter, |
| std::optional<Type> RemarkTypeFilter) { |
| Filters Filter; |
| Filter.RemarkNameFilter = std::move(RemarkNameFilter); |
| Filter.PassNameFilter = std::move(PassNameFilter); |
| Filter.ArgFilter = std::move(ArgFilter); |
| Filter.RemarkTypeFilter = std::move(RemarkTypeFilter); |
| if (auto E = Filter.regexArgumentsValid()) |
| return std::move(E); |
| return std::move(Filter); |
| } |
| /// Returns true if \p Remark satisfies all the provided filters. |
| bool filterRemark(const Remark &Remark); |
| |
| private: |
| /// Check if arguments can be parsed as valid regex types. |
| Error regexArgumentsValid(); |
| }; |
| |
| /// Convert Regex string error to an error object. |
| inline Error checkRegex(const Regex &Regex) { |
| std::string Error; |
| if (!Regex.isValid(Error)) |
| return createStringError(make_error_code(std::errc::invalid_argument), |
| Twine("Regex: ", Error)); |
| return Error::success(); |
| } |
| |
| /// Abstract counter class used to define the general required methods for |
| /// counting a remark. |
| struct Counter { |
| GroupBy Group = GroupBy::TOTAL; |
| Counter() = default; |
| Counter(enum GroupBy GroupBy) : Group(GroupBy) {} |
| /// Obtain the field for collecting remark info based on how we are |
| /// collecting. Remarks are grouped by FunctionName, Source, Source and |
| /// Function or collect by file. |
| std::optional<std::string> getGroupByKey(const Remark &Remark); |
| |
| /// Collect count information from \p Remark organized based on \p Group |
| /// property. |
| virtual void collect(const Remark &) = 0; |
| /// Output the final count to the file \p OutputFileName |
| virtual Error print(StringRef OutputFileName) = 0; |
| virtual ~Counter() = default; |
| }; |
| |
| /// Count remarks based on the provided \p Keys argument and summing up the |
| /// value for each matching key organized by source, function or reporting a |
| /// total for the specified remark file. |
| /// Reporting count grouped by source: |
| /// |
| /// | source | key1 | key2 | key3 | |
| /// |---------------|------|------|------| |
| /// | path/to/file1 | 0 | 1 | 3 | |
| /// | path/to/file2 | 1 | 0 | 2 | |
| /// | path/to/file3 | 2 | 3 | 1 | |
| /// |
| /// Reporting count grouped by function: |
| /// |
| /// | Function | key1 | key2 | key3 | |
| /// |---------------|------|------|------| |
| /// | function1 | 0 | 1 | 3 | |
| /// | function2 | 1 | 0 | 2 | |
| /// | function3 | 2 | 3 | 1 | |
| struct ArgumentCounter : Counter { |
| /// The internal object to keep the count for the remarks. The first argument |
| /// corresponds to the property we are collecting for this can be either a |
| /// source or function. The second argument is a row of integers where each |
| /// item in the row is the count for a specified key. |
| std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap; |
| /// A set of all the remark argument found in the remark file. The second |
| /// argument is the index of each of those arguments which can be used in |
| /// `CountByKeysMap` to fill count information for that argument. |
| MapVector<StringRef, unsigned> ArgumentSetIdxMap; |
| /// Create an argument counter. If the provided \p Arguments represent a regex |
| /// vector then we need to check that the provided regular expressions are |
| /// valid if not we return an Error. |
| static Expected<ArgumentCounter> |
| createArgumentCounter(GroupBy Group, ArrayRef<FilterMatcher> Arguments, |
| StringRef Buffer, Filters &Filter) { |
| ArgumentCounter AC; |
| AC.Group = Group; |
| for (auto &Arg : Arguments) { |
| if (Arg.IsRegex) { |
| if (auto E = checkRegex(Arg.FilterRE)) |
| return std::move(E); |
| } |
| } |
| if (auto E = AC.getAllMatchingArgumentsInRemark(Buffer, Arguments, Filter)) |
| return std::move(E); |
| return AC; |
| } |
| |
| /// Update the internal count map based on the remark integer arguments that |
| /// correspond the the user specified argument keys to collect for. |
| void collect(const Remark &) override; |
| |
| /// Print a CSV table consisting of an index which is specified by \p |
| /// `Group` and can be a function name, source file name or function name |
| /// with the full source path and columns of user specified remark arguments |
| /// to collect the count for. |
| Error print(StringRef OutputFileName) override; |
| |
| private: |
| /// collect all the arguments that match the list of \p Arguments provided by |
| /// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap |
| /// acting as a row for for all the keys that we are interested in collecting |
| /// information for. |
| Error getAllMatchingArgumentsInRemark(StringRef Buffer, |
| ArrayRef<FilterMatcher> Arguments, |
| Filters &Filter); |
| }; |
| |
| /// Collect remarks based by counting the existance of individual remarks. The |
| /// reported table will be structured based on the provided \p Group argument |
| /// by reporting count for functions, source or total count for the provided |
| /// remark file. |
| struct RemarkCounter : Counter { |
| std::map<std::string, unsigned> CountedByRemarksMap; |
| RemarkCounter(GroupBy Group) : Counter(Group) {} |
| |
| /// Advance the internal map count broken by \p Group when |
| /// seeing \p Remark. |
| void collect(const Remark &) override; |
| |
| /// Print a CSV table consisting of an index which is specified by \p |
| /// `Group` and can be a function name, source file name or function name |
| /// with the full source path and a counts column corresponding to the count |
| /// of each individual remark at th index. |
| Error print(StringRef OutputFileName) override; |
| }; |
| } // namespace remarks |
| |
| } // namespace llvm |
| #endif // TOOLS_LLVM_REMARKCOUNTER_H |