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