brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 124bd51 Raw
255 lines · cpp
1//===- RemarkSummary.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// Specialized tool to summarize remarks10//11//===----------------------------------------------------------------------===//12 13#include "RemarkUtilHelpers.h"14#include "RemarkUtilRegistry.h"15 16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/CommandLine.h"19#include "llvm/Support/Debug.h"20#include "llvm/Support/Error.h"21#include "llvm/Support/Regex.h"22#include "llvm/Support/WithColor.h"23#include <memory>24 25using namespace llvm;26using namespace remarks;27using namespace llvm::remarkutil;28 29namespace summary {30 31static cl::SubCommand32    SummarySub("summary", "Summarize remarks using different strategies.");33 34INPUT_FORMAT_COMMAND_LINE_OPTIONS(SummarySub)35OUTPUT_FORMAT_COMMAND_LINE_OPTIONS(SummarySub)36INPUT_OUTPUT_COMMAND_LINE_OPTIONS(SummarySub)37 38static cl::OptionCategory SummaryStrategyCat("Strategy options");39 40enum class KeepMode { None, Used, All };41 42static cl::opt<KeepMode> KeepInputOpt(43    "keep", cl::desc("Keep input remarks in output"), cl::init(KeepMode::None),44    cl::values(clEnumValN(KeepMode::None, "none",45                          "Don't keep input remarks (default)"),46               clEnumValN(KeepMode::Used, "used",47                          "Keep only remarks used for summary"),48               clEnumValN(KeepMode::All, "all", "Keep all input remarks")),49    cl::sub(SummarySub));50 51static cl::opt<bool>52    IgnoreMalformedOpt("ignore-malformed",53                       cl::desc("Ignore remarks that fail to process"),54                       cl::init(false), cl::Hidden, cl::sub(SummarySub));55 56// Use one cl::opt per Strategy, because future strategies might need to take57// per-strategy parameters.58static cl::opt<bool> EnableInlineSummaryOpt(59    "inline-callees", cl::desc("Summarize per-callee inling statistics"),60    cl::cat(SummaryStrategyCat), cl::init(false), cl::sub(SummarySub));61 62/// An interface to implement different strategies for creating remark63/// summaries. Override this class to develop new strategies.64class SummaryStrategy {65public:66  virtual ~SummaryStrategy() = default;67 68  /// Strategy should return true if it wants to process the remark \p R.69  virtual bool filter(Remark &R) = 0;70 71  /// Hook to process the remark \p R (i.e. collect the necessary data for72  /// producing summary remarks). This will only be called with remarks73  /// accepted by filter(). Can return an error if \p R is malformed or74  /// unexpected.75  virtual Error process(Remark &R) = 0;76 77  /// Hook to emit new remarks based on the collected data.78  virtual void emit(RemarkSerializer &Serializer) = 0;79};80 81/// Check if any summary strategy options are explicitly enabled.82static bool isAnyStrategyRequested() {83  StringMap<cl::Option *> Opts = cl::getRegisteredOptions(SummarySub);84  for (auto &[_, Opt] : Opts) {85    if (!is_contained(Opt->Categories, &SummaryStrategyCat))86      continue;87    if (!Opt->getNumOccurrences())88      continue;89    return true;90  }91  return false;92}93 94class InlineCalleeSummary : public SummaryStrategy {95  struct CallsiteCost {96    int Cost = 0;97    int Threshold = 0;98    std::optional<RemarkLocation> Loc;99 100    int getProfit() const { return Threshold - Cost; }101 102    friend bool operator==(const CallsiteCost &A, const CallsiteCost &B) {103      return A.Cost == B.Cost && A.Threshold == B.Threshold && A.Loc == B.Loc;104    }105 106    friend bool operator!=(const CallsiteCost &A, const CallsiteCost &B) {107      return !(A == B);108    }109  };110 111  struct CalleeSummary {112    SmallDenseMap<StringRef, size_t> Stats;113    std::optional<RemarkLocation> Loc;114    std::optional<CallsiteCost> LeastProfit;115    std::optional<CallsiteCost> MostProfit;116 117    void updateCost(CallsiteCost NewCost) {118      if (!LeastProfit || NewCost.getProfit() < LeastProfit->getProfit())119        LeastProfit = NewCost;120      if (!MostProfit || NewCost.getProfit() > MostProfit->getProfit())121        MostProfit = NewCost;122    }123  };124 125  DenseMap<StringRef, CalleeSummary> Callees;126 127  Error malformed() { return createStringError("Malformed inline remark."); }128 129  bool filter(Remark &R) override {130    return R.PassName == "inline" && R.RemarkName != "Summary";131  }132 133  Error process(Remark &R) override {134    auto *CalleeArg = R.getArgByKey("Callee");135    if (!CalleeArg)136      return Error::success();137    auto &Callee = Callees[CalleeArg->Val];138    ++Callee.Stats[R.RemarkName];139    if (!Callee.Loc)140      Callee.Loc = CalleeArg->Loc;141 142    Argument *CostArg = R.getArgByKey("Cost");143    Argument *ThresholdArg = R.getArgByKey("Threshold");144    if (!CostArg || !ThresholdArg)145      return Error::success();146    auto CostVal = CostArg->getValAsInt<int>();147    auto ThresholdVal = ThresholdArg->getValAsInt<int>();148    if (!CostVal || !ThresholdVal)149      return malformed();150    Callee.updateCost({*CostVal, *ThresholdVal, R.Loc});151    return Error::success();152  }153 154  void emit(RemarkSerializer &Serializer) override {155    SmallVector<StringRef> SortedKeys(Callees.keys());156    llvm::sort(SortedKeys);157    for (StringRef K : SortedKeys) {158      auto &V = Callees[K];159      RemarkBuilder RB(Type::Analysis, "inline", "Summary", K);160      if (V.Stats.empty())161        continue;162      RB.R.Loc = V.Loc;163      RB << "Incoming Calls (";164      SmallVector<StringRef> StatKeys(V.Stats.keys());165      llvm::sort(StatKeys);166      bool First = true;167      for (StringRef StatK : StatKeys) {168        if (!First)169          RB << ", ";170        RB << StatK << ": " << NV(StatK, V.Stats[StatK]);171        First = false;172      }173      RB << ")";174      if (V.LeastProfit && V.MostProfit != V.LeastProfit) {175        RB << "\nLeast profitable (cost="176           << NV("LeastProfitCost", V.LeastProfit->Cost, V.LeastProfit->Loc)177           << ", threshold="178           << NV("LeastProfitThreshold", V.LeastProfit->Threshold) << ")";179      }180      if (V.MostProfit) {181        RB << "\nMost profitable (cost="182           << NV("MostProfitCost", V.MostProfit->Cost, V.MostProfit->Loc)183           << ", threshold="184           << NV("MostProfitThreshold", V.MostProfit->Threshold) << ")";185      }186      Serializer.emit(RB.R);187    }188  }189};190 191static Error trySummary() {192  auto MaybeBuf = getInputMemoryBuffer(InputFileName);193  if (!MaybeBuf)194    return MaybeBuf.takeError();195  auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());196  if (!MaybeParser)197    return MaybeParser.takeError();198  auto &Parser = **MaybeParser;199 200  Format SerializerFormat =201      getSerializerFormat(OutputFileName, OutputFormat, Parser.ParserFormat);202 203  auto MaybeOF = getOutputFileForRemarks(OutputFileName, SerializerFormat);204  if (!MaybeOF)205    return MaybeOF.takeError();206  auto OF = std::move(*MaybeOF);207 208  auto MaybeSerializer = createRemarkSerializer(SerializerFormat, OF->os());209  if (!MaybeSerializer)210    return MaybeSerializer.takeError();211  auto &Serializer = **MaybeSerializer;212 213  bool UseDefaultStrategies = !isAnyStrategyRequested();214  SmallVector<std::unique_ptr<SummaryStrategy>> Strategies;215  if (EnableInlineSummaryOpt || UseDefaultStrategies)216    Strategies.push_back(std::make_unique<InlineCalleeSummary>());217 218  auto MaybeRemark = Parser.next();219  for (; MaybeRemark; MaybeRemark = Parser.next()) {220    Remark &Remark = **MaybeRemark;221    bool UsedRemark = false;222    for (auto &Strategy : Strategies) {223      if (!Strategy->filter(Remark))224        continue;225      UsedRemark = true;226      if (auto E = Strategy->process(Remark)) {227        if (IgnoreMalformedOpt) {228          WithColor::warning() << "Ignored error: " << E << "\n";229          consumeError(std::move(E));230          continue;231        }232        return E;233      }234    }235    if (KeepInputOpt == KeepMode::All ||236        (KeepInputOpt == KeepMode::Used && UsedRemark))237      Serializer.emit(Remark);238  }239 240  auto E = MaybeRemark.takeError();241  if (!E.isA<EndOfFileError>())242    return E;243  consumeError(std::move(E));244 245  for (auto &Strategy : Strategies)246    Strategy->emit(Serializer);247 248  OF->keep();249  return Error::success();250}251 252static CommandRegistration SummaryReg(&SummarySub, trySummary);253 254} // namespace summary255