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 "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/Program.h"
25 BenchmarkFailure::BenchmarkFailure(const llvm::Twine
&S
)
26 : llvm::StringError(S
, llvm::inconvertibleErrorCode()) {}
28 BenchmarkRunner::BenchmarkRunner(const LLVMState
&State
,
29 InstructionBenchmark::ModeE Mode
)
30 : State(State
), Mode(Mode
), Scratch(llvm::make_unique
<ScratchSpace
>()) {}
32 BenchmarkRunner::~BenchmarkRunner() = default;
34 // Repeat the snippet until there are at least MinInstructions in the resulting
36 static std::vector
<llvm::MCInst
>
37 GenerateInstructions(const BenchmarkCode
&BC
, const size_t MinInstructions
) {
38 if (BC
.Instructions
.empty())
40 std::vector
<llvm::MCInst
> Code
= BC
.Instructions
;
41 for (int I
= 0; Code
.size() < MinInstructions
; ++I
)
42 Code
.push_back(BC
.Instructions
[I
% BC
.Instructions
.size()]);
47 BenchmarkRunner::runConfiguration(const BenchmarkCode
&BC
,
48 unsigned NumRepetitions
) const {
49 InstructionBenchmark InstrBenchmark
;
50 InstrBenchmark
.Mode
= Mode
;
51 InstrBenchmark
.CpuName
= State
.getTargetMachine().getTargetCPU();
52 InstrBenchmark
.LLVMTriple
=
53 State
.getTargetMachine().getTargetTriple().normalize();
54 InstrBenchmark
.NumRepetitions
= NumRepetitions
;
55 InstrBenchmark
.Info
= BC
.Info
;
57 const std::vector
<llvm::MCInst
> &Instructions
= BC
.Instructions
;
59 InstrBenchmark
.Key
.Instructions
= Instructions
;
60 InstrBenchmark
.Key
.RegisterInitialValues
= BC
.RegisterInitialValues
;
62 // Assemble at least kMinInstructionsForSnippet instructions by repeating the
63 // snippet for debug/analysis. This is so that the user clearly understands
64 // that the inside instructions are repeated.
65 constexpr const int kMinInstructionsForSnippet
= 16;
67 auto ObjectFilePath
= writeObjectFile(
68 BC
, GenerateInstructions(BC
, kMinInstructionsForSnippet
));
69 if (llvm::Error E
= ObjectFilePath
.takeError()) {
70 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
71 return InstrBenchmark
;
73 const ExecutableFunction
EF(State
.createTargetMachine(),
74 getObjectFromFile(*ObjectFilePath
));
75 const auto FnBytes
= EF
.getFunctionBytes();
76 InstrBenchmark
.AssembledSnippet
.assign(FnBytes
.begin(), FnBytes
.end());
79 // Assemble NumRepetitions instructions repetitions of the snippet for
81 auto ObjectFilePath
= writeObjectFile(
82 BC
, GenerateInstructions(BC
, InstrBenchmark
.NumRepetitions
));
83 if (llvm::Error E
= ObjectFilePath
.takeError()) {
84 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
85 return InstrBenchmark
;
87 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
88 << *ObjectFilePath
<< "\n";
89 const ExecutableFunction
EF(State
.createTargetMachine(),
90 getObjectFromFile(*ObjectFilePath
));
91 InstrBenchmark
.Measurements
= runMeasurements(EF
, *Scratch
);
92 assert(InstrBenchmark
.NumRepetitions
> 0 && "invalid NumRepetitions");
93 for (BenchmarkMeasure
&BM
: InstrBenchmark
.Measurements
) {
94 // Scale the measurements by instruction.
95 BM
.PerInstructionValue
/= InstrBenchmark
.NumRepetitions
;
96 // Scale the measurements by snippet.
97 BM
.PerSnippetValue
*= static_cast<double>(BC
.Instructions
.size()) /
98 InstrBenchmark
.NumRepetitions
;
101 return InstrBenchmark
;
104 llvm::Expected
<std::string
>
105 BenchmarkRunner::writeObjectFile(const BenchmarkCode
&BC
,
106 llvm::ArrayRef
<llvm::MCInst
> Code
) const {
108 llvm::SmallString
<256> ResultPath
;
109 if (llvm::Error E
= llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
110 "snippet", "o", ResultFD
, ResultPath
)))
112 llvm::raw_fd_ostream
OFS(ResultFD
, true /*ShouldClose*/);
113 assembleToStream(State
.getExegesisTarget(), State
.createTargetMachine(),
114 BC
.LiveIns
, BC
.RegisterInitialValues
, Code
, OFS
);
115 return ResultPath
.str();
118 } // namespace exegesis