CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
256 lines
8.2 KiB
C++
256 lines
8.2 KiB
C++
// Copyright Advanced Micro Devices, Inc., or its affiliates.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include <rocRoller/InstructionValues/LDSAllocator.hpp>
|
|
#include <rocRoller/Utilities/Error.hpp>
|
|
#include <rocRoller/Utilities/Utils.hpp>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
namespace rocRoller
|
|
{
|
|
LDSAllocator::LDSAllocator(unsigned int maxAmount)
|
|
: m_maxAmount(maxAmount)
|
|
{
|
|
}
|
|
|
|
unsigned int LDSAllocator::maxUsed() const
|
|
{
|
|
return m_maxUsed;
|
|
}
|
|
|
|
unsigned int LDSAllocator::currentUsed() const
|
|
{
|
|
return m_currentUsed;
|
|
}
|
|
|
|
void LDSAllocator::updateMaxUsed()
|
|
{
|
|
if(m_maxUsed < m_nextAvailable)
|
|
{
|
|
m_maxUsed = m_nextAvailable;
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<LDSAllocation> LDSAllocator::allocate(unsigned int size, unsigned int alignment)
|
|
{
|
|
unsigned int alignedSize = RoundUpToMultiple(size, alignment);
|
|
std::shared_ptr<LDSAllocation> result;
|
|
|
|
AssertFatal(size == alignedSize,
|
|
"Can only allocate aligned sizes\n",
|
|
ShowValue(size),
|
|
ShowValue(alignedSize));
|
|
|
|
// Look for available free blocks that can hold the requested amount of memory.
|
|
for(auto it = m_freeBlocks.begin(); it != m_freeBlocks.end(); it++)
|
|
{
|
|
auto block = *it;
|
|
|
|
// If the start of free block's alignment doesn't match, skip it
|
|
auto alignedOffset = RoundUpToMultiple(block->offset(), alignment);
|
|
if(block->offset() != alignedOffset)
|
|
continue;
|
|
|
|
if(block->size() >= alignedSize)
|
|
{
|
|
result = std::make_shared<LDSAllocation>(
|
|
shared_from_this(), alignedSize, block->offset());
|
|
|
|
// If block is the exact amount requested, it can be removed from the m_freeBlocks list.
|
|
// Otherwise, the correct amount of space should be taken from the block.
|
|
if(block->size() == alignedSize)
|
|
{
|
|
m_consolidationDepth++;
|
|
m_freeBlocks.erase(it);
|
|
m_consolidationDepth--;
|
|
}
|
|
else
|
|
{
|
|
block->setSize(block->size() - alignedSize);
|
|
block->setOffset(block->offset() + alignedSize);
|
|
}
|
|
|
|
m_currentUsed += alignedSize;
|
|
updateMaxUsed();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// If there are no free blocks that can hold size, allocate more memory from m_nextAvailable
|
|
auto alignedOffset = RoundUpToMultiple(m_nextAvailable, alignment);
|
|
AssertFatal(alignedOffset + alignedSize <= m_maxAmount,
|
|
"Attempting to allocate more Local Data than is available",
|
|
ShowValue(alignedOffset),
|
|
ShowValue(alignedSize),
|
|
ShowValue(m_maxAmount));
|
|
|
|
if(alignedOffset > m_nextAvailable)
|
|
{
|
|
auto gap = std::make_shared<LDSAllocation>(
|
|
shared_from_this(), alignedOffset - m_nextAvailable, m_nextAvailable);
|
|
m_freeBlocks.push_back(gap);
|
|
}
|
|
|
|
auto allocation
|
|
= std::make_shared<LDSAllocation>(shared_from_this(), alignedSize, alignedOffset);
|
|
|
|
m_nextAvailable = alignedOffset + alignedSize;
|
|
m_currentUsed += alignedSize;
|
|
|
|
updateMaxUsed();
|
|
return allocation;
|
|
}
|
|
|
|
void LDSAllocator::deallocate(std::shared_ptr<LDSAllocation> allocation)
|
|
{
|
|
unsigned int allocation_end = allocation->offset() + allocation->size();
|
|
bool deallocated = false;
|
|
|
|
// Blocks should be returned in sorted order.
|
|
auto it = m_freeBlocks.begin();
|
|
while(it != m_freeBlocks.end() && !deallocated)
|
|
{
|
|
auto block = *it;
|
|
// Make sure block hasn't already been deallocated
|
|
AssertFatal(
|
|
!(allocation->offset() <= block->offset() && allocation_end > block->offset()),
|
|
ShowValue(allocation->offset()),
|
|
ShowValue(allocation_end),
|
|
ShowValue(block->offset()),
|
|
ShowValue(allocation->size()),
|
|
allocation->toString(),
|
|
"\nLocal memory allocation has already been freed.");
|
|
|
|
// Can allocation be added to the end of the current block?
|
|
if(block->offset() + block->size() == allocation->offset())
|
|
{
|
|
// Can allocation also be added to the beginning of the next block as well?
|
|
// If so, block and the next block can be merged together.
|
|
auto next = std::next(it);
|
|
if(next != m_freeBlocks.end() && allocation_end == (*next)->offset())
|
|
{
|
|
block->setSize(block->size() + allocation->size() + (*next)->size());
|
|
m_consolidationDepth++;
|
|
m_freeBlocks.erase(next);
|
|
m_consolidationDepth--;
|
|
}
|
|
else
|
|
{
|
|
block->setSize(block->size() + allocation->size());
|
|
}
|
|
|
|
deallocated = true;
|
|
}
|
|
// Can allocation be added to the beginning of the current block?
|
|
else if(allocation_end == block->offset())
|
|
{
|
|
block->setSize(block->size() + allocation->size());
|
|
block->setOffset(allocation->offset());
|
|
deallocated = true;
|
|
}
|
|
// Should new block be added
|
|
else if(allocation->offset() < block->offset())
|
|
{
|
|
m_freeBlocks.insert(it, allocation);
|
|
deallocated = true;
|
|
}
|
|
|
|
it++;
|
|
}
|
|
|
|
// If allocation wasn't added to m_freeBlocks, insert it at the end
|
|
if(!deallocated)
|
|
m_freeBlocks.push_back(allocation);
|
|
|
|
if(m_consolidationDepth == 0)
|
|
{
|
|
AssertFatal(m_currentUsed >= allocation->size(),
|
|
ShowValue(m_currentUsed),
|
|
ShowValue(allocation->size()));
|
|
|
|
m_currentUsed -= allocation->size();
|
|
|
|
// Remove last block if it's on the edge of free memory
|
|
if(!m_freeBlocks.empty()
|
|
&& m_nextAvailable == m_freeBlocks.back()->offset() + m_freeBlocks.back()->size())
|
|
{
|
|
m_consolidationDepth += 1;
|
|
m_nextAvailable -= m_freeBlocks.back()->size();
|
|
m_freeBlocks.pop_back();
|
|
m_consolidationDepth -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
LDSAllocation::LDSAllocation(std::shared_ptr<LDSAllocator> allocator,
|
|
unsigned int size,
|
|
unsigned int offset)
|
|
: m_size(size)
|
|
, m_offset(offset)
|
|
, m_allocator(allocator)
|
|
{
|
|
}
|
|
|
|
LDSAllocation::LDSAllocation(unsigned int size, unsigned int offset)
|
|
: m_size(size)
|
|
, m_offset(offset)
|
|
{
|
|
}
|
|
|
|
LDSAllocation::~LDSAllocation()
|
|
{
|
|
if(m_allocator.lock())
|
|
m_allocator.lock()->deallocate(copyForAllocator());
|
|
}
|
|
|
|
std::shared_ptr<LDSAllocation> LDSAllocation::copyForAllocator() const
|
|
{
|
|
return std::make_shared<LDSAllocation>(m_size, m_offset);
|
|
}
|
|
|
|
unsigned int LDSAllocation::size() const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
unsigned int LDSAllocation::offset() const
|
|
{
|
|
return m_offset;
|
|
}
|
|
|
|
void LDSAllocation::setSize(unsigned int size)
|
|
{
|
|
m_size = size;
|
|
}
|
|
|
|
void LDSAllocation::setOffset(unsigned int offset)
|
|
{
|
|
m_offset = offset;
|
|
}
|
|
|
|
std::string LDSAllocation::toString() const
|
|
{
|
|
std::stringstream ss;
|
|
ss << "(Offset: " << m_offset << ", Size: " << m_size << ")";
|
|
return ss.str();
|
|
}
|
|
|
|
bool LDSAllocation::intersects(LDSAllocation const& other) const
|
|
{
|
|
auto myMax = m_offset + m_size;
|
|
auto otherMax = other.m_offset + other.m_size;
|
|
|
|
return (myMax > other.m_offset && myMax <= otherMax)
|
|
|| (otherMax > m_offset && otherMax <= myMax);
|
|
}
|
|
|
|
bool LDSAllocation::intersects(std::shared_ptr<LDSAllocation> const& other) const
|
|
{
|
|
AssertFatal(other);
|
|
|
|
return intersects(*other);
|
|
}
|
|
}
|