blob: b8452ac35a8af6c3c0c6d446fca232320cadb52f [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
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000034llvm::Error LatencyBenchmarkRunner::isInfeasible(
35 const llvm::MCInstrDesc &MCInstrDesc) const {
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000036 if (llvm::any_of(MCInstrDesc.operands(), hasUnknownOperand))
37 return llvm::make_error<BenchmarkFailure>(
38 "Infeasible : has unknown operands");
39 if (llvm::any_of(MCInstrDesc.operands(), hasMemoryOperand))
40 return llvm::make_error<BenchmarkFailure>(
41 "Infeasible : has memory operands");
42 return llvm::Error::success();
43}
Clement Courbetac74acd2018-04-04 11:37:06 +000044
Guillaume Chatelete60866a2018-08-03 09:29:38 +000045llvm::Expected<CodeTemplate>
Guillaume Chateletef6cef52018-06-20 08:52:30 +000046LatencyBenchmarkRunner::generateTwoInstructionPrototype(
Clement Courbet717c9762018-06-28 07:41:16 +000047 const Instruction &Instr) const {
Clement Courbet0e69e2d2018-05-17 10:52:18 +000048 std::vector<unsigned> Opcodes;
Clement Courbet0e8bf4e2018-06-25 13:44:27 +000049 Opcodes.resize(State.getInstrInfo().getNumOpcodes());
Clement Courbet0e69e2d2018-05-17 10:52:18 +000050 std::iota(Opcodes.begin(), Opcodes.end(), 0U);
51 std::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
52 for (const unsigned OtherOpcode : Opcodes) {
Guillaume Chateletef6cef52018-06-20 08:52:30 +000053 if (OtherOpcode == Instr.Description->Opcode)
Clement Courbet0e69e2d2018-05-17 10:52:18 +000054 continue;
Clement Courbet0e8bf4e2018-06-25 13:44:27 +000055 const auto &OtherInstrDesc = State.getInstrInfo().get(OtherOpcode);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000056 if (auto E = isInfeasible(OtherInstrDesc)) {
57 llvm::consumeError(std::move(E));
Clement Courbet0e69e2d2018-05-17 10:52:18 +000058 continue;
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000059 }
60 const Instruction OtherInstr(OtherInstrDesc, RATC);
61 const AliasingConfigurations Forward(Instr, OtherInstr);
62 const AliasingConfigurations Back(OtherInstr, Instr);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000063 if (Forward.empty() || Back.empty())
64 continue;
Guillaume Chatelet171f3f42018-08-02 11:12:02 +000065 InstructionBuilder ThisIB(Instr);
66 InstructionBuilder OtherIB(OtherInstr);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000067 if (!Forward.hasImplicitAliasing())
Guillaume Chatelet171f3f42018-08-02 11:12:02 +000068 setRandomAliasing(Forward, ThisIB, OtherIB);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000069 if (!Back.hasImplicitAliasing())
Guillaume Chatelet171f3f42018-08-02 11:12:02 +000070 setRandomAliasing(Back, OtherIB, ThisIB);
Guillaume Chatelete60866a2018-08-03 09:29:38 +000071 CodeTemplate CT;
72 CT.Info = llvm::formatv("creating cycle through {0}.",
73 State.getInstrInfo().getName(OtherOpcode));
74 CT.Instructions.push_back(std::move(ThisIB));
75 CT.Instructions.push_back(std::move(OtherIB));
76 return std::move(CT);
Clement Courbet0e69e2d2018-05-17 10:52:18 +000077 }
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000078 return llvm::make_error<BenchmarkFailure>(
79 "Infeasible : Didn't find any scheme to make the instruction serial");
80}
Clement Courbet0e69e2d2018-05-17 10:52:18 +000081
Guillaume Chatelete60866a2018-08-03 09:29:38 +000082llvm::Expected<CodeTemplate>
83LatencyBenchmarkRunner::generateCodeTemplate(unsigned Opcode) const {
Clement Courbet0e8bf4e2018-06-25 13:44:27 +000084 const auto &InstrDesc = State.getInstrInfo().get(Opcode);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000085 if (auto E = isInfeasible(InstrDesc))
86 return std::move(E);
87 const Instruction Instr(InstrDesc, RATC);
Guillaume Chatelete60866a2018-08-03 09:29:38 +000088 if (auto CT = generateSelfAliasingCodeTemplate(Instr))
89 return CT;
Clement Courbet717c9762018-06-28 07:41:16 +000090 else
Guillaume Chatelete60866a2018-08-03 09:29:38 +000091 llvm::consumeError(CT.takeError());
Clement Courbet717c9762018-06-28 07:41:16 +000092 // No self aliasing, trying to create a dependency through another opcode.
93 return generateTwoInstructionPrototype(Instr);
Guillaume Chateletc9f727b2018-06-13 13:24:41 +000094}
95
John Brawn8fc5ec72018-07-02 13:14:49 +000096const char *LatencyBenchmarkRunner::getCounterName() const {
97 if (!State.getSubtargetInfo().getSchedModel().hasExtraProcessorInfo())
98 llvm::report_fatal_error("sched model is missing extra processor info!");
99 const char *CounterName = State.getSubtargetInfo()
100 .getSchedModel()
101 .getExtraProcessorInfo()
102 .PfmCounters.CycleCounter;
103 if (!CounterName)
104 llvm::report_fatal_error("sched model does not define a cycle counter");
105 return CounterName;
106}
107
Clement Courbetac74acd2018-04-04 11:37:06 +0000108std::vector<BenchmarkMeasure>
Clement Courbet0e69e2d2018-05-17 10:52:18 +0000109LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
Guillaume Chateletfb943542018-08-01 14:41:45 +0000110 ScratchSpace &Scratch,
Clement Courbetac74acd2018-04-04 11:37:06 +0000111 const unsigned NumRepetitions) const {
112 // Cycle measurements include some overhead from the kernel. Repeat the
113 // measure several times and take the minimum value.
114 constexpr const int NumMeasurements = 30;
115 int64_t MinLatency = std::numeric_limits<int64_t>::max();
John Brawn8fc5ec72018-07-02 13:14:49 +0000116 const char *CounterName = getCounterName();
Clement Courbetb4493792018-04-10 08:16:37 +0000117 if (!CounterName)
John Brawn8fc5ec72018-07-02 13:14:49 +0000118 llvm::report_fatal_error("could not determine cycle counter name");
Clement Courbetb4493792018-04-10 08:16:37 +0000119 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +0000120 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +0000121 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +0000122 for (size_t I = 0; I < NumMeasurements; ++I) {
123 pfm::Counter Counter(CyclesPerfEvent);
Guillaume Chateletfb943542018-08-01 14:41:45 +0000124 Scratch.clear();
Clement Courbetac74acd2018-04-04 11:37:06 +0000125 Counter.start();
Guillaume Chateletfb943542018-08-01 14:41:45 +0000126 Function(Scratch.ptr());
Clement Courbetac74acd2018-04-04 11:37:06 +0000127 Counter.stop();
128 const int64_t Value = Counter.read();
129 if (Value < MinLatency)
130 MinLatency = Value;
131 }
Clement Courbet3f20fee2018-04-04 12:01:38 +0000132 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +0000133}
134
135} // namespace exegesis