diff --git a/projects/hipdnn/test_sdk/include/hipdnn_test_sdk/utilities/FrontendGraphFactory.hpp b/projects/hipdnn/test_sdk/include/hipdnn_test_sdk/utilities/FrontendGraphFactory.hpp index 57d97cc6df1..94f0dac8854 100644 --- a/projects/hipdnn/test_sdk/include/hipdnn_test_sdk/utilities/FrontendGraphFactory.hpp +++ b/projects/hipdnn/test_sdk/include/hipdnn_test_sdk/utilities/FrontendGraphFactory.hpp @@ -30,7 +30,8 @@ enum class OperationType CONV_FWD_BIAS_ACTIV, BATCHNORM_TRAINING, BATCHNORM_INFERENCE, - BATCHNORM_BACKWARD + BATCHNORM_BACKWARD, + MATMUL }; /// Factory class for creating frontend Graph objects for testing @@ -59,6 +60,8 @@ class FrontendGraphFactory return createBatchnormInferenceGraph(); case OperationType::BATCHNORM_BACKWARD: return createBatchnormBackwardGraph(); + case OperationType::MATMUL: + return createMatmulGraph(); default: throw std::runtime_error("Unknown OperationType"); } @@ -312,6 +315,32 @@ class FrontendGraphFactory dScaleAttr->set_output(true); dBiasAttr->set_output(true); + return graphObj; + } + /// Matmul graph + static Graph createMatmulGraph() + { + Graph graphObj; + graphObj.set_name("Test_Matmul"); + graphObj.set_intermediate_data_type(DataType::FLOAT) + .set_compute_data_type(DataType::FLOAT) + .set_io_data_type(DataType::FLOAT); + + std::vector aDims = {2, 3}; + auto aStrides = hipdnn_data_sdk::utilities::generateStrides(aDims); + auto aAttr = graph::makeTensorAttributes("A", aDims, aStrides); + auto aTensorAttr = std::make_shared(std::move(aAttr)); + + std::vector bDims = {3, 4}; + auto bStrides = hipdnn_data_sdk::utilities::generateStrides(bDims); + auto bAttr = graph::makeTensorAttributes("B", bDims, bStrides); + auto bTensorAttr = std::make_shared(std::move(bAttr)); + + graph::MatmulAttributes matmulAttrs; + + auto cAttr = graphObj.matmul(aTensorAttr, bTensorAttr, matmulAttrs); + cAttr->set_output(true); + return graphObj; } }; diff --git a/projects/hipdnn/tests/frontend/CMakeLists.txt b/projects/hipdnn/tests/frontend/CMakeLists.txt index e35a16a78cf..a1fc4fd0cf7 100644 --- a/projects/hipdnn/tests/frontend/CMakeLists.txt +++ b/projects/hipdnn/tests/frontend/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable( IntegrationGraphEngineFiltering.cpp IntegrationGraphKnobsApi.cpp IntegrationConvFpropDescriptorLowering.cpp + IntegrationMatmul.cpp IntegrationConvolutionWgradDescriptorLowering.cpp ) diff --git a/projects/hipdnn/tests/frontend/IntegrationMatmul.cpp b/projects/hipdnn/tests/frontend/IntegrationMatmul.cpp new file mode 100644 index 00000000000..caf50c6544b --- /dev/null +++ b/projects/hipdnn/tests/frontend/IntegrationMatmul.cpp @@ -0,0 +1,285 @@ +// Copyright © Advanced Micro Devices, Inc., or its affiliates. +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "test_plugins/TestPluginConstants.hpp" + +using namespace hipdnn_frontend; +using namespace hipdnn_frontend::graph; +using namespace hipdnn_data_sdk::utilities; + +namespace +{ + +enum class FailurePoint +{ + NONE, + CREATE_EXECUTION_PLAN, + EXECUTE +}; + +struct IntegrationTestCase +{ + std::string pluginPath; + std::string description; + std::string graphName; + FailurePoint expectedFailure; + bool useManualUids; + + friend std::ostream& operator<<(std::ostream& os, const IntegrationTestCase& tc) + { + os << "MatmulTestCase{ plugin_path: " << tc.pluginPath + << ", description: " << tc.description << ", graph_name: " << tc.graphName + << ", expected_failure: "; + + switch(tc.expectedFailure) + { + case FailurePoint::NONE: + os << "NONE"; + break; + case FailurePoint::CREATE_EXECUTION_PLAN: + os << "CREATE_EXECUTION_PLAN"; + break; + case FailurePoint::EXECUTE: + os << "EXECUTE"; + break; + default: + os << "UNKNOWN"; + break; + } + + os << ", use_manual_uids: " << (tc.useManualUids ? "true" : "false") << " }"; + return os; + } +}; + +template +class IntegrationMatmul : public ::testing::TestWithParam +{ +protected: + struct SimpleMatmulTensorBundle + { + SimpleMatmulTensorBundle(const std::vector& aDims, + const std::vector& bDims, + const std::vector& cDims) + : aTensor(Tensor(aDims)) + , bTensor(Tensor(bDims)) + , cTensor(Tensor(cDims)) + { + aTensor.fillWithValue(static_cast(1.0)); + bTensor.fillWithValue(static_cast(1.0)); + cTensor.fillWithValue(static_cast(0.0)); + } + + Tensor aTensor; + Tensor bTensor; + Tensor cTensor; + }; + + struct MatmulTestTensors + { + std::shared_ptr a; + std::shared_ptr b; + std::shared_ptr c; + }; + + void SetUp() override + { + SKIP_IF_NO_DEVICES(); + } + + void TearDown() override + { + if(_handle != nullptr) + { + ASSERT_EQ(hipdnnDestroy(_handle), HIPDNN_STATUS_SUCCESS); + } + } + + static hipdnnHandle_t setupEnvironmentWithPlugin(const std::string& pluginPath) + { + EXPECT_EQ(hipInit(0), hipSuccess); + int deviceId = 0; + EXPECT_EQ(hipGetDevice(&deviceId), hipSuccess); + + const std::array paths = {pluginPath.c_str()}; + EXPECT_EQ(hipdnnSetEnginePluginPaths_ext( + paths.size(), paths.data(), HIPDNN_PLUGIN_LOADING_ABSOLUTE), + HIPDNN_STATUS_SUCCESS); + + hipdnnHandle_t handle = nullptr; + EXPECT_EQ(hipdnnCreate(&handle), HIPDNN_STATUS_SUCCESS); + return handle; + } + + static std::pair, MatmulTestTensors> createMatmulTestGraphWithUids( + const std::string& graphName, const SimpleMatmulTensorBundle& bundle, bool useManualUids) + { + auto graph = std::make_shared(); + graph->set_name(graphName) + .set_io_data_type(DataType::FLOAT) + .set_intermediate_data_type(DataType::FLOAT) + .set_compute_data_type(DataType::FLOAT); + + int64_t uid = 1; + MatmulTestTensors tensors; + + auto aAttr + = makeTensorAttributes("A", getDataTypeEnumFromType(), bundle.aTensor); + if(useManualUids) + { + aAttr.set_uid(uid++); + } + tensors.a = std::make_shared(std::move(aAttr)); + + auto bAttr + = makeTensorAttributes("B", getDataTypeEnumFromType(), bundle.bTensor); + if(useManualUids) + { + bAttr.set_uid(uid++); + } + tensors.b = std::make_shared(std::move(bAttr)); + + MatmulAttributes matmulAttrs; + matmulAttrs.set_name("matmul"); + + tensors.c = graph->matmul(tensors.a, tensors.b, matmulAttrs); + if(useManualUids) + { + tensors.c->set_uid(uid++); + } + tensors.c->set_output(true); + + return {graph, tensors}; + } + + static std::unordered_map createVariantPack(const MatmulTestTensors& tensors, + SimpleMatmulTensorBundle& bundle) + { + std::unordered_map vp; + vp[tensors.a->get_uid()] = bundle.aTensor.memory().deviceData(); + vp[tensors.b->get_uid()] = bundle.bTensor.memory().deviceData(); + vp[tensors.c->get_uid()] = bundle.cTensor.memory().deviceData(); + return vp; + } + + static void runGraphPipeline(const std::shared_ptr& graph, + hipdnnHandle_t handle, + const MatmulTestTensors& tensors, + SimpleMatmulTensorBundle& bundle, + FailurePoint expectedFailure) + { + auto result = graph->validate(); + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + + result = graph->build_operation_graph(handle); + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + + result = graph->create_execution_plans(); + if(expectedFailure == FailurePoint::CREATE_EXECUTION_PLAN) + { + ASSERT_NE(result.code, ErrorCode::OK); + return; + } + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + + result = graph->check_support(); + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + + result = graph->build_plans(); + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + + int64_t workspaceSize; + result = graph->get_workspace_size(workspaceSize); + ASSERT_EQ(result.code, ErrorCode::OK); + ASSERT_GE(workspaceSize, 0); + Workspace workspace(static_cast(workspaceSize)); + + auto vp = createVariantPack(tensors, bundle); + + result = graph->execute(handle, vp, workspace.get()); + if(expectedFailure == FailurePoint::EXECUTE) + { + ASSERT_NE(result.code, ErrorCode::OK); + } + else + { + ASSERT_EQ(result.code, ErrorCode::OK) << result.err_msg; + } + } + + void runTest() + { + const auto& tc = GetParam(); + + _handle = setupEnvironmentWithPlugin(tc.pluginPath); + + SimpleMatmulTensorBundle bundle({2, 3}, {3, 4}, {2, 4}); + + auto [graph, tensors] + = createMatmulTestGraphWithUids(tc.graphName, bundle, tc.useManualUids); + + runGraphPipeline(graph, _handle, tensors, bundle, tc.expectedFailure); + } + +private: + hipdnnHandle_t _handle = nullptr; +}; + +} // namespace + +class IntegrationMatmulFp32 : public IntegrationMatmul +{ +}; + +TEST_P(IntegrationMatmulFp32, ExecutePluginPipeline) +{ + runTest(); +} + +INSTANTIATE_TEST_SUITE_P( + , + IntegrationMatmulFp32, + ::testing::Values( + IntegrationTestCase{hipdnn_tests::plugin_constants::testGoodPluginPath(), + "GoodPluginManualUids", + "MatmulTestManualUID", + FailurePoint::NONE, + true}, + IntegrationTestCase{hipdnn_tests::plugin_constants::testGoodPluginPath(), + "GoodPluginAutoUids", + "MatmulTestAutoUID", + FailurePoint::NONE, + false}, + IntegrationTestCase{hipdnn_tests::plugin_constants::testExecuteFailsPluginPath(), + "ExecuteFailsPlugin", + "MatmulTestExecuteFail", + FailurePoint::EXECUTE, + true}, + IntegrationTestCase{hipdnn_tests::plugin_constants::testNoApplicableEnginesAPluginPath(), + "NoEnginesPlugin", + "MatmulTestNoEngines", + FailurePoint::CREATE_EXECUTION_PLAN, + true}), + [](const ::testing::TestParamInfo& info) { + std::string name = info.param.description; + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { + return std::isalnum(c) ? c : '_'; + }); + return name; + });