brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · 2ad6c5a Raw
250 lines · cpp
1//===-- Target.cpp ----------------------------------------------*- C++ -*-===//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#include "Target.h"9 10#include "LatencyBenchmarkRunner.h"11#include "ParallelSnippetGenerator.h"12#include "PerfHelper.h"13#include "SerialSnippetGenerator.h"14#include "UopsBenchmarkRunner.h"15#include "llvm/ADT/Twine.h"16#include "llvm/Support/Error.h"17#include "llvm/TargetParser/SubtargetFeature.h"18 19namespace llvm {20namespace exegesis {21 22cl::OptionCategory Options("llvm-exegesis options");23cl::OptionCategory BenchmarkOptions("llvm-exegesis benchmark options");24cl::OptionCategory AnalysisOptions("llvm-exegesis analysis options");25 26ExegesisTarget::~ExegesisTarget() = default; // anchor.27 28static ExegesisTarget *FirstTarget = nullptr;29 30const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {31  for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) {32    if (T->matchesArch(TT.getArch()))33      return T;34  }35  return nullptr;36}37 38const char *39ExegesisTarget::getIgnoredOpcodeReasonOrNull(const LLVMState &State,40                                             unsigned Opcode) const {41  const MCInstrDesc &InstrDesc = State.getIC().getInstr(Opcode).Description;42  if (InstrDesc.isPseudo() || InstrDesc.usesCustomInsertionHook())43    return "Unsupported opcode: isPseudo/usesCustomInserter";44  if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())45    return "Unsupported opcode: isBranch/isIndirectBranch";46  if (InstrDesc.isCall() || InstrDesc.isReturn())47    return "Unsupported opcode: isCall/isReturn";48  if (InstrDesc.getSchedClass() == 0)49    return "Unsupported opcode: No Sched Class";50  return nullptr;51}52 53Expected<std::unique_ptr<pfm::CounterGroup>>54ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &,55                              ArrayRef<const char *> ValidationCounters,56                              const pid_t ProcessID) const {57  pfm::PerfEvent Event(CounterName);58  if (!Event.valid())59    return make_error<Failure>(Twine("Unable to create counter with name '")60                                   .concat(CounterName)61                                   .concat("'"));62 63  std::vector<pfm::PerfEvent> ValidationEvents;64  for (const char *ValCounterName : ValidationCounters) {65    ValidationEvents.emplace_back(ValCounterName);66    if (!ValidationEvents.back().valid())67      return make_error<Failure>(68          Twine("Unable to create validation counter with name '")69              .concat(ValCounterName)70              .concat("'"));71  }72 73  return std::make_unique<pfm::CounterGroup>(74      std::move(Event), std::move(ValidationEvents), ProcessID);75}76 77void ExegesisTarget::registerTarget(ExegesisTarget *Target) {78  if (FirstTarget == nullptr) {79    FirstTarget = Target;80    return;81  }82  if (Target->Next != nullptr)83    return; // Already registered.84  Target->Next = FirstTarget;85  FirstTarget = Target;86}87 88std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator(89    Benchmark::ModeE Mode, const LLVMState &State,90    const SnippetGenerator::Options &Opts) const {91  switch (Mode) {92  case Benchmark::Unknown:93    return nullptr;94  case Benchmark::Latency:95    return createSerialSnippetGenerator(State, Opts);96  case Benchmark::Uops:97  case Benchmark::InverseThroughput:98    return createParallelSnippetGenerator(State, Opts);99  }100  return nullptr;101}102 103Expected<std::unique_ptr<BenchmarkRunner>>104ExegesisTarget::createBenchmarkRunner(105    Benchmark::ModeE Mode, const LLVMState &State,106    BenchmarkPhaseSelectorE BenchmarkPhaseSelector,107    BenchmarkRunner::ExecutionModeE ExecutionMode,108    unsigned BenchmarkRepeatCount, ArrayRef<ValidationEvent> ValidationCounters,109    Benchmark::ResultAggregationModeE ResultAggMode) const {110  PfmCountersInfo PfmCounters = State.getPfmCounters();111  switch (Mode) {112  case Benchmark::Unknown:113    return nullptr;114  case Benchmark::Latency:115  case Benchmark::InverseThroughput:116    if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&117        !PfmCounters.CycleCounter) {118      const char *ModeName = Mode == Benchmark::Latency119                                 ? "latency"120                                 : "inverse_throughput";121      return make_error<Failure>(122          Twine("can't run '")123              .concat(ModeName)124              .concat(125                  "' mode, sched model does not define a cycle counter. You "126                  "can pass --benchmark-phase=... to skip the actual "127                  "benchmarking or --use-dummy-perf-counters to not query "128                  "the kernel for real event counts."));129    }130    return createLatencyBenchmarkRunner(131        State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,132        ValidationCounters, BenchmarkRepeatCount);133  case Benchmark::Uops:134    if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&135        !PfmCounters.UopsCounter && !PfmCounters.IssueCounters)136      return make_error<Failure>(137          "can't run 'uops' mode, sched model does not define uops or issue "138          "counters. You can pass --benchmark-phase=... to skip the actual "139          "benchmarking or --use-dummy-perf-counters to not query the kernel "140          "for real event counts.");141    return createUopsBenchmarkRunner(State, BenchmarkPhaseSelector,142                                     ResultAggMode, ExecutionMode,143                                     ValidationCounters);144  }145  return nullptr;146}147 148std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator(149    const LLVMState &State, const SnippetGenerator::Options &Opts) const {150  return std::make_unique<SerialSnippetGenerator>(State, Opts);151}152 153std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator(154    const LLVMState &State, const SnippetGenerator::Options &Opts) const {155  return std::make_unique<ParallelSnippetGenerator>(State, Opts);156}157 158std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(159    const LLVMState &State, Benchmark::ModeE Mode,160    BenchmarkPhaseSelectorE BenchmarkPhaseSelector,161    Benchmark::ResultAggregationModeE ResultAggMode,162    BenchmarkRunner::ExecutionModeE ExecutionMode,163    ArrayRef<ValidationEvent> ValidationCounters,164    unsigned BenchmarkRepeatCount) const {165  return std::make_unique<LatencyBenchmarkRunner>(166      State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,167      ValidationCounters, BenchmarkRepeatCount);168}169 170std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(171    const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,172    Benchmark::ResultAggregationModeE /*unused*/,173    BenchmarkRunner::ExecutionModeE ExecutionMode,174    ArrayRef<ValidationEvent> ValidationCounters) const {175  return std::make_unique<UopsBenchmarkRunner>(176      State, BenchmarkPhaseSelector, ExecutionMode, ValidationCounters);177}178 179static_assert(std::is_trivial_v<PfmCountersInfo>,180              "We shouldn't have dynamic initialization here");181 182const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,183                                                  0u,      nullptr, 0u};184const PfmCountersInfo PfmCountersInfo::Dummy = {185    pfm::PerfEvent::DummyEventString,186    pfm::PerfEvent::DummyEventString,187    nullptr,188    0u,189    nullptr,190    0u};191 192const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {193  assert(194      is_sorted(CpuPfmCounters,195                [](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) {196                  return strcmp(LHS.CpuName, RHS.CpuName) < 0;197                }) &&198      "CpuPfmCounters table is not sorted");199 200  // Find entry201  auto Found = lower_bound(CpuPfmCounters, CpuName);202  if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) {203    // Use the default.204    if (!CpuPfmCounters.empty() && CpuPfmCounters.begin()->CpuName[0] == '\0') {205      Found = CpuPfmCounters.begin(); // The target specifies a default.206    } else {207      return PfmCountersInfo::Default; // No default for the target.208    }209  }210  assert(Found->PCI && "Missing counters");211  return *Found->PCI;212}213 214const PfmCountersInfo &ExegesisTarget::getDummyPfmCounters() const {215  return PfmCountersInfo::Dummy;216}217 218ExegesisTarget::SavedState::~SavedState() = default; // anchor.219 220namespace {221 222bool opcodeIsNotAvailable(unsigned, const FeatureBitset &) { return false; }223 224// Default implementation.225class ExegesisDefaultTarget : public ExegesisTarget {226public:227  ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {}228 229private:230  std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg,231                               const APInt &Value) const override {232    llvm_unreachable("Not yet implemented");233  }234 235  bool matchesArch(Triple::ArchType Arch) const override {236    llvm_unreachable("never called");237    return false;238  }239};240 241} // namespace242 243const ExegesisTarget &ExegesisTarget::getDefault() {244  static ExegesisDefaultTarget Target;245  return Target;246}247 248} // namespace exegesis249} // namespace llvm250