// Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include "TestContext.hpp" #include "common/CommonGraphs.hpp" #include "common/Utilities.hpp" namespace PrefetchScaleTest { TEST_CASE("PrefetchScale exchange placement", "[kernel-graph][graph-transforms]") { using namespace rocRoller; using namespace rocRoller::KernelGraph; using namespace rocRoller::KernelGraph::ControlGraph; using namespace rocRoller::KernelGraph::CoordinateGraph; using namespace rocRoller::Operations; auto context = TestContext::ForTarget(GPUArchitectureTarget{GPUArchitectureGFX::GFX950}); auto example = rocRollerTest::Graphs::GEMM(DataType::FP4, DataType::FP4, DataType::Half); example.setTileSize(128, 128, 256); example.setMFMA(16, 16, 128, 1); example.setUseLDS(true, true, false); example.setScaling( ScaleMode::Separate, ScaleMode::Separate, DataType::E8M0, DataType::E8M0, 32); example.setScaleLoadPaths(SolutionParams::LoadPath::BufferToVGPR, SolutionParams::LoadPath::BufferToVGPR); example.setPrefetch(true, 4, 1, true); example.setSwizzle(32, 32, 8, 8, true); example.setTranspose("T", "N"); example.setStreamK(StreamKMode::Standard); auto command = example.getCommand(); auto graph = example.getKernelGraph(); auto params = example.getCommandParameters(); graph = transform(graph, params); graph = transform(graph); graph = transform(graph, true); graph = transform(graph, params, context.get()); graph = transform(graph, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph); graph = transform(graph); graph = transform(graph); // AddStreamK has pre-loop of K loop inside of // another ForLoop which cause the bug. { auto numWGsArg = findArgumentByName(command, NUMWGS); REQUIRE(numWGsArg != nullptr); graph = transform(graph, context.get(), params, XLOOP, KLOOP, std::make_shared(numWGsArg)); } graph = transform(graph, context.get()); graph = transform(graph, context.get(), params->workgroupRemapXCC); graph = transform(graph, params, context.get()); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph); graph = transform(graph, params, context.get()); graph = transform(graph, params, context.get()); graph = transform(graph, params, context.get()); auto findLoop = [&](std::string const& name) -> std::optional { auto const rootTag = graph.control.roots().only().value(); for(auto const loop : filter(graph.control.isElemType(), graph.control.depthFirstVisit(rootTag))) { auto forloop = graph.control.get(loop).value(); if(forloop.loopName == name) return loop; } FAIL("Loop '" + name + "' not found"); return std::nullopt; }; auto kLoopTag = findLoop(KLOOP); REQUIRE(kLoopTag.has_value()); SECTION("Exchange nodes are placed inside the K loop body") { auto isExchange = graph.control.isElemType(); int exchangesInKLoop = 0; int exchangesOutsideK = 0; int totalExchanges = 0; std::optional kLoopTailTag = findLoop(KLOOPTAIL); for(auto exchangeTag : graph.control.getNodes().filter(isExchange)) { totalExchanges++; auto stack = controlStack(exchangeTag, graph); bool insideKLoop = std::find(stack.begin(), stack.end(), kLoopTag.value()) != stack.end(); bool insideKLoopTail = kLoopTailTag.has_value() && std::find(stack.begin(), stack.end(), kLoopTailTag.value()) != stack.end(); if(insideKLoop && !insideKLoopTail) exchangesInKLoop++; else exchangesOutsideK++; } INFO("totalExchanges=" << totalExchanges << " inKLoopBody=" << exchangesInKLoop << " outsideKBody=" << exchangesOutsideK); REQUIRE(totalExchanges > 0); // With prefetchScale and StreamK, the K loop body must contain // Exchange nodes for subiters. A prior bug in // DeterminePrefetchPositions caused it to place all // exchanges in the pre-loop instead of the K loop body. CHECK(exchangesInKLoop > 0); // The K loop body should have more exchanges than outside // (pre-loop + tail), because it processes all subiters each iteration. CHECK(exchangesInKLoop >= exchangesOutsideK); } } }