blob: 9c4ed567f11d63f3b95b0f14b8a3a873bae6d90e [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
Clement Courbet0e69e2d2018-05-17 10:52:18 +000059llvm::Expected<std::vector<llvm::MCInst>>
60LatencyBenchmarkRunner::createSnippet(RegisterAliasingTrackerCache &RATC,
61 unsigned Opcode,
62 llvm::raw_ostream &Info) const {
63 std::vector<llvm::MCInst> Snippet;
64 const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode);
65 const Instruction ThisInstruction(MCInstrDesc, RATC);
Clement Courbetac74acd2018-04-04 11:37:06 +000066
Clement Courbet0e69e2d2018-05-17 10:52:18 +000067 std::string Error;
68 if (IsInfeasible(ThisInstruction, Error))
69 return makeError(llvm::Twine("Infeasible : ").concat(Error));
70
71 const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction);
72 if (!SelfAliasing.empty()) {
73 if (!SelfAliasing.hasImplicitAliasing()) {
74 Info << "explicit self cycles, selecting one aliasing configuration.\n";
75 setRandomAliasing(SelfAliasing);
76 } else {
77 Info << "implicit Self cycles, picking random values.\n";
78 }
79 Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
80 return Snippet;
Clement Courbetac74acd2018-04-04 11:37:06 +000081 }
82
Clement Courbet0e69e2d2018-05-17 10:52:18 +000083 // Let's try to create a dependency through another opcode.
84 std::vector<unsigned> Opcodes;
85 Opcodes.resize(MCInstrInfo.getNumOpcodes());
86 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
87 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
88 for (const unsigned OtherOpcode : Opcodes) {
89 clearVariableAssignments(ThisInstruction);
90 if (OtherOpcode == Opcode)
91 continue;
92 const Instruction OtherInstruction(MCInstrInfo.get(OtherOpcode), RATC);
93 if (IsInfeasible(OtherInstruction, Error))
94 continue;
95 const AliasingConfigurations Forward(ThisInstruction, OtherInstruction);
96 const AliasingConfigurations Back(OtherInstruction, ThisInstruction);
97 if (Forward.empty() || Back.empty())
98 continue;
99 setRandomAliasing(Forward);
100 setRandomAliasing(Back);
101 Info << "creating cycle through " << MCInstrInfo.getName(OtherOpcode)
102 << ".\n";
103 Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
104 Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction));
105 return Snippet;
106 }
107
108 return makeError(
109 "Infeasible : Didn't find any scheme to make the instruction serial\n");
Clement Courbetac74acd2018-04-04 11:37:06 +0000110}
111
112std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000113LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Clement Courbetac74acd2018-04-04 11:37:06 +0000114 const unsigned NumRepetitions) const {
115 // Cycle measurements include some overhead from the kernel. Repeat the
116 // measure several times and take the minimum value.
117 constexpr const int NumMeasurements = 30;
118 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +0000119 const char *CounterName = State.getSubtargetInfo()
120 .getSchedModel()
121 .getExtraProcessorInfo()
122 .PfmCounters.CycleCounter;
123 if (!CounterName)
124 llvm::report_fatal_error("sched model does not define a cycle counter");
125 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000126 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000127 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000128 for (size_t I = 0; I < NumMeasurements; ++I) {
129 pfm::Counter Counter(CyclesPerfEvent);
130 Counter.start();
131 Function();
132 Counter.stop();
133 const int64_t Value = Counter.read();
134 if (Value < MinLatency)
135 MinLatency = Value;
136 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000137 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000138}
139
140} // namespace exegesis