2
0

EXSWHTEC-364 - Implement tests for hipMemPoolSetGetAccess and hipMemPoolSetGetAttribute APIs (#435)

Change-Id: I9a9bd22f99e2be60608d50fe649e92b3b267f655
Este cometimento está contido em:
Nives Vukovic
2023-12-01 12:46:08 +01:00
cometido por Rakesh Roy
ascendente 26a5250673
cometimento 7ffbf7f76b
6 ficheiros modificados com 1062 adições e 0 eliminações
+8
Ver ficheiro
@@ -144,6 +144,14 @@ THE SOFTWARE.
* @}
*/
/**
* @defgroup StreamOTest Ordered Memory Allocator
* @{
* This section describes the tests for Stream Ordered Memory Allocator functions of HIP runtime
* API.
* @}
*/
/**
* @defgroup StreamTest Stream Management
* @{
+42
Ver ficheiro
@@ -346,3 +346,45 @@ class StreamsGuard {
private:
std::vector<hipStream_t> streams_;
};
enum class MemPools { dev_default, created };
class MemPoolGuard {
public:
MemPoolGuard(const MemPools mempool_type, int device,
hipMemAllocationHandleType handle_type = hipMemHandleTypeNone)
: mempool_type_{mempool_type}, device_{device}, handle_type_{handle_type} {
switch (mempool_type_) {
case MemPools::dev_default:
HIP_CHECK(hipDeviceGetDefaultMemPool(&mempool_, device_));
break;
case MemPools::created:
hipMemPoolProps pool_props;
pool_props.allocType = hipMemAllocationTypePinned;
pool_props.handleTypes = handle_type_;
pool_props.location.type = hipMemLocationTypeDevice;
pool_props.location.id = device_;
pool_props.win32SecurityAttributes = nullptr;
memset(pool_props.reserved, 0, sizeof(pool_props.reserved));
HIP_CHECK(hipMemPoolCreate(&mempool_, &pool_props));
}
}
MemPoolGuard(const MemPoolGuard&) = delete;
MemPoolGuard(MemPoolGuard&&) = delete;
~MemPoolGuard() {
if (mempool_type_ == MemPools::created) {
static_cast<void>(hipMemPoolDestroy(mempool_));
}
}
hipMemPool_t mempool() const { return mempool_; }
private:
const MemPools mempool_type_;
int device_;
hipMemAllocationHandleType handle_type_;
hipMemPool_t mempool_;
};
+2
Ver ficheiro
@@ -107,6 +107,8 @@ set(TEST_SRC
hipMemcpyFromSymbol.cc
hipPtrGetAttribute.cc
hipMemPoolApi.cc
hipMemPoolSetGetAccess.cc
hipMemPoolSetGetAttribute.cc
hipMemcpyPeer.cc
hipMemcpyPeer_old.cc
hipMemcpyPeerAsync.cc
+361
Ver ficheiro
@@ -0,0 +1,361 @@
/*
Copyright (c) 2023 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 <hip_test_common.hh>
#include <resource_guards.hh>
#include <utils.hh>
/**
* @addtogroup hipMemPoolSetAccess hipMemPoolSetAccess
* @{
* @ingroup StreamOTest
* `hipMemPoolSetAccess(hipMemPool_t mem_pool, const hipMemAccessDesc* desc_list, size_t count)`
* - Controls visibility of the specified pool between devices
*/
__global__ void copyP2PAndScale(int* dst, const int* src, size_t N) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N) {
// scale & store src vector.
dst[idx] = 2 * src[idx];
}
}
static void MemPoolSetGetAccess(const MemPools mempool_type, int src_device, int dst_device,
hipMemAccessFlags access_flags) {
MemPoolGuard mempool(mempool_type, src_device);
hipMemAccessDesc desc;
memset(&desc, 0, sizeof(hipMemAccessDesc));
desc.location.type = hipMemLocationTypeDevice;
desc.location.id = dst_device;
desc.flags = access_flags;
HIP_CHECK(hipMemPoolSetAccess(mempool.mempool(), &desc, 1));
hipMemAccessFlags flags = hipMemAccessFlagsProtNone;
HIP_CHECK(hipMemPoolGetAccess(&flags, mempool.mempool(), &desc.location));
REQUIRE(flags == access_flags);
}
/**
* Test Description
* ------------------------
* - Basic test to verify hipMemPoolSetAccess/hipMemPoolGetAccess on a single device.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAccess.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetGetAccess_Positive_Basic") {
const auto device = GENERATE(range(0, HipTest::getDeviceCount()));
int mem_pool_support = 0;
HIP_CHECK(
hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, device));
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
const auto mempool_type = GENERATE(MemPools::dev_default, MemPools::created);
MemPoolSetGetAccess(mempool_type, device, device, hipMemAccessFlagsProtReadWrite);
}
int CheckP2PMemPoolSupport(int src_device, int dst_device) {
int mem_pool_support = 0;
HIP_CHECK(
hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, src_device));
if (mem_pool_support) {
HIP_CHECK(hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported,
dst_device));
}
return mem_pool_support;
}
/**
* Test Description
* ------------------------
* - Basic test to verify hipMemPoolSetAccess/hipMemPoolGetAccess on multiple devices.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAccess.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetGetAccess_Positive_MultipleGPU") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
const auto src_device = GENERATE(range(0, HipTest::getDeviceCount()));
const auto dst_device = GENERATE(range(0, HipTest::getDeviceCount()));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
int mem_pool_support = CheckP2PMemPoolSupport(src_device, dst_device);
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
const auto mempool_type = GENERATE(MemPools::dev_default, MemPools::created);
const auto access_flag = GENERATE(hipMemAccessFlagsProtNone, hipMemAccessFlagsProtRead,
hipMemAccessFlagsProtReadWrite);
int can_access_peer = 0;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
MemPoolSetGetAccess(mempool_type, src_device, dst_device, access_flag);
}
}
void MemPoolSetGetAccess_P2P(const MemPools mempool_type) {
const auto src_device = GENERATE(range(0, HipTest::getDeviceCount()));
const auto dst_device = GENERATE(range(0, HipTest::getDeviceCount()));
INFO("Src device: " << src_device << ", Dst device: " << dst_device);
const auto allocation_size = GENERATE(kPageSize / 2, kPageSize, kPageSize * 2);
int mem_pool_support = CheckP2PMemPoolSupport(src_device, dst_device);
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
int *alloc_mem1, *alloc_mem2;
int can_access_peer = 0;
HIP_CHECK(hipSetDevice(src_device));
HIP_CHECK(hipDeviceCanAccessPeer(&can_access_peer, src_device, dst_device));
if (can_access_peer) {
hipEvent_t waitOnStream1;
LinearAllocGuard<int> host_alloc(LinearAllocs::malloc, allocation_size);
HIP_CHECK(hipEventCreate(&waitOnStream1))
StreamGuard stream1(Streams::withFlags, hipStreamNonBlocking);
// Get/create mempool for src_device
MemPoolGuard mempool(mempool_type, src_device);
// Allocate memory in a stream from the pool set above
if (mempool_type == MemPools::dev_default) {
HIP_CHECK(
hipMallocAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size, stream1.stream()));
} else {
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
}
const auto element_count = allocation_size / sizeof(int);
constexpr auto thread_count = 1024;
const auto block_count = element_count / thread_count + 1;
constexpr int expected_value = 15;
VectorSet<<<block_count, thread_count, 0, stream1.stream()>>>(alloc_mem1, expected_value,
element_count);
HIP_CHECK(hipEventRecord(waitOnStream1, stream1.stream()));
HIP_CHECK(hipSetDevice(dst_device));
StreamGuard stream2(Streams::withFlags, hipStreamNonBlocking);
// Allocate memory in dst device
HIP_CHECK(
hipMallocAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size, stream2.stream()));
// Setup peer mappings for dst device
hipMemAccessDesc desc;
memset(&desc, 0, sizeof(hipMemAccessDesc));
desc.location.type = hipMemLocationTypeDevice;
desc.location.id = dst_device;
desc.flags = hipMemAccessFlagsProtReadWrite;
HIP_CHECK(hipMemPoolSetAccess(mempool.mempool(), &desc, 1));
hipMemAccessFlags flags = hipMemAccessFlagsProtNone;
HIP_CHECK(hipMemPoolGetAccess(&flags, mempool.mempool(), &desc.location));
REQUIRE(flags == hipMemAccessFlagsProtReadWrite);
HIP_CHECK(hipStreamWaitEvent(stream2.stream(), waitOnStream1, 0));
copyP2PAndScale<<<block_count, thread_count, 0, stream2.stream()>>>(alloc_mem2, alloc_mem1,
element_count);
HIP_CHECK(hipMemcpyAsync(host_alloc.host_ptr(), alloc_mem2, allocation_size,
hipMemcpyDeviceToHost, stream2.stream()));
HIP_CHECK(hipFreeAsync(alloc_mem1, stream2.stream()));
HIP_CHECK(hipFreeAsync(alloc_mem2, stream2.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
ArrayFindIfNot(host_alloc.host_ptr(), 2 * expected_value, element_count);
}
}
/**
* Test Description
* ------------------------
* - Basic test to verify peer-to-peer access of stream ordered memory with hipMemPoolSetAccess.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAccess.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetGetAccess_Positive_P2P") {
const auto device_count = HipTest::getDeviceCount();
if (device_count < 2) {
HipTest::HIP_SKIP_TEST("Skipping because devices < 2");
return;
}
SECTION("Default MemPool") { MemPoolSetGetAccess_P2P(MemPools::dev_default); }
SECTION("Created MemPool") { MemPoolSetGetAccess_P2P(MemPools::created); }
}
/**
* Test Description
* ------------------------
* - Test to verify hipMemPoolSetAccess behavior with invalid arguments:
* -# Nullptr mem_pool
* -# Desc is nullptr and count is > 0
* -# Count > num_device
* -# Invalid desc location type
* -# Invalid desc location id
* -# Revoking access to own memory pool
*
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAccess.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetAccess_Negative_Parameters") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
MemPoolGuard mempool(MemPools::dev_default, device_id);
int num_dev = 0;
HIP_CHECK(hipGetDeviceCount(&num_dev));
hipMemAccessDesc desc;
memset(&desc, 0, sizeof(hipMemAccessDesc));
desc.location.type = hipMemLocationTypeDevice;
desc.location.id = device_id;
desc.flags = hipMemAccessFlagsProtReadWrite;
SECTION("Mempool is nullptr") {
HIP_CHECK_ERROR(hipMemPoolSetAccess(nullptr, &desc, 1), hipErrorInvalidValue);
}
#if HT_AMD
SECTION("Desc is nullptr and count is > 0") {
HIP_CHECK_ERROR(hipMemPoolSetAccess(mempool.mempool(), nullptr, 1), hipErrorInvalidValue);
}
#endif
SECTION("Count > num_device") {
HIP_CHECK_ERROR(hipMemPoolSetAccess(mempool.mempool(), &desc, (num_dev + 1)),
hipErrorNotSupported);
}
SECTION("Passing invalid desc location type") {
desc.location.type = hipMemLocationTypeInvalid;
HIP_CHECK_ERROR(hipMemPoolSetAccess(mempool.mempool(), &desc, 1), hipErrorNotSupported);
desc.location.type = hipMemLocationTypeDevice;
}
SECTION("Passing invalid desc location id") {
desc.location.id = num_dev;
HIP_CHECK_ERROR(hipMemPoolSetAccess(mempool.mempool(), &desc, 1), hipErrorInvalidDevice);
desc.location.id = device_id;
}
SECTION("Revoking access to own memory pool") {
desc.flags = hipMemAccessFlagsProtNone;
HIP_CHECK_ERROR(hipMemPoolSetAccess(mempool.mempool(), &desc, 1), hipErrorInvalidDevice);
desc.flags = hipMemAccessFlagsProtReadWrite;
}
}
/**
* End doxygen group hipMemPoolSetAccess.
* @}
*/
/**
* @addtogroup hipMemPoolGetAccess hipMemPoolGetAccess
* @{
* @ingroup StreamOTest
* `hipMemPoolGetAccess(hipMemAccessFlags* flags, hipMemPool_t mem_pool, hipMemLocation* location)`
* - Returns the accessibility of a pool from a device
*/
/**
* Test Description
* ------------------------
* - Test to verify hipMemPoolGetAccess behavior with invalid arguments:
* -# Nullptr mem_pool
* -# Flags is nullptr
* -# Invalid location type
* -# Invalid location id
*
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAccess.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolGetAccess_Negative_Parameters") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
MemPoolGuard mempool(MemPools::dev_default, device_id);
int num_dev = 0;
HIP_CHECK(hipGetDeviceCount(&num_dev));
hipMemAccessFlags flags = hipMemAccessFlagsProtNone;
hipMemLocation location = {hipMemLocationTypeDevice, device_id};
SECTION("Mempool is nullptr") {
HIP_CHECK_ERROR(hipMemPoolGetAccess(&flags, nullptr, &location), hipErrorInvalidValue);
}
#if HT_AMD
SECTION("Flags is nullptr") {
HIP_CHECK_ERROR(hipMemPoolGetAccess(nullptr, mempool.mempool(), &location),
hipErrorInvalidValue);
}
#endif
SECTION("Passing invalid location type") {
location.type = hipMemLocationTypeInvalid;
HIP_CHECK_ERROR(hipMemPoolGetAccess(&flags, mempool.mempool(), &location),
hipErrorInvalidValue);
location.type = hipMemLocationTypeDevice;
}
SECTION("Passing invalid location id") {
location.id = num_dev;
HIP_CHECK_ERROR(hipMemPoolGetAccess(&flags, mempool.mempool(), &location),
hipErrorInvalidValue);
location.id = device_id;
}
}
+590
Ver ficheiro
@@ -0,0 +1,590 @@
/*
Copyright (c) 2023 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 "mempool_common.hh"
#include <resource_guards.hh>
#include <utils.hh>
/**
* @addtogroup hipMemPoolSetAttribute hipMemPoolSetAttribute
* @{
* @ingroup StreamOTest
* `hipMemPoolSetAttribute(hipMemPool_t mem_pool, hipMemPoolAttr attr, void* value)`
* - Sets attributes of a memory pool
*/
template <typename T>
static void MemPoolSetGetAttribute(const hipMemPool_t mempool, const hipMemPoolAttr attr,
T& set_value) {
T get_value = 100;
HIP_CHECK(hipMemPoolSetAttribute(mempool, attr, &set_value));
HIP_CHECK(hipMemPoolGetAttribute(mempool, attr, &get_value));
REQUIRE(get_value == set_value);
}
/**
* Test Description
* ------------------------
* - Basic test to verify that default attribute values are correct.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetGetAttribute_Positive_Default") {
const auto device = GENERATE(range(0, HipTest::getDeviceCount()));
int mem_pool_support = 0;
HIP_CHECK(
hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, device));
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
const auto mempool_type = GENERATE(MemPools::dev_default, MemPools::created);
MemPoolGuard mempool(mempool_type, device);
const auto attr_type =
GENERATE(hipMemPoolReuseFollowEventDependencies, hipMemPoolReuseAllowOpportunistic,
hipMemPoolReuseAllowInternalDependencies);
// Check default value
int def_value = 0;
HIP_CHECK(hipMemPoolGetAttribute(mempool.mempool(), attr_type, &def_value));
REQUIRE(def_value == 1);
// Check if attribute can be disabled
int set_value = 0;
MemPoolSetGetAttribute(mempool.mempool(), attr_type, set_value);
}
/**
* Test Description
* ------------------------
* - Basic test to verify hipMemPoolSetAttribute/hipMemPoolGetAttribute functionality.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetGetAttribute_Positive_MemBasic") {
const auto device = GENERATE(range(0, HipTest::getDeviceCount()));
int mem_pool_support = 0;
HIP_CHECK(
hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, device));
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
const auto mempool_type = GENERATE(MemPools::dev_default, MemPools::created);
MemPoolGuard mempool(mempool_type, device);
// Check hipMemPoolAttrReleaseThreshold default value
hipMemPoolAttr attr = hipMemPoolAttrReleaseThreshold;
std::uint64_t value64 = 100;
HIP_CHECK(hipMemPoolGetAttribute(mempool.mempool(), attr, &value64));
REQUIRE(value64 == 0);
// Check setting hipMemPoolAttrReleaseThreshold to a value
std::uint64_t set_value64 = kPageSize;
MemPoolSetGetAttribute(mempool.mempool(), hipMemPoolAttrReleaseThreshold, set_value64);
// Check reset of hipMemPoolAttrReservedMemHigh and hipMemPoolAttrUsedMemHigh
set_value64 = 0;
MemPoolSetGetAttribute(mempool.mempool(), hipMemPoolAttrReservedMemHigh, set_value64);
MemPoolSetGetAttribute(mempool.mempool(), hipMemPoolAttrUsedMemHigh, set_value64);
}
/**
* Test Description
* ------------------------
* - Basic test to verify correct behavior of the Opportunistic attribute.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetAttribute_Opportunistic") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
int mem_pool_support = 0;
HIP_CHECK(hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, 0));
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
MemPoolGuard mempool(MemPools::created, device_id);
hipMemPoolAttr attr;
int blocks = 2;
int clk_rate;
if (IsGfx11()) {
HIPCHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeWallClockRate, 0));
} else {
HIPCHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeClockRate, 0));
}
int *alloc_mem1, *alloc_mem2, *alloc_mem3;
// Create 2 async non-blocking streams
StreamGuard stream1(Streams::withFlags, hipStreamNonBlocking);
StreamGuard stream2(Streams::withFlags, hipStreamNonBlocking);
size_t allocation_size = kPageSize;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem3), allocation_size,
mempool.mempool(), stream1.stream()));
int value = 0;
SECTION("Disallow Opportunistic - No Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
// Disable all default pool states
attr = hipMemPoolReuseFollowEventDependencies;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
attr = hipMemPoolReuseAllowOpportunistic;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
attr = hipMemPoolReuseAllowInternalDependencies;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
// Sleep for 1 second GPU should be idle by now
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream2.stream()));
// Without Opportunistic state runtime must allocate another buffer
REQUIRE(alloc_mem1 != alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream2.stream()));
}
SECTION("Disallow Opportunistic - Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
// Disable all default pool states
attr = hipMemPoolReuseFollowEventDependencies;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
attr = hipMemPoolReuseAllowOpportunistic;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
attr = hipMemPoolReuseAllowInternalDependencies;
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
// Sleep for 1 second GPU should be idle by now
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream1.stream()));
// Without Opportunistic state runtime must allocate another buffer
REQUIRE(alloc_mem1 == alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream1.stream()));
}
SECTION("Allow Opportunistic - Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
value = 1;
attr = hipMemPoolReuseAllowOpportunistic;
// Enable Opportunistic
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
HIP_CHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeWallClockRate, 0));
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
HIP_CHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeClockRate, 0));
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
// Sleep for 1 second GPU should be idle by now
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream2.stream()));
// With Opportunistic state runtime will reuse freed buffer A
REQUIRE(alloc_mem1 == alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream2.stream()));
}
SECTION("Allow Opportunistic - No Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
value = 1;
attr = hipMemPoolReuseAllowOpportunistic;
// Enable Opportunistic
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream2.stream()));
// With Opportunistic state runtime can't reuse freed buffer A, because it's still busy with the
// kernel
REQUIRE(alloc_mem1 != alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream2.stream()));
}
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem3), stream1.stream()));
}
/**
* Test Description
* ------------------------
* - Basic test to verify correct behavior of the EventDependencies attribute.
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetAttribute_EventDependencies") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
int mem_pool_support = 0;
HIP_CHECK(hipDeviceGetAttribute(&mem_pool_support, hipDeviceAttributeMemoryPoolsSupported, 0));
if (!mem_pool_support) {
SUCCEED("Runtime doesn't support Memory Pool. Skip the test case.");
return;
}
MemPoolGuard mempool(MemPools::created, device_id);
hipMemPoolAttr attr;
int blocks = 2;
int clk_rate;
if (IsGfx11()) {
HIPCHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeWallClockRate, 0));
} else {
HIPCHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeClockRate, 0));
}
int *alloc_mem1, *alloc_mem2, *alloc_mem3;
// Create 2 async non-blocking streams
StreamGuard stream1(Streams::withFlags, hipStreamNonBlocking);
StreamGuard stream2(Streams::withFlags, hipStreamNonBlocking);
hipEvent_t event;
HIP_CHECK(hipEventCreate(&event));
size_t allocation_size = kPageSize;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem3), allocation_size,
mempool.mempool(), stream1.stream()));
int value = 0;
SECTION("Allow Event Dependencies - Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
value = 1;
attr = hipMemPoolReuseFollowEventDependencies;
// Enable Opportunistic
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
HIP_CHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeWallClockRate, 0));
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
HIP_CHECK(hipDeviceGetAttribute(&clk_rate, hipDeviceAttributeClockRate, 0));
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
HIP_CHECK(hipEventRecord(event, stream1.stream()));
HIP_CHECK(hipStreamWaitEvent(stream2.stream(), event, 0));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream2.stream()));
// With Opportunistic state runtime will reuse freed buffer A
REQUIRE(alloc_mem1 == alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream2.stream()));
}
SECTION("Disallow Event Dependencies - No Reuse") {
allocation_size = kPageSize * kPageSize * 2;
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem1), allocation_size,
mempool.mempool(), stream1.stream()));
value = 0;
attr = hipMemPoolReuseFollowEventDependencies;
// Enable Opportunistic
HIP_CHECK(hipMemPoolSetAttribute(mempool.mempool(), attr, &value));
// Run kernel for 500 ms in the first stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream1.stream()>>>(alloc_mem1, clk_rate);
}
// Not a real free, since kernel isn't done
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem1), stream1.stream()));
HIP_CHECK(hipEventRecord(event, stream1.stream()));
HIP_CHECK(hipStreamWaitEvent(stream2.stream(), event, 0));
// Allocate memory for the second stream
HIP_CHECK(hipMallocFromPoolAsync(reinterpret_cast<void**>(&alloc_mem2), allocation_size,
mempool.mempool(), stream2.stream()));
// With Opportunistic state runtime can't reuse freed buffer A, because it's still busy with the
// kernel
REQUIRE(alloc_mem1 != alloc_mem2);
// Run kernel with the new memory in the second stream
if (IsGfx11()) {
kernel_500ms_gfx11<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
} else {
kernel_500ms<<<32, blocks, 0, stream2.stream()>>>(alloc_mem2, clk_rate);
}
HIP_CHECK(hipStreamSynchronize(stream1.stream()));
HIP_CHECK(hipStreamSynchronize(stream2.stream()));
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem2), stream2.stream()));
}
HIP_CHECK(hipFreeAsync(reinterpret_cast<void*>(alloc_mem3), stream1.stream()));
HIP_CHECK(hipEventDestroy(event));
}
/**
* Test Description
* ------------------------
* - Test to verify hipMemPoolSetAttribute behavior with invalid arguments:
* -# Nullptr mem_pool
* -# Attribute value is not valid
* -# Nullptr value
* -# hipMemPoolAttrReservedMemHigh set to non-zero
* -# IhipMemPoolAttrUsedMemHigh set to non-zero
*
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolSetAttribute_Negative_Parameters") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
MemPoolGuard mempool(MemPools::dev_default, device_id);
hipMemPoolAttr attr = hipMemPoolReuseFollowEventDependencies;
int set_value = 0;
std::uint64_t set_value64 = 0;
SECTION("Mempool is nullptr") {
HIP_CHECK_ERROR(hipMemPoolSetAttribute(nullptr, attr, &set_value), hipErrorInvalidValue);
}
SECTION("Attribute value is not valid") {
HIP_CHECK_ERROR(
hipMemPoolSetAttribute(mempool.mempool(), static_cast<hipMemPoolAttr>(0x9), &set_value),
hipErrorInvalidValue);
}
#if HT_AMD
SECTION("Set values is nullptr") {
HIP_CHECK_ERROR(hipMemPoolSetAttribute(mempool.mempool(), attr, nullptr), hipErrorInvalidValue);
}
#endif
SECTION("Set hipMemPoolAttrReservedMemHigh to non-zero") {
hipMemPoolAttr attr = hipMemPoolAttrReservedMemHigh;
set_value64 = 1;
HIP_CHECK_ERROR((hipMemPoolSetAttribute(mempool.mempool(), attr, &set_value64)),
hipErrorInvalidValue);
}
SECTION("Set hipMemPoolAttrUsedMemHigh to non-zero") {
hipMemPoolAttr attr = hipMemPoolAttrUsedMemHigh;
set_value64 = 1;
HIP_CHECK_ERROR((hipMemPoolSetAttribute(mempool.mempool(), attr, &set_value64)),
hipErrorInvalidValue);
}
}
/**
* End doxygen group hipMemPoolSetAttribute.
* @}
*/
/**
* @addtogroup hipMemPoolGetAttribute hipMemPoolGetAttribute
* @{
* @ingroup StreamOTest
* `hipMemPoolGetAttribute(hipMemPool_t mem_pool, hipMemPoolAttr attr, void* value)`
* - Gets attributes of a memory pool
*/
/**
* Test Description
* ------------------------
* - Test to verify hipMemPoolGetAttribute behavior with invalid arguments:
* -# Nullptr mem_pool
* -# Attribute value is not valid
* -# Nullptr value
*
* Test source
* ------------------------
* - /unit/memory/hipMemPoolSetGetAttribute.cc
* Test requirements
* ------------------------
* - HIP_VERSION >= 6.0
*/
TEST_CASE("Unit_hipMemPoolGetAttribute_Negative_Parameters") {
int device_id = 0;
HIP_CHECK(hipSetDevice(device_id));
MemPoolGuard mempool(MemPools::dev_default, device_id);
hipMemPoolAttr attr = hipMemPoolReuseFollowEventDependencies;
int get_value = 0;
SECTION("Mempool is nullptr") {
HIP_CHECK_ERROR(hipMemPoolGetAttribute(nullptr, attr, &get_value), hipErrorInvalidValue);
}
SECTION("Attribute value is not valid") {
HIP_CHECK_ERROR(
hipMemPoolGetAttribute(mempool.mempool(), static_cast<hipMemPoolAttr>(0x9), &get_value),
hipErrorInvalidValue);
}
SECTION("Get values is nullptr") {
HIP_CHECK_ERROR(hipMemPoolGetAttribute(mempool.mempool(), attr, nullptr), hipErrorInvalidValue);
}
}
+59
Ver ficheiro
@@ -0,0 +1,59 @@
/*
Copyright (c) 2023 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.
*/
#pragma once
#include <hip_test_common.hh>
namespace {
constexpr hipMemPoolProps kPoolProps = {
hipMemAllocationTypePinned, hipMemHandleTypeNone, {hipMemLocationTypeDevice, 0}, nullptr, {0}};
constexpr auto wait_ms = 500;
} // anonymous namespace
template <typename T>
__global__ void kernel_500ms(T* host_res, int clk_rate) {
int tid = threadIdx.x + blockIdx.x * blockDim.x;
host_res[tid] = tid + 1;
__threadfence_system();
// expecting that the data is getting flushed to host here!
uint64_t start = clock64()/clk_rate, cur;
if (clk_rate > 1) {
do { cur = clock64()/clk_rate-start;}while (cur < wait_ms);
} else {
do { cur = clock64()/start;}while (cur < wait_ms);
}
}
template <typename T>
__global__ void kernel_500ms_gfx11(T* host_res, int clk_rate) {
#if HT_AMD
int tid = threadIdx.x + blockIdx.x * blockDim.x;
host_res[tid] = tid + 1;
__threadfence_system();
// expecting that the data is getting flushed to host here!
uint64_t start = wall_clock64()/clk_rate, cur;
if (clk_rate > 1) {
do { cur = wall_clock64()/clk_rate-start;}while (cur < wait_ms);
} else {
do { cur = wall_clock64()/start;}while (cur < wait_ms);
}
#endif
}