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
316 lines
11 KiB
C++
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);
|