#include "Views/SummaryView.h" #include "X86TestBase.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/MCA/CustomBehaviour.h" #include "llvm/MCA/IncrementalSourceMgr.h" #include "llvm/MCA/InstrBuilder.h" #include "llvm/MCA/Pipeline.h" #include "llvm/Support/Format.h" #include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace mca; TEST_F(X86TestBase, TestResumablePipeline) { mca::Context MCA(*MRI, *STI); mca::IncrementalSourceMgr ISM; // Empty CustomBehaviour. auto CB = std::make_unique(*STI, ISM, *MCII); auto PO = getDefaultPipelineOptions(); auto P = MCA.createDefaultPipeline(PO, ISM, *CB); ASSERT_TRUE(P); SmallVector MCIs; getSimpleInsts(MCIs, /*Repeats=*/100); // Add views. auto SV = std::make_unique(STI->getSchedModel(), MCIs, PO.DispatchWidth); P->addEventListener(SV.get()); auto IM = std::make_unique(*STI, *MCII); mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM); const SmallVector Instruments; // Tile size = 7 for (unsigned i = 0U, E = MCIs.size(); i < E;) { for (unsigned TE = i + 7; i < TE && i < E; ++i) { Expected> InstOrErr = IB.createInstruction(MCIs[i], Instruments); ASSERT_TRUE(bool(InstOrErr)); ISM.addInst(std::move(InstOrErr.get())); } // Run the pipeline. Expected Cycles = P->run(); if (!Cycles) { // Should be a stream pause error. ASSERT_TRUE(Cycles.errorIsA()); llvm::consumeError(Cycles.takeError()); } } ISM.endOfStream(); // Has to terminate properly. Expected Cycles = P->run(); ASSERT_TRUE(bool(Cycles)); json::Value Result = SV->toJSON(); auto *ResultObj = Result.getAsObject(); ASSERT_TRUE(ResultObj); // Run the baseline. json::Object BaselineResult; auto E = runBaselineMCA(BaselineResult, MCIs); ASSERT_FALSE(bool(E)) << "Failed to run baseline"; auto *BaselineObj = BaselineResult.getObject(SV->getNameAsString()); ASSERT_TRUE(BaselineObj) << "Does not contain SummaryView result"; // Compare the results. constexpr const char *Fields[] = {"Instructions", "TotalCycles", "TotaluOps", "BlockRThroughput"}; for (const auto *F : Fields) { auto V = ResultObj->getInteger(F); auto BV = BaselineObj->getInteger(F); ASSERT_TRUE(V && BV); ASSERT_EQ(*BV, *V) << "Value of '" << F << "' does not match"; } } TEST_F(X86TestBase, TestInstructionRecycling) { mca::Context MCA(*MRI, *STI); std::unordered_map> RecycledInsts; auto GetRecycledInst = [&](const mca::InstrDesc &Desc) -> mca::Instruction * { auto It = RecycledInsts.find(&Desc); if (It != RecycledInsts.end()) { auto &Insts = It->second; if (Insts.size()) { mca::Instruction *I = *Insts.begin(); Insts.erase(I); return I; } } return nullptr; }; auto AddRecycledInst = [&](mca::Instruction *I) { const mca::InstrDesc &D = I->getDesc(); RecycledInsts[&D].insert(I); }; mca::IncrementalSourceMgr ISM; ISM.setOnInstFreedCallback(AddRecycledInst); // Empty CustomBehaviour. auto CB = std::make_unique(*STI, ISM, *MCII); auto PO = getDefaultPipelineOptions(); auto P = MCA.createDefaultPipeline(PO, ISM, *CB); ASSERT_TRUE(P); SmallVector MCIs; getSimpleInsts(MCIs, /*Repeats=*/100); // Add views. auto SV = std::make_unique(STI->getSchedModel(), MCIs, PO.DispatchWidth); P->addEventListener(SV.get()); // Default InstrumentManager auto IM = std::make_unique(*STI, *MCII); mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM); IB.setInstRecycleCallback(GetRecycledInst); const SmallVector Instruments; // Tile size = 7 for (unsigned i = 0U, E = MCIs.size(); i < E;) { for (unsigned TE = i + 7; i < TE && i < E; ++i) { Expected> InstOrErr = IB.createInstruction(MCIs[i], Instruments); if (!InstOrErr) { mca::Instruction *RecycledInst = nullptr; // Check if the returned instruction is a recycled // one. auto RemainingE = handleErrors(InstOrErr.takeError(), [&](const mca::RecycledInstErr &RC) { RecycledInst = RC.getInst(); }); ASSERT_FALSE(bool(RemainingE)); ASSERT_TRUE(RecycledInst); ISM.addRecycledInst(RecycledInst); } else { ISM.addInst(std::move(InstOrErr.get())); } } // Run the pipeline. Expected Cycles = P->run(); if (!Cycles) { // Should be a stream pause error. ASSERT_TRUE(Cycles.errorIsA()); llvm::consumeError(Cycles.takeError()); } } ISM.endOfStream(); // Has to terminate properly. Expected Cycles = P->run(); ASSERT_TRUE(bool(Cycles)); json::Value Result = SV->toJSON(); auto *ResultObj = Result.getAsObject(); ASSERT_TRUE(ResultObj); // Run the baseline. json::Object BaselineResult; auto E = runBaselineMCA(BaselineResult, MCIs); ASSERT_FALSE(bool(E)) << "Failed to run baseline"; auto *BaselineObj = BaselineResult.getObject(SV->getNameAsString()); ASSERT_TRUE(BaselineObj) << "Does not contain SummaryView result"; // Compare the results. constexpr const char *Fields[] = {"Instructions", "TotalCycles", "TotaluOps", "BlockRThroughput"}; for (const auto *F : Fields) { auto V = ResultObj->getInteger(F); auto BV = BaselineObj->getInteger(F); ASSERT_TRUE(V && BV); ASSERT_EQ(*BV, *V) << "Value of '" << F << "' does not match"; } }