From f7be53ba7508a1561b2685dda1374e1c483ad41f Mon Sep 17 00:00:00 2001 From: sumanthtg <90063301+sumanthtg@users.noreply.github.com> Date: Fri, 17 Sep 2021 11:37:05 +0530 Subject: [PATCH 1/9] SWDEV-294470 - [dtest] Catch2 unit tests for memset related tests. (#2345) Change-Id: Ib227e75cb0bef9273bc787e47fa5b713086fac46 --- tests/catch/unit/memory/CMakeLists.txt | 8 + tests/catch/unit/memory/hipMemset.cc | 281 ++++++++++++++++++ .../unit/memory/hipMemsetAsyncAndKernel.cc | 193 ++++++++++++ .../unit/memory/hipMemsetAsyncMultiThread.cc | 243 +++++++++++++++ .../catch/unit/memory/hipMemsetInvalidPtr.cc | 127 ++++++++ 5 files changed, 852 insertions(+) create mode 100644 tests/catch/unit/memory/hipMemset.cc create mode 100644 tests/catch/unit/memory/hipMemsetAsyncAndKernel.cc create mode 100644 tests/catch/unit/memory/hipMemsetAsyncMultiThread.cc create mode 100644 tests/catch/unit/memory/hipMemsetInvalidPtr.cc diff --git a/tests/catch/unit/memory/CMakeLists.txt b/tests/catch/unit/memory/CMakeLists.txt index d9e688d167..093b6d8ba9 100644 --- a/tests/catch/unit/memory/CMakeLists.txt +++ b/tests/catch/unit/memory/CMakeLists.txt @@ -33,6 +33,10 @@ set(TEST_SRC hipMemoryAllocateCoherent.cc hipMallocManaged_MultiScenario.cc hipManagedKeyword.cc + hipMemsetInvalidPtr.cc + hipMemset.cc + hipMemsetAsyncMultiThread.cc + hipMemsetAsyncAndKernel.cc ) else() set(TEST_SRC @@ -66,6 +70,10 @@ set(TEST_SRC hipMemoryAllocateCoherent.cc hipMallocManaged_MultiScenario.cc hipManagedKeyword.cc + hipMemsetInvalidPtr.cc + hipMemset.cc + hipMemsetAsyncMultiThread.cc + hipMemsetAsyncAndKernel.cc ) endif() # Create shared lib of all tests diff --git a/tests/catch/unit/memory/hipMemset.cc b/tests/catch/unit/memory/hipMemset.cc new file mode 100644 index 0000000000..600a008436 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset.cc @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** +Testcase Scenarios : + 1) Test hipMemset small size buffers with unique memset values. + 2) Test hipMemset, hipMemsetD8, hipMemsetD16, hipMemsetD32 apis with unique + number of elements and memset values. + 3) Test hipMemsetAsync, hipMemsetD8Async, hipMemsetD16Async, hipMemsetD32Async + apis with unique number of elements and memset values. + 4) Test two memset async operations at the same time. +*/ + + +#include + + +// Table with unique number of elements and memset values. +// (N, memsetval, memsetD32val, memsetD16val, memsetD8val) +typedef std::tuple tupletype; +static constexpr std::initializer_list tableItems { + std::make_tuple((4*1024*1024), 0x42, 0xDEADBEEF, 0xDEAD, 0xDE), + std::make_tuple((10) , 0x42, 0x101 , 0x10, 0x1), + std::make_tuple((10013) , 0x5a, 0xDEADBEEF, 0xDEAD, 0xDE), + std::make_tuple((256*1024*1024), 0xa6, 0xCAFEBABE, 0xCAFE, 0xCA) + }; + +enum MemsetType { + hipMemsetTypeDefault, + hipMemsetTypeD8, + hipMemsetTypeD16, + hipMemsetTypeD32 +}; + +template +static bool testhipMemset(T *A_h, T *A_d, T memsetval, enum MemsetType type, + size_t numElements) { + size_t Nbytes = numElements * sizeof(T); + bool testResult = true; + constexpr auto MAX_OFFSET = 3; // To memset on unaligned ptr. + + HIP_CHECK(hipMalloc(&A_d, Nbytes)); + A_h = reinterpret_cast (malloc(Nbytes)); + REQUIRE(A_h != nullptr); + + for (int offset = MAX_OFFSET; offset >= 0; offset --) { + if (type == hipMemsetTypeDefault) { + HIP_CHECK(hipMemset(A_d + offset, memsetval, numElements - offset)); + + } else if (type == hipMemsetTypeD8) { + HIP_CHECK(hipMemsetD8((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset)); + + } else if (type == hipMemsetTypeD16) { + HIP_CHECK(hipMemsetD16((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset)); + + } else if (type == hipMemsetTypeD32) { + HIP_CHECK(hipMemsetD32((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset)); + } + + HIP_CHECK(hipMemcpy(A_h, A_d, Nbytes, hipMemcpyDeviceToHost)); + for (size_t i = offset; i < numElements; i++) { + if (A_h[i] != memsetval) { + testResult = false; + CAPTURE(i, A_h[i], memsetval); + break; + } + } + } + + HIP_CHECK(hipFree(A_d)); + free(A_h); + return testResult; +} + + +template +static bool testhipMemsetAsync(T *A_h, T *A_d, T memsetval, + enum MemsetType type, size_t numElements) { + size_t Nbytes = numElements * sizeof(T); + bool testResult = true; + constexpr auto MAX_OFFSET = 3; // To memset on unaligned ptr. + hipStream_t stream; + + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMalloc(&A_d, Nbytes)); + A_h = reinterpret_cast (malloc(Nbytes)); + REQUIRE(A_h != nullptr); + + for (int offset = MAX_OFFSET; offset >= 0; offset --) { + if (type == hipMemsetTypeDefault) { + HIP_CHECK(hipMemsetAsync(A_d + offset, memsetval, numElements - offset, + stream)); + + } else if (type == hipMemsetTypeD8) { + HIP_CHECK(hipMemsetD8Async((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset, stream)); + + } else if (type == hipMemsetTypeD16) { + HIP_CHECK(hipMemsetD16Async((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset, stream)); + + } else if (type == hipMemsetTypeD32) { + HIP_CHECK(hipMemsetD32Async((hipDeviceptr_t)(A_d + offset), memsetval, + numElements - offset, stream)); + } + + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipMemcpy(A_h, A_d, Nbytes, hipMemcpyDeviceToHost)); + for (size_t i = offset; i < numElements; i++) { + if (A_h[i] != memsetval) { + testResult = false; + CAPTURE(i, A_h[i], memsetval); + break; + } + } + } + + HIP_CHECK(hipFree(A_d)); + HIP_CHECK(hipStreamDestroy(stream)); + free(A_h); + return testResult; +} + + +/** + * Test hipMemset, hipMemsetD8, hipMemsetD16, hipMemsetD32 apis with unique + * number of elements and memset values. + */ +TEST_CASE("Unit_hipMemset_SetMemoryWithOffset") { + char memsetval; + int memsetD32val; + int16_t memsetD16val; + char memsetD8val; + size_t N; + bool ret; + + std::tie(N, memsetval, memsetD32val, memsetD16val, memsetD8val) = + GENERATE(table(tableItems)); + + + SECTION("Memset with hipMemsetTypeDefault") { + char *cA_d{nullptr}, *cA_h{nullptr}; + ret = testhipMemset(cA_h, cA_d, memsetval, hipMemsetTypeDefault, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD32") { + int32_t *iA_d{nullptr}, *iA_h{nullptr}; + ret = testhipMemset(iA_h, iA_d, memsetD32val, hipMemsetTypeD32, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD16") { + int16_t *siA_d{nullptr}, *siA_h{nullptr}; + ret = testhipMemset(siA_h, siA_d, memsetD16val, hipMemsetTypeD16, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD8") { + char *cA_d{nullptr}, *cA_h{nullptr}; + ret = testhipMemset(cA_h, cA_d, memsetD8val, hipMemsetTypeD8, N); + REQUIRE(ret == true); + } +} + + +/** + * Test hipMemsetAsync, hipMemsetD8Async, hipMemsetD16Async, hipMemsetD32Async + * apis with unique number of elements and memset values. + */ +TEST_CASE("Unit_hipMemsetAsync_SetMemoryWithOffset") { + char memsetval; + int memsetD32val; + int16_t memsetD16val; + char memsetD8val; + size_t N; + bool ret; + + std::tie(N, memsetval, memsetD32val, memsetD16val, memsetD8val) = + GENERATE(table(tableItems)); + + + SECTION("Memset with hipMemsetTypeDefault") { + char *cA_d{nullptr}, *cA_h{nullptr}; + ret = testhipMemsetAsync(cA_h, cA_d, memsetval, hipMemsetTypeDefault, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD32") { + int32_t *iA_d{nullptr}, *iA_h{nullptr}; + ret = testhipMemsetAsync(iA_h, iA_d, memsetD32val, hipMemsetTypeD32, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD16") { + int16_t *siA_d{nullptr}, *siA_h{nullptr}; + ret = testhipMemsetAsync(siA_h, siA_d, memsetD16val, hipMemsetTypeD16, N); + REQUIRE(ret == true); + } + + SECTION("Memset with hipMemsetTypeD8") { + char *cA_d{nullptr}, *cA_h{nullptr}; + ret = testhipMemsetAsync(cA_h, cA_d, memsetD8val, hipMemsetTypeD8, N); + REQUIRE(ret == true); + } +} + +/** + * Test hipMemset small size buffers with unique memset values. + */ +TEST_CASE("Unit_hipMemset_SmallBufferSizes") { + char *A_d, *A_h; + constexpr int memsetval = 0x24; + + auto numElements = GENERATE(range(1, 4)); + int numBytes = numElements * sizeof(char); + + HIP_CHECK(hipMalloc(&A_d, numBytes)); + A_h = reinterpret_cast (malloc(numBytes)); + + HIP_CHECK(hipMemset(A_d, memsetval, numBytes)); + HIP_CHECK(hipMemcpy(A_h, A_d, numBytes, hipMemcpyDeviceToHost)); + + for (int i = 0; i < numBytes; i++) { + if (A_h[i] != memsetval) { + INFO("Mismatch at index:" << i << " computed:" << A_h[i] + << " memsetval:" << memsetval); + REQUIRE(false); + } + } + + HIP_CHECK(hipFree(A_d)); + free(A_h); +} + + +/** + * Test two memset async operations at the same time. + */ +TEST_CASE("Unit_hipMemset_2AsyncOperations") { + std::vector v; + v.resize(2048); + float* p2, *p3; + hipMalloc(reinterpret_cast(&p2), 4096 + 4096*2); + p3 = p2+2048; + hipStream_t s; + hipStreamCreate(&s); + hipMemsetAsync(p2, 0, 32*32*4, s); + hipMemsetD32Async((hipDeviceptr_t)p3, 0x3fe00000, 32*32, s); + hipStreamSynchronize(s); + for (int i = 0; i < 256; ++i) { + hipMemsetAsync(p2, 0, 32*32*4, s); + hipMemsetD32Async((hipDeviceptr_t)p3, 0x3fe00000, 32*32, s); + } + hipStreamSynchronize(s); + hipDeviceSynchronize(); + hipMemcpy(&v[0], p2, 1024, hipMemcpyDeviceToHost); + hipMemcpy(&v[1024], p3, 1024, hipMemcpyDeviceToHost); + + REQUIRE(v[0] == 0); + REQUIRE(v[1024] == 1.75f); +} diff --git a/tests/catch/unit/memory/hipMemsetAsyncAndKernel.cc b/tests/catch/unit/memory/hipMemsetAsyncAndKernel.cc new file mode 100644 index 0000000000..adbd4a3964 --- /dev/null +++ b/tests/catch/unit/memory/hipMemsetAsyncAndKernel.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. +*/ + +/* + * Test for checking order of execution of device kernel and + * hipMemsetAsync apis on all gpus + */ + +#include +#include +#include + +#define ITER 6 +#define N 1024 * 1024 + +constexpr auto blocksPerCU = 6; // to hide latency +constexpr auto threadsPerBlock = 256; +static unsigned blocks = 0; + + +template +class MemSetKernelTest { + public: + T *A_h, *B_d, *B_h, *C_d; + T memSetVal; + size_t Nbytes; + bool testResult = true; + int validateCount = 0; + hipStream_t stream; + + void memAllocate(T memSetValue) { + memSetVal = memSetValue; + Nbytes = N * sizeof(T); + + A_h = reinterpret_cast(malloc(Nbytes)); + HIP_ASSERT(A_h != nullptr); + HIP_CHECK(hipMalloc(&B_d , Nbytes)); + B_h = reinterpret_cast(malloc(Nbytes)); + HIP_ASSERT(B_h != nullptr); + HIP_CHECK(hipMalloc(&C_d , Nbytes)); + + for (int i = 0 ; i < N ; i++) { + B_h[i] = i; + } + HIP_CHECK(hipMemcpy(B_d , B_h , Nbytes , hipMemcpyHostToDevice)); + HIP_CHECK(hipStreamCreate(&stream)); + } + + void memDeallocate() { + HIP_CHECK(hipFree(B_d)); HIP_CHECK(hipFree(C_d)); + free(B_h); free(A_h); + HIP_CHECK(hipStreamDestroy(stream)); + } + + void validateExecutionOrder() { + for (int p = 0 ; p < N ; p++) { + if (A_h[p] == memSetVal) { + validateCount+= 1; + } + } + } + + bool resultAfterAllIterations() { + testResult = (validateCount == (ITER * N)) ? true : false; + memDeallocate(); + return testResult; + } +}; + +static bool testhipMemsetAsyncWithKernel() { + MemSetKernelTest obj; + constexpr char memsetval = 0x42; + + obj.memAllocate(memsetval); + for (int k = 0 ; k < ITER ; k++) { + hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), + dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N); + HIP_CHECK(hipMemsetAsync(obj.C_d , obj.memSetVal , N , obj.stream)); + HIP_CHECK(hipStreamSynchronize(obj.stream)); + HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost)); + + obj.validateExecutionOrder(); + } + return obj.resultAfterAllIterations(); +} + +static bool testhipMemsetD32AsyncWithKernel() { + MemSetKernelTest obj; + constexpr int memsetD32val = 0xDEADBEEF; + + obj.memAllocate(memsetD32val); + for (int k = 0 ; k < ITER ; k++) { + hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), + dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N); + HIP_CHECK(hipMemsetD32Async((hipDeviceptr_t)obj.C_d , obj.memSetVal, + N, obj.stream)); + HIP_CHECK(hipStreamSynchronize(obj.stream)); + HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost)); + + obj.validateExecutionOrder(); + } + return obj.resultAfterAllIterations(); +} + +static bool testhipMemsetD16AsyncWithKernel() { + MemSetKernelTest obj; + constexpr int16_t memsetD16val = 0xDEAD; + + obj.memAllocate(memsetD16val); + for (int k = 0 ; k < ITER ; k++) { + hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), + dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N); + HIP_CHECK(hipMemsetD16Async((hipDeviceptr_t)obj.C_d , obj.memSetVal, + N, obj.stream)); + HIP_CHECK(hipStreamSynchronize(obj.stream)); + HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost)); + + obj.validateExecutionOrder(); + } + return obj.resultAfterAllIterations(); +} + +static bool testhipMemsetD8AsyncWithKernel() { + MemSetKernelTest obj; + constexpr char memsetD8val = 0xDE; + + obj.memAllocate(memsetD8val); + for (int k = 0; k < ITER; k++) { + hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), + dim3(threadsPerBlock), 0, obj.stream, obj.B_d, obj.C_d, N); + HIP_CHECK(hipMemsetD8Async((hipDeviceptr_t)obj.C_d, obj.memSetVal, + N, obj.stream)); + HIP_CHECK(hipStreamSynchronize(obj.stream)); + HIP_CHECK(hipMemcpy(obj.A_h, obj.C_d, obj.Nbytes, hipMemcpyDeviceToHost)); + + obj.validateExecutionOrder(); + } + return obj.resultAfterAllIterations(); +} + + +/* + * Test for checking order of execution of device kernel and + * hipMemsetAsync apis on all gpus + */ +TEST_CASE("Unit_hipMemsetAsync_VerifyExecutionWithKernel") { + int numDevices = 0; + bool ret; + + blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + + HIP_CHECK(hipGetDeviceCount(&numDevices)); + REQUIRE(numDevices > 0); + + auto devNum = GENERATE_COPY(range(0, numDevices)); + HIP_CHECK(hipSetDevice(devNum)); + + SECTION("hipMemsetAsync With Kernel") { + ret = testhipMemsetAsyncWithKernel(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD32Async With Kernel") { + ret = testhipMemsetD32AsyncWithKernel(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD16Async With Kernel") { + ret = testhipMemsetD16AsyncWithKernel(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD8Async With Kernel") { + ret = testhipMemsetD8AsyncWithKernel(); + REQUIRE(ret == true); + } +} diff --git a/tests/catch/unit/memory/hipMemsetAsyncMultiThread.cc b/tests/catch/unit/memory/hipMemsetAsyncMultiThread.cc new file mode 100644 index 0000000000..68deacda92 --- /dev/null +++ b/tests/catch/unit/memory/hipMemsetAsyncMultiThread.cc @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Test that validates functionality of hipmemsetAsync apis over multi threads + */ + +#include +#include + + +#define NUM_THREADS 20 +#define ITER 10 +#define N (4*1024*1024) + + +template +class MemSetAsyncMthreadTest { + public: + T *A_h, *A_d, *B_h; + T memSetVal; + size_t Nbytes; + bool testResult = true; + int validateCount = 0; + hipStream_t stream; + + void memAllocate(T memSetValue) { + memSetVal = memSetValue; + Nbytes = N * sizeof(T); + + A_h = reinterpret_cast(malloc(Nbytes)); + HIP_ASSERT(A_h != nullptr); + + HIP_CHECK(hipMalloc(&A_d, Nbytes)); + B_h = reinterpret_cast(malloc(Nbytes)); + HIP_ASSERT(B_h != nullptr); + + HIP_CHECK(hipStreamCreate(&stream)); + } + + void threadCompleteStatus() { + for (int k = 0 ; k < N ; k++) { + if ((A_h[k] == memSetVal) && (B_h[k] == memSetVal)) { + validateCount+= 1; + } + } + } + + bool resultAfterAllIterations() { + memDeallocate(); + testResult = (validateCount == (ITER * N)) ? true: false; + return testResult; + } + + void memDeallocate() { + HIP_CHECK(hipFree(A_d)); + free(A_h); + free(B_h); + HIP_CHECK(hipStreamDestroy(stream)); + } +}; + +template +void queueJobsForhipMemsetAsync(T* A_d, T* A_h, T memSetVal, size_t Nbytes, + hipStream_t stream) { + HIPCHECK(hipMemsetAsync(A_d, memSetVal, N, stream)); + HIPCHECK(hipMemcpyAsync(A_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream)); +} + +template +void queueJobsForhipMemsetD32Async(T* A_d, T* A_h, T memSetVal, size_t Nbytes, + hipStream_t stream) { + HIPCHECK(hipMemsetD32Async((hipDeviceptr_t)A_d, memSetVal, N, stream)); + HIPCHECK(hipMemcpyAsync(A_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream)); +} + +template +void queueJobsForhipMemsetD16Async(T* A_d, T* A_h, T memSetVal, size_t Nbytes, + hipStream_t stream) { + HIPCHECK(hipMemsetD16Async((hipDeviceptr_t)A_d, memSetVal, N, stream)); + HIPCHECK(hipMemcpyAsync(A_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream)); +} + +template +void queueJobsForhipMemsetD8Async(T* A_d, T* A_h, T memSetVal, size_t Nbytes, + hipStream_t stream) { + HIPCHECK(hipMemsetD8Async((hipDeviceptr_t)A_d, memSetVal, N, stream)); + HIPCHECK(hipMemcpyAsync(A_h, A_d, Nbytes, hipMemcpyDeviceToHost, stream)); +} + +/* Queue hipMemsetAsync jobs on multiple threads and verify they all + * finished on all threads successfully + */ +bool testhipMemsetAsyncWithMultiThread() { + MemSetAsyncMthreadTest obj; + constexpr char memsetval = 0x42; + obj.memAllocate(memsetval); + std::thread t[NUM_THREADS]; + + for (int i = 0 ; i < ITER ; i++) { + for (int k = 0 ; k < NUM_THREADS ; k++) { + if (k%2) { + t[k] = std::thread(queueJobsForhipMemsetAsync, obj.A_d, obj.A_h, + obj.memSetVal, obj.Nbytes, obj.stream); + } else { + t[k] = std::thread(queueJobsForhipMemsetAsync, obj.A_d, obj.B_h, + obj.memSetVal, obj.Nbytes, obj.stream); + } + } + + for (int j = 0 ; j < NUM_THREADS ; j++) { + t[j].join(); + } + + HIP_CHECK(hipStreamSynchronize(obj.stream)); + obj.threadCompleteStatus(); + } + return obj.resultAfterAllIterations(); +} + +bool testhipMemsetD32AsyncWithMultiThread() { + MemSetAsyncMthreadTest obj; + constexpr int memsetD32val = 0xDEADBEEF; + obj.memAllocate(memsetD32val); + std::thread t[NUM_THREADS]; + + for (int i = 0 ; i < ITER ; i++) { + for (int k = 0 ; k < NUM_THREADS ; k++) { + if (k%2) { + t[k] = std::thread(queueJobsForhipMemsetD32Async, obj.A_d, + obj.A_h, obj.memSetVal, obj.Nbytes, obj.stream); + } else { + t[k] = std::thread(queueJobsForhipMemsetD32Async, obj.A_d, + obj.B_h, obj.memSetVal, obj.Nbytes, obj.stream); + } + } + + for (int j = 0 ; j < NUM_THREADS ; j++) { + t[j].join(); + } + + HIP_CHECK(hipStreamSynchronize(obj.stream)); + obj.threadCompleteStatus(); + } + return obj.resultAfterAllIterations(); +} + +bool testhipMemsetD16AsyncWithMultiThread() { + MemSetAsyncMthreadTest obj; + constexpr int16_t memsetD16val = 0xDEAD; + obj.memAllocate(memsetD16val); + std::thread t[NUM_THREADS]; + + for (int i = 0 ; i < ITER ; i++) { + for (int k = 0 ; k < NUM_THREADS ; k++) { + if (k%2) { + t[k] = std::thread(queueJobsForhipMemsetD16Async, obj.A_d, + obj.A_h, obj.memSetVal, obj.Nbytes, obj.stream); + } else { + t[k] = std::thread(queueJobsForhipMemsetD16Async, obj.A_d, + obj.B_h, obj.memSetVal, obj.Nbytes, obj.stream); + } + } + + for (int j = 0 ; j < NUM_THREADS ; j++) { + t[j].join(); + } + + HIP_CHECK(hipStreamSynchronize(obj.stream)); + obj.threadCompleteStatus(); + } + return obj.resultAfterAllIterations(); +} + +bool testhipMemsetD8AsyncWithMultiThread() { + MemSetAsyncMthreadTest obj; + constexpr char memsetD8val = 0xDE; + obj.memAllocate(memsetD8val); + std::thread t[NUM_THREADS]; + + for (int i = 0 ; i < ITER ; i++) { + for (int k = 0 ; k < NUM_THREADS ; k++) { + if (k%2) { + t[k] = std::thread(queueJobsForhipMemsetD8Async, obj.A_d, + obj.A_h, obj.memSetVal, obj.Nbytes, obj.stream); + } else { + t[k] = std::thread(queueJobsForhipMemsetD8Async, obj.A_d, + obj.B_h, obj.memSetVal, obj.Nbytes, obj.stream); + } + } + for (int j = 0 ; j < NUM_THREADS ; j++) { + t[j].join(); + } + + HIP_CHECK(hipStreamSynchronize(obj.stream)); + obj.threadCompleteStatus(); + } + return obj.resultAfterAllIterations(); +} + + +/* + * Test that validates functionality of hipmemsetAsync apis over multi threads + */ +TEST_CASE("Unit_hipMemsetAsync_QueueJobsMultithreaded") { + bool ret; + + SECTION("hipMemsetAsync With MultiThread") { + ret = testhipMemsetAsyncWithMultiThread(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD32Async With MultiThread") { + ret = testhipMemsetD32AsyncWithMultiThread(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD16Async With MultiThread") { + ret = testhipMemsetD16AsyncWithMultiThread(); + REQUIRE(ret == true); + } + + SECTION("hipMemsetD8Async With MultiThread") { + ret = testhipMemsetD8AsyncWithMultiThread(); + REQUIRE(ret == true); + } +} diff --git a/tests/catch/unit/memory/hipMemsetInvalidPtr.cc b/tests/catch/unit/memory/hipMemsetInvalidPtr.cc new file mode 100644 index 0000000000..8c87c66ea8 --- /dev/null +++ b/tests/catch/unit/memory/hipMemsetInvalidPtr.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + 1) Test hipMemset apis with invalid pointer and invalid 2D pitch. + 2) Test hipMemsetAsync apis with invalid pointer and invalid 2D pitch. +*/ + + +#include + +#define N 50 +#define MEMSETVAL 0x42 + +/** + * Testcase validates hipMemset apis behavior with + * invalid pointer and invalid 2D pitch value. + */ +TEST_CASE("Unit_hipMemset_InvalidPtrTests") { + hipError_t ret; + constexpr int Nbytes = N*sizeof(char); + char *A_d; + + SECTION("hipMemset with null") { + ret = hipMemset(NULL, MEMSETVAL , Nbytes); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemset with hostptr") { + char *A_h; + A_h = reinterpret_cast(malloc(Nbytes)); + + ret = hipMemset(A_h, MEMSETVAL, Nbytes); + REQUIRE(ret != hipSuccess); + + free(A_h); + } + + SECTION("hipMemsetD32 with null") { + ret = hipMemsetD32(NULL, MEMSETVAL , Nbytes); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemsetD16 with null") { + ret = hipMemsetD16(NULL, MEMSETVAL , Nbytes); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemsetD8 with null") { + ret = hipMemsetD8(NULL, MEMSETVAL , Nbytes); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemset2D with null") { + constexpr size_t NUM_H = 256, NUM_W = 256; + size_t pitch_A; + size_t width = NUM_W * sizeof(char); + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width , NUM_H)); + ret = hipMemset2D(NULL, pitch_A, MEMSETVAL, NUM_W, NUM_H); + REQUIRE(ret != hipSuccess); + + hipFree(A_d); + } +} + + +/** + * Testcase validates hipMemsetAsync apis behavior with + * invalid pointer and invalid 2D pitch value. + */ +TEST_CASE("Unit_hipMemsetAsync_InvalidPtrTests") { + hipError_t ret; + constexpr int Nbytes = N*sizeof(char); + char *A_d; + + SECTION("hipMemsetAsync with null") { + ret = hipMemsetAsync(NULL, MEMSETVAL, Nbytes , 0); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemsetD32Async with null") { + ret = hipMemsetD32Async(NULL, MEMSETVAL , Nbytes, 0); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemsetD16Async with null") { + ret = hipMemsetD16Async(NULL, MEMSETVAL , Nbytes, 0); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemsetD8Async with null") { + ret = hipMemsetD8Async(NULL, MEMSETVAL , Nbytes, 0); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMemset2DAsync with null") { + constexpr size_t NUM_H = 256, NUM_W = 256; + size_t pitch_A; + size_t width = NUM_W * sizeof(char); + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width , NUM_H)); + ret = hipMemset2DAsync(NULL, pitch_A, MEMSETVAL, NUM_W, NUM_H, 0); + REQUIRE(ret != hipSuccess); + + hipFree(A_d); + } +} From bef1aa7ee6339c89e067e4412a242199a95a1e02 Mon Sep 17 00:00:00 2001 From: sumanthtg <90063301+sumanthtg@users.noreply.github.com> Date: Fri, 17 Sep 2021 11:39:25 +0530 Subject: [PATCH 2/9] SWDEV-292643 - [dtest] Catch2 additional unit tests for stream management apis. (#2349) APIs covered : hipStreamGetPriority, hipStreamCreate, hipStreamGetFlags, hipExtStreamGetCUMask apis. Change-Id: I238b4e631938471eab05c598f91477eeb0856054 --- tests/catch/unit/stream/CMakeLists.txt | 3 + .../catch/unit/stream/hipAPIStreamDisable.cc | 68 +++++++ tests/catch/unit/stream/hipStreamGetCUMask.cc | 177 ++++++++++++++++++ tests/catch/unit/stream/hipStreamGetFlags.cc | 70 ++++++- .../catch/unit/stream/hipStreamGetPriority.cc | 70 ++++++- 5 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 tests/catch/unit/stream/hipAPIStreamDisable.cc create mode 100644 tests/catch/unit/stream/hipStreamGetCUMask.cc diff --git a/tests/catch/unit/stream/CMakeLists.txt b/tests/catch/unit/stream/CMakeLists.txt index 14c05e7f74..31157f7da6 100644 --- a/tests/catch/unit/stream/CMakeLists.txt +++ b/tests/catch/unit/stream/CMakeLists.txt @@ -9,6 +9,8 @@ set(TEST_SRC hipStreamCreateWithFlags.cc hipStreamCreateWithPriority.cc hipStreamWithCUMask.cc + hipStreamGetCUMask.cc + hipAPIStreamDisable.cc ) else() set(TEST_SRC @@ -20,6 +22,7 @@ set(TEST_SRC hipStreamAddCallback.cc hipStreamCreateWithFlags.cc hipStreamCreateWithPriority.cc + hipAPIStreamDisable.cc ) endif() diff --git a/tests/catch/unit/stream/hipAPIStreamDisable.cc b/tests/catch/unit/stream/hipAPIStreamDisable.cc new file mode 100644 index 0000000000..4da259074b --- /dev/null +++ b/tests/catch/unit/stream/hipAPIStreamDisable.cc @@ -0,0 +1,68 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include +#include "hip/math_functions.h" + +#define NUM_STREAMS 8 + +namespace hipAPIStreamDisableTest { +const int NN = 1 << 21; + +__global__ void kernel(float* x, float* y, int n) { + int tid = threadIdx.x; + if (tid < 1) { + for (int i = 0; i < n; i++) { + x[i] = sqrt(powf(3.14159, i)); + } + y[tid] = y[tid] + 1.0f; + } +} + +__global__ void nKernel(float* y) { + int tid = threadIdx.x; + y[tid] = y[tid] + 1.0f; +} +} // namespace hipAPIStreamDisableTest + +/** + * Validate basic multistream functionalities + */ +TEST_CASE("Unit_hipStreamCreate_MultistreamBasicFunctionalities") { + hipStream_t streams[NUM_STREAMS]; + float *data[NUM_STREAMS], *yd, *xd; + float y = 1.0f, x = 1.0f; + HIP_CHECK(hipMalloc(reinterpret_cast(&yd), sizeof(float))); + HIP_CHECK(hipMalloc(reinterpret_cast(&xd), sizeof(float))); + HIP_CHECK(hipMemcpy(yd, &y, sizeof(float), hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(xd, &x, sizeof(float), hipMemcpyHostToDevice)); + + for (int i = 0; i < NUM_STREAMS; i++) { + HIP_CHECK(hipStreamCreate(&streams[i])); + HIP_CHECK(hipMalloc(&data[i], + (hipAPIStreamDisableTest::NN)*sizeof(float))); + hipLaunchKernelGGL(HIP_KERNEL_NAME(hipAPIStreamDisableTest::kernel), + dim3(1), dim3(1), 0, streams[i], data[i], xd, + hipAPIStreamDisableTest::NN); + hipLaunchKernelGGL(HIP_KERNEL_NAME(hipAPIStreamDisableTest::nKernel), + dim3(1), dim3(1), 0, 0, yd); + } + HIP_CHECK(hipMemcpy(&x, xd, sizeof(float), hipMemcpyDeviceToHost)); + HIP_CHECK(hipMemcpy(&y, yd, sizeof(float), hipMemcpyDeviceToHost)); + REQUIRE(x == y); +} diff --git a/tests/catch/unit/stream/hipStreamGetCUMask.cc b/tests/catch/unit/stream/hipStreamGetCUMask.cc new file mode 100644 index 0000000000..49f21bdbda --- /dev/null +++ b/tests/catch/unit/stream/hipStreamGetCUMask.cc @@ -0,0 +1,177 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : +1) Test to verify hipExtStreamGetCUMask api returning default CU Mask or global CU Mask. +2) Test to verify hipExtStreamGetCUMask api returns custom mask set. +3) Negative tests for hipExtStreamGetCUMask api. +*/ + +#include +#include + + +/** + * Scenario to verify hipExtStreamGetCUMask api returning default CU Mask or global CU Mask. + * Scenario to verify hipExtStreamGetCUMask api returns custom mask set. + */ +TEST_CASE("Unit_hipExtStreamGetCUMask_verifyDefaultAndCustomMask") { + constexpr int maxNum = 6; + std::vector cuMask(maxNum); + hipDeviceProp_t props; + std::stringstream ss; + char* gCUMask{nullptr}; + std::string globalCUMask(""); + std::vector defaultCUMask; + + int nGpu = 0; + HIP_CHECK(hipGetDeviceCount(&nGpu)); + if (nGpu < 1) { + INFO("info: didn't find any GPU! skipping the test!"); + return; + } + + HIP_CHECK(hipSetDevice(0)); + HIP_CHECK(hipGetDeviceProperties(&props, 0)); + INFO("info: running on bus " << "0x" << props.pciBusID << " " << + props.name << " with " << props.multiProcessorCount << " CUs"); + + // Get global CU Mask if exists + gCUMask = getenv("ROC_GLOBAL_CU_MASK"); + if (gCUMask != nullptr && gCUMask[0] != '\0') { + globalCUMask.assign(gCUMask); + + for_each(globalCUMask.begin(), globalCUMask.end(), [](char & c) { + c = ::tolower(c); + }); + } + + // Create default CU Mask + uint32_t temp = 0; + uint32_t bit_index = 0; + for (uint32_t i = 0; i < (uint32_t)props.multiProcessorCount; i++) { + temp |= 1UL << bit_index; + if (bit_index >= 32) { + defaultCUMask.push_back(temp); + temp = 0; + bit_index = 0; + temp |= 1UL << bit_index; + } + bit_index += 1; + } + if (bit_index != 0) { + defaultCUMask.push_back(temp); + } + + SECTION("Verify with default CU Mask or global CU Mask") { + // make a default CU mask bit-array where all CUs are active + // this default mask is expected to be returned when there is no + // custom or global CU mask defined + + HIP_CHECK(hipExtStreamGetCUMask(0, cuMask.size(), &cuMask[0])); + + ss << std::hex; + for (int i = cuMask.size() - 1; i >= 0; i--) { + ss << cuMask[i]; + } + + // remove extra 0 from ss if any present + size_t found = ss.str().find_first_not_of("0"); + if (found != std::string::npos) { + ss.str(ss.str().substr(found, ss.str().length())); + } + + INFO("info: CU mask for the default stream is: 0x" << ss.str().c_str()); + if (globalCUMask.size() > 0) { + if (ss.str().compare(globalCUMask) != 0) { + INFO("Expected CU mask:" << globalCUMask.c_str() << + ", api returned:" << ss.str().c_str()); + REQUIRE(false); + } + } else { + for (int i = 0 ; i < min(cuMask.size(), defaultCUMask.size()); i++) { + if (cuMask[i] != defaultCUMask[i]) { + INFO("Expected CU mask " << defaultCUMask[i] << + ", api returned:" << cuMask[i]); + REQUIRE(false); + } + } + } + } + + SECTION("Verify with custom mask set") { + std::vector customMask(defaultCUMask); + hipStream_t stream; + customMask[0] = 0xe; + + HIP_CHECK(hipExtStreamCreateWithCUMask(&stream, customMask.size(), + customMask.data())); + ss.str(""); + for (int i = customMask.size() - 1; i >= 0; i--) { + ss << customMask[i]; + } + INFO("info: setting a custom CU mask 0x" << ss.str()); + + HIP_CHECK(hipExtStreamGetCUMask(stream, cuMask.size(), &cuMask[0])); + ss.str(""); + for (int i = cuMask.size() - 1; i >= 0; i--) { + ss << cuMask[i]; + } + + size_t found = ss.str().find_first_not_of("0"); + if (found != std::string::npos) { + ss.str(ss.str().substr(found, ss.str().length())); + } + + INFO("info: reading back CU mask 0x" << ss.str() << + " for stream " << stream); + + if (!gCUMask) { + for (size_t i = 0; i < customMask.size(); i++) { + if (customMask[i] != cuMask[i]) { + INFO("Error! expected CU mask:" << customMask[i] + << ", Received CU mask:" << cuMask[i]); + REQUIRE(false); + } + } + } + + HIP_CHECK(hipStreamDestroy(stream)); + } +} + +/** + * Negative tests for hipExtStreamGetCUMask. + */ +TEST_CASE("Unit_hipExtStreamGetCUMask_Negative") { + hipError_t ret; + constexpr int maxNum = 6; + std::vector cuMask(maxNum); + + SECTION("cuMask is nullptr") { + ret = hipExtStreamGetCUMask(0, cuMask.size(), nullptr); + REQUIRE(ret == hipErrorInvalidValue); + } + + SECTION("cuMaskSize is 0") { + ret = hipExtStreamGetCUMask(0, 0, &cuMask[0]); + REQUIRE(ret == hipErrorInvalidValue); + } +} diff --git a/tests/catch/unit/stream/hipStreamGetFlags.cc b/tests/catch/unit/stream/hipStreamGetFlags.cc index 583abe5068..9cbe37b6de 100644 --- a/tests/catch/unit/stream/hipStreamGetFlags.cc +++ b/tests/catch/unit/stream/hipStreamGetFlags.cc @@ -16,16 +16,24 @@ 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. */ +/** +Testcase Scenarios : +1) Test flag value of stream created with hipStreamCreateWithFlags/ + /hipStreamCreate/hipStreamCreateWithPriority. +2) Negative tests for hipStreamGetFlags api. +3) Test flag value when streams created with CUMask. +*/ + #include -TEST_CASE("Unit_hipStreamGetFlags_Negative") { - // Get flags for uninitialized stream + +/** + * Test flag value of stream created with various types. + */ +TEST_CASE("Unit_hipStreamGetFlags_BasicFunctionalities") { hipStream_t stream; - HIP_CHECK(hipStreamCreateWithFlags(&stream, hipStreamDefault)); - REQUIRE(hipStreamGetFlags(stream, nullptr) == hipErrorInvalidValue); -} -TEST_CASE("Unit_hipStreamGetFlags") { - hipStream_t stream; - unsigned int flags; + unsigned int flags; + // Check flag value of stream created with hipStreamCreateWithFlags + SECTION("Check flag value of streams hipStreamCreateWithFlags") { HIP_CHECK(hipStreamCreateWithFlags(&stream, hipStreamDefault)); HIP_CHECK(hipStreamGetFlags(stream, &flags)); REQUIRE(flags == hipStreamDefault); @@ -34,4 +42,50 @@ TEST_CASE("Unit_hipStreamGetFlags") { HIP_CHECK(hipStreamGetFlags(stream, &flags)); REQUIRE(flags == hipStreamNonBlocking); HIP_CHECK(hipStreamDestroy(stream)); + } + // Check flag value of stream created with hipStreamCreate + SECTION("Check flag value of streams hipStreamCreate") { + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipStreamGetFlags(stream, &flags)); + REQUIRE(flags == hipStreamDefault); + HIP_CHECK(hipStreamDestroy(stream)); + } + // Check flag value of stream created with hipStreamCreateWithPriority + SECTION("Check flag value of streams hipStreamCreateWithPriority") { + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, 0)); + HIP_CHECK(hipStreamGetFlags(stream, &flags)); + REQUIRE(flags == hipStreamDefault); + HIP_CHECK(hipStreamDestroy(stream)); + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, 0)); + HIP_CHECK(hipStreamGetFlags(stream, &flags)); + REQUIRE(flags == hipStreamNonBlocking); + HIP_CHECK(hipStreamDestroy(stream)); + } } + +/** + * Negative Scenarios + */ +TEST_CASE("Unit_hipStreamGetFlags_Negative") { + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + // nullptr check + REQUIRE(hipStreamGetFlags(stream, nullptr) != hipSuccess); + REQUIRE(hipStreamGetFlags(nullptr, hipStreamDefault) != hipSuccess); + HIP_CHECK(hipStreamDestroy(stream)); +} + +#if HT_AMD +/** + * Test flag value when streams created with CUMask. + */ +TEST_CASE("Unit_hipStreamGetFlags_StreamsCreatedWithCUMask") { + hipStream_t stream; + unsigned int flags; + const uint32_t cuMask = 0xffffffff; + HIP_CHECK(hipExtStreamCreateWithCUMask(&stream, 1, &cuMask)); + HIP_CHECK(hipStreamGetFlags(stream, &flags)); + REQUIRE(flags == hipStreamDefault); + HIP_CHECK(hipStreamDestroy(stream)); +} +#endif diff --git a/tests/catch/unit/stream/hipStreamGetPriority.cc b/tests/catch/unit/stream/hipStreamGetPriority.cc index 3578fd9b5a..29f182ecdf 100644 --- a/tests/catch/unit/stream/hipStreamGetPriority.cc +++ b/tests/catch/unit/stream/hipStreamGetPriority.cc @@ -16,11 +16,28 @@ 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. */ +/** +Testcase Scenarios : +1) Negative tests for hipStreamGetPriority api. +2) Create stream and check default priority of stream is within range. +3) Create stream with high or low priority and check priority is set as expected. +4) Create stream with higher priority or lower priority for the priority range returned. +5) Create stream with CUMask and check priority is returned as expected. +*/ + #include + +/** + * Negative tests for hipStreamGetPriority api. + */ TEST_CASE("Unit_hipStreamGetPriority_Negative") { hipStream_t stream = 0; REQUIRE(hipStreamGetPriority(stream, nullptr) == hipErrorInvalidValue); } + +/** + * Create stream and check default priority of stream is within range. + */ TEST_CASE("Unit_hipStreamGetPriority_default") { int priority_low = 0; int priority_high = 0; @@ -37,6 +54,10 @@ TEST_CASE("Unit_hipStreamGetPriority_default") { REQUIRE(priority >= priority_high); HIP_CHECK(hipStreamDestroy(stream)); } + +/** + * Create stream with high priority and check priority is set as expected. + */ TEST_CASE("Unit_hipStreamGetPriority_high") { int priority_low = 0; int priority_high = 0; @@ -44,12 +65,17 @@ TEST_CASE("Unit_hipStreamGetPriority_high") { HIP_CHECK(hipSetDevice(devID)); HIP_CHECK(hipDeviceGetStreamPriorityRange(&priority_low, &priority_high)); hipStream_t stream; - HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, priority_high)); + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, + priority_high)); int priority = 0; HIP_CHECK(hipStreamGetPriority(stream, &priority)); REQUIRE(priority == priority_high); HIP_CHECK(hipStreamDestroy(stream)); } + +/** + * Create stream with higher priority for the priority range returned. + */ TEST_CASE("Unit_hipStreamGetPriority_higher") { int priority_low = 0; int priority_high = 0; @@ -57,12 +83,17 @@ TEST_CASE("Unit_hipStreamGetPriority_higher") { HIP_CHECK(hipSetDevice(devID)); HIP_CHECK(hipDeviceGetStreamPriorityRange(&priority_low, &priority_high)); hipStream_t stream; - HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, priority_high-1)); + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, + priority_high-1)); int priority = 0; HIP_CHECK(hipStreamGetPriority(stream, &priority)); REQUIRE(priority == priority_high); HIP_CHECK(hipStreamDestroy(stream)); } + +/** + * Create stream with low priority and check priority is set as expected. + */ TEST_CASE("Unit_hipStreamGetPriority_low") { int priority_low = 0; int priority_high = 0; @@ -70,12 +101,17 @@ TEST_CASE("Unit_hipStreamGetPriority_low") { HIP_CHECK(hipSetDevice(devID)); HIP_CHECK(hipDeviceGetStreamPriorityRange(&priority_low, &priority_high)); hipStream_t stream; - HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, priority_low)); + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamDefault, + priority_low)); int priority = 0; HIP_CHECK(hipStreamGetPriority(stream, &priority)); REQUIRE(priority_low == priority); HIP_CHECK(hipStreamDestroy(stream)); } + +/** + * Create stream with lower priority for the priority range returned. + */ TEST_CASE("Unit_hipStreamGetPriority_lower") { int priority_low = 0; int priority_high = 0; @@ -83,9 +119,35 @@ TEST_CASE("Unit_hipStreamGetPriority_lower") { HIP_CHECK(hipSetDevice(devID)); HIP_CHECK(hipDeviceGetStreamPriorityRange(&priority_low, &priority_high)); hipStream_t stream; - HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, priority_low+1)); + HIP_CHECK(hipStreamCreateWithPriority(&stream, hipStreamNonBlocking, + priority_low+1)); int priority = 0; HIP_CHECK(hipStreamGetPriority(stream, &priority)); REQUIRE(priority_low == priority); HIP_CHECK(hipStreamDestroy(stream)); } + +#if HT_AMD +/** + * Create stream with CUMask and check priority is returned as expected. + */ +TEST_CASE("Unit_hipStreamGetPriority_StreamsWithCUMask") { + hipStream_t stream; + int priority = 0; + int priority_normal = 0; + int priority_low = 0; + int priority_high = 0; + // Test is to get the Stream Priority Range + HIP_CHECK(hipDeviceGetStreamPriorityRange(&priority_low, &priority_high)); + priority_normal = priority_low + priority_high; + // Check if priorities are indeed supported + REQUIRE_FALSE(priority_low == priority_high); + // Creating a stream with hipExtStreamCreateWithCUMask and checking + // priority. + const uint32_t cuMask = 0xffffffff; + HIP_CHECK(hipExtStreamCreateWithCUMask(&stream, 1, &cuMask)); + HIP_CHECK(hipStreamGetPriority(stream, &priority)); + REQUIRE_FALSE(priority_normal != priority); + HIP_CHECK(hipStreamDestroy(stream)); +} +#endif From 8763c8c2ad985cbff41189cd42370e62355688f7 Mon Sep 17 00:00:00 2001 From: dkrottap <88473220+dkrottap@users.noreply.github.com> Date: Fri, 17 Sep 2021 11:39:36 +0530 Subject: [PATCH 3/9] SWDEV-289405 - [catch2][dtest][module] Migration of Module files to CATCH2 framework (#2351) Migrated all module related files to CATCH2 framework and optimized to have single module kernel file Change-Id: I39aa28ef22c1b2f4d0014ca32b59b9c645b725dc --- tests/catch/hipTestMain/CMakeLists.txt | 4 +- tests/catch/include/hip_test_common.hh | 61 +- tests/catch/include/hip_test_helper.hh | 2 +- tests/catch/include/hip_test_kernels.hh | 31 +- tests/catch/stress/CMakeLists.txt | 1 + tests/catch/stress/memory/CMakeLists.txt | 1 + .../memory/hipMemcpyBoundaryOffsetCheck.cc | 344 +++++++++++ tests/catch/stress/module/CMakeLists.txt | 19 + .../hipExtModuleLaunchKernel_CornerTest.cc | 86 +++ .../hipModuleLaunchKernel_CornerTests.cc | 90 +++ tests/catch/stress/module/kernels.cc | 28 + tests/catch/unit/CMakeLists.txt | 1 + tests/catch/unit/module/CMakeLists.txt | 51 ++ .../unit/module/hipExtLaunchKernelGGL.cc | 129 ++++ .../hipExtLaunchMultiKernelMultiDevice.cc | 128 ++++ .../unit/module/hipExtModuleLaunchKernel.cc | 433 ++++++++++++++ .../catch/unit/module/hipFuncGetAttributes.cc | 163 +++++ .../catch/unit/module/hipFuncSetAttribute.cc | 46 ++ .../unit/module/hipFuncSetCacheConfig.cc | 36 ++ .../unit/module/hipFuncSetSharedMemConfig.cc | 107 ++++ tests/catch/unit/module/hipManagedKeyword.cc | 56 ++ tests/catch/unit/module/hipModule.cc | 183 ++++++ tests/catch/unit/module/hipModuleGetGlobal.cc | 120 ++++ .../unit/module/hipModuleLaunchKernel.cc | 246 ++++++++ tests/catch/unit/module/hipModuleLoadData.cc | 91 +++ .../hipModuleLoadDataMultThreadOnMultGPU.cc | 161 +++++ .../module/hipModuleLoadDataMultThreaded.cc | 164 +++++ .../unit/module/hipModuleLoadMultiThreaded.cc | 121 ++++ .../unit/module/hipModuleLoadUnloadStress.cc | 93 +++ tests/catch/unit/module/hipModuleNegative.cc | 274 +++++++++ ...hipModuleOccupancyMaxPotentialBlockSize.cc | 267 +++++++++ .../unit/module/hipModuleTexture2dDrv.cc | 561 ++++++++++++++++++ tests/catch/unit/module/hipModuleUnload.cc | 34 ++ tests/catch/unit/module/hipOpenCLCOTest.cc | 229 +++++++ tests/catch/unit/module/module_kernels.cc | 167 ++++++ tests/catch/unit/module/opencl_add.cc | 37 ++ 36 files changed, 4560 insertions(+), 5 deletions(-) create mode 100644 tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc create mode 100644 tests/catch/stress/module/CMakeLists.txt create mode 100644 tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc create mode 100644 tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc create mode 100644 tests/catch/stress/module/kernels.cc create mode 100644 tests/catch/unit/module/CMakeLists.txt create mode 100755 tests/catch/unit/module/hipExtLaunchKernelGGL.cc create mode 100644 tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc create mode 100755 tests/catch/unit/module/hipExtModuleLaunchKernel.cc create mode 100644 tests/catch/unit/module/hipFuncGetAttributes.cc create mode 100644 tests/catch/unit/module/hipFuncSetAttribute.cc create mode 100644 tests/catch/unit/module/hipFuncSetCacheConfig.cc create mode 100644 tests/catch/unit/module/hipFuncSetSharedMemConfig.cc create mode 100644 tests/catch/unit/module/hipManagedKeyword.cc create mode 100755 tests/catch/unit/module/hipModule.cc create mode 100755 tests/catch/unit/module/hipModuleGetGlobal.cc create mode 100644 tests/catch/unit/module/hipModuleLaunchKernel.cc create mode 100644 tests/catch/unit/module/hipModuleLoadData.cc create mode 100644 tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc create mode 100644 tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc create mode 100644 tests/catch/unit/module/hipModuleLoadMultiThreaded.cc create mode 100644 tests/catch/unit/module/hipModuleLoadUnloadStress.cc create mode 100644 tests/catch/unit/module/hipModuleNegative.cc create mode 100644 tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc create mode 100755 tests/catch/unit/module/hipModuleTexture2dDrv.cc create mode 100644 tests/catch/unit/module/hipModuleUnload.cc create mode 100644 tests/catch/unit/module/hipOpenCLCOTest.cc create mode 100644 tests/catch/unit/module/module_kernels.cc create mode 100644 tests/catch/unit/module/opencl_add.cc diff --git a/tests/catch/hipTestMain/CMakeLists.txt b/tests/catch/hipTestMain/CMakeLists.txt index 2b3cb3f60c..5b62dbbb49 100644 --- a/tests/catch/hipTestMain/CMakeLists.txt +++ b/tests/catch/hipTestMain/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries(UnitTests PRIVATE UnitDeviceTests EventTest OccupancyTest DeviceTest + ModuleTest RTC stdc++fs) @@ -36,6 +37,7 @@ target_link_libraries(ABMTests PRIVATE ABMAddKernels stdc++fs) catch_discover_tests(ABMTests PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST") +add_dependencies(UnitTests module_kernels.code) add_dependencies(build_tests UnitTests ABMTests) @@ -63,7 +65,7 @@ else() target_compile_options(StressTest PUBLIC -std=c++17) endif() if(HIP_PLATFORM MATCHES "amd") -target_link_libraries(StressTest PRIVATE printf stream) +target_link_libraries(StressTest PRIVATE printf stream module) endif() target_link_libraries(StressTest PRIVATE memory stdc++fs) add_dependencies(build_stress_test StressTest) diff --git a/tests/catch/include/hip_test_common.hh b/tests/catch/include/hip_test_common.hh index 9107740333..9ffe839739 100644 --- a/tests/catch/include/hip_test_common.hh +++ b/tests/catch/include/hip_test_common.hh @@ -1,6 +1,5 @@ /* -Copyright (c) 2021 - 2021 Advanced Micro Devices, Inc. All rights reserved. - +Copyright (c) 2021 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 @@ -23,6 +22,13 @@ THE SOFTWARE. #pragma once #include "hip_test_context.hh" #include +#ifdef __linux__ +#include +#elif defined(_WIN32) +#include +#endif + + #define HIP_PRINT_STATUS(status) INFO(hipGetErrorName(status) << " at line: " << __LINE__); @@ -72,6 +78,27 @@ THE SOFTWARE. } +#if HT_NVIDIA +#define CTX_CREATE() \ + hipCtx_t context;\ + initHipCtx(&context); +#define CTX_DESTROY() HIPCHECK(hipCtxDestroy(context)); +#define ARRAY_DESTROY(array) HIPCHECK(hipArrayDestroy(array)); +#define HIP_TEX_REFERENCE hipTexRef +#define HIP_ARRAY hiparray +static void initHipCtx(hipCtx_t *pcontext) { + HIPCHECK(hipInit(0)); + hipDevice_t device; + HIPCHECK(hipDeviceGet(&device, 0)); + HIPCHECK(hipCtxCreate(pcontext, 0, device)); +} +#else +#define CTX_CREATE() +#define CTX_DESTROY() +#define ARRAY_DESTROY(array) HIPCHECK(hipFreeArray(array)); +#define HIP_TEX_REFERENCE textureReference* +#define HIP_ARRAY hipArray* +#endif // Utility Functions namespace HipTest { @@ -104,4 +131,34 @@ static inline unsigned setNumBlocks(unsigned blocksPerCU, unsigned threadsPerBlo return blocks; } +// Get Free Memory from the system +static size_t getMemoryAmount() { +#if __linux__ + struct sysinfo info; + sysinfo(&info); + return info.freeram / (1024 * 1024); // MB +#elif defined(_WIN32) + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return (statex.ullAvailPhys / (1024 * 1024)); // MB +#endif +} + +static inline size_t getHostThreadCount(const size_t memPerThread = 200, const size_t maxThreads = 0) { + if (memPerThread == 0) return 0; + auto memAmount = getMemoryAmount(); + const auto processor_count = std::thread::hardware_concurrency(); + if (processor_count == 0 || memAmount == 0) return 0; + size_t thread_count = 0; + if ((processor_count * memPerThread) < memAmount) + thread_count = processor_count; + else + thread_count = reinterpret_cast(memAmount / memPerThread); + if (maxThreads > 0) { + return (thread_count > maxThreads) ? maxThreads : thread_count; + } + return thread_count; +} + } diff --git a/tests/catch/include/hip_test_helper.hh b/tests/catch/include/hip_test_helper.hh index 1d0a57b776..08b6bec0c6 100644 --- a/tests/catch/include/hip_test_helper.hh +++ b/tests/catch/include/hip_test_helper.hh @@ -1,5 +1,5 @@ /* -Copyright (c) 2021 - 2021 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2021 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 diff --git a/tests/catch/include/hip_test_kernels.hh b/tests/catch/include/hip_test_kernels.hh index 04b00b5ad3..3805b4cbbc 100644 --- a/tests/catch/include/hip_test_kernels.hh +++ b/tests/catch/include/hip_test_kernels.hh @@ -1,5 +1,5 @@ /* -Copyright (c) 2021 - 2021 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2021 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 @@ -72,6 +72,35 @@ __global__ void addCountReverse(const T* A_d, T* C_d, int64_t NELEM, int count) } } +template +__device__ void waitKernel(uint64_t wait_sec, T clockrate) { + uint64_t start = clock64()/clockrate, cur; + do { cur = clock64()/clockrate-start;}while (cur < (wait_sec*1000)); +} + +template +__global__ void TwoSecKernel_GlobalVar(int globalvar, int clockrate) { + if (globalvar == 0x2222) { + globalvar = 0x3333; + } + waitKernel(2, clockrate); + if (globalvar != 0x3333) { + globalvar = 0x5555; + } +} + +template +__global__ void FourSecKernel_GlobalVar(int globalvar, int clockrate) { + if (globalvar == 1) { + globalvar = 0x2222; + } + waitKernel(4, clockrate); + if (globalvar == 0x2222) { + globalvar = 0x4444; + } +} + + template __global__ void memsetReverse(T* C_d, T val, int64_t NELEM) { size_t offset = (blockIdx.x * blockDim.x + threadIdx.x); size_t stride = blockDim.x * gridDim.x; diff --git a/tests/catch/stress/CMakeLists.txt b/tests/catch/stress/CMakeLists.txt index 00e12f2c2c..04038e0b8a 100644 --- a/tests/catch/stress/CMakeLists.txt +++ b/tests/catch/stress/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(memory) +add_subdirectory(module) if(HIP_PLATFORM MATCHES "amd") add_subdirectory(printf) add_subdirectory(stream) diff --git a/tests/catch/stress/memory/CMakeLists.txt b/tests/catch/stress/memory/CMakeLists.txt index 5afd69ee11..4338216fad 100644 --- a/tests/catch/stress/memory/CMakeLists.txt +++ b/tests/catch/stress/memory/CMakeLists.txt @@ -2,6 +2,7 @@ set(TEST_SRC memcpy.cc hipMemcpyMThreadMSize.cc + hipMemcpyBoundaryOffsetCheck.cc ) # Create shared lib of all tests diff --git a/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc b/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc new file mode 100644 index 0000000000..b81e575bcf --- /dev/null +++ b/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc @@ -0,0 +1,344 @@ +/* +Copyright (c) 2021 - present 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 testcase verifies following scenarios +3. Boundary checks with different sizes +5. device offset scenario +*/ +#include +#include +#include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include "sys/types.h" +#include "sys/sysinfo.h" +#endif +static constexpr auto NUM_ELM{4*1024 * 1024}; +template +class DeviceMemory { + public: + explicit DeviceMemory(size_t numElements); + DeviceMemory() = delete; + ~DeviceMemory(); + T* A_d() const { return _A_d + _offset; } + T* B_d() const { return _B_d + _offset; } + T* C_d() const { return _C_d + _offset; } + T* C_dd() const { return _C_dd + _offset; } + size_t maxNumElements() const { return _maxNumElements; } + void offset(int offset) { _offset = offset; } + int offset() const { return _offset; } + private: + T* _A_d; + T* _B_d; + T* _C_d; + T* _C_dd; + size_t _maxNumElements; + int _offset; +}; +template +DeviceMemory::DeviceMemory(size_t numElements) : + _maxNumElements(numElements), _offset(0) { + T** np = nullptr; + HipTest::initArrays(&_A_d, &_B_d, &_C_d, np, np, np, numElements, 0); + size_t sizeElements = numElements * sizeof(T); + HIP_CHECK(hipMalloc(&_C_dd, sizeElements)); +} +template +DeviceMemory::~DeviceMemory() { + T* np = nullptr; + HipTest::freeArrays(_A_d, _B_d, _C_d, np, np, np, 0); + HIP_CHECK(hipFree(_C_dd)); + _C_dd = NULL; +} +template +class HostMemory { + public: + HostMemory(size_t numElements, bool usePinnedHost); + HostMemory() = delete; + void reset(size_t numElements, bool full = false); + ~HostMemory(); + T* A_h() const { return _A_h + _offset; } + T* B_h() const { return _B_h + _offset; } + T* C_h() const { return _C_h + _offset; } + size_t maxNumElements() const { return _maxNumElements; } + void offset(int offset) { _offset = offset; } + int offset() const { return _offset; } + // Host arrays, secondary copy + T* A_hh; + T* B_hh; + bool _usePinnedHost; + private: + size_t _maxNumElements; + int _offset; + // Host arrays + T* _A_h; + T* _B_h; + T* _C_h; +}; + template +HostMemory::HostMemory(size_t numElements, bool usePinnedHost) + : _usePinnedHost(usePinnedHost), _maxNumElements(numElements), _offset(0) { + T** np = nullptr; + HipTest::initArrays(np, np, np, &_A_h, &_B_h, &_C_h, + numElements, usePinnedHost); + A_hh = NULL; + B_hh = NULL; + size_t sizeElements = numElements * sizeof(T); + if (usePinnedHost) { + HIP_CHECK(hipHostMalloc(reinterpret_cast(&A_hh), sizeElements, + hipHostMallocDefault)); + HIP_CHECK(hipHostMalloc(reinterpret_cast(&B_hh), sizeElements, + hipHostMallocDefault)); + } else { + A_hh = reinterpret_cast(malloc(sizeElements)); + B_hh = reinterpret_cast(malloc(sizeElements)); + } + } +template +void HostMemory::reset(size_t numElements, bool full) { + // Initialize the host data: + for (size_t i = 0; i < numElements; i++) { + (A_hh)[i] = 1097.0 + i; + (B_hh)[i] = 1492.0 + i; // Phi + if (full) { + (_A_h)[i] = 3.146f + i; // Pi + (_B_h)[i] = 1.618f + i; // Phi + } + } +} +template +HostMemory::~HostMemory() { + HipTest::freeArraysForHost(_A_h, _B_h, _C_h, _usePinnedHost); + if (_usePinnedHost) { + HIP_CHECK(hipHostFree(A_hh)); + HIP_CHECK(hipHostFree(B_hh)); + } else { + free(A_hh); + free(B_hh); + } +} +#ifdef _WIN32 +void memcpytest2_get_host_memory(size_t *free, size_t *total) { + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + // Windows doesn't allow allocating more than half of system memory to the gpu + // Since the runtime also needs space for its internal allocations, + // we should not try to allocate more than 40% of reported system memory, + // otherwise we can run into OOM issues. + *free = static_cast(0.4 * status.ullAvailPhys); + *total = static_cast(0.4 * status.ullTotalPhys); +} +#else +struct sysinfo memInfo; +void memcpytest2_get_host_memory(size_t *free, size_t *total) { + sysinfo(&memInfo); + uint64_t freePhysMem = memInfo.freeram; + freePhysMem *= memInfo.mem_unit; + *free = freePhysMem; + uint64_t totalPhysMem = memInfo.totalram; + totalPhysMem *= memInfo.mem_unit; + *total = totalPhysMem; +} +#endif +//--- +// Test many different kinds of memory copies. +// The subroutine allocates memory , copies to device, runs a vector +// add kernel, copies back, and +// checks the result. +// +// IN: numElements controls the number of elements used for allocations. +// IN: usePinnedHost : If true, allocate host with hipHostMalloc and is pinned +// else allocate host +// memory with malloc. IN: useHostToHost : If true, add an extra +// host-to-host copy. IN: +// useDeviceToDevice : If true, add an extra deviceto-device copy after +// result is produced. IN: +// useMemkindDefault : If true, use memkinddefault +// (runtime figures out direction). if false, use +// explicit memcpy direction. +// +template +void memcpytest2(DeviceMemory* dmem, HostMemory* hmem, + size_t numElements, bool useHostToHost, + bool useDeviceToDevice, bool useMemkindDefault) { + size_t sizeElements = numElements * sizeof(T); + hmem->reset(numElements); + assert(numElements <= dmem->maxNumElements()); + assert(numElements <= hmem->maxNumElements()); + if (useHostToHost) { + // Do some extra host-to-host copies here to mix things up: + HIP_CHECK(hipMemcpy(hmem->A_hh, hmem->A_h(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToHost)); + HIP_CHECK(hipMemcpy(hmem->B_hh, hmem->B_h(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToHost)); + HIP_CHECK(hipMemcpy(dmem->A_d(), hmem->A_hh, sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(dmem->B_d(), hmem->B_hh, sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); + } else { + HIP_CHECK(hipMemcpy(dmem->A_d(), hmem->A_h(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(dmem->B_d(), hmem->B_h(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); + } + hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1), 0, 0, + static_cast(dmem->A_d()), static_cast(dmem->B_d()), + dmem->C_d(), numElements); + if (useDeviceToDevice) { + // Do an extra device-to-device copy here to mix things up: + HIP_CHECK(hipMemcpy(dmem->C_dd(), dmem->C_d(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToDevice)); + // Destroy the original dmem->C_d(): + HIP_CHECK(hipMemset(dmem->C_d(), 0x5A, sizeElements)); + HIP_CHECK(hipMemcpy(hmem->C_h(), dmem->C_dd(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToHost)); + } else { + HIP_CHECK(hipMemcpy(hmem->C_h(), dmem->C_d(), sizeElements, + useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToHost)); + } + HIP_CHECK(hipDeviceSynchronize()); + HipTest::checkVectorADD(hmem->A_h(), hmem->B_h(), hmem->C_h(), numElements); +} +// Try all the 16 possible combinations to memcpytest2 - usePinnedHost, +// useHostToHost, +// useDeviceToDevice, useMemkindDefault +template +void memcpytest2_for_type(size_t numElements) { + DeviceMemory memD(numElements); + HostMemory memU(numElements, 0 /*usePinnedHost*/); + HostMemory memP(numElements, 1 /*usePinnedHost*/); + for (int usePinnedHost = 0; usePinnedHost <= 1; usePinnedHost++) { + for (int useHostToHost = 0; useHostToHost <= 1; useHostToHost++) { + for (int useDeviceToDevice = 0; useDeviceToDevice <= 1; + useDeviceToDevice++) { + for (int useMemkindDefault = 0; useMemkindDefault <= 1; + useMemkindDefault++) { + memcpytest2(&memD, usePinnedHost ? &memP : &memU, + numElements, useHostToHost, + useDeviceToDevice, useMemkindDefault); + } + } + } + } +} +// Try many different sizes to memory copy. +template +void memcpytest2_sizes(size_t maxElem = 0) { + int deviceId; + HIP_CHECK(hipGetDevice(&deviceId)); + size_t free, total, freeCPU, totalCPU; + HIP_CHECK(hipMemGetInfo(&free, &total)); + memcpytest2_get_host_memory(&freeCPU, &totalCPU); + if (maxElem == 0) { + // Use lesser maxElem if not enough host memory available + size_t maxElemGPU = free / sizeof(T) / 8; + size_t maxElemCPU = freeCPU / sizeof(T) / 8; + maxElem = maxElemGPU < maxElemCPU ? maxElemGPU : maxElemCPU; + } + HIP_CHECK(hipDeviceReset()); + DeviceMemory memD(maxElem); + HostMemory memU(maxElem, 0 /*usePinnedHost*/); + HostMemory memP(maxElem, 1 /*usePinnedHost*/); + for (size_t elem = 1; elem <= maxElem; elem *= 2) { + memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host + memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host + } +} +// Try many different sizes to memory copy. +template +void memcpytest2_offsets(size_t maxElem, bool devOffsets, bool hostOffsets) { + int deviceId; + HIP_CHECK(hipGetDevice(&deviceId)); + size_t free, total; + HIP_CHECK(hipMemGetInfo(&free, &total)); + HIP_CHECK(hipDeviceReset()); + DeviceMemory memD(maxElem); + HostMemory memU(maxElem, 0 /*usePinnedHost*/); + HostMemory memP(maxElem, 1 /*usePinnedHost*/); + size_t elem = maxElem / 2; + for (size_t offset = 0; offset < 512; offset++) { + assert(elem + offset < maxElem); + if (devOffsets) { + memD.offset(offset); + } + if (hostOffsets) { + memU.offset(offset); + memP.offset(offset); + } + memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host + memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host + } + for (size_t offset = 512; offset < elem; offset *= 2) { + assert(elem + offset < maxElem); + if (devOffsets) { + memD.offset(offset); + } + if (hostOffsets) { + memU.offset(offset); + memP.offset(offset); + } + memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host + memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host + } +} +// Create multiple threads to stress multi-thread locking behavior in the +// allocation/deallocation/tracking logic: +template +void multiThread_1(bool serialize, bool usePinnedHost) { + DeviceMemory memD(NUM_ELM); + HostMemory mem1(NUM_ELM, usePinnedHost); + HostMemory mem2(NUM_ELM, usePinnedHost); + std::thread t1(memcpytest2, &memD, &mem1, NUM_ELM, 0, 0, 0); + if (serialize) { + t1.join(); + } + std::thread t2(memcpytest2, &memD, &mem2, NUM_ELM, 0, 0, 0); + if (serialize) { + t2.join(); + } +} +/* +This testcase verfies the boundary checks of hipMemcpy API for different sizes +*/ +TEST_CASE("Unit_hipMemcpy_BoundaryCheck") { + size_t maxElem = 32 * 1024 * 1024; + DeviceMemory memD(maxElem); + HostMemory memU(maxElem, 0 /*usePinnedHost*/); + HostMemory memP(maxElem, 0 /*usePinnedHost*/); + memcpytest2(&memD, &memU, 32 * 1024 * 1024, 0, 0, 0); + auto sizes = GENERATE(15 * 1024 * 1024, 16 * 1024 * 1024, + 16 * 1024 * 1024 + 16 * 1024, + 16 * 1024 * 1024 + 512 * 1024, + 17 * 1024 * 1024 + 1024, + 32 * 1024 * 1024); + memcpytest2(&memD, &memP, sizes, 0, 0, 0); +} + +/* +This testcase verifies the device offsets +*/ +TEMPLATE_TEST_CASE("Unit_hipMemcpy_DeviceOffsets", "", float, double) { + HIP_CHECK(hipDeviceReset()); + size_t maxSize = 256 * 1024; + memcpytest2_offsets(maxSize, true, false); + memcpytest2_offsets(maxSize, false, true); +} diff --git a/tests/catch/stress/module/CMakeLists.txt b/tests/catch/stress/module/CMakeLists.txt new file mode 100644 index 0000000000..17ebb212e6 --- /dev/null +++ b/tests/catch/stress/module/CMakeLists.txt @@ -0,0 +1,19 @@ +# Common Tests - Test independent of all platforms +if(HIP_PLATFORM MATCHES "amd") +set(TEST_SRC + hipExtModuleLaunchKernel_CornerTest.cc + hipModuleLaunchKernel_CornerTests.cc +) +else() +set(TEST_SRC + hipModuleLaunchKernel_CornerTests.cc +) +endif() + +add_custom_target(kernels.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${HIP_COMMON_DIR}/tests/catch/stress/module/kernels.cc -o ${HIP_PATH}/catch/hipTestMain/kernels.code -I${HIP_PATH}/include/ -I${HIP_COMMON_DIR}/tests/catch/include) + +# Create shared lib of all tests +add_library(module SHARED EXCLUDE_FROM_ALL ${TEST_SRC}) + +# Add dependency on build_tests to build it on this custom target +add_dependencies(build_stress_test module kernels.code) diff --git a/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc b/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc new file mode 100644 index 0000000000..05c17c7b9b --- /dev/null +++ b/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc @@ -0,0 +1,86 @@ +/* + Copyright (c) 2021 - present 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 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* +Test Scenario +hipExtModuleLaunchKernel API verifying Corner Scenarios for Grid and Block dimensions +*/ + +#include "hip_test_common.hh" +#include "hip_test_kernels.hh" +#include "hip/hip_ext.h" + +#define fileName "kernels.code" +#define dummyKernel "EmptyKernel" + +struct gridblockDim { + unsigned int gridX; + unsigned int gridY; + unsigned int gridZ; + unsigned int blockX; + unsigned int blockY; + unsigned int blockZ; +}; + +/* +This testcase verifies hipExtModuleLaunchKernel API Corner +cases +*/ +TEST_CASE("Stress_hipExtModuleLaunchKernel_CornerCases") { + hipModule_t Module; + hipFunction_t DummyKernel; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); + constexpr auto gridblocksize{6}; + struct { + } args; + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + size_t size = sizeof(args); + void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + unsigned int maxblockX = deviceProp.maxThreadsDim[0]; + unsigned int maxblockY = deviceProp.maxThreadsDim[1]; + unsigned int maxblockZ = deviceProp.maxThreadsDim[2]; + struct gridblockDim test[gridblocksize] = {{1, 1, 1, maxblockX, 1, 1}, + {1, 1, 1, 1, maxblockY, 1}, + {1, 1, 1, 1, 1, maxblockZ}, + {UINT32_MAX, 1, 1, 1, 1, 1}, + {1, UINT32_MAX, 1, 1, 1, 1}, + {1, 1, UINT32_MAX, 1, 1, 1}}; + + // Launching kernel with corner cases in grid and block dimensions + for (int i = 0; i < gridblocksize; i++) { + HIP_CHECK(hipExtModuleLaunchKernel(DummyKernel, + test[i].gridX, + test[i].gridY, + test[i].gridZ, + test[i].blockX, + test[i].blockY, + test[i].blockZ, + 0, + stream, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0)); + } + HIP_CHECK(hipStreamDestroy(stream)); +} diff --git a/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc b/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc new file mode 100644 index 0000000000..f7bd866ceb --- /dev/null +++ b/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc @@ -0,0 +1,90 @@ +/* + Copyright (c) 2021 - present 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 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* +Test Scenario +hipModuleLaunchKernel API verifying Corner Scenarios for Grid and Block dimensions +*/ + +#include "hip_test_common.hh" +#include "hip_test_kernels.hh" +#include "hip/hip_ext.h" + +#define fileName "kernels.code" +#define dummyKernel "EmptyKernel" + +struct gridblockDim { + unsigned int gridX; + unsigned int gridY; + unsigned int gridZ; + unsigned int blockX; + unsigned int blockY; + unsigned int blockZ; +}; + +/* +This testcase verifies hipModuleLaunchKernel API Corner +cases +*/ +TEST_CASE("Stress_hipModuleLaunchKernel_CornerCases") { + HIP_CHECK(hipSetDevice(0)); + hipStream_t stream1; + CTX_CREATE() + hipModule_t Module; + hipFunction_t DummyKernel; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); + HIP_CHECK(hipStreamCreate(&stream1)); + + // Passing Max int value to block dimensions + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + unsigned int maxblockX = deviceProp.maxThreadsDim[0]; + unsigned int maxblockY = deviceProp.maxThreadsDim[1]; + unsigned int maxblockZ = deviceProp.maxThreadsDim[2]; +#if HT_NVIDIA + unsigned int maxgridX = deviceProp.maxGridSize[0]; + unsigned int maxgridY = deviceProp.maxGridSize[1]; + unsigned int maxgridZ = deviceProp.maxGridSize[2]; +#else + unsigned int maxgridX = UINT32_MAX; + unsigned int maxgridY = UINT32_MAX; + unsigned int maxgridZ = UINT32_MAX; +#endif + struct gridblockDim test[6] = {{1, 1, 1, maxblockX, 1, 1}, + {1, 1, 1, 1, maxblockY, 1}, + {1, 1, 1, 1, 1, maxblockZ}, + {maxgridX, 1, 1, 1, 1, 1}, + {1, maxgridY, 1, 1, 1, 1}, + {1, 1, maxgridZ, 1, 1, 1}}; + for (int i = 0; i < 6; i++) { + HIP_CHECK(hipModuleLaunchKernel(DummyKernel, + test[i].gridX, + test[i].gridY, + test[i].gridZ, + test[i].blockX, + test[i].blockY, + test[i].blockZ, + 0, + stream1, NULL, NULL)); + } + HIP_CHECK(hipStreamDestroy(stream1)); + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY(); +} diff --git a/tests/catch/stress/module/kernels.cc b/tests/catch/stress/module/kernels.cc new file mode 100644 index 0000000000..5a980c40e7 --- /dev/null +++ b/tests/catch/stress/module/kernels.cc @@ -0,0 +1,28 @@ +/* +Copyright (c) 2021 - present 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#include +#include "hip/hip_runtime.h" + +extern "C" __global__ void EmptyKernel() { +} + diff --git a/tests/catch/unit/CMakeLists.txt b/tests/catch/unit/CMakeLists.txt index f0ae8b6b93..0d19d6d82b 100644 --- a/tests/catch/unit/CMakeLists.txt +++ b/tests/catch/unit/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(module) add_subdirectory(memory) add_subdirectory(deviceLib) add_subdirectory(stream) diff --git a/tests/catch/unit/module/CMakeLists.txt b/tests/catch/unit/module/CMakeLists.txt new file mode 100644 index 0000000000..7e5d6aeaf6 --- /dev/null +++ b/tests/catch/unit/module/CMakeLists.txt @@ -0,0 +1,51 @@ +# Common Tests - Test independent of all platforms +if(HIP_PLATFORM MATCHES "amd") +set(TEST_SRC +hipExtLaunchKernelGGL.cc +hipExtModuleLaunchKernel.cc +hipExtLaunchMultiKernelMultiDevice.cc +hipModuleLaunchKernel.cc +hipFuncSetCacheConfig.cc +hipModuleUnload.cc +hipFuncSetAttribute.cc +hipModuleLoadData.cc +hipFuncSetSharedMemConfig.cc +hipManagedKeyword.cc +hipModuleGetGlobal.cc +hipFuncGetAttributes.cc +hipModule.cc +hipModuleLoadDataMultThreadOnMultGPU.cc +hipModuleLoadDataMultThreaded.cc +hipModuleLoadMultiThreaded.cc +hipModuleLoadUnloadStress.cc +hipModuleNegative.cc +hipModuleOccupancyMaxPotentialBlockSize.cc +hipModuleTexture2dDrv.cc +hipOpenCLCOTest.cc +) +else() +set(TEST_SRC +hipModuleLaunchKernel.cc +hipFuncSetCacheConfig.cc +hipModuleUnload.cc +hipFuncSetAttribute.cc +hipModuleLoadData.cc +hipFuncSetSharedMemConfig.cc +hipManagedKeyword.cc +hipModuleGetGlobal.cc +hipFuncGetAttributes.cc +hipModule.cc +hipModuleLoadDataMultThreadOnMultGPU.cc +hipModuleLoadDataMultThreaded.cc +hipModuleLoadMultiThreaded.cc +hipModuleLoadUnloadStress.cc +hipModuleNegative.cc +hipModuleOccupancyMaxPotentialBlockSize.cc +) +endif() + +add_custom_target(module_kernels.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${HIP_COMMON_DIR}/tests/catch/unit/module/module_kernels.cc -o ${HIP_PATH}/catch/hipTestMain/module_kernels.code -I${HIP_PATH}/include/ -I${HIP_COMMON_DIR}/tests/catch/include) +# Create shared lib of all tests +add_library(ModuleTest SHARED EXCLUDE_FROM_ALL ${TEST_SRC}) + +add_dependencies(build_tests ModuleTest module_kernels.code) diff --git a/tests/catch/unit/module/hipExtLaunchKernelGGL.cc b/tests/catch/unit/module/hipExtLaunchKernelGGL.cc new file mode 100755 index 0000000000..9ab420679e --- /dev/null +++ b/tests/catch/unit/module/hipExtLaunchKernelGGL.cc @@ -0,0 +1,129 @@ +/* + Copyright (c) 2021 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 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +/* + * Test Scenarios + 1. Verify kernel execution time of the particular kernel + 2. Verify hipExtLaunchKernelGGL API by disabling time flag in event creation + */ + +#include +#include +#include "hip/hip_ext.h" + +#define FOURSEC_KERNEL 4999 +#define TWOSEC_KERNEL 2999 + +__device__ int globalvar = 1; +__global__ void TwoSecKernel_GlobalVar(int clockrate) { + if (globalvar == 0x2222) { + globalvar = 0x3333; + } + HipTest::waitKernel(2, clockrate); + if (globalvar != 0x3333) { + globalvar = 0x5555; + } +} + +__global__ void FourSecKernel_GlobalVar(int clockrate) { + if (globalvar == 1) { + globalvar = 0x2222; + } + HipTest::waitKernel(4, clockrate); + if (globalvar == 0x2222) { + globalvar = 0x4444; + } +} + + +/* + * In this Scenario, we create events by disabling the timing flag + * We then Launch the kernel using hipExtModuleLaunchKernel by passing + * disabled events and try to fetch kernel execution time using + * hipEventElapsedTime API which would fail as the flag is disabled. + */ +TEST_CASE("Unit_hipExtLaunchKernelGGL_TimeFlagDisabled") { + hipStream_t stream; + HIP_CHECK(hipSetDevice(0)); + float time_2sec; + hipEvent_t start_event, end_event; + int clkRate = 0; + HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); + + // Event Creation and Launching kernels + HIP_CHECK(hipEventCreateWithFlags(&start_event, + hipEventDisableTiming)); + HIP_CHECK(hipEventCreateWithFlags(&end_event, + hipEventDisableTiming)); + HIP_CHECK(hipStreamCreate(&stream)); + + hipExtLaunchKernelGGL(TwoSecKernel_GlobalVar, dim3(1), dim3(1), 0, + stream, start_event, end_event, 0, clkRate); + HIP_CHECK(hipStreamSynchronize(stream)); + REQUIRE(hipEventElapsedTime(&time_2sec, start_event, end_event) + != hipSuccess); + + // Destroying the events and streams + HIP_CHECK(hipStreamDestroy(stream)); + HIP_CHECK(hipEventDestroy(start_event)); + HIP_CHECK(hipEventDestroy(end_event)); +} +/* + * Launching FourSecKernel and TwoSecKernel and then we try to + * get the event elapsed time of each kernel using the start and + * end events.The event elapsed time should return us the kernel + * execution time for that particular kernel +*/ +TEST_CASE("Unit_hipExtLaunchKernelGGL_KernelTimeExecution") { + hipStream_t stream; + HIP_CHECK(hipSetDevice(0)); + hipEvent_t start_event1, end_event1, start_event2, end_event2; + float time_4sec, time_2sec; + int clkRate = 0; + HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); + + // Creating streams and events + HIP_CHECK(hipEventCreate(&start_event1)); + HIP_CHECK(hipEventCreate(&end_event1)); + HIP_CHECK(hipEventCreate(&start_event2)); + HIP_CHECK(hipEventCreate(&end_event2)); + HIP_CHECK(hipStreamCreate(&stream)); + + // Launching 4sec and 2sec kernels + hipExtLaunchKernelGGL(FourSecKernel_GlobalVar, dim3(1), dim3(1), 0, + stream, start_event1, end_event1, 0, clkRate); + hipExtLaunchKernelGGL(TwoSecKernel_GlobalVar, dim3(1), dim3(1), 0, + stream, start_event2, end_event2, 0, clkRate); + HIP_CHECK(hipStreamSynchronize(stream)); + + HIP_CHECK(hipEventElapsedTime(&time_4sec, start_event1, end_event1)); + HIP_CHECK(hipEventElapsedTime(&time_2sec, start_event2, end_event2)); + + INFO("Expected Vs Actual: Kernel1-<" << FOURSEC_KERNEL << "Vs" << time_4sec + << "Kernel2-<" << TWOSEC_KERNEL << "Vs" << time_2sec); + // Verifying the kernel execution time + REQUIRE(time_4sec < static_cast(FOURSEC_KERNEL)); + REQUIRE(time_2sec < static_cast(TWOSEC_KERNEL)); + + // Destroying streams and events + HIP_CHECK(hipStreamDestroy(stream)); + HIP_CHECK(hipEventDestroy(start_event1)); + HIP_CHECK(hipEventDestroy(end_event1)); + HIP_CHECK(hipEventDestroy(start_event2)); + HIP_CHECK(hipEventDestroy(end_event2)); +} diff --git a/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc b/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc new file mode 100644 index 0000000000..d83c425b3d --- /dev/null +++ b/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc @@ -0,0 +1,128 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 testfile verifies the basic functionality of + hipExtLaunchMultiKernelMultiDevice API. + It can be tested on single GPU or multi GPUs. +*/ + + +#include +#include +#include "hip/hip_runtime.h" + +#define MAX_GPUS 8 +#define NUM_KERNEL_ARGS 3 + +/* +This testcase verifies hipExtLaunchMultiKernelMultiDevice API for different +datatypes where +1. Intitialize device variables +2. Initializing hipLaunchParams structure to pass it to + hipExtLaunchMultiKernelMultiDevice API +3. Launches vector_square kernel which performs square of the variable +4. Validates the result with the square of variable. +*/ + +TEMPLATE_TEST_CASE("Unit_hipExtLaunchMultiKernelMultiDevice_Basic", "", int + , float, double) { + TestType *A_d[MAX_GPUS], *C_d[MAX_GPUS]; + TestType *A_h, *C_h; + size_t N = 1000000; + size_t Nbytes = N * sizeof(TestType); + int nGpu = 0; + + HIP_CHECK(hipGetDeviceCount(&nGpu)); + if (nGpu < 1) { + SUCCEED("info: didn't find any GPU! Skipping the testcase"); + } else { + if (nGpu > MAX_GPUS) { + nGpu = MAX_GPUS; + } + HipTest::initArrays(nullptr, nullptr, nullptr, + &A_h, nullptr, &C_h, N, false); + const unsigned blocks = 512; + const unsigned threadsPerBlock = 256; + + // Allocating and initializing device variables + hipStream_t stream[MAX_GPUS]; + for (int i = 0; i < nGpu; i++) { + HIP_CHECK(hipSetDevice(i)); + HIP_CHECK(hipStreamCreateWithFlags(&stream[i], hipStreamNonBlocking)); + hipDeviceProp_t props; + HIP_CHECK(hipGetDeviceProperties(&props, i/*deviceID*/)); + INFO("Running on bus 0x" << props.pciBusID << " " << props.name); + INFO("Allocate device mem " << 2*Nbytes/1024.0/1024.0); + HIP_CHECK(hipMalloc(&A_d[i], Nbytes)); + HIP_CHECK(hipMalloc(&C_d[i], Nbytes)); + HIP_CHECK(hipMemcpy(A_d[i], A_h, Nbytes, hipMemcpyHostToDevice)); + } + + hipLaunchParams *launchParamsList = reinterpret_cast( + malloc(sizeof(hipLaunchParams)*nGpu)); + void *args[MAX_GPUS * NUM_KERNEL_ARGS]; + + // Intializing the hipLaunchParams structure with device variables + // ,kernel and launching hipExtLaunchMultiKernelMultiDevice API + for (int i = 0; i < nGpu; i++) { + args[i * NUM_KERNEL_ARGS] = &A_d[i]; + args[i * NUM_KERNEL_ARGS + 1] = &C_d[i]; + args[i * NUM_KERNEL_ARGS + 2] = &N; + launchParamsList[i].func = + reinterpret_cast(HipTest::vector_square); + launchParamsList[i].gridDim = dim3(blocks); + launchParamsList[i].blockDim = dim3(threadsPerBlock); + launchParamsList[i].sharedMem = 0; + launchParamsList[i].stream = stream[i]; + launchParamsList[i].args = args + i * NUM_KERNEL_ARGS; + } + + hipExtLaunchMultiKernelMultiDevice(launchParamsList, nGpu, 0); + + // Validating the result + for (int j = 0; j < nGpu; j++) { + hipStreamSynchronize(stream[j]); + hipDeviceProp_t props; + HIP_CHECK(hipGetDeviceProperties(&props, j/*deviceID*/)); + INFO("Checking result on bus " << props.pciBusID << props.name); + + HIP_CHECK(hipSetDevice(j)); + HIP_CHECK(hipMemcpy(C_h, C_d[j], Nbytes, hipMemcpyDeviceToHost)); + + for (size_t i = 0; i < N; i++) { + if (C_h[i] != A_h[i] * A_h[i]) { + INFO("validation failed " << C_h[i] << A_h[i]*A_h[i]); + REQUIRE(false); + } + } + } + + // DeAllocating memory + HipTest::freeArrays(nullptr, nullptr, nullptr, + A_h, nullptr, C_h, false); + for (int j = 0; j < nGpu; j++) { + HIP_CHECK(hipFree(A_d[j])); + HIP_CHECK(hipFree(C_d[j])); + HIP_CHECK(hipStreamDestroy(stream[j])); + } + } +} diff --git a/tests/catch/unit/module/hipExtModuleLaunchKernel.cc b/tests/catch/unit/module/hipExtModuleLaunchKernel.cc new file mode 100755 index 0000000000..45db114135 --- /dev/null +++ b/tests/catch/unit/module/hipExtModuleLaunchKernel.cc @@ -0,0 +1,433 @@ +/* + Copyright (c) 2021 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 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +/* Test Scenarios + 1. hipExtModuleLaunchKernel Negative Scenarios + 2. hipExtModuleLaunchKernel API verifying the kernel execution time of a particular kernel. + 3. hipExtModuleLaunchKernel API verifying the kernel execution time by disabling the time flag + 4. hipModuleLaunchKernel Work Group tests => + - (block.x * block.y * block.z) <= Work Group Size + where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + - (block.x * block.y * block.z) > Work Group Size + where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + */ + +#include +#include "hip_test_common.hh" +#include "hip_test_kernels.hh" +#include "hip/hip_ext.h" + +#define fileName "module_kernels.code" +#define matmulK "matmulK" +#define SixteenSec "SixteenSecKernel" +#define KernelandExtra "KernelandExtraParams" +#define FourSec "FourSecKernel" +#define TwoSec "TwoSecKernel" +#define globalDevVar "deviceGlobal" +#define dummyKernel "EmptyKernel" +#define FOURSEC_KERNEL 4999 +#define TWOSEC_KERNEL 2999 + +struct gridblockDim { + unsigned int gridX; + unsigned int gridY; + unsigned int gridZ; + unsigned int blockX; + unsigned int blockY; + unsigned int blockZ; +}; + +class ModuleLaunchKernel { + int N = 64; + int SIZE = N*N; + int *A, *B, *C; + hipDeviceptr_t *Ad, *Bd; + hipStream_t stream1, stream2; + hipEvent_t start_event1, end_event1, start_event2, end_event2, + start_timingDisabled, end_timingDisabled; + hipModule_t Module; + hipDeviceptr_t deviceGlobal; + hipFunction_t MultKernel, SixteenSecKernel, FourSecKernel, + TwoSecKernel, KernelandExtraParamKernel, DummyKernel; + struct { + int clockRate; + void* _Ad; + void* _Bd; + void* _Cd; + int _n; + } args1, args2; + struct { + } args3; + size_t size1; + size_t size2; + size_t size3; + size_t deviceGlobalSize; + public : + void AllocateMemory(); + void DeAllocateMemory(); + void ModuleLoad(); + void Module_Negative_tests(); + void ExtModule_Negative_tests(); + void Module_WorkGroup_Test(); + void ExtModule_KernelExecutionTime(); + void ExtModule_Disabled_Timingflag(); +}; + +void ModuleLaunchKernel::AllocateMemory() { + A = new int[N*N*sizeof(int)]; + B = new int[N*N*sizeof(int)]; + for (int i=0; i < N; i++) { + for (int j=0; j < N; j++) { + A[i*N +j] = 1; + B[i*N +j] = 1; + } + } + HIP_CHECK(hipStreamCreate(&stream1)); + HIP_CHECK(hipStreamCreate(&stream2)); + HIP_CHECK(hipMalloc(reinterpret_cast(&Ad), + SIZE*sizeof(int))); + HIP_CHECK(hipMalloc(reinterpret_cast(&Bd), + SIZE*sizeof(int))); + HIP_CHECK(hipHostMalloc(reinterpret_cast(&C), SIZE*sizeof(int))); + HIP_CHECK(hipMemcpy(Ad, A, SIZE*sizeof(int), hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(Bd, B, SIZE*sizeof(int), hipMemcpyHostToDevice)); + int clkRate = 0; + HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); + args1._Ad = Ad; + args1._Bd = Bd; + args1._Cd = C; + args1._n = N; + args1.clockRate = clkRate; + args2._Ad = NULL; + args2._Bd = NULL; + args2._Cd = NULL; + args2._n = 0; + args2.clockRate = clkRate; + size1 = sizeof(args1); + size2 = sizeof(args2); + size3 = sizeof(args3); + HIP_CHECK(hipEventCreate(&start_event1)); + HIP_CHECK(hipEventCreate(&end_event1)); + HIP_CHECK(hipEventCreate(&start_event2)); + HIP_CHECK(hipEventCreate(&end_event2)); + HIP_CHECK(hipEventCreateWithFlags(&start_timingDisabled, + hipEventDisableTiming)); + HIP_CHECK(hipEventCreateWithFlags(&end_timingDisabled, + hipEventDisableTiming)); +} + +void ModuleLaunchKernel::ModuleLoad() { + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&MultKernel, Module, matmulK)); + HIP_CHECK(hipModuleGetFunction(&SixteenSecKernel, Module, SixteenSec)); + HIP_CHECK(hipModuleGetFunction(&KernelandExtraParamKernel, + Module, KernelandExtra)); + HIP_CHECK(hipModuleGetFunction(&FourSecKernel, Module, FourSec)); + HIP_CHECK(hipModuleGetFunction(&TwoSecKernel, Module, TwoSec)); + HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); + HIP_CHECK(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, + Module, globalDevVar)); +} + +void ModuleLaunchKernel::DeAllocateMemory() { + HIP_CHECK(hipEventDestroy(start_event1)); + HIP_CHECK(hipEventDestroy(end_event1)); + HIP_CHECK(hipEventDestroy(start_event2)); + HIP_CHECK(hipEventDestroy(end_event2)); + HIP_CHECK(hipEventDestroy(start_timingDisabled)); + HIP_CHECK(hipEventDestroy(end_timingDisabled)); + HIP_CHECK(hipStreamDestroy(stream1)); + HIP_CHECK(hipStreamDestroy(stream2)); + delete[] A; + delete[] B; + HIP_CHECK(hipFree(Ad)); + HIP_CHECK(hipFree(Bd)); + HIP_CHECK(hipHostFree(C)); + HIP_CHECK(hipModuleUnload(Module)); +} +/* + * In this scenario,We launch the 4 sec kernel and 2 sec kernel + * and we fetch the event execution time of each kernel and it + * should not exceed the execution time of that particular kernel + */ +void ModuleLaunchKernel::ExtModule_KernelExecutionTime() { + HIP_CHECK(hipSetDevice(0)); + AllocateMemory(); + ModuleLoad(); + float time_4sec, time_2sec; + void *config2[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args2, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size2, + HIP_LAUNCH_PARAM_END}; + + // Launching kernels + HIP_CHECK(hipExtModuleLaunchKernel(FourSecKernel, 1, 1, 1, 1, 1, 1, 0, + stream1, + NULL, reinterpret_cast(&config2), + start_event1, end_event1, 0)); + HIP_CHECK(hipExtModuleLaunchKernel(TwoSecKernel, 1, 1, 1, 1, 1, 1, 0, stream1, + NULL, reinterpret_cast(&config2), + start_event2, end_event2, 0)); + HIP_CHECK(hipStreamSynchronize(stream1)); + HIP_CHECK(hipEventElapsedTime(&time_4sec, start_event1, end_event1)); + HIP_CHECK(hipEventElapsedTime(&time_2sec, start_event2, end_event2)); + + INFO("Expected Vs Actual: Kernel1-<" << FOURSEC_KERNEL << "Vs" << time_4sec + << "Kernel2-<" << TWOSEC_KERNEL << "Vs" << time_2sec); + // Verifying the kernel execution time + REQUIRE(time_4sec < static_cast(FOURSEC_KERNEL)); + REQUIRE(time_2sec < static_cast(TWOSEC_KERNEL)); + + DeAllocateMemory(); +} +/* + * In this Scenario, we create events by disabling the timing flag + * We then Launch the kernel using hipExtModuleLaunchKernel by passing + * disabled events and try to fetch kernel execution time using + * hipEventElapsedTime API which would fail as the flag is disabled. + */ +void ModuleLaunchKernel::ExtModule_Disabled_Timingflag() { + // Allocating Memory and Loading kernel + AllocateMemory(); + ModuleLoad(); + float time_2sec; + void *config2[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args2, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size2, + HIP_LAUNCH_PARAM_END}; + + // Launching Kernel + HIP_CHECK(hipExtModuleLaunchKernel(TwoSecKernel, 1, 1, 1, 1, 1, 1, 0, stream1, + NULL, reinterpret_cast(&config2), + start_timingDisabled, + end_timingDisabled, 0)); + HIP_CHECK(hipStreamSynchronize(stream1)); + + REQUIRE(hipEventElapsedTime(&time_2sec, start_timingDisabled, + end_timingDisabled) != hipSuccess); + + // DeAllocating the memory + DeAllocateMemory(); +} + +/* +This testcase verifies negative scenarios of hipExtModuleLaunchKernel API +*/ +void ModuleLaunchKernel::ExtModule_Negative_tests() { + HIP_CHECK(hipSetDevice(0)); + // Allocating memeory and loading kernel + AllocateMemory(); + ModuleLoad(); + void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args1, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, + HIP_LAUNCH_PARAM_END}; + void *params[] = {Ad}; + + SECTION("Nullptr to kernel function") { + REQUIRE(hipExtModuleLaunchKernel(nullptr, 1, 1, 1, 1, 1, 1, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Max int value to block dimensions") { + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Null values to all dimensions") { + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 0, 0, 0, + 0, + 0, + 0, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing 0 for x dimension") { + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 0, 1, 1, + 0, + 1, + 1, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing 0 for y dimension") { + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 0, 1, + 1, + 0, + 1, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing 0 for Z dimension") { + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 0, + 1, + 1, + 0, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing both kernel and extra params") { + REQUIRE(hipExtModuleLaunchKernel(KernelandExtraParamKernel, 1, 1, 1, 1, + 1, 1, 0, + stream1, + reinterpret_cast(¶ms), + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing both than maxthreadsperblock to block dimensions") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, + deviceProp.maxThreadsPerBlock+1, + deviceProp.maxThreadsPerBlock+1, + deviceProp.maxThreadsPerBlock+1, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Block dimension x = Max alloweed + 1") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, + deviceProp.maxThreadsDim[0]+1, + 1, + 1, 0, stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Block dimension Y = Max alloweed + 1") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, + 1, + deviceProp.maxThreadsDim[1]+1, + 1, 0, stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Block dimension Z = Max alloweed + 1") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, + 1, + 1, + deviceProp.maxThreadsDim[2]+1, 0, + stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + } + + SECTION("Passing invalid config data in extra params") { + void *config3[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, + HIP_LAUNCH_PARAM_END}; + REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, 1, 1, 1, 0, + stream1, NULL, + reinterpret_cast(&config3), + nullptr, nullptr, 0) != hipSuccess); + } + + DeAllocateMemory(); +} + +void ModuleLaunchKernel::Module_WorkGroup_Test() { + // Allocate memory and load modules + AllocateMemory(); + ModuleLoad(); + void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args3, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size3, + HIP_LAUNCH_PARAM_END}; + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + double cuberootVal = + cbrt(static_cast(deviceProp.maxThreadsPerBlock)); + uint32_t cuberoot_floor = floor(cuberootVal); + uint32_t cuberoot_ceil = ceil(cuberootVal); + + // Scenario: (block.x * block.y * block.z) <= Work Group Size where + // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + HIP_CHECK(hipExtModuleLaunchKernel(DummyKernel, + 1, 1, 1, + cuberoot_floor, cuberoot_floor, cuberoot_floor, + 0, stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0)); + + // Scenario: (block.x * block.y * block.z) > Work Group Size where + // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + REQUIRE(hipExtModuleLaunchKernel(DummyKernel, + 1, 1, 1, + cuberoot_ceil, cuberoot_ceil, cuberoot_ceil+1, + 0, stream1, NULL, + reinterpret_cast(&config1), + nullptr, nullptr, 0) != hipSuccess); + + // DeAllocating memory + DeAllocateMemory(); +} + +/* +This testcase verifies the negative scenarios of +hipExtModuleLaunchKernel API +*/ +TEST_CASE("Unit_hipExtModuleLaunchKernel_Negative") { + ModuleLaunchKernel Ext_obj; + Ext_obj.ExtModule_Negative_tests(); +} + +/* +This testcase verifies hipExtModuleLaunchKernel API by +disabling the timing flag +*/ +TEST_CASE("Unit_hipExtModuleLaunchKernel_TimingflagDisabled") { + ModuleLaunchKernel Ext_obj; + Ext_obj.ExtModule_Disabled_Timingflag(); +} + +/* +This testcase verifies hipExtModuleLaunchKernel API kernel +execution time +*/ +TEST_CASE("Unit_hipExtModuleLaunchKernel_KernelExecutionTime") { + ModuleLaunchKernel Ext_obj; + Ext_obj.ExtModule_KernelExecutionTime(); +} + +/* +This testcase verifies workgroup of hipExtModuleLaunchKernel API +*/ +TEST_CASE("Unit_hipExtModuleLaunchKernel_WorkGroup") { + ModuleLaunchKernel Ext_obj; + Ext_obj.Module_WorkGroup_Test(); +} diff --git a/tests/catch/unit/module/hipFuncGetAttributes.cc b/tests/catch/unit/module/hipFuncGetAttributes.cc new file mode 100644 index 0000000000..5e21dc17c6 --- /dev/null +++ b/tests/catch/unit/module/hipFuncGetAttributes.cc @@ -0,0 +1,163 @@ + +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ +#include +#include + +#define fileName "module_kernels.code" +#define kernel_name "hello_world" + +namespace testhipFuncGetAttributesApi { +__global__ +void fn(float* px, float* py) { + bool a[42]; + __shared__ double b[69]; + for (auto&& x : b) x = *py++; + for (auto&& x : a) x = *px++ > 0.0; + for (auto&& x : a) if (x) *--py = *--px; +} +template +__launch_bounds__(WGSIZE, 1) __global__ void kernelfn(int *x) { + __shared__ int lds[LDS]; + for (int i = 0; i < LDS; ++i) { + lds[i] = x[i]; + } + x[LDS - 1] = lds[0] / lds[LDS - 1]; +} +template bool test_Attributes_Values() { + bool TestPassed = true; + hipFuncAttributes attr{}; + hipFuncGetAttributes(&attr, + reinterpret_cast(kernelfn)); + if (attr.maxThreadsPerBlock != WGSIZE) { + TestPassed = false; + } + if (attr.sharedSizeBytes != LDS * sizeof(int)) { + TestPassed = false; + } + return TestPassed; +} +} // namespace testhipFuncGetAttributesApi +/** + * hipFuncGetAttributes and hipModuleGetFunction functional tests + * Scenario1: Validates the value of attribute "maxThreadsPerBlock" should be non zero. + * Scenario2: Validates the value of attribute + * "HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK" should be non zero. + */ +// scenario 1 +TEST_CASE("Unit_hipFuncGetAttributes_FuncTst") { + hipFuncAttributes attr{}; + auto r = hipFuncGetAttributes(&attr, + reinterpret_cast(&testhipFuncGetAttributesApi::fn)); + REQUIRE_FALSE(r != hipSuccess); + REQUIRE_FALSE(attr.maxThreadsPerBlock == 0); +} +// scenario 2 +TEST_CASE("Unit_hipFuncGetAttribute_FuncTst") { + hipModule_t Module; + int attrib_val; + CTX_CREATE() + hipFunction_t Function; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + auto r = hipFuncGetAttribute(&attrib_val, + HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, Function); + REQUIRE_FALSE(r != hipSuccess); + REQUIRE_FALSE(attrib_val == 0); + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} +/** + * hipFuncGetAttributes negative tests + * Scenario1: Validates returned error code for attr = nullptr + * Scenario2: Validates returned error code for function = nullptr + */ +TEST_CASE("Unit_hipFuncGetAttributes_NegTst") { + SECTION("attr is nullptr") { + REQUIRE_FALSE(hipSuccess == hipFuncGetAttributes(nullptr, + reinterpret_cast(&testhipFuncGetAttributesApi::fn))); + } + SECTION("function is nullptr") { + hipFuncAttributes attr{}; + REQUIRE_FALSE(hipSuccess == hipFuncGetAttributes(&attr, nullptr)); + } +} +/** + * hipFuncGetAttribute negative tests + * Scenario1: Validates returned error code for attrib_val = nullptr + * Scenario2: Validates returned error code for attrib = invalid = 0xff + */ +TEST_CASE("Unit_hipFuncGetAttribute_NegTst") { + hipModule_t Module; + CTX_CREATE() + hipFunction_t Function; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + SECTION("attr is nullptr") { + REQUIRE_FALSE(hipSuccess == hipFuncGetAttribute(nullptr, + HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, Function)); + } + SECTION("attr is invalid") { + int attrib_val; + REQUIRE_FALSE(hipSuccess == hipFuncGetAttribute(&attrib_val, + static_cast(0xff), Function)); + } + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} +/** + * hipFuncGetAttributes + * Scenario4: Validates the value of attribute "maxThreadsPerBlock". + * Scenario5: Validates the value of attribute "sharedSizeBytes". + */ +TEST_CASE("Unit_hipFuncGetAttributes_AttrTest") { + bool TestPassed = true; + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<64, 64>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<128, 64>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<256, 64>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<512, 64>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<1024, 64>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<64, 128>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<128, 128>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<256, 128>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<512, 128>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<1024, 128>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<64, 256>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<128, 256>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<256, 256>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<512, 256>(); + TestPassed &= testhipFuncGetAttributesApi:: + test_Attributes_Values<1024, 256>(); + REQUIRE(TestPassed); +} + diff --git a/tests/catch/unit/module/hipFuncSetAttribute.cc b/tests/catch/unit/module/hipFuncSetAttribute.cc new file mode 100644 index 0000000000..33602f9078 --- /dev/null +++ b/tests/catch/unit/module/hipFuncSetAttribute.cc @@ -0,0 +1,46 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#include "hip_test_common.hh" + +__global__ void fn(float* px, float* py) { + bool a[42]; + __shared__ double b[69]; + + for (auto&& x : b) x = *py++; + for (auto&& x : a) x = *px++ > 0.0; + for (auto&& x : a) if (x) *--py = *--px; +} + +/* +This testcases verifies the basic func of hipFuncSetAttribute API where +we need to pass function that executes on device +hipFuncAttributeMaxDynamicSharedMemorySize --> +The sum of this value + sharedSizeBytes should not exceed device attribute +hipFuncAttributePreferredSharedMemoryCarveout --> +Carving out the shared memory. +*/ +TEST_CASE("Unit_hipFuncSetAttribute_Basic") { + HIP_CHECK(hipFuncSetAttribute(reinterpret_cast(&fn), + hipFuncAttributeMaxDynamicSharedMemorySize, + 0)); + HIP_CHECK(hipFuncSetAttribute(reinterpret_cast(&fn), + hipFuncAttributePreferredSharedMemoryCarveout, + 0)); +} diff --git a/tests/catch/unit/module/hipFuncSetCacheConfig.cc b/tests/catch/unit/module/hipFuncSetCacheConfig.cc new file mode 100644 index 0000000000..cd5d58a8f6 --- /dev/null +++ b/tests/catch/unit/module/hipFuncSetCacheConfig.cc @@ -0,0 +1,36 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#include + +__global__ void Empty_Kernel() { +} + +/* +This testcase verifies the basic funct of hipFuncSetCacheConfig API +On GPU devices, where L1 and shared memory uses same resources +This sets the preferred cache configuration for the kernel function +In this testcases we are setting hipFuncCachePreferL1 where L1 is +preferred more than shared memory +*/ +TEST_CASE("Unit_hipFuncSetCacheConfig_Basic") { + hipFuncCache_t cacheConfig{hipFuncCachePreferL1}; + HIP_CHECK(hipFuncSetCacheConfig(reinterpret_cast(Empty_Kernel), + cacheConfig)); +} diff --git a/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc b/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc new file mode 100644 index 0000000000..c9d65275b5 --- /dev/null +++ b/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc @@ -0,0 +1,107 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +// Test Description: +// This test case verifies the working of hipFuncSetSharedMemConfig() api and +// the flag parameter + +#include +#include + + +__global__ void ReverseSeq(int *A, int *B, int N) { + extern __shared__ int SMem[]; + int offset = threadIdx.x; + int MirrorVal = N - offset - 1; + SMem[offset] = A[offset]; + __syncthreads(); + B[offset] = SMem[MirrorVal]; +} +/* +This testcase verifies the basic functionality of hipFuncSetSharedMemConfig API +by setting shared memory bank size + +1. hipSharedMemBankSizeDefault +2. hipSharedMemBankSizeFourByte +3. hipSharedMemBankSizeEightByte + +*/ +TEST_CASE("Unit_hipFuncSetSharedMemConfig_Basic") { + int *Ah{nullptr}, *RAh{nullptr}, NumElms = 128; + int *Ad{nullptr}, *RAd{nullptr}; + + HipTest::initArrays(&Ad, &RAd, nullptr, + &Ah, &RAh, nullptr, NumElms, false); + for (int i = 0; i < NumElms; ++i) { + Ah[i] = i; + RAh[i] = NumElms - i - 1; + } + HIP_CHECK(hipMemcpy(Ad, Ah, NumElms * sizeof(int), hipMemcpyHostToDevice)); + HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); + + // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeDefault flag + HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast + (&ReverseSeq), + hipSharedMemBankSizeDefault)); + + // Kernel Launch with shared mem size of = NumElms * sizeof(int) + ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); + memset(Ah, 0, NumElms * sizeof(int)); + + // Verifying the results + HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); + for (int i = 0; i < NumElms; ++i) { + REQUIRE(Ah[i] == RAh[i]); + } + + // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeFourBytes flg + HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast + (&ReverseSeq), + hipSharedMemBankSizeFourByte)); + HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); + + // Kernel Launch with shared mem size of = NumElms * sizeof(int) + ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); + memset(Ah, 0, NumElms * sizeof(int)); + + // Verifying the results + HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); + for (int i = 0; i < NumElms; ++i) { + REQUIRE(Ah[i] == RAh[i]); + } + + // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeEightBytes flg + HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast + (&ReverseSeq), + hipSharedMemBankSizeEightByte)); + HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); + + // Kernel Launch with shared mem size of = NumElms * sizeof(int) + ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); + memset(Ah, 0, NumElms * sizeof(int)); + + // Verifying the results + HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); + for (int i = 0; i < NumElms; ++i) { + REQUIRE(Ah[i] == RAh[i]); + } + + HipTest::freeArrays(Ad, RAd, nullptr, + Ah, RAh, nullptr, false); +} diff --git a/tests/catch/unit/module/hipManagedKeyword.cc b/tests/catch/unit/module/hipManagedKeyword.cc new file mode 100644 index 0000000000..7ed9bbe630 --- /dev/null +++ b/tests/catch/unit/module/hipManagedKeyword.cc @@ -0,0 +1,56 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ +/* +hipManagedKeyword API Scenario +1. Test hipModuleLoad on multiple GPUs +*/ + +#include "hip_test_common.hh" +#include "hip_test_kernels.hh" +#include "hip_test_checkers.hh" + +#define MANAGED_VAR_INIT_VALUE 10 +#define fileName "module_kernels.code" + +TEST_CASE("Unit_hipMangedKeyword_ModuleLoadMultiGPU") { + int numDevices = 0, data; + hipDeviceptr_t x; + size_t xSize; + hipGetDeviceCount(&numDevices); + for (int i = 0; i < numDevices; i++) { + hipSetDevice(i); + CTX_CREATE() + hipModule_t Module; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "GPU_func")); + HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, 1, 1, + 1, 0, 0, NULL, NULL)); + hipDeviceSynchronize(); + HIP_CHECK(hipModuleGetGlobal(reinterpret_cast(&x), + &xSize, Module, "x")); + HIP_CHECK(hipMemcpyDtoH(&data, hipDeviceptr_t(x), xSize)); + REQUIRE(data == (1 + MANAGED_VAR_INIT_VALUE)); + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() + } +} diff --git a/tests/catch/unit/module/hipModule.cc b/tests/catch/unit/module/hipModule.cc new file mode 100755 index 0000000000..9683eacee9 --- /dev/null +++ b/tests/catch/unit/module/hipModule.cc @@ -0,0 +1,183 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +This testcase verifies the hipModuleLoad API On +1. Single code object +2. Multi Target architecture code object +*/ +#include +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" +#ifdef __linux__ +#include +#endif +#define LEN 64 +#define SIZE (LEN << 2) +#define COMMAND_LEN 256 +#define CODE_OBJ_SINGLEARCH "module_kernels.code" +#define kernel_name "hello_world" +#define CODE_OBJ_MULTIARCH "vcpy_kernel_multarch.code" + +/* +This API loads the kernel function, Launches the kernel +which copies one variable to another and validates both +the device variables for the current GPU architecture +*/ +void testCodeObjFile(const char *codeObjFile) { + float *A, *B; + float *Ad, *Bd; + HipTest::initArrays(&Ad, &Bd, nullptr, + &A, &B, nullptr, LEN, false); + + HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(Ad), A, SIZE)); + HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(Bd), B, SIZE)); + + hipModule_t Module; + hipFunction_t Function; + HIP_CHECK(hipModuleLoad(&Module, codeObjFile)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + + struct { + void* _Ad; + void* _Bd; + } args; + args._Ad = reinterpret_cast(Ad); + args._Bd = reinterpret_cast(Bd); + size_t size = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, + stream, NULL, + reinterpret_cast(&config))); + + HIP_CHECK(hipStreamDestroy(stream)); + + HIP_CHECK(hipMemcpyDtoH(B, reinterpret_cast(Bd), SIZE)); + + for (uint32_t i = 0; i < LEN; i++) { + REQUIRE(A[i] == B[i]); + } + + HipTest::freeArrays(Ad, Bd, nullptr, + A, B, nullptr, + false); + HIP_CHECK(hipModuleUnload(Module)); +} + +#ifdef __linux__ +/** + * Check if environment variable $ROCM_PATH is defined + * + */ +bool isRocmPathSet() { + FILE *fpipe; + char const *command = "echo $ROCM_PATH"; + fpipe = popen(command, "r"); + + if (fpipe == nullptr) { + WARN("Unable to create command"); + return false; + } + char command_op[COMMAND_LEN]; + if (fgets(command_op, COMMAND_LEN, fpipe)) { + size_t len = strlen(command_op); + if (len > 1) { // This is because fgets always adds newline character + pclose(fpipe); + return true; + } + } + pclose(fpipe); + return false; +} +#endif +/* +This testcase checks the hipModuleLoadData API for the +current GPU architecture. +*/ +TEST_CASE("Unit_hipModule_TestCodeObjFile") { + testCodeObjFile(CODE_OBJ_SINGLEARCH); +} + +/* +This testcases +1. Creates kernel file and copies to tmp folder +2. Checks for Rocm path and generates code file for + multiple target architectures. +*/ +TEST_CASE("Unit_hipModule_MultiTargArchCodeObj") { +#ifdef __linux__ + char command[COMMAND_LEN]; + hipDeviceProp_t props; + hipGetDeviceProperties(&props, 0); + // Hardcoding the codeobject lines in multiple string to avoid cpplint warning + std::string CodeObjL1 = "#include \"hip/hip_runtime.h\"\n"; + std::string CodeObjL2 = + "extern \"C\" __global__ void hello_world(float* a, float* b) {\n"; + std::string CodeObjL3 = " int tx = hipThreadIdx_x;\n"; + std::string CodeObjL4 = " b[tx] = a[tx];\n"; + std::string CodeObjL5 = "}"; + // Creating the full code object string + static std::string CodeObj = CodeObjL1 + CodeObjL2 + CodeObjL3 + + CodeObjL4 + CodeObjL5; + std::ofstream ofs("/tmp/vcpy_kernel.cpp", std::ofstream::out); + ofs << CodeObj; + ofs.close(); + // Copy the file into current working location if not available + if (access("/tmp/vcpy_kernel.cpp", F_OK) == -1) { + INFO("Code Object File: /tmp/vcpy_kernel.cpp not found"); + REQUIRE(true); + } + // Generate the command to generate multi architecture code object file + const char* hipcc_path = nullptr; + if (isRocmPathSet()) { + hipcc_path = "$ROCM_PATH/bin/hipcc"; + } else { + hipcc_path = "/opt/rocm/bin/hipcc"; + } + /* Putting these command parameters into a variable to shorten the string + literal length in order to avoid multiline string literal cpplint warning + */ + const char* genco_option = "--offload-arch"; + const char* input_codeobj = "/tmp/vcpy_kernel.cpp"; + snprintf(command, COMMAND_LEN, + "%s --genco %s=gfx801,gfx802,gfx803,gfx900,gfx908,gfx1030,gfx90a,%s %s -o %s", + hipcc_path, genco_option, props.gcnArchName, input_codeobj, + CODE_OBJ_MULTIARCH); + + system((const char*)command); + // Check if the code object file is created + snprintf(command, COMMAND_LEN, "./%s", + CODE_OBJ_MULTIARCH); + + if (access(command, F_OK) == -1) { + INFO("Code Object File not found"); + REQUIRE(true); + } else { + testCodeObjFile(CODE_OBJ_MULTIARCH); + } +#else + SUCCEED("This test is skipped due to non linux environment"); +#endif +} diff --git a/tests/catch/unit/module/hipModuleGetGlobal.cc b/tests/catch/unit/module/hipModuleGetGlobal.cc new file mode 100755 index 0000000000..e99e3a64f1 --- /dev/null +++ b/tests/catch/unit/module/hipModuleGetGlobal.cc @@ -0,0 +1,120 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + + +#include +#include +#include +#include + +#define LEN 64 +#define SIZE LEN * sizeof(float) +#define ARRAY_SIZE 16 +#define fileName "module_kernels.code" + +/* +This testcase verifies the basic functionality of hipModuleGetGlobal API +1. Simple kernel +2. Global variables +*/ +TEST_CASE("Unit_hipModuleGetGlobal_Basic") { + float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; + HipTest::initArrays(&Ad, &Bd, nullptr, &A, &B, nullptr, LEN, + false); + CTX_CREATE() + hipMemcpyHtoD(reinterpret_cast(Ad), A, SIZE); + hipMemcpyHtoD(reinterpret_cast(Bd), B, SIZE); + hipModule_t Module; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + + float myDeviceGlobal_h = 42.0; + hipDeviceptr_t deviceGlobal; + size_t deviceGlobalSize; + HIP_CHECK(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, + Module, "myDeviceGlobal")); + HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(deviceGlobal), + &myDeviceGlobal_h, deviceGlobalSize)); + float myDeviceGlobalArray_h[ARRAY_SIZE]; + hipDeviceptr_t myDeviceGlobalArray; + size_t myDeviceGlobalArraySize; + + HIP_CHECK(hipModuleGetGlobal(reinterpret_cast + (&myDeviceGlobalArray), + &myDeviceGlobalArraySize, Module, + "myDeviceGlobalArray")); + + for (int i = 0; i < ARRAY_SIZE; i++) { + myDeviceGlobalArray_h[i] = i * 1000.0f; + HIP_CHECK(hipMemcpyHtoD(reinterpret_cast + (myDeviceGlobalArray), + &myDeviceGlobalArray_h, + myDeviceGlobalArraySize)); + } + + struct { + void* _Ad; + void* _Bd; + } args; + + args._Ad = reinterpret_cast(Ad); + args._Bd = reinterpret_cast(Bd); + size_t size = sizeof(args); + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + + SECTION("Testing with simple kernel") { + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "hello_world")); + HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, 0, + NULL, + reinterpret_cast(&config))); + + hipMemcpyDtoH(B, hipDeviceptr_t(Bd), SIZE); + + for (uint32_t i = 0; i < LEN; i++) { + REQUIRE(A[i] == B[i]); + } + } + + SECTION("Testing global variables") { + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "test_globals")); + HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, 0, + NULL, + reinterpret_cast(&config))); + + hipMemcpyDtoH(B, hipDeviceptr_t(Bd), SIZE); + + for (uint32_t i = 0; i < LEN; i++) { + float expected = A[i] + myDeviceGlobal_h + + myDeviceGlobalArray_h[i % 16]; + REQUIRE(expected == B[i]); + } + } + + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() + HipTest::freeArrays(Ad, Bd, nullptr, + A, B, nullptr, + false); +} diff --git a/tests/catch/unit/module/hipModuleLaunchKernel.cc b/tests/catch/unit/module/hipModuleLaunchKernel.cc new file mode 100644 index 0000000000..341378aec0 --- /dev/null +++ b/tests/catch/unit/module/hipModuleLaunchKernel.cc @@ -0,0 +1,246 @@ +/* + Copyright (c) 2021 - 2021 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 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +/* Test Scenarios + 1. hipModuleLaunchKernel Negative Scenarios + 2. hipModuleLaunchKernel Work Group tests => + - (block.x * block.y * block.z) <= Work Group Size + where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + - (block.x * block.y * block.z) > Work Group Size + where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + */ + +#include +#include + +#define fileName "module_kernels.code" +#define matmulK "matmulK" +#define SixteenSec "SixteenSecKernel" +#define KernelandExtra "KernelandExtraParams" +#define FourSec "FourSecKernel" +#define TwoSec "TwoSecKernel" +#define dummyKernel "EmptyKernel" + +struct gridblockDim { + unsigned int gridX; + unsigned int gridY; + unsigned int gridZ; + unsigned int blockX; + unsigned int blockY; + unsigned int blockZ; +}; + +/* +This testcase verifies the negative scenarios of +hipModuleLaunchKernel API +*/ +TEST_CASE("Unit_hipModuleLaunchKernel_Negative") { + HIP_CHECK(hipSetDevice(0)); + struct { + void* _Ad; + void* _Bd; + void* _Cd; + int _n; + } args1; + args1._Ad = nullptr; + args1._Bd = nullptr; + args1._Cd = nullptr; + args1._n = 0; + hipFunction_t MultKernel, KernelandExtraParamKernel; + size_t size1; + size1 = sizeof(args1); + hipModule_t Module; + hipStream_t stream1; + hipDeviceptr_t *Ad{nullptr}; + CTX_CREATE() + + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&MultKernel, Module, matmulK)); + HIP_CHECK(hipModuleGetFunction(&KernelandExtraParamKernel, + Module, KernelandExtra)); + void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args1, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, + HIP_LAUNCH_PARAM_END}; + void *params[] = {Ad}; + HIP_CHECK(hipStreamCreate(&stream1)); + SECTION("Passing nullptr to kernel function") { + REQUIRE(hipModuleLaunchKernel(nullptr, 1, 1, 1, 1, 1, 1, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Passing Max int value to block dim") { + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + 0, stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + + SECTION("Passing 0 to all value dim") { + REQUIRE(hipModuleLaunchKernel(MultKernel, 0, 0, 0, + 0, + 0, + 0, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Passing 0 for X dim") { + REQUIRE(hipModuleLaunchKernel(MultKernel, 0, 1, 1, + 0, + 1, + 1, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + + SECTION("Passing 0 for Y dim") { + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 0, 1, + 1, + 0, + 1, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Passing 0 for Z dim") { + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 0, + 1, + 1, + 0, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Passing both kernel and extra params") { + REQUIRE(hipModuleLaunchKernel(KernelandExtraParamKernel, 1, 1, 1, 1, + 1, 1, 0, stream1, + reinterpret_cast(¶ms), + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Passing more than maxthreadsperblock to block dim") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + deviceProp.maxThreadsPerBlock+1, + deviceProp.maxThreadsPerBlock+1, + deviceProp.maxThreadsPerBlock+1, 0, + stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Block dim X is more than max allowed") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + deviceProp.maxThreadsDim[0]+1, + 1, + 1, 0, stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Block dim Y is more than max allowed") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + 1, + deviceProp.maxThreadsDim[1]+1, + 1, 0, stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Block dim Z is more than max allowed") { + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + 1, + 1, + deviceProp.maxThreadsDim[2]+1, + 0, stream1, NULL, + reinterpret_cast(&config1)) + != hipSuccess); + } + + SECTION("Block invalid config to extra params") { + void *config3[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, + HIP_LAUNCH_PARAM_END}; + REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, + 1, 1, 1, 0, stream1, + NULL, + reinterpret_cast(&config3)) + != hipSuccess); + } + + HIP_CHECK(hipStreamDestroy(stream1)); + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} + +/* +This testcase verifies the work group scenarios of +hipModuleLaunchKernel API +*/ +TEST_CASE("Unit_hipModuleLaunchKernel_WorkGroup") { + HIP_CHECK(hipSetDevice(0)); + hipFunction_t DummyKernel; + hipModule_t Module; + hipStream_t stream1; + CTX_CREATE() + + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); + HIP_CHECK(hipStreamCreate(&stream1)); + // Passing Max int value to block dimensions + hipDeviceProp_t deviceProp; + hipGetDeviceProperties(&deviceProp, 0); + double cuberootVal = + cbrt(static_cast(deviceProp.maxThreadsPerBlock)); + uint32_t cuberoot_floor = floor(cuberootVal); + uint32_t cuberoot_ceil = ceil(cuberootVal); + // Scenario: (block.x * block.y * block.z) <= Work Group Size where + // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + HIP_CHECK(hipModuleLaunchKernel(DummyKernel, + 1, 1, 1, + cuberoot_floor, cuberoot_floor, cuberoot_floor, + 0, stream1, NULL, NULL)); + // Scenario: (block.x * block.y * block.z) > Work Group Size where + // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ + REQUIRE(hipModuleLaunchKernel(DummyKernel, + 1, 1, 1, + cuberoot_ceil, cuberoot_ceil, cuberoot_ceil + 1, + 0, stream1, NULL, NULL) != hipSuccess); + HIP_CHECK(hipStreamDestroy(stream1)); + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} diff --git a/tests/catch/unit/module/hipModuleLoadData.cc b/tests/catch/unit/module/hipModuleLoadData.cc new file mode 100644 index 0000000000..2102a10f49 --- /dev/null +++ b/tests/catch/unit/module/hipModuleLoadData.cc @@ -0,0 +1,91 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* +hipModuleLoadData scenarios + +1. Loads the kernel and the corresponding kernel function + which copies the data from one device variable to another. +*/ + +#include +#include +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define LEN 64 +#define SIZE LEN << 2 +#define FILENAME "module_kernels.code" +#define kernel_name "hello_world" + +static std::vector load_file() { + std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + INFO("could not open code object" << FILENAME); + REQUIRE(false); + } + return buffer; +} + + +TEST_CASE("Unit_hipModuleLoadData_Basic") { + auto buffer = load_file(); + float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; + HipTest::initArrays(&Ad, &Bd, nullptr, &A, &B, nullptr, + LEN, false); + HIP_CHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); + + hipModule_t Module; + hipFunction_t Function{nullptr}; + + HIP_CHECK(hipModuleLoadData(&Module, &buffer[0])); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + + struct { + void* _Ad; + void* _Bd; + } args; + args._Ad = reinterpret_cast(Ad); + args._Bd = reinterpret_cast(Bd); + size_t size = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, + stream, NULL, reinterpret_cast(&config))); + + HIP_CHECK(hipStreamDestroy(stream)); + + HIP_CHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); + + for (uint32_t i = 0; i < LEN; i++) { + REQUIRE(A[i] == B[i]); + } + HipTest::freeArrays(Ad, Bd, nullptr, + A, B, + nullptr, false); +} diff --git a/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc b/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc new file mode 100644 index 0000000000..bfb780ca06 --- /dev/null +++ b/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc @@ -0,0 +1,161 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +This testcase verifies the multithreaded scenario of +hipModuleLoadData API on MultiGPU system +*/ + +#include +#include + +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define LEN 64 +#define SIZE LEN << 2 +#define THREADS 8 + +#define FILENAME "module_kernels.code" +#define kernel_name "hello_world" + +/* +This function reads the kernel code object file into buffer +*/ +static std::vector load_file() { + std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + INFO("could not open code object " << FILENAME); + REQUIRE(false); + } + return buffer; +} + +/* +Thread function +1. Loads the module using hipModuleLoadData API +2. Initializes 2 device variables. +3. Launches kernel which copies one data into another. +4. validates the result and returns it to the caller using + std::ref variable. +*/ +static void run(const std::vector& buffer, int deviceNo, + bool &testResult) { + hipSetDevice(deviceNo); + hipModule_t Module; + hipFunction_t Function; + float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; + testResult = true; + HipTest::initArrays(&Ad, &Bd, nullptr, + &A, &B, nullptr, + LEN, false); + HIPCHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); + HIPCHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); + + HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); + HIPCHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + + hipStream_t stream; + HIPCHECK(hipStreamCreate(&stream)); + + struct { + void* _Ad; + void* _Bd; + } args; + args._Ad = static_cast(Ad); + args._Bd = static_cast(Bd); + size_t size = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, + 1, 1, 0, stream, NULL, + reinterpret_cast(&config))); + + HIPCHECK(hipStreamSynchronize(stream)); + + HIPCHECK(hipStreamDestroy(stream)); + + HIPCHECK(hipModuleUnload(Module)); + + HIPCHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); + + for (uint32_t i = 0; i < LEN; i++) { + REQUIRE(A[i] == B[i]); + } + HipTest::freeArrays(Ad, Bd, nullptr, + A, B, nullptr, + false); +} + +/* +Thread class inherited from std::thread +*/ +struct joinable_thread : std::thread { + template + joinable_thread(Xs&&... xs) : std::thread(std::forward(xs)...) {} // NOLINT + + joinable_thread& operator=(joinable_thread&& other) = default; + joinable_thread(joinable_thread&& other) = default; + + ~joinable_thread() { + if (this->joinable()) + this->join(); + } +}; + +/* +This API is triggered form the test case where in +1. Creates the thread object. +2. Loops through the number of GPUs and launches multiple threads. +*/ +static void run_multi_threads(uint32_t n, const std::vector& buffer) { + int numDevices = 0; + HIPCHECK(hipGetDeviceCount(&numDevices)); + bool testResult = false; + std::vector threads; + + for (int deviceNo=0; deviceNo < numDevices; ++deviceNo) { + for (uint32_t i = 0; i < n; i++) { + threads.emplace_back(std::thread{[&, buffer] { + run(buffer, deviceNo, std::ref(testResult)); + }}); + } + } +} +/* +The testcase verifies the multithreaded funtionality on MGPU system +1. Loads the kernel file by calling load_file API +2. Gets the host thread count +3. Creates multiple threads in parallel where in each thread initializes + 2 device variables and loads the kernel using hipModuleLoadData API. + The kernel copies the data from one variable to another.Then the thread + validates both the variables. +*/ +TEST_CASE("Unit_hipModuleLoadData_MGpuMultiThread") { + auto buffer = load_file(); + auto file_size = buffer.size() / (1024 * 1024); + auto thread_count = HipTest::getHostThreadCount(file_size + 10); + run_multi_threads(thread_count, buffer); +} diff --git a/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc b/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc new file mode 100644 index 0000000000..183da4c007 --- /dev/null +++ b/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc @@ -0,0 +1,164 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +This testcase verifies the multithreaded scenario of hipModuleLoadData API +*/ +#include +#include + +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define LEN 64 +#define SIZE LEN << 2 +#define THREADS 8 +#define MAX_THREADS 512 + +#define FILENAME "module_kernels.code" +#define kernel_name "hello_world" + +/* +This function reads the kernel code object file into buffer +*/ +std::vector load_file() { + std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + INFO("could not open code object" << FILENAME); + REQUIRE(false); + } + return buffer; +} + +/* +Thread function +1. Loads the module using hipModuleLoadData API +2. Initializes 2 device variables. +3. Launches kernel which copies one data into another. +4. validates the result and returns it to the caller using + std::ref variable. +*/ +void run(const std::vector& buffer, bool &testResult) { + hipModule_t Module; + hipFunction_t Function; + + float *A, *B, *Ad, *Bd; + testResult = true; + HipTest::initArrays(&Ad, &Bd, nullptr, + &A, &B, nullptr, + LEN, false); + + + HIPCHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); + HIPCHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); + + HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); + HIPCHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + + hipStream_t stream; + HIPCHECK(hipStreamCreate(&stream)); + + struct { + void* _Ad; + void* _Bd; + } args; + args._Ad = static_cast(Ad); + args._Bd = static_cast(Bd); + size_t size = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END}; + HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, + LEN, 1, 1, 0, stream, + NULL, reinterpret_cast(&config))); + + HIPCHECK(hipStreamSynchronize(stream)); + + HIPCHECK(hipStreamDestroy(stream)); + + HIPCHECK(hipModuleUnload(Module)); + + HIPCHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); + + for (uint32_t i = 0; i < LEN; i++) { + REQUIRE(A[i] == B[i]); + } + + HipTest::freeArrays(Ad, Bd, nullptr, + A, B, nullptr, + false); +} + +/* +Thread class inherited from std::thread +*/ +struct joinable_thread : std::thread { + template + joinable_thread(Xs&&... xs) : std::thread(std::forward(xs)...) {} // NOLINT + + joinable_thread& operator=(joinable_thread&& other) = default; + joinable_thread(joinable_thread&& other) = default; + + ~joinable_thread() { + if (this->joinable()) + this->join(); + } +}; + +/* +This API is triggered form the test case where in +1. Creates the thread object. +2. Loops through the number of GPUs and launches multiple threads. +*/ +void run_multi_threads(uint32_t n, const std::vector& buffer) { + std::vector threads; + bool testResult = false; + for (uint32_t i = 0; i < n; i++) { + threads.emplace_back(std::thread{[&] { + run(buffer, std::ref(testResult)); + }}); + } +} + +/* +The testcase verifies the multithreaded funtionality +1. Loads the kernel file by calling load_file API +2. Gets the host thread count +3. Creates multiple threads in parallel where in each thread initializes + 2 device variables and loads the kernel using hipModuleLoadData API. + The kernel copies the data from one variable to another.Then the thread + validates both the variables. +*/ +TEST_CASE("Unit_hipModuleLoadData_MultiThreaded") { + HIPCHECK(hipInit(0)); + auto buffer = load_file(); + auto file_size = buffer.size() / (1024 * 1024); + auto thread_count = HipTest::getHostThreadCount(file_size + 10); + if (thread_count == 0) { + INFO("Thread Count is zero"); + REQUIRE(false); + } + + run_multi_threads(thread_count, buffer); +} diff --git a/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc b/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc new file mode 100644 index 0000000000..401892915e --- /dev/null +++ b/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc @@ -0,0 +1,121 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 testcase verifies hipModuleLoad API in multithreaded scenario +*/ +#include +#include "hip/hip_runtime.h" +#if HT_AMD +#include "hip/hip_ext.h" +#endif +#include +#include +#include +#include +#include +#include +#define THREADS 8 +#define MAX_NUM_THREADS 128 + +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define NUM_GROUPS 1 +#define GROUP_SIZE 1 +#define WARMUP_RUN_COUNT 10 +#define TIMING_RUN_COUNT 100 +#define TOTAL_RUN_COUNT WARMUP_RUN_COUNT + TIMING_RUN_COUNT +#define FILENAME "module_kernels.code" +#define kernel_name "EmptyKernel" + +/* +This thread function loads the kernel file , synchronizes the threads +and Launches the kernel . +*/ +void hipModuleLaunchKernel_enqueue(std::atomic_int* shared, int max_threads) { + // resources necessary for this thread + hipStream_t stream; + HIPCHECK(hipStreamCreate(&stream)); + hipModule_t module; + hipFunction_t function; + + HIPCHECK(hipModuleLoad(&module, FILENAME)); + HIPCHECK(hipModuleGetFunction(&function, module, kernel_name)); + + void* kernel_params = nullptr; + + // synchronize all threads, before running + shared->fetch_add(1, std::memory_order_release); + while (max_threads != shared->load(std::memory_order_acquire)) {} + + for (auto i = 0; i < TOTAL_RUN_COUNT; ++i) { + HIPCHECK(hipModuleLaunchKernel(function, 1, 1, + 1, 1, 1, 1, 0, stream, + &kernel_params, nullptr)); + } + HIPCHECK(hipModuleUnload(module)); + HIPCHECK(hipStreamDestroy(stream)); +} + +/* +thread pool class contains launching the threads using std::async API +with future variable "threads". +The start API Launches the threads and finish API waits for the +thread execution to end. +*/ +struct thread_pool { + explicit thread_pool(int total_threads) : max_threads(total_threads) { + } + void start(std::function f) { + for (int i = 0; i < max_threads; ++i) { + threads.push_back(std::async(std::launch::async, f, + &shared, max_threads)); + } + } + void finish() { + for (auto&&thread : threads) { + thread.get(); + } + threads.clear(); + shared = 0; + } + ~thread_pool() { + finish(); + } + private: + std::atomic_int shared {0}; + std::vector buffer; + std::vector> threads; + int max_threads = 1; +}; + +/* +This testcase verifies the Multithreaded scenario of hipModule API +where in threadpool object is created and the object invokes start API +which launches multiple threads where each thread loads the kernel object +using hipModuleLoad API and launches the kernel in parallel. +*/ +TEST_CASE("Unit_hipModuleLoad_MultiThread") { + int max_threads = min(THREADS * std::thread::hardware_concurrency(), + MAX_NUM_THREADS); + thread_pool task(max_threads); + task.start(hipModuleLaunchKernel_enqueue); + task.finish(); +} diff --git a/tests/catch/unit/module/hipModuleLoadUnloadStress.cc b/tests/catch/unit/module/hipModuleLoadUnloadStress.cc new file mode 100644 index 0000000000..46acdae29b --- /dev/null +++ b/tests/catch/unit/module/hipModuleLoadUnloadStress.cc @@ -0,0 +1,93 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#include +#include +#include +#include +#include "hip_test_common.hh" + +#define TEST_ITERATIONS 1000 +#define CODEOBJ_FILE "module_kernels.code" +/** + * Run Valgrind tool with these test cases to validate memory leakage. + * E.g. valgrind --leak-check=yes ./a.out + */ + +/** + * Internal Function + */ +static std::vector load_file() { + std::ifstream file(CODEOBJ_FILE, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + WARN("could not open code object " << CODEOBJ_FILE); + } + file.close(); + return buffer; +} +/** + * Validates no memory leakage for hipModuleLoad + */ +TEST_CASE("Unit_hipModule_LoadUnloadStress") { + CTX_CREATE() + for (int count = 0; count < TEST_ITERATIONS; count++) { + hipModule_t Module; + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); + HIP_CHECK(hipModuleUnload(Module)); + } + CTX_DESTROY() +} +/** + * Validates no memory leakage for hipModuleLoadData + */ +TEST_CASE("Unit_hipModuleLoadData_LoadUnloadStress") { + CTX_CREATE() + auto buffer = load_file(); + for (int count = 0; count < TEST_ITERATIONS; count++) { + hipModule_t Module; + HIP_CHECK(hipModuleLoadData(&Module, &buffer[0])); + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); + HIP_CHECK(hipModuleUnload(Module)); + } + CTX_DESTROY() +} +/** + * Validates no memory leakage for hipModuleLoadDataEx + */ +TEST_CASE("Unit_hipModuleLoadDataEx_UnloadStress") { + CTX_CREATE() + auto buffer = load_file(); + for (int count = 0; count < TEST_ITERATIONS; count++) { + hipModule_t Module; + HIP_CHECK(hipModuleLoadDataEx(&Module, &buffer[0], 0, + nullptr, nullptr)); + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); + HIP_CHECK(hipModuleUnload(Module)); + } + CTX_DESTROY() +} diff --git a/tests/catch/unit/module/hipModuleNegative.cc b/tests/catch/unit/module/hipModuleNegative.cc new file mode 100644 index 0000000000..c43b507c21 --- /dev/null +++ b/tests/catch/unit/module/hipModuleNegative.cc @@ -0,0 +1,274 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 testcase verifies the negative scenarios of +1. hipModuleLoad API +2. hipModuleLoadData API +3. hipModuleGetFunction API +4. hipModuleGetGlobal API +*/ + +#include +#include +#include +#include +#include "hip_test_common.hh" + +#define FILENAME_NONEXST "sample_nonexst.code" +#define FILENAME_EMPTY "emptyfile.code" +#define FILENAME_RAND "rand_file.code" +#define RANDOMFILE_LEN 2048 +#define CODEOBJ_FILE "module_kernels.code" +#define KERNEL_NAME "hello_world" +#define KERNEL_NAME_NONEXST "xyz" +#define CODEOBJ_GLOBAL "module_kernels.code" +#define DEVGLOB_VAR_NONEXIST "xyz" +#define DEVGLOB_VAR "myDeviceGlobal" +/** + * Internal Function + * Loads the kernel file into buffer + */ +std::vector load_file(const char* filename) { + std::ifstream file(filename, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + INFO("could not open code object " << filename); + } + file.close(); + return buffer; +} + +/** + * Internal Function + Create Randome file + */ +void createRandomFile(const char* filename) { + std::ofstream outfile(filename, std::ios::binary); + char buf[RANDOMFILE_LEN]; + unsigned int seed = 1; + for (int i = 0; i < RANDOMFILE_LEN; i++) { + buf[i] = rand_r(&seed) % 256; + } + outfile.write(buf, RANDOMFILE_LEN); + outfile.close(); +} + +/** + * Validates negative scenarios for hipModuleLoad API + */ + +TEST_CASE("Unit_hipModuleLoad_Negative") { + CTX_CREATE() + hipModule_t Module; + + SECTION("Nullptr to module") { + REQUIRE(hipModuleLoad(nullptr, CODEOBJ_FILE) + != hipSuccess); + } + + SECTION("Nullptr to Fname") { + REQUIRE(hipModuleLoad(&Module, nullptr) + != hipSuccess); + } + + SECTION("Empty fname") { + std::fstream fs; + fs.open(FILENAME_EMPTY, std::ios::out); + fs.close(); + REQUIRE(hipModuleLoad(&Module, FILENAME_EMPTY) + != hipSuccess); + } + + SECTION("Binary file with random number") { + createRandomFile(FILENAME_RAND); + REQUIRE(hipModuleLoad(&Module, FILENAME_RAND) + != hipSuccess); + remove(FILENAME_RAND); + } + + SECTION("Non Existent file") { + REQUIRE(hipModuleLoad(&Module, FILENAME_NONEXST) + != hipSuccess); + } + + SECTION("Empty string to file name") { + REQUIRE(hipModuleLoad(&Module, "") + != hipSuccess); + } + + CTX_DESTROY() +} + +/** + * Validates negative scenarios for hipModuleLoadData API + */ +TEST_CASE("Unit_hipModuleLoadData_Negative") { + CTX_CREATE() + hipModule_t Module; + + SECTION("Nullptr to module") { + auto buffer = load_file(CODEOBJ_FILE); + REQUIRE(hipModuleLoadData(nullptr, &buffer[0]) + != hipSuccess); + } + + SECTION("Nullptr to image") { + REQUIRE(hipModuleLoadData(&Module, nullptr) + != hipSuccess); + } + + SECTION("Random file to image") { + createRandomFile(FILENAME_RAND); + auto buffer = load_file(FILENAME_RAND); + REQUIRE(hipModuleLoadData(&Module, &buffer[0]) + != hipSuccess); + } + + SECTION("Nullptr to Module") { + auto buffer = load_file(CODEOBJ_FILE); + REQUIRE(hipModuleLoadDataEx(nullptr, &buffer[0], 0, nullptr, nullptr) + != hipSuccess); + } + + SECTION("Nullptr to image") { + REQUIRE(hipModuleLoadDataEx(&Module, nullptr, 0, nullptr, nullptr) + != hipSuccess); + } + + SECTION("Random image file") { + // Create a binary file with random numbers + createRandomFile(FILENAME_RAND); + // Open the code object file and copy it in a buffer + auto buffer = load_file(FILENAME_RAND); + REQUIRE(hipModuleLoadDataEx(&Module, &buffer[0], 0, nullptr, nullptr) + != hipSuccess); + } + + CTX_DESTROY() +} + +/** + * Validates negative scenarios for hipModuleGetFunction API + */ +TEST_CASE("Unit_hipModuleGetFunction_Negative") { + CTX_CREATE() + hipFunction_t Function; + hipModule_t Module; + + SECTION("Nullptr to function name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + REQUIRE(hipModuleGetFunction(nullptr, Module, KERNEL_NAME) != hipSuccess); + HIP_CHECK(hipModuleUnload(Module)); + } + + SECTION("Uninitialized module") { + REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME) != hipSuccess); + } + + SECTION("Non existing function kernel name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME_NONEXST) + != hipSuccess); + HIP_CHECK(hipModuleUnload(Module)); + } + + SECTION("Nullptr to kernel name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + REQUIRE(hipModuleGetFunction(&Function, Module, nullptr) != hipSuccess); + HIP_CHECK(hipModuleUnload(Module)); + } +#if HT_AMD + SECTION("Unloaded module") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + HIP_CHECK(hipModuleUnload(Module)); + REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME) != hipSuccess); + } +#endif + + SECTION("Empty string to kernel name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + REQUIRE(hipModuleGetFunction(&Function, Module, "") != hipSuccess); + HIP_CHECK(hipModuleUnload(Module)); + } + + CTX_DESTROY() +} + +/** + * Validates negative scenarios for hipModuleGetGlobal API + */ +TEST_CASE("Unit_hipModuleGetGlobal_Negative") { + CTX_CREATE() + hipModule_t Module; + hipDeviceptr_t deviceGlobal; + size_t deviceGlobalSize; + + SECTION("Nullptr to varname") { + HIPCHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); + REQUIRE(hipModuleGetGlobal(&deviceGlobal, + &deviceGlobalSize, Module, nullptr) + != hipSuccess); + HIPCHECK(hipModuleUnload(Module)); + } + + SECTION("Wrong variable name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); + REQUIRE(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, + Module, DEVGLOB_VAR_NONEXIST) != hipSuccess); + HIPCHECK(hipModuleUnload(Module)); + } + + SECTION("Empty string to module name") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); + REQUIRE(hipModuleGetGlobal(&deviceGlobal, + &deviceGlobalSize, Module, "") != hipSuccess); + HIPCHECK(hipModuleUnload(Module)); + } + +#if HT_AMD + SECTION("Unloaded Module") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); + HIP_CHECK(hipModuleUnload(Module)); + REQUIRE(hipModuleGetGlobal(&deviceGlobal, + &deviceGlobalSize, Module, + DEVGLOB_VAR) != hipSuccess); + } + + SECTION("Unload an Unloaded module") { + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + HIP_CHECK(hipModuleUnload(Module)); + REQUIRE(hipModuleUnload(Module) != hipSuccess); + } + + SECTION("Uninitialized module") { + REQUIRE(hipModuleGetGlobal(&deviceGlobal, + &deviceGlobalSize, Module, + DEVGLOB_VAR) != hipSuccess); + } + SECTION("Unload Uninitialized module") { + REQUIRE(hipModuleUnload(Module) != hipSuccess); + } +#endif + + CTX_DESTROY() +} diff --git a/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc b/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc new file mode 100644 index 0000000000..c58b3978e6 --- /dev/null +++ b/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc @@ -0,0 +1,267 @@ + +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ +#include +#include + +#define fileName "module_kernels.code" +#define kernel_name "hello_world" +/** + * hipModuleOccupancyMaxPotentialBlockSize and hipModuleOccupancyMaxPotentialBlockSizeWithFlags + * corner tests. + * Scenario1: + * Validates the value of gridSize, which should be always non zero +ve integer and blockSize + * range returned for dynSharedMemPerBlk = 0 and blockSizeLimit = 0. + * Scenario2: + * Validates the value of gridSize, which should be always non zero +ve integer and blockSize + * range returned for dynSharedMemPerBlk = devProp.sharedMemPerBlock and + * blockSizeLimit = devProp.maxThreadsPerBlock. + */ +TEST_CASE("Unit_hipModuleOccupancyMaxPotentialBlockSize_FuncTst") { + // Initialize + hipDeviceProp_t devProp; + int gridSize = 0; + int blockSize = 0; + hipModule_t Module; + CTX_CREATE() + hipFunction_t Function; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); + // Scenario1 + SECTION("without flag - gridSize when input params are 0") { + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, + &blockSize, Function, 0, 0)); + } + // Scenario2 + SECTION("without flag - gridSize when input params are maximum") { + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, + &blockSize, Function, + devProp.sharedMemPerBlock, devProp.maxThreadsPerBlock)); + } + // Scenario1 + SECTION("with flag - gridSize when input params are 0") { + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, + &blockSize, Function, 0, 0, 0)); + } + // Scenario2 + SECTION("with flag - gridSize when input params are maximum") { + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, + &blockSize, Function, devProp.sharedMemPerBlock, + devProp.maxThreadsPerBlock, 0)); + } + // Check if blockSize doen't exceed maxThreadsPerBlock + REQUIRE_FALSE(gridSize <= 0); + REQUIRE_FALSE(blockSize <= 0); + REQUIRE_FALSE(blockSize > devProp.maxThreadsPerBlock); + // Un-initialize + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} +/** + * hipModuleOccupancyMaxActiveBlocksPerMultiprocessor and + * hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags Corner tests. + * Scenario1: + * Validates numBlock value range is within expected limit when sharedMemPerBlock + * is 0. + * Scenario2: + * Validates numBlock value range is within expected limit when + * dynSharedMemPerBlk = devProp.sharedMemPerBlock. + */ +TEST_CASE("Unit_hipModuleOccupancyMaxActiveBlocksPerMultiprocessor_FuncTst") { + // Initialize + hipDeviceProp_t devProp; + int gridSize = 0; + int blockSize = 0; + int numBlock = 0; + hipModule_t Module; + CTX_CREATE() + hipFunction_t Function; + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, + &blockSize, Function, 0, 0)); + HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); + // Scenario1 + SECTION("without flag - gridSize when input params are 0") { + HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlock, + Function, blockSize, 0)); + } + // Scenario2 + SECTION("without flag - gridSize when input params are maximum") { + HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlock, + Function, blockSize, devProp.sharedMemPerBlock)); + } + // Scenario1 + SECTION("with flag - gridSize when input params are 0") { + HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags( + &numBlock, Function, blockSize, 0, 0)); + } + // Scenario2 + SECTION("with flag - gridSize when input params are maximum") { + HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags( + &numBlock, Function, blockSize, devProp.sharedMemPerBlock, 0)) + } + // Check if numBlocks are within limits + int temp_val = (numBlock * blockSize); + REQUIRE_FALSE(numBlock <= 0); + REQUIRE_FALSE(temp_val > devProp.maxThreadsPerMultiProcessor); + // Un-initialize + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} +/** + * hipModuleOccupancyMaxPotentialBlockSize negative tests. + * Scenario1: gridSize is nullptr. + * Scenario2: blocksize is nullptr. + * Scenario3: blockSizeLimit < 0. + */ +TEST_CASE("Unit_hipModuleOccupancyMaxPotentialBlockSize_NegTst") { + int gridSize = 0; + int blockSize = 0; + hipModule_t Module; + hipFunction_t Function; + CTX_CREATE() + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + // Scenario1 + SECTION("without flag - gridSize is nullptr") { + REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( + nullptr, &blockSize, Function, 0, 0)); + } + // Scenario2 + SECTION("without flag - blocksize is nullptr") { + REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( + &gridSize, nullptr, Function, 0, 0)); + } + // Scenario3 + SECTION("without flag - blockSizeLimit is less than 0") { + hipDeviceProp_t devProp; + HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); +#if HT_NVIDIA + REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( + &gridSize, &blockSize, Function, 0, -1)); +#else + // As discussed in SWDEV-269400 + // with developers this difference in behavior between NVIDIA and AMD + // is retained. + REQUIRE_FALSE(hipSuccess != hipModuleOccupancyMaxPotentialBlockSize( + &gridSize, &blockSize, Function, 0, -1)); +#endif + } + // Scenario1 + SECTION("with flag - gridSize is nullptr") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxPotentialBlockSizeWithFlags(nullptr, + &blockSize, Function, 0, 0, 0)); + } + // Scenario2 + SECTION("with flag - blocksize is nullptr") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, + nullptr, Function, 0, 0, 0)); + } + // Scenario3 + SECTION("with flag - blockSizeLimit is less than 0") { +#if HT_NVIDIA + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, + &blockSize, Function, 0, -1, 0)); +#else + // As discussed in SWDEV-269400 + // with developers this difference in behavior between NVIDIA and AMD + // is retained. + REQUIRE_FALSE(hipSuccess != + hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, + &blockSize, Function, 0, -1, 0)); +#endif + } + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} +/** + * hipModuleOccupancyMaxActiveBlocksPerMultiprocessor negative tests. + * Scenario1: numBlocks is nullptr. + * Scenario2: Check the behavior for blockSize < 0. + * Scenario3: Check error code returned for dynSharedMemPerBlk = 0 and blockSize = 0. + * Scenario4: dynSharedMemPerBlk = size_t numeric limit. + */ +TEST_CASE("Unit_hipModuleOccupancyMaxActiveBlocksPerMultiprocessor_NegTst") { + int gridSize = 0; + int blockSize = 0; + int numBlocks = 0; + hipModule_t Module; + hipFunction_t Function; + CTX_CREATE() + HIP_CHECK(hipModuleLoad(&Module, fileName)); + HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); + HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, &blockSize, + Function, 0, 0)); + // Scenario1 + SECTION("without flag - numBlocks is nullptr") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(nullptr, + Function, blockSize, 0)); + } + // Scenario3 + SECTION("without flag - dynSharedMemPerBlk = 0 and blockSize = 0") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, + Function, 0, 0)); + } + // Scenario2 + SECTION("without flag - blockSize is less than 0") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, + Function, -1, 0)); + } + // Scenario4 + SECTION("without flag - dynSharedMemPerBlk = max_numerical_limit") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, + Function, 0, std::numeric_limits::max())); + } + // Scenario1 + SECTION("with flag - numBlocks is nullptr") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(nullptr, + Function, blockSize, 0, 0)); + } + // Scenario3 + SECTION("with flag - dynSharedMemPerBlk = 0 and blockSize = 0") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, + Function, 0, 0, 0)); + } + // Scenario2 + SECTION("with flag - blockSize is less than 0") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, + Function, -1, 0, 0)); + } + // Scenario4 + SECTION("with flag - dynSharedMemPerBlk = max_numerical_limit") { + REQUIRE_FALSE(hipSuccess == + hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, + Function, 0, std::numeric_limits::max(), 0)); + } + HIP_CHECK(hipModuleUnload(Module)); + CTX_DESTROY() +} + diff --git a/tests/catch/unit/module/hipModuleTexture2dDrv.cc b/tests/catch/unit/module/hipModuleTexture2dDrv.cc new file mode 100755 index 0000000000..2afa3e06fc --- /dev/null +++ b/tests/catch/unit/module/hipModuleTexture2dDrv.cc @@ -0,0 +1,561 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 testcase verifies the following scenarios of hipModuleGetTexRef API +1. Negative +2. Basic functionality using different data types +3. Multiple streams +4. MultiThreaded - MultStreamMultGPU +5. MultiThreaded - SingleStreamMultGPU +*/ + +#include +#include +#include +#include +#include +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define CODEOBJ_FILE "module_kernels.code" +#define NON_EXISTING_TEX_NAME "xyz" +#define EMPTY_TEX_NAME "" +#define GLOBAL_KERNEL_VAR "deviceGlobalFloat" +#define TEX_REF "ftex" +#define WIDTH 256 +#define HEIGHT 256 +#define MAX_STREAMS 4 +#define GRIDDIMX 16 +#define GRIDDIMY 16 +#define GRIDDIMZ 1 +#define BLOCKDIMZ 1 +#define MAX_GPU 16 + +std::atomic g_thTestPassed(1); + + +/** + * Internal Functions + * Loads the kernel file + */ +static std::vector load_file() { + std::ifstream file(CODEOBJ_FILE, std::ios::binary | std::ios::ate); + std::streamsize fsize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fsize); + if (!file.read(buffer.data(), fsize)) { + INFO("could not open code object " << CODEOBJ_FILE); + REQUIRE(false); + } + return buffer; +} + +/* +Initializes the array +*/ +template +void allocInitArray(unsigned int width, + unsigned int height, + hipArray_Format format, + HIP_ARRAY* array + ) { + HIP_ARRAY_DESCRIPTOR desc; + desc.Format = format; + desc.NumChannels = 1; + desc.Width = width * sizeof(T); + desc.Height = height; + HIPCHECK(hipArrayCreate(array, &desc)); +} + +/* +Copies buffer to array using hipMemcpyParam2D API +*/ +template void copyBuffer2Array(unsigned int width, + unsigned int height, + T* hData, + T1 array + ) { + hip_Memcpy2D copyParam; + memset(©Param, 0, sizeof(copyParam)); +#if HT_NVIDIA + copyParam.dstMemoryType = CU_MEMORYTYPE_ARRAY; + copyParam.srcMemoryType = CU_MEMORYTYPE_HOST; + copyParam.dstArray = *array; +#else + copyParam.dstMemoryType = hipMemoryTypeArray; + copyParam.srcMemoryType = hipMemoryTypeHost; + copyParam.dstArray = array; +#endif + copyParam.srcHost = hData; + copyParam.srcPitch = width * sizeof(T); + copyParam.WidthInBytes = width * sizeof(T); + copyParam.Height = height; + HIPCHECK(hipMemcpyParam2D(©Param)); +} + +/* +Assigns array to texture ref +*/ +template void assignArray2TexRef(hipArray_Format format, + const char* texRefName, + hipModule_t Module, + T array + ) { + HIP_TEX_REFERENCE texref; +#if HT_NVIDIA + HIPCHECK(hipModuleGetTexRef(&texref, Module, texRefName)); + HIPCHECK(hipTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP)); + HIPCHECK(hipTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP)); + HIPCHECK(hipTexRefSetFilterMode(texref, HIP_TR_FILTER_MODE_POINT)); + HIPCHECK(hipTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER)); + HIPCHECK(hipTexRefSetFormat(texref, format, 1)); + HIPCHECK(hipTexRefSetArray(texref, *array, CU_TRSA_OVERRIDE_FORMAT)); +#else + HIPCHECK(hipModuleGetTexRef(&texref, Module, texRefName)); + HIPCHECK(hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap)); + HIPCHECK(hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap)); + HIPCHECK(hipTexRefSetFilterMode(texref, hipFilterModePoint)); + HIPCHECK(hipTexRefSetFlags(texref, HIP_TRSF_READ_AS_INTEGER)); + HIPCHECK(hipTexRefSetFormat(texref, format, 1)); + HIPCHECK(hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT)); +#endif +} + +template bool validateOutput(unsigned int width, + unsigned int height, + T* hData, + T* hOutputData) { + for (unsigned int i = 0; i < height; i++) { + for (unsigned int j = 0; j < width; j++) { + if (hData[i * width + j] != hOutputData[i * width + j]) { + return false; + } + } + } + return true; +} + +/** + * Validates texture functionality with multiple streams for hipModuleGetTexRef + * + */ +template bool testTexMultStream(const std::vector& buffer, + hipArray_Format format, + const char* texRefName, + const char* kerFuncName, + unsigned int numOfStreams) { + bool TestPassed = true; + unsigned int width = WIDTH; + unsigned int height = HEIGHT; + unsigned int size = width * height * sizeof(T); + T* hData = reinterpret_cast(malloc(size)); + CTX_CREATE() + HipTest::setDefaultData(width * height, hData, nullptr, nullptr); + + // Load Kernel File and create hipArray + hipModule_t Module; + HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); + HIP_ARRAY array; + allocInitArray(width, height, format, &array); +#if HT_NVIDIA + // Copy from hData to array using hipMemcpyParam2D + copyBuffer2Array(width, height, hData, &array); + // Get tex reference from the loaded kernel file + // Assign array to the tex reference + assignArray2TexRef(format, texRefName, Module, &array); +#else + // Copy from hData to array using hipMemcpyParam2D + copyBuffer2Array(width, height, hData, array); + // Get tex reference from the loaded kernel file + // Assign array to the tex reference + assignArray2TexRef(format, texRefName, Module, array); +#endif + hipFunction_t Function; + HIPCHECK(hipModuleGetFunction(&Function, Module, kerFuncName)); + + // Create Multiple Strings + hipStream_t streams[MAX_STREAMS]={0}; + T* dData[MAX_STREAMS] = {NULL}; + T* hOutputData[MAX_STREAMS] = {NULL}; + if (numOfStreams > MAX_STREAMS) { + numOfStreams = MAX_STREAMS; + } + unsigned int totalStreamsCreated = 0; + for (unsigned int stream_num = 0; stream_num < numOfStreams; stream_num++) { + hOutputData[stream_num] = reinterpret_cast(malloc(size)); + if (NULL == hOutputData[stream_num]) { + WARN("Failed to allocate using malloc in testTexMultStream"); + TestPassed &= false; + } + HIPCHECK(hipStreamCreate(&streams[stream_num])); + HIPCHECK(hipMalloc(reinterpret_cast(&dData[stream_num]), size)); + memset(hOutputData[stream_num], 0, size); + struct { + void* _Ad; + unsigned int _Bd; + unsigned int _Cd; + } args; + args._Ad = reinterpret_cast(dData[stream_num]); + args._Bd = width; + args._Cd = height; + + size_t sizeTemp = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, + &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, + &sizeTemp, + HIP_LAUNCH_PARAM_END}; + + int temp1 = width / GRIDDIMX; + int temp2 = height / GRIDDIMY; + HIPCHECK(hipModuleLaunchKernel(Function, GRIDDIMX, GRIDDIMY, GRIDDIMZ, + temp1, temp2, BLOCKDIMZ, 0, + streams[stream_num], + NULL, reinterpret_cast(&config))); + totalStreamsCreated++; + } + // Check the kernel results separately + for (unsigned int stream_num = 0; stream_num < totalStreamsCreated; + stream_num++) { + HIPCHECK(hipStreamSynchronize(streams[stream_num])); + HIPCHECK(hipMemcpy(hOutputData[stream_num], dData[stream_num], size, + hipMemcpyDeviceToHost)); + TestPassed &= validateOutput(width, height, hData, + hOutputData[stream_num]); + } + for (unsigned int i = 0; i < totalStreamsCreated; i++) { + HIPCHECK(hipFree(dData[i])); + HIPCHECK(hipStreamDestroy(streams[i])); + free(hOutputData[i]); + } + ARRAY_DESTROY(array) + HIPCHECK(hipModuleUnload(Module)); + free(hData); + CTX_DESTROY() + return TestPassed; +} + +/** + * Internal Thread Functions + * + */ +void launchSingleStreamMultGPU(int gpu, const std::vector& buffer) { + bool TestPassed = true; + HIPCHECK(hipSetDevice(gpu)); + TestPassed = testTexMultStream(buffer, + HIP_AD_FORMAT_FLOAT, + "ftex", + "tex2dKernelFloat", 1); + g_thTestPassed &= static_cast(TestPassed); +} + +void launchMultStreamMultGPU(int gpu, const std::vector& buffer) { + bool TestPassed = true; + HIPCHECK(hipSetDevice(gpu)); + TestPassed = testTexMultStream(buffer, + HIP_AD_FORMAT_FLOAT, + "ftex", + "tex2dKernelFloat", 3); + g_thTestPassed &= static_cast(TestPassed); +} +/** + * Validates texture functionality with Multiple Streams on multuple GPU + * for hipModuleGetTexRef + * + */ +bool testTexMultStreamMultGPU(unsigned int numOfGPUs, + const std::vector& buffer) { + bool TestPassed = true; + std::thread T[MAX_GPU]; + + for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { + T[gpu] = std::thread(launchMultStreamMultGPU, gpu, buffer); + } + for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { + T[gpu].join(); + } + + if (g_thTestPassed) { + TestPassed = true; + } else { + TestPassed = false; + } + return TestPassed; +} + +/** + * Validates texture functionality with Single Stream on multuple GPU + * for hipModuleGetTexRef + * + */ +bool testTexSingleStreamMultGPU(unsigned int numOfGPUs, + const std::vector& buffer) { + bool TestPassed = true; + std::thread T[MAX_GPU]; + + for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { + T[gpu] = std::thread(launchSingleStreamMultGPU, gpu, buffer); + } + for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { + T[gpu].join(); + } + + if (g_thTestPassed) { + TestPassed = true; + } else { + TestPassed = false; + } + return TestPassed; +} + +/* +This testcase verifies the negative scenarios of hipModuleGetTexRef API +*/ +TEST_CASE("Unit_hipModuleGetTexRef_Negative") { + hipModule_t Module; + HIP_TEX_REFERENCE texref; + CTX_CREATE() + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + + SECTION("TexRef as nullptr") { + REQUIRE(hipModuleGetTexRef(nullptr, Module, "tex") != hipSuccess); + } + + SECTION("Name as nullptr") { + REQUIRE(hipModuleGetTexRef(&texref, Module, nullptr) != hipSuccess); + } + + SECTION("Name as non existing TexName") { + REQUIRE(hipModuleGetTexRef(&texref, Module, + NON_EXISTING_TEX_NAME) != hipSuccess); + } + + SECTION("Empty tex name") { + REQUIRE(hipModuleGetTexRef(&texref, Module, EMPTY_TEX_NAME) != hipSuccess); + } +#if HT_NVIDIA + SECTION("Name as Global kernel Var") { + REQUIRE(hipModuleGetTexRef(&texref, Module, + GLOBAL_KERNEL_VAR) != hipSuccess); + } +#endif + + SECTION("Unload Module") { + HIP_CHECK(hipModuleUnload(Module)); + REQUIRE(hipModuleGetTexRef(&texref, Module, TEX_REF) != hipSuccess); + } + + CTX_DESTROY() +} +/** + * Validates texture type data functionality for hipModuleGetTexRef + * 1.Loads the code object file + * 2.Based on the template type texRefName,KernelFuncName and format are assigned. + * 3.Allocate array based on format. + * 4.Assigns array to texRef + * 5.Launches the kernel based on the template type which invokes text2D API + and copies the data to output variable. + * 6.Validates the data. + */ +TEMPLATE_TEST_CASE("Unit_hipModuleGetTexRef_Basic", "", int, + char, uint16_t, float) { + bool TestPassed = true; + constexpr unsigned int width = WIDTH; + constexpr unsigned int height = HEIGHT; + constexpr unsigned int size = width * height * sizeof(TestType); + const char *texRefName, *kerFuncName; + hipArray_Format format; + + TestType* hData = reinterpret_cast(malloc(size)); + if (NULL == hData) { + INFO("Failed to allocate using malloc in testTexType.\n"); + REQUIRE(false); + } + CTX_CREATE() + HipTest::setDefaultData(width * height, hData, nullptr, nullptr); + // Load Kernel File and create hipArray + hipModule_t Module; + HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); + HIP_ARRAY array; + + if (std::is_same::value) { + texRefName = "ctex"; + kerFuncName = "tex2dKernelInt8"; + format = HIP_AD_FORMAT_SIGNED_INT8; + } else if (std::is_same::value) { + texRefName = "stex"; + kerFuncName = "tex2dKernelInt16"; + format = HIP_AD_FORMAT_SIGNED_INT16; + } else if (std::is_same::value) { + texRefName = "itex"; + kerFuncName = "tex2dKernelInt"; + format = HIP_AD_FORMAT_SIGNED_INT32; + } else if (std::is_same::value) { + texRefName = "ftex"; + kerFuncName = "tex2dKernelFloat"; + format = HIP_AD_FORMAT_FLOAT; + } + allocInitArray(width, height, format, &array); + +#if HT_NVIDIA + // Copy from hData to array using hipMemcpyParam2D + copyBuffer2Array(width, height, hData, &array); + // Get tex reference from the loaded kernel file + // Assign array to the tex reference + assignArray2TexRef(format, texRefName, Module, &array); +#else + // Copy from hData to array using hipMemcpyParam2D + copyBuffer2Array(width, height, hData, array); + // Get tex reference from the loaded kernel file + // Assign array to the tex reference + assignArray2TexRef(format, texRefName, Module, array); +#endif + hipFunction_t Function; + HIP_CHECK(hipModuleGetFunction(&Function, Module, kerFuncName)); + + TestType* dData = NULL; + HIP_CHECK(hipMalloc(reinterpret_cast(&dData), size)); + + struct { + void* _Ad; + unsigned int _Bd; + unsigned int _Cd; + } args; + args._Ad = reinterpret_cast(dData); + args._Bd = width; + args._Cd = height; + + size_t sizeTemp = sizeof(args); + + void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, + &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, + &sizeTemp, + HIP_LAUNCH_PARAM_END}; + + int temp1 = width / GRIDDIMX; + int temp2 = height / GRIDDIMY; + HIP_CHECK( + hipModuleLaunchKernel(Function, GRIDDIMX, GRIDDIMY, GRIDDIMZ, + temp1, temp2, BLOCKDIMZ, 0, 0, + NULL, reinterpret_cast(&config))); + HIP_CHECK(hipDeviceSynchronize()); + TestType* hOutputData = reinterpret_cast(malloc(size)); + if (NULL == hOutputData) { + INFO("Failed to allocate using malloc in testTexType"); + REQUIRE(false); + } else { + memset(hOutputData, 0, size); + HIP_CHECK(hipMemcpy(hOutputData, dData, size, hipMemcpyDeviceToHost)); + TestPassed = validateOutput(width, height, hData, hOutputData); + REQUIRE(TestPassed); + } + free(hOutputData); + HIP_CHECK(hipFree(dData)); + ARRAY_DESTROY(array) + HIP_CHECK(hipModuleUnload(Module)); + free(hData); + CTX_DESTROY() +} + +/* +This testcase verifies hipModuleGetTexRef on multiple streams +where + * 1..Loads the code object file + * 2.Allocate array and initializes it with hData + * 3.Assigns array to texRef + 4.Creates multiple streams + * 4.Launches the kernel on each stream which invokes text2D API + and copies the data to output variable + * 5.Validates the hData with output data in each stream. +*/ +TEST_CASE("Unit_hipModuleGetTexRef_TexMultStream") { + bool TestPassed = true; + auto buffer = load_file(); + TestPassed = testTexMultStream(buffer, + HIP_AD_FORMAT_FLOAT, + "ftex", + "tex2dKernelFloat", + MAX_STREAMS); + REQUIRE(TestPassed); +} +/* +This testcase verifies hipModuleGetTexRef Multithreaded scenario on +single stream and multi GPU machine. +1. Gets the device count. +2. Create the threads based on device count. +3. Each thread calls the testTexMultStream which performs the same + above funtionality on single Stream +4. The threads are executed in parallel and are joined later. + +This testcase ensures that the multi thread execution on single stream +in parallel is successful +*/ +TEST_CASE("Unit_hipModuleGetTexRef_MultiThreadTexSingleStreamMultiGPU") { + bool TestPassed = true; + // Testcase skipped on nvidia with CUDA API version 11.2, + // as hipModuleLoadData returning error code + // 'a PTX JIT compilation failed'(218), which is invalid + // behavior. Test passes with AMD and previous CUDA versions. +#if HT_NVIDIA + INFO("Testcase skipped on CUDA version 11.2\n"); + REQUIRE(true); +#else + int gpu_cnt = 0; + auto buffer = load_file(); + HIP_CHECK(hipGetDeviceCount(&gpu_cnt)); + TestPassed = testTexSingleStreamMultGPU(gpu_cnt, buffer); + REQUIRE(TestPassed); +#endif +} + + +/* +This testcase verifies hipModuleGetTexRef Multithreaded scenario on +single stream and multi GPU machine. +1. Gets the device count. +2. Create the threads based on device count. +3. Each thread calls the testTexMultStream which performs the same + above funtionality on multiple Stream +4. The threads are executed in parallel and are joined later. + +This testcase ensures that the multi thread execution on multiple streams +in parallel is successful +*/ +TEST_CASE("Unit_hipModuleGetTexRef_MultiThreadTexMultiStreamMultiGPU") { + bool TestPassed = true; + // Testcase skipped on nvidia with CUDA API version 11.2, + // as hipModuleLoadData returning error code + // 'a PTX JIT compilation failed'(218), which is invalid + // behavior. Test passes with AMD and previous CUDA versions. +#if HT_NVIDIA + INFO("Testcase skipped on CUDA version 11.2\n"); + REQUIRE(true); +#else + int gpu_cnt = 0; + auto buffer = load_file(); + HIP_CHECK(hipGetDeviceCount(&gpu_cnt)); + TestPassed = testTexMultStreamMultGPU(gpu_cnt, buffer); + REQUIRE(TestPassed); +#endif +} diff --git a/tests/catch/unit/module/hipModuleUnload.cc b/tests/catch/unit/module/hipModuleUnload.cc new file mode 100644 index 0000000000..24c6575d1b --- /dev/null +++ b/tests/catch/unit/module/hipModuleUnload.cc @@ -0,0 +1,34 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + + +#include + +#define fileName "module_kernels.code" +/* +This testcase verifies the basic functionality of hipModuleUnload API +*/ +TEST_CASE("Unit_hipModuleUnload_Basic") { + CTX_CREATE() + hipModule_t module; + HIP_CHECK(hipModuleLoad(&module, fileName)); + HIP_CHECK(hipModuleUnload(module)); + CTX_DESTROY() +} diff --git a/tests/catch/unit/module/hipOpenCLCOTest.cc b/tests/catch/unit/module/hipOpenCLCOTest.cc new file mode 100644 index 0000000000..91cfae767a --- /dev/null +++ b/tests/catch/unit/module/hipOpenCLCOTest.cc @@ -0,0 +1,229 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +This testcase reads the openCL kernel file and generate the the code object +file which gets executed in HIP interface. +This testcase verifies for the +1. Current GPU architecture +2. Code object version v3 +*/ + +#ifdef __linux__ +#include + #include +#endif +#include +#include "hip_test_common.hh" +#include "hip_test_checkers.hh" + +#define OPENCL_OBJ_FILE "opencl_add.cc" +#define HIP_CODEOBJ_FILE_DEFAULT "opencl_add.co" +#define HIP_CODEOBJ_FILE_V3 "opencl_add_v3.co" +#define COMMAND_LEN 256 +#define BUFFER_LEN 256 + + +#ifdef __linux__ + +/* Check if environment variable $ROCM_PATH is defined */ +static bool isRocmPathSet() { + FILE *fpipe; + char const *command = "echo $ROCM_PATH"; + fpipe = popen(command, "r"); + + if (fpipe == nullptr) { + WARN("Unable to create command"); + return false; + } + char command_op[BUFFER_LEN]; + if (fgets(command_op, BUFFER_LEN, fpipe)) { + size_t len = strlen(command_op); + if (len > 1) { // This is because fgets always adds newline character + pclose(fpipe); + return true; + } + } + pclose(fpipe); + return false; +} + +/* Gets the sramecc/xnack settings from rocm info */ + +int getV3TargetIdFeature(char* feature, bool rocmPathSet) { + FILE *fpipe; + char command[COMMAND_LEN] = ""; + const char *rocmpath = nullptr; + if (rocmPathSet) { + // For STG2 testing where /opt/rocm path is not present + rocmpath = "$ROCM_PATH/bin/rocminfo"; + } else { + // Check if the rocminfo tool exists + rocmpath = "/opt/rocm/bin/rocminfo"; + } + snprintf(command, COMMAND_LEN, "%s", rocmpath); + strncat(command, " | grep -m1 \"sramecc.:xnack.\"", COMMAND_LEN); + fpipe = popen(command, "r"); + + if (fpipe == nullptr) { + WARN("Unable to create command file"); + return -1; + } + char command_op[BUFFER_LEN]; + const char* pOpt1 = nullptr; + const char *pOpt2 = nullptr; + if (fgets(command_op, BUFFER_LEN, fpipe)) { + if (strstr(command_op, "sramecc+")) { + pOpt1 = "-msram-ecc"; + } else if (strstr(command_op, "sramecc-")) { + pOpt1 = "-mno-sram-ecc"; + } else { + pclose(fpipe); + return -1; + } + if (strstr(command_op, "xnack+")) { + pOpt2 = " -mxnack"; + } else if (strstr(command_op, "xnack-")) { + pOpt2 = " -mno-xnack"; + } else { + pclose(fpipe); + return -1; + } + } else { + printf("No sramecc/xnack settings found.\n"); + pclose(fpipe); + return -1; + } + strncpy(feature, pOpt1, strlen(pOpt1)); + strncat(feature, pOpt2, strlen(pOpt2)); + pclose(fpipe); + return 0; +} +#endif +/** + * Validates OpenCL Static Lds Code Object where + * 1. Tries to access opencl kernel file + * 2. Copies it to current folder + * 3. Tries to get RocmPath and execute the kernel file to + generate the code object file.code-object-version argument + specifies the code object version + * 4. Launch the kernel which copies one variable to another + * 5. Validates the result. + */ +TEST_CASE("Unit_hipModuleLoad_OpenCLStaticCodeObjV3") { +#ifdef __linux__ + auto codeobj_type = GENERATE(0, 1); + char command[COMMAND_LEN] = ""; + char v3option[32] = ""; + hipDeviceProp_t props; + hipGetDeviceProperties(&props, 0); + std::string path = std::experimental::filesystem::current_path(); + WARN("path is " << path.c_str()); + if (access("./opencl_add.cc", F_OK) == -1) { + system("cp ./../../../../hip-on-rocclr/tests/catch/unit/module/opencl_add.cc ."); + } + // Generate the command to translate the OpenCL code object to hip code object + const char *pCodeObjVer = nullptr; + const char *pCodeObjFile = nullptr; + bool rocmPathSet = isRocmPathSet(); + if (codeobj_type == 0) { + pCodeObjVer = ""; + pCodeObjFile = HIP_CODEOBJ_FILE_DEFAULT; + } else { + pCodeObjVer = "-mcode-object-version=3"; + if (-1 == getV3TargetIdFeature(v3option, rocmPathSet)) { + INFO("Error getting V3 Option. Skipping Test. \n"); + REQUIRE(true); + } + pCodeObjFile = HIP_CODEOBJ_FILE_V3; + } + INFO("v3option "<< v3option); + /* The command string is created using multiple concatenation instead of one go + to avoid the following cpplint error: + " Multi-line string ("...") found. This lint script doesn't do well with such strings, + and may give bogus warnings. Use C++11 raw strings or concatenation instead." + */ + if (rocmPathSet) { + // For STG2 testing where /opt/rocm path is not present + snprintf(command, COMMAND_LEN, + "$ROCM_PATH/llvm/bin/clang -target amdgcn-amd-amdhsa -x cl "); + } else { + snprintf(command, COMMAND_LEN, + "/opt/rocm/llvm/bin/clang -target amdgcn-amd-amdhsa -x cl "); + } + char command_temp[COMMAND_LEN] = ""; + snprintf(command_temp, COMMAND_LEN, + "-include `find /opt/rocm* -name opencl-c.h` %s %s -mcpu=%s -o %s %s", + pCodeObjVer, v3option, props.gcnArchName, pCodeObjFile, OPENCL_OBJ_FILE); + + strncat(command, command_temp, COMMAND_LEN); + INFO("command executed "<< command); + + system((const char*)command); + // Check if the code object file is created + snprintf(command, COMMAND_LEN, "./%s", + pCodeObjFile); + + if (access(command, F_OK) == -1) { + INFO("Code Object File not found \n"); + REQUIRE(true); + } + + hipDevice_t device; + hipModule_t Module; + hipFunction_t Function; + HIPCHECK(hipDeviceGet(&device, 0)); + HIPCHECK(hipModuleLoad(&Module, pCodeObjFile)); + HIPCHECK(hipModuleGetFunction(&Function, Module, "add")); + float *Ah, *Bh, *Ad, *Bd; + HipTest::initArrays(&Ad, &Bd, nullptr, &Ah, &Bh, nullptr, + BUFFER_LEN, false); + + HIPCHECK(hipMemcpy(Ad, Ah, sizeof(float) * BUFFER_LEN, + hipMemcpyHostToDevice)); + + struct { + void* _Bd; + void* _Ad; + } args; + args._Ad = static_cast(Ad); + args._Bd = static_cast(Bd); + size_t size = sizeof(args); + + void *config[] = { + HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, + HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, + HIP_LAUNCH_PARAM_END + }; + + HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, BUFFER_LEN, 1, 1, 0, 0, + NULL, reinterpret_cast(&config))); + HIPCHECK(hipMemcpy(Bh, Bd, sizeof(float) * BUFFER_LEN, + hipMemcpyDeviceToHost)); + + for (uint32_t i = 0; i < BUFFER_LEN; i++) { + REQUIRE(Ah[i] == Bh[i]); + } + HipTest::freeArrays(Ad, Bd, nullptr, + Ah, Bh, nullptr, false); +#else + INFO("This test is skipped due to non linux environment.\n"); + REQUIRE(true); +#endif +} diff --git a/tests/catch/unit/module/module_kernels.cc b/tests/catch/unit/module/module_kernels.cc new file mode 100644 index 0000000000..ccb9c204ea --- /dev/null +++ b/tests/catch/unit/module/module_kernels.cc @@ -0,0 +1,167 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#include +#include "hip/hip_runtime.h" + +#define GLOBAL_BUF_SIZE 2048 +#define ARRAY_SIZE (16) + +texture ftex; +texture itex; +texture stex; +texture ctex; + +__device__ int deviceGlobal = 1; +__managed__ int x = 10; +__device__ float myDeviceGlobal; +__device__ float myDeviceGlobalArray[16]; + + +__device__ float deviceGlobalFloat; +__device__ int deviceGlobalInt1; +__device__ int deviceGlobalInt2; +__device__ uint16_t deviceGlobalShort; +__device__ char deviceGlobalChar; + +extern "C" __global__ void tex2dKernelFloat(float* outputData, + int width, int height) { + int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; + int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + if ((x < width) && (y < width)) { + outputData[y * width + x] = tex2D(ftex, x, y); + } +} + +extern "C" __global__ void tex2dKernelInt(int* outputData, + int width, int height) { + int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; + int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + if ((x < width) && (y < width)) { + outputData[y * width + x] = tex2D(itex, x, y); + } +} + +extern "C" __global__ void tex2dKernelInt16(uint16_t* outputData, + int width, int height) { + int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; + int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + if ((x < width) && (y < width)) { + outputData[y * width + x] = tex2D(stex, x, y); + } +} + +extern "C" __global__ void tex2dKernelInt8(char* outputData, + int width, int height) { + int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; + int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + if ((x < width) && (y < width)) { + outputData[y * width + x] = tex2D(ctex, x, y); + } +} + +extern "C" __global__ void matmulK(int clockrate, int* A, int* B, int* C, + int N) { + int ROW = blockIdx.y*blockDim.y+threadIdx.y; + int COL = blockIdx.x*blockDim.x+threadIdx.x; + int tmpSum = 0; + if ((ROW < N) && (COL < N)) { + // each thread computes one element of the block sub-matrix + for (int i = 0; i < N; i++) { + tmpSum += A[ROW * N + i] * B[i * N + COL]; + } + C[ROW * N + COL] = tmpSum; + } +} + +extern "C" __global__ void KernelandExtraParams(int* A, int* B, int* C, + int *D, int N) { + int ROW = blockIdx.y*blockDim.y+threadIdx.y; + int COL = blockIdx.x*blockDim.x+threadIdx.x; + int tmpSum = 0; + if (ROW < N && COL < N) { + // each thread computes one element of the block sub-matrix + for (int i = 0; i < N; i++) { + tmpSum += A[ROW * N + i] * B[i * N + COL]; + } + } + C[ROW * N + COL] = tmpSum; + D[ROW * N + COL] = tmpSum; +} + +extern "C" __global__ void SixteenSecKernel(int clockrate) { + HipTest::waitKernel(16, clockrate); +} + +extern "C" __global__ void TwoSecKernel(int clockrate) { + if (deviceGlobal == 0x2222) { + deviceGlobal = 0x3333; + } + + HipTest::waitKernel(2, clockrate); + + if (deviceGlobal != 0x3333) { + deviceGlobal = 0x5555; + } +} + +extern "C" __global__ void FourSecKernel(int clockrate) { + if (deviceGlobal == 1) { + deviceGlobal = 0x2222; + } + + HipTest::waitKernel(4, clockrate); + + if (deviceGlobal == 0x2222) { + deviceGlobal = 0x4444; + } +} + +extern "C" __global__ void GPU_func() { + x++; +} + + +__device__ int getSquareOfGlobalFloat() { + return static_cast(deviceGlobalFloat*deviceGlobalFloat); +} + +extern "C" __global__ void testWeightedCopy(int* a, int* b) { + int tx = hipThreadIdx_x; + b[tx] = deviceGlobalInt1*a[tx] + deviceGlobalInt2 + + static_cast(deviceGlobalShort) + static_cast(deviceGlobalChar) + + getSquareOfGlobalFloat(); +} + + +extern "C" __global__ void hello_world(const float* a, float* b) { + int tx = hipThreadIdx_x; + b[tx] = a[tx]; +} + +extern "C" __global__ void test_globals(const float* a, float* b) { + int tx = hipThreadIdx_x; + b[tx] = a[tx] + myDeviceGlobal + myDeviceGlobalArray[tx % ARRAY_SIZE]; +} + +extern "C" __global__ void EmptyKernel() { +} diff --git a/tests/catch/unit/module/opencl_add.cc b/tests/catch/unit/module/opencl_add.cc new file mode 100644 index 0000000000..267ffc7f3b --- /dev/null +++ b/tests/catch/unit/module/opencl_add.cc @@ -0,0 +1,37 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +kernel void add(global float* output, global float* input) { + __local float lds[100]; + int id = get_global_id(0); + + if (id == 0) { + for (int i = 0; i < 100; i++) { + lds[i] = input[i]; + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + if (id < 100) { + output[id] = lds[id]; + } else { + output[id] = input[id]; + } +} From b537d94974f0e63a99eb82a8197a09868cc6e6dd Mon Sep 17 00:00:00 2001 From: sumanthtg <90063301+sumanthtg@users.noreply.github.com> Date: Fri, 17 Sep 2021 11:54:39 +0530 Subject: [PATCH 4/9] SWDEV-294470 - [dtest] Catch2 unit tests for hipMemset2d, hipMemset2d Mthread, hipMemset3d files. (#2347) Change-Id: Ia503f9dd12b8c576dee17c3fcbb018eeac305a7e Co-authored-by: Maneesh Gupta --- tests/catch/include/hip_test_helper.hh | 38 +++- tests/catch/unit/memory/CMakeLists.txt | 6 + tests/catch/unit/memory/hipMemset2D.cc | 175 +++++++++++++++++ .../hipMemset2DAsyncMultiThreadAndKernel.cc | 185 ++++++++++++++++++ tests/catch/unit/memory/hipMemset3D.cc | 128 ++++++++++++ 5 files changed, 531 insertions(+), 1 deletion(-) create mode 100644 tests/catch/unit/memory/hipMemset2D.cc create mode 100644 tests/catch/unit/memory/hipMemset2DAsyncMultiThreadAndKernel.cc create mode 100644 tests/catch/unit/memory/hipMemset3D.cc diff --git a/tests/catch/include/hip_test_helper.hh b/tests/catch/include/hip_test_helper.hh index 08b6bec0c6..0aec8bac00 100644 --- a/tests/catch/include/hip_test_helper.hh +++ b/tests/catch/include/hip_test_helper.hh @@ -23,10 +23,46 @@ THE SOFTWARE. #pragma once #include "hip_test_common.hh" +#ifdef __linux__ +#include +#endif + namespace HipTest { static inline int getGeviceCount() { int dev = 0; - HIPCHECK(hipGetDeviceCount(&dev)); + HIP_CHECK(hipGetDeviceCount(&dev)); return dev; } + +// Get Free Memory from the system +static size_t getMemoryAmount() { +#ifdef __linux__ + struct sysinfo info{}; + sysinfo(&info); + return info.freeram / (1024 * 1024); // MB +#elif defined(_WIN32) + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return (statex.ullAvailPhys / (1024 * 1024)); // MB +#endif +} + +static size_t getHostThreadCount(const size_t memPerThread, + const size_t maxThreads) { + if (memPerThread == 0) return 0; + auto memAmount = getMemoryAmount(); + const auto processor_count = std::thread::hardware_concurrency(); + if (processor_count == 0 || memAmount == 0) return 0; + size_t thread_count = 0; + if ((processor_count * memPerThread) < memAmount) + thread_count = processor_count; + else + thread_count = reinterpret_cast(memAmount / memPerThread); + if (maxThreads > 0) { + return (thread_count > maxThreads) ? maxThreads : thread_count; + } + return thread_count; +} + } // namespace HipTest diff --git a/tests/catch/unit/memory/CMakeLists.txt b/tests/catch/unit/memory/CMakeLists.txt index 093b6d8ba9..773abef797 100644 --- a/tests/catch/unit/memory/CMakeLists.txt +++ b/tests/catch/unit/memory/CMakeLists.txt @@ -37,6 +37,9 @@ set(TEST_SRC hipMemset.cc hipMemsetAsyncMultiThread.cc hipMemsetAsyncAndKernel.cc + hipMemset3D.cc + hipMemset2D.cc + hipMemset2DAsyncMultiThreadAndKernel.cc ) else() set(TEST_SRC @@ -74,6 +77,9 @@ set(TEST_SRC hipMemset.cc hipMemsetAsyncMultiThread.cc hipMemsetAsyncAndKernel.cc + hipMemset3D.cc + hipMemset2D.cc + hipMemset2DAsyncMultiThreadAndKernel.cc ) endif() # Create shared lib of all tests diff --git a/tests/catch/unit/memory/hipMemset2D.cc b/tests/catch/unit/memory/hipMemset2D.cc new file mode 100644 index 0000000000..e48b8931f0 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset2D.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * 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. + */ + +/** + Testcase Scenarios : + 1) hipMemset2D api with basic functionality. + 2) hipMemset2DAsync api with basic functionality. + 3) hipMemset2D api with partial memset and unique width/height. +*/ + + +#include + + +// Table with unique width/height and memset values. +// (width2D, height2D, memsetWidth, memsetHeight) +typedef std::tuple tupletype; + +static constexpr std::initializer_list tableItems { + std::make_tuple(20, 20, 20, 20), + std::make_tuple(10, 10, 4, 4), + std::make_tuple(100, 100, 20, 40), + std::make_tuple(256, 256, 39, 19), + std::make_tuple(100, 100, 20, 0), + std::make_tuple(100, 100, 0, 20), + std::make_tuple(100, 100, 0, 0), + }; + + + +/** + * Basic Functionality of hipMemset2D + */ +TEST_CASE("Unit_hipMemset2D_BasicFunctional") { + constexpr int memsetval = 0x24; + constexpr size_t numH = 256; + constexpr size_t numW = 256; + size_t pitch_A; + size_t width = numW * sizeof(char); + size_t sizeElements = width * numH; + size_t elements = numW * numH; + char *A_d, *A_h; + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, width, + numH)); + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + + for (size_t i = 0; i < elements; i++) { + A_h[i] = 1; + } + + HIP_CHECK(hipMemset2D(A_d, pitch_A, memsetval, numW, numH)); + HIP_CHECK(hipMemcpy2D(A_h, width, A_d, pitch_A, numW, numH, + hipMemcpyDeviceToHost)); + + for (size_t i = 0; i < elements; i++) { + if (A_h[i] != memsetval) { + INFO("Memset2D mismatch at index:" << i << " computed:" + << A_h[i] << " memsetval:" << memsetval); + REQUIRE(false); + } + } + + hipFree(A_d); + free(A_h); +} + + +/** + * Basic Functionality of hipMemset2DAsync + */ +TEST_CASE("Unit_hipMemset2DAsync_BasicFunctional") { + constexpr int memsetval = 0x26; + constexpr size_t numH = 256; + constexpr size_t numW = 256; + size_t pitch_A; + size_t width = numW * sizeof(char); + size_t sizeElements = width * numH; + size_t elements = numW * numH; + char *A_d, *A_h; + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width, numH)); + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + + for (size_t i = 0; i < elements; i++) { + A_h[i] = 1; + } + + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset2DAsync(A_d, pitch_A, memsetval, numW, numH, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipMemcpy2D(A_h, width, A_d, pitch_A, numW, numH, + hipMemcpyDeviceToHost)); + + for (size_t i=0; i < elements; i++) { + if (A_h[i] != memsetval) { + INFO("Memset2DAsync mismatch at index:" << i << " computed:" + << A_h[i] << " memsetval:" << memsetval); + REQUIRE(false); + } + } + + hipFree(A_d); + HIP_CHECK(hipStreamDestroy(stream)); + free(A_h); +} + + +/** + * Memset partial buffer with unique Width and Height + */ +TEST_CASE("Unit_hipMemset2D_UniqueWidthHeight") { + int width2D, height2D; + int memsetWidth, memsetHeight; + char *A_d, *A_h; + size_t pitch_A; + constexpr int memsetval = 0x26; + + std::tie(width2D, height2D, memsetWidth, memsetHeight) = + GENERATE(table(tableItems)); + + size_t width = width2D * sizeof(char); + size_t sizeElements = width * height2D; + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width, height2D)); + + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + + for (size_t index = 0; index < sizeElements; index++) { + A_h[index] = 'c'; + } + + INFO("2D Dimension: Width:" << width2D << " Height:" << height2D << + " MemsetWidth:" << memsetWidth << " MemsetHeight:" << memsetHeight); + + HIP_CHECK(hipMemset2D(A_d, pitch_A, memsetval, memsetWidth, memsetHeight)); + HIP_CHECK(hipMemcpy2D(A_h, width, A_d, pitch_A, width2D, height2D, + hipMemcpyDeviceToHost)); + + for (int row = 0; row < memsetHeight; row++) { + for (int column = 0; column < memsetWidth; column++) { + if (A_h[(row * width) + column] != memsetval) { + INFO("A_h[" << row << "][" << column << "]" << + " didnot match " << memsetval); + REQUIRE(false); + } + } + } + + hipFree(A_d); + free(A_h); +} + diff --git a/tests/catch/unit/memory/hipMemset2DAsyncMultiThreadAndKernel.cc b/tests/catch/unit/memory/hipMemset2DAsyncMultiThreadAndKernel.cc new file mode 100644 index 0000000000..04240a4104 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset2DAsyncMultiThreadAndKernel.cc @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2021 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 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. +*/ + +/** + Testcase Scenarios : + 1) Order of execution of device kernel and hipMemset2DAsync api + 2) hipMemSet2DAsync execution in multiple threads +*/ + +#include +#include +#include +#include + + +/* Defines */ +#define NUM_THREADS 1000 +#define ITER 100 +#define NUM_H 256 +#define NUM_W 256 + + + +void queueJobsForhipMemset2DAsync(char* A_d, char* A_h, size_t pitch, + size_t width, hipStream_t stream) { + constexpr int memsetval = 0x22; + HIPCHECK(hipMemset2DAsync(A_d, pitch, memsetval, NUM_W, NUM_H, stream)); + HIPCHECK(hipMemcpy2DAsync(A_h, width, A_d, pitch, NUM_W, NUM_H, + hipMemcpyDeviceToHost, stream)); +} + + +/** + * Order of execution of device kernel and hipMemset2DAsync api. + */ +TEST_CASE("Unit_hipMemset2DAsync_WithKernel") { + constexpr auto N = 4 * 1024 * 1024; + constexpr auto blocksPerCU = 6; // to hide latency + constexpr auto threadsPerBlock = 256; + constexpr int memsetval = 0x22; + char *A_d, *A_h, *B_d, *B_h, *C_d; + size_t pitch_A, pitch_B, pitch_C; + size_t width = NUM_W * sizeof(char); + size_t sizeElements = width * NUM_H; + size_t elements = NUM_W * NUM_H; + unsigned blocks{}; + int validateCount{}; + hipStream_t stream; + + blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width, NUM_H)); + HIP_CHECK(hipMallocPitch(reinterpret_cast(&B_d), &pitch_B, + width, NUM_H)); + + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + B_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(B_h != nullptr); + HIP_CHECK(hipMallocPitch(reinterpret_cast(&C_d), &pitch_C, + width, NUM_H)); + + for (size_t i = 0; i < elements; i++) { + B_h[i] = i; + } + HIP_CHECK(hipMemcpy2D(B_d, width, B_h, pitch_B, NUM_W, NUM_H, + hipMemcpyHostToDevice)); + HIP_CHECK(hipStreamCreate(&stream)); + + + for (size_t k = 0; k < ITER; k++) { + hipLaunchKernelGGL(HipTest::vector_square, dim3(blocks), + dim3(threadsPerBlock), 0, stream, B_d, C_d, elements); + + HIP_CHECK(hipMemset2DAsync(C_d, pitch_C, memsetval, NUM_W, NUM_H, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipMemcpy2D(A_h, width, C_d, pitch_C, NUM_W, NUM_H, + hipMemcpyDeviceToHost)); + + for (size_t p = 0 ; p < elements ; p++) { + if (A_h[p] == memsetval) { + validateCount+= 1; + } + } + } + + REQUIRE(static_cast(validateCount) == (ITER * elements)); + + HIP_CHECK(hipFree(A_d)); HIP_CHECK(hipFree(B_d)); HIP_CHECK(hipFree(C_d)); + free(A_h); free(B_h); + HIP_CHECK(hipStreamDestroy(stream)); +} + + +/** + * hipMemSet2DAsync execution in multiple threads. + */ +TEST_CASE("Unit_hipMemset2DAsync_MultiThread") { + constexpr auto N = 4 * 1024 * 1024; + constexpr auto blocksPerCU = 6; // to hide latency + constexpr auto threadsPerBlock = 256; + constexpr auto memPerThread = 200; + constexpr int memsetval = 0x22; + char *A_d, *A_h, *B_d, *B_h, *C_d; + size_t pitch_A, pitch_B, pitch_C; + size_t width = NUM_W * sizeof(char); + size_t sizeElements = width * NUM_H; + size_t elements = NUM_W * NUM_H; + unsigned blocks{}; + int validateCount{}; + hipStream_t stream; + + blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + auto thread_count = HipTest::getHostThreadCount(memPerThread, NUM_THREADS); + if (thread_count == 0) { + WARN("Resources not available for thread creation"); + return; + } + + std::thread *t = new std::thread[thread_count]; + + HIP_CHECK(hipMallocPitch(reinterpret_cast(&A_d), &pitch_A, + width, NUM_H)); + HIP_CHECK(hipMallocPitch(reinterpret_cast(&B_d), &pitch_B, + width, NUM_H)); + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + B_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(B_h != nullptr); + HIP_CHECK(hipMallocPitch(reinterpret_cast(&C_d), &pitch_C, + width, NUM_H)); + + for (size_t i = 0 ; i < elements ; i++) { + B_h[i] = i; + } + HIP_CHECK(hipMemcpy2D(B_d, width, B_h, pitch_B, NUM_W, NUM_H, + hipMemcpyHostToDevice)); + HIP_CHECK(hipStreamCreate(&stream)); + + for (int i = 0 ; i < ITER ; i++) { + for (size_t k = 0 ; k < thread_count; k++) { + if (k%2) { + t[k] = std::thread(queueJobsForhipMemset2DAsync, A_d, A_h, pitch_A, + width, stream); + } else { + t[k] = std::thread(queueJobsForhipMemset2DAsync, A_d, B_h, pitch_A, + width, stream); + } + } + for (size_t j = 0 ; j < thread_count; j++) { + t[j].join(); + } + + HIP_CHECK(hipStreamSynchronize(stream)); + for (size_t k = 0 ; k < elements ; k++) { + if ((A_h[k] == memsetval) && (B_h[k] == memsetval)) { + validateCount+= 1; + } + } + } + + REQUIRE(static_cast(validateCount) == (ITER * elements)); + + HIP_CHECK(hipFree(A_d)); HIP_CHECK(hipFree(B_d)); HIP_CHECK(hipFree(C_d)); + free(A_h); free(B_h); + HIP_CHECK(hipStreamDestroy(stream)); + + delete[] t; +} diff --git a/tests/catch/unit/memory/hipMemset3D.cc b/tests/catch/unit/memory/hipMemset3D.cc new file mode 100644 index 0000000000..0fc1a83818 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset3D.cc @@ -0,0 +1,128 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +/** + Functional test for Memset3D and Memset3DAsync + */ + + +#include + + +/** + * Basic Functional test of hipMemset3D + */ +TEST_CASE("Unit_hipMemset3D_BasicFunctional") { + constexpr int memsetval = 0x22; + constexpr size_t numH = 256; + constexpr size_t numW = 256; + constexpr size_t depth = 10; + size_t width = numW * sizeof(char); + size_t sizeElements = width * numH * depth; + size_t elements = numW * numH * depth; + char *A_h; + + hipExtent extent = make_hipExtent(width, numH, depth); + hipPitchedPtr devPitchedPtr; + + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + + for (size_t i = 0; i < elements; i++) { + A_h[i] = 1; + } + HIP_CHECK(hipMemset3D(devPitchedPtr, memsetval, extent)); + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width , numW, numH); + myparms.srcPtr = devPitchedPtr; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (size_t i = 0; i < elements; i++) { + if (A_h[i] != memsetval) { + INFO("Memset3D mismatch at index:" << i << " computed:" + << A_h[i] << " memsetval:" << memsetval); + REQUIRE(false); + } + } + HIP_CHECK(hipFree(devPitchedPtr.ptr)); + free(A_h); +} + +/** + * Basic Functional test of hipMemset3DAsync + */ +TEST_CASE("Unit_hipMemset3DAsync_BasicFunctional") { + constexpr int memsetval = 0x22; + constexpr size_t numH = 256; + constexpr size_t numW = 256; + constexpr size_t depth = 10; + size_t width = numW * sizeof(char); + size_t sizeElements = width * numH * depth; + size_t elements = numW * numH * depth; + hipExtent extent = make_hipExtent(width, numH, depth); + hipPitchedPtr devPitchedPtr; + char *A_h; + + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + + for (size_t i = 0; i < elements; i++) { + A_h[i] = 1; + } + + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset3DAsync(devPitchedPtr, memsetval, extent, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width , numW, numH); + myparms.srcPtr = devPitchedPtr; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (size_t i = 0; i < elements; i++) { + if (A_h[i] != memsetval) { + INFO("Memset3DAsync mismatch at index:" << i << " computed:" + << A_h[i] << " memsetval:" << memsetval); + REQUIRE(false); + } + } + HIP_CHECK(hipFree(devPitchedPtr.ptr)); + free(A_h); +} From 8c0558c448b8f90e1cb6d3978e8c88052f35295f Mon Sep 17 00:00:00 2001 From: sumanthtg <90063301+sumanthtg@users.noreply.github.com> Date: Fri, 17 Sep 2021 12:11:26 +0530 Subject: [PATCH 5/9] SWDEV-292637 - [dtest] Catch2 unit and multiprocess tests for Memset3d,HostMalloc and MallocConcurrency tests (#2348) Change-Id: I9025bc13735c1d9fb0f0811a9c9d6ad304adc134 --- tests/catch/CMakeLists.txt | 1 + tests/catch/TypeQualifiers/CMakeLists.txt | 12 + .../hipManagedKeyword.cc | 0 tests/catch/hipTestMain/CMakeLists.txt | 11 + tests/catch/include/hip_test_smi.hh | 88 +++ tests/catch/multiproc/CMakeLists.txt | 7 +- .../multiproc/hipHostMallocTestsMproc.cc | 314 +++++++++++ tests/catch/multiproc/hipMallocConcurrency.cc | 171 ------ .../multiproc/hipMallocConcurrencyMproc.cc | 228 ++++++++ tests/catch/unit/memory/CMakeLists.txt | 10 + tests/catch/unit/memory/hipHostMallocTests.cc | 61 +++ .../catch/unit/memory/hipMallocConcurrency.cc | 412 ++++++++++++++ .../unit/memory/hipMemset3DFunctional.cc | 515 ++++++++++++++++++ .../catch/unit/memory/hipMemset3DNegative.cc | 236 ++++++++ .../memory/hipMemset3DRegressMultiThread.cc | 266 +++++++++ 15 files changed, 2159 insertions(+), 173 deletions(-) create mode 100644 tests/catch/TypeQualifiers/CMakeLists.txt rename tests/catch/{unit/memory => TypeQualifiers}/hipManagedKeyword.cc (100%) create mode 100644 tests/catch/include/hip_test_smi.hh create mode 100644 tests/catch/multiproc/hipHostMallocTestsMproc.cc delete mode 100644 tests/catch/multiproc/hipMallocConcurrency.cc create mode 100644 tests/catch/multiproc/hipMallocConcurrencyMproc.cc create mode 100644 tests/catch/unit/memory/hipHostMallocTests.cc create mode 100644 tests/catch/unit/memory/hipMallocConcurrency.cc create mode 100644 tests/catch/unit/memory/hipMemset3DFunctional.cc create mode 100644 tests/catch/unit/memory/hipMemset3DNegative.cc create mode 100644 tests/catch/unit/memory/hipMemset3DRegressMultiThread.cc diff --git a/tests/catch/CMakeLists.txt b/tests/catch/CMakeLists.txt index 0fddc8f346..434dc92b2b 100644 --- a/tests/catch/CMakeLists.txt +++ b/tests/catch/CMakeLists.txt @@ -69,6 +69,7 @@ add_subdirectory(unit) add_subdirectory(ABM) add_subdirectory(hipTestMain) add_subdirectory(stress) +add_subdirectory(TypeQualifiers) if(UNIX) add_subdirectory(multiproc) diff --git a/tests/catch/TypeQualifiers/CMakeLists.txt b/tests/catch/TypeQualifiers/CMakeLists.txt new file mode 100644 index 0000000000..3c60bdf411 --- /dev/null +++ b/tests/catch/TypeQualifiers/CMakeLists.txt @@ -0,0 +1,12 @@ +# Common Tests +set(TEST_SRC + hipManagedKeyword.cc +) + + +# Create shared lib of all tests +add_library(TypeQualifiers SHARED EXCLUDE_FROM_ALL ${TEST_SRC}) + +# Add dependency on build_tests to build it on this custom target +add_dependencies(build_tests TypeQualifiers) + diff --git a/tests/catch/unit/memory/hipManagedKeyword.cc b/tests/catch/TypeQualifiers/hipManagedKeyword.cc similarity index 100% rename from tests/catch/unit/memory/hipManagedKeyword.cc rename to tests/catch/TypeQualifiers/hipManagedKeyword.cc diff --git a/tests/catch/hipTestMain/CMakeLists.txt b/tests/catch/hipTestMain/CMakeLists.txt index 5b62dbbb49..7fe98c71d9 100644 --- a/tests/catch/hipTestMain/CMakeLists.txt +++ b/tests/catch/hipTestMain/CMakeLists.txt @@ -71,3 +71,14 @@ target_link_libraries(StressTest PRIVATE memory stdc++fs) add_dependencies(build_stress_test StressTest) add_custom_target(stress_test COMMAND StressTest) +# Space Specifiers/Qualifiers exe +add_executable(TypeQualifierTests EXCLUDE_FROM_ALL main.cc hip_test_context.cc) +if(HIP_PLATFORM MATCHES "amd") + set_property(TARGET TypeQualifierTests PROPERTY CXX_STANDARD 17) +else() + target_compile_options(TypeQualifierTests PUBLIC -std=c++17) +endif() +target_link_libraries(TypeQualifierTests PRIVATE TypeQualifiers stdc++fs) + +catch_discover_tests(TypeQualifierTests PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST") +add_dependencies(build_tests TypeQualifierTests) diff --git a/tests/catch/include/hip_test_smi.hh b/tests/catch/include/hip_test_smi.hh new file mode 100644 index 0000000000..8962d4f230 --- /dev/null +++ b/tests/catch/include/hip_test_smi.hh @@ -0,0 +1,88 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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. +*/ + +#pragma once + +/** + * @brief Error codes retured by rocm_smi_lib functions + */ +typedef enum { + RSMI_STATUS_SUCCESS = 0x0, //!< Operation was successful + RSMI_STATUS_INVALID_ARGS, //!< Passed in arguments are not valid + RSMI_STATUS_NOT_SUPPORTED, //!< The requested information or + //!< action is not available for the + //!< given input, on the given system + RSMI_STATUS_FILE_ERROR, //!< Problem accessing a file. This + //!< may because the operation is not + //!< supported by the Linux kernel + //!< version running on the executing + //!< machine + RSMI_STATUS_PERMISSION, //!< Permission denied/EACCESS file + //!< error. Many functions require + //!< root access to run. + RSMI_STATUS_OUT_OF_RESOURCES, //!< Unable to acquire memory or other + //!< resource + RSMI_STATUS_INTERNAL_EXCEPTION, //!< An internal exception was caught + RSMI_STATUS_INPUT_OUT_OF_BOUNDS, //!< The provided input is out of + //!< allowable or safe range + RSMI_STATUS_INIT_ERROR, //!< An error occurred when rsmi + //!< initializing internal data + //!< structures + RSMI_INITIALIZATION_ERROR = RSMI_STATUS_INIT_ERROR, + RSMI_STATUS_NOT_YET_IMPLEMENTED, //!< The requested function has not + //!< yet been implemented in the + //!< current system for the current + //!< devices + RSMI_STATUS_NOT_FOUND, //!< An item was searched for but not + //!< found + RSMI_STATUS_INSUFFICIENT_SIZE, //!< Not enough resources were + //!< available for the operation + RSMI_STATUS_INTERRUPT, //!< An interrupt occurred during + //!< execution of function + RSMI_STATUS_UNEXPECTED_SIZE, //!< An unexpected amount of data + //!< was read + RSMI_STATUS_NO_DATA, //!< No data was found for a given + //!< input + RSMI_STATUS_UNEXPECTED_DATA, //!< The data read or provided to + //!< function is not what was expected + RSMI_STATUS_BUSY, //!< A resource or mutex could not be + //!< acquired because it is already + //!< being used + RSMI_STATUS_REFCOUNT_OVERFLOW, //!< An internal reference counter + //!< exceeded INT32_MAX + + RSMI_STATUS_UNKNOWN_ERROR = 0xFFFFFFFF, //!< An unknown error occurred +} rsmi_status_t; + + +/** + * @brief Types of memory + */ +typedef enum { + RSMI_MEM_TYPE_FIRST = 0, + + RSMI_MEM_TYPE_VRAM = RSMI_MEM_TYPE_FIRST, //!< VRAM memory + RSMI_MEM_TYPE_VIS_VRAM, //!< VRAM memory that is visible + RSMI_MEM_TYPE_GTT, //!< GTT memory + + RSMI_MEM_TYPE_LAST = RSMI_MEM_TYPE_GTT +} rsmi_memory_type_t; diff --git a/tests/catch/multiproc/CMakeLists.txt b/tests/catch/multiproc/CMakeLists.txt index 4d2c69b114..3e19d38ef9 100644 --- a/tests/catch/multiproc/CMakeLists.txt +++ b/tests/catch/multiproc/CMakeLists.txt @@ -1,6 +1,5 @@ -# AMD Tests +# Common Tests set(LINUX_TEST_SRC - hipMallocConcurrency.cc childMalloc.cc hipDeviceComputeCapabilityMproc.cc hipDeviceGetPCIBusIdMproc.cc @@ -10,12 +9,16 @@ set(LINUX_TEST_SRC hipGetDevicePropertiesMproc.cc hipSetGetDeviceMproc.cc hipIpcMemAccessTest.cc + hipHostMallocTestsMproc.cc + hipMallocConcurrencyMproc.cc ) if(UNIX) # Create shared lib of all tests add_library(MultiProc SHARED EXCLUDE_FROM_ALL ${LINUX_TEST_SRC}) + target_link_libraries(MultiProc ${CMAKE_DL_LIBS}) + # Add dependency on build_tests to build it on this custom target add_dependencies(build_tests MultiProc) endif() diff --git a/tests/catch/multiproc/hipHostMallocTestsMproc.cc b/tests/catch/multiproc/hipHostMallocTestsMproc.cc new file mode 100644 index 0000000000..cca3c396aa --- /dev/null +++ b/tests/catch/multiproc/hipHostMallocTestsMproc.cc @@ -0,0 +1,314 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + 1) Validate page table allocation of hipHostMalloc() api when + HIP_VISIBLE_DEVICES set to single device. + 2) Validate page table allocation of hipHostMalloc() api when + HIP_VISIBLE_DEVICES set to list of multiple devices. +*/ + +#include +#include + +#if defined(__linux__) +#include +#include +#include +#include + +#if HT_AMD +/* AMD specific as below tests use rocm-smi */ + +/** + * Defines + */ +#define LIB_ROCMSMI "librocm_smi64.so" +#define ALLOC_SIZE (1*1024*1024) + +/** + * Global variables + */ +static rsmi_status_t (*rsmi_dev_memory_usage_get_fp)(uint32_t, + rsmi_memory_type_t, + uint64_t *); +static rsmi_status_t (*rsmi_init_fp)(uint64_t); +static rsmi_status_t (*rsmi_shut_down_fp)(); +static void *rocm_smi_h; + + +/** + * Fetches Gpu device count + */ +static void getDeviceCount(int *pdevCnt) { + int fd[2], val = 0; + pid_t childpid; + + // create pipe descriptors + pipe(fd); + + // disable visible_devices env from shell + unsetenv("ROCR_VISIBLE_DEVICES"); + unsetenv("HIP_VISIBLE_DEVICES"); + + childpid = fork(); + + if (childpid > 0) { // Parent + close(fd[1]); + // parent will wait to read the device cnt + read(fd[0], &val, sizeof(val)); + + // close the read-descriptor + close(fd[0]); + + // wait for child exit + wait(nullptr); + + *pdevCnt = val; + } else if (!childpid) { // Child + int devCnt = 1; + // writing only, no need for read-descriptor + close(fd[0]); + + HIP_CHECK(hipGetDeviceCount(&devCnt)); + // send the value on the write-descriptor: + write(fd[1], &devCnt, sizeof(devCnt)); + + // close the write descriptor: + close(fd[1]); + exit(0); + } else { // failure + *pdevCnt = 0; + return; + } +} + +/** + * Initializes rocm smi library handles + */ +static bool rocm_smi_init() { + // Open ROCm SMI Library + if (!(rocm_smi_h = dlopen(LIB_ROCMSMI, RTLD_LAZY))) { + printf("Error opening rocm smi library!\n"); + return false; + } + + void* fnsym = dlsym(rocm_smi_h, "rsmi_dev_memory_usage_get"); + if (!fnsym) { + printf("Error getting rsmi_dev_memory_usage_get() function\n"); + dlclose(rocm_smi_h); + return false; + } + rsmi_dev_memory_usage_get_fp = reinterpret_cast(fnsym); + + fnsym = dlsym(rocm_smi_h, "rsmi_init"); + if (!fnsym) { + printf("Error getting rsmi_init() function\n"); + dlclose(rocm_smi_h); + return false; + } + rsmi_init_fp = reinterpret_cast(fnsym); + + fnsym = dlsym(rocm_smi_h, "rsmi_shut_down"); + if (!fnsym) { + printf("Error getting rsmi_shut_down() function\n"); + dlclose(rocm_smi_h); + return false; + } + rsmi_shut_down_fp = reinterpret_cast(fnsym); + + uint64_t init_flags = 0; + rsmi_status_t retsmi_init; + retsmi_init = rsmi_init_fp(init_flags); + if (RSMI_STATUS_SUCCESS != retsmi_init) { + printf("Error when initializing rocm_smi\n"); + dlclose(rocm_smi_h); + return false; + } + + return true; +} + +/** + * Exits rocm smi library + */ +static void rocm_smi_exit() { + rsmi_shut_down_fp(); + dlclose(rocm_smi_h); +} + +/** + * Validates page table memory allocations + * by setting visible devices selected. + */ +static bool validatePageTableAllocations(const char *devList, int visDevCnt) { + int fd[2]; + bool testResult = false; + pid_t pid; + int numdev = 0; + + getDeviceCount(&numdev); + REQUIRE(numdev > 0); + + if (pipe(fd) < 0) { + printf("Pipe system call failed\n"); + return false; + } + + pid = fork(); + + if (!pid) { // Child process + rsmi_status_t ret; + std::vector prev, current; + uint64_t used = 0; + int tmpdev = 0, changeCnt = 0, indx = 0; + char *ptr = nullptr; + bool testPassed = true; + + // Disable visible_devices env from shell + unsetenv("ROCR_VISIBLE_DEVICES"); + unsetenv("HIP_VISIBLE_DEVICES"); + + setenv("HIP_VISIBLE_DEVICES", devList, 1); + + // First Call to initialize hip api + hipGetDeviceCount(&tmpdev); + + + // Get memory snapshot before hostmalloc + for (indx = 0; indx < numdev; indx++) { + ret = rsmi_dev_memory_usage_get_fp(indx, RSMI_MEM_TYPE_VRAM, &used); + if (RSMI_STATUS_SUCCESS != ret) { + printf("Error while running rsmi_dev_memory_usage_get func\n"); + dlclose(rocm_smi_h); + rsmi_shut_down_fp(); + return false; + } + prev.push_back(used); + } + + HIP_CHECK(hipHostMalloc(&ptr, ALLOC_SIZE)); + + // Get memory snapshot after hostmalloc + for (indx = 0; indx < numdev; indx++) { + ret = rsmi_dev_memory_usage_get_fp(indx, RSMI_MEM_TYPE_VRAM, &used); + if (RSMI_STATUS_SUCCESS != ret) { + printf("Error while running rsmi_dev_memory_usage_get func\n"); + dlclose(rocm_smi_h); + rsmi_shut_down_fp(); + hipHostFree(ptr); + return false; + } + current.push_back(used); + } + + for (indx = 0; indx < numdev; indx++) { + if (current[indx] - prev[indx]) + changeCnt++; + } + + // Check if memory allocation happened only for visible devices + if (changeCnt == visDevCnt) { + testPassed = true; + } else { + testPassed = false; + } + + hipHostFree(ptr); + + // writing only, no need for read-descriptor + close(fd[0]); + + // send the value on the write-descriptor: + write(fd[1], &testPassed, sizeof(testPassed)); + + // close the write descriptor: + close(fd[1]); + exit(0); + } else if (pid > 0) { // parent + close(fd[1]); + read(fd[0], &testResult, sizeof(testResult)); + close(fd[0]); + wait(nullptr); + } else { + printf("fork() failed\n"); + HIP_ASSERT(false); + } + + return testResult; +} + +/** + * Test page table allocation when HIP_VISIBLE_DEVICES set to + * single device + */ +TEST_CASE("Unit_hipHostMalloc_SingleVisibleDevicePageAlloc") { + int devCnt; + std::string str; + + if (!rocm_smi_init()) { + WARN("Testcase skipped as rocm smi not initialized/present"); + return; + } + + getDeviceCount(&devCnt); + REQUIRE(devCnt > 0); + + // Select single visible device and validate memory usage + for (int i = 0; i < devCnt; i++) { + str = std::to_string(i); + REQUIRE(validatePageTableAllocations(str.c_str(), 1) == true); + } + + rocm_smi_exit(); +} + +/** + * Test page table allocation when HIP_VISIBLE_DEVICES set to + * multiple devices + */ +TEST_CASE("Unit_hipHostMalloc_MultipleVisibleDevicesPageAlloc") { + int devCnt = 0, vdCnt = 0; + std::string str; + + if (!rocm_smi_init()) { + WARN("Testcase skipped as rocm smi not initialized/present"); + return; + } + + getDeviceCount(&devCnt); + REQUIRE(devCnt > 0); + + // Select multiple visible devices and validate memory usage + for (int i = 0; i < devCnt; i++) { + if (i == 0) + str += std::to_string(i); + else + str += "," + std::to_string(i); + + vdCnt++; + REQUIRE(validatePageTableAllocations(str.c_str(), vdCnt) == true); + } + + rocm_smi_exit(); +} +#endif // HT_AMD +#endif // __linux__ diff --git a/tests/catch/multiproc/hipMallocConcurrency.cc b/tests/catch/multiproc/hipMallocConcurrency.cc deleted file mode 100644 index f6520403d5..0000000000 --- a/tests/catch/multiproc/hipMallocConcurrency.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include -#ifdef __linux__ -#include -#include -#endif -#include -#include -#include -#include - -#include - - -static constexpr size_t N = 4 * 1024 * 1024; -static constexpr unsigned blocksPerCU = 6; // to hide latency -static constexpr unsigned threadsPerBlock = 256; -/** - * Validates data consitency on supplied gpu - */ -bool validateMemoryOnGPU(int gpu, bool concurOnOneGPU = false) { - size_t Nbytes = N * sizeof(int); - int *A_d, *B_d, *C_d; - int *A_h, *B_h, *C_h; - size_t prevAvl, prevTot, curAvl, curTot; - bool TestPassed = true; - - HIP_CHECK(hipSetDevice(gpu)); - HIP_CHECK(hipMemGetInfo(&prevAvl, &prevTot)); - printf("tgs allocating..\n"); - HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false); - - unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); - - HIP_CHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice)); - HIP_CHECK(hipMemcpy(B_d, B_h, Nbytes, hipMemcpyHostToDevice)); - - hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), 0, 0, - static_cast(A_d), static_cast(B_d), C_d, N); - - HIP_CHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost)); - - if (!HipTest::checkVectorADD(A_h, B_h, C_h, N)) { - printf("Validation PASSED for gpu %d from pid %d\n", gpu, getpid()); - } else { - printf("%s : Validation FAILED for gpu %d from pid %d\n", __func__, gpu, getpid()); - TestPassed &= false; - } - - HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false); - HIP_CHECK(hipMemGetInfo(&curAvl, &curTot)); - - if (!concurOnOneGPU && (prevAvl != curAvl || prevTot != curTot)) { - // In concurrent calls on one GPU, we cannot verify leaking in this way - printf( - "%s : Memory allocation mismatch observed." - "Possible memory leak.\n", - __func__); - TestPassed &= false; - } - - return TestPassed; -} - - -#if 1 -/** - * Fetches Gpu device count - */ -void getDeviceCount1(int* pdevCnt) { -#ifdef __linux__ - int fd[2], val = 0; - pid_t childpid; - - // create pipe descriptors - pipe(fd); - - // disable visible_devices env from shell - unsetenv("ROCR_VISIBLE_DEVICES"); - unsetenv("HIP_VISIBLE_DEVICES"); - - childpid = fork(); - - if (childpid > 0) { // Parent - close(fd[1]); - // parent will wait to read the device cnt - read(fd[0], &val, sizeof(val)); - - // close the read-descriptor - close(fd[0]); - - // wait for child exit - wait(NULL); - - *pdevCnt = val; - } else if (!childpid) { // Child - int devCnt = 1; - // writing only, no need for read-descriptor - close(fd[0]); - - HIP_CHECK(hipGetDeviceCount(&devCnt)); - // send the value on the write-descriptor: - write(fd[1], &devCnt, sizeof(devCnt)); - - // close the write descriptor: - close(fd[1]); - exit(0); - } else { // failure - *pdevCnt = 1; - return; - } - -#else - HIP_CHECK(hipGetDeviceCount(pdevCnt)); -#endif -} -#endif - - -TEST_CASE("hipMallocChild_Concurrency_MultiGpu") { - bool TestPassed = false; -#ifdef __linux__ - // Parallel execution on multiple gpus from different child processes - int devCnt = 1, pid = 0; - - // Get GPU count - getDeviceCount1(&devCnt); - - // Spawn child for each GPU - for (int gpu = 0; gpu < devCnt; gpu++) { - if ((pid = fork()) < 0) { - INFO("Child_Concurrency_MultiGpu : fork() returned error" << pid); - REQUIRE(false); - - } else if (!pid) { // Child process - bool TestPassedChild = false; - TestPassedChild = validateMemoryOnGPU(gpu); - - if (TestPassedChild) { - printf("returning exit(1) for success\n"); - exit(1); // child exit with success status - } else { - printf("Child_Concurrency_MultiGpu : childpid %d failed\n", getpid()); - exit(2); // child exit with failure status - } - } - } - - // Parent shall wait for child to complete - int cnt = 0; - - for (int i = 0; i < devCnt; i++) { - int pidwait = 0, exitStatus; - pidwait = wait(&exitStatus); - - printf("exitStatus for iter:%d is %d\n", i, exitStatus); - if (pidwait < 0) { - break; - } - - if (WEXITSTATUS(exitStatus) == 1) cnt++; - } - - if (cnt && (cnt == devCnt)) TestPassed = true; - -#else - INFO("Test hipMallocChild_Concurrency_MultiGpu skipped on non-linux"); -#endif - REQUIRE(TestPassed == true); -} diff --git a/tests/catch/multiproc/hipMallocConcurrencyMproc.cc b/tests/catch/multiproc/hipMallocConcurrencyMproc.cc new file mode 100644 index 0000000000..9018f694a2 --- /dev/null +++ b/tests/catch/multiproc/hipMallocConcurrencyMproc.cc @@ -0,0 +1,228 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + + 1) Run hipMalloc() api/kernel code on same gpu parallely from parent and child + processes, validate the results. + + 2) Execute hipMalloc() api simultaneously on all the gpus by spawning multiple + child processes. Validate buffers allocated after running kernel code. + +*/ + +#include +#include +#include + +#ifdef __linux__ +#include +#include +#include + +/** + * Fetches Gpu device count + */ +static void getDeviceCount(int* pdevCnt) { + int fd[2], val = 0; + pid_t childpid; + + // create pipe descriptors + pipe(fd); + + // disable visible_devices env from shell +#ifdef HT_NVIDIA + unsetenv("CUDA_VISIBLE_DEVICES"); +#else + unsetenv("ROCR_VISIBLE_DEVICES"); + unsetenv("HIP_VISIBLE_DEVICES"); +#endif + + childpid = fork(); + + if (childpid > 0) { // Parent + close(fd[1]); + // parent will wait to read the device cnt + read(fd[0], &val, sizeof(val)); + + // close the read-descriptor + close(fd[0]); + + // wait for child exit + wait(nullptr); + + *pdevCnt = val; + } else if (!childpid) { // Child + int devCnt = 1; + // writing only, no need for read-descriptor + close(fd[0]); + + HIP_CHECK(hipGetDeviceCount(&devCnt)); + // send the value on the write-descriptor: + write(fd[1], &devCnt, sizeof(devCnt)); + + // close the write descriptor: + close(fd[1]); + exit(0); + } else { // failure + *pdevCnt = 0; + return; + } +} + +/** + * Validates data consistency on supplied gpu + */ +static bool validateMemoryOnGPU(int gpu, bool concurOnOneGPU = false) { + int *A_d, *B_d, *C_d; + int *A_h, *B_h, *C_h; + size_t prevAvl, prevTot, curAvl, curTot; + bool TestPassed = true; + constexpr auto N = 4 * 1024 * 1024; + constexpr auto blocksPerCU = 6; // to hide latency + constexpr auto threadsPerBlock = 256; + size_t Nbytes = N * sizeof(int); + + HIP_CHECK(hipSetDevice(gpu)); + HIP_CHECK(hipMemGetInfo(&prevAvl, &prevTot)); + HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false); + + unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + + HIP_CHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(B_d, B_h, Nbytes, hipMemcpyHostToDevice)); + + hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), + 0, 0, static_cast(A_d), + static_cast(B_d), C_d, N); + + HIP_CHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost)); + + if (!HipTest::checkVectorADD(A_h, B_h, C_h, N)) { + printf("Validation PASSED for gpu %d from pid %d\n", gpu, getpid()); + } else { + printf("Validation FAILED for gpu %d from pid %d\n", gpu, getpid()); + TestPassed = false; + } + + HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false); + HIP_CHECK(hipMemGetInfo(&curAvl, &curTot)); + + if (!concurOnOneGPU && (prevAvl != curAvl || prevTot != curTot)) { + // In concurrent calls on one GPU, we cannot verify leaking in this way + printf( + "%s : Memory allocation mismatch observed." + "Possible memory leak.\n", + __func__); + TestPassed = false; + } + + return TestPassed; +} + +/** + * Parallel execution of parent and child on gpu0 + */ +TEST_CASE("Unit_hipMalloc_ChildConcurrencyDefaultGpu") { + int devCnt = 0, pid = 0; + constexpr auto resSuccess = 1, resFailure = 2; + bool TestPassed = true; + + // Get GPU count + getDeviceCount(&devCnt); + REQUIRE(devCnt > 0); + + if ((pid = fork()) < 0) { + INFO("Child_Concurrency_DefaultGpu : fork() returned error : " << pid); + HIP_ASSERT(false); + + } else if (!pid) { // Child process + bool TestPassedChild = false; + + // Allocates and validates memory on Gpu0 simultaneously with parent + TestPassedChild = validateMemoryOnGPU(0, true); + + if (TestPassedChild) { + exit(resSuccess); // child exit with success status + } else { + exit(resFailure); // child exit with failure status + } + + } else { // Parent process + int exitStatus; + + // Allocates and validates memory on Gpu0 simultaneously with child + TestPassed = validateMemoryOnGPU(0, true); + + // Wait and get result from child + pid = wait(&exitStatus); + if ((WEXITSTATUS(exitStatus) == resFailure) || (pid < 0)) + TestPassed = false; + } + + REQUIRE(TestPassed == true); +} + +/** + * Parallel execution of api on multiple gpus from + * different child processes. + */ +TEST_CASE("Unit_hipMalloc_ChildConcurrencyMultiGpu") { + int devCnt = 0, pid = 0; + constexpr auto resSuccess = 1, resFailure = 2; + + // Get GPU count + getDeviceCount(&devCnt); + REQUIRE(devCnt > 0); + + // Spawn child for each GPU + for (int gpu = 0; gpu < devCnt; gpu++) { + if ((pid = fork()) < 0) { + INFO("Child_Concurrency_MultiGpu : fork() returned error : " << pid); + REQUIRE(false); + + } else if (!pid) { // Child process + bool TestPassedChild = false; + TestPassedChild = validateMemoryOnGPU(gpu); + + if (TestPassedChild) { + exit(resSuccess); // child exit with success status + } else { + exit(resFailure); // child exit with failure status + } + } + } + + // Parent shall wait for child to complete + int passCnt = 0; + for (int i = 0; i < devCnt; i++) { + int pidwait = 0, exitStatus; + pidwait = wait(&exitStatus); + + printf("exitStatus for dev:%d is %d\n", i, WEXITSTATUS(exitStatus)); + if (pidwait < 0) { + break; + } + + if (WEXITSTATUS(exitStatus) == resSuccess) passCnt++; + } + REQUIRE(passCnt == devCnt); +} +#endif // __linux__ diff --git a/tests/catch/unit/memory/CMakeLists.txt b/tests/catch/unit/memory/CMakeLists.txt index 773abef797..61571884a1 100644 --- a/tests/catch/unit/memory/CMakeLists.txt +++ b/tests/catch/unit/memory/CMakeLists.txt @@ -40,6 +40,11 @@ set(TEST_SRC hipMemset3D.cc hipMemset2D.cc hipMemset2DAsyncMultiThreadAndKernel.cc + hipHostMallocTests.cc + hipMallocConcurrency.cc + hipMemset3DFunctional.cc + hipMemset3DNegative.cc + hipMemset3DRegressMultiThread.cc ) else() set(TEST_SRC @@ -80,6 +85,11 @@ set(TEST_SRC hipMemset3D.cc hipMemset2D.cc hipMemset2DAsyncMultiThreadAndKernel.cc + hipHostMallocTests.cc + hipMallocConcurrency.cc + hipMemset3DFunctional.cc + hipMemset3DNegative.cc + hipMemset3DRegressMultiThread.cc ) endif() # Create shared lib of all tests diff --git a/tests/catch/unit/memory/hipHostMallocTests.cc b/tests/catch/unit/memory/hipHostMallocTests.cc new file mode 100644 index 0000000000..de445e2e24 --- /dev/null +++ b/tests/catch/unit/memory/hipHostMallocTests.cc @@ -0,0 +1,61 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + + 1) Test hipHostMalloc() api with ptr as nullptr and check for return value. + 2) Test hipHostMalloc() api with size as max(size_t) and check for OOM error. + 3) Test hipHostMalloc() api with flags as max(unsigned int) and validate + return value. + 4) Pass size as zero for hipHostMalloc() api and check ptr is reset with + with return value success. +*/ + +#include + +/** + * Performs argument validation of hipHostMalloc api. + */ +TEST_CASE("Unit_hipHostMalloc_ArgValidation") { + hipError_t ret; + constexpr size_t allocSize = 1000; + char *ptr; + + SECTION("Pass ptr as nullptr") { + ret = hipHostMalloc(static_cast(nullptr), allocSize); + REQUIRE(ret != hipSuccess); + } + + SECTION("Size as max(size_t)") { + ret = hipHostMalloc(&ptr, std::numeric_limits::max()); + REQUIRE(ret != hipSuccess); + } + + SECTION("Flags as max(uint)") { + ret = hipHostMalloc(&ptr, allocSize, + std::numeric_limits::max()); + REQUIRE(ret != hipSuccess); + } + + SECTION("Pass size as zero and check ptr reset") { + HIP_CHECK(hipHostMalloc(&ptr, 0)); + REQUIRE(ptr == nullptr); + } +} diff --git a/tests/catch/unit/memory/hipMallocConcurrency.cc b/tests/catch/unit/memory/hipMallocConcurrency.cc new file mode 100644 index 0000000000..5083ea1c25 --- /dev/null +++ b/tests/catch/unit/memory/hipMallocConcurrency.cc @@ -0,0 +1,412 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + + 1) Test hipMalloc() api passing zero size and confirming *ptr returning + nullptr. Also pass nullptr to hipFree() api. + + 2) Pass maximum value of size_t for hipMalloc() api and make sure appropriate + error is returned. + + 3) Check for hipMalloc() error code, passing invalid/null pointer. + + 4) Regress hipMalloc()/hipFree() in loop for bigger chunk of allocation + with adequate number of iterations and later test for kernel execution on + default gpu. + + 5) Regress hipMalloc()/hipFree() in loop while allocating smaller chunks + keeping maximum number of iterations and then run kernel code on default + gpu, perfom data validation. + + 6) Check hipMalloc() api adaptability when app creates small chunks of memory + continuously, stores it for later use and then frees it at later point + of time. + + 7) Multithread Scenario : Exercise hipMalloc() api parellely on all gpus from + multiple threads and regress the api. + + 8) Validate memory usage with hipMemGetInfo() while regressing hipMalloc() + api. Check for any possible memory leaks. +*/ + +#include +#include +#include + + +#include +#include +#include + + +/* Buffer size for bigger chunks in alloc/free cycles */ +static constexpr auto BuffSizeBC = 5*1024*1024; + +/* Buffer size for smaller chunks in alloc/free cycles */ +static constexpr auto BuffSizeSC = 16; + +/* You may change it for individual test. + * But default 100 is for quick return in Jenkin Build */ +static constexpr auto NumDiv = 100; + +/* Max alloc/free iterations for smaller chunks */ +static constexpr auto MaxAllocFree_SmallChunks = (5000000/NumDiv); + +/* Max alloc/free iterations for bigger chunks */ +static constexpr auto MaxAllocFree_BigChunks = 10000; + +/* Max alloc and pool iterations */ +static constexpr auto MaxAllocPoolIter = (2000000/NumDiv); + +/* Test status shared across threads */ +static std::atomic g_thTestPassed{true}; + + + +/** + * Validates data consistency on supplied gpu + */ +static bool validateMemoryOnGPU(int gpu, bool concurOnOneGPU = false) { + int *A_d, *B_d, *C_d; + int *A_h, *B_h, *C_h; + size_t prevAvl, prevTot, curAvl, curTot; + bool TestPassed = true; + constexpr auto N = 4 * 1024 * 1024; + constexpr auto blocksPerCU = 6; // to hide latency + constexpr auto threadsPerBlock = 256; + size_t Nbytes = N * sizeof(int); + + HIP_CHECK(hipSetDevice(gpu)); + HIP_CHECK(hipMemGetInfo(&prevAvl, &prevTot)); + HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false); + + unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + + HIP_CHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice)); + HIP_CHECK(hipMemcpy(B_d, B_h, Nbytes, hipMemcpyHostToDevice)); + + hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), + 0, 0, static_cast(A_d), + static_cast(B_d), C_d, N); + + HIP_CHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost)); + + if (!HipTest::checkVectorADD(A_h, B_h, C_h, N)) { + UNSCOPED_INFO("Validation PASSED for gpu " << gpu); + } else { + UNSCOPED_INFO("Validation FAILED for gpu " << gpu); + TestPassed = false; + } + + HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false); + HIP_CHECK(hipMemGetInfo(&curAvl, &curTot)); + + if (!concurOnOneGPU && (prevAvl != curAvl || prevTot != curTot)) { + // In concurrent calls on one GPU, we cannot verify leaking in this way + UNSCOPED_INFO( + "validateMemoryOnGPU : Memory allocation mismatch observed." + << "Possible memory leak."); + TestPassed = false; + } + + return TestPassed; +} + + +/** + * Regress memory allocation and free in loop + */ +static bool regressAllocInLoop(int gpu) { + bool TestPassed = true; + size_t tot, avail, ptot, pavail, numBytes; + int i = 0; + int *ptr; + + HIP_CHECK(hipSetDevice(gpu)); + numBytes = BuffSizeBC; + + // Exercise allocation in loop with bigger chunks + for (i = 0; i < MaxAllocFree_BigChunks; i++) { + HIP_CHECK(hipMemGetInfo(&pavail, &ptot)); + HIP_CHECK(hipMalloc(&ptr, numBytes)); + HIP_CHECK(hipMemGetInfo(&avail, &tot)); + HIP_CHECK(hipFree(ptr)); + + if (pavail-avail < numBytes) { // We expect pavail-avail >= numBytes + UNSCOPED_INFO("LoopAllocation " << i << " : Memory allocation of " << + numBytes << " not matching with hipMemGetInfo - FAIL." << "pavail=" << + pavail << ", ptot=" << ptot << ", avail=" << avail << ", tot=" << + tot << ", pavail-avail=" << pavail-avail); + TestPassed = false; + break; + } + } + + // Exercise allocation in loop with smaller chunks and maximum iters + HIP_CHECK(hipMemGetInfo(&pavail, &ptot)); + numBytes = BuffSizeSC; + + for (i = 0; i < MaxAllocFree_SmallChunks; i++) { + HIP_CHECK(hipMalloc(&ptr, numBytes)); + + HIP_CHECK(hipFree(ptr)); + } + + HIP_CHECK(hipMemGetInfo(&avail, &tot)); + + if ((pavail != avail) || (ptot != tot)) { + UNSCOPED_INFO("LoopAllocation : Memory allocation mismatch observed." << + "Possible memory leak."); + TestPassed &= false; + } + + return TestPassed; +} + +/** + * Validates data consistency on supplied gpu + * In Multithreaded Environment + */ +static bool validateMemoryOnGpuMThread(int gpu, bool concurOnOneGPU = false) { + int *A_d, *B_d, *C_d; + int *A_h, *B_h, *C_h; + size_t prevAvl, prevTot, curAvl, curTot; + bool TestPassed = true; + constexpr auto N = 4 * 1024 * 1024; + constexpr auto blocksPerCU = 6; // to hide latency + constexpr auto threadsPerBlock = 256; + size_t Nbytes = N * sizeof(int); + HIPCHECK(hipSetDevice(gpu)); + HIPCHECK(hipMemGetInfo(&prevAvl, &prevTot)); + HipTest::initArrays(&A_d, &B_d, &C_d, &A_h, &B_h, &C_h, N, false); + + unsigned blocks = HipTest::setNumBlocks(blocksPerCU, threadsPerBlock, N); + + HIPCHECK(hipMemcpy(A_d, A_h, Nbytes, hipMemcpyHostToDevice)); + HIPCHECK(hipMemcpy(B_d, B_h, Nbytes, hipMemcpyHostToDevice)); + + hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), + 0, 0, static_cast(A_d), + static_cast(B_d), C_d, N); + + HIPCHECK(hipMemcpy(C_h, C_d, Nbytes, hipMemcpyDeviceToHost)); + + if (!HipTest::checkVectorADD(A_h, B_h, C_h, N)) { + UNSCOPED_INFO("Validation PASSED for gpu " << gpu); + } else { + UNSCOPED_INFO("Validation FAILED for gpu " << gpu); + TestPassed = false; + } + + HipTest::freeArrays(A_d, B_d, C_d, A_h, B_h, C_h, false); + HIPCHECK(hipMemGetInfo(&curAvl, &curTot)); + + if (!concurOnOneGPU && (prevAvl != curAvl || prevTot != curTot)) { + // In concurrent calls on one GPU, we cannot verify leaking in this way + UNSCOPED_INFO( + "validateMemoryOnGpuMThread : Memory allocation mismatch observed." + "Possible memory leak."); + TestPassed = false; + } + + return TestPassed; +} + +/** + * Regress memory allocation and free in loop + * In Multithreaded Environment + */ +static bool regressAllocInLoopMthread(int gpu) { + bool TestPassed = true; + size_t tot, avail, ptot, pavail, numBytes; + int i = 0; + int *ptr; + + HIPCHECK(hipSetDevice(gpu)); + numBytes = BuffSizeBC; + + // Exercise allocation in loop with bigger chunks + for (i = 0; i < MaxAllocFree_BigChunks; i++) { + HIPCHECK(hipMemGetInfo(&pavail, &ptot)); + HIPCHECK(hipMalloc(&ptr, numBytes)); + HIPCHECK(hipMemGetInfo(&avail, &tot)); + HIPCHECK(hipFree(ptr)); + + if (pavail-avail < numBytes) { // We expect pavail-avail >= numBytes + UNSCOPED_INFO("LoopAllocation " << i << " : Memory allocation of " << + numBytes << " not matching with hipMemGetInfo - FAIL." << "pavail=" << + pavail << ", ptot=" << ptot << ", avail=" << avail << ", tot=" << + tot << ", pavail-avail=" << pavail-avail); + TestPassed = false; + break; + } + } + + // Exercise allocation in loop with smaller chunks and maximum iters + HIPCHECK(hipMemGetInfo(&pavail, &ptot)); + numBytes = BuffSizeSC; + + for (i = 0; i < MaxAllocFree_SmallChunks; i++) { + HIPCHECK(hipMalloc(&ptr, numBytes)); + + HIPCHECK(hipFree(ptr)); + } + + HIPCHECK(hipMemGetInfo(&avail, &tot)); + + if ((pavail != avail) || (ptot != tot)) { + UNSCOPED_INFO("LoopAllocation : Memory allocation mismatch observed." << + "Possible memory leak."); + TestPassed &= false; + } + + return TestPassed; +} + +/* + * Thread func to regress alloc and check data consistency + */ +static void threadFunc(int gpu) { + g_thTestPassed = regressAllocInLoopMthread(gpu); + g_thTestPassed = g_thTestPassed & validateMemoryOnGpuMThread(gpu); + + UNSCOPED_INFO("thread execution status on gpu" << gpu << ":" << + g_thTestPassed.load()); +} + + +/* Performs Argument Validation of api */ +TEST_CASE("Unit_hipMalloc_ArgumentValidation") { + int *ptr; + hipError_t ret; + + SECTION("hipMalloc() when size(0)") { + HIP_CHECK(hipMalloc(&ptr, 0)); + // ptr expected to be reset to null ptr + REQUIRE(ptr == nullptr); + } + + SECTION("hipFree() when freeing nullptr ") { + ptr = nullptr; + // api should return success and shudnt crash + HIP_CHECK(hipFree(ptr)); + } + + SECTION("hipMalloc() with invalid argument") { + constexpr auto sizeBytes = 100; + ret = hipMalloc(nullptr, sizeBytes); + REQUIRE(ret != hipSuccess); + } + + SECTION("hipMalloc() with max size_t") { + ret = hipMalloc(&ptr, std::numeric_limits::max()); + REQUIRE(ret != hipSuccess); + } +} + +/** + * Regress hipMalloc()/hipFree() in loop for bigger chunks and + * smaller chunks of memory allocation + */ +TEST_CASE("Unit_hipMalloc_LoopRegressionAllocFreeCycles") { + int devCnt = 0; + + // Get GPU count + HIP_CHECK(hipGetDeviceCount(&devCnt)); + REQUIRE(devCnt > 0); + + CHECK(regressAllocInLoop(0) == true); + CHECK(validateMemoryOnGPU(0) == true); +} + +/** + * Application Behavior Modelling. + * Check hipMalloc() api adaptability when app creates small chunks of memory + * continuously, stores it for later use and then frees it at later point + * of time. + */ +TEST_CASE("Unit_hipMalloc_AllocateAndPoolBuffers") { + size_t avail, tot, pavail, ptot; + bool ret; + hipError_t err; + std::vector ptrlist; + constexpr auto BuffSize = 10; + int devCnt, *ptr; + + // Get GPU count + HIP_CHECK(hipGetDeviceCount(&devCnt)); + REQUIRE(devCnt > 0); + + HIP_CHECK(hipMemGetInfo(&pavail, &ptot)); + + // Allocate small chunks of memory million times + for (int i = 0; i < MaxAllocPoolIter ; i++) { + if ((err = hipMalloc(&ptr, BuffSize)) != hipSuccess) { + HIP_CHECK(hipMemGetInfo(&avail, &tot)); + + INFO("Loop regression pool allocation failure. " << + "Total gpu memory " << tot/(1024.0*1024.0) <<", Free memory " << + avail/(1024.0*1024.0) << " iter " << i << " error " + << hipGetErrorString(err)); + + REQUIRE(false); + } + + // Store pointers allocated to emulate memory pool of app + ptrlist.push_back(ptr); + } + + // Free ptrs at later point of time + for ( auto &t : ptrlist ) { + HIP_CHECK(hipFree(t)); + } + + HIP_CHECK(hipMemGetInfo(&avail, &tot)); + + ret = validateMemoryOnGPU(0); + REQUIRE(ret == true); + REQUIRE(pavail == avail); + REQUIRE(ptot == tot); +} + + +/** + * Exercise hipMalloc() api parellely on all gpus from + * multiple threads and regress the api. + */ +TEST_CASE("Unit_hipMalloc_Multithreaded_MultiGPU") { + std::vector threadlist; + int devCnt; + + // Get GPU count + HIP_CHECK(hipGetDeviceCount(&devCnt)); + REQUIRE(devCnt > 0); + + for (int i = 0; i < devCnt; i++) { + threadlist.push_back(std::thread(threadFunc, i)); + } + + for (auto &t : threadlist) { + t.join(); + } + + REQUIRE(g_thTestPassed == true); +} diff --git a/tests/catch/unit/memory/hipMemset3DFunctional.cc b/tests/catch/unit/memory/hipMemset3DFunctional.cc new file mode 100644 index 0000000000..421e066ab4 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset3DFunctional.cc @@ -0,0 +1,515 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + + 1) Passing width as 0 in extent, verify hipMemset3D api returns success and + doesn't modify the buffer passed. + 2) Passing width as 0 in extent, verify hipMemset3DAsync api returns success + and doesn't modify the buffer passed. + + 3) Passing height as 0 in extent, verify hipMemset3D api returns success and + doesn't modify the buffer passed. + 4) Passing height as 0 in extent, verify hipMemset3DAsync api returns success + and doesn't modify the buffer passed. + + 5) Passing depth as 0 in extent, verify hipMemset3D api returns success and + doesn't modify the buffer passed. + 6) Passing depth as 0 in extent, verify hipMemset3DAsync api returns success + and doesn't modify the buffer passed. + + 7) When extent passed with width, height and depth all as zeroes, verify + hipMemset3D api returns success and doesn't modify the buffer passed. + 8) When extent passed with width, height and depth all as zeroes, verify + hipMemset3DAsync api returns success and doesn't modify the buffer passed. + + 9) Validate data after performing memory set operation with max memset value + for hipMemset3D api. + 10) Validate data after performing memory set operation with max memset value + for hipMemset3DAsync api. + + 11) Select random slice of 3d array and Memset complete slice with + hipMemset3D api. + 12) Select random slice of 3d array and Memset complete slice with + hipMemset3DAsync api. + + 13) Seek device pitched ptr to desired portion of 3d array and memset the + portion with hipMemset3D api. + 14) Seek device pitched ptr to desired portion of 3d array and memset the + portion with hipMemset3DAsync api. +*/ + +#include + +/* + * Defines + */ +#define MEMSETVAL 1 +#define TESTVAL 2 +#define NUMH_EXT 256 +#define NUMW_EXT 100 +#define DEPTH_EXT 10 +#define NUMH_MAX 256 +#define NUMW_MAX 256 +#define DEPTH_MAX 10 +#define ZSIZE_S 32 +#define YSIZE_S 32 +#define XSIZE_S 32 +#define ZSIZE_P 30 +#define YSIZE_P 30 +#define XSIZE_P 30 +#define ZPOS_START 10 +#define ZSET_LEN 10 +#define ZPOS_END 19 +#define YPOS_START 10 +#define YSET_LEN 10 +#define YPOS_END 19 +#define XPOS_START 10 +#define XSET_LEN 10 +#define XPOS_END 19 + + +/** + * Memset with extent passed and verify data to be intact + */ +static void testMemsetWithExtent(bool bAsync, hipExtent tstExtent) { + hipPitchedPtr devPitchedPtr; + hipError_t ret; + char *A_h; + size_t numH = NUMH_EXT, numW = NUMW_EXT, depth = DEPTH_EXT; + size_t width = numW * sizeof(char); + hipExtent extent = make_hipExtent(width, numH, depth); + + size_t sizeElements = width * numH * depth; + size_t elements = numW* numH* depth; + + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + memset(A_h, 0, sizeElements); + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + if (bAsync) { + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + + ret = hipMemset3DAsync(devPitchedPtr, MEMSETVAL, extent, stream); + INFO("testMemsetWithExtent(" << extent.width << "," << extent.height + << "," << extent.depth << ") memset " + << MEMSETVAL << ", ret : " << ret); + REQUIRE(ret == hipSuccess); + + ret = hipMemset3DAsync(devPitchedPtr, TESTVAL, tstExtent, stream); + INFO("testMemsetWithExtent(" << tstExtent.width << "," << tstExtent.height + << "," << tstExtent.depth << ") memset " + << TESTVAL << "ret : " << ret); + REQUIRE(ret == hipSuccess); + + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipStreamDestroy(stream)); + } else { + ret = hipMemset3D(devPitchedPtr, MEMSETVAL, extent); + INFO("testMemsetWithExtent(" << extent.width << "," << extent.height + << "," << extent.depth << ") memset " + << MEMSETVAL << ",ret : " << ret); + REQUIRE(ret == hipSuccess); + + ret = hipMemset3D(devPitchedPtr, TESTVAL, tstExtent); + INFO("testMemsetWithExtent(" << tstExtent.width << "," << tstExtent.height + << "," << tstExtent.depth << ") memset " + << TESTVAL << ",ret : " << ret); + REQUIRE(ret == hipSuccess); + } + + + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width, numW, numH); + myparms.srcPtr = devPitchedPtr; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (size_t i = 0; i < elements; i++) { + if (A_h[i] != MEMSETVAL) { + INFO("testMemsetWithExtent: index:" << i << ",computed:" + << std::hex << static_cast(A_h[i]) << ",memsetval:" + << std::hex << MEMSETVAL); + REQUIRE(false); + } + } + + HIP_CHECK(hipFree(devPitchedPtr.ptr)); + free(A_h); +} + + +/** + * Validates data after performing memory set operation with max memset value + */ +static void testMemsetMaxValue(bool bAsync) { + hipPitchedPtr devPitchedPtr; + unsigned char *A_h; + int memsetval = std::numeric_limits::max(); + size_t numH = NUMH_MAX, numW = NUMW_MAX, depth = DEPTH_MAX; + size_t width = numW * sizeof(unsigned char); + hipExtent extent = make_hipExtent(width, numH, depth); + size_t sizeElements = width * numH * depth; + size_t elements = numW* numH* depth; + + A_h = reinterpret_cast (malloc(sizeElements)); + REQUIRE(A_h != nullptr); + memset(A_h, 0, sizeElements); + + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + if (bAsync) { + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset3DAsync(devPitchedPtr, memsetval, extent, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipStreamDestroy(stream)); + } else { + HIP_CHECK(hipMemset3D(devPitchedPtr, memsetval, extent)); + } + + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width, numW, numH); + myparms.srcPtr = devPitchedPtr; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (size_t i = 0; i < elements; i++) { + if (A_h[i] != memsetval) { + INFO("testMemsetMaxValue: index:" << i << ",computed:" + << std::hex << static_cast(A_h[i]) << ",memsetval:" + << std::hex << memsetval); + REQUIRE(false); + } + } + HIP_CHECK(hipFree(devPitchedPtr.ptr)); + free(A_h); +} + +/** + * Function seeks device ptr to random slice and performs Memset operation + * on the slice selected. + */ +static void seekAndSet3DArraySlice(bool bAsync) { + char array3D[ZSIZE_S][YSIZE_S][XSIZE_S]{}; + dim3 arr_dimensions = dim3(ZSIZE_S, YSIZE_S, XSIZE_S); + hipExtent extent = make_hipExtent(sizeof(char) * arr_dimensions.x, + arr_dimensions.y, arr_dimensions.z); + hipPitchedPtr devicePitchedPointer; + int memsetval = MEMSETVAL, memsetval4seeked = TESTVAL; + + HIP_CHECK(hipMalloc3D(&devicePitchedPointer, extent)); + HIP_CHECK(hipMemset3D(devicePitchedPointer, memsetval, extent)); + + // select random slice for memset + unsigned int seed = time(nullptr); + int slice_index = rand_r(&seed) % ZSIZE_S; + + INFO("memset3d for sliceindex " << slice_index); + + // Get attributes from device pitched pointer + size_t pitch = devicePitchedPointer.pitch; + size_t slicePitch = pitch * extent.height; + + // Point devptr to selected slice + char *devPtrSlice = (reinterpret_cast(devicePitchedPointer.ptr)) + + slice_index * slicePitch; + hipExtent extentSlice = make_hipExtent(sizeof(char) * arr_dimensions.x, + arr_dimensions.y, 1); + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrSlice, pitch, + arr_dimensions.x, arr_dimensions.y); + + if (bAsync) { + // Memset selected slice (Async) + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset3DAsync(modDevPitchedPtr, memsetval4seeked, + extentSlice, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipStreamDestroy(stream)); + } else { + // Memset selected slice + HIP_CHECK(hipMemset3D(modDevPitchedPtr, memsetval4seeked, extentSlice)); + } + + // Copy result back to host buffer + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(array3D, sizeof(char) * arr_dimensions.x, + arr_dimensions.x, arr_dimensions.y); + myparms.srcPtr = devicePitchedPointer; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (int z = 0; z < ZSIZE_S; z++) { + for (int y = 0; y < YSIZE_S; y++) { + for (int x = 0; x < XSIZE_S; x++) { + if (z == slice_index) { + if (array3D[z][y][x] != memsetval4seeked) { + INFO("seekAndSet3DArray Slice: mismatch at index: Arr(" << z + << "," << y << "," << x << ") " << "computed:" << std::hex + << array3D[z][y][x] << ", memsetval:" << std::hex + << memsetval4seeked); + REQUIRE(false); + } + } else { + if (array3D[z][y][x] != memsetval) { + INFO("seekAndSet3DArray Slice: mismatch at index: Arr(" << z + << "," << y << "," << x << ") " << "computed:" << std::hex + << array3D[z][y][x] << ", memsetval:" << std::hex + << memsetval); + REQUIRE(false); + } + } + } + } + } + + HIP_CHECK(hipFree(devicePitchedPointer.ptr)); +} + +/** + * Function seeks device ptr to selected portion of 3d array + * and performs Memset operation on the portion. + */ +static void seekAndSet3DArrayPortion(bool bAsync) { + char array3D[ZSIZE_P][YSIZE_P][XSIZE_P]{}; + dim3 arr_dimensions = dim3(ZSIZE_P, YSIZE_P, XSIZE_P); + hipExtent extent = make_hipExtent(sizeof(char) * arr_dimensions.x, + arr_dimensions.y, arr_dimensions.z); + hipPitchedPtr devicePitchedPointer; + int memsetval = MEMSETVAL, memsetval4seeked = TESTVAL; + + HIP_CHECK(hipMalloc3D(&devicePitchedPointer, extent)); + HIP_CHECK(hipMemset3D(devicePitchedPointer, memsetval, extent)); + + // For memsetting extent/size(10,10,10) in the mid portion of cube(30,30,30), + // seek device ptr to (10,10,10) and then memset 10 bytes across x,y,z axis. + size_t pitch = devicePitchedPointer.pitch; + size_t slicePitch = pitch * extent.height; + int slice_index = ZPOS_START, y = YPOS_START, x = XPOS_START; + + // Select 10th slice + char *devPtrSlice = (reinterpret_cast(devicePitchedPointer.ptr)) + + slice_index * slicePitch; + + // Now select row at height as 10 + char *current_row = reinterpret_cast(devPtrSlice + y * pitch); + + // Now select index of selected row as 10 + char *devPtrIndexed = ¤t_row[x]; + + // Make dev Pitchedptr, extent + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrIndexed, pitch, + arr_dimensions.x, arr_dimensions.y); + hipExtent setExtent = make_hipExtent(sizeof(char) * XSET_LEN, YSET_LEN, + ZSET_LEN); + + if (bAsync) { + // Memset selected portion (Async) + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset3DAsync(modDevPitchedPtr, memsetval4seeked, + setExtent, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipStreamDestroy(stream)); + } else { + // Memset selected portion + HIP_CHECK(hipMemset3D(modDevPitchedPtr, memsetval4seeked, setExtent)); + } + + // Copy result back to host buffer + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(array3D, sizeof(char) * arr_dimensions.x, + arr_dimensions.x, arr_dimensions.y); + myparms.srcPtr = devicePitchedPointer; + myparms.extent = extent; +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (int z = 0; z < ZSIZE_P; z++) { + for (int y = 0; y < YSIZE_P; y++) { + for (int x = 0; x < XSIZE_P; x++) { + if ((z >= ZPOS_START && z <= ZPOS_END) && + (y >= YPOS_START && y <= YPOS_END) && + (x >= XPOS_START && x <= XPOS_END)) { + if (array3D[z][y][x] != memsetval4seeked) { + INFO("seekAndSet3DArray Portion: mismatch at index: Arr(" << z + << "," << y << "," << x << ") " << "computed:" << std::hex + << array3D[z][y][x] << ", memsetval:" << std::hex + << memsetval4seeked); + REQUIRE(false); + } + } else { + if (array3D[z][y][x] != memsetval) { + INFO("seekAndSet3DArray Portion: mismatch at index: Arr(" << z + << "," << y << "," << x << ") " << "computed:" << std::hex + << array3D[z][y][x] << ", memsetval:" << std::hex + << memsetval); + REQUIRE(false); + } + } + } + } + } + + HIP_CHECK(hipFree(devicePitchedPointer.ptr)); +} + + + +/** + * Test Memset3D with different combinations of extent + * taking zero and non-zero fields. + */ +TEST_CASE("Unit_hipMemset3D_MemsetWithExtent") { + hipExtent testExtent; + size_t numH = NUMH_EXT, numW = NUMW_EXT, depth = DEPTH_EXT; + + SECTION("Memset with extent width(0)") { + // Memset with extent width(0) and verify data to be intact + testExtent = make_hipExtent(0, numH, depth); + testMemsetWithExtent(0, testExtent); + } + + SECTION("Memset with extent height(0)") { + // Memset with extent height(0) and verify data to be intact + testExtent = make_hipExtent(numW, 0, depth); + testMemsetWithExtent(0, testExtent); + } + + SECTION("Memset with extent depth(0)") { + // Memset with extent depth(0) and verify data to be intact + testExtent = make_hipExtent(numW, numH, 0); + testMemsetWithExtent(0, testExtent); + } + + SECTION("Memset with extent width,height,depth as 0") { + // Memset with extent width,height,depth as 0 and verify data to be intact + testExtent = make_hipExtent(0, 0, 0); + testMemsetWithExtent(0, testExtent); + } +} + + +/** + * Test Memset3DAsync with different combinations of extent + * taking zero and non-zero fields. + */ +TEST_CASE("Unit_hipMemset3DAsync_MemsetWithExtent") { + hipExtent testExtent; + size_t numH = NUMH_EXT, numW = NUMW_EXT, depth = DEPTH_EXT; + + SECTION("Memset with extent width(0)") { + // Memset with extent width(0) and verify data to be intact + testExtent = make_hipExtent(0, numH, depth); + testMemsetWithExtent(1, testExtent); + } + + SECTION("Memset with extent height(0)") { + // Memset with extent height(0) and verify data to be intact + testExtent = make_hipExtent(numW, 0, depth); + testMemsetWithExtent(1, testExtent); + } + + SECTION("Memset with extent depth(0)") { + // Memset with extent depth(0) and verify data to be intact + testExtent = make_hipExtent(numW, numH, 0); + testMemsetWithExtent(1, testExtent); + } + + SECTION("Memset with extent width,height,depth as 0") { + // Memset with extent width,height,depth as 0 and verify data to be intact + testExtent = make_hipExtent(0, 0, 0); + testMemsetWithExtent(1, testExtent); + } +} + +/** + * Memset3D with max unsigned char and verify memset operation is success + */ +TEST_CASE("Unit_hipMemset3D_MemsetMaxValue") { + testMemsetMaxValue(0); +} + +/** + * Memset3DAsync with max unsigned char and verify memset operation is success + */ +TEST_CASE("Unit_hipMemset3DAsync_MemsetMaxValue") { + testMemsetMaxValue(1); +} + +/** + * Seek and set random slice of 3d array, verify memset is success + */ +TEST_CASE("Unit_hipMemset3D_SeekSetSlice") { + seekAndSet3DArraySlice(0); +} + +/** + * Seek and set random slice of 3d array with async, verify memset is success + */ +TEST_CASE("Unit_hipMemset3DAsync_SeekSetSlice") { + seekAndSet3DArraySlice(1); +} + +/** + * Memset3D selected portion of 3d array + */ +TEST_CASE("Unit_hipMemset3D_SeekSetArrayPortion") { + seekAndSet3DArrayPortion(0); +} + +/** + * Memset3DAsync selected portion of 3d array + */ +TEST_CASE("Unit_hipMemset3DAsync_SeekSetArrayPortion") { + seekAndSet3DArrayPortion(1); +} diff --git a/tests/catch/unit/memory/hipMemset3DNegative.cc b/tests/catch/unit/memory/hipMemset3DNegative.cc new file mode 100644 index 0000000000..798c90e1ac --- /dev/null +++ b/tests/catch/unit/memory/hipMemset3DNegative.cc @@ -0,0 +1,236 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + 1) Test hipMemset3D() with uninitialized devPitchedPtr. + 2) Test hipMemset3DAsync() with uninitialized devPitchedPtr. + + 3) Reset devPitchedPtr to zero and check return value for hipMemset3D(). + 4) Reset devPitchedPtr to zero and check return value for hipMemset3DAsync(). + + 5) Test hipMemset3D() with extent.width as max size_t and keeping height, + depth as valid values. + 6) Test hipMemset3DAsync() with extent.width as max size_t and keeping height, + depth as valid values. + 7) Test hipMemset3D() with extent.height as max size_t and keeping width, + depth as valid values. + 8) Test hipMemset3DAsync() with extent.height as max size_t and keeping width, + depth as valid values. + 9) Test hipMemset3D() with extent.depth as max size_t and keeping height, + width as valid values. +10) Test hipMemset3DAsync() with extent.depth as max size_t and keeping height, + width as valid values. + +11) Device Ptr out bound and extent(0) passed for hipMemset3D(). +12) Device Ptr out bound and extent(0) passed for hipMemset3DAsync(). + +13) Device Ptr out bound and valid extent passed for hipMemset3D(). +14) Device Ptr out bound and valid extent passed for hipMemset3DAsync(). +*/ + +#include + +TEST_CASE("Unit_hipMemset3D_Negative") { + hipError_t ret; + hipPitchedPtr devPitchedPtr; + constexpr int memsetval = 1; + constexpr size_t numH = 256, numW = 256; + constexpr size_t depth = 10; + constexpr size_t width = numW * sizeof(char); + hipExtent extent = make_hipExtent(width, numH, depth); + + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + + SECTION("Using uninitialized devpitched ptr") { + hipPitchedPtr devPitchedUnPtr; + + ret = hipMemset3D(devPitchedUnPtr, memsetval, extent); + REQUIRE(ret != hipSuccess); + } + + SECTION("Reset devPitchedPtr to zero") { + hipPitchedPtr rdevPitchedPtr{}; + + ret = hipMemset3D(rdevPitchedPtr, memsetval, extent); + REQUIRE(ret != hipSuccess); + } + + SECTION("Pass extent fields as max size_t") { + hipExtent extMW = make_hipExtent(std::numeric_limits::max(), + numH, + depth); + hipExtent extMH = make_hipExtent(width, + std::numeric_limits::max(), + depth); + hipExtent extMD = make_hipExtent(width, + numH, + std::numeric_limits::max()); + + ret = hipMemset3D(devPitchedPtr, memsetval, extMW); + REQUIRE(ret != hipSuccess); + + ret = hipMemset3D(devPitchedPtr, memsetval, extMH); + REQUIRE(ret != hipSuccess); + + if ((TestContext::get()).isAmd()) { + ret = hipMemset3D(devPitchedPtr, memsetval, extMD); + REQUIRE(ret != hipSuccess); + } else { + WARN("Test is skipped for max depth." + << "Cuda doesn't check the maximum depth of extent field"); + } + } + + SECTION("Device Ptr out bound and extent(0) passed for memset") { + size_t pitch = devPitchedPtr.pitch; + size_t slicePitch = pitch * extent.height; + constexpr auto advanceOffset = 10; + + // Point devptr to end of allocated memory + char *devPtrMod = (reinterpret_cast(devPitchedPtr.ptr)) + + depth * slicePitch; + + // Advance devptr further to go out of boundary + devPtrMod = devPtrMod + advanceOffset; + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrMod, pitch, + numW * sizeof(char), numH); + hipExtent extent0{}; + ret = hipMemset3D(modDevPitchedPtr, memsetval, extent0); + + // api expected to check extent0 and return success before going for ptr. + REQUIRE(ret == hipSuccess); + } + + SECTION("Device Ptr out bound and valid extent passed for memset") { + size_t pitch = devPitchedPtr.pitch; + size_t slicePitch = pitch * extent.height; + constexpr auto advanceOffset = 10; + + // Point devptr to end of allocated memory + char *devPtrMod = (reinterpret_cast(devPitchedPtr.ptr)) + + depth * slicePitch; + + // Advance devptr further to go out of boundary + devPtrMod = devPtrMod + advanceOffset; + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrMod, pitch, + numW * sizeof(char), numH); + ret = hipMemset3D(modDevPitchedPtr, memsetval, extent); + + REQUIRE(ret != hipSuccess); + } + + HIP_CHECK(hipFree(devPitchedPtr.ptr)); +} + +TEST_CASE("Unit_hipMemset3DAsync_Negative") { + hipError_t ret; + hipPitchedPtr devPitchedPtr; + hipStream_t stream; + constexpr int memsetval = 1; + constexpr size_t numH = 256; + constexpr size_t numW = 256; + constexpr size_t depth = 10; + constexpr size_t width = numW * sizeof(char); + hipExtent extent = make_hipExtent(width, numH, depth); + + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMalloc3D(&devPitchedPtr, extent)); + + SECTION("Using uninitialized devpitched ptr") { + hipPitchedPtr devPitchedUnPtr; + + ret = hipMemset3DAsync(devPitchedUnPtr, memsetval, extent, stream); + REQUIRE(ret != hipSuccess); + } + + SECTION("Reset devPitchedPtr to zero") { + hipPitchedPtr rdevPitchedPtr{}; + + ret = hipMemset3DAsync(rdevPitchedPtr, memsetval, extent, stream); + REQUIRE(ret != hipSuccess); + } + + SECTION("Pass extent fields as max size_t") { + hipExtent extMW = make_hipExtent(std::numeric_limits::max(), + numH, + depth); + hipExtent extMH = make_hipExtent(width, + std::numeric_limits::max(), + depth); + hipExtent extMD = make_hipExtent(width, + numH, + std::numeric_limits::max()); + + ret = hipMemset3DAsync(devPitchedPtr, memsetval, extMW, stream); + REQUIRE(ret != hipSuccess); + + ret = hipMemset3DAsync(devPitchedPtr, memsetval, extMH, stream); + REQUIRE(ret != hipSuccess); + + if ((TestContext::get()).isAmd()) { + ret = hipMemset3DAsync(devPitchedPtr, memsetval, extMD, stream); + REQUIRE(ret != hipSuccess); + } else { + WARN("Test is skipped for max depth." + << "Cuda doesn't check the maximum depth of extent field"); + } + } + + SECTION("Device Ptr out bound and extent(0) passed for memset") { + size_t pitch = devPitchedPtr.pitch; + size_t slicePitch = pitch * extent.height; + constexpr auto advanceOffset = 10; + + // Point devptr to end of allocated memory + char *devPtrMod = (reinterpret_cast(devPitchedPtr.ptr)) + + depth * slicePitch; + + // Advance devptr further to go out of boundary + devPtrMod = devPtrMod + advanceOffset; + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrMod, pitch, + numW * sizeof(char), numH); + hipExtent extent0{}; + ret = hipMemset3DAsync(modDevPitchedPtr, memsetval, extent0, stream); + + // api expected to check extent0 and return success before going for ptr. + REQUIRE(ret == hipSuccess); + } + + SECTION("Device Ptr out bound and valid extent passed for memset") { + size_t pitch = devPitchedPtr.pitch; + size_t slicePitch = pitch * extent.height; + constexpr auto advanceOffset = 10; + + // Point devptr to end of allocated memory + char *devPtrMod = (reinterpret_cast(devPitchedPtr.ptr)) + + depth * slicePitch; + + // Advance devptr further to go out of boundary + devPtrMod = devPtrMod + advanceOffset; + hipPitchedPtr modDevPitchedPtr = make_hipPitchedPtr(devPtrMod, pitch, + numW * sizeof(char), numH); + ret = hipMemset3DAsync(modDevPitchedPtr, memsetval, extent, stream); + + REQUIRE(ret != hipSuccess); + } + + HIP_CHECK(hipStreamDestroy(stream)); + HIP_CHECK(hipFree(devPitchedPtr.ptr)); +} diff --git a/tests/catch/unit/memory/hipMemset3DRegressMultiThread.cc b/tests/catch/unit/memory/hipMemset3DRegressMultiThread.cc new file mode 100644 index 0000000000..b3a65f2104 --- /dev/null +++ b/tests/catch/unit/memory/hipMemset3DRegressMultiThread.cc @@ -0,0 +1,266 @@ +/* +Copyright (c) 2021 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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/** +Testcase Scenarios : + 1) Validate Async behavior of hipMemset3DAsync with commands queued + concurrently from multiple threads. + 2) Validate hipMemset3DAsync behavior when api is queued along with kernel + function operating on same memory. + 3) Perform regression of hipMemset3D api in loop with device memory allocated + on different gpus. + 4) Perform regression of hipMemset3DAsync api in loop with device memory + allocated on different gpus. +*/ + +#include + + +/* + * Defines + */ +#define MAX_REGRESS_ITERS 2 +#define MAX_THREADS 10 + +/** + * kernel function sets device memory with value passed + */ +static __global__ void func_set_value(hipPitchedPtr devicePitchedPointer, + hipExtent extent, + unsigned char val) { + // Index Calculation + size_t x = threadIdx.x + blockDim.x * blockIdx.x; + size_t y = threadIdx.y + blockDim.y * blockIdx.y; + size_t z = threadIdx.z + blockDim.z * blockIdx.z; + + // Get attributes from device pitched pointer + char *devicePointer = reinterpret_cast(devicePitchedPointer.ptr); + size_t pitch = devicePitchedPointer.pitch; + size_t slicePitch = pitch * extent.height; + + // Loop over the device buffer + if (z < extent.depth) { + char *current_slice_index = devicePointer + z * slicePitch; + if (y < extent.height) { + // Get data array containing all elements from the current row + char *current_row = reinterpret_cast(current_slice_index + + y * pitch); + if (x < extent.width) { + current_row[x] = val; + } + } + } +} + + +/** + * Thread function queues kernel function and memset cmds + */ +static void threadFunc(hipStream_t stream, hipPitchedPtr devpPtr, + int memsetval, int testval, hipExtent extent, hipMemcpy3DParms myparms) { + // Kernel Launch Configuration + constexpr auto size = 8; + dim3 threadsPerBlock = dim3(size, size, size); + dim3 blocks; + blocks = dim3((extent.width + threadsPerBlock.x - 1) / threadsPerBlock.x, + (extent.height + threadsPerBlock.y - 1) / threadsPerBlock.y, + (extent.depth + threadsPerBlock.z - 1) / threadsPerBlock.z); + + hipLaunchKernelGGL(func_set_value, dim3(blocks), dim3(threadsPerBlock), 0, + stream, devpPtr, extent, memsetval); + HIPCHECK(hipMemset3DAsync(devpPtr, testval, extent, stream)); + HIPCHECK(hipMemcpy3DAsync(&myparms, stream)); +} + + +/** + * Performs api regression in loop + */ +bool loopRegression(bool bAsync) { + bool testPassed = true; + char *A_h; + constexpr int memsetval = 1; + constexpr size_t numH = 256, numW = 100, depth = 10; + int numGpu = 0, hasPeerAccess = 0; + size_t width = numW * sizeof(char); + hipExtent extent = make_hipExtent(width, numH, depth); + size_t sizeElements = width * numH * depth; + size_t elements = numW* numH* depth; + std::vector devPitchedPtrlist; + hipPitchedPtr pitchedPtr, devpPtr; + + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + memset(A_h, 0, sizeElements); + + // Populate hipMemcpy3D parameters + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width, numW, numH); + myparms.extent = extent; + +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + HIP_CHECK(hipGetDeviceCount(&numGpu)); + REQUIRE(numGpu > 0); + + // Alloc 3D arrays in all GPUs + for (int j = 0; j < numGpu; j++) { + HIP_CHECK(hipSetDevice(j)); + HIP_CHECK(hipMalloc3D(&pitchedPtr, extent)); + devPitchedPtrlist.push_back(pitchedPtr); + } + + for (int itern = 0; itern < MAX_REGRESS_ITERS; itern++) { + // Validate hipMemset3D data consistency in multiple iters + for (int i = 0; i < numGpu; i++) { + for (int j = 0; j < numGpu; j++) { + HIP_CHECK(hipDeviceCanAccessPeer(&hasPeerAccess, i, j)); + if (!hasPeerAccess) { + // Skip and continue if no peer access + continue; + } + + HIP_CHECK(hipSetDevice(i)); + devpPtr = devPitchedPtrlist[j]; + HIP_CHECK(hipDeviceEnablePeerAccess(j, 0)); + HIP_CHECK(hipMemset3D(devpPtr, 0, extent)); + + if (bAsync) { + hipStream_t stream; + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMemset3DAsync(devpPtr, memsetval, extent, stream)); + HIP_CHECK(hipStreamSynchronize(stream)); + HIP_CHECK(hipStreamDestroy(stream)); + } else { + HIP_CHECK(hipMemset3D(devpPtr, memsetval, extent)); + } + + myparms.srcPtr = devpPtr; + memset(A_h, 0, sizeElements); + HIP_CHECK(hipMemcpy3D(&myparms)); + + for (size_t indx = 0; indx < elements; indx++) { + if (A_h[indx] != memsetval) { + testPassed = false; + printf("RegressIter : mismatch at index:%d computed:%02x, " + "memsetval:%02x\n", static_cast(indx), + static_cast(A_h[indx]), static_cast(memsetval)); + break; + } + } + } + } + } + + for (int j = 0; j < numGpu; j++) { + HIP_CHECK(hipFree(devPitchedPtrlist[j].ptr)); + } + + free(A_h); + return testPassed; +} + +/** + * Perform regression of hipMemset3D api with device memory allocated + * on different gpus. + */ +TEST_CASE("Unit_hipMemset3D_RegressInLoop") { + bool TestPassed = false; + + TestPassed = loopRegression(0); + REQUIRE(TestPassed == true); +} + +/** + * Perform regression of hipMemset3DAsync api with device memory allocated + * on different gpus. + */ +TEST_CASE("Unit_hipMemset3DAsync_RegressInLoop") { + bool TestPassed = false; + + TestPassed = loopRegression(1); + REQUIRE(TestPassed == true); +} + +/** + * Async commands queued concurrently and executed + */ +TEST_CASE("Unit_hipMemset3DAsync_ConcurrencyMthread") { + char *A_h; + constexpr int memsetval = 1, testval = 2; + constexpr size_t numH = 256, numW = 100, depth = 10; + size_t width = numW * sizeof(char); + hipExtent extent = make_hipExtent(width, numH, depth); + size_t sizeElements = width * numH * depth; + size_t elements = numW* numH* depth; + hipPitchedPtr devpPtr; + hipStream_t stream; + + HIP_CHECK(hipStreamCreate(&stream)); + HIP_CHECK(hipMalloc3D(&devpPtr, extent)); + + A_h = reinterpret_cast(malloc(sizeElements)); + REQUIRE(A_h != nullptr); + memset(A_h, 0, sizeElements); + + // Populate hipMemcpy3D parameters + hipMemcpy3DParms myparms{}; + myparms.srcPos = make_hipPos(0, 0, 0); + myparms.srcPtr = devpPtr; + myparms.dstPos = make_hipPos(0, 0, 0); + myparms.dstPtr = make_hipPitchedPtr(A_h, width, numW, numH); + myparms.extent = extent; + +#if HT_NVIDIA + myparms.kind = hipMemcpyKindToCudaMemcpyKind(hipMemcpyDeviceToHost); +#else + myparms.kind = hipMemcpyDeviceToHost; +#endif + + std::vector threadlist; + + // Queue cmds concurrently from multiple threads on same stream + for (int i = 0; i < MAX_THREADS; i++) { + threadlist.push_back(std::thread(threadFunc, stream, devpPtr, memsetval, + testval, extent, myparms)); + } + + for (auto &t : threadlist) { + t.join(); + } + + HIP_CHECK(hipStreamSynchronize(stream)); + + for (size_t k = 0 ; k < elements ; k++) { + if (A_h[k] != testval) { + CAPTURE(A_h[k], testval, k); + REQUIRE(false); + } + } + + HIP_CHECK(hipStreamDestroy(stream)); + free(A_h); + HIP_CHECK(hipFree(devpPtr.ptr)); +} From e31d5bd8e0e1589787ed93b4445053305ea178f2 Mon Sep 17 00:00:00 2001 From: Maneesh Gupta Date: Mon, 20 Sep 2021 09:41:45 +0530 Subject: [PATCH 6/9] Fix catch2 unit test build failure Incorrect resolution of merge conflict resulted in not updating tests/catch/unit/memory/CMakeLists.txt correctly --- tests/catch/unit/memory/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/catch/unit/memory/CMakeLists.txt b/tests/catch/unit/memory/CMakeLists.txt index 61571884a1..a4619410b6 100644 --- a/tests/catch/unit/memory/CMakeLists.txt +++ b/tests/catch/unit/memory/CMakeLists.txt @@ -32,7 +32,6 @@ set(TEST_SRC hipHostGetFlags.cc hipMemoryAllocateCoherent.cc hipMallocManaged_MultiScenario.cc - hipManagedKeyword.cc hipMemsetInvalidPtr.cc hipMemset.cc hipMemsetAsyncMultiThread.cc @@ -77,7 +76,6 @@ set(TEST_SRC hipHostGetFlags.cc hipMemoryAllocateCoherent.cc hipMallocManaged_MultiScenario.cc - hipManagedKeyword.cc hipMemsetInvalidPtr.cc hipMemset.cc hipMemsetAsyncMultiThread.cc From 61ae7884a418761cc1fefd4161712fc23d48defd Mon Sep 17 00:00:00 2001 From: Maneesh Gupta Date: Mon, 20 Sep 2021 10:47:52 +0530 Subject: [PATCH 7/9] Revert "SWDEV-289405 - [catch2][dtest][module] Migration of Module files to CATCH2 framework (#2351)" (#2354) This reverts commit 8763c8c2ad985cbff41189cd42370e62355688f7. --- tests/catch/hipTestMain/CMakeLists.txt | 4 +- tests/catch/include/hip_test_common.hh | 61 +- tests/catch/include/hip_test_helper.hh | 2 +- tests/catch/include/hip_test_kernels.hh | 31 +- tests/catch/stress/CMakeLists.txt | 1 - tests/catch/stress/memory/CMakeLists.txt | 1 - .../memory/hipMemcpyBoundaryOffsetCheck.cc | 344 ----------- tests/catch/stress/module/CMakeLists.txt | 19 - .../hipExtModuleLaunchKernel_CornerTest.cc | 86 --- .../hipModuleLaunchKernel_CornerTests.cc | 90 --- tests/catch/stress/module/kernels.cc | 28 - tests/catch/unit/CMakeLists.txt | 1 - tests/catch/unit/module/CMakeLists.txt | 51 -- .../unit/module/hipExtLaunchKernelGGL.cc | 129 ---- .../hipExtLaunchMultiKernelMultiDevice.cc | 128 ---- .../unit/module/hipExtModuleLaunchKernel.cc | 433 -------------- .../catch/unit/module/hipFuncGetAttributes.cc | 163 ----- .../catch/unit/module/hipFuncSetAttribute.cc | 46 -- .../unit/module/hipFuncSetCacheConfig.cc | 36 -- .../unit/module/hipFuncSetSharedMemConfig.cc | 107 ---- tests/catch/unit/module/hipManagedKeyword.cc | 56 -- tests/catch/unit/module/hipModule.cc | 183 ------ tests/catch/unit/module/hipModuleGetGlobal.cc | 120 ---- .../unit/module/hipModuleLaunchKernel.cc | 246 -------- tests/catch/unit/module/hipModuleLoadData.cc | 91 --- .../hipModuleLoadDataMultThreadOnMultGPU.cc | 161 ----- .../module/hipModuleLoadDataMultThreaded.cc | 164 ----- .../unit/module/hipModuleLoadMultiThreaded.cc | 121 ---- .../unit/module/hipModuleLoadUnloadStress.cc | 93 --- tests/catch/unit/module/hipModuleNegative.cc | 274 --------- ...hipModuleOccupancyMaxPotentialBlockSize.cc | 267 --------- .../unit/module/hipModuleTexture2dDrv.cc | 561 ------------------ tests/catch/unit/module/hipModuleUnload.cc | 34 -- tests/catch/unit/module/hipOpenCLCOTest.cc | 229 ------- tests/catch/unit/module/module_kernels.cc | 167 ------ tests/catch/unit/module/opencl_add.cc | 37 -- 36 files changed, 5 insertions(+), 4560 deletions(-) delete mode 100644 tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc delete mode 100644 tests/catch/stress/module/CMakeLists.txt delete mode 100644 tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc delete mode 100644 tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc delete mode 100644 tests/catch/stress/module/kernels.cc delete mode 100644 tests/catch/unit/module/CMakeLists.txt delete mode 100755 tests/catch/unit/module/hipExtLaunchKernelGGL.cc delete mode 100644 tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc delete mode 100755 tests/catch/unit/module/hipExtModuleLaunchKernel.cc delete mode 100644 tests/catch/unit/module/hipFuncGetAttributes.cc delete mode 100644 tests/catch/unit/module/hipFuncSetAttribute.cc delete mode 100644 tests/catch/unit/module/hipFuncSetCacheConfig.cc delete mode 100644 tests/catch/unit/module/hipFuncSetSharedMemConfig.cc delete mode 100644 tests/catch/unit/module/hipManagedKeyword.cc delete mode 100755 tests/catch/unit/module/hipModule.cc delete mode 100755 tests/catch/unit/module/hipModuleGetGlobal.cc delete mode 100644 tests/catch/unit/module/hipModuleLaunchKernel.cc delete mode 100644 tests/catch/unit/module/hipModuleLoadData.cc delete mode 100644 tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc delete mode 100644 tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc delete mode 100644 tests/catch/unit/module/hipModuleLoadMultiThreaded.cc delete mode 100644 tests/catch/unit/module/hipModuleLoadUnloadStress.cc delete mode 100644 tests/catch/unit/module/hipModuleNegative.cc delete mode 100644 tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc delete mode 100755 tests/catch/unit/module/hipModuleTexture2dDrv.cc delete mode 100644 tests/catch/unit/module/hipModuleUnload.cc delete mode 100644 tests/catch/unit/module/hipOpenCLCOTest.cc delete mode 100644 tests/catch/unit/module/module_kernels.cc delete mode 100644 tests/catch/unit/module/opencl_add.cc diff --git a/tests/catch/hipTestMain/CMakeLists.txt b/tests/catch/hipTestMain/CMakeLists.txt index 7fe98c71d9..a70169efb0 100644 --- a/tests/catch/hipTestMain/CMakeLists.txt +++ b/tests/catch/hipTestMain/CMakeLists.txt @@ -15,7 +15,6 @@ target_link_libraries(UnitTests PRIVATE UnitDeviceTests EventTest OccupancyTest DeviceTest - ModuleTest RTC stdc++fs) @@ -37,7 +36,6 @@ target_link_libraries(ABMTests PRIVATE ABMAddKernels stdc++fs) catch_discover_tests(ABMTests PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST") -add_dependencies(UnitTests module_kernels.code) add_dependencies(build_tests UnitTests ABMTests) @@ -65,7 +63,7 @@ else() target_compile_options(StressTest PUBLIC -std=c++17) endif() if(HIP_PLATFORM MATCHES "amd") -target_link_libraries(StressTest PRIVATE printf stream module) +target_link_libraries(StressTest PRIVATE printf stream) endif() target_link_libraries(StressTest PRIVATE memory stdc++fs) add_dependencies(build_stress_test StressTest) diff --git a/tests/catch/include/hip_test_common.hh b/tests/catch/include/hip_test_common.hh index 9ffe839739..9107740333 100644 --- a/tests/catch/include/hip_test_common.hh +++ b/tests/catch/include/hip_test_common.hh @@ -1,5 +1,6 @@ /* -Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2021 - 2021 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 @@ -22,13 +23,6 @@ THE SOFTWARE. #pragma once #include "hip_test_context.hh" #include -#ifdef __linux__ -#include -#elif defined(_WIN32) -#include -#endif - - #define HIP_PRINT_STATUS(status) INFO(hipGetErrorName(status) << " at line: " << __LINE__); @@ -78,27 +72,6 @@ THE SOFTWARE. } -#if HT_NVIDIA -#define CTX_CREATE() \ - hipCtx_t context;\ - initHipCtx(&context); -#define CTX_DESTROY() HIPCHECK(hipCtxDestroy(context)); -#define ARRAY_DESTROY(array) HIPCHECK(hipArrayDestroy(array)); -#define HIP_TEX_REFERENCE hipTexRef -#define HIP_ARRAY hiparray -static void initHipCtx(hipCtx_t *pcontext) { - HIPCHECK(hipInit(0)); - hipDevice_t device; - HIPCHECK(hipDeviceGet(&device, 0)); - HIPCHECK(hipCtxCreate(pcontext, 0, device)); -} -#else -#define CTX_CREATE() -#define CTX_DESTROY() -#define ARRAY_DESTROY(array) HIPCHECK(hipFreeArray(array)); -#define HIP_TEX_REFERENCE textureReference* -#define HIP_ARRAY hipArray* -#endif // Utility Functions namespace HipTest { @@ -131,34 +104,4 @@ static inline unsigned setNumBlocks(unsigned blocksPerCU, unsigned threadsPerBlo return blocks; } -// Get Free Memory from the system -static size_t getMemoryAmount() { -#if __linux__ - struct sysinfo info; - sysinfo(&info); - return info.freeram / (1024 * 1024); // MB -#elif defined(_WIN32) - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - return (statex.ullAvailPhys / (1024 * 1024)); // MB -#endif -} - -static inline size_t getHostThreadCount(const size_t memPerThread = 200, const size_t maxThreads = 0) { - if (memPerThread == 0) return 0; - auto memAmount = getMemoryAmount(); - const auto processor_count = std::thread::hardware_concurrency(); - if (processor_count == 0 || memAmount == 0) return 0; - size_t thread_count = 0; - if ((processor_count * memPerThread) < memAmount) - thread_count = processor_count; - else - thread_count = reinterpret_cast(memAmount / memPerThread); - if (maxThreads > 0) { - return (thread_count > maxThreads) ? maxThreads : thread_count; - } - return thread_count; -} - } diff --git a/tests/catch/include/hip_test_helper.hh b/tests/catch/include/hip_test_helper.hh index 0aec8bac00..0ea01021e3 100644 --- a/tests/catch/include/hip_test_helper.hh +++ b/tests/catch/include/hip_test_helper.hh @@ -1,5 +1,5 @@ /* -Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2021 - 2021 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 diff --git a/tests/catch/include/hip_test_kernels.hh b/tests/catch/include/hip_test_kernels.hh index 3805b4cbbc..04b00b5ad3 100644 --- a/tests/catch/include/hip_test_kernels.hh +++ b/tests/catch/include/hip_test_kernels.hh @@ -1,5 +1,5 @@ /* -Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2021 - 2021 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 @@ -72,35 +72,6 @@ __global__ void addCountReverse(const T* A_d, T* C_d, int64_t NELEM, int count) } } -template -__device__ void waitKernel(uint64_t wait_sec, T clockrate) { - uint64_t start = clock64()/clockrate, cur; - do { cur = clock64()/clockrate-start;}while (cur < (wait_sec*1000)); -} - -template -__global__ void TwoSecKernel_GlobalVar(int globalvar, int clockrate) { - if (globalvar == 0x2222) { - globalvar = 0x3333; - } - waitKernel(2, clockrate); - if (globalvar != 0x3333) { - globalvar = 0x5555; - } -} - -template -__global__ void FourSecKernel_GlobalVar(int globalvar, int clockrate) { - if (globalvar == 1) { - globalvar = 0x2222; - } - waitKernel(4, clockrate); - if (globalvar == 0x2222) { - globalvar = 0x4444; - } -} - - template __global__ void memsetReverse(T* C_d, T val, int64_t NELEM) { size_t offset = (blockIdx.x * blockDim.x + threadIdx.x); size_t stride = blockDim.x * gridDim.x; diff --git a/tests/catch/stress/CMakeLists.txt b/tests/catch/stress/CMakeLists.txt index 04038e0b8a..00e12f2c2c 100644 --- a/tests/catch/stress/CMakeLists.txt +++ b/tests/catch/stress/CMakeLists.txt @@ -1,5 +1,4 @@ add_subdirectory(memory) -add_subdirectory(module) if(HIP_PLATFORM MATCHES "amd") add_subdirectory(printf) add_subdirectory(stream) diff --git a/tests/catch/stress/memory/CMakeLists.txt b/tests/catch/stress/memory/CMakeLists.txt index 4338216fad..5afd69ee11 100644 --- a/tests/catch/stress/memory/CMakeLists.txt +++ b/tests/catch/stress/memory/CMakeLists.txt @@ -2,7 +2,6 @@ set(TEST_SRC memcpy.cc hipMemcpyMThreadMSize.cc - hipMemcpyBoundaryOffsetCheck.cc ) # Create shared lib of all tests diff --git a/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc b/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc deleted file mode 100644 index b81e575bcf..0000000000 --- a/tests/catch/stress/memory/hipMemcpyBoundaryOffsetCheck.cc +++ /dev/null @@ -1,344 +0,0 @@ -/* -Copyright (c) 2021 - present 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 testcase verifies following scenarios -3. Boundary checks with different sizes -5. device offset scenario -*/ -#include -#include -#include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#else -#include "sys/types.h" -#include "sys/sysinfo.h" -#endif -static constexpr auto NUM_ELM{4*1024 * 1024}; -template -class DeviceMemory { - public: - explicit DeviceMemory(size_t numElements); - DeviceMemory() = delete; - ~DeviceMemory(); - T* A_d() const { return _A_d + _offset; } - T* B_d() const { return _B_d + _offset; } - T* C_d() const { return _C_d + _offset; } - T* C_dd() const { return _C_dd + _offset; } - size_t maxNumElements() const { return _maxNumElements; } - void offset(int offset) { _offset = offset; } - int offset() const { return _offset; } - private: - T* _A_d; - T* _B_d; - T* _C_d; - T* _C_dd; - size_t _maxNumElements; - int _offset; -}; -template -DeviceMemory::DeviceMemory(size_t numElements) : - _maxNumElements(numElements), _offset(0) { - T** np = nullptr; - HipTest::initArrays(&_A_d, &_B_d, &_C_d, np, np, np, numElements, 0); - size_t sizeElements = numElements * sizeof(T); - HIP_CHECK(hipMalloc(&_C_dd, sizeElements)); -} -template -DeviceMemory::~DeviceMemory() { - T* np = nullptr; - HipTest::freeArrays(_A_d, _B_d, _C_d, np, np, np, 0); - HIP_CHECK(hipFree(_C_dd)); - _C_dd = NULL; -} -template -class HostMemory { - public: - HostMemory(size_t numElements, bool usePinnedHost); - HostMemory() = delete; - void reset(size_t numElements, bool full = false); - ~HostMemory(); - T* A_h() const { return _A_h + _offset; } - T* B_h() const { return _B_h + _offset; } - T* C_h() const { return _C_h + _offset; } - size_t maxNumElements() const { return _maxNumElements; } - void offset(int offset) { _offset = offset; } - int offset() const { return _offset; } - // Host arrays, secondary copy - T* A_hh; - T* B_hh; - bool _usePinnedHost; - private: - size_t _maxNumElements; - int _offset; - // Host arrays - T* _A_h; - T* _B_h; - T* _C_h; -}; - template -HostMemory::HostMemory(size_t numElements, bool usePinnedHost) - : _usePinnedHost(usePinnedHost), _maxNumElements(numElements), _offset(0) { - T** np = nullptr; - HipTest::initArrays(np, np, np, &_A_h, &_B_h, &_C_h, - numElements, usePinnedHost); - A_hh = NULL; - B_hh = NULL; - size_t sizeElements = numElements * sizeof(T); - if (usePinnedHost) { - HIP_CHECK(hipHostMalloc(reinterpret_cast(&A_hh), sizeElements, - hipHostMallocDefault)); - HIP_CHECK(hipHostMalloc(reinterpret_cast(&B_hh), sizeElements, - hipHostMallocDefault)); - } else { - A_hh = reinterpret_cast(malloc(sizeElements)); - B_hh = reinterpret_cast(malloc(sizeElements)); - } - } -template -void HostMemory::reset(size_t numElements, bool full) { - // Initialize the host data: - for (size_t i = 0; i < numElements; i++) { - (A_hh)[i] = 1097.0 + i; - (B_hh)[i] = 1492.0 + i; // Phi - if (full) { - (_A_h)[i] = 3.146f + i; // Pi - (_B_h)[i] = 1.618f + i; // Phi - } - } -} -template -HostMemory::~HostMemory() { - HipTest::freeArraysForHost(_A_h, _B_h, _C_h, _usePinnedHost); - if (_usePinnedHost) { - HIP_CHECK(hipHostFree(A_hh)); - HIP_CHECK(hipHostFree(B_hh)); - } else { - free(A_hh); - free(B_hh); - } -} -#ifdef _WIN32 -void memcpytest2_get_host_memory(size_t *free, size_t *total) { - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - // Windows doesn't allow allocating more than half of system memory to the gpu - // Since the runtime also needs space for its internal allocations, - // we should not try to allocate more than 40% of reported system memory, - // otherwise we can run into OOM issues. - *free = static_cast(0.4 * status.ullAvailPhys); - *total = static_cast(0.4 * status.ullTotalPhys); -} -#else -struct sysinfo memInfo; -void memcpytest2_get_host_memory(size_t *free, size_t *total) { - sysinfo(&memInfo); - uint64_t freePhysMem = memInfo.freeram; - freePhysMem *= memInfo.mem_unit; - *free = freePhysMem; - uint64_t totalPhysMem = memInfo.totalram; - totalPhysMem *= memInfo.mem_unit; - *total = totalPhysMem; -} -#endif -//--- -// Test many different kinds of memory copies. -// The subroutine allocates memory , copies to device, runs a vector -// add kernel, copies back, and -// checks the result. -// -// IN: numElements controls the number of elements used for allocations. -// IN: usePinnedHost : If true, allocate host with hipHostMalloc and is pinned -// else allocate host -// memory with malloc. IN: useHostToHost : If true, add an extra -// host-to-host copy. IN: -// useDeviceToDevice : If true, add an extra deviceto-device copy after -// result is produced. IN: -// useMemkindDefault : If true, use memkinddefault -// (runtime figures out direction). if false, use -// explicit memcpy direction. -// -template -void memcpytest2(DeviceMemory* dmem, HostMemory* hmem, - size_t numElements, bool useHostToHost, - bool useDeviceToDevice, bool useMemkindDefault) { - size_t sizeElements = numElements * sizeof(T); - hmem->reset(numElements); - assert(numElements <= dmem->maxNumElements()); - assert(numElements <= hmem->maxNumElements()); - if (useHostToHost) { - // Do some extra host-to-host copies here to mix things up: - HIP_CHECK(hipMemcpy(hmem->A_hh, hmem->A_h(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToHost)); - HIP_CHECK(hipMemcpy(hmem->B_hh, hmem->B_h(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToHost)); - HIP_CHECK(hipMemcpy(dmem->A_d(), hmem->A_hh, sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); - HIP_CHECK(hipMemcpy(dmem->B_d(), hmem->B_hh, sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); - } else { - HIP_CHECK(hipMemcpy(dmem->A_d(), hmem->A_h(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); - HIP_CHECK(hipMemcpy(dmem->B_d(), hmem->B_h(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyHostToDevice)); - } - hipLaunchKernelGGL(HipTest::vectorADD, dim3(1), dim3(1), 0, 0, - static_cast(dmem->A_d()), static_cast(dmem->B_d()), - dmem->C_d(), numElements); - if (useDeviceToDevice) { - // Do an extra device-to-device copy here to mix things up: - HIP_CHECK(hipMemcpy(dmem->C_dd(), dmem->C_d(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToDevice)); - // Destroy the original dmem->C_d(): - HIP_CHECK(hipMemset(dmem->C_d(), 0x5A, sizeElements)); - HIP_CHECK(hipMemcpy(hmem->C_h(), dmem->C_dd(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToHost)); - } else { - HIP_CHECK(hipMemcpy(hmem->C_h(), dmem->C_d(), sizeElements, - useMemkindDefault ? hipMemcpyDefault : hipMemcpyDeviceToHost)); - } - HIP_CHECK(hipDeviceSynchronize()); - HipTest::checkVectorADD(hmem->A_h(), hmem->B_h(), hmem->C_h(), numElements); -} -// Try all the 16 possible combinations to memcpytest2 - usePinnedHost, -// useHostToHost, -// useDeviceToDevice, useMemkindDefault -template -void memcpytest2_for_type(size_t numElements) { - DeviceMemory memD(numElements); - HostMemory memU(numElements, 0 /*usePinnedHost*/); - HostMemory memP(numElements, 1 /*usePinnedHost*/); - for (int usePinnedHost = 0; usePinnedHost <= 1; usePinnedHost++) { - for (int useHostToHost = 0; useHostToHost <= 1; useHostToHost++) { - for (int useDeviceToDevice = 0; useDeviceToDevice <= 1; - useDeviceToDevice++) { - for (int useMemkindDefault = 0; useMemkindDefault <= 1; - useMemkindDefault++) { - memcpytest2(&memD, usePinnedHost ? &memP : &memU, - numElements, useHostToHost, - useDeviceToDevice, useMemkindDefault); - } - } - } - } -} -// Try many different sizes to memory copy. -template -void memcpytest2_sizes(size_t maxElem = 0) { - int deviceId; - HIP_CHECK(hipGetDevice(&deviceId)); - size_t free, total, freeCPU, totalCPU; - HIP_CHECK(hipMemGetInfo(&free, &total)); - memcpytest2_get_host_memory(&freeCPU, &totalCPU); - if (maxElem == 0) { - // Use lesser maxElem if not enough host memory available - size_t maxElemGPU = free / sizeof(T) / 8; - size_t maxElemCPU = freeCPU / sizeof(T) / 8; - maxElem = maxElemGPU < maxElemCPU ? maxElemGPU : maxElemCPU; - } - HIP_CHECK(hipDeviceReset()); - DeviceMemory memD(maxElem); - HostMemory memU(maxElem, 0 /*usePinnedHost*/); - HostMemory memP(maxElem, 1 /*usePinnedHost*/); - for (size_t elem = 1; elem <= maxElem; elem *= 2) { - memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host - memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host - } -} -// Try many different sizes to memory copy. -template -void memcpytest2_offsets(size_t maxElem, bool devOffsets, bool hostOffsets) { - int deviceId; - HIP_CHECK(hipGetDevice(&deviceId)); - size_t free, total; - HIP_CHECK(hipMemGetInfo(&free, &total)); - HIP_CHECK(hipDeviceReset()); - DeviceMemory memD(maxElem); - HostMemory memU(maxElem, 0 /*usePinnedHost*/); - HostMemory memP(maxElem, 1 /*usePinnedHost*/); - size_t elem = maxElem / 2; - for (size_t offset = 0; offset < 512; offset++) { - assert(elem + offset < maxElem); - if (devOffsets) { - memD.offset(offset); - } - if (hostOffsets) { - memU.offset(offset); - memP.offset(offset); - } - memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host - memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host - } - for (size_t offset = 512; offset < elem; offset *= 2) { - assert(elem + offset < maxElem); - if (devOffsets) { - memD.offset(offset); - } - if (hostOffsets) { - memU.offset(offset); - memP.offset(offset); - } - memcpytest2(&memD, &memU, elem, 1, 1, 0); // unpinned host - memcpytest2(&memD, &memP, elem, 1, 1, 0); // pinned host - } -} -// Create multiple threads to stress multi-thread locking behavior in the -// allocation/deallocation/tracking logic: -template -void multiThread_1(bool serialize, bool usePinnedHost) { - DeviceMemory memD(NUM_ELM); - HostMemory mem1(NUM_ELM, usePinnedHost); - HostMemory mem2(NUM_ELM, usePinnedHost); - std::thread t1(memcpytest2, &memD, &mem1, NUM_ELM, 0, 0, 0); - if (serialize) { - t1.join(); - } - std::thread t2(memcpytest2, &memD, &mem2, NUM_ELM, 0, 0, 0); - if (serialize) { - t2.join(); - } -} -/* -This testcase verfies the boundary checks of hipMemcpy API for different sizes -*/ -TEST_CASE("Unit_hipMemcpy_BoundaryCheck") { - size_t maxElem = 32 * 1024 * 1024; - DeviceMemory memD(maxElem); - HostMemory memU(maxElem, 0 /*usePinnedHost*/); - HostMemory memP(maxElem, 0 /*usePinnedHost*/); - memcpytest2(&memD, &memU, 32 * 1024 * 1024, 0, 0, 0); - auto sizes = GENERATE(15 * 1024 * 1024, 16 * 1024 * 1024, - 16 * 1024 * 1024 + 16 * 1024, - 16 * 1024 * 1024 + 512 * 1024, - 17 * 1024 * 1024 + 1024, - 32 * 1024 * 1024); - memcpytest2(&memD, &memP, sizes, 0, 0, 0); -} - -/* -This testcase verifies the device offsets -*/ -TEMPLATE_TEST_CASE("Unit_hipMemcpy_DeviceOffsets", "", float, double) { - HIP_CHECK(hipDeviceReset()); - size_t maxSize = 256 * 1024; - memcpytest2_offsets(maxSize, true, false); - memcpytest2_offsets(maxSize, false, true); -} diff --git a/tests/catch/stress/module/CMakeLists.txt b/tests/catch/stress/module/CMakeLists.txt deleted file mode 100644 index 17ebb212e6..0000000000 --- a/tests/catch/stress/module/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Common Tests - Test independent of all platforms -if(HIP_PLATFORM MATCHES "amd") -set(TEST_SRC - hipExtModuleLaunchKernel_CornerTest.cc - hipModuleLaunchKernel_CornerTests.cc -) -else() -set(TEST_SRC - hipModuleLaunchKernel_CornerTests.cc -) -endif() - -add_custom_target(kernels.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${HIP_COMMON_DIR}/tests/catch/stress/module/kernels.cc -o ${HIP_PATH}/catch/hipTestMain/kernels.code -I${HIP_PATH}/include/ -I${HIP_COMMON_DIR}/tests/catch/include) - -# Create shared lib of all tests -add_library(module SHARED EXCLUDE_FROM_ALL ${TEST_SRC}) - -# Add dependency on build_tests to build it on this custom target -add_dependencies(build_stress_test module kernels.code) diff --git a/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc b/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc deleted file mode 100644 index 05c17c7b9b..0000000000 --- a/tests/catch/stress/module/hipExtModuleLaunchKernel_CornerTest.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright (c) 2021 - present 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 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR - IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - -/* -Test Scenario -hipExtModuleLaunchKernel API verifying Corner Scenarios for Grid and Block dimensions -*/ - -#include "hip_test_common.hh" -#include "hip_test_kernels.hh" -#include "hip/hip_ext.h" - -#define fileName "kernels.code" -#define dummyKernel "EmptyKernel" - -struct gridblockDim { - unsigned int gridX; - unsigned int gridY; - unsigned int gridZ; - unsigned int blockX; - unsigned int blockY; - unsigned int blockZ; -}; - -/* -This testcase verifies hipExtModuleLaunchKernel API Corner -cases -*/ -TEST_CASE("Stress_hipExtModuleLaunchKernel_CornerCases") { - hipModule_t Module; - hipFunction_t DummyKernel; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); - constexpr auto gridblocksize{6}; - struct { - } args; - hipStream_t stream; - HIP_CHECK(hipStreamCreate(&stream)); - size_t size = sizeof(args); - void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - unsigned int maxblockX = deviceProp.maxThreadsDim[0]; - unsigned int maxblockY = deviceProp.maxThreadsDim[1]; - unsigned int maxblockZ = deviceProp.maxThreadsDim[2]; - struct gridblockDim test[gridblocksize] = {{1, 1, 1, maxblockX, 1, 1}, - {1, 1, 1, 1, maxblockY, 1}, - {1, 1, 1, 1, 1, maxblockZ}, - {UINT32_MAX, 1, 1, 1, 1, 1}, - {1, UINT32_MAX, 1, 1, 1, 1}, - {1, 1, UINT32_MAX, 1, 1, 1}}; - - // Launching kernel with corner cases in grid and block dimensions - for (int i = 0; i < gridblocksize; i++) { - HIP_CHECK(hipExtModuleLaunchKernel(DummyKernel, - test[i].gridX, - test[i].gridY, - test[i].gridZ, - test[i].blockX, - test[i].blockY, - test[i].blockZ, - 0, - stream, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0)); - } - HIP_CHECK(hipStreamDestroy(stream)); -} diff --git a/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc b/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc deleted file mode 100644 index f7bd866ceb..0000000000 --- a/tests/catch/stress/module/hipModuleLaunchKernel_CornerTests.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (c) 2021 - present 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 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR - IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - -/* -Test Scenario -hipModuleLaunchKernel API verifying Corner Scenarios for Grid and Block dimensions -*/ - -#include "hip_test_common.hh" -#include "hip_test_kernels.hh" -#include "hip/hip_ext.h" - -#define fileName "kernels.code" -#define dummyKernel "EmptyKernel" - -struct gridblockDim { - unsigned int gridX; - unsigned int gridY; - unsigned int gridZ; - unsigned int blockX; - unsigned int blockY; - unsigned int blockZ; -}; - -/* -This testcase verifies hipModuleLaunchKernel API Corner -cases -*/ -TEST_CASE("Stress_hipModuleLaunchKernel_CornerCases") { - HIP_CHECK(hipSetDevice(0)); - hipStream_t stream1; - CTX_CREATE() - hipModule_t Module; - hipFunction_t DummyKernel; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); - HIP_CHECK(hipStreamCreate(&stream1)); - - // Passing Max int value to block dimensions - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - unsigned int maxblockX = deviceProp.maxThreadsDim[0]; - unsigned int maxblockY = deviceProp.maxThreadsDim[1]; - unsigned int maxblockZ = deviceProp.maxThreadsDim[2]; -#if HT_NVIDIA - unsigned int maxgridX = deviceProp.maxGridSize[0]; - unsigned int maxgridY = deviceProp.maxGridSize[1]; - unsigned int maxgridZ = deviceProp.maxGridSize[2]; -#else - unsigned int maxgridX = UINT32_MAX; - unsigned int maxgridY = UINT32_MAX; - unsigned int maxgridZ = UINT32_MAX; -#endif - struct gridblockDim test[6] = {{1, 1, 1, maxblockX, 1, 1}, - {1, 1, 1, 1, maxblockY, 1}, - {1, 1, 1, 1, 1, maxblockZ}, - {maxgridX, 1, 1, 1, 1, 1}, - {1, maxgridY, 1, 1, 1, 1}, - {1, 1, maxgridZ, 1, 1, 1}}; - for (int i = 0; i < 6; i++) { - HIP_CHECK(hipModuleLaunchKernel(DummyKernel, - test[i].gridX, - test[i].gridY, - test[i].gridZ, - test[i].blockX, - test[i].blockY, - test[i].blockZ, - 0, - stream1, NULL, NULL)); - } - HIP_CHECK(hipStreamDestroy(stream1)); - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY(); -} diff --git a/tests/catch/stress/module/kernels.cc b/tests/catch/stress/module/kernels.cc deleted file mode 100644 index 5a980c40e7..0000000000 --- a/tests/catch/stress/module/kernels.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright (c) 2021 - present 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -#include -#include "hip/hip_runtime.h" - -extern "C" __global__ void EmptyKernel() { -} - diff --git a/tests/catch/unit/CMakeLists.txt b/tests/catch/unit/CMakeLists.txt index 0d19d6d82b..f0ae8b6b93 100644 --- a/tests/catch/unit/CMakeLists.txt +++ b/tests/catch/unit/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(module) add_subdirectory(memory) add_subdirectory(deviceLib) add_subdirectory(stream) diff --git a/tests/catch/unit/module/CMakeLists.txt b/tests/catch/unit/module/CMakeLists.txt deleted file mode 100644 index 7e5d6aeaf6..0000000000 --- a/tests/catch/unit/module/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -# Common Tests - Test independent of all platforms -if(HIP_PLATFORM MATCHES "amd") -set(TEST_SRC -hipExtLaunchKernelGGL.cc -hipExtModuleLaunchKernel.cc -hipExtLaunchMultiKernelMultiDevice.cc -hipModuleLaunchKernel.cc -hipFuncSetCacheConfig.cc -hipModuleUnload.cc -hipFuncSetAttribute.cc -hipModuleLoadData.cc -hipFuncSetSharedMemConfig.cc -hipManagedKeyword.cc -hipModuleGetGlobal.cc -hipFuncGetAttributes.cc -hipModule.cc -hipModuleLoadDataMultThreadOnMultGPU.cc -hipModuleLoadDataMultThreaded.cc -hipModuleLoadMultiThreaded.cc -hipModuleLoadUnloadStress.cc -hipModuleNegative.cc -hipModuleOccupancyMaxPotentialBlockSize.cc -hipModuleTexture2dDrv.cc -hipOpenCLCOTest.cc -) -else() -set(TEST_SRC -hipModuleLaunchKernel.cc -hipFuncSetCacheConfig.cc -hipModuleUnload.cc -hipFuncSetAttribute.cc -hipModuleLoadData.cc -hipFuncSetSharedMemConfig.cc -hipManagedKeyword.cc -hipModuleGetGlobal.cc -hipFuncGetAttributes.cc -hipModule.cc -hipModuleLoadDataMultThreadOnMultGPU.cc -hipModuleLoadDataMultThreaded.cc -hipModuleLoadMultiThreaded.cc -hipModuleLoadUnloadStress.cc -hipModuleNegative.cc -hipModuleOccupancyMaxPotentialBlockSize.cc -) -endif() - -add_custom_target(module_kernels.code COMMAND ${CMAKE_CXX_COMPILER} --genco ${HIP_COMMON_DIR}/tests/catch/unit/module/module_kernels.cc -o ${HIP_PATH}/catch/hipTestMain/module_kernels.code -I${HIP_PATH}/include/ -I${HIP_COMMON_DIR}/tests/catch/include) -# Create shared lib of all tests -add_library(ModuleTest SHARED EXCLUDE_FROM_ALL ${TEST_SRC}) - -add_dependencies(build_tests ModuleTest module_kernels.code) diff --git a/tests/catch/unit/module/hipExtLaunchKernelGGL.cc b/tests/catch/unit/module/hipExtLaunchKernelGGL.cc deleted file mode 100755 index 9ab420679e..0000000000 --- a/tests/catch/unit/module/hipExtLaunchKernelGGL.cc +++ /dev/null @@ -1,129 +0,0 @@ -/* - Copyright (c) 2021 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 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR - IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ -/* - * Test Scenarios - 1. Verify kernel execution time of the particular kernel - 2. Verify hipExtLaunchKernelGGL API by disabling time flag in event creation - */ - -#include -#include -#include "hip/hip_ext.h" - -#define FOURSEC_KERNEL 4999 -#define TWOSEC_KERNEL 2999 - -__device__ int globalvar = 1; -__global__ void TwoSecKernel_GlobalVar(int clockrate) { - if (globalvar == 0x2222) { - globalvar = 0x3333; - } - HipTest::waitKernel(2, clockrate); - if (globalvar != 0x3333) { - globalvar = 0x5555; - } -} - -__global__ void FourSecKernel_GlobalVar(int clockrate) { - if (globalvar == 1) { - globalvar = 0x2222; - } - HipTest::waitKernel(4, clockrate); - if (globalvar == 0x2222) { - globalvar = 0x4444; - } -} - - -/* - * In this Scenario, we create events by disabling the timing flag - * We then Launch the kernel using hipExtModuleLaunchKernel by passing - * disabled events and try to fetch kernel execution time using - * hipEventElapsedTime API which would fail as the flag is disabled. - */ -TEST_CASE("Unit_hipExtLaunchKernelGGL_TimeFlagDisabled") { - hipStream_t stream; - HIP_CHECK(hipSetDevice(0)); - float time_2sec; - hipEvent_t start_event, end_event; - int clkRate = 0; - HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); - - // Event Creation and Launching kernels - HIP_CHECK(hipEventCreateWithFlags(&start_event, - hipEventDisableTiming)); - HIP_CHECK(hipEventCreateWithFlags(&end_event, - hipEventDisableTiming)); - HIP_CHECK(hipStreamCreate(&stream)); - - hipExtLaunchKernelGGL(TwoSecKernel_GlobalVar, dim3(1), dim3(1), 0, - stream, start_event, end_event, 0, clkRate); - HIP_CHECK(hipStreamSynchronize(stream)); - REQUIRE(hipEventElapsedTime(&time_2sec, start_event, end_event) - != hipSuccess); - - // Destroying the events and streams - HIP_CHECK(hipStreamDestroy(stream)); - HIP_CHECK(hipEventDestroy(start_event)); - HIP_CHECK(hipEventDestroy(end_event)); -} -/* - * Launching FourSecKernel and TwoSecKernel and then we try to - * get the event elapsed time of each kernel using the start and - * end events.The event elapsed time should return us the kernel - * execution time for that particular kernel -*/ -TEST_CASE("Unit_hipExtLaunchKernelGGL_KernelTimeExecution") { - hipStream_t stream; - HIP_CHECK(hipSetDevice(0)); - hipEvent_t start_event1, end_event1, start_event2, end_event2; - float time_4sec, time_2sec; - int clkRate = 0; - HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); - - // Creating streams and events - HIP_CHECK(hipEventCreate(&start_event1)); - HIP_CHECK(hipEventCreate(&end_event1)); - HIP_CHECK(hipEventCreate(&start_event2)); - HIP_CHECK(hipEventCreate(&end_event2)); - HIP_CHECK(hipStreamCreate(&stream)); - - // Launching 4sec and 2sec kernels - hipExtLaunchKernelGGL(FourSecKernel_GlobalVar, dim3(1), dim3(1), 0, - stream, start_event1, end_event1, 0, clkRate); - hipExtLaunchKernelGGL(TwoSecKernel_GlobalVar, dim3(1), dim3(1), 0, - stream, start_event2, end_event2, 0, clkRate); - HIP_CHECK(hipStreamSynchronize(stream)); - - HIP_CHECK(hipEventElapsedTime(&time_4sec, start_event1, end_event1)); - HIP_CHECK(hipEventElapsedTime(&time_2sec, start_event2, end_event2)); - - INFO("Expected Vs Actual: Kernel1-<" << FOURSEC_KERNEL << "Vs" << time_4sec - << "Kernel2-<" << TWOSEC_KERNEL << "Vs" << time_2sec); - // Verifying the kernel execution time - REQUIRE(time_4sec < static_cast(FOURSEC_KERNEL)); - REQUIRE(time_2sec < static_cast(TWOSEC_KERNEL)); - - // Destroying streams and events - HIP_CHECK(hipStreamDestroy(stream)); - HIP_CHECK(hipEventDestroy(start_event1)); - HIP_CHECK(hipEventDestroy(end_event1)); - HIP_CHECK(hipEventDestroy(start_event2)); - HIP_CHECK(hipEventDestroy(end_event2)); -} diff --git a/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc b/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc deleted file mode 100644 index d83c425b3d..0000000000 --- a/tests/catch/unit/module/hipExtLaunchMultiKernelMultiDevice.cc +++ /dev/null @@ -1,128 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 testfile verifies the basic functionality of - hipExtLaunchMultiKernelMultiDevice API. - It can be tested on single GPU or multi GPUs. -*/ - - -#include -#include -#include "hip/hip_runtime.h" - -#define MAX_GPUS 8 -#define NUM_KERNEL_ARGS 3 - -/* -This testcase verifies hipExtLaunchMultiKernelMultiDevice API for different -datatypes where -1. Intitialize device variables -2. Initializing hipLaunchParams structure to pass it to - hipExtLaunchMultiKernelMultiDevice API -3. Launches vector_square kernel which performs square of the variable -4. Validates the result with the square of variable. -*/ - -TEMPLATE_TEST_CASE("Unit_hipExtLaunchMultiKernelMultiDevice_Basic", "", int - , float, double) { - TestType *A_d[MAX_GPUS], *C_d[MAX_GPUS]; - TestType *A_h, *C_h; - size_t N = 1000000; - size_t Nbytes = N * sizeof(TestType); - int nGpu = 0; - - HIP_CHECK(hipGetDeviceCount(&nGpu)); - if (nGpu < 1) { - SUCCEED("info: didn't find any GPU! Skipping the testcase"); - } else { - if (nGpu > MAX_GPUS) { - nGpu = MAX_GPUS; - } - HipTest::initArrays(nullptr, nullptr, nullptr, - &A_h, nullptr, &C_h, N, false); - const unsigned blocks = 512; - const unsigned threadsPerBlock = 256; - - // Allocating and initializing device variables - hipStream_t stream[MAX_GPUS]; - for (int i = 0; i < nGpu; i++) { - HIP_CHECK(hipSetDevice(i)); - HIP_CHECK(hipStreamCreateWithFlags(&stream[i], hipStreamNonBlocking)); - hipDeviceProp_t props; - HIP_CHECK(hipGetDeviceProperties(&props, i/*deviceID*/)); - INFO("Running on bus 0x" << props.pciBusID << " " << props.name); - INFO("Allocate device mem " << 2*Nbytes/1024.0/1024.0); - HIP_CHECK(hipMalloc(&A_d[i], Nbytes)); - HIP_CHECK(hipMalloc(&C_d[i], Nbytes)); - HIP_CHECK(hipMemcpy(A_d[i], A_h, Nbytes, hipMemcpyHostToDevice)); - } - - hipLaunchParams *launchParamsList = reinterpret_cast( - malloc(sizeof(hipLaunchParams)*nGpu)); - void *args[MAX_GPUS * NUM_KERNEL_ARGS]; - - // Intializing the hipLaunchParams structure with device variables - // ,kernel and launching hipExtLaunchMultiKernelMultiDevice API - for (int i = 0; i < nGpu; i++) { - args[i * NUM_KERNEL_ARGS] = &A_d[i]; - args[i * NUM_KERNEL_ARGS + 1] = &C_d[i]; - args[i * NUM_KERNEL_ARGS + 2] = &N; - launchParamsList[i].func = - reinterpret_cast(HipTest::vector_square); - launchParamsList[i].gridDim = dim3(blocks); - launchParamsList[i].blockDim = dim3(threadsPerBlock); - launchParamsList[i].sharedMem = 0; - launchParamsList[i].stream = stream[i]; - launchParamsList[i].args = args + i * NUM_KERNEL_ARGS; - } - - hipExtLaunchMultiKernelMultiDevice(launchParamsList, nGpu, 0); - - // Validating the result - for (int j = 0; j < nGpu; j++) { - hipStreamSynchronize(stream[j]); - hipDeviceProp_t props; - HIP_CHECK(hipGetDeviceProperties(&props, j/*deviceID*/)); - INFO("Checking result on bus " << props.pciBusID << props.name); - - HIP_CHECK(hipSetDevice(j)); - HIP_CHECK(hipMemcpy(C_h, C_d[j], Nbytes, hipMemcpyDeviceToHost)); - - for (size_t i = 0; i < N; i++) { - if (C_h[i] != A_h[i] * A_h[i]) { - INFO("validation failed " << C_h[i] << A_h[i]*A_h[i]); - REQUIRE(false); - } - } - } - - // DeAllocating memory - HipTest::freeArrays(nullptr, nullptr, nullptr, - A_h, nullptr, C_h, false); - for (int j = 0; j < nGpu; j++) { - HIP_CHECK(hipFree(A_d[j])); - HIP_CHECK(hipFree(C_d[j])); - HIP_CHECK(hipStreamDestroy(stream[j])); - } - } -} diff --git a/tests/catch/unit/module/hipExtModuleLaunchKernel.cc b/tests/catch/unit/module/hipExtModuleLaunchKernel.cc deleted file mode 100755 index 45db114135..0000000000 --- a/tests/catch/unit/module/hipExtModuleLaunchKernel.cc +++ /dev/null @@ -1,433 +0,0 @@ -/* - Copyright (c) 2021 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 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR - IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ -/* Test Scenarios - 1. hipExtModuleLaunchKernel Negative Scenarios - 2. hipExtModuleLaunchKernel API verifying the kernel execution time of a particular kernel. - 3. hipExtModuleLaunchKernel API verifying the kernel execution time by disabling the time flag - 4. hipModuleLaunchKernel Work Group tests => - - (block.x * block.y * block.z) <= Work Group Size - where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - - (block.x * block.y * block.z) > Work Group Size - where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - */ - -#include -#include "hip_test_common.hh" -#include "hip_test_kernels.hh" -#include "hip/hip_ext.h" - -#define fileName "module_kernels.code" -#define matmulK "matmulK" -#define SixteenSec "SixteenSecKernel" -#define KernelandExtra "KernelandExtraParams" -#define FourSec "FourSecKernel" -#define TwoSec "TwoSecKernel" -#define globalDevVar "deviceGlobal" -#define dummyKernel "EmptyKernel" -#define FOURSEC_KERNEL 4999 -#define TWOSEC_KERNEL 2999 - -struct gridblockDim { - unsigned int gridX; - unsigned int gridY; - unsigned int gridZ; - unsigned int blockX; - unsigned int blockY; - unsigned int blockZ; -}; - -class ModuleLaunchKernel { - int N = 64; - int SIZE = N*N; - int *A, *B, *C; - hipDeviceptr_t *Ad, *Bd; - hipStream_t stream1, stream2; - hipEvent_t start_event1, end_event1, start_event2, end_event2, - start_timingDisabled, end_timingDisabled; - hipModule_t Module; - hipDeviceptr_t deviceGlobal; - hipFunction_t MultKernel, SixteenSecKernel, FourSecKernel, - TwoSecKernel, KernelandExtraParamKernel, DummyKernel; - struct { - int clockRate; - void* _Ad; - void* _Bd; - void* _Cd; - int _n; - } args1, args2; - struct { - } args3; - size_t size1; - size_t size2; - size_t size3; - size_t deviceGlobalSize; - public : - void AllocateMemory(); - void DeAllocateMemory(); - void ModuleLoad(); - void Module_Negative_tests(); - void ExtModule_Negative_tests(); - void Module_WorkGroup_Test(); - void ExtModule_KernelExecutionTime(); - void ExtModule_Disabled_Timingflag(); -}; - -void ModuleLaunchKernel::AllocateMemory() { - A = new int[N*N*sizeof(int)]; - B = new int[N*N*sizeof(int)]; - for (int i=0; i < N; i++) { - for (int j=0; j < N; j++) { - A[i*N +j] = 1; - B[i*N +j] = 1; - } - } - HIP_CHECK(hipStreamCreate(&stream1)); - HIP_CHECK(hipStreamCreate(&stream2)); - HIP_CHECK(hipMalloc(reinterpret_cast(&Ad), - SIZE*sizeof(int))); - HIP_CHECK(hipMalloc(reinterpret_cast(&Bd), - SIZE*sizeof(int))); - HIP_CHECK(hipHostMalloc(reinterpret_cast(&C), SIZE*sizeof(int))); - HIP_CHECK(hipMemcpy(Ad, A, SIZE*sizeof(int), hipMemcpyHostToDevice)); - HIP_CHECK(hipMemcpy(Bd, B, SIZE*sizeof(int), hipMemcpyHostToDevice)); - int clkRate = 0; - HIP_CHECK(hipDeviceGetAttribute(&clkRate, hipDeviceAttributeClockRate, 0)); - args1._Ad = Ad; - args1._Bd = Bd; - args1._Cd = C; - args1._n = N; - args1.clockRate = clkRate; - args2._Ad = NULL; - args2._Bd = NULL; - args2._Cd = NULL; - args2._n = 0; - args2.clockRate = clkRate; - size1 = sizeof(args1); - size2 = sizeof(args2); - size3 = sizeof(args3); - HIP_CHECK(hipEventCreate(&start_event1)); - HIP_CHECK(hipEventCreate(&end_event1)); - HIP_CHECK(hipEventCreate(&start_event2)); - HIP_CHECK(hipEventCreate(&end_event2)); - HIP_CHECK(hipEventCreateWithFlags(&start_timingDisabled, - hipEventDisableTiming)); - HIP_CHECK(hipEventCreateWithFlags(&end_timingDisabled, - hipEventDisableTiming)); -} - -void ModuleLaunchKernel::ModuleLoad() { - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&MultKernel, Module, matmulK)); - HIP_CHECK(hipModuleGetFunction(&SixteenSecKernel, Module, SixteenSec)); - HIP_CHECK(hipModuleGetFunction(&KernelandExtraParamKernel, - Module, KernelandExtra)); - HIP_CHECK(hipModuleGetFunction(&FourSecKernel, Module, FourSec)); - HIP_CHECK(hipModuleGetFunction(&TwoSecKernel, Module, TwoSec)); - HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); - HIP_CHECK(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, - Module, globalDevVar)); -} - -void ModuleLaunchKernel::DeAllocateMemory() { - HIP_CHECK(hipEventDestroy(start_event1)); - HIP_CHECK(hipEventDestroy(end_event1)); - HIP_CHECK(hipEventDestroy(start_event2)); - HIP_CHECK(hipEventDestroy(end_event2)); - HIP_CHECK(hipEventDestroy(start_timingDisabled)); - HIP_CHECK(hipEventDestroy(end_timingDisabled)); - HIP_CHECK(hipStreamDestroy(stream1)); - HIP_CHECK(hipStreamDestroy(stream2)); - delete[] A; - delete[] B; - HIP_CHECK(hipFree(Ad)); - HIP_CHECK(hipFree(Bd)); - HIP_CHECK(hipHostFree(C)); - HIP_CHECK(hipModuleUnload(Module)); -} -/* - * In this scenario,We launch the 4 sec kernel and 2 sec kernel - * and we fetch the event execution time of each kernel and it - * should not exceed the execution time of that particular kernel - */ -void ModuleLaunchKernel::ExtModule_KernelExecutionTime() { - HIP_CHECK(hipSetDevice(0)); - AllocateMemory(); - ModuleLoad(); - float time_4sec, time_2sec; - void *config2[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args2, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size2, - HIP_LAUNCH_PARAM_END}; - - // Launching kernels - HIP_CHECK(hipExtModuleLaunchKernel(FourSecKernel, 1, 1, 1, 1, 1, 1, 0, - stream1, - NULL, reinterpret_cast(&config2), - start_event1, end_event1, 0)); - HIP_CHECK(hipExtModuleLaunchKernel(TwoSecKernel, 1, 1, 1, 1, 1, 1, 0, stream1, - NULL, reinterpret_cast(&config2), - start_event2, end_event2, 0)); - HIP_CHECK(hipStreamSynchronize(stream1)); - HIP_CHECK(hipEventElapsedTime(&time_4sec, start_event1, end_event1)); - HIP_CHECK(hipEventElapsedTime(&time_2sec, start_event2, end_event2)); - - INFO("Expected Vs Actual: Kernel1-<" << FOURSEC_KERNEL << "Vs" << time_4sec - << "Kernel2-<" << TWOSEC_KERNEL << "Vs" << time_2sec); - // Verifying the kernel execution time - REQUIRE(time_4sec < static_cast(FOURSEC_KERNEL)); - REQUIRE(time_2sec < static_cast(TWOSEC_KERNEL)); - - DeAllocateMemory(); -} -/* - * In this Scenario, we create events by disabling the timing flag - * We then Launch the kernel using hipExtModuleLaunchKernel by passing - * disabled events and try to fetch kernel execution time using - * hipEventElapsedTime API which would fail as the flag is disabled. - */ -void ModuleLaunchKernel::ExtModule_Disabled_Timingflag() { - // Allocating Memory and Loading kernel - AllocateMemory(); - ModuleLoad(); - float time_2sec; - void *config2[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args2, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size2, - HIP_LAUNCH_PARAM_END}; - - // Launching Kernel - HIP_CHECK(hipExtModuleLaunchKernel(TwoSecKernel, 1, 1, 1, 1, 1, 1, 0, stream1, - NULL, reinterpret_cast(&config2), - start_timingDisabled, - end_timingDisabled, 0)); - HIP_CHECK(hipStreamSynchronize(stream1)); - - REQUIRE(hipEventElapsedTime(&time_2sec, start_timingDisabled, - end_timingDisabled) != hipSuccess); - - // DeAllocating the memory - DeAllocateMemory(); -} - -/* -This testcase verifies negative scenarios of hipExtModuleLaunchKernel API -*/ -void ModuleLaunchKernel::ExtModule_Negative_tests() { - HIP_CHECK(hipSetDevice(0)); - // Allocating memeory and loading kernel - AllocateMemory(); - ModuleLoad(); - void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args1, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, - HIP_LAUNCH_PARAM_END}; - void *params[] = {Ad}; - - SECTION("Nullptr to kernel function") { - REQUIRE(hipExtModuleLaunchKernel(nullptr, 1, 1, 1, 1, 1, 1, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Max int value to block dimensions") { - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, - std::numeric_limits::max(), - std::numeric_limits::max(), - std::numeric_limits::max(), 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Null values to all dimensions") { - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 0, 0, 0, - 0, - 0, - 0, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing 0 for x dimension") { - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 0, 1, 1, - 0, - 1, - 1, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing 0 for y dimension") { - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 0, 1, - 1, - 0, - 1, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing 0 for Z dimension") { - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 0, - 1, - 1, - 0, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing both kernel and extra params") { - REQUIRE(hipExtModuleLaunchKernel(KernelandExtraParamKernel, 1, 1, 1, 1, - 1, 1, 0, - stream1, - reinterpret_cast(¶ms), - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing both than maxthreadsperblock to block dimensions") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, - deviceProp.maxThreadsPerBlock+1, - deviceProp.maxThreadsPerBlock+1, - deviceProp.maxThreadsPerBlock+1, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Block dimension x = Max alloweed + 1") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, - deviceProp.maxThreadsDim[0]+1, - 1, - 1, 0, stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Block dimension Y = Max alloweed + 1") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, - 1, - deviceProp.maxThreadsDim[1]+1, - 1, 0, stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Block dimension Z = Max alloweed + 1") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, - 1, - 1, - deviceProp.maxThreadsDim[2]+1, 0, - stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - } - - SECTION("Passing invalid config data in extra params") { - void *config3[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, - HIP_LAUNCH_PARAM_END}; - REQUIRE(hipExtModuleLaunchKernel(MultKernel, 1, 1, 1, 1, 1, 1, 0, - stream1, NULL, - reinterpret_cast(&config3), - nullptr, nullptr, 0) != hipSuccess); - } - - DeAllocateMemory(); -} - -void ModuleLaunchKernel::Module_WorkGroup_Test() { - // Allocate memory and load modules - AllocateMemory(); - ModuleLoad(); - void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args3, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size3, - HIP_LAUNCH_PARAM_END}; - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - double cuberootVal = - cbrt(static_cast(deviceProp.maxThreadsPerBlock)); - uint32_t cuberoot_floor = floor(cuberootVal); - uint32_t cuberoot_ceil = ceil(cuberootVal); - - // Scenario: (block.x * block.y * block.z) <= Work Group Size where - // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - HIP_CHECK(hipExtModuleLaunchKernel(DummyKernel, - 1, 1, 1, - cuberoot_floor, cuberoot_floor, cuberoot_floor, - 0, stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0)); - - // Scenario: (block.x * block.y * block.z) > Work Group Size where - // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - REQUIRE(hipExtModuleLaunchKernel(DummyKernel, - 1, 1, 1, - cuberoot_ceil, cuberoot_ceil, cuberoot_ceil+1, - 0, stream1, NULL, - reinterpret_cast(&config1), - nullptr, nullptr, 0) != hipSuccess); - - // DeAllocating memory - DeAllocateMemory(); -} - -/* -This testcase verifies the negative scenarios of -hipExtModuleLaunchKernel API -*/ -TEST_CASE("Unit_hipExtModuleLaunchKernel_Negative") { - ModuleLaunchKernel Ext_obj; - Ext_obj.ExtModule_Negative_tests(); -} - -/* -This testcase verifies hipExtModuleLaunchKernel API by -disabling the timing flag -*/ -TEST_CASE("Unit_hipExtModuleLaunchKernel_TimingflagDisabled") { - ModuleLaunchKernel Ext_obj; - Ext_obj.ExtModule_Disabled_Timingflag(); -} - -/* -This testcase verifies hipExtModuleLaunchKernel API kernel -execution time -*/ -TEST_CASE("Unit_hipExtModuleLaunchKernel_KernelExecutionTime") { - ModuleLaunchKernel Ext_obj; - Ext_obj.ExtModule_KernelExecutionTime(); -} - -/* -This testcase verifies workgroup of hipExtModuleLaunchKernel API -*/ -TEST_CASE("Unit_hipExtModuleLaunchKernel_WorkGroup") { - ModuleLaunchKernel Ext_obj; - Ext_obj.Module_WorkGroup_Test(); -} diff --git a/tests/catch/unit/module/hipFuncGetAttributes.cc b/tests/catch/unit/module/hipFuncGetAttributes.cc deleted file mode 100644 index 5e21dc17c6..0000000000 --- a/tests/catch/unit/module/hipFuncGetAttributes.cc +++ /dev/null @@ -1,163 +0,0 @@ - -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ -#include -#include - -#define fileName "module_kernels.code" -#define kernel_name "hello_world" - -namespace testhipFuncGetAttributesApi { -__global__ -void fn(float* px, float* py) { - bool a[42]; - __shared__ double b[69]; - for (auto&& x : b) x = *py++; - for (auto&& x : a) x = *px++ > 0.0; - for (auto&& x : a) if (x) *--py = *--px; -} -template -__launch_bounds__(WGSIZE, 1) __global__ void kernelfn(int *x) { - __shared__ int lds[LDS]; - for (int i = 0; i < LDS; ++i) { - lds[i] = x[i]; - } - x[LDS - 1] = lds[0] / lds[LDS - 1]; -} -template bool test_Attributes_Values() { - bool TestPassed = true; - hipFuncAttributes attr{}; - hipFuncGetAttributes(&attr, - reinterpret_cast(kernelfn)); - if (attr.maxThreadsPerBlock != WGSIZE) { - TestPassed = false; - } - if (attr.sharedSizeBytes != LDS * sizeof(int)) { - TestPassed = false; - } - return TestPassed; -} -} // namespace testhipFuncGetAttributesApi -/** - * hipFuncGetAttributes and hipModuleGetFunction functional tests - * Scenario1: Validates the value of attribute "maxThreadsPerBlock" should be non zero. - * Scenario2: Validates the value of attribute - * "HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK" should be non zero. - */ -// scenario 1 -TEST_CASE("Unit_hipFuncGetAttributes_FuncTst") { - hipFuncAttributes attr{}; - auto r = hipFuncGetAttributes(&attr, - reinterpret_cast(&testhipFuncGetAttributesApi::fn)); - REQUIRE_FALSE(r != hipSuccess); - REQUIRE_FALSE(attr.maxThreadsPerBlock == 0); -} -// scenario 2 -TEST_CASE("Unit_hipFuncGetAttribute_FuncTst") { - hipModule_t Module; - int attrib_val; - CTX_CREATE() - hipFunction_t Function; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - auto r = hipFuncGetAttribute(&attrib_val, - HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, Function); - REQUIRE_FALSE(r != hipSuccess); - REQUIRE_FALSE(attrib_val == 0); - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} -/** - * hipFuncGetAttributes negative tests - * Scenario1: Validates returned error code for attr = nullptr - * Scenario2: Validates returned error code for function = nullptr - */ -TEST_CASE("Unit_hipFuncGetAttributes_NegTst") { - SECTION("attr is nullptr") { - REQUIRE_FALSE(hipSuccess == hipFuncGetAttributes(nullptr, - reinterpret_cast(&testhipFuncGetAttributesApi::fn))); - } - SECTION("function is nullptr") { - hipFuncAttributes attr{}; - REQUIRE_FALSE(hipSuccess == hipFuncGetAttributes(&attr, nullptr)); - } -} -/** - * hipFuncGetAttribute negative tests - * Scenario1: Validates returned error code for attrib_val = nullptr - * Scenario2: Validates returned error code for attrib = invalid = 0xff - */ -TEST_CASE("Unit_hipFuncGetAttribute_NegTst") { - hipModule_t Module; - CTX_CREATE() - hipFunction_t Function; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - SECTION("attr is nullptr") { - REQUIRE_FALSE(hipSuccess == hipFuncGetAttribute(nullptr, - HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, Function)); - } - SECTION("attr is invalid") { - int attrib_val; - REQUIRE_FALSE(hipSuccess == hipFuncGetAttribute(&attrib_val, - static_cast(0xff), Function)); - } - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} -/** - * hipFuncGetAttributes - * Scenario4: Validates the value of attribute "maxThreadsPerBlock". - * Scenario5: Validates the value of attribute "sharedSizeBytes". - */ -TEST_CASE("Unit_hipFuncGetAttributes_AttrTest") { - bool TestPassed = true; - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<64, 64>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<128, 64>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<256, 64>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<512, 64>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<1024, 64>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<64, 128>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<128, 128>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<256, 128>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<512, 128>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<1024, 128>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<64, 256>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<128, 256>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<256, 256>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<512, 256>(); - TestPassed &= testhipFuncGetAttributesApi:: - test_Attributes_Values<1024, 256>(); - REQUIRE(TestPassed); -} - diff --git a/tests/catch/unit/module/hipFuncSetAttribute.cc b/tests/catch/unit/module/hipFuncSetAttribute.cc deleted file mode 100644 index 33602f9078..0000000000 --- a/tests/catch/unit/module/hipFuncSetAttribute.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -#include "hip_test_common.hh" - -__global__ void fn(float* px, float* py) { - bool a[42]; - __shared__ double b[69]; - - for (auto&& x : b) x = *py++; - for (auto&& x : a) x = *px++ > 0.0; - for (auto&& x : a) if (x) *--py = *--px; -} - -/* -This testcases verifies the basic func of hipFuncSetAttribute API where -we need to pass function that executes on device -hipFuncAttributeMaxDynamicSharedMemorySize --> -The sum of this value + sharedSizeBytes should not exceed device attribute -hipFuncAttributePreferredSharedMemoryCarveout --> -Carving out the shared memory. -*/ -TEST_CASE("Unit_hipFuncSetAttribute_Basic") { - HIP_CHECK(hipFuncSetAttribute(reinterpret_cast(&fn), - hipFuncAttributeMaxDynamicSharedMemorySize, - 0)); - HIP_CHECK(hipFuncSetAttribute(reinterpret_cast(&fn), - hipFuncAttributePreferredSharedMemoryCarveout, - 0)); -} diff --git a/tests/catch/unit/module/hipFuncSetCacheConfig.cc b/tests/catch/unit/module/hipFuncSetCacheConfig.cc deleted file mode 100644 index cd5d58a8f6..0000000000 --- a/tests/catch/unit/module/hipFuncSetCacheConfig.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -#include - -__global__ void Empty_Kernel() { -} - -/* -This testcase verifies the basic funct of hipFuncSetCacheConfig API -On GPU devices, where L1 and shared memory uses same resources -This sets the preferred cache configuration for the kernel function -In this testcases we are setting hipFuncCachePreferL1 where L1 is -preferred more than shared memory -*/ -TEST_CASE("Unit_hipFuncSetCacheConfig_Basic") { - hipFuncCache_t cacheConfig{hipFuncCachePreferL1}; - HIP_CHECK(hipFuncSetCacheConfig(reinterpret_cast(Empty_Kernel), - cacheConfig)); -} diff --git a/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc b/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc deleted file mode 100644 index c9d65275b5..0000000000 --- a/tests/catch/unit/module/hipFuncSetSharedMemConfig.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -// Test Description: -// This test case verifies the working of hipFuncSetSharedMemConfig() api and -// the flag parameter - -#include -#include - - -__global__ void ReverseSeq(int *A, int *B, int N) { - extern __shared__ int SMem[]; - int offset = threadIdx.x; - int MirrorVal = N - offset - 1; - SMem[offset] = A[offset]; - __syncthreads(); - B[offset] = SMem[MirrorVal]; -} -/* -This testcase verifies the basic functionality of hipFuncSetSharedMemConfig API -by setting shared memory bank size - -1. hipSharedMemBankSizeDefault -2. hipSharedMemBankSizeFourByte -3. hipSharedMemBankSizeEightByte - -*/ -TEST_CASE("Unit_hipFuncSetSharedMemConfig_Basic") { - int *Ah{nullptr}, *RAh{nullptr}, NumElms = 128; - int *Ad{nullptr}, *RAd{nullptr}; - - HipTest::initArrays(&Ad, &RAd, nullptr, - &Ah, &RAh, nullptr, NumElms, false); - for (int i = 0; i < NumElms; ++i) { - Ah[i] = i; - RAh[i] = NumElms - i - 1; - } - HIP_CHECK(hipMemcpy(Ad, Ah, NumElms * sizeof(int), hipMemcpyHostToDevice)); - HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); - - // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeDefault flag - HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast - (&ReverseSeq), - hipSharedMemBankSizeDefault)); - - // Kernel Launch with shared mem size of = NumElms * sizeof(int) - ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); - memset(Ah, 0, NumElms * sizeof(int)); - - // Verifying the results - HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); - for (int i = 0; i < NumElms; ++i) { - REQUIRE(Ah[i] == RAh[i]); - } - - // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeFourBytes flg - HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast - (&ReverseSeq), - hipSharedMemBankSizeFourByte)); - HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); - - // Kernel Launch with shared mem size of = NumElms * sizeof(int) - ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); - memset(Ah, 0, NumElms * sizeof(int)); - - // Verifying the results - HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); - for (int i = 0; i < NumElms; ++i) { - REQUIRE(Ah[i] == RAh[i]); - } - - // Testing hipFuncSetSharedMemConfig() with hipSharedMemBankSizeEightBytes flg - HIP_CHECK(hipFuncSetSharedMemConfig(reinterpret_cast - (&ReverseSeq), - hipSharedMemBankSizeEightByte)); - HIP_CHECK(hipMemset(RAd, 0, NumElms * sizeof(int))); - - // Kernel Launch with shared mem size of = NumElms * sizeof(int) - ReverseSeq<<<1, NumElms, NumElms * sizeof(int)>>>(Ad, RAd, NumElms); - memset(Ah, 0, NumElms * sizeof(int)); - - // Verifying the results - HIP_CHECK(hipMemcpy(Ah, RAd, NumElms * sizeof(int), hipMemcpyDeviceToHost)); - for (int i = 0; i < NumElms; ++i) { - REQUIRE(Ah[i] == RAh[i]); - } - - HipTest::freeArrays(Ad, RAd, nullptr, - Ah, RAh, nullptr, false); -} diff --git a/tests/catch/unit/module/hipManagedKeyword.cc b/tests/catch/unit/module/hipManagedKeyword.cc deleted file mode 100644 index 7ed9bbe630..0000000000 --- a/tests/catch/unit/module/hipManagedKeyword.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ -/* -hipManagedKeyword API Scenario -1. Test hipModuleLoad on multiple GPUs -*/ - -#include "hip_test_common.hh" -#include "hip_test_kernels.hh" -#include "hip_test_checkers.hh" - -#define MANAGED_VAR_INIT_VALUE 10 -#define fileName "module_kernels.code" - -TEST_CASE("Unit_hipMangedKeyword_ModuleLoadMultiGPU") { - int numDevices = 0, data; - hipDeviceptr_t x; - size_t xSize; - hipGetDeviceCount(&numDevices); - for (int i = 0; i < numDevices; i++) { - hipSetDevice(i); - CTX_CREATE() - hipModule_t Module; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "GPU_func")); - HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, 1, 1, - 1, 0, 0, NULL, NULL)); - hipDeviceSynchronize(); - HIP_CHECK(hipModuleGetGlobal(reinterpret_cast(&x), - &xSize, Module, "x")); - HIP_CHECK(hipMemcpyDtoH(&data, hipDeviceptr_t(x), xSize)); - REQUIRE(data == (1 + MANAGED_VAR_INIT_VALUE)); - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() - } -} diff --git a/tests/catch/unit/module/hipModule.cc b/tests/catch/unit/module/hipModule.cc deleted file mode 100755 index 9683eacee9..0000000000 --- a/tests/catch/unit/module/hipModule.cc +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* -This testcase verifies the hipModuleLoad API On -1. Single code object -2. Multi Target architecture code object -*/ -#include -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" -#ifdef __linux__ -#include -#endif -#define LEN 64 -#define SIZE (LEN << 2) -#define COMMAND_LEN 256 -#define CODE_OBJ_SINGLEARCH "module_kernels.code" -#define kernel_name "hello_world" -#define CODE_OBJ_MULTIARCH "vcpy_kernel_multarch.code" - -/* -This API loads the kernel function, Launches the kernel -which copies one variable to another and validates both -the device variables for the current GPU architecture -*/ -void testCodeObjFile(const char *codeObjFile) { - float *A, *B; - float *Ad, *Bd; - HipTest::initArrays(&Ad, &Bd, nullptr, - &A, &B, nullptr, LEN, false); - - HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(Ad), A, SIZE)); - HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(Bd), B, SIZE)); - - hipModule_t Module; - hipFunction_t Function; - HIP_CHECK(hipModuleLoad(&Module, codeObjFile)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - - hipStream_t stream; - HIP_CHECK(hipStreamCreate(&stream)); - - struct { - void* _Ad; - void* _Bd; - } args; - args._Ad = reinterpret_cast(Ad); - args._Bd = reinterpret_cast(Bd); - size_t size = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, - stream, NULL, - reinterpret_cast(&config))); - - HIP_CHECK(hipStreamDestroy(stream)); - - HIP_CHECK(hipMemcpyDtoH(B, reinterpret_cast(Bd), SIZE)); - - for (uint32_t i = 0; i < LEN; i++) { - REQUIRE(A[i] == B[i]); - } - - HipTest::freeArrays(Ad, Bd, nullptr, - A, B, nullptr, - false); - HIP_CHECK(hipModuleUnload(Module)); -} - -#ifdef __linux__ -/** - * Check if environment variable $ROCM_PATH is defined - * - */ -bool isRocmPathSet() { - FILE *fpipe; - char const *command = "echo $ROCM_PATH"; - fpipe = popen(command, "r"); - - if (fpipe == nullptr) { - WARN("Unable to create command"); - return false; - } - char command_op[COMMAND_LEN]; - if (fgets(command_op, COMMAND_LEN, fpipe)) { - size_t len = strlen(command_op); - if (len > 1) { // This is because fgets always adds newline character - pclose(fpipe); - return true; - } - } - pclose(fpipe); - return false; -} -#endif -/* -This testcase checks the hipModuleLoadData API for the -current GPU architecture. -*/ -TEST_CASE("Unit_hipModule_TestCodeObjFile") { - testCodeObjFile(CODE_OBJ_SINGLEARCH); -} - -/* -This testcases -1. Creates kernel file and copies to tmp folder -2. Checks for Rocm path and generates code file for - multiple target architectures. -*/ -TEST_CASE("Unit_hipModule_MultiTargArchCodeObj") { -#ifdef __linux__ - char command[COMMAND_LEN]; - hipDeviceProp_t props; - hipGetDeviceProperties(&props, 0); - // Hardcoding the codeobject lines in multiple string to avoid cpplint warning - std::string CodeObjL1 = "#include \"hip/hip_runtime.h\"\n"; - std::string CodeObjL2 = - "extern \"C\" __global__ void hello_world(float* a, float* b) {\n"; - std::string CodeObjL3 = " int tx = hipThreadIdx_x;\n"; - std::string CodeObjL4 = " b[tx] = a[tx];\n"; - std::string CodeObjL5 = "}"; - // Creating the full code object string - static std::string CodeObj = CodeObjL1 + CodeObjL2 + CodeObjL3 + - CodeObjL4 + CodeObjL5; - std::ofstream ofs("/tmp/vcpy_kernel.cpp", std::ofstream::out); - ofs << CodeObj; - ofs.close(); - // Copy the file into current working location if not available - if (access("/tmp/vcpy_kernel.cpp", F_OK) == -1) { - INFO("Code Object File: /tmp/vcpy_kernel.cpp not found"); - REQUIRE(true); - } - // Generate the command to generate multi architecture code object file - const char* hipcc_path = nullptr; - if (isRocmPathSet()) { - hipcc_path = "$ROCM_PATH/bin/hipcc"; - } else { - hipcc_path = "/opt/rocm/bin/hipcc"; - } - /* Putting these command parameters into a variable to shorten the string - literal length in order to avoid multiline string literal cpplint warning - */ - const char* genco_option = "--offload-arch"; - const char* input_codeobj = "/tmp/vcpy_kernel.cpp"; - snprintf(command, COMMAND_LEN, - "%s --genco %s=gfx801,gfx802,gfx803,gfx900,gfx908,gfx1030,gfx90a,%s %s -o %s", - hipcc_path, genco_option, props.gcnArchName, input_codeobj, - CODE_OBJ_MULTIARCH); - - system((const char*)command); - // Check if the code object file is created - snprintf(command, COMMAND_LEN, "./%s", - CODE_OBJ_MULTIARCH); - - if (access(command, F_OK) == -1) { - INFO("Code Object File not found"); - REQUIRE(true); - } else { - testCodeObjFile(CODE_OBJ_MULTIARCH); - } -#else - SUCCEED("This test is skipped due to non linux environment"); -#endif -} diff --git a/tests/catch/unit/module/hipModuleGetGlobal.cc b/tests/catch/unit/module/hipModuleGetGlobal.cc deleted file mode 100755 index e99e3a64f1..0000000000 --- a/tests/catch/unit/module/hipModuleGetGlobal.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - - -#include -#include -#include -#include - -#define LEN 64 -#define SIZE LEN * sizeof(float) -#define ARRAY_SIZE 16 -#define fileName "module_kernels.code" - -/* -This testcase verifies the basic functionality of hipModuleGetGlobal API -1. Simple kernel -2. Global variables -*/ -TEST_CASE("Unit_hipModuleGetGlobal_Basic") { - float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; - HipTest::initArrays(&Ad, &Bd, nullptr, &A, &B, nullptr, LEN, - false); - CTX_CREATE() - hipMemcpyHtoD(reinterpret_cast(Ad), A, SIZE); - hipMemcpyHtoD(reinterpret_cast(Bd), B, SIZE); - hipModule_t Module; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - - float myDeviceGlobal_h = 42.0; - hipDeviceptr_t deviceGlobal; - size_t deviceGlobalSize; - HIP_CHECK(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, - Module, "myDeviceGlobal")); - HIP_CHECK(hipMemcpyHtoD(reinterpret_cast(deviceGlobal), - &myDeviceGlobal_h, deviceGlobalSize)); - float myDeviceGlobalArray_h[ARRAY_SIZE]; - hipDeviceptr_t myDeviceGlobalArray; - size_t myDeviceGlobalArraySize; - - HIP_CHECK(hipModuleGetGlobal(reinterpret_cast - (&myDeviceGlobalArray), - &myDeviceGlobalArraySize, Module, - "myDeviceGlobalArray")); - - for (int i = 0; i < ARRAY_SIZE; i++) { - myDeviceGlobalArray_h[i] = i * 1000.0f; - HIP_CHECK(hipMemcpyHtoD(reinterpret_cast - (myDeviceGlobalArray), - &myDeviceGlobalArray_h, - myDeviceGlobalArraySize)); - } - - struct { - void* _Ad; - void* _Bd; - } args; - - args._Ad = reinterpret_cast(Ad); - args._Bd = reinterpret_cast(Bd); - size_t size = sizeof(args); - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - - SECTION("Testing with simple kernel") { - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "hello_world")); - HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, 0, - NULL, - reinterpret_cast(&config))); - - hipMemcpyDtoH(B, hipDeviceptr_t(Bd), SIZE); - - for (uint32_t i = 0; i < LEN; i++) { - REQUIRE(A[i] == B[i]); - } - } - - SECTION("Testing global variables") { - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "test_globals")); - HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, 0, - NULL, - reinterpret_cast(&config))); - - hipMemcpyDtoH(B, hipDeviceptr_t(Bd), SIZE); - - for (uint32_t i = 0; i < LEN; i++) { - float expected = A[i] + myDeviceGlobal_h + - myDeviceGlobalArray_h[i % 16]; - REQUIRE(expected == B[i]); - } - } - - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() - HipTest::freeArrays(Ad, Bd, nullptr, - A, B, nullptr, - false); -} diff --git a/tests/catch/unit/module/hipModuleLaunchKernel.cc b/tests/catch/unit/module/hipModuleLaunchKernel.cc deleted file mode 100644 index 341378aec0..0000000000 --- a/tests/catch/unit/module/hipModuleLaunchKernel.cc +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright (c) 2021 - 2021 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 - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR - IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ -/* Test Scenarios - 1. hipModuleLaunchKernel Negative Scenarios - 2. hipModuleLaunchKernel Work Group tests => - - (block.x * block.y * block.z) <= Work Group Size - where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - - (block.x * block.y * block.z) > Work Group Size - where block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - */ - -#include -#include - -#define fileName "module_kernels.code" -#define matmulK "matmulK" -#define SixteenSec "SixteenSecKernel" -#define KernelandExtra "KernelandExtraParams" -#define FourSec "FourSecKernel" -#define TwoSec "TwoSecKernel" -#define dummyKernel "EmptyKernel" - -struct gridblockDim { - unsigned int gridX; - unsigned int gridY; - unsigned int gridZ; - unsigned int blockX; - unsigned int blockY; - unsigned int blockZ; -}; - -/* -This testcase verifies the negative scenarios of -hipModuleLaunchKernel API -*/ -TEST_CASE("Unit_hipModuleLaunchKernel_Negative") { - HIP_CHECK(hipSetDevice(0)); - struct { - void* _Ad; - void* _Bd; - void* _Cd; - int _n; - } args1; - args1._Ad = nullptr; - args1._Bd = nullptr; - args1._Cd = nullptr; - args1._n = 0; - hipFunction_t MultKernel, KernelandExtraParamKernel; - size_t size1; - size1 = sizeof(args1); - hipModule_t Module; - hipStream_t stream1; - hipDeviceptr_t *Ad{nullptr}; - CTX_CREATE() - - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&MultKernel, Module, matmulK)); - HIP_CHECK(hipModuleGetFunction(&KernelandExtraParamKernel, - Module, KernelandExtra)); - void *config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args1, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, - HIP_LAUNCH_PARAM_END}; - void *params[] = {Ad}; - HIP_CHECK(hipStreamCreate(&stream1)); - SECTION("Passing nullptr to kernel function") { - REQUIRE(hipModuleLaunchKernel(nullptr, 1, 1, 1, 1, 1, 1, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Passing Max int value to block dim") { - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - std::numeric_limits::max(), - std::numeric_limits::max(), - std::numeric_limits::max(), - 0, stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - - SECTION("Passing 0 to all value dim") { - REQUIRE(hipModuleLaunchKernel(MultKernel, 0, 0, 0, - 0, - 0, - 0, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Passing 0 for X dim") { - REQUIRE(hipModuleLaunchKernel(MultKernel, 0, 1, 1, - 0, - 1, - 1, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - - SECTION("Passing 0 for Y dim") { - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 0, 1, - 1, - 0, - 1, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Passing 0 for Z dim") { - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 0, - 1, - 1, - 0, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Passing both kernel and extra params") { - REQUIRE(hipModuleLaunchKernel(KernelandExtraParamKernel, 1, 1, 1, 1, - 1, 1, 0, stream1, - reinterpret_cast(¶ms), - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Passing more than maxthreadsperblock to block dim") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - deviceProp.maxThreadsPerBlock+1, - deviceProp.maxThreadsPerBlock+1, - deviceProp.maxThreadsPerBlock+1, 0, - stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Block dim X is more than max allowed") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - deviceProp.maxThreadsDim[0]+1, - 1, - 1, 0, stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Block dim Y is more than max allowed") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - 1, - deviceProp.maxThreadsDim[1]+1, - 1, 0, stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Block dim Z is more than max allowed") { - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - 1, - 1, - deviceProp.maxThreadsDim[2]+1, - 0, stream1, NULL, - reinterpret_cast(&config1)) - != hipSuccess); - } - - SECTION("Block invalid config to extra params") { - void *config3[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size1, - HIP_LAUNCH_PARAM_END}; - REQUIRE(hipModuleLaunchKernel(MultKernel, 1, 1, 1, - 1, 1, 1, 0, stream1, - NULL, - reinterpret_cast(&config3)) - != hipSuccess); - } - - HIP_CHECK(hipStreamDestroy(stream1)); - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} - -/* -This testcase verifies the work group scenarios of -hipModuleLaunchKernel API -*/ -TEST_CASE("Unit_hipModuleLaunchKernel_WorkGroup") { - HIP_CHECK(hipSetDevice(0)); - hipFunction_t DummyKernel; - hipModule_t Module; - hipStream_t stream1; - CTX_CREATE() - - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&DummyKernel, Module, dummyKernel)); - HIP_CHECK(hipStreamCreate(&stream1)); - // Passing Max int value to block dimensions - hipDeviceProp_t deviceProp; - hipGetDeviceProperties(&deviceProp, 0); - double cuberootVal = - cbrt(static_cast(deviceProp.maxThreadsPerBlock)); - uint32_t cuberoot_floor = floor(cuberootVal); - uint32_t cuberoot_ceil = ceil(cuberootVal); - // Scenario: (block.x * block.y * block.z) <= Work Group Size where - // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - HIP_CHECK(hipModuleLaunchKernel(DummyKernel, - 1, 1, 1, - cuberoot_floor, cuberoot_floor, cuberoot_floor, - 0, stream1, NULL, NULL)); - // Scenario: (block.x * block.y * block.z) > Work Group Size where - // block.x < MaxBlockDimX , block.y < MaxBlockDimY and block.z < MaxBlockDimZ - REQUIRE(hipModuleLaunchKernel(DummyKernel, - 1, 1, 1, - cuberoot_ceil, cuberoot_ceil, cuberoot_ceil + 1, - 0, stream1, NULL, NULL) != hipSuccess); - HIP_CHECK(hipStreamDestroy(stream1)); - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} diff --git a/tests/catch/unit/module/hipModuleLoadData.cc b/tests/catch/unit/module/hipModuleLoadData.cc deleted file mode 100644 index 2102a10f49..0000000000 --- a/tests/catch/unit/module/hipModuleLoadData.cc +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -/* -hipModuleLoadData scenarios - -1. Loads the kernel and the corresponding kernel function - which copies the data from one device variable to another. -*/ - -#include -#include -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define LEN 64 -#define SIZE LEN << 2 -#define FILENAME "module_kernels.code" -#define kernel_name "hello_world" - -static std::vector load_file() { - std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - INFO("could not open code object" << FILENAME); - REQUIRE(false); - } - return buffer; -} - - -TEST_CASE("Unit_hipModuleLoadData_Basic") { - auto buffer = load_file(); - float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; - HipTest::initArrays(&Ad, &Bd, nullptr, &A, &B, nullptr, - LEN, false); - HIP_CHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); - HIP_CHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); - - hipModule_t Module; - hipFunction_t Function{nullptr}; - - HIP_CHECK(hipModuleLoadData(&Module, &buffer[0])); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - - hipStream_t stream; - HIP_CHECK(hipStreamCreate(&stream)); - - struct { - void* _Ad; - void* _Bd; - } args; - args._Ad = reinterpret_cast(Ad); - args._Bd = reinterpret_cast(Bd); - size_t size = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - HIP_CHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, 1, 1, 0, - stream, NULL, reinterpret_cast(&config))); - - HIP_CHECK(hipStreamDestroy(stream)); - - HIP_CHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); - - for (uint32_t i = 0; i < LEN; i++) { - REQUIRE(A[i] == B[i]); - } - HipTest::freeArrays(Ad, Bd, nullptr, - A, B, - nullptr, false); -} diff --git a/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc b/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc deleted file mode 100644 index bfb780ca06..0000000000 --- a/tests/catch/unit/module/hipModuleLoadDataMultThreadOnMultGPU.cc +++ /dev/null @@ -1,161 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* -This testcase verifies the multithreaded scenario of -hipModuleLoadData API on MultiGPU system -*/ - -#include -#include - -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define LEN 64 -#define SIZE LEN << 2 -#define THREADS 8 - -#define FILENAME "module_kernels.code" -#define kernel_name "hello_world" - -/* -This function reads the kernel code object file into buffer -*/ -static std::vector load_file() { - std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - INFO("could not open code object " << FILENAME); - REQUIRE(false); - } - return buffer; -} - -/* -Thread function -1. Loads the module using hipModuleLoadData API -2. Initializes 2 device variables. -3. Launches kernel which copies one data into another. -4. validates the result and returns it to the caller using - std::ref variable. -*/ -static void run(const std::vector& buffer, int deviceNo, - bool &testResult) { - hipSetDevice(deviceNo); - hipModule_t Module; - hipFunction_t Function; - float *A{nullptr}, *B{nullptr}, *Ad{nullptr}, *Bd{nullptr}; - testResult = true; - HipTest::initArrays(&Ad, &Bd, nullptr, - &A, &B, nullptr, - LEN, false); - HIPCHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); - HIPCHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); - - HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); - HIPCHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - - hipStream_t stream; - HIPCHECK(hipStreamCreate(&stream)); - - struct { - void* _Ad; - void* _Bd; - } args; - args._Ad = static_cast(Ad); - args._Bd = static_cast(Bd); - size_t size = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, LEN, - 1, 1, 0, stream, NULL, - reinterpret_cast(&config))); - - HIPCHECK(hipStreamSynchronize(stream)); - - HIPCHECK(hipStreamDestroy(stream)); - - HIPCHECK(hipModuleUnload(Module)); - - HIPCHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); - - for (uint32_t i = 0; i < LEN; i++) { - REQUIRE(A[i] == B[i]); - } - HipTest::freeArrays(Ad, Bd, nullptr, - A, B, nullptr, - false); -} - -/* -Thread class inherited from std::thread -*/ -struct joinable_thread : std::thread { - template - joinable_thread(Xs&&... xs) : std::thread(std::forward(xs)...) {} // NOLINT - - joinable_thread& operator=(joinable_thread&& other) = default; - joinable_thread(joinable_thread&& other) = default; - - ~joinable_thread() { - if (this->joinable()) - this->join(); - } -}; - -/* -This API is triggered form the test case where in -1. Creates the thread object. -2. Loops through the number of GPUs and launches multiple threads. -*/ -static void run_multi_threads(uint32_t n, const std::vector& buffer) { - int numDevices = 0; - HIPCHECK(hipGetDeviceCount(&numDevices)); - bool testResult = false; - std::vector threads; - - for (int deviceNo=0; deviceNo < numDevices; ++deviceNo) { - for (uint32_t i = 0; i < n; i++) { - threads.emplace_back(std::thread{[&, buffer] { - run(buffer, deviceNo, std::ref(testResult)); - }}); - } - } -} -/* -The testcase verifies the multithreaded funtionality on MGPU system -1. Loads the kernel file by calling load_file API -2. Gets the host thread count -3. Creates multiple threads in parallel where in each thread initializes - 2 device variables and loads the kernel using hipModuleLoadData API. - The kernel copies the data from one variable to another.Then the thread - validates both the variables. -*/ -TEST_CASE("Unit_hipModuleLoadData_MGpuMultiThread") { - auto buffer = load_file(); - auto file_size = buffer.size() / (1024 * 1024); - auto thread_count = HipTest::getHostThreadCount(file_size + 10); - run_multi_threads(thread_count, buffer); -} diff --git a/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc b/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc deleted file mode 100644 index 183da4c007..0000000000 --- a/tests/catch/unit/module/hipModuleLoadDataMultThreaded.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* -This testcase verifies the multithreaded scenario of hipModuleLoadData API -*/ -#include -#include - -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define LEN 64 -#define SIZE LEN << 2 -#define THREADS 8 -#define MAX_THREADS 512 - -#define FILENAME "module_kernels.code" -#define kernel_name "hello_world" - -/* -This function reads the kernel code object file into buffer -*/ -std::vector load_file() { - std::ifstream file(FILENAME, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - INFO("could not open code object" << FILENAME); - REQUIRE(false); - } - return buffer; -} - -/* -Thread function -1. Loads the module using hipModuleLoadData API -2. Initializes 2 device variables. -3. Launches kernel which copies one data into another. -4. validates the result and returns it to the caller using - std::ref variable. -*/ -void run(const std::vector& buffer, bool &testResult) { - hipModule_t Module; - hipFunction_t Function; - - float *A, *B, *Ad, *Bd; - testResult = true; - HipTest::initArrays(&Ad, &Bd, nullptr, - &A, &B, nullptr, - LEN, false); - - - HIPCHECK(hipMemcpy(Ad, A, SIZE, hipMemcpyHostToDevice)); - HIPCHECK(hipMemcpy(Bd, B, SIZE, hipMemcpyHostToDevice)); - - HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); - HIPCHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - - hipStream_t stream; - HIPCHECK(hipStreamCreate(&stream)); - - struct { - void* _Ad; - void* _Bd; - } args; - args._Ad = static_cast(Ad); - args._Bd = static_cast(Bd); - size_t size = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END}; - HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, - LEN, 1, 1, 0, stream, - NULL, reinterpret_cast(&config))); - - HIPCHECK(hipStreamSynchronize(stream)); - - HIPCHECK(hipStreamDestroy(stream)); - - HIPCHECK(hipModuleUnload(Module)); - - HIPCHECK(hipMemcpy(B, Bd, SIZE, hipMemcpyDeviceToHost)); - - for (uint32_t i = 0; i < LEN; i++) { - REQUIRE(A[i] == B[i]); - } - - HipTest::freeArrays(Ad, Bd, nullptr, - A, B, nullptr, - false); -} - -/* -Thread class inherited from std::thread -*/ -struct joinable_thread : std::thread { - template - joinable_thread(Xs&&... xs) : std::thread(std::forward(xs)...) {} // NOLINT - - joinable_thread& operator=(joinable_thread&& other) = default; - joinable_thread(joinable_thread&& other) = default; - - ~joinable_thread() { - if (this->joinable()) - this->join(); - } -}; - -/* -This API is triggered form the test case where in -1. Creates the thread object. -2. Loops through the number of GPUs and launches multiple threads. -*/ -void run_multi_threads(uint32_t n, const std::vector& buffer) { - std::vector threads; - bool testResult = false; - for (uint32_t i = 0; i < n; i++) { - threads.emplace_back(std::thread{[&] { - run(buffer, std::ref(testResult)); - }}); - } -} - -/* -The testcase verifies the multithreaded funtionality -1. Loads the kernel file by calling load_file API -2. Gets the host thread count -3. Creates multiple threads in parallel where in each thread initializes - 2 device variables and loads the kernel using hipModuleLoadData API. - The kernel copies the data from one variable to another.Then the thread - validates both the variables. -*/ -TEST_CASE("Unit_hipModuleLoadData_MultiThreaded") { - HIPCHECK(hipInit(0)); - auto buffer = load_file(); - auto file_size = buffer.size() / (1024 * 1024); - auto thread_count = HipTest::getHostThreadCount(file_size + 10); - if (thread_count == 0) { - INFO("Thread Count is zero"); - REQUIRE(false); - } - - run_multi_threads(thread_count, buffer); -} diff --git a/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc b/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc deleted file mode 100644 index 401892915e..0000000000 --- a/tests/catch/unit/module/hipModuleLoadMultiThreaded.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 testcase verifies hipModuleLoad API in multithreaded scenario -*/ -#include -#include "hip/hip_runtime.h" -#if HT_AMD -#include "hip/hip_ext.h" -#endif -#include -#include -#include -#include -#include -#include -#define THREADS 8 -#define MAX_NUM_THREADS 128 - -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define NUM_GROUPS 1 -#define GROUP_SIZE 1 -#define WARMUP_RUN_COUNT 10 -#define TIMING_RUN_COUNT 100 -#define TOTAL_RUN_COUNT WARMUP_RUN_COUNT + TIMING_RUN_COUNT -#define FILENAME "module_kernels.code" -#define kernel_name "EmptyKernel" - -/* -This thread function loads the kernel file , synchronizes the threads -and Launches the kernel . -*/ -void hipModuleLaunchKernel_enqueue(std::atomic_int* shared, int max_threads) { - // resources necessary for this thread - hipStream_t stream; - HIPCHECK(hipStreamCreate(&stream)); - hipModule_t module; - hipFunction_t function; - - HIPCHECK(hipModuleLoad(&module, FILENAME)); - HIPCHECK(hipModuleGetFunction(&function, module, kernel_name)); - - void* kernel_params = nullptr; - - // synchronize all threads, before running - shared->fetch_add(1, std::memory_order_release); - while (max_threads != shared->load(std::memory_order_acquire)) {} - - for (auto i = 0; i < TOTAL_RUN_COUNT; ++i) { - HIPCHECK(hipModuleLaunchKernel(function, 1, 1, - 1, 1, 1, 1, 0, stream, - &kernel_params, nullptr)); - } - HIPCHECK(hipModuleUnload(module)); - HIPCHECK(hipStreamDestroy(stream)); -} - -/* -thread pool class contains launching the threads using std::async API -with future variable "threads". -The start API Launches the threads and finish API waits for the -thread execution to end. -*/ -struct thread_pool { - explicit thread_pool(int total_threads) : max_threads(total_threads) { - } - void start(std::function f) { - for (int i = 0; i < max_threads; ++i) { - threads.push_back(std::async(std::launch::async, f, - &shared, max_threads)); - } - } - void finish() { - for (auto&&thread : threads) { - thread.get(); - } - threads.clear(); - shared = 0; - } - ~thread_pool() { - finish(); - } - private: - std::atomic_int shared {0}; - std::vector buffer; - std::vector> threads; - int max_threads = 1; -}; - -/* -This testcase verifies the Multithreaded scenario of hipModule API -where in threadpool object is created and the object invokes start API -which launches multiple threads where each thread loads the kernel object -using hipModuleLoad API and launches the kernel in parallel. -*/ -TEST_CASE("Unit_hipModuleLoad_MultiThread") { - int max_threads = min(THREADS * std::thread::hardware_concurrency(), - MAX_NUM_THREADS); - thread_pool task(max_threads); - task.start(hipModuleLaunchKernel_enqueue); - task.finish(); -} diff --git a/tests/catch/unit/module/hipModuleLoadUnloadStress.cc b/tests/catch/unit/module/hipModuleLoadUnloadStress.cc deleted file mode 100644 index 46acdae29b..0000000000 --- a/tests/catch/unit/module/hipModuleLoadUnloadStress.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -#include -#include -#include -#include -#include "hip_test_common.hh" - -#define TEST_ITERATIONS 1000 -#define CODEOBJ_FILE "module_kernels.code" -/** - * Run Valgrind tool with these test cases to validate memory leakage. - * E.g. valgrind --leak-check=yes ./a.out - */ - -/** - * Internal Function - */ -static std::vector load_file() { - std::ifstream file(CODEOBJ_FILE, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - WARN("could not open code object " << CODEOBJ_FILE); - } - file.close(); - return buffer; -} -/** - * Validates no memory leakage for hipModuleLoad - */ -TEST_CASE("Unit_hipModule_LoadUnloadStress") { - CTX_CREATE() - for (int count = 0; count < TEST_ITERATIONS; count++) { - hipModule_t Module; - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); - HIP_CHECK(hipModuleUnload(Module)); - } - CTX_DESTROY() -} -/** - * Validates no memory leakage for hipModuleLoadData - */ -TEST_CASE("Unit_hipModuleLoadData_LoadUnloadStress") { - CTX_CREATE() - auto buffer = load_file(); - for (int count = 0; count < TEST_ITERATIONS; count++) { - hipModule_t Module; - HIP_CHECK(hipModuleLoadData(&Module, &buffer[0])); - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); - HIP_CHECK(hipModuleUnload(Module)); - } - CTX_DESTROY() -} -/** - * Validates no memory leakage for hipModuleLoadDataEx - */ -TEST_CASE("Unit_hipModuleLoadDataEx_UnloadStress") { - CTX_CREATE() - auto buffer = load_file(); - for (int count = 0; count < TEST_ITERATIONS; count++) { - hipModule_t Module; - HIP_CHECK(hipModuleLoadDataEx(&Module, &buffer[0], 0, - nullptr, nullptr)); - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, "testWeightedCopy")); - HIP_CHECK(hipModuleUnload(Module)); - } - CTX_DESTROY() -} diff --git a/tests/catch/unit/module/hipModuleNegative.cc b/tests/catch/unit/module/hipModuleNegative.cc deleted file mode 100644 index c43b507c21..0000000000 --- a/tests/catch/unit/module/hipModuleNegative.cc +++ /dev/null @@ -1,274 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 testcase verifies the negative scenarios of -1. hipModuleLoad API -2. hipModuleLoadData API -3. hipModuleGetFunction API -4. hipModuleGetGlobal API -*/ - -#include -#include -#include -#include -#include "hip_test_common.hh" - -#define FILENAME_NONEXST "sample_nonexst.code" -#define FILENAME_EMPTY "emptyfile.code" -#define FILENAME_RAND "rand_file.code" -#define RANDOMFILE_LEN 2048 -#define CODEOBJ_FILE "module_kernels.code" -#define KERNEL_NAME "hello_world" -#define KERNEL_NAME_NONEXST "xyz" -#define CODEOBJ_GLOBAL "module_kernels.code" -#define DEVGLOB_VAR_NONEXIST "xyz" -#define DEVGLOB_VAR "myDeviceGlobal" -/** - * Internal Function - * Loads the kernel file into buffer - */ -std::vector load_file(const char* filename) { - std::ifstream file(filename, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - INFO("could not open code object " << filename); - } - file.close(); - return buffer; -} - -/** - * Internal Function - Create Randome file - */ -void createRandomFile(const char* filename) { - std::ofstream outfile(filename, std::ios::binary); - char buf[RANDOMFILE_LEN]; - unsigned int seed = 1; - for (int i = 0; i < RANDOMFILE_LEN; i++) { - buf[i] = rand_r(&seed) % 256; - } - outfile.write(buf, RANDOMFILE_LEN); - outfile.close(); -} - -/** - * Validates negative scenarios for hipModuleLoad API - */ - -TEST_CASE("Unit_hipModuleLoad_Negative") { - CTX_CREATE() - hipModule_t Module; - - SECTION("Nullptr to module") { - REQUIRE(hipModuleLoad(nullptr, CODEOBJ_FILE) - != hipSuccess); - } - - SECTION("Nullptr to Fname") { - REQUIRE(hipModuleLoad(&Module, nullptr) - != hipSuccess); - } - - SECTION("Empty fname") { - std::fstream fs; - fs.open(FILENAME_EMPTY, std::ios::out); - fs.close(); - REQUIRE(hipModuleLoad(&Module, FILENAME_EMPTY) - != hipSuccess); - } - - SECTION("Binary file with random number") { - createRandomFile(FILENAME_RAND); - REQUIRE(hipModuleLoad(&Module, FILENAME_RAND) - != hipSuccess); - remove(FILENAME_RAND); - } - - SECTION("Non Existent file") { - REQUIRE(hipModuleLoad(&Module, FILENAME_NONEXST) - != hipSuccess); - } - - SECTION("Empty string to file name") { - REQUIRE(hipModuleLoad(&Module, "") - != hipSuccess); - } - - CTX_DESTROY() -} - -/** - * Validates negative scenarios for hipModuleLoadData API - */ -TEST_CASE("Unit_hipModuleLoadData_Negative") { - CTX_CREATE() - hipModule_t Module; - - SECTION("Nullptr to module") { - auto buffer = load_file(CODEOBJ_FILE); - REQUIRE(hipModuleLoadData(nullptr, &buffer[0]) - != hipSuccess); - } - - SECTION("Nullptr to image") { - REQUIRE(hipModuleLoadData(&Module, nullptr) - != hipSuccess); - } - - SECTION("Random file to image") { - createRandomFile(FILENAME_RAND); - auto buffer = load_file(FILENAME_RAND); - REQUIRE(hipModuleLoadData(&Module, &buffer[0]) - != hipSuccess); - } - - SECTION("Nullptr to Module") { - auto buffer = load_file(CODEOBJ_FILE); - REQUIRE(hipModuleLoadDataEx(nullptr, &buffer[0], 0, nullptr, nullptr) - != hipSuccess); - } - - SECTION("Nullptr to image") { - REQUIRE(hipModuleLoadDataEx(&Module, nullptr, 0, nullptr, nullptr) - != hipSuccess); - } - - SECTION("Random image file") { - // Create a binary file with random numbers - createRandomFile(FILENAME_RAND); - // Open the code object file and copy it in a buffer - auto buffer = load_file(FILENAME_RAND); - REQUIRE(hipModuleLoadDataEx(&Module, &buffer[0], 0, nullptr, nullptr) - != hipSuccess); - } - - CTX_DESTROY() -} - -/** - * Validates negative scenarios for hipModuleGetFunction API - */ -TEST_CASE("Unit_hipModuleGetFunction_Negative") { - CTX_CREATE() - hipFunction_t Function; - hipModule_t Module; - - SECTION("Nullptr to function name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - REQUIRE(hipModuleGetFunction(nullptr, Module, KERNEL_NAME) != hipSuccess); - HIP_CHECK(hipModuleUnload(Module)); - } - - SECTION("Uninitialized module") { - REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME) != hipSuccess); - } - - SECTION("Non existing function kernel name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME_NONEXST) - != hipSuccess); - HIP_CHECK(hipModuleUnload(Module)); - } - - SECTION("Nullptr to kernel name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - REQUIRE(hipModuleGetFunction(&Function, Module, nullptr) != hipSuccess); - HIP_CHECK(hipModuleUnload(Module)); - } -#if HT_AMD - SECTION("Unloaded module") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - HIP_CHECK(hipModuleUnload(Module)); - REQUIRE(hipModuleGetFunction(&Function, Module, KERNEL_NAME) != hipSuccess); - } -#endif - - SECTION("Empty string to kernel name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - REQUIRE(hipModuleGetFunction(&Function, Module, "") != hipSuccess); - HIP_CHECK(hipModuleUnload(Module)); - } - - CTX_DESTROY() -} - -/** - * Validates negative scenarios for hipModuleGetGlobal API - */ -TEST_CASE("Unit_hipModuleGetGlobal_Negative") { - CTX_CREATE() - hipModule_t Module; - hipDeviceptr_t deviceGlobal; - size_t deviceGlobalSize; - - SECTION("Nullptr to varname") { - HIPCHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); - REQUIRE(hipModuleGetGlobal(&deviceGlobal, - &deviceGlobalSize, Module, nullptr) - != hipSuccess); - HIPCHECK(hipModuleUnload(Module)); - } - - SECTION("Wrong variable name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); - REQUIRE(hipModuleGetGlobal(&deviceGlobal, &deviceGlobalSize, - Module, DEVGLOB_VAR_NONEXIST) != hipSuccess); - HIPCHECK(hipModuleUnload(Module)); - } - - SECTION("Empty string to module name") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); - REQUIRE(hipModuleGetGlobal(&deviceGlobal, - &deviceGlobalSize, Module, "") != hipSuccess); - HIPCHECK(hipModuleUnload(Module)); - } - -#if HT_AMD - SECTION("Unloaded Module") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_GLOBAL)); - HIP_CHECK(hipModuleUnload(Module)); - REQUIRE(hipModuleGetGlobal(&deviceGlobal, - &deviceGlobalSize, Module, - DEVGLOB_VAR) != hipSuccess); - } - - SECTION("Unload an Unloaded module") { - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - HIP_CHECK(hipModuleUnload(Module)); - REQUIRE(hipModuleUnload(Module) != hipSuccess); - } - - SECTION("Uninitialized module") { - REQUIRE(hipModuleGetGlobal(&deviceGlobal, - &deviceGlobalSize, Module, - DEVGLOB_VAR) != hipSuccess); - } - SECTION("Unload Uninitialized module") { - REQUIRE(hipModuleUnload(Module) != hipSuccess); - } -#endif - - CTX_DESTROY() -} diff --git a/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc b/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc deleted file mode 100644 index c58b3978e6..0000000000 --- a/tests/catch/unit/module/hipModuleOccupancyMaxPotentialBlockSize.cc +++ /dev/null @@ -1,267 +0,0 @@ - -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ -#include -#include - -#define fileName "module_kernels.code" -#define kernel_name "hello_world" -/** - * hipModuleOccupancyMaxPotentialBlockSize and hipModuleOccupancyMaxPotentialBlockSizeWithFlags - * corner tests. - * Scenario1: - * Validates the value of gridSize, which should be always non zero +ve integer and blockSize - * range returned for dynSharedMemPerBlk = 0 and blockSizeLimit = 0. - * Scenario2: - * Validates the value of gridSize, which should be always non zero +ve integer and blockSize - * range returned for dynSharedMemPerBlk = devProp.sharedMemPerBlock and - * blockSizeLimit = devProp.maxThreadsPerBlock. - */ -TEST_CASE("Unit_hipModuleOccupancyMaxPotentialBlockSize_FuncTst") { - // Initialize - hipDeviceProp_t devProp; - int gridSize = 0; - int blockSize = 0; - hipModule_t Module; - CTX_CREATE() - hipFunction_t Function; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); - // Scenario1 - SECTION("without flag - gridSize when input params are 0") { - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, - &blockSize, Function, 0, 0)); - } - // Scenario2 - SECTION("without flag - gridSize when input params are maximum") { - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, - &blockSize, Function, - devProp.sharedMemPerBlock, devProp.maxThreadsPerBlock)); - } - // Scenario1 - SECTION("with flag - gridSize when input params are 0") { - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, - &blockSize, Function, 0, 0, 0)); - } - // Scenario2 - SECTION("with flag - gridSize when input params are maximum") { - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, - &blockSize, Function, devProp.sharedMemPerBlock, - devProp.maxThreadsPerBlock, 0)); - } - // Check if blockSize doen't exceed maxThreadsPerBlock - REQUIRE_FALSE(gridSize <= 0); - REQUIRE_FALSE(blockSize <= 0); - REQUIRE_FALSE(blockSize > devProp.maxThreadsPerBlock); - // Un-initialize - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} -/** - * hipModuleOccupancyMaxActiveBlocksPerMultiprocessor and - * hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags Corner tests. - * Scenario1: - * Validates numBlock value range is within expected limit when sharedMemPerBlock - * is 0. - * Scenario2: - * Validates numBlock value range is within expected limit when - * dynSharedMemPerBlk = devProp.sharedMemPerBlock. - */ -TEST_CASE("Unit_hipModuleOccupancyMaxActiveBlocksPerMultiprocessor_FuncTst") { - // Initialize - hipDeviceProp_t devProp; - int gridSize = 0; - int blockSize = 0; - int numBlock = 0; - hipModule_t Module; - CTX_CREATE() - hipFunction_t Function; - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, - &blockSize, Function, 0, 0)); - HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); - // Scenario1 - SECTION("without flag - gridSize when input params are 0") { - HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlock, - Function, blockSize, 0)); - } - // Scenario2 - SECTION("without flag - gridSize when input params are maximum") { - HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlock, - Function, blockSize, devProp.sharedMemPerBlock)); - } - // Scenario1 - SECTION("with flag - gridSize when input params are 0") { - HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags( - &numBlock, Function, blockSize, 0, 0)); - } - // Scenario2 - SECTION("with flag - gridSize when input params are maximum") { - HIP_CHECK(hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags( - &numBlock, Function, blockSize, devProp.sharedMemPerBlock, 0)) - } - // Check if numBlocks are within limits - int temp_val = (numBlock * blockSize); - REQUIRE_FALSE(numBlock <= 0); - REQUIRE_FALSE(temp_val > devProp.maxThreadsPerMultiProcessor); - // Un-initialize - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} -/** - * hipModuleOccupancyMaxPotentialBlockSize negative tests. - * Scenario1: gridSize is nullptr. - * Scenario2: blocksize is nullptr. - * Scenario3: blockSizeLimit < 0. - */ -TEST_CASE("Unit_hipModuleOccupancyMaxPotentialBlockSize_NegTst") { - int gridSize = 0; - int blockSize = 0; - hipModule_t Module; - hipFunction_t Function; - CTX_CREATE() - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - // Scenario1 - SECTION("without flag - gridSize is nullptr") { - REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( - nullptr, &blockSize, Function, 0, 0)); - } - // Scenario2 - SECTION("without flag - blocksize is nullptr") { - REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( - &gridSize, nullptr, Function, 0, 0)); - } - // Scenario3 - SECTION("without flag - blockSizeLimit is less than 0") { - hipDeviceProp_t devProp; - HIP_CHECK(hipGetDeviceProperties(&devProp, 0)); -#if HT_NVIDIA - REQUIRE_FALSE(hipSuccess == hipModuleOccupancyMaxPotentialBlockSize( - &gridSize, &blockSize, Function, 0, -1)); -#else - // As discussed in SWDEV-269400 - // with developers this difference in behavior between NVIDIA and AMD - // is retained. - REQUIRE_FALSE(hipSuccess != hipModuleOccupancyMaxPotentialBlockSize( - &gridSize, &blockSize, Function, 0, -1)); -#endif - } - // Scenario1 - SECTION("with flag - gridSize is nullptr") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxPotentialBlockSizeWithFlags(nullptr, - &blockSize, Function, 0, 0, 0)); - } - // Scenario2 - SECTION("with flag - blocksize is nullptr") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, - nullptr, Function, 0, 0, 0)); - } - // Scenario3 - SECTION("with flag - blockSizeLimit is less than 0") { -#if HT_NVIDIA - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, - &blockSize, Function, 0, -1, 0)); -#else - // As discussed in SWDEV-269400 - // with developers this difference in behavior between NVIDIA and AMD - // is retained. - REQUIRE_FALSE(hipSuccess != - hipModuleOccupancyMaxPotentialBlockSizeWithFlags(&gridSize, - &blockSize, Function, 0, -1, 0)); -#endif - } - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} -/** - * hipModuleOccupancyMaxActiveBlocksPerMultiprocessor negative tests. - * Scenario1: numBlocks is nullptr. - * Scenario2: Check the behavior for blockSize < 0. - * Scenario3: Check error code returned for dynSharedMemPerBlk = 0 and blockSize = 0. - * Scenario4: dynSharedMemPerBlk = size_t numeric limit. - */ -TEST_CASE("Unit_hipModuleOccupancyMaxActiveBlocksPerMultiprocessor_NegTst") { - int gridSize = 0; - int blockSize = 0; - int numBlocks = 0; - hipModule_t Module; - hipFunction_t Function; - CTX_CREATE() - HIP_CHECK(hipModuleLoad(&Module, fileName)); - HIP_CHECK(hipModuleGetFunction(&Function, Module, kernel_name)); - HIP_CHECK(hipModuleOccupancyMaxPotentialBlockSize(&gridSize, &blockSize, - Function, 0, 0)); - // Scenario1 - SECTION("without flag - numBlocks is nullptr") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(nullptr, - Function, blockSize, 0)); - } - // Scenario3 - SECTION("without flag - dynSharedMemPerBlk = 0 and blockSize = 0") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, - Function, 0, 0)); - } - // Scenario2 - SECTION("without flag - blockSize is less than 0") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, - Function, -1, 0)); - } - // Scenario4 - SECTION("without flag - dynSharedMemPerBlk = max_numerical_limit") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks, - Function, 0, std::numeric_limits::max())); - } - // Scenario1 - SECTION("with flag - numBlocks is nullptr") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(nullptr, - Function, blockSize, 0, 0)); - } - // Scenario3 - SECTION("with flag - dynSharedMemPerBlk = 0 and blockSize = 0") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, - Function, 0, 0, 0)); - } - // Scenario2 - SECTION("with flag - blockSize is less than 0") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, - Function, -1, 0, 0)); - } - // Scenario4 - SECTION("with flag - dynSharedMemPerBlk = max_numerical_limit") { - REQUIRE_FALSE(hipSuccess == - hipModuleOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(&numBlocks, - Function, 0, std::numeric_limits::max(), 0)); - } - HIP_CHECK(hipModuleUnload(Module)); - CTX_DESTROY() -} - diff --git a/tests/catch/unit/module/hipModuleTexture2dDrv.cc b/tests/catch/unit/module/hipModuleTexture2dDrv.cc deleted file mode 100755 index 2afa3e06fc..0000000000 --- a/tests/catch/unit/module/hipModuleTexture2dDrv.cc +++ /dev/null @@ -1,561 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 testcase verifies the following scenarios of hipModuleGetTexRef API -1. Negative -2. Basic functionality using different data types -3. Multiple streams -4. MultiThreaded - MultStreamMultGPU -5. MultiThreaded - SingleStreamMultGPU -*/ - -#include -#include -#include -#include -#include -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define CODEOBJ_FILE "module_kernels.code" -#define NON_EXISTING_TEX_NAME "xyz" -#define EMPTY_TEX_NAME "" -#define GLOBAL_KERNEL_VAR "deviceGlobalFloat" -#define TEX_REF "ftex" -#define WIDTH 256 -#define HEIGHT 256 -#define MAX_STREAMS 4 -#define GRIDDIMX 16 -#define GRIDDIMY 16 -#define GRIDDIMZ 1 -#define BLOCKDIMZ 1 -#define MAX_GPU 16 - -std::atomic g_thTestPassed(1); - - -/** - * Internal Functions - * Loads the kernel file - */ -static std::vector load_file() { - std::ifstream file(CODEOBJ_FILE, std::ios::binary | std::ios::ate); - std::streamsize fsize = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer(fsize); - if (!file.read(buffer.data(), fsize)) { - INFO("could not open code object " << CODEOBJ_FILE); - REQUIRE(false); - } - return buffer; -} - -/* -Initializes the array -*/ -template -void allocInitArray(unsigned int width, - unsigned int height, - hipArray_Format format, - HIP_ARRAY* array - ) { - HIP_ARRAY_DESCRIPTOR desc; - desc.Format = format; - desc.NumChannels = 1; - desc.Width = width * sizeof(T); - desc.Height = height; - HIPCHECK(hipArrayCreate(array, &desc)); -} - -/* -Copies buffer to array using hipMemcpyParam2D API -*/ -template void copyBuffer2Array(unsigned int width, - unsigned int height, - T* hData, - T1 array - ) { - hip_Memcpy2D copyParam; - memset(©Param, 0, sizeof(copyParam)); -#if HT_NVIDIA - copyParam.dstMemoryType = CU_MEMORYTYPE_ARRAY; - copyParam.srcMemoryType = CU_MEMORYTYPE_HOST; - copyParam.dstArray = *array; -#else - copyParam.dstMemoryType = hipMemoryTypeArray; - copyParam.srcMemoryType = hipMemoryTypeHost; - copyParam.dstArray = array; -#endif - copyParam.srcHost = hData; - copyParam.srcPitch = width * sizeof(T); - copyParam.WidthInBytes = width * sizeof(T); - copyParam.Height = height; - HIPCHECK(hipMemcpyParam2D(©Param)); -} - -/* -Assigns array to texture ref -*/ -template void assignArray2TexRef(hipArray_Format format, - const char* texRefName, - hipModule_t Module, - T array - ) { - HIP_TEX_REFERENCE texref; -#if HT_NVIDIA - HIPCHECK(hipModuleGetTexRef(&texref, Module, texRefName)); - HIPCHECK(hipTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP)); - HIPCHECK(hipTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP)); - HIPCHECK(hipTexRefSetFilterMode(texref, HIP_TR_FILTER_MODE_POINT)); - HIPCHECK(hipTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER)); - HIPCHECK(hipTexRefSetFormat(texref, format, 1)); - HIPCHECK(hipTexRefSetArray(texref, *array, CU_TRSA_OVERRIDE_FORMAT)); -#else - HIPCHECK(hipModuleGetTexRef(&texref, Module, texRefName)); - HIPCHECK(hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap)); - HIPCHECK(hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap)); - HIPCHECK(hipTexRefSetFilterMode(texref, hipFilterModePoint)); - HIPCHECK(hipTexRefSetFlags(texref, HIP_TRSF_READ_AS_INTEGER)); - HIPCHECK(hipTexRefSetFormat(texref, format, 1)); - HIPCHECK(hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT)); -#endif -} - -template bool validateOutput(unsigned int width, - unsigned int height, - T* hData, - T* hOutputData) { - for (unsigned int i = 0; i < height; i++) { - for (unsigned int j = 0; j < width; j++) { - if (hData[i * width + j] != hOutputData[i * width + j]) { - return false; - } - } - } - return true; -} - -/** - * Validates texture functionality with multiple streams for hipModuleGetTexRef - * - */ -template bool testTexMultStream(const std::vector& buffer, - hipArray_Format format, - const char* texRefName, - const char* kerFuncName, - unsigned int numOfStreams) { - bool TestPassed = true; - unsigned int width = WIDTH; - unsigned int height = HEIGHT; - unsigned int size = width * height * sizeof(T); - T* hData = reinterpret_cast(malloc(size)); - CTX_CREATE() - HipTest::setDefaultData(width * height, hData, nullptr, nullptr); - - // Load Kernel File and create hipArray - hipModule_t Module; - HIPCHECK(hipModuleLoadData(&Module, &buffer[0])); - HIP_ARRAY array; - allocInitArray(width, height, format, &array); -#if HT_NVIDIA - // Copy from hData to array using hipMemcpyParam2D - copyBuffer2Array(width, height, hData, &array); - // Get tex reference from the loaded kernel file - // Assign array to the tex reference - assignArray2TexRef(format, texRefName, Module, &array); -#else - // Copy from hData to array using hipMemcpyParam2D - copyBuffer2Array(width, height, hData, array); - // Get tex reference from the loaded kernel file - // Assign array to the tex reference - assignArray2TexRef(format, texRefName, Module, array); -#endif - hipFunction_t Function; - HIPCHECK(hipModuleGetFunction(&Function, Module, kerFuncName)); - - // Create Multiple Strings - hipStream_t streams[MAX_STREAMS]={0}; - T* dData[MAX_STREAMS] = {NULL}; - T* hOutputData[MAX_STREAMS] = {NULL}; - if (numOfStreams > MAX_STREAMS) { - numOfStreams = MAX_STREAMS; - } - unsigned int totalStreamsCreated = 0; - for (unsigned int stream_num = 0; stream_num < numOfStreams; stream_num++) { - hOutputData[stream_num] = reinterpret_cast(malloc(size)); - if (NULL == hOutputData[stream_num]) { - WARN("Failed to allocate using malloc in testTexMultStream"); - TestPassed &= false; - } - HIPCHECK(hipStreamCreate(&streams[stream_num])); - HIPCHECK(hipMalloc(reinterpret_cast(&dData[stream_num]), size)); - memset(hOutputData[stream_num], 0, size); - struct { - void* _Ad; - unsigned int _Bd; - unsigned int _Cd; - } args; - args._Ad = reinterpret_cast(dData[stream_num]); - args._Bd = width; - args._Cd = height; - - size_t sizeTemp = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, - &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, - &sizeTemp, - HIP_LAUNCH_PARAM_END}; - - int temp1 = width / GRIDDIMX; - int temp2 = height / GRIDDIMY; - HIPCHECK(hipModuleLaunchKernel(Function, GRIDDIMX, GRIDDIMY, GRIDDIMZ, - temp1, temp2, BLOCKDIMZ, 0, - streams[stream_num], - NULL, reinterpret_cast(&config))); - totalStreamsCreated++; - } - // Check the kernel results separately - for (unsigned int stream_num = 0; stream_num < totalStreamsCreated; - stream_num++) { - HIPCHECK(hipStreamSynchronize(streams[stream_num])); - HIPCHECK(hipMemcpy(hOutputData[stream_num], dData[stream_num], size, - hipMemcpyDeviceToHost)); - TestPassed &= validateOutput(width, height, hData, - hOutputData[stream_num]); - } - for (unsigned int i = 0; i < totalStreamsCreated; i++) { - HIPCHECK(hipFree(dData[i])); - HIPCHECK(hipStreamDestroy(streams[i])); - free(hOutputData[i]); - } - ARRAY_DESTROY(array) - HIPCHECK(hipModuleUnload(Module)); - free(hData); - CTX_DESTROY() - return TestPassed; -} - -/** - * Internal Thread Functions - * - */ -void launchSingleStreamMultGPU(int gpu, const std::vector& buffer) { - bool TestPassed = true; - HIPCHECK(hipSetDevice(gpu)); - TestPassed = testTexMultStream(buffer, - HIP_AD_FORMAT_FLOAT, - "ftex", - "tex2dKernelFloat", 1); - g_thTestPassed &= static_cast(TestPassed); -} - -void launchMultStreamMultGPU(int gpu, const std::vector& buffer) { - bool TestPassed = true; - HIPCHECK(hipSetDevice(gpu)); - TestPassed = testTexMultStream(buffer, - HIP_AD_FORMAT_FLOAT, - "ftex", - "tex2dKernelFloat", 3); - g_thTestPassed &= static_cast(TestPassed); -} -/** - * Validates texture functionality with Multiple Streams on multuple GPU - * for hipModuleGetTexRef - * - */ -bool testTexMultStreamMultGPU(unsigned int numOfGPUs, - const std::vector& buffer) { - bool TestPassed = true; - std::thread T[MAX_GPU]; - - for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { - T[gpu] = std::thread(launchMultStreamMultGPU, gpu, buffer); - } - for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { - T[gpu].join(); - } - - if (g_thTestPassed) { - TestPassed = true; - } else { - TestPassed = false; - } - return TestPassed; -} - -/** - * Validates texture functionality with Single Stream on multuple GPU - * for hipModuleGetTexRef - * - */ -bool testTexSingleStreamMultGPU(unsigned int numOfGPUs, - const std::vector& buffer) { - bool TestPassed = true; - std::thread T[MAX_GPU]; - - for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { - T[gpu] = std::thread(launchSingleStreamMultGPU, gpu, buffer); - } - for (unsigned int gpu = 0; gpu < numOfGPUs; gpu++) { - T[gpu].join(); - } - - if (g_thTestPassed) { - TestPassed = true; - } else { - TestPassed = false; - } - return TestPassed; -} - -/* -This testcase verifies the negative scenarios of hipModuleGetTexRef API -*/ -TEST_CASE("Unit_hipModuleGetTexRef_Negative") { - hipModule_t Module; - HIP_TEX_REFERENCE texref; - CTX_CREATE() - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - - SECTION("TexRef as nullptr") { - REQUIRE(hipModuleGetTexRef(nullptr, Module, "tex") != hipSuccess); - } - - SECTION("Name as nullptr") { - REQUIRE(hipModuleGetTexRef(&texref, Module, nullptr) != hipSuccess); - } - - SECTION("Name as non existing TexName") { - REQUIRE(hipModuleGetTexRef(&texref, Module, - NON_EXISTING_TEX_NAME) != hipSuccess); - } - - SECTION("Empty tex name") { - REQUIRE(hipModuleGetTexRef(&texref, Module, EMPTY_TEX_NAME) != hipSuccess); - } -#if HT_NVIDIA - SECTION("Name as Global kernel Var") { - REQUIRE(hipModuleGetTexRef(&texref, Module, - GLOBAL_KERNEL_VAR) != hipSuccess); - } -#endif - - SECTION("Unload Module") { - HIP_CHECK(hipModuleUnload(Module)); - REQUIRE(hipModuleGetTexRef(&texref, Module, TEX_REF) != hipSuccess); - } - - CTX_DESTROY() -} -/** - * Validates texture type data functionality for hipModuleGetTexRef - * 1.Loads the code object file - * 2.Based on the template type texRefName,KernelFuncName and format are assigned. - * 3.Allocate array based on format. - * 4.Assigns array to texRef - * 5.Launches the kernel based on the template type which invokes text2D API - and copies the data to output variable. - * 6.Validates the data. - */ -TEMPLATE_TEST_CASE("Unit_hipModuleGetTexRef_Basic", "", int, - char, uint16_t, float) { - bool TestPassed = true; - constexpr unsigned int width = WIDTH; - constexpr unsigned int height = HEIGHT; - constexpr unsigned int size = width * height * sizeof(TestType); - const char *texRefName, *kerFuncName; - hipArray_Format format; - - TestType* hData = reinterpret_cast(malloc(size)); - if (NULL == hData) { - INFO("Failed to allocate using malloc in testTexType.\n"); - REQUIRE(false); - } - CTX_CREATE() - HipTest::setDefaultData(width * height, hData, nullptr, nullptr); - // Load Kernel File and create hipArray - hipModule_t Module; - HIP_CHECK(hipModuleLoad(&Module, CODEOBJ_FILE)); - HIP_ARRAY array; - - if (std::is_same::value) { - texRefName = "ctex"; - kerFuncName = "tex2dKernelInt8"; - format = HIP_AD_FORMAT_SIGNED_INT8; - } else if (std::is_same::value) { - texRefName = "stex"; - kerFuncName = "tex2dKernelInt16"; - format = HIP_AD_FORMAT_SIGNED_INT16; - } else if (std::is_same::value) { - texRefName = "itex"; - kerFuncName = "tex2dKernelInt"; - format = HIP_AD_FORMAT_SIGNED_INT32; - } else if (std::is_same::value) { - texRefName = "ftex"; - kerFuncName = "tex2dKernelFloat"; - format = HIP_AD_FORMAT_FLOAT; - } - allocInitArray(width, height, format, &array); - -#if HT_NVIDIA - // Copy from hData to array using hipMemcpyParam2D - copyBuffer2Array(width, height, hData, &array); - // Get tex reference from the loaded kernel file - // Assign array to the tex reference - assignArray2TexRef(format, texRefName, Module, &array); -#else - // Copy from hData to array using hipMemcpyParam2D - copyBuffer2Array(width, height, hData, array); - // Get tex reference from the loaded kernel file - // Assign array to the tex reference - assignArray2TexRef(format, texRefName, Module, array); -#endif - hipFunction_t Function; - HIP_CHECK(hipModuleGetFunction(&Function, Module, kerFuncName)); - - TestType* dData = NULL; - HIP_CHECK(hipMalloc(reinterpret_cast(&dData), size)); - - struct { - void* _Ad; - unsigned int _Bd; - unsigned int _Cd; - } args; - args._Ad = reinterpret_cast(dData); - args._Bd = width; - args._Cd = height; - - size_t sizeTemp = sizeof(args); - - void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, - &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, - &sizeTemp, - HIP_LAUNCH_PARAM_END}; - - int temp1 = width / GRIDDIMX; - int temp2 = height / GRIDDIMY; - HIP_CHECK( - hipModuleLaunchKernel(Function, GRIDDIMX, GRIDDIMY, GRIDDIMZ, - temp1, temp2, BLOCKDIMZ, 0, 0, - NULL, reinterpret_cast(&config))); - HIP_CHECK(hipDeviceSynchronize()); - TestType* hOutputData = reinterpret_cast(malloc(size)); - if (NULL == hOutputData) { - INFO("Failed to allocate using malloc in testTexType"); - REQUIRE(false); - } else { - memset(hOutputData, 0, size); - HIP_CHECK(hipMemcpy(hOutputData, dData, size, hipMemcpyDeviceToHost)); - TestPassed = validateOutput(width, height, hData, hOutputData); - REQUIRE(TestPassed); - } - free(hOutputData); - HIP_CHECK(hipFree(dData)); - ARRAY_DESTROY(array) - HIP_CHECK(hipModuleUnload(Module)); - free(hData); - CTX_DESTROY() -} - -/* -This testcase verifies hipModuleGetTexRef on multiple streams -where - * 1..Loads the code object file - * 2.Allocate array and initializes it with hData - * 3.Assigns array to texRef - 4.Creates multiple streams - * 4.Launches the kernel on each stream which invokes text2D API - and copies the data to output variable - * 5.Validates the hData with output data in each stream. -*/ -TEST_CASE("Unit_hipModuleGetTexRef_TexMultStream") { - bool TestPassed = true; - auto buffer = load_file(); - TestPassed = testTexMultStream(buffer, - HIP_AD_FORMAT_FLOAT, - "ftex", - "tex2dKernelFloat", - MAX_STREAMS); - REQUIRE(TestPassed); -} -/* -This testcase verifies hipModuleGetTexRef Multithreaded scenario on -single stream and multi GPU machine. -1. Gets the device count. -2. Create the threads based on device count. -3. Each thread calls the testTexMultStream which performs the same - above funtionality on single Stream -4. The threads are executed in parallel and are joined later. - -This testcase ensures that the multi thread execution on single stream -in parallel is successful -*/ -TEST_CASE("Unit_hipModuleGetTexRef_MultiThreadTexSingleStreamMultiGPU") { - bool TestPassed = true; - // Testcase skipped on nvidia with CUDA API version 11.2, - // as hipModuleLoadData returning error code - // 'a PTX JIT compilation failed'(218), which is invalid - // behavior. Test passes with AMD and previous CUDA versions. -#if HT_NVIDIA - INFO("Testcase skipped on CUDA version 11.2\n"); - REQUIRE(true); -#else - int gpu_cnt = 0; - auto buffer = load_file(); - HIP_CHECK(hipGetDeviceCount(&gpu_cnt)); - TestPassed = testTexSingleStreamMultGPU(gpu_cnt, buffer); - REQUIRE(TestPassed); -#endif -} - - -/* -This testcase verifies hipModuleGetTexRef Multithreaded scenario on -single stream and multi GPU machine. -1. Gets the device count. -2. Create the threads based on device count. -3. Each thread calls the testTexMultStream which performs the same - above funtionality on multiple Stream -4. The threads are executed in parallel and are joined later. - -This testcase ensures that the multi thread execution on multiple streams -in parallel is successful -*/ -TEST_CASE("Unit_hipModuleGetTexRef_MultiThreadTexMultiStreamMultiGPU") { - bool TestPassed = true; - // Testcase skipped on nvidia with CUDA API version 11.2, - // as hipModuleLoadData returning error code - // 'a PTX JIT compilation failed'(218), which is invalid - // behavior. Test passes with AMD and previous CUDA versions. -#if HT_NVIDIA - INFO("Testcase skipped on CUDA version 11.2\n"); - REQUIRE(true); -#else - int gpu_cnt = 0; - auto buffer = load_file(); - HIP_CHECK(hipGetDeviceCount(&gpu_cnt)); - TestPassed = testTexMultStreamMultGPU(gpu_cnt, buffer); - REQUIRE(TestPassed); -#endif -} diff --git a/tests/catch/unit/module/hipModuleUnload.cc b/tests/catch/unit/module/hipModuleUnload.cc deleted file mode 100644 index 24c6575d1b..0000000000 --- a/tests/catch/unit/module/hipModuleUnload.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - - - -#include - -#define fileName "module_kernels.code" -/* -This testcase verifies the basic functionality of hipModuleUnload API -*/ -TEST_CASE("Unit_hipModuleUnload_Basic") { - CTX_CREATE() - hipModule_t module; - HIP_CHECK(hipModuleLoad(&module, fileName)); - HIP_CHECK(hipModuleUnload(module)); - CTX_DESTROY() -} diff --git a/tests/catch/unit/module/hipOpenCLCOTest.cc b/tests/catch/unit/module/hipOpenCLCOTest.cc deleted file mode 100644 index 91cfae767a..0000000000 --- a/tests/catch/unit/module/hipOpenCLCOTest.cc +++ /dev/null @@ -1,229 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* -This testcase reads the openCL kernel file and generate the the code object -file which gets executed in HIP interface. -This testcase verifies for the -1. Current GPU architecture -2. Code object version v3 -*/ - -#ifdef __linux__ -#include - #include -#endif -#include -#include "hip_test_common.hh" -#include "hip_test_checkers.hh" - -#define OPENCL_OBJ_FILE "opencl_add.cc" -#define HIP_CODEOBJ_FILE_DEFAULT "opencl_add.co" -#define HIP_CODEOBJ_FILE_V3 "opencl_add_v3.co" -#define COMMAND_LEN 256 -#define BUFFER_LEN 256 - - -#ifdef __linux__ - -/* Check if environment variable $ROCM_PATH is defined */ -static bool isRocmPathSet() { - FILE *fpipe; - char const *command = "echo $ROCM_PATH"; - fpipe = popen(command, "r"); - - if (fpipe == nullptr) { - WARN("Unable to create command"); - return false; - } - char command_op[BUFFER_LEN]; - if (fgets(command_op, BUFFER_LEN, fpipe)) { - size_t len = strlen(command_op); - if (len > 1) { // This is because fgets always adds newline character - pclose(fpipe); - return true; - } - } - pclose(fpipe); - return false; -} - -/* Gets the sramecc/xnack settings from rocm info */ - -int getV3TargetIdFeature(char* feature, bool rocmPathSet) { - FILE *fpipe; - char command[COMMAND_LEN] = ""; - const char *rocmpath = nullptr; - if (rocmPathSet) { - // For STG2 testing where /opt/rocm path is not present - rocmpath = "$ROCM_PATH/bin/rocminfo"; - } else { - // Check if the rocminfo tool exists - rocmpath = "/opt/rocm/bin/rocminfo"; - } - snprintf(command, COMMAND_LEN, "%s", rocmpath); - strncat(command, " | grep -m1 \"sramecc.:xnack.\"", COMMAND_LEN); - fpipe = popen(command, "r"); - - if (fpipe == nullptr) { - WARN("Unable to create command file"); - return -1; - } - char command_op[BUFFER_LEN]; - const char* pOpt1 = nullptr; - const char *pOpt2 = nullptr; - if (fgets(command_op, BUFFER_LEN, fpipe)) { - if (strstr(command_op, "sramecc+")) { - pOpt1 = "-msram-ecc"; - } else if (strstr(command_op, "sramecc-")) { - pOpt1 = "-mno-sram-ecc"; - } else { - pclose(fpipe); - return -1; - } - if (strstr(command_op, "xnack+")) { - pOpt2 = " -mxnack"; - } else if (strstr(command_op, "xnack-")) { - pOpt2 = " -mno-xnack"; - } else { - pclose(fpipe); - return -1; - } - } else { - printf("No sramecc/xnack settings found.\n"); - pclose(fpipe); - return -1; - } - strncpy(feature, pOpt1, strlen(pOpt1)); - strncat(feature, pOpt2, strlen(pOpt2)); - pclose(fpipe); - return 0; -} -#endif -/** - * Validates OpenCL Static Lds Code Object where - * 1. Tries to access opencl kernel file - * 2. Copies it to current folder - * 3. Tries to get RocmPath and execute the kernel file to - generate the code object file.code-object-version argument - specifies the code object version - * 4. Launch the kernel which copies one variable to another - * 5. Validates the result. - */ -TEST_CASE("Unit_hipModuleLoad_OpenCLStaticCodeObjV3") { -#ifdef __linux__ - auto codeobj_type = GENERATE(0, 1); - char command[COMMAND_LEN] = ""; - char v3option[32] = ""; - hipDeviceProp_t props; - hipGetDeviceProperties(&props, 0); - std::string path = std::experimental::filesystem::current_path(); - WARN("path is " << path.c_str()); - if (access("./opencl_add.cc", F_OK) == -1) { - system("cp ./../../../../hip-on-rocclr/tests/catch/unit/module/opencl_add.cc ."); - } - // Generate the command to translate the OpenCL code object to hip code object - const char *pCodeObjVer = nullptr; - const char *pCodeObjFile = nullptr; - bool rocmPathSet = isRocmPathSet(); - if (codeobj_type == 0) { - pCodeObjVer = ""; - pCodeObjFile = HIP_CODEOBJ_FILE_DEFAULT; - } else { - pCodeObjVer = "-mcode-object-version=3"; - if (-1 == getV3TargetIdFeature(v3option, rocmPathSet)) { - INFO("Error getting V3 Option. Skipping Test. \n"); - REQUIRE(true); - } - pCodeObjFile = HIP_CODEOBJ_FILE_V3; - } - INFO("v3option "<< v3option); - /* The command string is created using multiple concatenation instead of one go - to avoid the following cpplint error: - " Multi-line string ("...") found. This lint script doesn't do well with such strings, - and may give bogus warnings. Use C++11 raw strings or concatenation instead." - */ - if (rocmPathSet) { - // For STG2 testing where /opt/rocm path is not present - snprintf(command, COMMAND_LEN, - "$ROCM_PATH/llvm/bin/clang -target amdgcn-amd-amdhsa -x cl "); - } else { - snprintf(command, COMMAND_LEN, - "/opt/rocm/llvm/bin/clang -target amdgcn-amd-amdhsa -x cl "); - } - char command_temp[COMMAND_LEN] = ""; - snprintf(command_temp, COMMAND_LEN, - "-include `find /opt/rocm* -name opencl-c.h` %s %s -mcpu=%s -o %s %s", - pCodeObjVer, v3option, props.gcnArchName, pCodeObjFile, OPENCL_OBJ_FILE); - - strncat(command, command_temp, COMMAND_LEN); - INFO("command executed "<< command); - - system((const char*)command); - // Check if the code object file is created - snprintf(command, COMMAND_LEN, "./%s", - pCodeObjFile); - - if (access(command, F_OK) == -1) { - INFO("Code Object File not found \n"); - REQUIRE(true); - } - - hipDevice_t device; - hipModule_t Module; - hipFunction_t Function; - HIPCHECK(hipDeviceGet(&device, 0)); - HIPCHECK(hipModuleLoad(&Module, pCodeObjFile)); - HIPCHECK(hipModuleGetFunction(&Function, Module, "add")); - float *Ah, *Bh, *Ad, *Bd; - HipTest::initArrays(&Ad, &Bd, nullptr, &Ah, &Bh, nullptr, - BUFFER_LEN, false); - - HIPCHECK(hipMemcpy(Ad, Ah, sizeof(float) * BUFFER_LEN, - hipMemcpyHostToDevice)); - - struct { - void* _Bd; - void* _Ad; - } args; - args._Ad = static_cast(Ad); - args._Bd = static_cast(Bd); - size_t size = sizeof(args); - - void *config[] = { - HIP_LAUNCH_PARAM_BUFFER_POINTER, &args, - HIP_LAUNCH_PARAM_BUFFER_SIZE, &size, - HIP_LAUNCH_PARAM_END - }; - - HIPCHECK(hipModuleLaunchKernel(Function, 1, 1, 1, BUFFER_LEN, 1, 1, 0, 0, - NULL, reinterpret_cast(&config))); - HIPCHECK(hipMemcpy(Bh, Bd, sizeof(float) * BUFFER_LEN, - hipMemcpyDeviceToHost)); - - for (uint32_t i = 0; i < BUFFER_LEN; i++) { - REQUIRE(Ah[i] == Bh[i]); - } - HipTest::freeArrays(Ad, Bd, nullptr, - Ah, Bh, nullptr, false); -#else - INFO("This test is skipped due to non linux environment.\n"); - REQUIRE(true); -#endif -} diff --git a/tests/catch/unit/module/module_kernels.cc b/tests/catch/unit/module/module_kernels.cc deleted file mode 100644 index ccb9c204ea..0000000000 --- a/tests/catch/unit/module/module_kernels.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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. -*/ - -#include -#include "hip/hip_runtime.h" - -#define GLOBAL_BUF_SIZE 2048 -#define ARRAY_SIZE (16) - -texture ftex; -texture itex; -texture stex; -texture ctex; - -__device__ int deviceGlobal = 1; -__managed__ int x = 10; -__device__ float myDeviceGlobal; -__device__ float myDeviceGlobalArray[16]; - - -__device__ float deviceGlobalFloat; -__device__ int deviceGlobalInt1; -__device__ int deviceGlobalInt2; -__device__ uint16_t deviceGlobalShort; -__device__ char deviceGlobalChar; - -extern "C" __global__ void tex2dKernelFloat(float* outputData, - int width, int height) { - int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; - int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; - if ((x < width) && (y < width)) { - outputData[y * width + x] = tex2D(ftex, x, y); - } -} - -extern "C" __global__ void tex2dKernelInt(int* outputData, - int width, int height) { - int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; - int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; - if ((x < width) && (y < width)) { - outputData[y * width + x] = tex2D(itex, x, y); - } -} - -extern "C" __global__ void tex2dKernelInt16(uint16_t* outputData, - int width, int height) { - int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; - int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; - if ((x < width) && (y < width)) { - outputData[y * width + x] = tex2D(stex, x, y); - } -} - -extern "C" __global__ void tex2dKernelInt8(char* outputData, - int width, int height) { - int x = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x; - int y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; - if ((x < width) && (y < width)) { - outputData[y * width + x] = tex2D(ctex, x, y); - } -} - -extern "C" __global__ void matmulK(int clockrate, int* A, int* B, int* C, - int N) { - int ROW = blockIdx.y*blockDim.y+threadIdx.y; - int COL = blockIdx.x*blockDim.x+threadIdx.x; - int tmpSum = 0; - if ((ROW < N) && (COL < N)) { - // each thread computes one element of the block sub-matrix - for (int i = 0; i < N; i++) { - tmpSum += A[ROW * N + i] * B[i * N + COL]; - } - C[ROW * N + COL] = tmpSum; - } -} - -extern "C" __global__ void KernelandExtraParams(int* A, int* B, int* C, - int *D, int N) { - int ROW = blockIdx.y*blockDim.y+threadIdx.y; - int COL = blockIdx.x*blockDim.x+threadIdx.x; - int tmpSum = 0; - if (ROW < N && COL < N) { - // each thread computes one element of the block sub-matrix - for (int i = 0; i < N; i++) { - tmpSum += A[ROW * N + i] * B[i * N + COL]; - } - } - C[ROW * N + COL] = tmpSum; - D[ROW * N + COL] = tmpSum; -} - -extern "C" __global__ void SixteenSecKernel(int clockrate) { - HipTest::waitKernel(16, clockrate); -} - -extern "C" __global__ void TwoSecKernel(int clockrate) { - if (deviceGlobal == 0x2222) { - deviceGlobal = 0x3333; - } - - HipTest::waitKernel(2, clockrate); - - if (deviceGlobal != 0x3333) { - deviceGlobal = 0x5555; - } -} - -extern "C" __global__ void FourSecKernel(int clockrate) { - if (deviceGlobal == 1) { - deviceGlobal = 0x2222; - } - - HipTest::waitKernel(4, clockrate); - - if (deviceGlobal == 0x2222) { - deviceGlobal = 0x4444; - } -} - -extern "C" __global__ void GPU_func() { - x++; -} - - -__device__ int getSquareOfGlobalFloat() { - return static_cast(deviceGlobalFloat*deviceGlobalFloat); -} - -extern "C" __global__ void testWeightedCopy(int* a, int* b) { - int tx = hipThreadIdx_x; - b[tx] = deviceGlobalInt1*a[tx] + deviceGlobalInt2 + - static_cast(deviceGlobalShort) + static_cast(deviceGlobalChar) - + getSquareOfGlobalFloat(); -} - - -extern "C" __global__ void hello_world(const float* a, float* b) { - int tx = hipThreadIdx_x; - b[tx] = a[tx]; -} - -extern "C" __global__ void test_globals(const float* a, float* b) { - int tx = hipThreadIdx_x; - b[tx] = a[tx] + myDeviceGlobal + myDeviceGlobalArray[tx % ARRAY_SIZE]; -} - -extern "C" __global__ void EmptyKernel() { -} diff --git a/tests/catch/unit/module/opencl_add.cc b/tests/catch/unit/module/opencl_add.cc deleted file mode 100644 index 267ffc7f3b..0000000000 --- a/tests/catch/unit/module/opencl_add.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright (c) 2021 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 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANNTY OF ANY KIND, EXPRESS OR -IMPLIED, INNCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANNY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER INN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR INN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -kernel void add(global float* output, global float* input) { - __local float lds[100]; - int id = get_global_id(0); - - if (id == 0) { - for (int i = 0; i < 100; i++) { - lds[i] = input[i]; - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - if (id < 100) { - output[id] = lds[id]; - } else { - output[id] = input[id]; - } -} From c2ce476d09d80fe5ae088ab7084a646ef306c437 Mon Sep 17 00:00:00 2001 From: Julia Jiang <56359287+jujiang-del@users.noreply.github.com> Date: Mon, 20 Sep 2021 02:43:01 -0400 Subject: [PATCH 8/9] SWDEV-300860 - Add summary of HIP environment variables in hip_debugging.md (#2352) Change-Id: Id36dce73346fa5a3259257c78f0cf289f9b9f41a --- docs/markdown/hip_debugging.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/docs/markdown/hip_debugging.md b/docs/markdown/hip_debugging.md index 1ebb83352e..8215db17c8 100644 --- a/docs/markdown/hip_debugging.md +++ b/docs/markdown/hip_debugging.md @@ -127,7 +127,7 @@ Breakpoint 1, main () ``` ### Other Debugging Tools -There are also other debugging tools availble online developers can google and choose the one best suits the debugging requirements. +There are also other debugging tools available online developers can google and choose the one best suits the debugging requirements. ## Debugging HIP Applications @@ -192,7 +192,7 @@ AMD_SERIALIZE_COPY, for serializing copies. So HIP runtime can wait for GPU idle before/after any GPU command depending on the environment setting. ### Making Device visible -For system with multiple devices, it's possible to make only certain device(s) visible to HIP via setting environment varible, +For system with multiple devices, it's possible to make only certain device(s) visible to HIP via setting environment variable, HIP_VISIBLE_DEVICES, only devices whose index is present in the sequence are visible to HIP. For example, @@ -200,7 +200,7 @@ For example, $ HIP_VISIBLE_DEVICES=0,1 ``` -or in the appliation, +or in the application, ``` if (totalDeviceNum > 2) { setenv("HIP_VISIBLE_DEVICES", "0,1,2", 1); @@ -210,11 +210,11 @@ if (totalDeviceNum > 2) { ``` ### Dump code object -Developers can dump code object to anylize compiler related issues via setting environment variable, +Developers can dump code object to analyze compiler related issues via setting environment variable, GPU_DUMP_CODE_OBJECT ### HSA related environment variables -HSA provides some environment varibles help to analize issues in driver or hardware, for example, +HSA provides some environment variables help to analyze issues in driver or hardware, for example, HSA_ENABLE_SDMA=0 It causes host-to-device and device-to-host copies to use compute shader blit kernels rather than the dedicated DMA copy engines. @@ -225,8 +225,24 @@ HSA_ENABLE_INTERRUPT=0 Causes completion signals to be detected with memory-based polling rather than interrupts. This environment variable can be useful to diagnose interrupt storm issues in the driver. +### Summary of environment variables in HIP + +The following is the summary of the most useful environment variables in HIP. + +| **Environment variable** | **Default value** | **Usage** | +| ---------------------------------------------------------------------------------------------------------------| ----------------- | --------- | +| AMD_LOG_LEVEL
Enable HIP log on different Level. | 0 | 0: Disable log.
1: Enable log on error level.
2: Enable log on warning and below levels.
0x3: Enable log on information and below levels.
0x4: Decode and display AQL packets. | +| AMD_LOG_MASK
Enable HIP log on different Level. | 0x7FFFFFFF | 0x1: Log API calls.
0x02: Kernel and Copy Commands and Barriers.
0x4: Synchronization and waiting for commands to finish.
0x8: Enable log on information and below levels.
0x20: Queue commands and queue contents.
0x40:Signal creation, allocation, pool.
0x80: Locks and thread-safety code.
0x100: Copy debug.
0x200: Detailed copy debug.
0x400: Resource allocation, performance-impacting events.
0x800: Initialization and shutdown.
0x1000: Misc debug, not yet classified.
0x2000: Show raw bytes of AQL packet.
0x4000: Show code creation debug.
0x8000: More detailed command info, including barrier commands.
0x10000: Log message location.
0xFFFFFFFF: Log always even mask flag is zero. | +| HIP_VISIBLE_DEVICES
Only devices whose index is present in the sequence are visible to HIP. | | 0,1,2: Depending on the number of devices on the system. | +| GPU_DUMP_CODE_OBJECT
Dump code object. | 0 | 0: Disable.
1: Enable. | +| AMD_SERIALIZE_KERNEL
Serialize kernel enqueue. | 0 | 1: Wait for completion before enqueue.
2: Wait for completion after enqueue.
3: Both. | +| AMD_SERIALIZE_COPY
Serialize copies. | 0 | 1: Wait for completion before enqueue.
2: Wait for completion after enqueue.
3: Both. | +| HIP_HOST_COHERENT
Coherent memory in hipHostMalloc. | 0 | 0: memory is not coherent between host and GPU.
1: memory is coherent with host. | +| AMD_DIRECT_DISPATCH
Enable direct kernel dispatch. | 0 | 0: Disable.
1: Enable. | + + ## General Debugging Tips -- 'gdb --args' can be used to conviently pass the executable and arguments to gdb. +- 'gdb --args' can be used to conveniently pass the executable and arguments to gdb. - From inside GDB, you can set environment variables "set env". Note the command does not use an '=' sign: ``` From 2312cf8ad34218ad24a79056b1e3b30c23381a4b Mon Sep 17 00:00:00 2001 From: Julia Jiang <56359287+jujiang-del@users.noreply.github.com> Date: Mon, 20 Sep 2021 02:43:40 -0400 Subject: [PATCH 9/9] SWDEV-302172 - update Coherenty control in HIP programming (#2353) Change-Id: I5ec4e2afd8b3759ded954d0de7486fdf51a412b5 --- docs/markdown/hip_programming_guide.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/markdown/hip_programming_guide.md b/docs/markdown/hip_programming_guide.md index 08a2374aa8..94183bb6f9 100644 --- a/docs/markdown/hip_programming_guide.md +++ b/docs/markdown/hip_programming_guide.md @@ -66,12 +66,15 @@ ROCm defines two coherency options for host memory: - Non-coherent memory : Can be cached by GPU, but cannot support synchronization while the kernel is running.  Non-coherent memory can be optionally synchronized only at command (end-of-kernel or copy command) boundaries.  This memory is appropriate for high-performance access when fine-grain synchronization is not required. HIP provides the developer with controls to select which type of memory is used via allocation flags passed to hipHostMalloc and the HIP_HOST_COHERENT environment variable. By default, the environment variable HIP_HOST_COHERENT is set to 0 in HIP. -- hipHostMallocCoherent=0, hipHostMallocNonCoherent=0: Use HIP_HOST_COHERENT environment variable, +The control logic in the current version of HIP is as follows: +- No flags are passed in: the host memory allocation is coherent, the HIP_HOST_COHERENT environment variable is ignored. +- hipHostMallocCoherent=1: The host memory allocation will be coherent, the HIP_HOST_COHERENT environment variable is ignored. +- hipHostMallocMapped=1: The host memory allocation will be coherent, the HIP_HOST_COHERENT environment variable is ignored. +- hipHostMallocNonCoherent=1, hipHostMallocCoherent=0, and hipHostMallocMapped=0: The host memory will be non-coherent, the HIP_HOST_COHERENT environment variable is ignored. +- hipHostMallocCoherent=0, hipHostMallocNonCoherent=0, hipHostMallocMapped=0, but one of the other HostMalloc flags is set: - If HIP_HOST_COHERENT is defined as 1, the host memory allocation is coherent. - If HIP_HOST_COHERENT is not defined, or defined as 0, the host memory allocation is non-coherent. -- hipHostMallocCoherent=1, hipHostMallocNonCoherent=0: The host memory allocation will be coherent.  HIP_HOST_COHERENT env variable is ignored. -- hipHostMallocCoherent=0, hipHostMallocNonCoherent=1: The host memory allocation will be non-coherent.  HIP_HOST_COHERENT env variable is ignored. -- hipHostMallocCoherent=1, hipHostMallocNonCoherent=1: Illegal. +- hipHostMallocCoherent=1, hipHostMallocNonCoherent=1: Illegal. ### Visibility of Zero-Copy Host Memory Coherent host memory is automatically visible at synchronization points.