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