SWDEV-311271 - Make sure memory pool can accept default stream

Add lock protection for access to the pool list.
Remove destroyed stream from the list of the safe streams

Change-Id: I1863b89bd3f5e188c161227cc790c3adaf72cc58


[ROCm/clr commit: 5957ff9f7b]
This commit is contained in:
German Andryeyev
2022-04-14 19:04:01 -04:00
bovenliggende 5516c2d12e
commit 3de1a9e36c
6 gewijzigde bestanden met toevoegingen van 63 en 8 verwijderingen
@@ -36,6 +36,17 @@ amd::HostQueue* Device::NullStream(bool skip_alloc) {
return null_queue;
}
// ================================================================================================
Stream* Device::GetNullStream() {
amd::HostQueue* null_queue = null_stream_.asHostQueue();
if (null_queue == nullptr) {
return nullptr;
}
// Wait for all active streams before executing commands on the default
iHipWaitActiveStreams(null_queue);
return &null_stream_;
}
// ================================================================================================
bool Device::Create() {
// Create default memory pool
@@ -50,6 +61,7 @@ bool Device::Create() {
// ================================================================================================
void Device::AddMemoryPool(MemoryPool* pool) {
amd::ScopedLock lock(lock_);
if (auto it = mem_pools_.find(pool); it == mem_pools_.end()) {
mem_pools_.insert(pool);
}
@@ -57,6 +69,7 @@ void Device::AddMemoryPool(MemoryPool* pool) {
// ================================================================================================
void Device::RemoveMemoryPool(MemoryPool* pool) {
amd::ScopedLock lock(lock_);
if (auto it = mem_pools_.find(pool); it != mem_pools_.end()) {
mem_pools_.erase(it);
}
@@ -64,6 +77,7 @@ void Device::RemoveMemoryPool(MemoryPool* pool) {
// ================================================================================================
bool Device::FreeMemory(amd::Memory* memory, Stream* stream) {
amd::ScopedLock lock(lock_);
// Search for memory in the entire list of pools
for (auto& it : mem_pools_) {
if (it->FreeMemory(memory, stream)) {
@@ -75,12 +89,22 @@ bool Device::FreeMemory(amd::Memory* memory, Stream* stream) {
// ================================================================================================
void Device::ReleaseFreedMemory(Stream* stream) {
amd::ScopedLock lock(lock_);
// Search for memory in the entire list of pools
for (auto& it : mem_pools_) {
it->ReleaseFreedMemory(stream);
}
}
// ================================================================================================
void Device::RemoveStreamFromPools(Stream* stream) {
amd::ScopedLock lock(lock_);
// Update all pools with the destroyed stream
for (auto& it : mem_pools_) {
it->RemoveStream(stream);
}
}
// ================================================================================================
Device::~Device() {
if (default_mem_pool_ != nullptr) {
@@ -391,6 +391,7 @@ namespace hip {
unsigned int getFlags() const { return flags_; }
void setFlags(unsigned int flags) { flags_ = flags; }
amd::HostQueue* NullStream(bool skip_alloc = false);
Stream* GetNullStream();
void SaveQueue(amd::HostQueue* queue) {
amd::ScopedLock lock(lock_);
@@ -431,6 +432,9 @@ namespace hip {
/// Release freed memory from all pools on the current device
void ReleaseFreedMemory(Stream* stream);
/// Removes a destroyed stream from the safe list of memory pools
void RemoveStreamFromPools(Stream* stream);
};
/// Current thread's device
@@ -58,26 +58,29 @@ hipError_t hipDeviceGetMemPool(hipMemPool_t* mem_pool, int device) {
// ================================================================================================
hipError_t hipMallocAsync(void** dev_ptr, size_t size, hipStream_t stream) {
HIP_INIT_API(hipMallocAsync, dev_ptr, size, stream);
if ((dev_ptr == nullptr) || (size == 0) || (stream == nullptr)) {
if ((dev_ptr == nullptr) || (size == 0) || (!hip::isValid(stream))) {
HIP_RETURN(hipErrorInvalidValue);
}
auto device = reinterpret_cast<hip::Stream*>(stream)->GetDevice();
auto mem_pool = device->GetCurrentMemoryPool();
*dev_ptr = reinterpret_cast<hip::MemoryPool*>(mem_pool)->AllocateMemory(
size, reinterpret_cast<hip::Stream*>(stream));
auto hip_stream = (stream == nullptr) ? hip::getCurrentDevice()->GetNullStream() :
reinterpret_cast<hip::Stream*>(stream);
*dev_ptr = reinterpret_cast<hip::MemoryPool*>(mem_pool)->AllocateMemory(size, hip_stream);
HIP_RETURN(hipSuccess);
}
// ================================================================================================
hipError_t hipFreeAsync(void* dev_ptr, hipStream_t stream) {
HIP_INIT_API(hipFreeAsync, dev_ptr, stream);
if ((dev_ptr == nullptr) || (stream == nullptr)) {
if ((dev_ptr == nullptr) || (!hip::isValid(stream))) {
HIP_RETURN(hipErrorInvalidValue);
}
size_t offset = 0;
auto memory = getMemoryObject(dev_ptr, offset);
auto id = memory->getUserData().deviceId;
if (!g_devices[id]->FreeMemory(memory, reinterpret_cast<hip::Stream*>(stream))) {
auto hip_stream = (stream == nullptr) ? hip::getCurrentDevice()->GetNullStream() :
reinterpret_cast<hip::Stream*>(stream);
if (!g_devices[id]->FreeMemory(memory, hip_stream)) {
//! @todo It's not the most optimal logic. The current implementation has unconditional waits
HIP_RETURN(ihipFree(dev_ptr));
}
@@ -185,11 +188,12 @@ hipError_t hipMallocFromPoolAsync(
hipMemPool_t mem_pool,
hipStream_t stream) {
HIP_INIT_API(hipMallocFromPoolAsync, dev_ptr, size, mem_pool, stream);
if ((dev_ptr == nullptr) || (size == 0) || (mem_pool == nullptr) || (stream == nullptr)) {
if ((dev_ptr == nullptr) || (size == 0) || (mem_pool == nullptr) || (!hip::isValid(stream))) {
HIP_RETURN(hipErrorInvalidValue);
}
*dev_ptr = reinterpret_cast<hip::MemoryPool*>(mem_pool)->AllocateMemory(
size, reinterpret_cast<hip::Stream*>(stream));
auto hip_stream = (stream == nullptr) ? hip::getCurrentDevice()->GetNullStream() :
reinterpret_cast<hip::Stream*>(stream);
*dev_ptr = reinterpret_cast<hip::MemoryPool*>(mem_pool)->AllocateMemory(size, hip_stream);
HIP_RETURN(hipSuccess);
}
@@ -120,6 +120,13 @@ bool Heap::ReleaseAllMemory(hip::Stream* stream) {
return true;
}
// ================================================================================================
void Heap::RemoveStream(hip::Stream* stream) {
for (auto it = allocations_.begin(); it != allocations_.end();) {
it->second.safe_streams_.erase(stream);
}
}
// ================================================================================================
void* MemoryPool::AllocateMemory(size_t size, hip::Stream* stream) {
amd::ScopedLock lock(lock_pool_ops_);
@@ -197,6 +204,13 @@ void MemoryPool::ReleaseFreedMemory(hip::Stream* stream) {
free_heap_.ReleaseAllMemory(stream);
}
// ================================================================================================
void MemoryPool::RemoveStream(hip::Stream* stream) {
amd::ScopedLock lock(lock_pool_ops_);
free_heap_.RemoveStream(stream);
}
// ================================================================================================
void MemoryPool::TrimTo(size_t min_bytes_to_hold) {
amd::ScopedLock lock(lock_pool_ops_);
@@ -104,6 +104,9 @@ public:
/// Releases all memory, safe to the provided stream, until the threshold value is met
bool ReleaseAllMemory(hip::Stream* stream);
/// Remove the provided stream from the safe list
void RemoveStream(hip::Stream* stream);
/// Heap doesn't have any allocations
bool IsEmpty() const { return (allocations_.size() == 0) ? true : false; }
@@ -122,6 +125,7 @@ public:
/// Set maximum total, allocated by the heap
void SetMaxTotalSize(uint64_t value) { max_total_size_ = value; }
/// Erases single allocation form the heap's map
std::unordered_map<amd::Memory*, MemoryTimestamp>::iterator EraseAllocaton(
std::unordered_map<amd::Memory*, MemoryTimestamp>::iterator& it);
@@ -171,6 +175,9 @@ public:
/// @note The caller must make sure it's safe to release memory
void ReleaseFreedMemory(hip::Stream* stream = nullptr);
/// Removes a stream from tracking
void RemoveStream(hip::Stream* stream);
/// Releases all allocations in MemoryPool
void ReleaseAllMemory();
@@ -436,6 +436,8 @@ hipError_t hipStreamDestroy(hipStream_t stream) {
}
hip::Stream* s = reinterpret_cast<hip::Stream*>(stream);
s->GetDevice()->RemoveStreamFromPools(s);
amd::ScopedLock lock(g_captureStreamsLock);
const auto& g_it = std::find(g_captureStreams.begin(), g_captureStreams.end(), s);
if (g_it != g_captureStreams.end()) {