blob: 97fdf4eff1fe63a4d74f3b267e75b3d52ec9fd7b [file] [log] [blame]
Clement Courbet37f0ca02018-05-15 12:08:00 +00001//===-- Analysis.cpp --------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Clement Courbet37f0ca02018-05-15 12:08:00 +000010#include "Analysis.h"
Clement Courbeta66bfaa42018-05-15 13:07:05 +000011#include "BenchmarkResult.h"
Clement Courbet37f0ca02018-05-15 12:08:00 +000012#include "llvm/Support/FormatVariadic.h"
13#include <vector>
14
15namespace exegesis {
16
17static const char kCsvSep = ',';
18
Clement Courbeta66bfaa42018-05-15 13:07:05 +000019static void writeCsvEscaped(llvm::raw_ostream &OS, const std::string &S) {
Clement Courbet37f0ca02018-05-15 12:08:00 +000020 if (std::find(S.begin(), S.end(), kCsvSep) == S.end()) {
21 OS << S;
22 } else {
23 // Needs escaping.
24 OS << '"';
25 for (const char C : S) {
26 if (C == '"')
27 OS << "\"\"";
28 else
29 OS << C;
30 }
31 OS << '"';
32 }
33}
34
35// Prints a row representing an instruction, along with scheduling info and
36// point coordinates (measurements).
Clement Courbet6d6c1a92018-05-16 08:47:21 +000037void Analysis::printInstructionRow(const size_t ClusterId, const size_t PointId,
38 llvm::raw_ostream &OS) const {
39 const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
40
Clement Courbet37f0ca02018-05-15 12:08:00 +000041 OS << ClusterId << kCsvSep;
Clement Courbeta66bfaa42018-05-15 13:07:05 +000042 writeCsvEscaped(OS, Point.Key.OpcodeName);
43 OS << kCsvSep;
44 writeCsvEscaped(OS, Point.Key.Config);
Clement Courbet6d6c1a92018-05-16 08:47:21 +000045 OS << kCsvSep;
46 const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
47 if (OpcodeIt != MnemonicToOpcode_.end()) {
48 const auto &SchedModel = SubtargetInfo_->getSchedModel();
49 const unsigned SchedClassId = InstrInfo_->get(OpcodeIt->second).getSchedClass();
50 const llvm::MCSchedClassDesc *const SCDesc =
51 SchedModel.getSchedClassDesc(SchedClassId);
52#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
53 writeCsvEscaped(OS, SCDesc->Name);
54#else
55 OS << SchedClassId;
56#endif
57 }
Clement Courbet37f0ca02018-05-15 12:08:00 +000058 // FIXME: Print the sched class once InstructionBenchmark separates key into
59 // (mnemonic, mode, opaque).
60 for (const auto &Measurement : Point.Measurements) {
61 OS << kCsvSep;
62 writeCsvEscaped(OS, llvm::formatv("{0:F}", Measurement.Value));
63 }
64 OS << "\n";
65}
66
Clement Courbet6d6c1a92018-05-16 08:47:21 +000067Analysis::Analysis(const llvm::Target &Target,
68 const InstructionBenchmarkClustering &Clustering)
69 : Clustering_(Clustering) {
70 if (Clustering.getPoints().empty())
71 return;
72
73 InstrInfo_.reset(Target.createMCInstrInfo());
74 const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
75 SubtargetInfo_.reset(Target.createMCSubtargetInfo(
76 FirstPoint.LLVMTriple, FirstPoint.CpuName, ""));
77
78 // Build an index of mnemonic->opcode.
79 for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I)
80 MnemonicToOpcode_.emplace(InstrInfo_->getName(I), I);
Clement Courbet37f0ca02018-05-15 12:08:00 +000081}
82
Clement Courbet6d6c1a92018-05-16 08:47:21 +000083llvm::Error Analysis::printClusters(llvm::raw_ostream &OS) const {
84 if (Clustering_.getPoints().empty())
Clement Courbet37f0ca02018-05-15 12:08:00 +000085 return llvm::Error::success();
86
87 // Write the header.
Clement Courbeta66bfaa42018-05-15 13:07:05 +000088 OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config"
89 << kCsvSep << "sched_class";
Clement Courbet6d6c1a92018-05-16 08:47:21 +000090 for (const auto &Measurement : Clustering_.getPoints().front().Measurements) {
Clement Courbet37f0ca02018-05-15 12:08:00 +000091 OS << kCsvSep;
92 writeCsvEscaped(OS, Measurement.Key);
93 }
94 OS << "\n";
95
96 // Write the points.
Clement Courbet6d6c1a92018-05-16 08:47:21 +000097 const auto& Clusters = Clustering_.getValidClusters();
98 for (size_t I = 0, E = Clusters.size(); I < E; ++I) {
99 for (const size_t PointId : Clusters[I].PointIndices) {
100 printInstructionRow(I, PointId, OS);
101 }
Clement Courbet37f0ca02018-05-15 12:08:00 +0000102 OS << "\n\n";
103 }
104 return llvm::Error::success();
105}
106
107} // namespace exegesis