| #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 <unordered_map> |
| |
| 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<mca::CustomBehaviour>(*STI, ISM, *MCII); |
| |
| auto PO = getDefaultPipelineOptions(); |
| auto P = MCA.createDefaultPipeline(PO, ISM, *CB); |
| ASSERT_TRUE(P); |
| |
| SmallVector<MCInst> MCIs; |
| getSimpleInsts(MCIs, /*Repeats=*/100); |
| |
| // Add views. |
| auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), MCIs, |
| PO.DispatchWidth); |
| P->addEventListener(SV.get()); |
| |
| auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII); |
| mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM); |
| |
| const SmallVector<mca::Instrument *> Instruments; |
| // Tile size = 7 |
| for (unsigned i = 0U, E = MCIs.size(); i < E;) { |
| for (unsigned TE = i + 7; i < TE && i < E; ++i) { |
| Expected<std::unique_ptr<mca::Instruction>> InstOrErr = |
| IB.createInstruction(MCIs[i], Instruments); |
| ASSERT_TRUE(bool(InstOrErr)); |
| ISM.addInst(std::move(InstOrErr.get())); |
| } |
| |
| // Run the pipeline. |
| Expected<unsigned> Cycles = P->run(); |
| if (!Cycles) { |
| // Should be a stream pause error. |
| ASSERT_TRUE(Cycles.errorIsA<mca::InstStreamPause>()); |
| llvm::consumeError(Cycles.takeError()); |
| } |
| } |
| |
| ISM.endOfStream(); |
| // Has to terminate properly. |
| Expected<unsigned> 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<const mca::InstrDesc *, SmallPtrSet<mca::Instruction *, 2>> |
| 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<mca::CustomBehaviour>(*STI, ISM, *MCII); |
| |
| auto PO = getDefaultPipelineOptions(); |
| auto P = MCA.createDefaultPipeline(PO, ISM, *CB); |
| ASSERT_TRUE(P); |
| |
| SmallVector<MCInst> MCIs; |
| getSimpleInsts(MCIs, /*Repeats=*/100); |
| |
| // Add views. |
| auto SV = std::make_unique<SummaryView>(STI->getSchedModel(), MCIs, |
| PO.DispatchWidth); |
| P->addEventListener(SV.get()); |
| |
| // Default InstrumentManager |
| auto IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII); |
| |
| mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM); |
| IB.setInstRecycleCallback(GetRecycledInst); |
| |
| const SmallVector<mca::Instrument *> Instruments; |
| // Tile size = 7 |
| for (unsigned i = 0U, E = MCIs.size(); i < E;) { |
| for (unsigned TE = i + 7; i < TE && i < E; ++i) { |
| Expected<std::unique_ptr<mca::Instruction>> 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<unsigned> Cycles = P->run(); |
| if (!Cycles) { |
| // Should be a stream pause error. |
| ASSERT_TRUE(Cycles.errorIsA<mca::InstStreamPause>()); |
| llvm::consumeError(Cycles.takeError()); |
| } |
| } |
| |
| ISM.endOfStream(); |
| // Has to terminate properly. |
| Expected<unsigned> 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"; |
| } |
| } |