blob: 6545660d65a824de619fda5fb47d10cb869ca00f [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
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000022static bool hasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000023 return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
24}
25
Clement Courbetac74acd2018-04-04 11:37:06 +000026// FIXME: Handle memory, see PR36905.
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000027static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000028 return OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
29}
30
Clement Courbetac74acd2018-04-04 11:37:06 +000031LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
32
Clement Courbet62b34fa2018-06-06 09:42:36 +000033InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const {
34 return InstructionBenchmark::Latency;
Clement Courbet2cb97b92018-06-04 11:43:40 +000035}
Clement Courbetac74acd2018-04-04 11:37:06 +000036
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000037llvm::Error LatencyBenchmarkRunner::isInfeasible(
38 const llvm::MCInstrDesc &MCInstrDesc) const {
39 if (MCInstrDesc.isPseudo())
40 return llvm::make_error<BenchmarkFailure>("Infeasible : is pseudo");
41 if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
42 return llvm::make_error<BenchmarkFailure>(
43 "Infeasible : has unknown operands");
44 if (llvm::any_of(MCInstrDesc.operands(), hasMemoryOperand))
45 return llvm::make_error<BenchmarkFailure>(
46 "Infeasible : has memory operands");
47 return llvm::Error::success();
48}
Clement Courbetac74acd2018-04-04 11:37:06 +000049
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000050llvm::Expected<BenchmarkConfiguration>
51LatencyBenchmarkRunner::generateSelfAliasingConfiguration(
52 const Instruction &Instr,
53 const AliasingConfigurations &SelfAliasing) const {
Guillaume Chateletb4f15822018-06-07 14:00:29 +000054 BenchmarkConfiguration Conf;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000055 InstructionInstance II(Instr);
56 if (SelfAliasing.hasImplicitAliasing()) {
57 Conf.Info = "implicit Self cycles, picking random values.";
58 } else {
59 Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
60 // This is a self aliasing instruction so defs and uses are from the same
61 // instance, hence twice II in the following call.
62 setRandomAliasing(SelfAliasing, II, II);
Clement Courbetac74acd2018-04-04 11:37:06 +000063 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000064 Conf.Snippet = {II.randomizeUnsetVariablesAndBuild()};
65 return Conf;
66}
Clement Courbetac74acd2018-04-04 11:37:06 +000067
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000068llvm::Expected<BenchmarkConfiguration>
69LatencyBenchmarkRunner::generateTwoInstructionConfiguration(
70 const Instruction &Instr,
71 const AliasingConfigurations &SelfAliasing) const {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000072 std::vector<unsigned> Opcodes;
73 Opcodes.resize(MCInstrInfo.getNumOpcodes());
74 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
75 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
76 for (const unsigned OtherOpcode : Opcodes) {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000077 if (OtherOpcode == Instr.Description.Opcode)
Clement Courbet0e69e2d2018-05-17 10:52:18 +000078 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000079 const auto &OtherInstrDesc = MCInstrInfo.get(OtherOpcode);
80 if (auto E = isInfeasible(OtherInstrDesc)) {
81 llvm::consumeError(std::move(E));
Clement Courbet0e69e2d2018-05-17 10:52:18 +000082 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000083 }
84 const Instruction OtherInstr(OtherInstrDesc, RATC);
85 const AliasingConfigurations Forward(Instr, OtherInstr);
86 const AliasingConfigurations Back(OtherInstr, Instr);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000087 if (Forward.empty() || Back.empty())
88 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000089 InstructionInstance ThisII(Instr);
90 InstructionInstance OtherII(OtherInstr);
91 if (!Forward.hasImplicitAliasing())
92 setRandomAliasing(Forward, ThisII, OtherII);
93 if (!Back.hasImplicitAliasing())
94 setRandomAliasing(Back, OtherII, ThisII);
95 BenchmarkConfiguration Conf;
Guillaume Chateletb4f15822018-06-07 14:00:29 +000096 Conf.Info = llvm::Twine("creating cycle through ")
97 .concat(MCInstrInfo.getName(OtherOpcode))
98 .concat(".")
99 .str();
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000100 Conf.Snippet.push_back(ThisII.randomizeUnsetVariablesAndBuild());
101 Conf.Snippet.push_back(OtherII.randomizeUnsetVariablesAndBuild());
102 return Conf;
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000103 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000104 return llvm::make_error<BenchmarkFailure>(
105 "Infeasible : Didn't find any scheme to make the instruction serial");
106}
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000107
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000108llvm::Expected<BenchmarkConfiguration>
109LatencyBenchmarkRunner::generateConfiguration(unsigned Opcode) const {
110 const auto &InstrDesc = MCInstrInfo.get(Opcode);
111 if (auto E = isInfeasible(InstrDesc))
112 return std::move(E);
113 const Instruction Instr(InstrDesc, RATC);
114 const AliasingConfigurations SelfAliasing(Instr, Instr);
115 if (SelfAliasing.empty()) {
116 // No self aliasing, trying to create a dependency through another opcode.
117 return generateTwoInstructionConfiguration(Instr, SelfAliasing);
118 } else {
119 return generateSelfAliasingConfiguration(Instr, SelfAliasing);
120 }
121}
122
123llvm::Expected<std::vector<BenchmarkConfiguration>>
124LatencyBenchmarkRunner::createConfigurations(unsigned Opcode) const {
125 if (auto E = generateConfiguration(Opcode))
126 return std::vector<BenchmarkConfiguration>{E.get()};
127 else
128 return E.takeError();
Clement Courbetac74acd2018-04-04 11:37:06 +0000129}
130
131std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000132LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Clement Courbetac74acd2018-04-04 11:37:06 +0000133 const unsigned NumRepetitions) const {
134 // Cycle measurements include some overhead from the kernel. Repeat the
135 // measure several times and take the minimum value.
136 constexpr const int NumMeasurements = 30;
137 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +0000138 const char *CounterName = State.getSubtargetInfo()
139 .getSchedModel()
140 .getExtraProcessorInfo()
141 .PfmCounters.CycleCounter;
142 if (!CounterName)
143 llvm::report_fatal_error("sched model does not define a cycle counter");
144 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000145 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000146 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000147 for (size_t I = 0; I < NumMeasurements; ++I) {
148 pfm::Counter Counter(CyclesPerfEvent);
149 Counter.start();
150 Function();
151 Counter.stop();
152 const int64_t Value = Counter.read();
153 if (Value < MinLatency)
154 MinLatency = Value;
155 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000156 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000157}
158
159} // namespace exegesis