Files
TheRock/rocm-libraries/projects/hipdnn/backend/tests/descriptors/TestNodeFactory.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

318 lines
13 KiB
C++

// Copyright © Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include "TestMacros.hpp"
#include "descriptors/ConvolutionFwdOperationDescriptor.hpp"
#include "descriptors/LayernormOperationDescriptor.hpp"
#include "descriptors/NodeFactory.hpp"
#include "descriptors/SdpaBwdOperationDescriptor.hpp"
#include "descriptors/TensorDescriptor.hpp"
#include <gtest/gtest.h>
#include <hipdnn_flatbuffers_sdk/data_objects/convolution_fwd_attributes_generated.h>
#include <hipdnn_flatbuffers_sdk/data_objects/graph_generated.h>
#include <hipdnn_flatbuffers_sdk/data_objects/layernorm_attributes_generated.h>
#include <hipdnn_flatbuffers_sdk/data_objects/sdpa_backward_attributes_generated.h>
#include <hipdnn_flatbuffers_sdk/data_objects/tensor_attributes_generated.h>
#include <hipdnn_test_sdk/constants/ConvFpropConstants.hpp>
#include <hipdnn_test_sdk/constants/LayernormConstants.hpp>
#include <hipdnn_test_sdk/constants/SdpaBwdConstants.hpp>
#include <hipdnn_test_sdk/utilities/ToVec.hpp>
#include <memory>
#include <vector>
using namespace hipdnn_backend;
using namespace hipdnn_flatbuffers_sdk::data_objects;
using namespace hipdnn_tests::constants;
using hipdnn_tests::toVec;
// =============================================================================
// NodeFactory::createOperationFromNode() Tests
// =============================================================================
class TestNodeFactory : public ::testing::Test
{
protected:
std::unordered_map<int64_t, std::shared_ptr<TensorDescriptor>> _tensorMap;
void SetUp() override
{
TensorAttributesT xAttrs;
xAttrs.uid = K_FPROP_TENSOR_X_UID;
xAttrs.data_type = DataType::FLOAT;
xAttrs.dims = toVec(K_FPROP_TENSOR_X_DIMS);
xAttrs.strides = toVec(K_FPROP_TENSOR_X_STRIDES);
TensorAttributesT wAttrs;
wAttrs.uid = K_FPROP_TENSOR_W_UID;
wAttrs.data_type = DataType::FLOAT;
wAttrs.dims = toVec(K_FPROP_TENSOR_W_DIMS);
wAttrs.strides = toVec(K_FPROP_TENSOR_W_STRIDES);
TensorAttributesT yAttrs;
yAttrs.uid = K_FPROP_TENSOR_Y_UID;
yAttrs.data_type = DataType::FLOAT;
yAttrs.dims = toVec(K_FPROP_TENSOR_Y_DIMS);
yAttrs.strides = toVec(K_FPROP_TENSOR_Y_STRIDES);
_tensorMap[K_FPROP_TENSOR_X_UID] = TensorDescriptor::fromFlatBuffer(xAttrs);
_tensorMap[K_FPROP_TENSOR_W_UID] = TensorDescriptor::fromFlatBuffer(wAttrs);
_tensorMap[K_FPROP_TENSOR_Y_UID] = TensorDescriptor::fromFlatBuffer(yAttrs);
}
static ConvolutionFwdAttributesT createStandardConvAttrs()
{
ConvolutionFwdAttributesT attrs;
attrs.x_tensor_uid = K_FPROP_TENSOR_X_UID;
attrs.w_tensor_uid = K_FPROP_TENSOR_W_UID;
attrs.y_tensor_uid = K_FPROP_TENSOR_Y_UID;
attrs.pre_padding = toVec(K_FPROP_CONV_PADDING);
attrs.post_padding = toVec(K_FPROP_CONV_PADDING);
attrs.stride = toVec(K_FPROP_CONV_STRIDE);
attrs.dilation = toVec(K_FPROP_CONV_DILATION);
attrs.conv_mode = ConvMode::CROSS_CORRELATION;
return attrs;
}
static NodeT createStandardNode()
{
NodeT node;
node.compute_data_type = DataType::FLOAT;
node.attributes.Set(createStandardConvAttrs());
return node;
}
};
TEST_F(TestNodeFactory, CreateOperationFromNodeConvFwd)
{
auto node = createStandardNode();
auto graphOp = NodeFactory::createOperationFromNode(node, _tensorMap);
ASSERT_NE(graphOp, nullptr);
// Verify the factory dispatched to the correct operation type, then static_cast.
// Cannot use dynamic_pointer_cast: backend tests compile with -fno-rtti.
auto* op = graphOp->asGraphOperation();
ASSERT_NE(op, nullptr);
auto rebuiltNode = op->buildNode();
ASSERT_EQ(rebuiltNode->attributes.type, NodeAttributes::ConvolutionFwdAttributes);
auto desc = std::static_pointer_cast<ConvolutionFwdOperationDescriptor>(graphOp);
ASSERT_TRUE(desc->isFinalized());
EXPECT_EQ(desc->getData().x_tensor_uid, K_FPROP_TENSOR_X_UID);
EXPECT_EQ(desc->getData().w_tensor_uid, K_FPROP_TENSOR_W_UID);
EXPECT_EQ(desc->getData().y_tensor_uid, K_FPROP_TENSOR_Y_UID);
}
TEST_F(TestNodeFactory, CreateOperationFromNodeLayernorm)
{
// Build a minimal layernorm tensor map
std::unordered_map<int64_t, std::shared_ptr<TensorDescriptor>> lnTensorMap;
auto makeTensor = [](int64_t uid) {
TensorAttributesT attrs;
attrs.uid = uid;
attrs.data_type = DataType::FLOAT;
attrs.dims = {2, 64, 32, 32};
attrs.strides = {65536, 1024, 32, 1};
return TensorDescriptor::fromFlatBuffer(attrs);
};
lnTensorMap[K_LAYERNORM_TENSOR_X_UID] = makeTensor(K_LAYERNORM_TENSOR_X_UID);
lnTensorMap[K_LAYERNORM_TENSOR_SCALE_UID] = makeTensor(K_LAYERNORM_TENSOR_SCALE_UID);
lnTensorMap[K_LAYERNORM_TENSOR_BIAS_UID] = makeTensor(K_LAYERNORM_TENSOR_BIAS_UID);
lnTensorMap[K_LAYERNORM_TENSOR_EPSILON_UID] = makeTensor(K_LAYERNORM_TENSOR_EPSILON_UID);
lnTensorMap[K_LAYERNORM_TENSOR_Y_UID] = makeTensor(K_LAYERNORM_TENSOR_Y_UID);
LayernormAttributesT lnAttrs;
lnAttrs.x_tensor_uid = K_LAYERNORM_TENSOR_X_UID;
lnAttrs.scale_tensor_uid = K_LAYERNORM_TENSOR_SCALE_UID;
lnAttrs.bias_tensor_uid = K_LAYERNORM_TENSOR_BIAS_UID;
lnAttrs.epsilon_tensor_uid = K_LAYERNORM_TENSOR_EPSILON_UID;
lnAttrs.y_tensor_uid = K_LAYERNORM_TENSOR_Y_UID;
lnAttrs.normalized_dim_count = 3;
lnAttrs.forward_phase = NormFwdPhase::TRAINING;
NodeT node;
node.compute_data_type = DataType::FLOAT;
node.attributes.Set(lnAttrs);
auto graphOp = NodeFactory::createOperationFromNode(node, lnTensorMap);
ASSERT_NE(graphOp, nullptr);
auto* op = graphOp->asGraphOperation();
ASSERT_NE(op, nullptr);
auto rebuiltNode = op->buildNode();
ASSERT_EQ(rebuiltNode->attributes.type, NodeAttributes::LayernormAttributes);
auto desc = std::static_pointer_cast<LayernormOperationDescriptor>(graphOp);
ASSERT_TRUE(desc->isFinalized());
EXPECT_EQ(desc->getData().x_tensor_uid, K_LAYERNORM_TENSOR_X_UID);
EXPECT_EQ(desc->getData().normalized_dim_count, 3);
EXPECT_EQ(desc->getData().forward_phase, NormFwdPhase::TRAINING);
}
TEST_F(TestNodeFactory, CreateOperationFromNodeSdpaBwd)
{
// Set up tensor map with 9 required SDPA bwd tensors
auto makeTensor =
[](int64_t uid, const std::array<int64_t, 4>& dims, const std::array<int64_t, 4>& strides) {
TensorAttributesT t;
t.uid = uid;
t.data_type = DataType::FLOAT;
t.dims = toVec(dims);
t.strides = toVec(strides);
return TensorDescriptor::fromFlatBuffer(t);
};
std::unordered_map<int64_t, std::shared_ptr<TensorDescriptor>> sdpaTensorMap;
sdpaTensorMap[K_SDPA_BWD_TENSOR_Q_UID] = makeTensor(
K_SDPA_BWD_TENSOR_Q_UID, K_SDPA_BWD_TENSOR_Q_DIMS, K_SDPA_BWD_TENSOR_Q_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_K_UID] = makeTensor(
K_SDPA_BWD_TENSOR_K_UID, K_SDPA_BWD_TENSOR_K_DIMS, K_SDPA_BWD_TENSOR_K_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_V_UID] = makeTensor(
K_SDPA_BWD_TENSOR_V_UID, K_SDPA_BWD_TENSOR_V_DIMS, K_SDPA_BWD_TENSOR_V_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_O_UID] = makeTensor(
K_SDPA_BWD_TENSOR_O_UID, K_SDPA_BWD_TENSOR_O_DIMS, K_SDPA_BWD_TENSOR_O_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_DO_UID] = makeTensor(
K_SDPA_BWD_TENSOR_DO_UID, K_SDPA_BWD_TENSOR_DO_DIMS, K_SDPA_BWD_TENSOR_DO_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_STATS_UID] = makeTensor(
K_SDPA_BWD_TENSOR_STATS_UID, K_SDPA_BWD_TENSOR_STATS_DIMS, K_SDPA_BWD_TENSOR_STATS_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_DQ_UID] = makeTensor(
K_SDPA_BWD_TENSOR_DQ_UID, K_SDPA_BWD_TENSOR_DQ_DIMS, K_SDPA_BWD_TENSOR_DQ_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_DK_UID] = makeTensor(
K_SDPA_BWD_TENSOR_DK_UID, K_SDPA_BWD_TENSOR_DK_DIMS, K_SDPA_BWD_TENSOR_DK_STRIDES);
sdpaTensorMap[K_SDPA_BWD_TENSOR_DV_UID] = makeTensor(
K_SDPA_BWD_TENSOR_DV_UID, K_SDPA_BWD_TENSOR_DV_DIMS, K_SDPA_BWD_TENSOR_DV_STRIDES);
// Create SDPA backward attributes
SdpaBackwardAttributesT sdpaAttrs;
sdpaAttrs.q_tensor_uid = K_SDPA_BWD_TENSOR_Q_UID;
sdpaAttrs.k_tensor_uid = K_SDPA_BWD_TENSOR_K_UID;
sdpaAttrs.v_tensor_uid = K_SDPA_BWD_TENSOR_V_UID;
sdpaAttrs.o_tensor_uid = K_SDPA_BWD_TENSOR_O_UID;
sdpaAttrs.do_tensor_uid = K_SDPA_BWD_TENSOR_DO_UID;
sdpaAttrs.stats_tensor_uid = K_SDPA_BWD_TENSOR_STATS_UID;
sdpaAttrs.dq_tensor_uid = K_SDPA_BWD_TENSOR_DQ_UID;
sdpaAttrs.dk_tensor_uid = K_SDPA_BWD_TENSOR_DK_UID;
sdpaAttrs.dv_tensor_uid = K_SDPA_BWD_TENSOR_DV_UID;
NodeT node;
node.compute_data_type = DataType::FLOAT;
node.attributes.Set(sdpaAttrs);
auto graphOp = NodeFactory::createOperationFromNode(node, sdpaTensorMap);
ASSERT_NE(graphOp, nullptr);
auto* op = graphOp->asGraphOperation();
ASSERT_NE(op, nullptr);
auto rebuiltNode = op->buildNode();
ASSERT_EQ(rebuiltNode->attributes.type, NodeAttributes::SdpaBackwardAttributes);
auto desc = std::static_pointer_cast<SdpaBwdOperationDescriptor>(graphOp);
ASSERT_TRUE(desc->isFinalized());
EXPECT_EQ(desc->getData().q_tensor_uid, K_SDPA_BWD_TENSOR_Q_UID);
EXPECT_EQ(desc->getData().k_tensor_uid, K_SDPA_BWD_TENSOR_K_UID);
EXPECT_EQ(desc->getData().v_tensor_uid, K_SDPA_BWD_TENSOR_V_UID);
EXPECT_EQ(desc->getData().o_tensor_uid, K_SDPA_BWD_TENSOR_O_UID);
EXPECT_EQ(desc->getData().do_tensor_uid, K_SDPA_BWD_TENSOR_DO_UID);
EXPECT_EQ(desc->getData().stats_tensor_uid, K_SDPA_BWD_TENSOR_STATS_UID);
EXPECT_EQ(desc->getData().dq_tensor_uid, K_SDPA_BWD_TENSOR_DQ_UID);
EXPECT_EQ(desc->getData().dk_tensor_uid, K_SDPA_BWD_TENSOR_DK_UID);
EXPECT_EQ(desc->getData().dv_tensor_uid, K_SDPA_BWD_TENSOR_DV_UID);
}
TEST_F(TestNodeFactory, CreateOperationFromNodeUnsupportedType)
{
NodeT node;
node.compute_data_type = DataType::FLOAT;
// attributes.type defaults to NodeAttributes::NONE (unsupported)
ASSERT_THROW_HIPDNN_STATUS(NodeFactory::createOperationFromNode(node, _tensorMap),
HIPDNN_STATUS_NOT_SUPPORTED);
}
// =============================================================================
// NodeFactory::buildTensorMap() Tests
// =============================================================================
TEST_F(TestNodeFactory, BuildTensorMapSuccess)
{
std::vector<std::unique_ptr<TensorAttributesT>> tensors;
auto t1 = std::make_unique<TensorAttributesT>();
t1->uid = 10;
t1->data_type = DataType::FLOAT;
t1->dims = {1, 3, 32, 32};
t1->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t1));
auto t2 = std::make_unique<TensorAttributesT>();
t2->uid = 20;
t2->data_type = DataType::FLOAT;
t2->dims = {1, 3, 32, 32};
t2->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t2));
auto t3 = std::make_unique<TensorAttributesT>();
t3->uid = 30;
t3->data_type = DataType::FLOAT;
t3->dims = {1, 3, 32, 32};
t3->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t3));
auto result = NodeFactory::buildTensorMap(tensors);
ASSERT_EQ(result.size(), 3u);
ASSERT_NE(result.find(10), result.end());
ASSERT_NE(result.find(20), result.end());
ASSERT_NE(result.find(30), result.end());
EXPECT_EQ(result[10]->getData().uid, 10);
EXPECT_EQ(result[20]->getData().uid, 20);
EXPECT_EQ(result[30]->getData().uid, 30);
}
TEST_F(TestNodeFactory, BuildTensorMapEmptyVector)
{
const std::vector<std::unique_ptr<TensorAttributesT>> tensors;
auto result = NodeFactory::buildTensorMap(tensors);
EXPECT_TRUE(result.empty());
}
TEST_F(TestNodeFactory, BuildTensorMapNullTensor)
{
std::vector<std::unique_ptr<TensorAttributesT>> tensors;
auto t1 = std::make_unique<TensorAttributesT>();
t1->uid = 10;
t1->data_type = DataType::FLOAT;
t1->dims = {1, 3, 32, 32};
t1->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t1));
tensors.push_back(nullptr);
ASSERT_THROW_HIPDNN_STATUS(NodeFactory::buildTensorMap(tensors), HIPDNN_STATUS_INTERNAL_ERROR);
}
TEST_F(TestNodeFactory, BuildTensorMapDuplicateUID)
{
std::vector<std::unique_ptr<TensorAttributesT>> tensors;
auto t1 = std::make_unique<TensorAttributesT>();
t1->uid = 10;
t1->data_type = DataType::FLOAT;
t1->dims = {1, 3, 32, 32};
t1->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t1));
auto t2 = std::make_unique<TensorAttributesT>();
t2->uid = 10;
t2->data_type = DataType::FLOAT;
t2->dims = {1, 3, 32, 32};
t2->strides = {3072, 1024, 32, 1};
tensors.push_back(std::move(t2));
ASSERT_THROW_HIPDNN_STATUS(NodeFactory::buildTensorMap(tensors), HIPDNN_STATUS_INTERNAL_ERROR);
}