1 //===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
13 #include "Assembler.h"
14 #include "BenchmarkRunner.h"
15 #include "MCInstrDescView.h"
16 #include "PerfHelper.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Support/CrashRecoveryContext.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Program.h"
28 BenchmarkFailure::BenchmarkFailure(const llvm::Twine
&S
)
29 : llvm::StringError(S
, llvm::inconvertibleErrorCode()) {}
31 BenchmarkRunner::BenchmarkRunner(const LLVMState
&State
,
32 InstructionBenchmark::ModeE Mode
)
33 : State(State
), Mode(Mode
), Scratch(llvm::make_unique
<ScratchSpace
>()) {}
35 BenchmarkRunner::~BenchmarkRunner() = default;
37 // Repeat the snippet until there are at least MinInstructions in the resulting
39 static std::vector
<llvm::MCInst
>
40 GenerateInstructions(const BenchmarkCode
&BC
, const size_t MinInstructions
) {
41 if (BC
.Instructions
.empty())
43 std::vector
<llvm::MCInst
> Code
= BC
.Instructions
;
44 for (int I
= 0; Code
.size() < MinInstructions
; ++I
)
45 Code
.push_back(BC
.Instructions
[I
% BC
.Instructions
.size()]);
50 class FunctionExecutorImpl
: public BenchmarkRunner::FunctionExecutor
{
52 FunctionExecutorImpl(const LLVMState
&State
,
53 llvm::object::OwningBinary
<llvm::object::ObjectFile
> Obj
,
54 BenchmarkRunner::ScratchSpace
*Scratch
)
55 : Function(State
.createTargetMachine(), std::move(Obj
)),
59 llvm::Expected
<int64_t> runAndMeasure(const char *Counters
) const override
{
60 // We sum counts when there are several counters for a single ProcRes
61 // (e.g. P23 on SandyBridge).
62 int64_t CounterValue
= 0;
63 llvm::SmallVector
<llvm::StringRef
, 2> CounterNames
;
64 llvm::StringRef(Counters
).split(CounterNames
, ',');
65 char *const ScratchPtr
= Scratch
->ptr();
66 for (const auto &CounterName
: CounterNames
) {
67 pfm::PerfEvent
PerfEvent(CounterName
);
68 if (!PerfEvent
.valid())
69 llvm::report_fatal_error(
70 llvm::Twine("invalid perf event ").concat(Counters
));
71 pfm::Counter
Counter(PerfEvent
);
74 llvm::CrashRecoveryContext CRC
;
75 llvm::CrashRecoveryContext::Enable();
76 const bool Crashed
= !CRC
.RunSafely([this, &Counter
, ScratchPtr
]() {
78 this->Function(ScratchPtr
);
81 llvm::CrashRecoveryContext::Disable();
82 // FIXME: Better diagnosis.
84 return llvm::make_error
<BenchmarkFailure
>(
85 "snippet crashed while running");
87 CounterValue
+= Counter
.read();
92 const ExecutableFunction Function
;
93 BenchmarkRunner::ScratchSpace
*const Scratch
;
98 BenchmarkRunner::runConfiguration(const BenchmarkCode
&BC
,
99 unsigned NumRepetitions
) const {
100 InstructionBenchmark InstrBenchmark
;
101 InstrBenchmark
.Mode
= Mode
;
102 InstrBenchmark
.CpuName
= State
.getTargetMachine().getTargetCPU();
103 InstrBenchmark
.LLVMTriple
=
104 State
.getTargetMachine().getTargetTriple().normalize();
105 InstrBenchmark
.NumRepetitions
= NumRepetitions
;
106 InstrBenchmark
.Info
= BC
.Info
;
108 const std::vector
<llvm::MCInst
> &Instructions
= BC
.Instructions
;
110 InstrBenchmark
.Key
.Instructions
= Instructions
;
111 InstrBenchmark
.Key
.RegisterInitialValues
= BC
.RegisterInitialValues
;
113 // Assemble at least kMinInstructionsForSnippet instructions by repeating the
114 // snippet for debug/analysis. This is so that the user clearly understands
115 // that the inside instructions are repeated.
116 constexpr const int kMinInstructionsForSnippet
= 16;
118 auto ObjectFilePath
= writeObjectFile(
119 BC
, GenerateInstructions(BC
, kMinInstructionsForSnippet
));
120 if (llvm::Error E
= ObjectFilePath
.takeError()) {
121 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
122 return InstrBenchmark
;
124 const ExecutableFunction
EF(State
.createTargetMachine(),
125 getObjectFromFile(*ObjectFilePath
));
126 const auto FnBytes
= EF
.getFunctionBytes();
127 InstrBenchmark
.AssembledSnippet
.assign(FnBytes
.begin(), FnBytes
.end());
130 // Assemble NumRepetitions instructions repetitions of the snippet for
132 auto ObjectFilePath
= writeObjectFile(
133 BC
, GenerateInstructions(BC
, InstrBenchmark
.NumRepetitions
));
134 if (llvm::Error E
= ObjectFilePath
.takeError()) {
135 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
136 return InstrBenchmark
;
138 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
139 << *ObjectFilePath
<< "\n";
140 const FunctionExecutorImpl
Executor(State
, getObjectFromFile(*ObjectFilePath
),
142 auto Measurements
= runMeasurements(Executor
);
143 if (llvm::Error E
= Measurements
.takeError()) {
144 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
145 return InstrBenchmark
;
147 InstrBenchmark
.Measurements
= std::move(*Measurements
);
148 assert(InstrBenchmark
.NumRepetitions
> 0 && "invalid NumRepetitions");
149 for (BenchmarkMeasure
&BM
: InstrBenchmark
.Measurements
) {
150 // Scale the measurements by instruction.
151 BM
.PerInstructionValue
/= InstrBenchmark
.NumRepetitions
;
152 // Scale the measurements by snippet.
153 BM
.PerSnippetValue
*= static_cast<double>(BC
.Instructions
.size()) /
154 InstrBenchmark
.NumRepetitions
;
157 return InstrBenchmark
;
160 llvm::Expected
<std::string
>
161 BenchmarkRunner::writeObjectFile(const BenchmarkCode
&BC
,
162 llvm::ArrayRef
<llvm::MCInst
> Code
) const {
164 llvm::SmallString
<256> ResultPath
;
165 if (llvm::Error E
= llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
166 "snippet", "o", ResultFD
, ResultPath
)))
168 llvm::raw_fd_ostream
OFS(ResultFD
, true /*ShouldClose*/);
169 assembleToStream(State
.getExegesisTarget(), State
.createTargetMachine(),
170 BC
.LiveIns
, BC
.RegisterInitialValues
, Code
, OFS
);
171 return ResultPath
.str();
174 BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
176 } // namespace exegesis