blob: 896b54358a69eae01091920dffb57e56d321c92f [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
Clement Courbetac74acd2018-04-04 11:37:06 +000048LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
49
Clement Courbet62b34fa2018-06-06 09:42:36 +000050InstructionBenchmark::ModeE LatencyBenchmarkRunner::getMode() const {
51 return InstructionBenchmark::Latency;
Clement Courbet2cb97b92018-06-04 11:43:40 +000052}
Clement Courbetac74acd2018-04-04 11:37:06 +000053
Guillaume Chateletb4f15822018-06-07 14:00:29 +000054llvm::Expected<std::vector<BenchmarkConfiguration>>
55LatencyBenchmarkRunner::createConfigurations(RegisterAliasingTrackerCache &RATC,
56 unsigned Opcode) const {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000057 const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode);
58 const Instruction ThisInstruction(MCInstrDesc, RATC);
Clement Courbetac74acd2018-04-04 11:37:06 +000059
Clement Courbet0e69e2d2018-05-17 10:52:18 +000060 std::string Error;
61 if (IsInfeasible(ThisInstruction, Error))
Guillaume Chateletb4f15822018-06-07 14:00:29 +000062 return llvm::make_error<llvm::StringError>(
63 llvm::Twine("Infeasible : ").concat(Error),
64 llvm::inconvertibleErrorCode());
Clement Courbet0e69e2d2018-05-17 10:52:18 +000065
Guillaume Chateletb4f15822018-06-07 14:00:29 +000066 BenchmarkConfiguration Conf;
Clement Courbet0e69e2d2018-05-17 10:52:18 +000067 const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction);
68 if (!SelfAliasing.empty()) {
69 if (!SelfAliasing.hasImplicitAliasing()) {
Guillaume Chateletb4f15822018-06-07 14:00:29 +000070 Conf.Info = "explicit self cycles, selecting one aliasing Conf.";
Clement Courbet0e69e2d2018-05-17 10:52:18 +000071 setRandomAliasing(SelfAliasing);
72 } else {
Guillaume Chateletb4f15822018-06-07 14:00:29 +000073 Conf.Info = "implicit Self cycles, picking random values.";
Clement Courbet0e69e2d2018-05-17 10:52:18 +000074 }
Guillaume Chateletb4f15822018-06-07 14:00:29 +000075 Conf.Snippet = {randomizeUnsetVariablesAndBuild(ThisInstruction)};
76 return std::vector<BenchmarkConfiguration>{Conf};
Clement Courbetac74acd2018-04-04 11:37:06 +000077 }
78
Clement Courbet0e69e2d2018-05-17 10:52:18 +000079 // Let's try to create a dependency through another opcode.
80 std::vector<unsigned> Opcodes;
81 Opcodes.resize(MCInstrInfo.getNumOpcodes());
82 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
83 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
84 for (const unsigned OtherOpcode : Opcodes) {
85 clearVariableAssignments(ThisInstruction);
86 if (OtherOpcode == Opcode)
87 continue;
88 const Instruction OtherInstruction(MCInstrInfo.get(OtherOpcode), RATC);
89 if (IsInfeasible(OtherInstruction, Error))
90 continue;
91 const AliasingConfigurations Forward(ThisInstruction, OtherInstruction);
92 const AliasingConfigurations Back(OtherInstruction, ThisInstruction);
93 if (Forward.empty() || Back.empty())
94 continue;
95 setRandomAliasing(Forward);
96 setRandomAliasing(Back);
Guillaume Chateletb4f15822018-06-07 14:00:29 +000097 Conf.Info = llvm::Twine("creating cycle through ")
98 .concat(MCInstrInfo.getName(OtherOpcode))
99 .concat(".")
100 .str();
101 Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction));
102 Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction));
103 return std::vector<BenchmarkConfiguration>{Conf};
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000104 }
105
Guillaume Chateletb4f15822018-06-07 14:00:29 +0000106 return llvm::make_error<llvm::StringError>(
107 "Infeasible : Didn't find any scheme to make the instruction serial",
108 llvm::inconvertibleErrorCode());
Clement Courbetac74acd2018-04-04 11:37:06 +0000109}
110
111std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000112LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Clement Courbetac74acd2018-04-04 11:37:06 +0000113 const unsigned NumRepetitions) const {
114 // Cycle measurements include some overhead from the kernel. Repeat the
115 // measure several times and take the minimum value.
116 constexpr const int NumMeasurements = 30;
117 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +0000118 const char *CounterName = State.getSubtargetInfo()
119 .getSchedModel()
120 .getExtraProcessorInfo()
121 .PfmCounters.CycleCounter;
122 if (!CounterName)
123 llvm::report_fatal_error("sched model does not define a cycle counter");
124 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000125 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000126 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000127 for (size_t I = 0; I < NumMeasurements; ++I) {
128 pfm::Counter Counter(CyclesPerfEvent);
129 Counter.start();
130 Function();
131 Counter.stop();
132 const int64_t Value = Counter.read();
133 if (Value < MinLatency)
134 MinLatency = Value;
135 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000136 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000137}
138
139} // namespace exegesis