blob: 59097e1d2a28616c1cc3869dc5bc431b5bff143a [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- Latency.cpp ---------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Latency.h"
Clement Courbet0e69e2d2018-05-17 10:52:18 +000011
12#include "Assembler.h"
13#include "BenchmarkRunner.h"
14#include "MCInstrDescView.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000015#include "PerfHelper.h"
Clement Courbet0e69e2d2018-05-17 10:52:18 +000016#include "llvm/ADT/STLExtras.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/MC/MCInstBuilder.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000019
20namespace exegesis {
21
Clement Courbet0e69e2d2018-05-17 10:52:18 +000022static bool HasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
23 return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
24}
25
Clement Courbetac74acd2018-04-04 11:37:06 +000026// FIXME: Handle memory, see PR36905.
Clement Courbet0e69e2d2018-05-17 10:52:18 +000027static bool HasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
28 return OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
29}
30
31static bool IsInfeasible(const Instruction &Instruction, std::string &Error) {
32 const auto &MCInstrDesc = Instruction.Description;
33 if (MCInstrDesc.isPseudo()) {
34 Error = "is pseudo";
Clement Courbetac74acd2018-04-04 11:37:06 +000035 return true;
Clement Courbetac74acd2018-04-04 11:37:06 +000036 }
Clement Courbet0e69e2d2018-05-17 10:52:18 +000037 if (llvm::any_of(MCInstrDesc.operands(), HasUnknownOperand)) {
38 Error = "has unknown operands";
39 return true;
40 }
41 if (llvm::any_of(MCInstrDesc.operands(), HasMemoryOperand)) {
42 Error = "has memory operands";
43 return true;
44 }
45 return false;
Clement Courbetac74acd2018-04-04 11:37:06 +000046}
47
48static llvm::Error makeError(llvm::Twine Msg) {
49 return llvm::make_error<llvm::StringError>(Msg,
50 llvm::inconvertibleErrorCode());
51}
52
53LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
54
Clement Courbet62b34fa2018-06-06 09:42:36 +000055InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const {
56 return InstructionBenchmark::Latency;
Clement Courbet2cb97b92018-06-04 11:43:40 +000057}
Clement Courbetac74acd2018-04-04 11:37:06 +000058
Guillaume Chatelet7b852cd2018-06-07 08:11:54 +000059llvm::Expected<BenchmarkConfiguration>
60LatencyBenchmarkRunner::createConfiguration(RegisterAliasingTrackerCache &RATC,
61 unsigned Opcode,
62 llvm::raw_ostream &Info) const {
63 BenchmarkConfiguration Configuration;
64 std::vector<llvm::MCInst> &Snippet = Configuration.Snippet;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000065 const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode);
66 const Instruction ThisInstruction(MCInstrDesc, RATC);
Clement Courbetac74acd2018-04-04 11:37:06 +000067
Clement Courbet0e69e2d2018-05-17 10:52:18 +000068 std::string Error;
69 if (IsInfeasible(ThisInstruction, Error))
70 return makeError(llvm::Twine("Infeasible : ").concat(Error));
71
72 const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction);
73 if (!SelfAliasing.empty()) {
74 if (!SelfAliasing.hasImplicitAliasing()) {
75 Info << "explicit self cycles, selecting one aliasing configuration.\n";
76 setRandomAliasing(SelfAliasing);
77 } else {
78 Info << "implicit Self cycles, picking random values.\n";
79 }
80 Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
Guillaume Chatelet7b852cd2018-06-07 08:11:54 +000081 return Configuration;
Clement Courbetac74acd2018-04-04 11:37:06 +000082 }
83
Clement Courbet0e69e2d2018-05-17 10:52:18 +000084 // Let's try to create a dependency through another opcode.
85 std::vector<unsigned> Opcodes;
86 Opcodes.resize(MCInstrInfo.getNumOpcodes());
87 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
88 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
89 for (const unsigned OtherOpcode : Opcodes) {
90 clearVariableAssignments(ThisInstruction);
91 if (OtherOpcode == Opcode)
92 continue;
93 const Instruction OtherInstruction(MCInstrInfo.get(OtherOpcode), RATC);
94 if (IsInfeasible(OtherInstruction, Error))
95 continue;
96 const AliasingConfigurations Forward(ThisInstruction, OtherInstruction);
97 const AliasingConfigurations Back(OtherInstruction, ThisInstruction);
98 if (Forward.empty() || Back.empty())
99 continue;
100 setRandomAliasing(Forward);
101 setRandomAliasing(Back);
102 Info << "creating cycle through " << MCInstrInfo.getName(OtherOpcode)
103 << ".\n";
104 Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
105 Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction));
Guillaume Chatelet7b852cd2018-06-07 08:11:54 +0000106 return Configuration;
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000107 }
108
109 return makeError(
110 "Infeasible : Didn't find any scheme to make the instruction serial\n");
Clement Courbetac74acd2018-04-04 11:37:06 +0000111}
112
113std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000114LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Clement Courbetac74acd2018-04-04 11:37:06 +0000115 const unsigned NumRepetitions) const {
116 // Cycle measurements include some overhead from the kernel. Repeat the
117 // measure several times and take the minimum value.
118 constexpr const int NumMeasurements = 30;
119 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +0000120 const char *CounterName = State.getSubtargetInfo()
121 .getSchedModel()
122 .getExtraProcessorInfo()
123 .PfmCounters.CycleCounter;
124 if (!CounterName)
125 llvm::report_fatal_error("sched model does not define a cycle counter");
126 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000127 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000128 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000129 for (size_t I = 0; I < NumMeasurements; ++I) {
130 pfm::Counter Counter(CyclesPerfEvent);
131 Counter.start();
132 Function();
133 Counter.stop();
134 const int64_t Value = Counter.read();
135 if (Value < MinLatency)
136 MinLatency = Value;
137 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000138 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000139}
140
141} // namespace exegesis