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