blob: 96d20ae5641f877e680e7819d0cc17d9fbdcca12 [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"
Guillaume Chateletef6cef52018-06-20 08:52:30 +000019#include "llvm/Support/FormatVariadic.h"
Clement Courbetac74acd2018-04-04 11:37:06 +000020
21namespace exegesis {
22
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000023static bool hasUnknownOperand(const llvm::MCOperandInfo &OpInfo) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000024 return OpInfo.OperandType == llvm::MCOI::OPERAND_UNKNOWN;
25}
26
Clement Courbetac74acd2018-04-04 11:37:06 +000027// FIXME: Handle memory, see PR36905.
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000028static bool hasMemoryOperand(const llvm::MCOperandInfo &OpInfo) {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000029 return OpInfo.OperandType == llvm::MCOI::OPERAND_MEMORY;
30}
31
Clement Courbetac74acd2018-04-04 11:37:06 +000032LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
33
Clement Courbet62b34fa2018-06-06 09:42:36 +000034InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const {
35 return InstructionBenchmark::Latency;
Clement Courbet2cb97b92018-06-04 11:43:40 +000036}
Clement Courbetac74acd2018-04-04 11:37:06 +000037
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000038llvm::Error LatencyBenchmarkRunner::isInfeasible(
39 const llvm::MCInstrDesc &MCInstrDesc) const {
40 if (MCInstrDesc.isPseudo())
41 return llvm::make_error<BenchmarkFailure>("Infeasible : is pseudo");
42 if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
43 return llvm::make_error<BenchmarkFailure>(
44 "Infeasible : has unknown operands");
45 if (llvm::any_of(MCInstrDesc.operands(), hasMemoryOperand))
46 return llvm::make_error<BenchmarkFailure>(
47 "Infeasible : has memory operands");
48 return llvm::Error::success();
49}
Clement Courbetac74acd2018-04-04 11:37:06 +000050
Guillaume Chateletef6cef52018-06-20 08:52:30 +000051llvm::Expected<SnippetPrototype>
52LatencyBenchmarkRunner::generateSelfAliasingPrototype(
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000053 const Instruction &Instr,
54 const AliasingConfigurations &SelfAliasing) const {
Guillaume Chateletef6cef52018-06-20 08:52:30 +000055 SnippetPrototype Prototype;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000056 InstructionInstance II(Instr);
57 if (SelfAliasing.hasImplicitAliasing()) {
Guillaume Chateletef6cef52018-06-20 08:52:30 +000058 Prototype.Explanation = "implicit Self cycles, picking random values.";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000059 } else {
Guillaume Chateletef6cef52018-06-20 08:52:30 +000060 Prototype.Explanation =
61 "explicit self cycles, selecting one aliasing Conf.";
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000062 // This is a self aliasing instruction so defs and uses are from the same
63 // instance, hence twice II in the following call.
64 setRandomAliasing(SelfAliasing, II, II);
Clement Courbetac74acd2018-04-04 11:37:06 +000065 }
Guillaume Chateletef6cef52018-06-20 08:52:30 +000066 Prototype.Snippet.push_back(std::move(II));
67 return Prototype;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000068}
Clement Courbetac74acd2018-04-04 11:37:06 +000069
Guillaume Chateletef6cef52018-06-20 08:52:30 +000070llvm::Expected<SnippetPrototype>
71LatencyBenchmarkRunner::generateTwoInstructionPrototype(
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000072 const Instruction &Instr,
73 const AliasingConfigurations &SelfAliasing) const {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000074 std::vector<unsigned> Opcodes;
75 Opcodes.resize(MCInstrInfo.getNumOpcodes());
76 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
77 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
78 for (const unsigned OtherOpcode : Opcodes) {
Guillaume Chateletef6cef52018-06-20 08:52:30 +000079 if (OtherOpcode == Instr.Description->Opcode)
Clement Courbet0e69e2d2018-05-17 10:52:18 +000080 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000081 const auto &OtherInstrDesc = MCInstrInfo.get(OtherOpcode);
82 if (auto E = isInfeasible(OtherInstrDesc)) {
83 llvm::consumeError(std::move(E));
Clement Courbet0e69e2d2018-05-17 10:52:18 +000084 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000085 }
86 const Instruction OtherInstr(OtherInstrDesc, RATC);
87 const AliasingConfigurations Forward(Instr, OtherInstr);
88 const AliasingConfigurations Back(OtherInstr, Instr);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000089 if (Forward.empty() || Back.empty())
90 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000091 InstructionInstance ThisII(Instr);
92 InstructionInstance OtherII(OtherInstr);
93 if (!Forward.hasImplicitAliasing())
94 setRandomAliasing(Forward, ThisII, OtherII);
95 if (!Back.hasImplicitAliasing())
96 setRandomAliasing(Back, OtherII, ThisII);
Guillaume Chateletef6cef52018-06-20 08:52:30 +000097 SnippetPrototype Prototype;
98 Prototype.Explanation = llvm::formatv("creating cycle through {0}.",
99 MCInstrInfo.getName(OtherOpcode));
100 Prototype.Snippet.push_back(std::move(ThisII));
101 Prototype.Snippet.push_back(std::move(OtherII));
102 return Prototype;
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 Chateletef6cef52018-06-20 08:52:30 +0000108llvm::Expected<SnippetPrototype>
109LatencyBenchmarkRunner::generatePrototype(unsigned Opcode) const {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000110 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.
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000117 return generateTwoInstructionPrototype(Instr, SelfAliasing);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000118 } else {
Guillaume Chateletef6cef52018-06-20 08:52:30 +0000119 return generateSelfAliasingPrototype(Instr, SelfAliasing);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +0000120 }
121}
122
Clement Courbetac74acd2018-04-04 11:37:06 +0000123std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000124LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Clement Courbetac74acd2018-04-04 11:37:06 +0000125 const unsigned NumRepetitions) const {
126 // Cycle measurements include some overhead from the kernel. Repeat the
127 // measure several times and take the minimum value.
128 constexpr const int NumMeasurements = 30;
129 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +0000130 const char *CounterName = State.getSubtargetInfo()
131 .getSchedModel()
132 .getExtraProcessorInfo()
133 .PfmCounters.CycleCounter;
134 if (!CounterName)
135 llvm::report_fatal_error("sched model does not define a cycle counter");
136 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000137 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000138 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000139 for (size_t I = 0; I < NumMeasurements; ++I) {
140 pfm::Counter Counter(CyclesPerfEvent);
141 Counter.start();
142 Function();
143 Counter.stop();
144 const int64_t Value = Counter.read();
145 if (Value < MinLatency)
146 MinLatency = Value;
147 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000148 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000149}
150
151} // namespace exegesis