Re-land "[llvm-exegesis] Support analyzing results from a different target."
With Mips fixes.
This reverts commit 7daf60e344
.
This commit is contained in:
parent
b2cd8118d0
commit
e52f8406e8
|
@ -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>✔</td>";
|
OS << "<tr><td>✔</td>";
|
||||||
OS << "<td>" << (RSC.WasVariant ? "✔" : "✕") << "</td>";
|
OS << "<td>" << (RSC.WasVariant ? "✔" : "✕") << "</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.
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue