Re-land "[llvm-exegesis] Support analyzing results from a different target."

With Mips fixes.

This reverts commit 7daf60e344.
This commit is contained in:
Clement Courbet 2022-09-22 11:27:44 +02:00
parent b2cd8118d0
commit e52f8406e8
7 changed files with 164 additions and 110 deletions

View File

@ -102,6 +102,7 @@ template <typename EscapeTag, EscapeTag Tag>
void Analysis::writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes, void Analysis::writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes,
const char *Separator) const { const char *Separator) const {
SmallVector<std::string, 3> Lines; SmallVector<std::string, 3> Lines;
const auto &SI = State_.getSubtargetInfo();
// Parse the asm snippet and print it. // Parse the asm snippet and print it.
while (!Bytes.empty()) { while (!Bytes.empty()) {
MCInst MI; MCInst MI;
@ -114,7 +115,7 @@ void Analysis::writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes,
} }
SmallString<128> InstPrinterStr; // FIXME: magic number. SmallString<128> InstPrinterStr; // FIXME: magic number.
raw_svector_ostream OSS(InstPrinterStr); raw_svector_ostream OSS(InstPrinterStr);
InstPrinter_->printInst(&MI, 0, "", *SubtargetInfo_, OSS); InstPrinter_->printInst(&MI, 0, "", SI, OSS);
Bytes = Bytes.drop_front(MISize); Bytes = Bytes.drop_front(MISize);
Lines.emplace_back(InstPrinterStr.str().trim()); Lines.emplace_back(InstPrinterStr.str().trim());
} }
@ -136,10 +137,10 @@ void Analysis::printInstructionRowCsv(const size_t PointId,
const MCInst &MCI = Point.keyInstruction(); const MCInst &MCI = Point.keyInstruction();
unsigned SchedClassId; unsigned SchedClassId;
std::tie(SchedClassId, std::ignore) = ResolvedSchedClass::resolveSchedClassId( std::tie(SchedClassId, std::ignore) = ResolvedSchedClass::resolveSchedClassId(
*SubtargetInfo_, *InstrInfo_, MCI); State_.getSubtargetInfo(), State_.getInstrInfo(), MCI);
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
const MCSchedClassDesc *const SCDesc = const MCSchedClassDesc *const SCDesc =
SubtargetInfo_->getSchedModel().getSchedClassDesc(SchedClassId); State_.getSubtargetInfo().getSchedModel().getSchedClassDesc(SchedClassId);
writeEscaped<kEscapeCsv>(OS, SCDesc->Name); writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
#else #else
OS << SchedClassId; OS << SchedClassId;
@ -151,38 +152,30 @@ void Analysis::printInstructionRowCsv(const size_t PointId,
OS << "\n"; OS << "\n";
} }
Analysis::Analysis(const Target &Target, Analysis::Analysis(const LLVMState &State,
std::unique_ptr<MCSubtargetInfo> SubtargetInfo,
std::unique_ptr<MCInstrInfo> InstrInfo,
const InstructionBenchmarkClustering &Clustering, const InstructionBenchmarkClustering &Clustering,
double AnalysisInconsistencyEpsilon, double AnalysisInconsistencyEpsilon,
bool AnalysisDisplayUnstableOpcodes, bool AnalysisDisplayUnstableOpcodes)
const std::string &ForceCpuName) : Clustering_(Clustering), State_(State),
: Clustering_(Clustering), SubtargetInfo_(std::move(SubtargetInfo)),
InstrInfo_(std::move(InstrInfo)),
AnalysisInconsistencyEpsilonSquared_(AnalysisInconsistencyEpsilon * AnalysisInconsistencyEpsilonSquared_(AnalysisInconsistencyEpsilon *
AnalysisInconsistencyEpsilon), AnalysisInconsistencyEpsilon),
AnalysisDisplayUnstableOpcodes_(AnalysisDisplayUnstableOpcodes) { AnalysisDisplayUnstableOpcodes_(AnalysisDisplayUnstableOpcodes) {
if (Clustering.getPoints().empty()) if (Clustering.getPoints().empty())
return; return;
const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
const std::string CpuName =
ForceCpuName.empty() ? FirstPoint.CpuName : ForceCpuName;
RegInfo_.reset(Target.createMCRegInfo(FirstPoint.LLVMTriple));
MCTargetOptions MCOptions; MCTargetOptions MCOptions;
AsmInfo_.reset( const auto &TM = State.getTargetMachine();
Target.createMCAsmInfo(*RegInfo_, FirstPoint.LLVMTriple, MCOptions)); const auto &Triple = TM.getTargetTriple();
SubtargetInfo_.reset( AsmInfo_.reset(TM.getTarget().createMCAsmInfo(State_.getRegInfo(),
Target.createMCSubtargetInfo(FirstPoint.LLVMTriple, CpuName, "")); Triple.str(), MCOptions));
InstPrinter_.reset(Target.createMCInstPrinter( InstPrinter_.reset(TM.getTarget().createMCInstPrinter(
Triple(FirstPoint.LLVMTriple), 0 /*default variant*/, *AsmInfo_, Triple, 0 /*default variant*/, *AsmInfo_, State_.getInstrInfo(),
*InstrInfo_, *RegInfo_)); State_.getRegInfo()));
Context_ = Context_ = std::make_unique<MCContext>(
std::make_unique<MCContext>(Triple(FirstPoint.LLVMTriple), AsmInfo_.get(), Triple, AsmInfo_.get(), &State_.getRegInfo(), &State_.getSubtargetInfo());
RegInfo_.get(), SubtargetInfo_.get()); Disasm_.reset(TM.getTarget().createMCDisassembler(State_.getSubtargetInfo(),
Disasm_.reset(Target.createMCDisassembler(*SubtargetInfo_, *Context_)); *Context_));
assert(Disasm_ && "cannot create MCDisassembler. missing call to " assert(Disasm_ && "cannot create MCDisassembler. missing call to "
"InitializeXXXTargetDisassembler ?"); "InitializeXXXTargetDisassembler ?");
} }
@ -232,14 +225,14 @@ Analysis::makePointsPerSchedClass() const {
unsigned SchedClassId; unsigned SchedClassId;
bool WasVariant; bool WasVariant;
std::tie(SchedClassId, WasVariant) = std::tie(SchedClassId, WasVariant) =
ResolvedSchedClass::resolveSchedClassId(*SubtargetInfo_, *InstrInfo_, ResolvedSchedClass::resolveSchedClassId(State_.getSubtargetInfo(),
MCI); State_.getInstrInfo(), MCI);
const auto IndexIt = SchedClassIdToIndex.find(SchedClassId); const auto IndexIt = SchedClassIdToIndex.find(SchedClassId);
if (IndexIt == SchedClassIdToIndex.end()) { if (IndexIt == SchedClassIdToIndex.end()) {
// Create a new entry. // Create a new entry.
SchedClassIdToIndex.emplace(SchedClassId, Entries.size()); SchedClassIdToIndex.emplace(SchedClassId, Entries.size());
ResolvedSchedClassAndPoints Entry( ResolvedSchedClassAndPoints Entry(ResolvedSchedClass(
ResolvedSchedClass(*SubtargetInfo_, SchedClassId, WasVariant)); State_.getSubtargetInfo(), SchedClassId, WasVariant));
Entry.PointIds.push_back(PointId); Entry.PointIds.push_back(PointId);
Entries.push_back(std::move(Entry)); Entries.push_back(std::move(Entry));
} else { } else {
@ -284,11 +277,11 @@ void Analysis::printPointHtml(const InstructionBenchmark &Point,
OS << "\">"; OS << "\">";
switch (Point.Mode) { switch (Point.Mode) {
case InstructionBenchmark::Latency: case InstructionBenchmark::Latency:
writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); writeLatencySnippetHtml(OS, Point.Key.Instructions, State_.getInstrInfo());
break; break;
case InstructionBenchmark::Uops: case InstructionBenchmark::Uops:
case InstructionBenchmark::InverseThroughput: case InstructionBenchmark::InverseThroughput:
writeParallelSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); writeParallelSnippetHtml(OS, Point.Key.Instructions, State_.getInstrInfo());
break; break;
default: default:
llvm_unreachable("invalid mode"); llvm_unreachable("invalid mode");
@ -314,7 +307,8 @@ void Analysis::printSchedClassClustersHtml(
OS << "</tr>"; OS << "</tr>";
for (const SchedClassCluster &Cluster : Clusters) { for (const SchedClassCluster &Cluster : Clusters) {
OS << "<tr class=\"" OS << "<tr class=\""
<< (Cluster.measurementsMatch(*SubtargetInfo_, RSC, Clustering_, << (Cluster.measurementsMatch(State_.getSubtargetInfo(), RSC,
Clustering_,
AnalysisInconsistencyEpsilonSquared_) AnalysisInconsistencyEpsilonSquared_)
? "good-cluster" ? "good-cluster"
: "bad-cluster") : "bad-cluster")
@ -383,15 +377,15 @@ void Analysis::printSchedClassDescHtml(const ResolvedSchedClass &RSC,
"idealized unit resource (port) pressure assuming ideal " "idealized unit resource (port) pressure assuming ideal "
"distribution\">Idealized Resource Pressure</th></tr>"; "distribution\">Idealized Resource Pressure</th></tr>";
if (RSC.SCDesc->isValid()) { if (RSC.SCDesc->isValid()) {
const auto &SM = SubtargetInfo_->getSchedModel(); const auto &SI = State_.getSubtargetInfo();
const auto &SM = SI.getSchedModel();
OS << "<tr><td>&#10004;</td>"; OS << "<tr><td>&#10004;</td>";
OS << "<td>" << (RSC.WasVariant ? "&#10004;" : "&#10005;") << "</td>"; OS << "<td>" << (RSC.WasVariant ? "&#10004;" : "&#10005;") << "</td>";
OS << "<td>" << RSC.SCDesc->NumMicroOps << "</td>"; OS << "<td>" << RSC.SCDesc->NumMicroOps << "</td>";
// Latencies. // Latencies.
OS << "<td><ul>"; OS << "<td><ul>";
for (int I = 0, E = RSC.SCDesc->NumWriteLatencyEntries; I < E; ++I) { for (int I = 0, E = RSC.SCDesc->NumWriteLatencyEntries; I < E; ++I) {
const auto *const Entry = const auto *const Entry = SI.getWriteLatencyEntry(RSC.SCDesc, I);
SubtargetInfo_->getWriteLatencyEntry(RSC.SCDesc, I);
OS << "<li>" << Entry->Cycles; OS << "<li>" << Entry->Cycles;
if (RSC.SCDesc->NumWriteLatencyEntries > 1) { if (RSC.SCDesc->NumWriteLatencyEntries > 1) {
// Dismabiguate if more than 1 latency. // Dismabiguate if more than 1 latency.
@ -403,8 +397,7 @@ void Analysis::printSchedClassDescHtml(const ResolvedSchedClass &RSC,
// inverse throughput. // inverse throughput.
OS << "<td>"; OS << "<td>";
writeMeasurementValue<kEscapeHtml>( writeMeasurementValue<kEscapeHtml>(
OS, OS, MCSchedModel::getReciprocalThroughput(SI, *RSC.SCDesc));
MCSchedModel::getReciprocalThroughput(*SubtargetInfo_, *RSC.SCDesc));
OS << "</td>"; OS << "</td>";
// WriteProcRes. // WriteProcRes.
OS << "<td><ul>"; OS << "<td><ul>";
@ -419,9 +412,8 @@ void Analysis::printSchedClassDescHtml(const ResolvedSchedClass &RSC,
OS << "<td><ul>"; OS << "<td><ul>";
for (const auto &Pressure : RSC.IdealizedProcResPressure) { for (const auto &Pressure : RSC.IdealizedProcResPressure) {
OS << "<li><span class=\"mono\">"; OS << "<li><span class=\"mono\">";
writeEscaped<kEscapeHtml>(OS, SubtargetInfo_->getSchedModel() writeEscaped<kEscapeHtml>(
.getProcResource(Pressure.first) OS, SI.getSchedModel().getProcResource(Pressure.first)->Name);
->Name);
OS << "</span>: "; OS << "</span>: ";
writeMeasurementValue<kEscapeHtml>(OS, Pressure.second); writeMeasurementValue<kEscapeHtml>(OS, Pressure.second);
OS << "</li>"; OS << "</li>";
@ -550,6 +542,7 @@ Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
writeEscaped<kEscapeHtml>(OS, FirstPoint.CpuName); writeEscaped<kEscapeHtml>(OS, FirstPoint.CpuName);
OS << "</span></h3>"; OS << "</span></h3>";
const auto &SI = State_.getSubtargetInfo();
for (const auto &RSCAndPoints : makePointsPerSchedClass()) { for (const auto &RSCAndPoints : makePointsPerSchedClass()) {
if (!RSCAndPoints.RSC.SCDesc) if (!RSCAndPoints.RSC.SCDesc)
continue; continue;
@ -574,10 +567,9 @@ Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
// Print any scheduling class that has at least one cluster that does not // Print any scheduling class that has at least one cluster that does not
// match the checked-in data. // match the checked-in data.
if (all_of(SchedClassClusters, [this, if (all_of(SchedClassClusters, [this, &RSCAndPoints,
&RSCAndPoints](const SchedClassCluster &C) { &SI](const SchedClassCluster &C) {
return C.measurementsMatch(*SubtargetInfo_, RSCAndPoints.RSC, return C.measurementsMatch(SI, RSCAndPoints.RSC, Clustering_,
Clustering_,
AnalysisInconsistencyEpsilonSquared_); AnalysisInconsistencyEpsilonSquared_);
})) }))
continue; // Nothing weird. continue; // Nothing weird.

View File

@ -36,12 +36,10 @@ namespace exegesis {
// A helper class to analyze benchmark results for a target. // A helper class to analyze benchmark results for a target.
class Analysis { class Analysis {
public: public:
Analysis(const Target &Target, std::unique_ptr<MCSubtargetInfo> SubtargetInfo, Analysis(const LLVMState &State,
std::unique_ptr<MCInstrInfo> InstrInfo,
const InstructionBenchmarkClustering &Clustering, const InstructionBenchmarkClustering &Clustering,
double AnalysisInconsistencyEpsilon, double AnalysisInconsistencyEpsilon,
bool AnalysisDisplayUnstableOpcodes, bool AnalysisDisplayUnstableOpcodes);
const std::string &ForceCpuName = "");
// Prints a csv of instructions for each cluster. // Prints a csv of instructions for each cluster.
struct PrintClusters {}; struct PrintClusters {};
@ -113,10 +111,8 @@ private:
const char *Separator) const; const char *Separator) const;
const InstructionBenchmarkClustering &Clustering_; const InstructionBenchmarkClustering &Clustering_;
const LLVMState &State_;
std::unique_ptr<MCContext> Context_; std::unique_ptr<MCContext> Context_;
std::unique_ptr<MCSubtargetInfo> SubtargetInfo_;
std::unique_ptr<MCInstrInfo> InstrInfo_;
std::unique_ptr<MCRegisterInfo> RegInfo_;
std::unique_ptr<MCAsmInfo> AsmInfo_; std::unique_ptr<MCAsmInfo> AsmInfo_;
std::unique_ptr<MCInstPrinter> InstPrinter_; std::unique_ptr<MCInstPrinter> InstPrinter_;
std::unique_ptr<MCDisassembler> Disasm_; std::unique_ptr<MCDisassembler> Disasm_;

View File

@ -327,47 +327,69 @@ struct MappingContextTraits<exegesis::InstructionBenchmark, YamlContext> {
} }
}; };
template <> struct MappingTraits<exegesis::InstructionBenchmark::TripleAndCpu> {
static void mapping(IO &Io,
exegesis::InstructionBenchmark::TripleAndCpu &Obj) {
assert(!Io.outputting() && "can only read TripleAndCpu");
// Read triple.
Io.mapRequired("llvm_triple", Obj.LLVMTriple);
Io.mapRequired("cpu_name", Obj.CpuName);
// Drop everything else.
}
};
} // namespace yaml } // namespace yaml
namespace exegesis { namespace exegesis {
Expected<InstructionBenchmark> Expected<std::set<InstructionBenchmark::TripleAndCpu>>
InstructionBenchmark::readYaml(const LLVMState &State, StringRef Filename) { InstructionBenchmark::readTriplesAndCpusFromYamls(MemoryBufferRef Buffer) {
if (auto ExpectedMemoryBuffer = // We're only mapping a field, drop other fields and silence the corresponding
errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) { // warnings.
yaml::Input Yin(*ExpectedMemoryBuffer.get()); yaml::Input Yin(
YamlContext Context(State); Buffer, nullptr, +[](const SMDiagnostic &, void *Context) {});
InstructionBenchmark Benchmark; Yin.setAllowUnknownKeys(true);
if (Yin.setCurrentDocument()) std::set<TripleAndCpu> Result;
yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context); yaml::EmptyContext Context;
if (!Context.getLastError().empty()) while (Yin.setCurrentDocument()) {
return make_error<Failure>(Context.getLastError()); TripleAndCpu TC;
return Benchmark; yamlize(Yin, TC, /*unused*/ true, Context);
} else { if (Yin.error())
return ExpectedMemoryBuffer.takeError(); return errorCodeToError(Yin.error());
Result.insert(TC);
Yin.nextDocument();
} }
return Result;
}
Expected<InstructionBenchmark>
InstructionBenchmark::readYaml(const LLVMState &State, MemoryBufferRef Buffer) {
yaml::Input Yin(Buffer);
YamlContext Context(State);
InstructionBenchmark Benchmark;
if (Yin.setCurrentDocument())
yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
if (!Context.getLastError().empty())
return make_error<Failure>(Context.getLastError());
return Benchmark;
} }
Expected<std::vector<InstructionBenchmark>> Expected<std::vector<InstructionBenchmark>>
InstructionBenchmark::readYamls(const LLVMState &State, StringRef Filename) { InstructionBenchmark::readYamls(const LLVMState &State,
if (auto ExpectedMemoryBuffer = MemoryBufferRef Buffer) {
errorOrToExpected(MemoryBuffer::getFile(Filename, /*IsText=*/true))) { yaml::Input Yin(Buffer);
yaml::Input Yin(*ExpectedMemoryBuffer.get()); YamlContext Context(State);
YamlContext Context(State); std::vector<InstructionBenchmark> Benchmarks;
std::vector<InstructionBenchmark> Benchmarks; while (Yin.setCurrentDocument()) {
while (Yin.setCurrentDocument()) { Benchmarks.emplace_back();
Benchmarks.emplace_back(); yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context); if (Yin.error())
if (Yin.error()) return errorCodeToError(Yin.error());
return errorCodeToError(Yin.error()); if (!Context.getLastError().empty())
if (!Context.getLastError().empty()) return make_error<Failure>(Context.getLastError());
return make_error<Failure>(Context.getLastError()); Yin.nextDocument();
Yin.nextDocument();
}
return Benchmarks;
} else {
return ExpectedMemoryBuffer.takeError();
} }
return Benchmarks;
} }
Error InstructionBenchmark::writeYamlTo(const LLVMState &State, Error InstructionBenchmark::writeYamlTo(const LLVMState &State,

View File

@ -19,10 +19,12 @@
#include "RegisterValue.h" #include "RegisterValue.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/MC/MCInst.h" #include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCInstBuilder.h"
#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/YAMLTraits.h"
#include <limits> #include <limits>
#include <set>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -78,10 +80,22 @@ struct InstructionBenchmark {
enum ResultAggregationModeE { Min, Max, Mean, MinVariance }; enum ResultAggregationModeE { Min, Max, Mean, MinVariance };
// Read functions. // Read functions.
static Expected<InstructionBenchmark> readYaml(const LLVMState &State, static Expected<InstructionBenchmark> readYaml(const LLVMState &State,
StringRef Filename); MemoryBufferRef Buffer);
static Expected<std::vector<InstructionBenchmark>> static Expected<std::vector<InstructionBenchmark>>
readYamls(const LLVMState &State, StringRef Filename); readYamls(const LLVMState &State, MemoryBufferRef Buffer);
// Given a set of serialized instruction benchmarks, returns the set of
// triples and CPUs that appear in the list of benchmarks.
struct TripleAndCpu {
std::string LLVMTriple;
std::string CpuName;
bool operator<(const TripleAndCpu &O) const {
return std::tie(LLVMTriple, CpuName) < std::tie(O.LLVMTriple, O.CpuName);
}
};
static Expected<std::set<TripleAndCpu>>
readTriplesAndCpusFromYamls(MemoryBufferRef Buffer);
class Error readYamlFrom(const LLVMState &State, StringRef InputContent); class Error readYamlFrom(const LLVMState &State, StringRef InputContent);

View File

@ -416,40 +416,50 @@ static void analysisMain() {
InitializeNativeTargetDisassembler(); InitializeNativeTargetDisassembler();
InitializeNativeExegesisTarget(); InitializeNativeExegesisTarget();
auto MemoryBuffer = ExitOnFileError(
BenchmarkFile,
errorOrToExpected(MemoryBuffer::getFile(BenchmarkFile, /*IsText=*/true)));
const auto TriplesAndCpus = ExitOnFileError(
BenchmarkFile,
InstructionBenchmark::readTriplesAndCpusFromYamls(*MemoryBuffer));
if (TriplesAndCpus.empty()) {
errs() << "no benchmarks to analyze\n";
return;
}
if (TriplesAndCpus.size() > 1) {
ExitWithError("analysis file contains benchmarks from several CPUs. This "
"is unsupported.");
}
auto TripleAndCpu = *TriplesAndCpus.begin();
if (!CpuName.empty()) {
llvm::errs() << "overridding file CPU name (" << TripleAndCpu.CpuName
<< ") with provided CPU name (" << CpuName << ")\n";
TripleAndCpu.CpuName = CpuName;
}
llvm::errs() << "using Triple '" << TripleAndCpu.LLVMTriple << "' and CPU '"
<< TripleAndCpu.CpuName << "'\n";
// Read benchmarks. // Read benchmarks.
const LLVMState State = ExitOnErr(LLVMState::Create("", "")); const LLVMState State = ExitOnErr(
LLVMState::Create(TripleAndCpu.LLVMTriple, TripleAndCpu.CpuName));
const std::vector<InstructionBenchmark> Points = ExitOnFileError( const std::vector<InstructionBenchmark> Points = ExitOnFileError(
BenchmarkFile, InstructionBenchmark::readYamls(State, BenchmarkFile)); BenchmarkFile, InstructionBenchmark::readYamls(State, *MemoryBuffer));
outs() << "Parsed " << Points.size() << " benchmark points\n"; outs() << "Parsed " << Points.size() << " benchmark points\n";
if (Points.empty()) { if (Points.empty()) {
errs() << "no benchmarks to analyze\n"; errs() << "no benchmarks to analyze\n";
return; return;
} }
// FIXME: Check that all points have the same triple/cpu.
// FIXME: Merge points from several runs (latency and uops). // FIXME: Merge points from several runs (latency and uops).
std::string Error;
const auto *TheTarget =
TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
if (!TheTarget) {
errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
return;
}
std::unique_ptr<MCSubtargetInfo> SubtargetInfo(
TheTarget->createMCSubtargetInfo(Points[0].LLVMTriple, CpuName, ""));
std::unique_ptr<MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
assert(InstrInfo && "Unable to create instruction info!");
const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create( const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create(
Points, AnalysisClusteringAlgorithm, AnalysisDbscanNumPoints, Points, AnalysisClusteringAlgorithm, AnalysisDbscanNumPoints,
AnalysisClusteringEpsilon, SubtargetInfo.get(), InstrInfo.get())); AnalysisClusteringEpsilon, &State.getSubtargetInfo(),
&State.getInstrInfo()));
const Analysis Analyzer( const Analysis Analyzer(State, Clustering, AnalysisInconsistencyEpsilon,
*TheTarget, std::move(SubtargetInfo), std::move(InstrInfo), Clustering, AnalysisDisplayUnstableOpcodes);
AnalysisInconsistencyEpsilon, AnalysisDisplayUnstableOpcodes, CpuName);
maybeRunAnalysis<Analysis::PrintClusters>(Analyzer, "analysis clusters", maybeRunAnalysis<Analysis::PrintClusters>(Analyzer, "analysis clusters",
AnalysisClustersOutputFile); AnalysisClustersOutputFile);

View File

@ -80,10 +80,13 @@ TEST_F(MipsBenchmarkResultTest, WriteToAndReadFromDisk) {
errs() << Filename << "-------\n"; errs() << Filename << "-------\n";
ExitOnErr(ToDisk.writeYaml(State, Filename)); ExitOnErr(ToDisk.writeYaml(State, Filename));
const std::unique_ptr<MemoryBuffer> Buffer =
std::move(*MemoryBuffer::getFile(Filename));
{ {
// One-element version. // One-element version.
const auto FromDisk = const auto FromDisk =
ExitOnErr(InstructionBenchmark::readYaml(State, Filename)); ExitOnErr(InstructionBenchmark::readYaml(State, *Buffer));
EXPECT_THAT(FromDisk.Key.Instructions, EXPECT_THAT(FromDisk.Key.Instructions,
Pointwise(EqMCInst(), ToDisk.Key.Instructions)); Pointwise(EqMCInst(), ToDisk.Key.Instructions));
@ -99,7 +102,7 @@ TEST_F(MipsBenchmarkResultTest, WriteToAndReadFromDisk) {
{ {
// Vector version. // Vector version.
const auto FromDiskVector = const auto FromDiskVector =
ExitOnErr(InstructionBenchmark::readYamls(State, Filename)); ExitOnErr(InstructionBenchmark::readYamls(State, *Buffer));
ASSERT_EQ(FromDiskVector.size(), size_t{1}); ASSERT_EQ(FromDiskVector.size(), size_t{1});
const auto FromDisk = FromDiskVector[0]; const auto FromDisk = FromDiskVector[0];
EXPECT_THAT(FromDisk.Key.Instructions, EXPECT_THAT(FromDisk.Key.Instructions,

View File

@ -20,7 +20,9 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
using ::testing::AllOf; using ::testing::AllOf;
using ::testing::ElementsAre;
using ::testing::Eq; using ::testing::Eq;
using ::testing::Field;
using ::testing::get; using ::testing::get;
using ::testing::Pointwise; using ::testing::Pointwise;
using ::testing::Property; using ::testing::Property;
@ -89,10 +91,25 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
errs() << Filename << "-------\n"; errs() << Filename << "-------\n";
ExitOnErr(ToDisk.writeYaml(State, Filename)); ExitOnErr(ToDisk.writeYaml(State, Filename));
const std::unique_ptr<MemoryBuffer> Buffer =
std::move(*MemoryBuffer::getFile(Filename));
{
// Read Triples/Cpu only.
const auto TriplesAndCpus =
ExitOnErr(InstructionBenchmark::readTriplesAndCpusFromYamls(*Buffer));
ASSERT_THAT(TriplesAndCpus,
testing::ElementsAre(
AllOf(Field(&InstructionBenchmark::TripleAndCpu::LLVMTriple,
Eq("llvm_triple")),
Field(&InstructionBenchmark::TripleAndCpu::CpuName,
Eq("cpu_name")))));
}
{ {
// One-element version. // One-element version.
const auto FromDisk = const auto FromDisk =
ExitOnErr(InstructionBenchmark::readYaml(State, Filename)); ExitOnErr(InstructionBenchmark::readYaml(State, *Buffer));
EXPECT_THAT(FromDisk.Key.Instructions, EXPECT_THAT(FromDisk.Key.Instructions,
Pointwise(EqMCInst(), ToDisk.Key.Instructions)); Pointwise(EqMCInst(), ToDisk.Key.Instructions));
@ -108,7 +125,7 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
{ {
// Vector version. // Vector version.
const auto FromDiskVector = const auto FromDiskVector =
ExitOnErr(InstructionBenchmark::readYamls(State, Filename)); ExitOnErr(InstructionBenchmark::readYamls(State, *Buffer));
ASSERT_EQ(FromDiskVector.size(), size_t{1}); ASSERT_EQ(FromDiskVector.size(), size_t{1});
const auto FromDisk = FromDiskVector[0]; const auto FromDisk = FromDiskVector[0];
EXPECT_THAT(FromDisk.Key.Instructions, EXPECT_THAT(FromDisk.Key.Instructions,