[llvm] Remark Util introduce remark count (PR #66214)
Zain Jaffal via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 26 06:35:24 PDT 2023
================
@@ -0,0 +1,198 @@
+//===- 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/ADT/SmallSet.h"
+#include "llvm/Support/Regex.h"
+#include <list>
+
+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 {
+ std::variant<Regex, std::string> FilterRE, FilterStr;
+ bool IsRegex;
+ FilterMatcher(std::string Filter, bool IsRegex) : IsRegex(IsRegex) {
+ if (IsRegex)
+ FilterRE = Regex(Filter);
+ else
+ FilterStr = Filter;
+ }
+
+ bool match(StringRef StringToMatch) {
+ if (IsRegex)
+ return std::get<Regex>(FilterRE).match(StringToMatch);
+ std::string FString = std::get<std::string>(FilterStr);
+ return FString == 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 E;
+ return 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 GroupBy;
+ Counter(){};
+ Counter(enum GroupBy GroupBy) : GroupBy(GroupBy) {}
+ std::optional<std::string> getGroupByKey(const Remark &Remark);
+
+ /// Collect count information from \p Remark organized based on \p GroupBy
+ /// 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 KeyCounter : 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<int, 4>> CountByKeysMap;
+ /// A set of all the keys found in the remark file. The second argument is the
+ /// index of each of those keys which can be used in `CountByKeysMap` to fill
+ /// count information for that key.
+ MapVector<StringRef, int> KeySetIdxMap;
+ KeyCounter(){};
+ /// Create a key counte. If the provided \p Keys represent a regex vector then
+ /// we need to check that the provided regular expressions are valid if not we
+ /// return an Error.
+ static Expected<KeyCounter>
+ createKeyCounter(enum GroupBy GroupBy, SmallVector<FilterMatcher, 4> &Keys,
+ StringRef Buffer, Filters &Filter) {
+ KeyCounter KC;
+ KC.GroupBy = GroupBy;
+ for (auto &Key : Keys) {
+ if (Key.IsRegex) {
+ if (auto E = checkRegex(std::get<Regex>(Key.FilterRE)))
+ return E;
+ }
+ }
+ if (auto E = KC.getAllKeysInRemarks(Buffer, Keys, Filter))
+ return E;
+ return KC;
+ }
+ void collect(const Remark &) override;
+ Error print(StringRef OutputFileName) override;
+
+private:
+ /// collect all the keys that match the list of \p Keys provided by parsing
+ /// through \p Buffer of remarks and filling \p KeySetIdxMap acting as a row
+ /// for for all the keys that we are interested in collecting information for.
+ Error getAllKeysInRemarks(StringRef Buffer,
+ SmallVector<FilterMatcher, 4> &Keys,
+ Filters &Filter);
+};
+
+/// Collect remarks based by counting the existance of individual remarks. The
+/// reported table will be structured based on the provided \p GroupBy argument
+/// by reporting count for functions, source or total count for the provided
+/// remark file.
+struct RemarkCounter : Counter {
+ std::map<std::string, int> CountedByRemarksMap;
----------------
zjaffal wrote:
it makes sense for the tool to report the remark count by the order it parsed the files in
https://github.com/llvm/llvm-project/pull/66214
More information about the llvm-commits
mailing list