Files
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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);
}
}