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
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() {} // 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(Arch: TT.getArch()))
33 return T;
34 }
35 return nullptr;
36}
37
38Expected<std::unique_ptr<pfm::CounterGroup>>
39ExegesisTarget::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>(Args: Twine("Unable to create counter with name '")
45 .concat(Suffix: CounterName)
46 .concat(Suffix: "'"));
47
48 std::vector<pfm::PerfEvent> ValidationEvents;
49 for (const char *ValCounterName : ValidationCounters) {
50 ValidationEvents.emplace_back(args&: ValCounterName);
51 if (!ValidationEvents.back().valid())
52 return make_error<Failure>(
53 Args: Twine("Unable to create validation counter with name '")
54 .concat(Suffix: ValCounterName)
55 .concat(Suffix: "'"));
56 }
57
58 return std::make_unique<pfm::CounterGroup>(
59 args: std::move(Event), args: std::move(ValidationEvents), args: ProcessID);
60}
61
62void 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
73std::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
88Expected<std::unique_ptr<BenchmarkRunner>>
89ExegesisTarget::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 Args: Twine("can't run '")
108 .concat(Suffix: ModeName)
109 .concat(
110 Suffix: "' 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 Args: "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
133std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator(
134 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
135 return std::make_unique<SerialSnippetGenerator>(args: State, args: Opts);
136}
137
138std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator(
139 const LLVMState &State, const SnippetGenerator::Options &Opts) const {
140 return std::make_unique<ParallelSnippetGenerator>(args: State, args: Opts);
141}
142
143std::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 args: State, args&: Mode, args&: BenchmarkPhaseSelector, args&: ResultAggMode, args&: ExecutionMode,
152 args&: ValidationCounters, args&: BenchmarkRepeatCount);
153}
154
155std::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 args: State, args&: BenchmarkPhaseSelector, args&: ExecutionMode, args&: ValidationCounters);
162}
163
164static_assert(std::is_trivial_v<PfmCountersInfo>,
165 "We shouldn't have dynamic initialization here");
166
167const PfmCountersInfo PfmCountersInfo::Default = {.CycleCounter: nullptr, .UopsCounter: nullptr, .IssueCounters: nullptr,
168 .NumIssueCounters: 0u, .ValidationEvents: nullptr, .NumValidationEvents: 0u};
169const PfmCountersInfo PfmCountersInfo::Dummy = {
170 .CycleCounter: pfm::PerfEvent::DummyEventString,
171 .UopsCounter: pfm::PerfEvent::DummyEventString,
172 .IssueCounters: nullptr,
173 .NumIssueCounters: 0u,
174 .ValidationEvents: nullptr,
175 .NumValidationEvents: 0u};
176
177const 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(Range: CpuPfmCounters, Value&: 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
199const PfmCountersInfo &ExegesisTarget::getDummyPfmCounters() const {
200 return PfmCountersInfo::Dummy;
201}
202
203ExegesisTarget::SavedState::~SavedState() {} // anchor.
204
205namespace {
206
207bool opcodeIsNotAvailable(unsigned, const FeatureBitset &) { return false; }
208
209// Default implementation.
210class ExegesisDefaultTarget : public ExegesisTarget {
211public:
212 ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {}
213
214private:
215 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned 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
228const ExegesisTarget &ExegesisTarget::getDefault() {
229 static ExegesisDefaultTarget Target;
230 return Target;
231}
232
233} // namespace exegesis
234} // namespace llvm
235