[llvm-exegesis] Update to cover latency through another opcode.
Restructuring the code to measure latency and uops.
The end goal is to have this program spawn another process to deal with SIGILL and other malformed programs. It is not yet the case in this redesign, it is still the main program that runs the code (and may crash).
It now uses BitVector instead of Graph for performance reasons.
https://reviews.llvm.org/D46821
Authored by Guillaume Chatelet
llvm-svn: 332579
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index 2615a82..0e2052f 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -7,23 +7,33 @@
//
//===----------------------------------------------------------------------===//
+#include <array>
+#include <string>
+
+#include "Assembler.h"
#include "BenchmarkRunner.h"
-#include "InMemoryAssembler.h"
+#include "MCInstrDescView.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include <string>
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
namespace exegesis {
BenchmarkRunner::InstructionFilter::~InstructionFilter() = default;
-
+BenchmarkRunner::BenchmarkRunner(const LLVMState &State)
+ : State(State), MCInstrInfo(State.getInstrInfo()),
+ MCRegisterInfo(State.getRegInfo()),
+ RATC(MCRegisterInfo,
+ getFunctionReservedRegs(*State.createTargetMachine())) {}
BenchmarkRunner::~BenchmarkRunner() = default;
-InstructionBenchmark
-BenchmarkRunner::run(const LLVMState &State, const unsigned Opcode,
- unsigned NumRepetitions,
- const InstructionFilter &Filter) const {
+InstructionBenchmark BenchmarkRunner::run(unsigned Opcode,
+ const InstructionFilter &Filter,
+ unsigned NumRepetitions) {
InstructionBenchmark InstrBenchmark;
InstrBenchmark.Key.OpcodeName = State.getInstrInfo().getName(Opcode);
@@ -41,36 +51,56 @@
InstrBenchmark.Error = llvm::toString(std::move(E));
return InstrBenchmark;
}
+ llvm::raw_string_ostream InfoStream(InstrBenchmark.Info);
+ llvm::Expected<std::vector<llvm::MCInst>> SnippetOrError =
+ createSnippet(RATC, Opcode, InfoStream);
+ if (llvm::Error E = SnippetOrError.takeError()) {
+ InstrBenchmark.Error = llvm::toString(std::move(E));
+ return InstrBenchmark;
+ }
+ std::vector<llvm::MCInst> &Snippet = SnippetOrError.get();
+ if (Snippet.empty()) {
+ InstrBenchmark.Error = "Empty snippet";
+ return InstrBenchmark;
+ }
- JitFunctionContext Context(State.createTargetMachine());
- auto ExpectedInstructions =
- createCode(State, Opcode, NumRepetitions, Context);
- if (llvm::Error E = ExpectedInstructions.takeError()) {
+ InfoStream << "Snippet:\n";
+ for (const auto &MCInst : Snippet) {
+ DumpMCInst(MCRegisterInfo, MCInstrInfo, MCInst, InfoStream);
+ InfoStream << "\n";
+ }
+
+ std::vector<llvm::MCInst> Code;
+ for (int I = 0; I < InstrBenchmark.NumRepetitions; ++I)
+ Code.push_back(Snippet[I % Snippet.size()]);
+
+ auto ExpectedObjectPath = writeObjectFile(Code);
+ if (llvm::Error E = ExpectedObjectPath.takeError()) {
InstrBenchmark.Error = llvm::toString(std::move(E));
return InstrBenchmark;
}
- const std::vector<llvm::MCInst> Instructions = *ExpectedInstructions;
- const JitFunction Function(std::move(Context), Instructions);
- const llvm::StringRef CodeBytes = Function.getFunctionBytes();
+ // FIXME: Check if TargetMachine or ExecutionEngine can be reused instead of
+ // creating one everytime.
+ const ExecutableFunction EF(State.createTargetMachine(),
+ getObjectFromFile(*ExpectedObjectPath));
+ InstrBenchmark.Measurements = runMeasurements(EF, NumRepetitions);
- std::string AsmExcerpt;
- constexpr const int ExcerptSize = 100;
- constexpr const int ExcerptTailSize = 10;
- if (CodeBytes.size() <= ExcerptSize) {
- AsmExcerpt = llvm::toHex(CodeBytes);
- } else {
- AsmExcerpt =
- llvm::toHex(CodeBytes.take_front(ExcerptSize - ExcerptTailSize + 3));
- AsmExcerpt += "...";
- AsmExcerpt += llvm::toHex(CodeBytes.take_back(ExcerptTailSize));
- }
- llvm::outs() << "# Asm excerpt: " << AsmExcerpt << "\n";
- llvm::outs().flush(); // In case we crash.
-
- InstrBenchmark.Measurements =
- runMeasurements(State, Function, NumRepetitions);
return InstrBenchmark;
}
+llvm::Expected<std::string>
+BenchmarkRunner::writeObjectFile(llvm::ArrayRef<llvm::MCInst> Code) const {
+ int ResultFD = 0;
+ llvm::SmallString<256> ResultPath;
+ if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
+ "snippet", "o", ResultFD, ResultPath)))
+ return std::move(E);
+ llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
+ assembleToStream(State.createTargetMachine(), Code, OFS);
+ llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
+ << ResultPath << "\n";
+ return ResultPath.str();
+}
+
} // namespace exegesis