Files
TheRock/rocm-libraries/projects/hipblaslt/tensilelite/tests/PciChipId_test.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

578 lines
24 KiB
C++

// Copyright (C) Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <gtest/gtest.h>
#include <iomanip>
#include <iostream>
#include <set>
#include <hip/hip_runtime.h>
#include <Tensile/AMDGPU.hpp>
#include <Tensile/AMDGPUPredicates.hpp>
#include <Tensile/ContractionLibrary.hpp>
#include <Tensile/ContractionProblemPredicates.hpp>
#include <Tensile/ContractionProblemProperties.hpp>
#include <Tensile/Debug.hpp>
#include <Tensile/ExactLogicLibrary.hpp>
#include <Tensile/hip/HipHardware.hpp>
#include "FallbackTestUtils.hpp"
using namespace TensileLite;
using namespace TensileLite::testing;
// Verify that hipDeviceAttributePciChipId is correctly queried and matches
// a known chip ID.
TEST(PciChipIdTest, QueryDeviceChipId)
{
int deviceCount = 0;
hipError_t err = hipGetDeviceCount(&deviceCount);
ASSERT_EQ(err, hipSuccess) << "Failed to get device count";
ASSERT_GT(deviceCount, 0) << "No HIP devices available";
hipDeviceProp_t prop;
ASSERT_EQ(hipGetDeviceProperties(&prop, 0), hipSuccess) << "Failed to get device properties";
auto processor = AMDGPU::toProcessor(prop.gcnArchName);
if(!ChipIdRegistry::supportsChipIdPredicate(processor))
GTEST_SKIP() << "PCI chip ID querying is gfx950-only at runtime";
// Query PCI Chip ID using hipDeviceGetAttribute directly
int pciChipId = 0;
err = hipDeviceGetAttribute(&pciChipId, hipDeviceAttributePciChipId, 0);
ASSERT_EQ(err, hipSuccess) << "Failed to get PCI Chip ID attribute";
auto isKnownChipId = ChipIdRegistry::isKnownChipId(pciChipId);
EXPECT_TRUE(isKnownChipId) << "PCI Chip ID should be known";
}
// Verify that HipAMDGPU correctly populates pciChipId from HIP runtime
// and matches a known chip ID.
TEST(PciChipIdTest, HipHardwarePopulatesPciChipId)
{
int deviceCount = 0;
hipError_t err = hipGetDeviceCount(&deviceCount);
ASSERT_EQ(err, hipSuccess) << "Failed to get device count";
ASSERT_GT(deviceCount, 0) << "No HIP devices available";
// Get the current device using Tensile's hip::GetCurrentDevice()
auto hardware = hip::GetCurrentDevice();
ASSERT_NE(hardware, nullptr) << "Failed to get current device";
// Cast to AMDGPU to access pciChipId
auto* amdgpu = dynamic_cast<AMDGPU*>(hardware.get());
ASSERT_NE(amdgpu, nullptr) << "Hardware is not an AMDGPU";
if(!ChipIdRegistry::supportsChipIdPredicate(amdgpu->processor))
{
EXPECT_FALSE(amdgpu->pciChipId().has_value())
<< "pciChipId should be unset for non-gfx950 processors";
return;
}
if(Debug::Instance().printDeviceSelection())
{
// Print device information
std::cout << "\n=== AMDGPU Hardware Info ===" << std::endl;
std::cout << "Description: " << amdgpu->description() << std::endl;
std::cout << "Processor: " << AMDGPU::toString(amdgpu->processor) << std::endl;
std::cout << "CU Count: " << amdgpu->computeUnitCount << std::endl;
if(amdgpu->pciChipId().has_value())
{
std::cout << "PCI Chip ID: 0x" << std::hex << amdgpu->pciChipId().value() << std::dec
<< " (" << amdgpu->pciChipId().value() << ")" << std::endl;
}
else
{
std::cout << "PCI Chip ID: (not set)" << std::endl;
}
std::cout << "=============================\n" << std::endl;
}
EXPECT_TRUE(amdgpu->pciChipId().has_value()) << "pciChipId should be populated from HIP runtime";
EXPECT_GT(amdgpu->pciChipId().value(), 0) << "pciChipId should be a positive value";
auto isKnownChipId = ChipIdRegistry::isKnownChipId(amdgpu->pciChipId().value());
EXPECT_TRUE(isKnownChipId) << "PCI Chip ID should be known";
}
// Verify PciChipIdEqual predicate matches the correct device
TEST(PciChipIdTest, PciChipIdEqualPredicate)
{
int deviceCount = 0;
hipError_t err = hipGetDeviceCount(&deviceCount);
ASSERT_EQ(err, hipSuccess) << "Failed to get device count";
ASSERT_GT(deviceCount, 0) << "No HIP devices available";
// Get the current device
auto hardware = hip::GetCurrentDevice();
ASSERT_NE(hardware, nullptr);
auto* amdgpu = dynamic_cast<AMDGPU*>(hardware.get());
ASSERT_NE(amdgpu, nullptr);
if(!ChipIdRegistry::supportsChipIdPredicate(amdgpu->processor))
GTEST_SKIP() << "PciChipIdEqual runtime matching is gfx950-only";
ASSERT_TRUE(amdgpu->pciChipId().has_value()) << "pciChipId must be set for this test";
int actualPciChipId = amdgpu->pciChipId().value();
ASSERT_GT(actualPciChipId, 0) << "pciChipId must be valid for this test";
// Create predicate that matches the actual chip ID
auto matchingPred = std::make_shared<Predicates::GPU::PciChipIdEqual>(actualPciChipId);
// Create predicate that does NOT match (use a different ID)
auto nonMatchingPred = std::make_shared<Predicates::GPU::PciChipIdEqual>(0x1234);
EXPECT_TRUE((*matchingPred)(*amdgpu)) << "Predicate should match actual chip ID";
EXPECT_FALSE((*nonMatchingPred)(*amdgpu)) << "Predicate should NOT match different chip ID";
}
TEST(PciChipIdTest, PciChipIdEqualIgnoredOnNonGfx950)
{
AMDGPU gpuWithChipId(AMDGPU::Processor::gfx942, 120, "gfx942-mock", std::make_optional(0x75a0));
auto pred = std::make_shared<Predicates::GPU::PciChipIdEqual>(0x75a0);
EXPECT_FALSE((*pred)(gpuWithChipId))
<< "PciChipIdEqual must ignore chip IDs for non-gfx950 processors";
EXPECT_FALSE(pred->isFallbackMatch(gpuWithChipId))
<< "Fallback matching must also be disabled for non-gfx950 processors";
}
TEST(PciChipIdTest, OrPciChipIdPredicateExactForAllTargets)
{
constexpr int chipA = 0x75a0;
constexpr int chipB = 0x75a2;
constexpr int chipFallback = 0x75a3; // Falls back to 0x75a0.
auto isProcessor = std::make_shared<Predicates::GPU::ProcessorEqual>(AMDGPU::Processor::gfx950);
auto isChipA = std::make_shared<Predicates::GPU::PciChipIdEqual>(chipA);
auto isChipB = std::make_shared<Predicates::GPU::PciChipIdEqual>(chipB);
auto isChipAOrB = std::make_shared<Predicates::Or<AMDGPU>>(
std::initializer_list<std::shared_ptr<Predicates::Predicate<AMDGPU>>>{isChipA, isChipB});
auto isTargetDevice = std::make_shared<Predicates::And<AMDGPU>>(
std::initializer_list<std::shared_ptr<Predicates::Predicate<AMDGPU>>>{isProcessor, isChipAOrB});
HardwarePredicate pred(std::make_shared<Predicates::IsSubclass<Hardware, AMDGPU>>(isTargetDevice),
std::set<int>{chipA, chipB});
AMDGPU gpuA(AMDGPU::Processor::gfx950, 256, "gpuA", std::make_optional(chipA));
AMDGPU gpuB(AMDGPU::Processor::gfx950, 256, "gpuB", std::make_optional(chipB));
AMDGPU gpuFallback(AMDGPU::Processor::gfx950, 256, "gpuFallback", std::make_optional(chipFallback));
// Both members of the Or chip-ID set are exact (not fallback).
EXPECT_TRUE(pred(dummyProblem(), gpuA));
EXPECT_FALSE(pred.isFallbackMatch(gpuA));
EXPECT_TRUE(pred(dummyProblem(), gpuB));
EXPECT_FALSE(pred.isFallbackMatch(gpuB));
// A chip that matches through fallback should still be classified as fallback.
EXPECT_TRUE(pred(dummyProblem(), gpuFallback));
EXPECT_TRUE(pred.isFallbackMatch(gpuFallback));
}
// Test: Hardware selection with PciChipIdEqual in a library hierarchy
TEST(PciChipIdTest, HardwareSelectionWithPciChipId)
{
int deviceCount = 0;
hipError_t err = hipGetDeviceCount(&deviceCount);
ASSERT_EQ(err, hipSuccess) << "Failed to get device count";
ASSERT_GT(deviceCount, 0) << "No HIP devices available";
// Get the current device
auto hardware = hip::GetCurrentDevice();
ASSERT_NE(hardware, nullptr);
auto* amdgpu = dynamic_cast<AMDGPU*>(hardware.get());
ASSERT_NE(amdgpu, nullptr);
if(!ChipIdRegistry::supportsChipIdPredicate(amdgpu->processor))
GTEST_SKIP() << "HardwareSelectionWithPciChipId is gfx950-specific";
ASSERT_TRUE(amdgpu->pciChipId().has_value()) << "pciChipId must be set for this test";
int actualPciChipId = amdgpu->pciChipId().value();
AMDGPU::Processor actualProcessor = amdgpu->processor;
// Create solutions for different scenarios
auto deviceSpecificSolution = std::make_shared<ContractionSolution>();
deviceSpecificSolution->index = 1;
deviceSpecificSolution->solutionName = "DeviceSpecific_0x" +
([&]() { std::ostringstream ss; ss << std::hex << actualPciChipId; return ss.str(); })();
auto fallbackSolution = std::make_shared<ContractionSolution>();
fallbackSolution->index = 2;
fallbackSolution->solutionName = "Fallback_" + AMDGPU::toString(actualProcessor);
// Create libraries
auto deviceSpecificLib = std::make_shared<SingleContractionLibrary>(deviceSpecificSolution);
auto fallbackLib = std::make_shared<SingleContractionLibrary>(fallbackSolution);
// Create hardware predicate for specific PCI Chip ID + Processor
auto isPciChip = std::make_shared<Predicates::GPU::PciChipIdEqual>(actualPciChipId);
auto isProcessor = std::make_shared<Predicates::GPU::ProcessorEqual>(actualProcessor);
auto isSpecificDevice = std::make_shared<Predicates::And<AMDGPU>>(
std::initializer_list<std::shared_ptr<Predicates::Predicate<AMDGPU>>>{isProcessor, isPciChip});
HardwarePredicate deviceSpecificPred(
std::make_shared<Predicates::IsSubclass<Hardware, AMDGPU>>(isSpecificDevice),
actualPciChipId);
// Create fallback predicate (processor only, no chip ID)
HardwarePredicate fallbackPred(
std::make_shared<Predicates::IsSubclass<Hardware, AMDGPU>>(isProcessor));
// Build the hardware selection library (device-specific first, then fallback)
ContractionHardwareSelectionLibrary::Row deviceRow(deviceSpecificPred, deviceSpecificLib);
ContractionHardwareSelectionLibrary::Row fallbackRow(fallbackPred, fallbackLib);
ContractionHardwareSelectionLibrary lib({deviceRow, fallbackRow});
// Create a simple problem
auto problem = ContractionProblemGemm::GEMM(false, false, 1024, 1024, 1024, 1024, 1024, 1024, 1.0, false, 1);
// Find best solution - should match device-specific
auto solution = lib.findBestSolution(problem, *hardware);
if(Debug::Instance().printDeviceSelection())
{
std::cout << "\n=== Hardware Selection with PCI Chip ID ===" << std::endl;
std::cout << "Device: " << amdgpu->description() << std::endl;
std::cout << "PCI Chip ID: 0x" << std::hex << actualPciChipId << std::dec << std::endl;
if(solution)
{
std::cout << "Selected solution: " << solution->solutionName << " (index=" << solution->index << ")"
<< std::endl;
}
else
{
std::cout << "No solution found!" << std::endl;
}
std::cout << "============================================\n" << std::endl;
}
ASSERT_NE(solution, nullptr) << "Should find a matching solution";
EXPECT_EQ(solution->index, 1) << "Should select device-specific solution (index 1)";
// Test with a different hardware (simulated) to verify fallback
// Use std::make_optional to explicitly set a different chip ID
AMDGPU differentDevice(actualProcessor, amdgpu->computeUnitCount, "Different Device", std::make_optional(0x1234));
auto fallbackResult = lib.findBestSolution(problem, differentDevice);
ASSERT_NE(fallbackResult, nullptr) << "Should find fallback solution";
EXPECT_EQ(fallbackResult->index, 2) << "Should select fallback solution (index 2) for different chip ID";
if(Debug::Instance().printDeviceSelection())
{
std::cout << "Fallback test with different PCI Chip ID (0x1234):" << std::endl;
std::cout << "Selected solution: " << fallbackResult->solutionName << " (index=" << fallbackResult->index
<< ")" << std::endl;
std::cout << "=================================================\n" << std::endl;
}
}
// Test: findAllSolutions with hardware containing pciChipId
TEST(PciChipIdTest, FindAllSolutionsWithPciChipId)
{
int deviceCount = 0;
hipError_t err = hipGetDeviceCount(&deviceCount);
ASSERT_EQ(err, hipSuccess);
ASSERT_GT(deviceCount, 0);
auto hardware = hip::GetCurrentDevice();
ASSERT_NE(hardware, nullptr);
auto* amdgpu = dynamic_cast<AMDGPU*>(hardware.get());
ASSERT_NE(amdgpu, nullptr);
// Create multiple solutions
auto solution1 = std::make_shared<ContractionSolution>();
solution1->index = 1;
solution1->solutionName = "Solution_A";
auto solution2 = std::make_shared<ContractionSolution>();
solution2->index = 2;
solution2->solutionName = "Solution_B";
// Create libraries
auto lib1 = std::make_shared<SingleContractionLibrary>(solution1);
auto lib2 = std::make_shared<SingleContractionLibrary>(solution2);
// Create hardware predicate that matches current device
auto isProcessor = std::make_shared<Predicates::GPU::ProcessorEqual>(amdgpu->processor);
HardwarePredicate hwPred(std::make_shared<Predicates::IsSubclass<Hardware, AMDGPU>>(isProcessor));
// Build library with multiple solutions for same hardware
ContractionHardwareSelectionLibrary::Row row1(hwPred, lib1);
ContractionHardwareSelectionLibrary::Row row2(hwPred, lib2);
ContractionHardwareSelectionLibrary lib({row1, row2});
// Create a problem
auto problem = ContractionProblemGemm::GEMM(false, false, 512, 512, 512, 512, 512, 512, 1.0, false, 1);
// Find all solutions
auto solutions = lib.findAllSolutions(problem, *hardware);
if(Debug::Instance().printDeviceSelection())
{
std::cout << "\n=== findAllSolutions Test ===" << std::endl;
std::cout << "Hardware: " << amdgpu->description() << std::endl;
if(amdgpu->pciChipId().has_value())
{
std::cout << "PCI Chip ID: 0x" << std::hex << amdgpu->pciChipId().value() << std::dec << std::endl;
}
else
{
std::cout << "PCI Chip ID: (not set)" << std::endl;
}
std::cout << "Found " << solutions.size() << " solution(s):" << std::endl;
for(const auto& sol : solutions)
{
std::cout << " - " << sol->solutionName << " (index=" << sol->index << ")" << std::endl;
}
std::cout << "==============================\n" << std::endl;
}
EXPECT_EQ(solutions.size(), 2) << "Should find both solutions";
}
// ===========================================================================
// ChipIdFallbackTest fixture -- verifies the 4 kernel-availability scenarios
// described in the mi350/mi355 fallback specification.
//
// Each scenario constructs a HardwareSelectionLibrary whose rows are in the
// exact order the Python build system produces after the descending-chip-ID
// sort fix (higher chip IDs first, higher CU counts first within a chip,
// processor-only catch-all last).
//
// Row evaluation is first-match-wins (ExactLogicLibrary), and
// PciChipIdEqual includes one-directional fallback (mi355->mi350).
// ===========================================================================
class ChipIdFallbackTest : public ::testing::Test
{
protected:
// Mock devices
AMDGPU mi350spx = makeDevice(_MI350_CHIP_ID, _SPX_CU, "mi350spx");
AMDGPU mi355spx = makeDevice(_MI355_CHIP_ID, _SPX_CU, "mi355spx");
AMDGPU mi350cpx = makeDevice(_MI350_CHIP_ID, _CPX_CU, "mi350cpx");
AMDGPU mi355cpx = makeDevice(_MI355_CHIP_ID, _CPX_CU, "mi355cpx");
static constexpr auto gfx950 = AMDGPU::Processor::gfx950;
// Index counter for unique solution IDs
int nextIdx = 1;
std::shared_ptr<ContractionSolution> sol(const std::string& name)
{
return makeSolution(name, nextIdx++);
}
void expectSelected(const ContractionHardwareSelectionLibrary& lib,
const AMDGPU& device,
const std::string& expectedName)
{
std::string got = selectSolution(lib, device, device.deviceName);
EXPECT_EQ(got, expectedName)
<< "Device " << device.deviceName
<< " (chip=" << hexChipId(device.pciChipId().value())
<< ", CU=" << device.computeUnitCount
<< "): expected \"" << expectedName << "\", got \"" << got << "\"";
}
};
// ---------------------------------------------------------------------------
// Scenario 1: Only mi350 kernels (equality + Origami)
//
// Available kernels : mi350spx_eq, mi350spx_oob
// Expected:
// mi350spx -> mi350spx_eq (exact chip match, SPX CU)
// mi355spx -> mi350spx_oob (mi355 falls through mi355-oob-only row)
// mi350cpx -> mi350spx_oob (CU=64 skips CU=256 rows)
// mi355cpx -> mi350spx_oob (CU=64 skips CU=256 rows)
// ---------------------------------------------------------------------------
TEST_F(ChipIdFallbackTest, Scenario1_MI350Only)
{
dbg("=== Scenario 1: MI350 Only ===");
auto mi350spx_eq = sol("mi350spx_eq");
auto mi350spx_oob = sol("mi350spx_oob");
// Row order mirrors the Python sort: higher chipId first, higher CU first.
// Since only mi350 kernels exist, the mi355 rows map to mi350 oob.
auto lib = buildHwLib({
// Row 1: mi355, CU=256 -- no mi355-specific kernels, oob only
{makeHwPred(gfx950, _MI355_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 2: mi350, CU=256 -- equality + oob
{makeHwPred(gfx950, _MI350_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi350spx_eq), singleLib(mi350spx_oob))},
// Row 3: mi355, any CU -- oob only
{makeHwPred(gfx950, _MI355_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 4: mi350, any CU -- oob only
{makeHwPred(gfx950, _MI350_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 5: gfx950 catch-all
{makeHwPred(gfx950),
buildProblemLib(singleLib(mi350spx_oob))},
});
expectSelected(*lib, mi350spx, "mi350spx_eq");
expectSelected(*lib, mi355spx, "mi350spx_oob");
expectSelected(*lib, mi350cpx, "mi350spx_oob");
expectSelected(*lib, mi355cpx, "mi350spx_oob");
}
// ---------------------------------------------------------------------------
// Scenario 2: mi355spx equality + mi350 (equality + Origami)
//
// Available kernels : mi350spx_eq, mi350spx_oob, mi355spx_eq
// Expected:
// mi350spx -> mi350spx_eq
// mi355spx -> mi355spx_eq (exact chip match)
// mi350cpx -> mi350spx_oob
// mi355cpx -> mi350spx_oob
// ---------------------------------------------------------------------------
TEST_F(ChipIdFallbackTest, Scenario2_MI355Eq)
{
dbg("=== Scenario 2: MI355 Eq ===");
auto mi350spx_eq = sol("mi350spx_eq");
auto mi350spx_oob = sol("mi350spx_oob");
auto mi355spx_eq = sol("mi355spx_eq");
auto lib = buildHwLib({
// Row 1: mi355, CU=256 -- mi355 equality + mi350 oob fallback
{makeHwPred(gfx950, _MI355_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi355spx_eq), singleLib(mi350spx_oob))},
// Row 2: mi350, CU=256 -- mi350 equality + oob
{makeHwPred(gfx950, _MI350_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi350spx_eq), singleLib(mi350spx_oob))},
// Row 3: mi355, any CU -- oob only
{makeHwPred(gfx950, _MI355_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 4: mi350, any CU -- oob only
{makeHwPred(gfx950, _MI350_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 5: catch-all
{makeHwPred(gfx950),
buildProblemLib(singleLib(mi350spx_oob))},
});
expectSelected(*lib, mi350spx, "mi350spx_eq");
expectSelected(*lib, mi355spx, "mi355spx_eq");
expectSelected(*lib, mi350cpx, "mi350spx_oob");
expectSelected(*lib, mi355cpx, "mi350spx_oob");
}
// ---------------------------------------------------------------------------
// Scenario 3: mi355spx (equality + Origami) + mi350 (equality + Origami)
//
// Available kernels : mi350spx_eq, mi350spx_oob, mi355spx_eq, mi355spx_oob
// Expected:
// mi350spx -> mi350spx_eq
// mi355spx -> mi355spx_eq
// mi350cpx -> mi350spx_oob
// mi355cpx -> mi355spx_oob
// ---------------------------------------------------------------------------
TEST_F(ChipIdFallbackTest, Scenario3_MI355EqOob)
{
dbg("=== Scenario 3: MI355 Eq + Oob ===");
auto mi350spx_eq = sol("mi350spx_eq");
auto mi350spx_oob = sol("mi350spx_oob");
auto mi355spx_eq = sol("mi355spx_eq");
auto mi355spx_oob = sol("mi355spx_oob");
auto lib = buildHwLib({
// Row 1: mi355, CU=256 -- mi355 equality + mi355 oob
{makeHwPred(gfx950, _MI355_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi355spx_eq), singleLib(mi355spx_oob))},
// Row 2: mi350, CU=256 -- mi350 equality + mi350 oob
{makeHwPred(gfx950, _MI350_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi350spx_eq), singleLib(mi350spx_oob))},
// Row 3: mi355, any CU -- mi355 oob
{makeHwPred(gfx950, _MI355_CHIP_ID),
buildProblemLib(singleLib(mi355spx_oob))},
// Row 4: mi350, any CU -- mi350 oob
{makeHwPred(gfx950, _MI350_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 5: catch-all
{makeHwPred(gfx950),
buildProblemLib(singleLib(mi350spx_oob))},
});
expectSelected(*lib, mi350spx, "mi350spx_eq");
expectSelected(*lib, mi355spx, "mi355spx_eq");
expectSelected(*lib, mi350cpx, "mi350spx_oob");
expectSelected(*lib, mi355cpx, "mi355spx_oob");
}
// ---------------------------------------------------------------------------
// Scenario 4: mi355spx (equality + OOB) + mi355cpx equality + mi350 (eq + oob)
//
// Available kernels : mi350spx_eq, mi350spx_oob, mi355spx_eq, mi355spx_oob,
// mi355cpx_eq
// Expected:
// mi350spx -> mi350spx_eq
// mi355spx -> mi355spx_eq
// mi350cpx -> mi350spx_oob
// mi355cpx -> mi355cpx_eq (has its own CPX equality kernels)
//
// NOTE: The original specification listed "mi355cpx: mi350cpx_eq -> mi355spx_oob"
// while the prose said "mi355cpx should use mi355cpx equality kernels first".
// We follow the prose and use mi355cpx_eq; rename if needed.
// ---------------------------------------------------------------------------
TEST_F(ChipIdFallbackTest, Scenario4_MI355CpxEq)
{
dbg("=== Scenario 4: MI355 CPX Eq ===");
auto mi350spx_eq = sol("mi350spx_eq");
auto mi350spx_oob = sol("mi350spx_oob");
auto mi355spx_eq = sol("mi355spx_eq");
auto mi355spx_oob = sol("mi355spx_oob");
auto mi355cpx_eq = sol("mi355cpx_eq");
auto lib = buildHwLib({
// Row 1: mi355, CU=256 -- mi355 equality + oob
{makeHwPred(gfx950, _MI355_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi355spx_eq), singleLib(mi355spx_oob))},
// Row 2: mi350, CU=256 -- mi350 equality + oob
{makeHwPred(gfx950, _MI350_CHIP_ID, _SPX_CU),
buildProblemLib(singleLib(mi350spx_eq), singleLib(mi350spx_oob))},
// Row 3: mi355, CU=64 -- mi355 cpx equality + mi355 spx oob fallback
{makeHwPred(gfx950, _MI355_CHIP_ID, _CPX_CU),
buildProblemLib(singleLib(mi355cpx_eq), singleLib(mi355spx_oob))},
// Row 4: mi355, any CU -- mi355 oob
{makeHwPred(gfx950, _MI355_CHIP_ID),
buildProblemLib(singleLib(mi355spx_oob))},
// Row 5: mi350, any CU -- mi350 oob
{makeHwPred(gfx950, _MI350_CHIP_ID),
buildProblemLib(singleLib(mi350spx_oob))},
// Row 6: catch-all
{makeHwPred(gfx950),
buildProblemLib(singleLib(mi350spx_oob))},
});
expectSelected(*lib, mi350spx, "mi350spx_eq");
expectSelected(*lib, mi355spx, "mi355spx_eq");
expectSelected(*lib, mi350cpx, "mi350spx_oob");
expectSelected(*lib, mi355cpx, "mi355cpx_eq");
}