Path: blob/main/contrib/llvm-project/llvm/tools/llvm-remarkutil/RemarkCounter.h
35230 views
//===- RemarkCounter.h ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Generic tool to count remarks based on properties9//10//===----------------------------------------------------------------------===//11#ifndef TOOLS_LLVM_REMARKCOUNTER_H12#define TOOLS_LLVM_REMARKCOUNTER_H13#include "RemarkUtilHelpers.h"14#include "llvm/ADT/MapVector.h"15#include "llvm/Support/Regex.h"1617namespace llvm {18namespace remarks {1920/// Collect remarks by counting the existance of a remark or by looking through21/// the keys and summing through the total count.22enum class CountBy { REMARK, ARGUMENT };2324/// Summarize the count by either emitting one count for the remark file, or25/// grouping the count by source file or by function name.26enum class GroupBy {27TOTAL,28PER_SOURCE,29PER_FUNCTION,30PER_FUNCTION_WITH_DEBUG_LOC31};3233/// Convert \p GroupBy to a std::string.34inline std::string groupByToStr(GroupBy GroupBy) {35switch (GroupBy) {36default:37return "Total";38case GroupBy::PER_FUNCTION:39return "Function";40case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:41return "FuctionWithDebugLoc";42case GroupBy::PER_SOURCE:43return "Source";44}45}4647/// Filter object which can be either a string or a regex to match with the48/// remark properties.49struct FilterMatcher {50Regex FilterRE;51std::string FilterStr;52bool IsRegex;53FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) {54if (IsRegex)55FilterRE = Regex(Filter);56else57FilterStr = Filter;58}5960bool match(StringRef StringToMatch) const {61if (IsRegex)62return FilterRE.match(StringToMatch);63return FilterStr == StringToMatch.trim().str();64}65};6667/// Filter out remarks based on remark properties based on name, pass name,68/// argument and type.69struct Filters {70std::optional<FilterMatcher> RemarkNameFilter;71std::optional<FilterMatcher> PassNameFilter;72std::optional<FilterMatcher> ArgFilter;73std::optional<Type> RemarkTypeFilter;74/// Returns a filter object if all the arguments provided are valid regex75/// types otherwise return an error.76static Expected<Filters>77createRemarkFilter(std::optional<FilterMatcher> RemarkNameFilter,78std::optional<FilterMatcher> PassNameFilter,79std::optional<FilterMatcher> ArgFilter,80std::optional<Type> RemarkTypeFilter) {81Filters Filter;82Filter.RemarkNameFilter = std::move(RemarkNameFilter);83Filter.PassNameFilter = std::move(PassNameFilter);84Filter.ArgFilter = std::move(ArgFilter);85Filter.RemarkTypeFilter = std::move(RemarkTypeFilter);86if (auto E = Filter.regexArgumentsValid())87return std::move(E);88return std::move(Filter);89}90/// Returns true if \p Remark satisfies all the provided filters.91bool filterRemark(const Remark &Remark);9293private:94/// Check if arguments can be parsed as valid regex types.95Error regexArgumentsValid();96};9798/// Convert Regex string error to an error object.99inline Error checkRegex(const Regex &Regex) {100std::string Error;101if (!Regex.isValid(Error))102return createStringError(make_error_code(std::errc::invalid_argument),103Twine("Regex: ", Error));104return Error::success();105}106107/// Abstract counter class used to define the general required methods for108/// counting a remark.109struct Counter {110GroupBy Group = GroupBy::TOTAL;111Counter() = default;112Counter(enum GroupBy GroupBy) : Group(GroupBy) {}113/// Obtain the field for collecting remark info based on how we are114/// collecting. Remarks are grouped by FunctionName, Source, Source and115/// Function or collect by file.116std::optional<std::string> getGroupByKey(const Remark &Remark);117118/// Collect count information from \p Remark organized based on \p Group119/// property.120virtual void collect(const Remark &) = 0;121/// Output the final count to the file \p OutputFileName122virtual Error print(StringRef OutputFileName) = 0;123virtual ~Counter() = default;124};125126/// Count remarks based on the provided \p Keys argument and summing up the127/// value for each matching key organized by source, function or reporting a128/// total for the specified remark file.129/// Reporting count grouped by source:130///131/// | source | key1 | key2 | key3 |132/// |---------------|------|------|------|133/// | path/to/file1 | 0 | 1 | 3 |134/// | path/to/file2 | 1 | 0 | 2 |135/// | path/to/file3 | 2 | 3 | 1 |136///137/// Reporting count grouped by function:138///139/// | Function | key1 | key2 | key3 |140/// |---------------|------|------|------|141/// | function1 | 0 | 1 | 3 |142/// | function2 | 1 | 0 | 2 |143/// | function3 | 2 | 3 | 1 |144struct ArgumentCounter : Counter {145/// The internal object to keep the count for the remarks. The first argument146/// corresponds to the property we are collecting for this can be either a147/// source or function. The second argument is a row of integers where each148/// item in the row is the count for a specified key.149std::map<std::string, SmallVector<unsigned, 4>> CountByKeysMap;150/// A set of all the remark argument found in the remark file. The second151/// argument is the index of each of those arguments which can be used in152/// `CountByKeysMap` to fill count information for that argument.153MapVector<StringRef, unsigned> ArgumentSetIdxMap;154/// Create an argument counter. If the provided \p Arguments represent a regex155/// vector then we need to check that the provided regular expressions are156/// valid if not we return an Error.157static Expected<ArgumentCounter>158createArgumentCounter(GroupBy Group, ArrayRef<FilterMatcher> Arguments,159StringRef Buffer, Filters &Filter) {160ArgumentCounter AC;161AC.Group = Group;162for (auto &Arg : Arguments) {163if (Arg.IsRegex) {164if (auto E = checkRegex(Arg.FilterRE))165return std::move(E);166}167}168if (auto E = AC.getAllMatchingArgumentsInRemark(Buffer, Arguments, Filter))169return std::move(E);170return AC;171}172173/// Update the internal count map based on the remark integer arguments that174/// correspond the the user specified argument keys to collect for.175void collect(const Remark &) override;176177/// Print a CSV table consisting of an index which is specified by \p178/// `Group` and can be a function name, source file name or function name179/// with the full source path and columns of user specified remark arguments180/// to collect the count for.181Error print(StringRef OutputFileName) override;182183private:184/// collect all the arguments that match the list of \p Arguments provided by185/// parsing through \p Buffer of remarks and filling \p ArgumentSetIdxMap186/// acting as a row for for all the keys that we are interested in collecting187/// information for.188Error getAllMatchingArgumentsInRemark(StringRef Buffer,189ArrayRef<FilterMatcher> Arguments,190Filters &Filter);191};192193/// Collect remarks based by counting the existance of individual remarks. The194/// reported table will be structured based on the provided \p Group argument195/// by reporting count for functions, source or total count for the provided196/// remark file.197struct RemarkCounter : Counter {198std::map<std::string, unsigned> CountedByRemarksMap;199RemarkCounter(GroupBy Group) : Counter(Group) {}200201/// Advance the internal map count broken by \p Group when202/// seeing \p Remark.203void collect(const Remark &) override;204205/// Print a CSV table consisting of an index which is specified by \p206/// `Group` and can be a function name, source file name or function name207/// with the full source path and a counts column corresponding to the count208/// of each individual remark at th index.209Error print(StringRef OutputFileName) override;210};211} // namespace remarks212213} // namespace llvm214#endif // TOOLS_LLVM_REMARKCOUNTER_H215216217