mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 17:36:06 +00:00
216 lines
8.0 KiB
C++
216 lines
8.0 KiB
C++
//===- 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
|