OSDN Git Service

Re-land r329156 "Add llvm-exegesis tool."
[android-x86/external-llvm.git] / tools / llvm-exegesis / lib / Latency.cpp
1 //===-- 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
19 namespace exegesis {
20
21 // FIXME: Handle memory, see PR36905.
22 static 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
32 static llvm::Error makeError(llvm::Twine Msg) {
33   return llvm::make_error<llvm::StringError>(Msg,
34                                              llvm::inconvertibleErrorCode());
35 }
36
37 LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
38
39 const char *LatencyBenchmarkRunner::getDisplayName() const { return "latency"; }
40
41 llvm::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
71 std::vector<BenchmarkMeasure>
72 LatencyBenchmarkRunner::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();
79   // FIXME: Read the perf event from the MCSchedModel (see PR36984).
80   const pfm::PerfEvent CyclesPerfEvent("UNHALTED_CORE_CYCLES");
81   if (!CyclesPerfEvent.valid())
82     llvm::report_fatal_error("invalid perf event 'UNHALTED_CORE_CYCLES'");
83   for (size_t I = 0; I < NumMeasurements; ++I) {
84     pfm::Counter Counter(CyclesPerfEvent);
85     Counter.start();
86     Function();
87     Counter.stop();
88     const int64_t Value = Counter.read();
89     if (Value < MinLatency)
90       MinLatency = Value;
91   }
92   return {{"latency", static_cast<double>(MinLatency) / NumRepetitions}};
93 }
94
95 } // namespace exegesis