Files
TheRock/rocm-libraries/shared/rocroller/test/unit/WaitCountTest.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

368 lines
13 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <rocRoller/CodeGen/WaitCount.hpp>
#include <rocRoller/Utilities/Logging.hpp>
#include "SimpleFixture.hpp"
#include <common/SourceMatcher.hpp>
using namespace rocRoller;
class WaitCountTest : public SimpleFixture
{
};
TEST_F(WaitCountTest, Basic)
{
GPUArchitecture arch{GPUArchitectureTarget{GPUArchitectureGFX::GFX90A}};
auto wc = WaitCount::KMCnt(arch, 2);
EXPECT_EQ(2, wc.kmcnt());
EXPECT_EQ(-1, wc.dscnt());
EXPECT_EQ(-1, wc.loadcnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.vscnt());
EXPECT_EQ(-1, wc.expcnt());
EXPECT_EQ("s_waitcnt lgkmcnt(2)\n", wc.toString(LogLevel::Terse));
}
TEST_F(WaitCountTest, Combine)
{
GPUArchitecture arch{GPUArchitectureTarget{GPUArchitectureGFX::GFX90A}};
// Add capability so VSCnt can be generated
arch.AddCapability(GPUCapability::SeparateVscnt, 0);
arch.AddCapability(GPUCapability::HasExpcnt, 0);
auto wc = WaitCount::KMCnt(arch, 2);
wc.combine(WaitCount::LoadCnt(arch, 4));
EXPECT_EQ(2, wc.kmcnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.dscnt());
EXPECT_EQ(-1, wc.vscnt());
EXPECT_EQ(-1, wc.expcnt());
wc.combine(WaitCount::KMCnt(arch, 4));
EXPECT_EQ(2, wc.kmcnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.dscnt());
EXPECT_EQ(-1, wc.vscnt());
EXPECT_EQ(-1, wc.expcnt());
wc.combine(WaitCount::KMCnt(arch, 1, "Wait for LDS"));
wc.combine(WaitCount::DSCnt(arch, 1, "Wait for LDS"));
EXPECT_EQ(1, wc.kmcnt());
EXPECT_EQ(1, wc.dscnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.vscnt());
EXPECT_EQ(-1, wc.expcnt());
// -1 is no wait, shouldn't affect the value.
wc.combine(WaitCount::KMCnt(arch, -1));
wc.combine(WaitCount::DSCnt(arch, -1));
EXPECT_EQ(1, wc.kmcnt());
EXPECT_EQ(1, wc.dscnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.vscnt());
EXPECT_EQ(-1, wc.expcnt());
wc.combine(WaitCount::VSCnt(arch, 2, "Wait for store"));
EXPECT_EQ(1, wc.kmcnt());
EXPECT_EQ(1, wc.dscnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(2, wc.vscnt());
EXPECT_EQ(-1, wc.storecnt());
EXPECT_EQ(-1, wc.expcnt());
wc.combine(WaitCount::EXPCnt(arch, 20));
EXPECT_EQ(1, wc.kmcnt());
EXPECT_EQ(1, wc.dscnt());
EXPECT_EQ(4, wc.loadcnt());
EXPECT_EQ(2, wc.vscnt());
EXPECT_EQ(20, wc.expcnt());
EXPECT_EQ(-1, wc.storecnt());
auto stringValue = wc.toString(LogLevel::Debug);
EXPECT_THAT(stringValue, testing::HasSubstr("// Wait for LDS"));
EXPECT_THAT(stringValue, testing::HasSubstr("// Wait for store"));
EXPECT_THAT(stringValue, testing::HasSubstr("s_waitcnt"));
EXPECT_THAT(stringValue, testing::HasSubstr("vmcnt(4)"));
EXPECT_THAT(stringValue, testing::HasSubstr("lgkmcnt(1)"));
EXPECT_THAT(stringValue, testing::HasSubstr("expcnt(20)"));
EXPECT_THAT(stringValue, testing::HasSubstr("s_waitcnt_vscnt 2"));
stringValue = wc.toString(LogLevel::Terse);
// No comments for terse version
EXPECT_THAT(stringValue, testing::Not(testing::HasSubstr("// Wait for LDS")));
EXPECT_THAT(stringValue, testing::Not(testing::HasSubstr("// Wait for store")));
// Still need all the functional parts.
EXPECT_THAT(stringValue, testing::HasSubstr("s_waitcnt"));
EXPECT_THAT(stringValue, testing::HasSubstr("vmcnt(4)"));
EXPECT_THAT(stringValue, testing::HasSubstr("lgkmcnt(1)"));
EXPECT_THAT(stringValue, testing::HasSubstr("expcnt(20)"));
EXPECT_THAT(stringValue, testing::HasSubstr("s_waitcnt_vscnt 2"));
{
WaitCount wc = WaitCount::SyncQueue(
arch, GPUWaitQueueType::SMemQueue, "DEBUG: Wait for scalar queue");
EXPECT_EQ(wc.queuesToSync().count(), 1);
EXPECT_EQ(wc.queuesToSync()[GPUWaitQueueType::SMemQueue], true);
}
{
WaitCount wc = WaitCount::SyncQueues(
arch,
EnumBitset<GPUWaitQueueType>{GPUWaitQueueType::SMemQueue, GPUWaitQueueType::DSQueue},
"DEBUG: Wait for scalar and LDS queues");
EXPECT_EQ(wc.queuesToSync().count(), 2);
EXPECT_EQ(wc.queuesToSync()[GPUWaitQueueType::SMemQueue], true);
EXPECT_EQ(wc.queuesToSync()[GPUWaitQueueType::DSQueue], true);
}
}
/**
* This test checks that if an architecture has the SeparateVscnt capability, then a waitcnt zero will
* produce a wait zero for vscnt, and if it doesn't have that capability, then no vscnt wait is produced.
**/
TEST_F(WaitCountTest, VSCnt)
{
GPUArchitecture TestWithVSCnt{GPUArchitectureTarget{GPUArchitectureGFX::GFX90A}};
TestWithVSCnt.AddCapability(GPUCapability::SupportedISA, 0);
TestWithVSCnt.AddCapability(GPUCapability::SeparateVscnt, 0);
TestWithVSCnt.AddCapability(GPUCapability::HasExpcnt, 0);
EXPECT_EQ(TestWithVSCnt.HasCapability(GPUCapability::SupportedISA), true);
EXPECT_EQ(TestWithVSCnt.HasCapability(GPUCapability::SeparateVscnt), true);
auto wcWithVSCnt = WaitCount::Zero(TestWithVSCnt);
EXPECT_EQ(0, wcWithVSCnt.kmcnt());
EXPECT_EQ(0, wcWithVSCnt.dscnt());
EXPECT_EQ(0, wcWithVSCnt.loadcnt());
EXPECT_EQ(0, wcWithVSCnt.storecnt());
EXPECT_EQ(0, wcWithVSCnt.vscnt());
EXPECT_EQ(0, wcWithVSCnt.expcnt());
std::string expectedWithVSCnt = R"(
s_waitcnt vmcnt(0) lgkmcnt(0) expcnt(0)
s_waitcnt_vscnt 0
)";
EXPECT_EQ(NormalizedSource(wcWithVSCnt.toString(LogLevel::Debug)),
NormalizedSource(expectedWithVSCnt));
GPUArchitecture TestNoVSCnt{GPUArchitectureTarget{GPUArchitectureGFX::GFX90A}};
TestNoVSCnt.AddCapability(GPUCapability::SupportedISA, 0);
TestNoVSCnt.AddCapability(GPUCapability::HasExpcnt, 0);
EXPECT_EQ(TestNoVSCnt.HasCapability(GPUCapability::SupportedISA), true);
EXPECT_EQ(TestNoVSCnt.HasCapability(GPUCapability::SeparateVscnt), false);
auto wcNoVSCnt = WaitCount::Zero(TestNoVSCnt);
EXPECT_EQ(0, wcNoVSCnt.kmcnt());
EXPECT_EQ(0, wcNoVSCnt.dscnt());
EXPECT_EQ(0, wcNoVSCnt.loadcnt());
EXPECT_EQ(0, wcNoVSCnt.storecnt());
EXPECT_EQ(-1, wcNoVSCnt.vscnt());
EXPECT_EQ(0, wcNoVSCnt.expcnt());
std::string expectedNoVSCnt = R"(
s_waitcnt vmcnt(0) lgkmcnt(0) expcnt(0)
)";
EXPECT_EQ(NormalizedSource(wcNoVSCnt.toString(LogLevel::Debug)),
NormalizedSource(expectedNoVSCnt));
}
TEST_F(WaitCountTest, TensorCnt)
{
GPUArchitecture TestNoTensorCnt{GPUArchitectureTarget{GPUArchitectureGFX::GFX1250}};
TestNoTensorCnt.AddCapability(GPUCapability::SupportedISA, 0);
TestNoTensorCnt.AddCapability(GPUCapability::HasSplitWaitCounters, 0);
EXPECT_EQ(TestNoTensorCnt.HasCapability(GPUCapability::SupportedISA), true);
EXPECT_EQ(TestNoTensorCnt.HasCapability(GPUCapability::HasTensorcnt), false);
auto wcNoTensorCnt = WaitCount::Zero(TestNoTensorCnt);
EXPECT_EQ(0, wcNoTensorCnt.kmcnt());
EXPECT_EQ(0, wcNoTensorCnt.dscnt());
EXPECT_EQ(0, wcNoTensorCnt.loadcnt());
EXPECT_EQ(0, wcNoTensorCnt.storecnt());
EXPECT_EQ(-1, wcNoTensorCnt.vscnt());
EXPECT_EQ(-1, wcNoTensorCnt.expcnt());
EXPECT_EQ(-1, wcNoTensorCnt.tensorcnt());
std::string expectedNoTensorCnt = R"(
s_wait_loadcnt 0
s_wait_storecnt 0
s_wait_kmcnt 0
s_wait_dscnt 0
)";
EXPECT_EQ(NormalizedSource(wcNoTensorCnt.toString(LogLevel::Debug)),
NormalizedSource(expectedNoTensorCnt));
GPUArchitecture TestWithTensorCnt{GPUArchitectureTarget{GPUArchitectureGFX::GFX1250}};
TestWithTensorCnt.AddCapability(GPUCapability::SupportedISA, 0);
TestWithTensorCnt.AddCapability(GPUCapability::HasSplitWaitCounters, 0);
TestWithTensorCnt.AddCapability(GPUCapability::HasTensorcnt, 0);
EXPECT_EQ(TestWithTensorCnt.HasCapability(GPUCapability::SupportedISA), true);
EXPECT_EQ(TestWithTensorCnt.HasCapability(GPUCapability::HasTensorcnt), true);
auto wcWithTensorCnt = WaitCount::Zero(TestWithTensorCnt);
EXPECT_EQ(0, wcWithTensorCnt.kmcnt());
EXPECT_EQ(0, wcWithTensorCnt.dscnt());
EXPECT_EQ(0, wcWithTensorCnt.loadcnt());
EXPECT_EQ(0, wcWithTensorCnt.storecnt());
EXPECT_EQ(-1, wcWithTensorCnt.vscnt());
EXPECT_EQ(-1, wcWithTensorCnt.expcnt());
EXPECT_EQ(0, wcWithTensorCnt.tensorcnt());
std::string expectedWithTensorCnt = R"(
s_wait_loadcnt 0
s_wait_storecnt 0
s_wait_kmcnt 0
s_wait_dscnt 0
s_wait_tensorcnt 0
)";
EXPECT_EQ(NormalizedSource(wcWithTensorCnt.toString(LogLevel::Debug)),
NormalizedSource(expectedWithTensorCnt));
}
TEST_F(WaitCountTest, SaturatedValues)
{
GPUArchitecture testArch{GPUArchitectureTarget{GPUArchitectureGFX::GFX90A}};
testArch.AddCapability(GPUCapability::MaxExpcnt, 7);
testArch.AddCapability(GPUCapability::MaxLgkmcnt, 15);
testArch.AddCapability(GPUCapability::MaxVmcnt, 63);
testArch.AddCapability(GPUCapability::HasExpcnt, 0);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxExpcnt), true);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxLgkmcnt), true);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxVmcnt), true);
auto wcZero = WaitCount::Zero(testArch).getAsSaturatedWaitCount(testArch);
EXPECT_EQ(0, wcZero.kmcnt());
EXPECT_EQ(0, wcZero.dscnt());
EXPECT_EQ(0, wcZero.loadcnt());
EXPECT_EQ(0, wcZero.storecnt());
EXPECT_EQ(-1, wcZero.vscnt());
EXPECT_EQ(0, wcZero.expcnt());
auto wcExp = WaitCount::EXPCnt(testArch, 20);
EXPECT_EQ(-1, wcExp.kmcnt());
EXPECT_EQ(-1, wcExp.dscnt());
EXPECT_EQ(-1, wcExp.loadcnt());
EXPECT_EQ(-1, wcExp.storecnt());
EXPECT_EQ(-1, wcExp.vscnt());
EXPECT_EQ(20, wcExp.expcnt());
auto wcSatExp = wcExp.getAsSaturatedWaitCount(testArch);
EXPECT_EQ(-1, wcSatExp.kmcnt());
EXPECT_EQ(-1, wcSatExp.dscnt());
EXPECT_EQ(-1, wcSatExp.loadcnt());
EXPECT_EQ(-1, wcSatExp.storecnt());
EXPECT_EQ(-1, wcSatExp.vscnt());
EXPECT_EQ(7, wcSatExp.expcnt());
auto wcVm = WaitCount::LoadCnt(testArch, 100);
EXPECT_EQ(100, wcVm.loadcnt());
wcVm.combine(wcExp);
auto wcComb = wcVm.getAsSaturatedWaitCount(testArch);
EXPECT_EQ(-1, wcComb.kmcnt());
EXPECT_EQ(-1, wcComb.dscnt());
EXPECT_EQ(63, wcComb.loadcnt());
EXPECT_EQ(-1, wcComb.storecnt());
EXPECT_EQ(-1, wcComb.vscnt());
EXPECT_EQ(7, wcComb.expcnt());
}
TEST_F(WaitCountTest, SaturatedValuesGFX1250)
{
GPUArchitecture testArch{GPUArchitectureTarget{GPUArchitectureGFX::GFX1250}};
testArch.AddCapability(GPUCapability::HasSplitWaitCounters, 0);
testArch.AddCapability(GPUCapability::MaxExpcnt, 7);
testArch.AddCapability(GPUCapability::MaxLgkmcnt, 15);
testArch.AddCapability(GPUCapability::MaxVmcnt, 63);
testArch.AddCapability(GPUCapability::MaxTensorcnt, 63);
testArch.AddCapability(GPUCapability::HasExpcnt, 0);
testArch.AddCapability(GPUCapability::HasTensorcnt, 0);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxExpcnt), true);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxLgkmcnt), true);
EXPECT_EQ(testArch.HasCapability(GPUCapability::MaxVmcnt), true);
EXPECT_EQ(testArch.HasCapability(GPUCapability::HasTensorcnt), true);
auto wcZero = WaitCount::Zero(testArch).getAsSaturatedWaitCount(testArch);
EXPECT_EQ(0, wcZero.kmcnt());
EXPECT_EQ(0, wcZero.dscnt());
EXPECT_EQ(0, wcZero.loadcnt());
EXPECT_EQ(0, wcZero.storecnt());
EXPECT_EQ(-1, wcZero.vscnt());
EXPECT_EQ(0, wcZero.expcnt());
EXPECT_EQ(0, wcZero.tensorcnt());
auto wcExp = WaitCount::EXPCnt(testArch, 20);
EXPECT_EQ(-1, wcExp.kmcnt());
EXPECT_EQ(-1, wcExp.dscnt());
EXPECT_EQ(-1, wcExp.loadcnt());
EXPECT_EQ(-1, wcExp.storecnt());
EXPECT_EQ(-1, wcExp.vscnt());
EXPECT_EQ(20, wcExp.expcnt());
EXPECT_EQ(-1, wcExp.tensorcnt());
auto wcSatExp = wcExp.getAsSaturatedWaitCount(testArch);
EXPECT_EQ(-1, wcSatExp.kmcnt());
EXPECT_EQ(-1, wcSatExp.dscnt());
EXPECT_EQ(-1, wcSatExp.loadcnt());
EXPECT_EQ(-1, wcSatExp.storecnt());
EXPECT_EQ(-1, wcSatExp.vscnt());
EXPECT_EQ(7, wcSatExp.expcnt());
EXPECT_EQ(-1, wcSatExp.tensorcnt());
auto wcVm = WaitCount::LoadCnt(testArch, 100);
EXPECT_EQ(100, wcVm.loadcnt());
wcVm.combine(wcExp);
auto wcComb = wcVm.getAsSaturatedWaitCount(testArch);
EXPECT_EQ(-1, wcComb.kmcnt());
EXPECT_EQ(-1, wcComb.dscnt());
EXPECT_EQ(63, wcComb.loadcnt());
EXPECT_EQ(-1, wcComb.storecnt());
EXPECT_EQ(-1, wcComb.vscnt());
EXPECT_EQ(7, wcComb.expcnt());
EXPECT_EQ(-1, wcComb.tensorcnt());
auto wcTensor = WaitCount::TensorCnt(testArch, 100);
EXPECT_EQ(100, wcTensor.tensorcnt());
wcTensor.combine(wcSatExp);
wcComb = wcTensor.getAsSaturatedWaitCount(testArch);
EXPECT_EQ(-1, wcComb.kmcnt());
EXPECT_EQ(-1, wcComb.dscnt());
EXPECT_EQ(-1, wcComb.loadcnt());
EXPECT_EQ(-1, wcComb.storecnt());
EXPECT_EQ(-1, wcComb.vscnt());
EXPECT_EQ(7, wcComb.expcnt());
EXPECT_EQ(63, wcComb.tensorcnt());
}