Jon Roelofs 42c8742e0e
[llvm-remarkutil] Make invalid states un-representable in the count tool (#140829)
This consolidates some of the error handling around regex arguments to
the tool, and sets up the APIs such that errors must be handled before
their usage.
2025-05-28 16:27:56 -07:00

162 lines
6.3 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 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 true if \p Remark satisfies all the provided filters.
bool filterRemark(const Remark &Remark);
};
/// 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;
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