blob: 4a2632c7b5ceb09d08ca6c3cca3e236c14c5f921 [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"
11#include "BenchmarkResult.h"
12#include "InstructionSnippetGenerator.h"
13#include "PerfHelper.h"
14#include "llvm/MC/MCInstrDesc.h"
15#include "llvm/Support/Error.h"
16#include <algorithm>
17#include <random>
18
19namespace exegesis {
20
21// FIXME: Handle memory, see PR36905.
22static bool isInvalidOperand(const llvm::MCOperandInfo &OpInfo) {
23 switch (OpInfo.OperandType) {
24 default:
25 return true;
26 case llvm::MCOI::OPERAND_IMMEDIATE:
27 case llvm::MCOI::OPERAND_REGISTER:
28 return false;
29 }
30}
31
32static llvm::Error makeError(llvm::Twine Msg) {
33 return llvm::make_error<llvm::StringError>(Msg,
34 llvm::inconvertibleErrorCode());
35}
36
37LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
38
39const char *LatencyBenchmarkRunner::getDisplayName() const { return "latency"; }
40
41llvm::Expected<std::vector<llvm::MCInst>> LatencyBenchmarkRunner::createCode(
42 const LLVMState &State, const unsigned OpcodeIndex,
43 const unsigned NumRepetitions, const JitFunctionContext &Context) const {
44 std::default_random_engine RandomEngine;
45 const auto GetRandomIndex = [&RandomEngine](size_t Size) {
46 assert(Size > 0 && "trying to get select a random element of an empty set");
47 return std::uniform_int_distribution<>(0, Size - 1)(RandomEngine);
48 };
49
50 const auto &InstrInfo = State.getInstrInfo();
51 const auto &RegInfo = State.getRegInfo();
52 const llvm::MCInstrDesc &InstrDesc = InstrInfo.get(OpcodeIndex);
53 for (const llvm::MCOperandInfo &OpInfo : InstrDesc.operands()) {
54 if (isInvalidOperand(OpInfo))
55 return makeError("Only registers and immediates are supported");
56 }
57
58 const auto Vars = getVariables(RegInfo, InstrDesc, Context.getReservedRegs());
59 const std::vector<AssignmentChain> AssignmentChains =
60 computeSequentialAssignmentChains(RegInfo, Vars);
61 if (AssignmentChains.empty())
62 return makeError("Unable to find a dependency chain.");
63 const std::vector<llvm::MCPhysReg> Regs =
64 getRandomAssignment(Vars, AssignmentChains, GetRandomIndex);
65 const llvm::MCInst Inst = generateMCInst(InstrDesc, Vars, Regs);
66 if (!State.canAssemble(Inst))
67 return makeError("MCInst does not assemble.");
68 return std::vector<llvm::MCInst>(NumRepetitions, Inst);
69}
70
71std::vector<BenchmarkMeasure>
72LatencyBenchmarkRunner::runMeasurements(const LLVMState &State,
73 const JitFunction &Function,
74 const unsigned NumRepetitions) const {
75 // Cycle measurements include some overhead from the kernel. Repeat the
76 // measure several times and take the minimum value.
77 constexpr const int NumMeasurements = 30;
78 int64_t MinLatency = std::numeric_limits<int64_t>::max();
Clement Courbetb4493792018-04-10 08:16:37 +000079 const char *CounterName = State.getSubtargetInfo()
80 .getSchedModel()
81 .getExtraProcessorInfo()
82 .PfmCounters.CycleCounter;
83 if (!CounterName)
84 llvm::report_fatal_error("sched model does not define a cycle counter");
85 const pfm::PerfEvent CyclesPerfEvent(CounterName);
Clement Courbetac74acd2018-04-04 11:37:06 +000086 if (!CyclesPerfEvent.valid())
Clement Courbetb4493792018-04-10 08:16:37 +000087 llvm::report_fatal_error("invalid perf event");
Clement Courbetac74acd2018-04-04 11:37:06 +000088 for (size_t I = 0; I < NumMeasurements; ++I) {
89 pfm::Counter Counter(CyclesPerfEvent);
90 Counter.start();
91 Function();
92 Counter.stop();
93 const int64_t Value = Counter.read();
94 if (Value < MinLatency)
95 MinLatency = Value;
96 }
Clement Courbet3f20fee2018-04-04 12:01:38 +000097 return {{"latency", static_cast<double>(MinLatency) / NumRepetitions, ""}};
Clement Courbetac74acd2018-04-04 11:37:06 +000098}
99
100} // namespace exegesis