xref: /llvm-project/llvm/tools/llvm-exegesis/lib/Target.cpp (revision ff1b01bb7897bf2401540096af775d35b12eb247)
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