EXSWHTEC-91 - Implement tests for memcpy of 1D/2D hipArray (#32)

- Implement tests for hipMemcpyAtoH using resource guards and templates
- Implement tests for hipMemcpyHtoA using resource guards and templates
- Implement tests for hipMemcpy2DFromArray using resource guards and templates
- Implement tests for hipMemcpy2DToArray using resource guards and templates

[ROCm/hip-tests commit: 9d62df85a1]
This commit is contained in:
nives-vukovic
2023-01-17 12:56:17 +01:00
committed by GitHub
parent 8a141b0b91
commit 042cdb088a
9 changed files with 1720 additions and 956 deletions
@@ -1,5 +1,5 @@
/*
Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
@@ -16,317 +16,234 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This file verifies the following scenarios of hipMemcpy2DToArray API
1. Negative Scenarios
2. Extent Validation Scenarios
3. hipMemcpy2DToArray Basic Scenario
4. Pinned Memory scenarios on same and peer GPU
5. Device Context change scenario where memory is allocated in
one GPU and API is triggered from peer GPU.
Testcase Scenarios :
Unit_hipMemcpy2DToArray_Positive_Default - Test basic memcpy between host/device
and 2D array with hipMemcpy2DToArray api
Unit_hipMemcpy2DToArray_Positive_Synchronization_Behavior - Test synchronization
behavior for hipMemcpy2DToArray api
Unit_hipMemcpy2DToArray_Positive_ZeroWidthHeight - Test that no data is copied
when width/height is set to 0 Unit_hipMemcpy2DToArray_Negative_Parameters - Test
unsuccessful execution of hipMemcpy2DToArray api when parameters are invalid
*/
#include "array_memcpy_tests_common.hh"
#include <hip/hip_runtime_api.h>
#include <hip_test_common.hh>
#include <hip_test_checkers.hh>
#include <iostream>
#include <resource_guards.hh>
#include <utils.hh>
static constexpr auto NUM_W{10};
static constexpr auto NUM_H{10};
/*
* This Scenario copies the data from host to device
* INPUT: Copying Host variable hData(Initialized with value Phi(1.618))
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Basic") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_Default") {
using namespace std::placeholders;
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(1, 16, 32, 48);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This testcase verifies the extent validation scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_ExtentValidation") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Source width is 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0, hData, 0,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with height 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Height is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
width, 0, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
}
// hipMemcpy2DToArray API would return success for width and height as 0
// and does not perform any copy
// Validating the result with the initialized value
// 1.Initializing A_d with Pi value
// 2.copying hData(Phi)-->A_d device variable
// with width 0(copy will not be performed)
// 3.copying A_d-->hData and validating it with A_h data
SECTION("Width is 0") {
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
A_h, width, width,
NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0,
hData, width,
0, NUM_H, hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(hData, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(hData, A_h, NUM_W, NUM_H) == true);
SECTION("Host to Array") {
Memcpy2DHosttoAShell<false, int>(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3,
width * sizeof(int), height, hipMemcpyHostToDevice),
width, height);
}
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device on same GPU
* INPUT: Copying Host variable PinnMem(Initialized with value "10" )
* --> A_d device variable
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with PinnedMem[0](i.e., 10)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_PinnedMemSameGPU") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
constexpr auto def_val{10};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *PinnMem{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&PinnMem), width * NUM_H));
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
for (int i = 0; i < NUM_W*NUM_H; i++) {
PinnMem[i] = def_val + i;
SECTION("Host to Array with default kind") {
Memcpy2DHosttoAShell<false, int>(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3,
width * sizeof(int), height, hipMemcpyDefault),
width, height);
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, PinnMem,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, PinnMem, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(PinnMem));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
}
/*
* This Scenario Verifies hipMemcpy2DToArray API by copying the
* data from pinned host memory to device from Peer GPU.
* Device Memory is allocated in GPU 0 and the API is trigerred from GPU1
* INPUT: Copying Host variable E_h(Initialized with value 10+i(numelements))
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with E_h[0]+i(i.e., 10+i)
*/
TEST_CASE("Unit_hipMemcpy2DToArray_multiDevicePinnedMemPeerGpu") {
int numDevices = 0;
constexpr auto def_val{10};
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *E_h{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, nullptr, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, nullptr, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&E_h), width * NUM_H));
for (int i = 0; i < NUM_W*NUM_H; i++) {
E_h[i] = def_val + i;
}
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, E_h,
width, width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipSetDevice(0));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, E_h, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HIP_CHECK(hipHostFree(E_h));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, nullptr, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
#if HT_NVIDIA // EXSWHTEC-120
SECTION("Device to Array") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<false, false, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/*
* This scenario verifies the hipMemcpy2DToArray API in case of device
* context change.
* Memory is allocated in GPU-0 and the API is triggered from GPU-1
* INPUT: Copying Host variable hData(Initial value Phi)
* --> A_d device variable
* whose memory is allocated in GPU 0
* OUTPUT: For validating the result,Copying A_d device variable
* --> A_h host variable
* and verifying A_h with Phi
* */
TEST_CASE("Unit_hipMemcpy2DToArray_multiDeviceDeviceContextChange") {
int numDevices = 0;
HIP_CHECK(hipGetDeviceCount(&numDevices));
if (numDevices > 1) {
int canAccessPeer = 0;
HIP_CHECK(hipDeviceCanAccessPeer(&canAccessPeer, 0, 1));
if (canAccessPeer) {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
HIP_CHECK(hipSetDevice(1));
HIP_CHECK(hipMemcpy2DToArray(A_d, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice));
HIP_CHECK(hipMemcpy2DFromArray(A_h, width, A_d,
0, 0, width, NUM_H,
hipMemcpyDeviceToHost));
REQUIRE(HipTest::checkArray(A_h, hData, NUM_W, NUM_H) == true);
// Cleaning the memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
} else {
SUCCEED("Machine Does not have P2P capability");
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<false, true, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDeviceToDevice),
width, height);
}
} else {
SUCCEED("Number of devices are < 2");
}
}
/* This testcase verifies the negative scenarios
*/
TEST_CASE("Unit_hipMemcpy2DToArray_Negative") {
HIP_CHECK(hipSetDevice(0));
hipArray *A_d{nullptr};
size_t width{sizeof(float)*NUM_W};
float *A_h{nullptr}, *hData{nullptr};
// Initialization of variables
HipTest::initArrays<float>(nullptr, nullptr, nullptr,
&A_h, &hData, nullptr,
width*NUM_H, false);
HipTest::setDefaultData<float>(width*NUM_H, A_h, hData, nullptr);
hipChannelFormatDesc desc = hipCreateChannelDesc<float>();
HIP_CHECK(hipMallocArray(&A_d, &desc, NUM_W, NUM_H, hipArrayDefault));
SECTION("Nullptr to destination") {
REQUIRE(hipMemcpy2DToArray(nullptr, 0, 0, hData, width,
width, NUM_H,
hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Nullptr to source") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
nullptr, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
SECTION("Device to Array with default kind") {
SECTION("Peer access disabled") {
Memcpy2DDevicetoAShell<false, false, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
SECTION("Peer access enabled") {
Memcpy2DDevicetoAShell<false, true, int>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), height,
hipMemcpyDefault),
width, height);
}
}
SECTION("Passing offset more than 0") {
REQUIRE(hipMemcpy2DToArray(A_d, 1, 1,
hData, width, width,
NUM_H, hipMemcpyHostToDevice) != hipSuccess);
}
SECTION("Passing array more than allocated") {
REQUIRE(hipMemcpy2DToArray(A_d, 0, 0,
hData, width, width+2,
NUM_H+2, hipMemcpyHostToDevice) != hipSuccess);
}
// Cleaning of memory
HIP_CHECK(hipFreeArray(A_d));
HipTest::freeArrays<float>(nullptr, nullptr, nullptr,
A_h, hData, nullptr, false);
#endif
}
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_Synchronization_Behavior") {
using namespace std::placeholders;
HIP_CHECK(hipDeviceSynchronize());
SECTION("Host to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyHtoASyncBehavior(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
width, height, true);
}
#if HT_NVIDIA // EXSWHTEC-214
SECTION("Device to Array") {
const auto width = GENERATE(16, 32, 48);
const auto height = GENERATE(16, 32, 48);
MemcpyDtoASyncBehavior(std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int),
height, hipMemcpyDeviceToDevice),
width, height, false);
}
#endif
}
TEST_CASE("Unit_hipMemcpy2DToArray_Positive_ZeroWidthHeight") {
using namespace std::placeholders;
const auto width = 16;
const auto height = 16;
SECTION("Array to host") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyHostToDevice),
width, height);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, 0, height, hipMemcpyHostToDevice), width,
height);
}
}
SECTION("Array to device") {
SECTION("Height is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, width * sizeof(int), 0,
hipMemcpyDeviceToDevice),
width, height);
}
SECTION("Width is 0") {
Memcpy2DToArrayZeroWidthHeight<false>(
std::bind(hipMemcpy2DToArray, _1, 0, 0, _2, _3, 0, height, hipMemcpyDeviceToDevice),
width, height);
}
}
}
TEST_CASE("Unit_hipMemcpy2DToArray_Negative_Parameters") {
using namespace std::placeholders;
const auto width = 32;
const auto height = 32;
const auto allocation_size = 2 * width * height * sizeof(int);
const unsigned int flag = hipArrayDefault;
ArrayAllocGuard<int> array_alloc(make_hipExtent(width, height, 0), flag);
LinearAllocGuard2D<int> device_alloc(width, height);
LinearAllocGuard<int> host_alloc(LinearAllocs::hipHostMalloc, allocation_size);
SECTION("Host to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(nullptr, 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, nullptr, 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("spitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), width * sizeof(int) - 10,
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 1, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 1, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int) + 1, height, hipMemcpyHostToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height + 1, hipMemcpyHostToDevice),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, host_alloc.ptr(), 2 * width * sizeof(int),
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
SECTION("Device to Array") {
SECTION("dst == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(nullptr, 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidHandle);
}
SECTION("src == nullptr") {
HIP_CHECK_ERROR(hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, nullptr, device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
#if HT_NVIDIA // EXSWHTEC-119
SECTION("spitch < width") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), width * sizeof(int) - 10,
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidPitchValue);
}
SECTION("Offset + width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 1, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 1, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Width/height overflows") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int) + 1, height, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height + 1, hipMemcpyDeviceToDevice),
hipErrorInvalidValue);
}
SECTION("Memcpy kind is invalid") {
HIP_CHECK_ERROR(
hipMemcpy2DToArray(array_alloc.ptr(), 0, 0, device_alloc.ptr(), device_alloc.pitch(),
width * sizeof(int), height, static_cast<hipMemcpyKind>(-1)),
hipErrorInvalidMemcpyDirection);
}
#endif
}
}