Files
TheRock/rocm-systems/projects/hip-tests/catch/unit/memory/hipArrayCreate.cc
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

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(&copyParams));
}
}
// 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);
}