Files
TheRock/rocm-libraries/projects/miopen/test/gtest/find_2_conv.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

316 lines
11 KiB
C++

// Copyright © Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <gtest/gtest.h>
#include "get_handle.hpp"
#include "gtest_common.hpp"
#include "../lib_env_var.hpp"
#include "../workspace.hpp"
#include <miopen/miopen.h>
#include <miopen/convolution.hpp>
#include <miopen/solution.hpp>
#include <miopen/solver_id.hpp>
#include <nlohmann/json.hpp>
#include <vector>
#include <limits>
#include <optional>
#include <algorithm>
namespace {
struct Find2ConvTestCase
{
miopenProblemDirection_t direction;
int tune;
bool preallocate;
std::size_t workspace_limit;
bool attach_binaries;
friend std::ostream& operator<<(std::ostream& os, const Find2ConvTestCase& tc)
{
return os << "direction:" << tc.direction << " tune:" << tc.tune
<< " preallocate:" << tc.preallocate << " ws_limit:" << tc.workspace_limit
<< " attach_binaries:" << tc.attach_binaries;
}
};
void RunFind2ConvTest(const Find2ConvTestCase& test_case)
{
auto& handle_deref = get_handle();
// Generate tensors
tensor<float> x{16, 192, 28, 28};
x.generate(tensor_elem_gen_integer{17});
tensor<float> w{32, 192, 5, 5};
w.generate(tensor_elem_gen_integer{17});
miopen::ConvolutionDescriptor filter = {
2, miopenConvolution, miopenPaddingDefault, {1, 1}, {1, 1}, {1, 1}};
tensor<float> y{filter.GetForwardOutputTensor(x.desc, w.desc)};
auto x_dev = handle_deref.Write(x.data);
auto w_dev = handle_deref.Write(w.data);
auto y_dev = handle_deref.Write(y.data);
// Test convolution
miopenHandle_t handle = &handle_deref;
miopenProblem_t problem;
EXPECT_EQ(miopenCreateConvProblem(&problem, &filter, test_case.direction), miopenStatusSuccess);
// Add tensor descriptors
EXPECT_EQ(miopenSetProblemTensorDescriptor(problem, miopenTensorConvolutionX, &x.desc),
miopenStatusSuccess);
EXPECT_EQ(miopenSetProblemTensorDescriptor(problem, miopenTensorConvolutionW, &w.desc),
miopenStatusSuccess);
EXPECT_EQ(miopenSetProblemTensorDescriptor(problem, miopenTensorConvolutionY, &y.desc),
miopenStatusSuccess);
// Adding x descriptor again to validate that error is produced
EXPECT_EQ(miopenSetProblemTensorDescriptor(problem, miopenTensorConvolutionX, &x.desc),
miopenStatusBadParm);
// Test FindSolutions
auto solutions = std::vector<miopenSolution_t>{};
std::size_t found = 0;
solutions.resize(100);
EXPECT_EQ(
miopenFindSolutions(handle, problem, nullptr, solutions.data(), &found, solutions.size()),
miopenStatusSuccess);
EXPECT_GE(found, 0);
solutions.resize(found);
// Test FindSolutions with options
solutions.resize(100);
found = 0;
{
miopenFindOptions_t options;
EXPECT_EQ(miopenCreateFindOptions(&options), miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionTuning(options, test_case.tune), miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionResultsOrder(options, miopenFindResultsOrderByTime),
miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionWorkspaceLimit(options, test_case.workspace_limit),
miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionAttachBinaries(options, test_case.attach_binaries),
miopenStatusSuccess);
Workspace wspace{}; // This GPU buffer may be used by miopenFindSolutions
if(test_case.preallocate)
{
std::size_t workspace_max = [&]() {
std::size_t workspace_max_ = 0;
switch(test_case.direction)
{
case miopenProblemDirectionForward:
EXPECT_EQ(miopenConvolutionForwardGetWorkSpaceSize(
handle, &x.desc, &w.desc, &filter, &y.desc, &workspace_max_),
miopenStatusSuccess);
return workspace_max_;
case miopenProblemDirectionBackward:
EXPECT_EQ(miopenConvolutionBackwardDataGetWorkSpaceSize(
handle, &y.desc, &w.desc, &filter, &x.desc, &workspace_max_),
miopenStatusSuccess);
return workspace_max_;
case miopenProblemDirectionBackwardWeights:
EXPECT_EQ(miopenConvolutionBackwardWeightsGetWorkSpaceSize(
handle, &y.desc, &x.desc, &filter, &w.desc, &workspace_max_),
miopenStatusSuccess);
return workspace_max_;
#ifdef MIOPEN_BETA_API
case miopenProblemDirectionInference: break;
#endif
}
MIOPEN_THROW(miopenStatusNotImplemented);
}();
const auto workspace_size = std::min(test_case.workspace_limit, workspace_max);
wspace.resize(workspace_size);
EXPECT_EQ(
miopenSetFindOptionPreallocatedWorkspace(options, wspace.ptr(), wspace.size()),
miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionPreallocatedTensor(
options, miopenTensorConvolutionX, x_dev.get()),
miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionPreallocatedTensor(
options, miopenTensorConvolutionW, w_dev.get()),
miopenStatusSuccess);
EXPECT_EQ(miopenSetFindOptionPreallocatedTensor(
options, miopenTensorConvolutionY, y_dev.get()),
miopenStatusSuccess);
}
EXPECT_EQ(miopenFindSolutions(
handle, problem, options, solutions.data(), &found, solutions.size()),
miopenStatusSuccess);
EXPECT_EQ(miopenDestroyFindOptions(options), miopenStatusSuccess);
}
EXPECT_GE(found, 0);
solutions.resize(found);
// Test solution attributes
for(const auto& solution : solutions)
{
float time;
std::size_t workspace_size;
uint64_t solver_id;
miopenConvAlgorithm_t algo;
EXPECT_EQ(miopenGetSolutionTime(solution, &time), miopenStatusSuccess);
EXPECT_EQ(miopenGetSolutionWorkspaceSize(solution, &workspace_size), miopenStatusSuccess);
EXPECT_EQ(miopenGetSolutionSolverId(solution, &solver_id), miopenStatusSuccess);
EXPECT_EQ(miopenGetSolverIdConvAlgorithm(solver_id, &algo), miopenStatusSuccess);
}
// Test running solutions
miopenTensorDescriptor_t x_desc = &x.desc, w_desc = &w.desc, y_desc = &y.desc;
for(const auto& solution : solutions)
{
uint64_t solver_id;
EXPECT_EQ(miopenGetSolutionSolverId(solution, &solver_id), miopenStatusSuccess);
miopenTensorArgumentId_t names[3] = {
miopenTensorConvolutionX, miopenTensorConvolutionW, miopenTensorConvolutionY};
void* buffers[3] = {x_dev.get(), w_dev.get(), y_dev.get()};
miopenTensorDescriptor_t descriptors[3] = {x_desc, w_desc, y_desc};
// Run solution
std::size_t workspace_size;
EXPECT_EQ(miopenGetSolutionWorkspaceSize(solution, &workspace_size), miopenStatusSuccess);
Workspace wspace{workspace_size};
auto arguments = std::make_unique<miopenTensorArgument_t[]>(3);
for(auto i = 0; i < 3; ++i)
{
arguments[i].id = names[i];
arguments[i].descriptor = &descriptors[i];
arguments[i].buffer = buffers[i];
}
EXPECT_EQ(
miopenRunSolution(handle, solution, 3, arguments.get(), wspace.ptr(), wspace.size()),
miopenStatusSuccess);
// Save-load cycle
std::size_t solution_size;
EXPECT_EQ(miopenGetSolutionSize(solution, &solution_size), miopenStatusSuccess);
EXPECT_GT(solution_size, 0);
auto solution_binary = std::vector<char>{};
solution_binary.resize(solution_size);
EXPECT_EQ(miopenSaveSolution(solution, solution_binary.data()), miopenStatusSuccess);
EXPECT_EQ(miopenDestroySolution(solution), miopenStatusSuccess);
miopenSolution_t read_solution;
EXPECT_EQ(
miopenLoadSolution(&read_solution, solution_binary.data(), solution_binary.size()),
miopenStatusSuccess);
// Run loaded solution
auto read_arguments = std::make_unique<miopenTensorArgument_t[]>(3);
for(auto i = 0; i < 3; ++i)
{
read_arguments[i].id = names[i];
read_arguments[i].descriptor = &descriptors[i];
read_arguments[i].buffer = buffers[i];
}
EXPECT_EQ(miopenRunSolution(
handle, read_solution, 3, read_arguments.get(), wspace.ptr(), wspace.size()),
miopenStatusSuccess);
EXPECT_EQ(miopenDestroySolution(read_solution), miopenStatusSuccess);
}
EXPECT_EQ(miopenDestroyProblem(problem), miopenStatusSuccess);
}
} // namespace
class GPU_Find2Conv_FP32 : public testing::TestWithParam<
std::tuple<miopenProblemDirection_t, int, bool, std::size_t, bool>>
{
protected:
void SetUp() override
{
prng::reset_seed();
// Parity with CTest: Set log level to 6
if(MIOPEN_LOG_LEVEL)
{
prev_log_level = lib_env::value<int>(MIOPEN_LOG_LEVEL);
}
lib_env::update(MIOPEN_LOG_LEVEL, 6);
}
void TearDown() override
{
// Reset internal environment values as per Wiki guidelines
if(prev_log_level.has_value())
{
lib_env::update(MIOPEN_LOG_LEVEL, *prev_log_level);
}
else
{
lib_env::clear(MIOPEN_LOG_LEVEL);
}
}
private:
std::optional<int> prev_log_level;
};
// TEST_INFO is "Find2ConvTest" for descriptiveness.
// Specificity is provided by Parameter Name Generator in the test output.
TEST_P(GPU_Find2Conv_FP32, Find2ConvTest)
{
auto param = GetParam();
Find2ConvTestCase tc{std::get<0>(param),
std::get<1>(param),
std::get<2>(param),
std::get<3>(param),
std::get<4>(param)};
RunFind2ConvTest(tc);
}
inline std::string
GetFind2ConvTestCaseName(const testing::TestParamInfo<GPU_Find2Conv_FP32::ParamType>& info)
{
Find2ConvTestCase tc{std::get<0>(info.param),
std::get<1>(info.param),
std::get<2>(info.param),
std::get<3>(info.param),
std::get<4>(info.param)};
std::ostringstream os;
os << tc;
std::string name = os.str();
std::replace_if(name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_');
return name;
}
INSTANTIATE_TEST_SUITE_P(Smoke,
GPU_Find2Conv_FP32,
testing::Combine(testing::Values(miopenProblemDirectionForward,
miopenProblemDirectionBackward,
miopenProblemDirectionBackwardWeights),
testing::Values(0, 1),
testing::Values(false, true),
testing::Values(std::numeric_limits<std::size_t>::max(),
static_cast<std::size_t>(0)),
testing::Values(false, true)),
GetFind2ConvTestCaseName);