Added testing for hipMemGetInfo (#2682)

This commit is contained in:
Anton Mitkov
2022-07-28 11:15:42 +01:00
committato da GitHub
parent 1c4822f24a
commit 9eae1e0f53
2 ha cambiato i file con 431 aggiunte e 0 eliminazioni
@@ -91,6 +91,7 @@ set(TEST_SRC
hipMemPrefetchAsync.cc
hipArray.cc
hipMemVmm.cc
hipMemGetInfo.cc
)
else()
set(TEST_SRC
@@ -157,6 +158,7 @@ set(TEST_SRC
hipPointerGetAttribute.cc
hipDrvPtrGetAttributes.cc
hipMemPrefetchAsync.cc
hipMemGetInfo.cc
)
endif()
+429
Vedi File
@@ -0,0 +1,429 @@
/*
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>
#include <thread>
#include <vector>
/*
* This testcase verifies hipMemGetInfo API
* 1. Different memory chunk allocation
* 1.1. hipMalloc
* 1.2. hipMallocArray
* 1.3. hipMalloc3D
* 1.3. hipMalloc3DArray
* 2. Allocation using different threads
* 3. Negative: Invalid args
*/
struct MinAlloc {
private:
int value;
MinAlloc() {
size_t freeMemInit;
size_t totalMemInit;
unsigned int* A_mem{nullptr};
size_t mallocSize{1};
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
// allocate 1 byte
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), mallocSize));
size_t freeMemRet;
size_t totalMemRet;
// actual allocation should be bigger to reflect the minimum allocation on device
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
REQUIRE(freeMemInit >= freeMemRet);
HIP_CHECK(hipFree(A_mem));
// store the size of minimum allocation
value = (freeMemInit - freeMemRet);
}
public:
static int Get() {
static MinAlloc instance;
return instance.value;
}
};
// if the memory being allocated is not divisible by the minimum allocation add an extra minimum
// allocation AddedAllocation = InitialAllocation + (MinAllocation - divisionRemainer)
void fixAllocSize(size_t& allocation) {
REQUIRE(MinAlloc::Get() != 0);
if (allocation % MinAlloc::Get() != 0) {
auto adjustment = allocation % MinAlloc::Get();
adjustment = MinAlloc::Get() - adjustment;
allocation = allocation + adjustment;
}
}
// Print information about memory
#define MEMINFO(totalMem, freeMemInit, freeMemRet, usedMem) \
INFO("Total memory: \t\t\t" << totalMem << "\n" \
<< "Memory used: \t\t\t\t" << freeMemInit - freeMemRet << "\n" \
<< "Free memory after alloc: \t\t" << freeMemRet << "\n" \
<< "Free memory initally: \t\t" << freeMemInit << "\n" \
<< "Memory assumed to be used: \t\t" << usedMem);
TEST_CASE("Unit_hipMemGetInfo_DifferentMallocLarge") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
unsigned int* B_mem{nullptr};
size_t freeMemRet;
size_t totalMemRet;
int device;
HIP_CHECK(hipGetDevice(&device));
hipDeviceProp_t prop;
HIP_CHECK(hipGetDeviceProperties(&prop, device));
auto totalMemory = prop.totalGlobalMem;
// allocate half of free mem
auto Malloc1Size = freeMemInit >> 1;
// if the allocation is not divisible by the MinAllocation
// take into account and add padding
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), Malloc1Size));
// allocate an extra quarter of free mem
auto Malloc2Size = Malloc1Size >> 1;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&B_mem), Malloc2Size));
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
MEMINFO(totalMemRet, freeMemInit, freeMemRet, Malloc1Size + Malloc2Size);
// check if device property total memory is the same as
// total memory returned from hipMemGetInfo
REQUIRE(totalMemory == totalMemRet);
auto allocSize = Malloc1Size + Malloc2Size;
auto assumedFreeMem = freeMemInit - allocSize;
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFree(A_mem));
HIP_CHECK(hipFree(B_mem));
}
TEST_CASE("Unit_hipMemGetInfo_DifferentMallocSmall") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
size_t freeMemRet;
size_t totalMemRet;
// allocate smaller chunk than minimum
size_t Malloc1Size = 1;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), Malloc1Size));
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
MEMINFO(totalMemRet, freeMemInit, freeMemRet, Malloc1Size);
auto assumedFreeMem = freeMemInit - Malloc1Size;
// Free memory should be less than assumed for
// single allocation smaller than min allocation chunk
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFree(A_mem));
}
TEST_CASE("Unit_hipMemGetInfo_DifferentMallocMultiSmall") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
unsigned int* B_mem{nullptr};
size_t freeMemRet;
size_t totalMemRet;
// Allocate memory that is a quarter of the min allocation
// Expected behaviour is to reuse the min allocation memory
size_t MallocSize = MinAlloc::Get() >> 2;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), MallocSize));
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&B_mem), MallocSize));
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
MEMINFO(totalMemRet, freeMemInit, freeMemRet, MallocSize * 2);
auto assumedFreeMem = freeMemInit - (MallocSize * 2);
// Confirm mem alocation results
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFree(A_mem));
HIP_CHECK(hipFree(B_mem));
}
TEMPLATE_TEST_CASE("Unit_hipMemGetInfo_MallocArray", "", int, int4, char) {
// get initial mem data
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
// create and allocate an Array
hipArray_t arrayPtr{};
auto bytesPerItem = sizeof(TestType);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
hipExtent extent{};
extent.width = GENERATE(32, 128, 256, 512, 1024);
extent.height = GENERATE(0, 32, 128, 256, 512, 1024);
HIP_CHECK(hipMallocArray(&arrayPtr, &desc, extent.width, extent.height, hipArrayDefault));
// check if memory is correct
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
// calculate used memory, take into account 1D array (height = 0)
size_t usedMem = bytesPerItem * extent.width * (extent.height != 0 ? extent.height : 1);
// ensure we allocate at least the min allocation for the array
MEMINFO(totalMemRet, freeMemInit, freeMemRet, usedMem);
size_t assumedFreeMem = freeMemInit - usedMem;
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFreeArray(arrayPtr));
}
TEST_CASE("Unit_hipMemGetInfo_Malloc3D") {
// Get initial memory
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
// Allocate 3D object
hipExtent extent{};
// extent is given in bytes for with
extent.width = GENERATE(32, 128, 256);
extent.height = GENERATE(32, 128, 256);
extent.depth = GENERATE(32, 128, 256);
hipPitchedPtr A_mem{};
HIP_CHECK(hipMalloc3D(&A_mem, extent));
// Get memory after allocation
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
// Verify result
size_t mallocSize = A_mem.pitch * extent.height * extent.depth;
size_t assumedFreeMem = freeMemInit - mallocSize;
MEMINFO(totalMemRet, freeMemInit, freeMemRet, mallocSize);
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFree(A_mem.ptr));
}
TEMPLATE_TEST_CASE("Unit_hipMemGetInfo_Malloc3DArray", "", char, int, int4) {
// Get initial memory
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
// Allocate 3D object
hipArray_t arrayPtr{};
size_t sizeInBytes = (size_t)sizeof(TestType);
hipChannelFormatDesc desc = hipCreateChannelDesc<TestType>();
int device;
HIP_CHECK(hipGetDevice(&device));
int allignSize{0};
hipDeviceGetAttribute(&allignSize, hipDeviceAttributeTextureAlignment, device);
#if HT_NVIDIA
auto flag = GENERATE(hipArrayDefault, hipArrayLayered, hipArrayCubemap,
hipArrayLayered | hipArrayCubemap);
#else
// hipArrayCubemap not supported on AMD
auto flag = GENERATE(hipArrayDefault, hipArrayLayered);
#endif
hipExtent extent{};
extent.width = GENERATE(32, 128, 256, 512);
extent.height = GENERATE(0, 32, 128, 256, 512);
if (flag == hipArrayCubemap) {
// width must be equal to height, and depth must be six.
extent.height = extent.width;
extent.depth = 6;
} else if (flag == hipArrayLayered | hipArrayCubemap) {
// width must be equal to height, and depth must be a multiple six.
extent.height = extent.width;
extent.depth = 6 * GENERATE(4, 8, 16, 32);
} else if (extent.height == 0 && flag != hipArrayLayered) {
// if height = 0 the depth must be 0 unless using hipArrayLayered flag
extent.depth = 0;
} else {
extent.depth = GENERATE(32, 128, 256, 512);
}
// Get memory after allocation
auto h = extent.height == 0 ? 1 : extent.height;
auto d = extent.depth == 0 ? 1 : extent.depth;
auto w = extent.width * sizeInBytes;
size_t mallocSize = w * h * d;
HIP_CHECK(hipMalloc3DArray(&arrayPtr, &desc, extent, flag));
// Verify result
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
// Sometimes hipMemGetInfo reports that no new memory has be allocated for testcase
// take this into account
if (freeMemInit == freeMemRet) {
// no new memory allocation has occured verify that memory trying
// to be allocated is less than a min allocation block
MEMINFO(totalMemRet, freeMemInit, freeMemRet, mallocSize);
REQUIRE(mallocSize <= static_cast<size_t>(MinAlloc::Get()));
} else {
MEMINFO(totalMemRet, freeMemInit, freeMemRet, mallocSize);
size_t assumedFreeMem = freeMemInit - mallocSize;
REQUIRE(freeMemRet <= assumedFreeMem);
}
HIP_CHECK(hipFreeArray(arrayPtr));
}
TEST_CASE("Unit_hipMemGetInfo_ParaLarge") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
unsigned int* B_mem{nullptr};
// allocate half of free mem
auto Malloc1Size = freeMemInit >> 1;
// if the allocation is not divisible by the MinAllocation
// take into account and add padding
std::thread t1(
[&] { HIP_CHECK_THREAD(hipMalloc(reinterpret_cast<void**>(&A_mem), Malloc1Size)); });
// allocate an extra quarter of free mem
auto Malloc2Size = Malloc1Size >> 1;
std::thread t2(
[&] { HIP_CHECK_THREAD(hipMalloc(reinterpret_cast<void**>(&B_mem), Malloc2Size)); });
t1.join();
t2.join();
HIP_CHECK_THREAD_FINALIZE();
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
MEMINFO(totalMemRet, freeMemInit, freeMemRet, Malloc1Size + Malloc2Size);
auto allocSize = Malloc1Size + Malloc2Size;
REQUIRE(freeMemRet <= freeMemInit - allocSize);
HIP_CHECK(hipFree(A_mem));
HIP_CHECK(hipFree(B_mem));
}
TEST_CASE("Unit_hipMemGetInfo_ParaSmall") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
// allocate smaller chunk than minimum
size_t Malloc1Size = 1;
std::thread t1(
[&] { HIP_CHECK_THREAD(hipMalloc(reinterpret_cast<void**>(&A_mem), Malloc1Size)) });
t1.join();
HIP_CHECK_THREAD_FINALIZE();
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
MEMINFO(totalMemRet, freeMemInit, freeMemRet, Malloc1Size);
auto assumedFreeMem = freeMemInit - Malloc1Size;
// Free memory should be less than assumed for
// single allocation smaller than min allocation chunk
REQUIRE(freeMemRet <= assumedFreeMem);
HIP_CHECK(hipFree(A_mem));
}
TEST_CASE("Unit_hipMemGetInfo_Negative") {
size_t freeMemInit;
size_t totalMemInit;
HIP_CHECK(hipMemGetInfo(&freeMemInit, &totalMemInit));
unsigned int* A_mem{nullptr};
auto MallocSize = MinAlloc::Get();
SECTION("Zero allocation") {
size_t freeMemRet;
size_t totalMemRet;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), 0));
HIP_CHECK(hipMemGetInfo(&freeMemRet, &totalMemRet));
REQUIRE(freeMemRet == freeMemInit);
}
SECTION("Nullptr as first param passed to hipMemGetInfo") {
size_t* freeMemRet = nullptr;
size_t totalMemRet;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), MallocSize));
// Segfaults on AMD and returns hipSuccess on Nvidia
HIP_CHECK(hipMemGetInfo(freeMemRet, &totalMemRet));
}
SECTION("Nullptr as second param passed to hipMemGetInfo") {
size_t freeMemRet;
size_t* totalMemRet = nullptr;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), MallocSize));
// Segfaults on AMD and returns hipSuccess on Nvidia
HIP_CHECK(hipMemGetInfo(&freeMemRet, totalMemRet));
}
SECTION("Nullptr as both params passed to hipMemGetInfo") {
#if HT_AMD
HipTest::HIP_SKIP_TEST("EXSWCPHIPT-135");
return;
#endif
size_t* freeMemRet = nullptr;
size_t* totalMemRet = nullptr;
HIP_CHECK(hipMalloc(reinterpret_cast<void**>(&A_mem), MallocSize));
// Segfaults on AMD and returns hipSuccess on Nvidia
HIP_CHECK(hipMemGetInfo(freeMemRet, totalMemRet));
}
HIP_CHECK(hipFree(A_mem));
}