brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.3 KiB · 1b0073e Raw
267 lines · cpp
1#include "MCTargetDesc/X86MCTargetDesc.h"2#include "Views/SummaryView.h"3#include "X86TestBase.h"4#include "llvm/ADT/SmallPtrSet.h"5#include "llvm/MC/MCInstBuilder.h"6#include "llvm/MCA/CustomBehaviour.h"7#include "llvm/MCA/IncrementalSourceMgr.h"8#include "llvm/MCA/InstrBuilder.h"9#include "llvm/MCA/Pipeline.h"10#include "llvm/Support/Format.h"11#include "llvm/Support/JSON.h"12#include "llvm/Support/raw_ostream.h"13#include <memory>14#include <unordered_map>15 16using namespace llvm;17using namespace mca;18 19TEST_F(X86TestBase, TestResumablePipeline) {20  mca::Context MCA(*MRI, *STI);21 22  mca::IncrementalSourceMgr ISM;23  // Empty CustomBehaviour.24  auto CB = std::make_unique<mca::CustomBehaviour>(*STI, ISM, *MCII);25 26  auto PO = getDefaultPipelineOptions();27  auto P = MCA.createDefaultPipeline(PO, ISM, *CB);28  ASSERT_TRUE(P);29 30  SmallVector<MCInst> MCIs;31  getSimpleInsts(MCIs, /*Repeats=*/100);32 33  // Add views.34  auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), MCIs,35                                          PO.DispatchWidth);36  P->addEventListener(SV.get());37 38  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);39  mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, /*CallLatency=*/100);40 41  const SmallVector<mca::Instrument *> Instruments;42  // Tile size = 743  for (unsigned i = 0U, E = MCIs.size(); i < E;) {44    for (unsigned TE = i + 7; i < TE && i < E; ++i) {45      Expected<std::unique_ptr<mca::Instruction>> InstOrErr =46          IB.createInstruction(MCIs[i], Instruments);47      ASSERT_TRUE(bool(InstOrErr));48      ISM.addInst(std::move(InstOrErr.get()));49    }50 51    // Run the pipeline.52    Expected<unsigned> Cycles = P->run();53    if (!Cycles) {54      // Should be a stream pause error.55      ASSERT_TRUE(Cycles.errorIsA<mca::InstStreamPause>());56      llvm::consumeError(Cycles.takeError());57    }58  }59 60  ISM.endOfStream();61  // Has to terminate properly.62  Expected<unsigned> Cycles = P->run();63  ASSERT_TRUE(bool(Cycles));64 65  json::Value Result = SV->toJSON();66  auto *ResultObj = Result.getAsObject();67  ASSERT_TRUE(ResultObj);68 69  // Run the baseline.70  json::Object BaselineResult;71  auto E = runBaselineMCA(BaselineResult, MCIs);72  ASSERT_FALSE(bool(E)) << "Failed to run baseline";73  auto *BaselineObj = BaselineResult.getObject(SV->getNameAsString());74  ASSERT_TRUE(BaselineObj) << "Does not contain SummaryView result";75 76  // Compare the results.77  constexpr const char *Fields[] = {"Instructions", "TotalCycles", "TotaluOps",78                                    "BlockRThroughput"};79  for (const auto *F : Fields) {80    auto V = ResultObj->getInteger(F);81    auto BV = BaselineObj->getInteger(F);82    ASSERT_TRUE(V && BV);83    ASSERT_EQ(*BV, *V) << "Value of '" << F << "' does not match";84  }85}86 87TEST_F(X86TestBase, TestInstructionRecycling) {88  mca::Context MCA(*MRI, *STI);89 90  std::unordered_map<const mca::InstrDesc *, SmallPtrSet<mca::Instruction *, 2>>91      RecycledInsts;92  auto GetRecycledInst = [&](const mca::InstrDesc &Desc) -> mca::Instruction * {93    auto It = RecycledInsts.find(&Desc);94    if (It != RecycledInsts.end()) {95      auto &Insts = It->second;96      if (Insts.size()) {97        mca::Instruction *I = *Insts.begin();98        Insts.erase(I);99        return I;100      }101    }102    return nullptr;103  };104  auto AddRecycledInst = [&](mca::Instruction *I) {105    const mca::InstrDesc &D = I->getDesc();106    RecycledInsts[&D].insert(I);107  };108 109  mca::IncrementalSourceMgr ISM;110  ISM.setOnInstFreedCallback(AddRecycledInst);111 112  // Empty CustomBehaviour.113  auto CB = std::make_unique<mca::CustomBehaviour>(*STI, ISM, *MCII);114 115  auto PO = getDefaultPipelineOptions();116  auto P = MCA.createDefaultPipeline(PO, ISM, *CB);117  ASSERT_TRUE(P);118 119  SmallVector<MCInst> MCIs;120  getSimpleInsts(MCIs, /*Repeats=*/100);121 122  // Add views.123  auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), MCIs,124                                          PO.DispatchWidth);125  P->addEventListener(SV.get());126 127  // Default InstrumentManager128  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);129 130  mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, /*CallLatency=*/100);131  IB.setInstRecycleCallback(GetRecycledInst);132 133  // Setup a generic IPP that does not do anything (as it is not target134  // specific) for testing purposes.135  auto IPP = std::make_unique<InstrPostProcess>(*STI, *MCII);136 137  const SmallVector<mca::Instrument *> Instruments;138  // Tile size = 7139  for (unsigned i = 0U, E = MCIs.size(); i < E;) {140    for (unsigned TE = i + 7; i < TE && i < E; ++i) {141      Expected<std::unique_ptr<mca::Instruction>> InstOrErr =142          IB.createInstruction(MCIs[i], Instruments);143 144      if (!InstOrErr) {145        mca::Instruction *RecycledInst = nullptr;146        // Check if the returned instruction is a recycled147        // one.148        auto RemainingE = handleErrors(InstOrErr.takeError(),149                                       [&](const mca::RecycledInstErr &RC) {150                                         RecycledInst = RC.getInst();151                                       });152        ASSERT_FALSE(bool(RemainingE));153        ASSERT_TRUE(RecycledInst);154        IPP->postProcessInstruction(*RecycledInst, MCIs[i]);155        ISM.addRecycledInst(RecycledInst);156      } else {157        IPP->postProcessInstruction(*InstOrErr.get(), MCIs[i]);158        ISM.addInst(std::move(InstOrErr.get()));159      }160    }161 162    // Run the pipeline.163    Expected<unsigned> Cycles = P->run();164    if (!Cycles) {165      // Should be a stream pause error.166      ASSERT_TRUE(Cycles.errorIsA<mca::InstStreamPause>());167      llvm::consumeError(Cycles.takeError());168    }169  }170 171  ISM.endOfStream();172  // Has to terminate properly.173  Expected<unsigned> Cycles = P->run();174  ASSERT_TRUE(bool(Cycles));175 176  json::Value Result = SV->toJSON();177  auto *ResultObj = Result.getAsObject();178  ASSERT_TRUE(ResultObj);179 180  // Run the baseline.181  json::Object BaselineResult;182  auto E = runBaselineMCA(BaselineResult, MCIs);183  ASSERT_FALSE(bool(E)) << "Failed to run baseline";184  auto *BaselineObj = BaselineResult.getObject(SV->getNameAsString());185  ASSERT_TRUE(BaselineObj) << "Does not contain SummaryView result";186 187  // Compare the results.188  constexpr const char *Fields[] = {"Instructions", "TotalCycles", "TotaluOps",189                                    "BlockRThroughput"};190  for (const auto *F : Fields) {191    auto V = ResultObj->getInteger(F);192    auto BV = BaselineObj->getInteger(F);193    ASSERT_TRUE(V && BV);194    ASSERT_EQ(*BV, *V) << "Value of '" << F << "' does not match";195  }196}197 198// Test that we do not depend upon the MCInst address for variant description199// construction. This test creates two instructions that will use variant200// description as they are both zeroing idioms, but write to different201// registers. If the key used to access the variant instruction description is202// the same between the descriptions (like the MCInst pointer), we will run into203// an assertion failure due to the different writes.204TEST_F(X86TestBase, TestVariantInstructionsSameAddress) {205  mca::Context MCA(*MRI, *STI);206 207  mca::IncrementalSourceMgr ISM;208  // Empty CustomBehaviour.209  auto CB = std::make_unique<mca::CustomBehaviour>(*STI, ISM, *MCII);210 211  auto PO = getDefaultPipelineOptions();212  auto P = MCA.createDefaultPipeline(PO, ISM, *CB);213  ASSERT_TRUE(P);214 215  auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);216  mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, 100);217 218  const SmallVector<mca::Instrument *> Instruments;219 220  MCInst InstructionToAdd;221  InstructionToAdd = MCInstBuilder(X86::XOR64rr)222                         .addReg(X86::RAX)223                         .addReg(X86::RAX)224                         .addReg(X86::RAX);225  Expected<std::unique_ptr<mca::Instruction>> Instruction1OrErr =226      IB.createInstruction(InstructionToAdd, Instruments);227  ASSERT_TRUE(static_cast<bool>(Instruction1OrErr));228  ISM.addInst(std::move(Instruction1OrErr.get()));229 230  InstructionToAdd = MCInstBuilder(X86::XORPSrr)231                         .addReg(X86::XMM0)232                         .addReg(X86::XMM0)233                         .addReg(X86::XMM0);234  Expected<std::unique_ptr<mca::Instruction>> Instruction2OrErr =235      IB.createInstruction(InstructionToAdd, Instruments);236  ASSERT_TRUE(static_cast<bool>(Instruction2OrErr));237  ISM.addInst(std::move(Instruction2OrErr.get()));238 239  ISM.endOfStream();240  Expected<unsigned> Cycles = P->run();241  ASSERT_TRUE(static_cast<bool>(Cycles));242}243 244// Test customization of instruction latency with instruments245TEST_F(X86TestBase, TestInstructionCustomization) {246  const unsigned ExplicitLatency = 100;247  SmallVector<MCInst> MCIs;248  MCInst InstructionToAdd = MCInstBuilder(X86::XOR64rr)249                                .addReg(X86::RAX)250                                .addReg(X86::RBX)251                                .addReg(X86::RCX);252  MCIs.push_back(InstructionToAdd);253  SmallVector<std::pair<StringRef, StringRef>> InstrDescs;254  auto LatStr = std::to_string(ExplicitLatency);255  InstrDescs.push_back(std::make_pair(StringRef("LATENCY"), StringRef(LatStr)));256 257  // Run the baseline.258  json::Object BaselineResult;259  auto E = runBaselineMCA(BaselineResult, MCIs, {}, nullptr, InstrDescs);260  ASSERT_FALSE(bool(E)) << "Failed to run baseline";261  auto *BaselineObj = BaselineResult.getObject("SummaryView");262  auto V = BaselineObj->getInteger("TotalCycles");263  ASSERT_TRUE(V);264  // Additional 3 cycles for Dispatch, Executed and Retired states265  ASSERT_EQ(unsigned(*V), ExplicitLatency + 3) << "Total cycles do not match";266}267