// Copyright (C) Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include #include #include #include #include "FallbackTestUtils.hpp" using namespace TensileLite; using namespace TensileLite::testing; namespace { class StubTopLibrary : public ContractionLibrary { public: explicit StubTopLibrary(std::shared_ptr solution) : m_solution(std::move(solution)) { } std::shared_ptr getSolutionByIndex(ContractionProblemGemm const&, Hardware const&, int) const override { return {}; } std::shared_ptr findBestSolution(ContractionProblemGemm const&, Hardware const&, double* = nullptr) const override { return m_solution; } SolutionSet findAllSolutions(ContractionProblemGemm const&, Hardware const&, SolutionLibrarySearchType = SolutionLibrarySearchType::DEFAULT) const override { return m_solution ? SolutionSet({m_solution}) : SolutionSet(); } SolutionSet findAllSolutionsGroupedGemm(std::vector const&, Hardware const&, SolutionLibrarySearchType = SolutionLibrarySearchType::DEFAULT) const override { return {}; } std::string type() const override { return "StubTop"; } std::string description() const override { return "StubTop"; } SolutionVector findTopSolutions(ContractionProblemGemm const&, Hardware const&, int) const override { return m_solution ? SolutionVector({m_solution}) : SolutionVector(); } private: std::shared_ptr m_solution; }; class ScopedStreamK5ForceMode { public: explicit ScopedStreamK5ForceMode(std::optional value) { m_previous = std::getenv("TENSILE_STREAMK5_FORCE_MODE"); if(m_previous) m_previousValue = m_previous; if(value) setenv("TENSILE_STREAMK5_FORCE_MODE", value->c_str(), 1); else unsetenv("TENSILE_STREAMK5_FORCE_MODE"); Debug::Instance().reloadDebugBitsForTest(); } ~ScopedStreamK5ForceMode() { if(m_previous) setenv("TENSILE_STREAMK5_FORCE_MODE", m_previousValue.c_str(), 1); else unsetenv("TENSILE_STREAMK5_FORCE_MODE"); Debug::Instance().reloadDebugBitsForTest(); } private: const char* m_previous = nullptr; std::string m_previousValue; }; ContractionProblemPredicate makeRowPredicate( std::shared_ptr> predicate) { return ContractionProblemPredicate(std::move(predicate)); } std::shared_ptr buildMatchingRowsLibrary() { auto lib = std::make_shared(); lib->rows.push_back(ContractionProblemSelectionLibrary::Row( makeRowPredicate(std::make_shared()), std::make_shared(makeSolution("equality", 1)))); lib->rows.push_back(ContractionProblemSelectionLibrary::Row( makeRowPredicate(std::make_shared()), std::make_shared(makeSolution("range", 2)))); lib->rows.push_back(ContractionProblemSelectionLibrary::Row( makeRowPredicate(std::make_shared()), std::make_shared(makeSolution("prediction", 3)))); return lib; } std::vector solutionNames(SolutionVector const& solutions) { std::vector names; names.reserve(solutions.size()); for(auto const& solution : solutions) names.push_back(solution->solutionName); return names; } } // namespace TEST(ExactLogicLibraryTest, FindTopSolutionsIncludesEqualityAndRangeByDefault) { auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"equality", "range", "prediction"})); } TEST(ExactLogicLibraryTest, FindTopSolutionsSkipsEqualityAndRangeWhenStreamKSchedulingOn) { auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); problem.setParams().setStreamKTileSchedulingMode(1); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"prediction"})); } TEST(ExactLogicLibraryTest, FindTopSolutionsSkipsEqualityAndRangeWhenStreamKSchedulingAuto) { auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); problem.setParams().setStreamKTileSchedulingMode(2); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"prediction"})); } TEST(ExactLogicLibraryTest, FindTopSolutionsSkipsEqualityAndRangeWhenStreamK5ForceDynamic) { ScopedStreamK5ForceMode forceDynamic("1"); auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"prediction"})); } TEST(ExactLogicLibraryTest, FindTopSolutionsForceStaticDoesNotSkipEqualityAndRange) { ScopedStreamK5ForceMode forceStatic("0"); auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"equality", "range", "prediction"})); } TEST(ExactLogicLibraryTest, FindTopSolutionsForceStaticOverridesStreamKScheduling) { ScopedStreamK5ForceMode forceStatic("0"); auto lib = buildMatchingRowsLibrary(); auto problem = dummyProblem(); problem.setParams().setStreamKTileSchedulingMode(1); const AMDGPU device = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx"); EXPECT_EQ(solutionNames(lib->findTopSolutions(problem, device, 3)), (std::vector{"equality", "range", "prediction"})); }