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
353 lines
11 KiB
C++
353 lines
11 KiB
C++
/*
|
|
* Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
/*
|
|
hipArrayCreate API test scenarios
|
|
1. Negative Scenarios
|
|
2. Allocating Small and big chunk data
|
|
3. Multithreaded scenario
|
|
*/
|
|
|
|
#include <array>
|
|
#include <numeric>
|
|
#include <hip_test_common.hh>
|
|
#include <hip_array_common.hh>
|
|
#include "hipArrayCommon.hh"
|
|
#include "DriverContext.hh"
|
|
|
|
static constexpr size_t NUM_W{4};
|
|
static constexpr size_t BIGNUM_W{100};
|
|
static constexpr size_t NUM_H{4};
|
|
static constexpr size_t BIGNUM_H{100};
|
|
static constexpr auto ARRAY_LOOP{100};
|
|
|
|
/*
|
|
* This API verifies memory allocations for small and
|
|
* bigger chunks of data.
|
|
* Two scenarios are verified in this API
|
|
* 1. SmallArray: Allocates NUM_W*NUM_H in a loop and
|
|
* releases the memory.
|
|
* 2. BigArray: Allocates BIGNUM_W*BIGNUM_H in a loop and
|
|
* releases the memory.
|
|
*
|
|
*/
|
|
|
|
static void ArrayCreate_DiffSizes(int gpu) {
|
|
HIP_CHECK_THREAD(hipSetDevice(gpu));
|
|
// Use of GENERATE in thead function causes random failures with multithread condition.
|
|
std::vector<std::pair<size_t, size_t>> runs{std::make_pair(NUM_W, NUM_H),
|
|
std::make_pair(BIGNUM_W, BIGNUM_H)};
|
|
for (const auto& size : runs) {
|
|
std::array<HIP_ARRAY, ARRAY_LOOP> array;
|
|
size_t pavail;
|
|
HIP_CHECK_THREAD(hipMemGetInfo(&pavail, nullptr));
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.NumChannels = 1;
|
|
desc.Width = std::get<0>(size);
|
|
desc.Height = std::get<1>(size);
|
|
desc.Format = HIP_AD_FORMAT_FLOAT;
|
|
|
|
for (int i = 0; i < ARRAY_LOOP; i++) {
|
|
HIP_CHECK_THREAD(hipArrayCreate(&array[i], &desc));
|
|
}
|
|
for (int i = 0; i < ARRAY_LOOP; i++) {
|
|
HIP_CHECK_THREAD(hipArrayDestroy(array[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This testcase verifies hipArrayCreate API for small and big chunks data*/
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_DiffSizes) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
ArrayCreate_DiffSizes(0);
|
|
HIP_CHECK_THREAD_FINALIZE();
|
|
}
|
|
|
|
/*
|
|
This testcase verifies the hipArrayCreate API in multithreaded
|
|
scenario by launching threads in parallel on multiple GPUs
|
|
and verifies the hipArrayCreate API with small and big chunks data
|
|
*/
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_MultiThread) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
std::vector<std::thread> threadlist;
|
|
int devCnt = 0;
|
|
|
|
devCnt = HipTest::getDeviceCount();
|
|
|
|
for (int i = 0; i < devCnt; i++) {
|
|
threadlist.push_back(std::thread(ArrayCreate_DiffSizes, i));
|
|
}
|
|
|
|
for (auto& t : threadlist) {
|
|
t.join();
|
|
}
|
|
HIP_CHECK_THREAD_FINALIZE();
|
|
}
|
|
|
|
|
|
// Tests /////////////////////////////////////////
|
|
|
|
#if HT_AMD
|
|
constexpr auto NORMALIZED_COORDINATES = HIP_TRSF_NORMALIZED_COORDINATES;
|
|
constexpr auto READ_AS_INTEGER = HIP_TRSF_READ_AS_INTEGER;
|
|
#else
|
|
// (EXSWCPHIPT-92) HIP equivalents not defined for CUDA backend.
|
|
constexpr auto NORMALIZED_COORDINATES = CU_TRSF_NORMALIZED_COORDINATES;
|
|
constexpr auto READ_AS_INTEGER = CU_TRSF_READ_AS_INTEGER;
|
|
#endif
|
|
|
|
// Copy data from host to the hipArray_t, accounting 1D or 2D arrays
|
|
template <typename T>
|
|
void copyToArray(hipArray_t dst, const std::vector<T>& src, const size_t height) {
|
|
const auto sizeInBytes = src.size() * sizeof(T);
|
|
if (height == 0) {
|
|
// FIXME(EXSWCPHIPT-64) remove cast when API is fixed (will require major version change)
|
|
HIP_CHECK(hipMemcpyHtoA(reinterpret_cast<hipArray_t>(dst), 0, src.data(), sizeInBytes));
|
|
} else {
|
|
const auto pitch = sizeInBytes / height;
|
|
hip_Memcpy2D copyParams{};
|
|
copyParams.srcMemoryType = hipMemoryTypeHost;
|
|
copyParams.srcXInBytes = 0; // x offset
|
|
copyParams.srcY = 0; // y offset
|
|
copyParams.srcHost = src.data();
|
|
copyParams.srcPitch = pitch;
|
|
|
|
copyParams.dstMemoryType = hipMemoryTypeArray;
|
|
copyParams.dstXInBytes = 0; // x offset
|
|
copyParams.dstY = 0; // y offset
|
|
copyParams.dstArray = dst;
|
|
|
|
copyParams.WidthInBytes = pitch;
|
|
copyParams.Height = height;
|
|
|
|
HIP_CHECK(hipMemcpyParam2D(©Params));
|
|
}
|
|
}
|
|
|
|
// Test the allocated array by generating a texture from it then reading from that texture.
|
|
// Textures are read-only, so write to the array then copy that into normal device memory.
|
|
template <typename T>
|
|
void testArrayAsTexture(hipArray_t array, const size_t width, const size_t height) {
|
|
using vec_info = vector_info<T>;
|
|
using scalar_type = typename vec_info::type;
|
|
const auto h = height ? height : 1;
|
|
const auto size = sizeof(T) * width * h;
|
|
|
|
// set hip array
|
|
std::vector<scalar_type> hostData(width * h * vec_info::size);
|
|
// assigned ascending values to the data array to show indexing is working
|
|
std::iota(std::begin(hostData), std::end(hostData), 0);
|
|
|
|
copyToArray(array, hostData, height);
|
|
|
|
// create texture
|
|
hipTextureObject_t textObj{};
|
|
|
|
HIP_RESOURCE_DESC resDesc{};
|
|
memset(&resDesc, 0, sizeof(HIP_RESOURCE_DESC));
|
|
resDesc.resType = HIP_RESOURCE_TYPE_ARRAY;
|
|
resDesc.res.array.hArray = array;
|
|
resDesc.flags = 0;
|
|
|
|
HIP_TEXTURE_DESC texDesc{};
|
|
memset(&texDesc, 0, sizeof(HIP_TEXTURE_DESC));
|
|
// use the actual values in the texture, not normalized data
|
|
texDesc.filterMode = HIP_TR_FILTER_MODE_POINT;
|
|
// Use normalized coordinates and also read the data in the original data type
|
|
texDesc.flags |= NORMALIZED_COORDINATES | READ_AS_INTEGER;
|
|
|
|
HIP_CHECK(hipTexObjectCreate(&textObj, &resDesc, &texDesc, nullptr));
|
|
|
|
// run kernel
|
|
T* device_data{};
|
|
HIP_CHECK(hipMalloc(&device_data, size));
|
|
readFromTexture<<<dim3(width / BlockSize, height ? height / BlockSize : 1, 1),
|
|
dim3(BlockSize, height ? BlockSize : 1, 1)>>>(device_data, textObj, width,
|
|
height, false);
|
|
HIP_CHECK(hipGetLastError()); // check for errors when running the kernel
|
|
|
|
// copy data back and then test it
|
|
std::fill(std::begin(hostData), std::end(hostData), 0);
|
|
HIP_CHECK(hipMemcpy(hostData.data(), device_data, size, hipMemcpyDeviceToHost));
|
|
|
|
#if !__HIP_NO_IMAGE_SUPPORT
|
|
checkDataIsAscending(hostData);
|
|
#endif
|
|
|
|
// clean up
|
|
HIP_CHECK(hipTexObjectDestroy(textObj));
|
|
HIP_CHECK(hipFree(device_data));
|
|
}
|
|
|
|
// Selection of types chosen since trying all types would be slow to compile
|
|
// Test the happy path of the hipArrayCreate
|
|
HIP_TEMPLATE_TEST_CASE(Unit_hipArrayCreate_happy, uint, int, int4, ushort, short2, char, uchar2,
|
|
char4, float, float2, float4) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
using vec_info = vector_info<TestType>;
|
|
DriverContext ctx;
|
|
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.Format = vec_info::format;
|
|
desc.NumChannels = vec_info::size;
|
|
desc.Width = 1024;
|
|
desc.Height = GENERATE(0, 1024);
|
|
|
|
// pointer to the array in device memory
|
|
hipArray_t array{};
|
|
|
|
HIP_CHECK(hipArrayCreate(&array, &desc));
|
|
|
|
testArrayAsTexture<TestType>(array, desc.Width, desc.Height);
|
|
|
|
HIP_CHECK(hipArrayDestroy(array));
|
|
}
|
|
|
|
|
|
// Only widths and Heights up to the maxTexture size is supported
|
|
HIP_TEMPLATE_TEST_CASE(Unit_hipArrayCreate_maxTexture, uint, int, int4, ushort, short2, char,
|
|
uchar2, char4, float, float2, float4) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
using vec_info = vector_info<TestType>;
|
|
DriverContext ctx;
|
|
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.Format = vec_info::format;
|
|
desc.NumChannels = vec_info::size;
|
|
|
|
const Sizes sizes(hipArrayDefault);
|
|
const size_t s = 64;
|
|
|
|
hipArray_t array{};
|
|
SECTION("Happy") {
|
|
SECTION("1D - Max") {
|
|
desc.Width = sizes.max1D;
|
|
desc.Height = 0;
|
|
}
|
|
SECTION("2D - Max Width") {
|
|
desc.Width = sizes.max2D[0];
|
|
desc.Height = s;
|
|
}
|
|
SECTION("2D - Max Height") {
|
|
desc.Width = s;
|
|
desc.Height = sizes.max2D[1];
|
|
}
|
|
SECTION("2D - Max Width and Height") {
|
|
desc.Width = sizes.max2D[0];
|
|
desc.Height = sizes.max2D[1];
|
|
}
|
|
auto maxArrayCreateError = hipArrayCreate(&array, &desc);
|
|
// this can try to alloc many GB of memory, so out of memory is acceptable
|
|
// return to avoid destroy
|
|
if (maxArrayCreateError == hipErrorOutOfMemory) return;
|
|
HIP_CHECK(maxArrayCreateError);
|
|
HIP_CHECK(hipArrayDestroy(array));
|
|
}
|
|
SECTION("Negative") {
|
|
SECTION("1D - More Than Max") {
|
|
desc.Width = sizes.max1D + 1;
|
|
desc.Height = 0;
|
|
}
|
|
SECTION("2D - More Than Max Width") {
|
|
desc.Width = sizes.max2D[0] + 1;
|
|
desc.Height = s;
|
|
}
|
|
SECTION("2D - More Than Max Height") {
|
|
desc.Width = s;
|
|
desc.Height = sizes.max2D[1] + 1;
|
|
}
|
|
SECTION("2D - More Than Max Width and Height") {
|
|
desc.Width = sizes.max2D[0] + 1;
|
|
desc.Height = sizes.max2D[1] + 1;
|
|
}
|
|
HIP_CHECK_ERROR(hipArrayCreate(&array, &desc), hipErrorInvalidValue);
|
|
}
|
|
}
|
|
|
|
// zero-width array is not supported
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_ZeroWidth) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
DriverContext ctx;
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.Format = driverFormats[0];
|
|
desc.NumChannels = 4;
|
|
desc.Width = 0;
|
|
desc.Height = GENERATE(0, 1024);
|
|
|
|
// pointer to the array in device memory
|
|
hipArray_t array;
|
|
HIP_CHECK_ERROR(hipArrayCreate(&array, &desc), hipErrorInvalidValue);
|
|
}
|
|
|
|
// HipArrayCreate will return an error when nullptr is used as the array argument
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_Nullptr) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
DriverContext ctx;
|
|
SECTION("Null array") {
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.Format = driverFormats[0];
|
|
desc.NumChannels = 4;
|
|
desc.Width = 1024;
|
|
desc.Height = 1024;
|
|
|
|
HIP_CHECK_ERROR(hipArrayCreate(nullptr, &desc), hipErrorInvalidValue);
|
|
}
|
|
SECTION("Null Description") {
|
|
hipArray_t array;
|
|
HIP_CHECK_ERROR(hipArrayCreate(&array, nullptr), hipErrorInvalidValue);
|
|
}
|
|
}
|
|
|
|
// Only elements with 1,2, or 4 channels is supported
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_BadNumberChannelElement) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
DriverContext ctx;
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
desc.Format = GENERATE(from_range(std::begin(driverFormats), std::end(driverFormats)));
|
|
desc.NumChannels = GENERATE(-1, 0, 3, 5, 8);
|
|
desc.Width = 1024;
|
|
desc.Height = GENERATE(0, 1024);
|
|
|
|
hipArray_t array;
|
|
|
|
INFO("Format: " << formatToString(desc.Format) << " NumChannels: " << desc.NumChannels
|
|
<< " Height: " << desc.Height);
|
|
HIP_CHECK_ERROR(hipArrayCreate(&array, &desc), hipErrorInvalidValue);
|
|
}
|
|
|
|
// Only certain channel formats are acceptable.
|
|
HIP_TEST_CASE(Unit_hipArrayCreate_BadChannelFormat) {
|
|
CHECK_IMAGE_SUPPORT
|
|
|
|
DriverContext ctx;
|
|
HIP_ARRAY_DESCRIPTOR desc;
|
|
|
|
// create a bad format
|
|
desc.Format =
|
|
std::accumulate(std::begin(driverFormats), std::end(driverFormats), driverFormats[0],
|
|
[](auto i, auto f) { return static_cast<decltype(desc.Format)>(i + f); });
|
|
for (auto&& format : driverFormats) {
|
|
REQUIRE(desc.Format != format);
|
|
}
|
|
|
|
desc.NumChannels = 4;
|
|
desc.Width = 1024;
|
|
desc.Height = GENERATE(0, 1024);
|
|
|
|
hipArray_t array;
|
|
|
|
INFO("Format: " << formatToString(desc.Format) << " Height: " << desc.Height);
|
|
HIP_CHECK_ERROR(hipArrayCreate(&array, &desc), hipErrorInvalidValue);
|
|
}
|