brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 4e429b7 Raw
238 lines · cpp
1//===- RemarkCounter.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Generic tool to count remarks based on properties10//11//===----------------------------------------------------------------------===//12 13#include "RemarkCounter.h"14#include "RemarkUtilRegistry.h"15#include "llvm/Support/CommandLine.h"16#include "llvm/Support/InterleavedRange.h"17#include "llvm/Support/Regex.h"18 19using namespace llvm;20using namespace remarks;21using namespace llvm::remarkutil;22 23static cl::SubCommand CountSub("count",24                               "Collect remarks based on specified criteria.");25 26INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub)27INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub)28REMARK_FILTER_COMMAND_LINE_OPTIONS(CountSub)29 30REMARK_FILTER_SETUP_FUNC()31 32static cl::list<std::string>33    Keys("args", cl::desc("Specify remark argument/s to count by."),34         cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);35static cl::list<std::string> RKeys(36    "rargs",37    cl::desc(38        "Specify remark argument/s to count (accepts regular expressions)."),39    cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional);40 41static cl::opt<CountBy> CountByOpt(42    "count-by", cl::desc("Specify the property to collect remarks by."),43    cl::values(44        clEnumValN(CountBy::REMARK, "remark-name",45                   "Counts individual remarks based on how many of the remark "46                   "exists."),47        clEnumValN(CountBy::ARGUMENT, "arg",48                   "Counts based on the value each specified argument has. The "49                   "argument has to have a number value to be considered.")),50    cl::init(CountBy::REMARK), cl::sub(CountSub));51static cl::opt<GroupBy> GroupByOpt(52    "group-by", cl::desc("Specify the property to group remarks by."),53    cl::values(54        clEnumValN(55            GroupBy::PER_SOURCE, "source",56            "Display the count broken down by the filepath of each remark "57            "emitted. Requires remarks to have DebugLoc information."),58        clEnumValN(GroupBy::PER_FUNCTION, "function",59                   "Breakdown the count by function name."),60        clEnumValN(61            GroupBy::PER_FUNCTION_WITH_DEBUG_LOC, "function-with-loc",62            "Breakdown the count by function name taking into consideration "63            "the filepath info from the DebugLoc of the remark."),64        clEnumValN(GroupBy::TOTAL, "total",65                   "Output the total number corresponding to the count for the "66                   "provided input file.")),67    cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub));68 69/// Look for matching argument with \p Key in \p Remark and return the parsed70/// integer value or 0 if it is has no integer value.71static unsigned getValForKey(StringRef Key, const Remark &Remark) {72  auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) {73    return Arg.Key == Key && Arg.getValAsInt<unsigned>();74  });75  if (RemarkArg == Remark.Args.end())76    return 0;77  return *RemarkArg->getValAsInt<unsigned>();78}79 80Error ArgumentCounter::getAllMatchingArgumentsInRemark(81    StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) {82  auto MaybeParser = createRemarkParser(InputFormat, Buffer);83  if (!MaybeParser)84    return MaybeParser.takeError();85  auto &Parser = **MaybeParser;86  auto MaybeRemark = Parser.next();87  for (; MaybeRemark; MaybeRemark = Parser.next()) {88    auto &Remark = **MaybeRemark;89    // Only collect keys from remarks included in the filter.90    if (!Filter.filterRemark(Remark))91      continue;92    for (auto &Key : Arguments) {93      for (Argument Arg : Remark.Args)94        if (Key.match(Arg.Key) && Arg.getValAsInt<unsigned>())95          ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()});96    }97  }98 99  auto E = MaybeRemark.takeError();100  if (!E.isA<EndOfFileError>())101    return E;102  consumeError(std::move(E));103  return Error::success();104}105 106std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) {107  switch (Group) {108  case GroupBy::PER_FUNCTION:109    return Remark.FunctionName.str();110  case GroupBy::TOTAL:111    return "Total";112  case GroupBy::PER_SOURCE:113  case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC:114    if (!Remark.Loc.has_value())115      return std::nullopt;116 117    if (Group == GroupBy::PER_FUNCTION_WITH_DEBUG_LOC)118      return Remark.Loc->SourceFilePath.str() + ":" + Remark.FunctionName.str();119    return Remark.Loc->SourceFilePath.str();120  }121  llvm_unreachable("Fully covered switch above!");122}123 124void ArgumentCounter::collect(const Remark &Remark) {125  SmallVector<unsigned, 4> Row(ArgumentSetIdxMap.size());126  std::optional<std::string> GroupByKey = getGroupByKey(Remark);127  // Early return if we don't have a value128  if (!GroupByKey)129    return;130  auto GroupVal = *GroupByKey;131  CountByKeysMap.insert({GroupVal, Row});132  for (auto [Key, Idx] : ArgumentSetIdxMap) {133    auto Count = getValForKey(Key, Remark);134    CountByKeysMap[GroupVal][Idx] += Count;135  }136}137 138void RemarkCounter::collect(const Remark &Remark) {139  if (std::optional<std::string> Key = getGroupByKey(Remark))140    ++CountedByRemarksMap[*Key];141}142 143Error ArgumentCounter::print(StringRef OutputFileName) {144  auto MaybeOF =145      getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);146  if (!MaybeOF)147    return MaybeOF.takeError();148 149  auto OF = std::move(*MaybeOF);150  OF->os() << groupByToStr(Group) << ",";151  OF->os() << llvm::interleaved(llvm::make_first_range(ArgumentSetIdxMap), ",");152  OF->os() << "\n";153  for (auto [Header, CountVector] : CountByKeysMap) {154    OF->os() << Header << ",";155    OF->os() << llvm::interleaved(CountVector, ",");156    OF->os() << "\n";157  }158  return Error::success();159}160 161Error RemarkCounter::print(StringRef OutputFileName) {162  auto MaybeOF =163      getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF);164  if (!MaybeOF)165    return MaybeOF.takeError();166 167  auto OF = std::move(*MaybeOF);168  OF->os() << groupByToStr(Group) << ","169           << "Count\n";170  for (auto [Key, Count] : CountedByRemarksMap)171    OF->os() << Key << "," << Count << "\n";172  OF->keep();173  return Error::success();174}175 176Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) {177  // Create Parser.178  auto MaybeParser = createRemarkParser(InputFormat, Buffer);179  if (!MaybeParser)180    return MaybeParser.takeError();181  auto &Parser = **MaybeParser;182  auto MaybeRemark = Parser.next();183  for (; MaybeRemark; MaybeRemark = Parser.next()) {184    const Remark &Remark = **MaybeRemark;185    if (Filter.filterRemark(Remark))186      Counter.collect(Remark);187  }188 189  if (auto E = Counter.print(OutputFileName))190    return E;191  auto E = MaybeRemark.takeError();192  if (!E.isA<EndOfFileError>())193    return E;194  consumeError(std::move(E));195  return Error::success();196}197 198static Error collectRemarks() {199  // Create a parser for the user-specified input format.200  auto MaybeBuf = getInputMemoryBuffer(InputFileName);201  if (!MaybeBuf)202    return MaybeBuf.takeError();203  StringRef Buffer = (*MaybeBuf)->getBuffer();204  auto MaybeFilter = getRemarkFilters();205  if (!MaybeFilter)206    return MaybeFilter.takeError();207  auto &Filter = *MaybeFilter;208  if (CountByOpt == CountBy::REMARK) {209    RemarkCounter RC(GroupByOpt);210    if (auto E = useCollectRemark(Buffer, RC, Filter))211      return E;212  } else if (CountByOpt == CountBy::ARGUMENT) {213    SmallVector<FilterMatcher, 4> ArgumentsVector;214    if (!Keys.empty()) {215      for (auto &Key : Keys)216        ArgumentsVector.push_back(FilterMatcher::createExact(Key));217    } else if (!RKeys.empty())218      for (auto Key : RKeys) {219        auto FM = FilterMatcher::createRE(Key, RKeys);220        if (!FM)221          return FM.takeError();222        ArgumentsVector.push_back(std::move(*FM));223      }224    else225      ArgumentsVector.push_back(FilterMatcher::createAny());226 227    Expected<ArgumentCounter> AC = ArgumentCounter::createArgumentCounter(228        GroupByOpt, ArgumentsVector, Buffer, Filter);229    if (!AC)230      return AC.takeError();231    if (auto E = useCollectRemark(Buffer, *AC, Filter))232      return E;233  }234  return Error::success();235}236 237static CommandRegistration CountReg(&CountSub, collectRemarks);238