Skip to content

Commit

Permalink
Implement CArena::shrink_in_place
Browse files Browse the repository at this point in the history
This function is used by PODVector::shrink_to_fit. It avoids a new memory
allocation and data movement.
  • Loading branch information
WeiqunZhang committed Nov 10, 2023
1 parent d364631 commit 13d525d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Src/Base/AMReX_CArena.H
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,15 @@ protected:
MemStat* m_stat;
};

//! The list of blocks allocated via ::operator new().
std::vector<std::pair<void*,std::size_t> > m_alloc;

/**
* \brief The type of our freelist and blocklist.
* We use a set sorted from lo to hi memory addresses.
*/
using NL = std::set<Node>;

//! The list of blocks allocated via ::operator new().
std::vector<std::pair<void*,std::size_t> > m_alloc;

/**
* \brief The free list of allocated but not currently used blocks.
* Maintained in lo to hi memory sorted order.
Expand Down
49 changes: 47 additions & 2 deletions Src/Base/AMReX_CArena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,54 @@ CArena::alloc_in_place (void* pt, std::size_t szmin, std::size_t szmax)
}

void*
CArena::shrink_in_place (void* /*pt*/, std::size_t sz)
CArena::shrink_in_place (void* pt, std::size_t sz)
{
return alloc(sz); // xxxxx TODO
if ((pt == nullptr) || (sz == 0)) { return nullptr; }

sz = Arena::align(sz);

std::lock_guard<std::mutex> lock(carena_mutex);

auto busy_it = m_busylist.find(Node(pt,nullptr,0));
if (busy_it == m_busylist.end()) {
amrex::Abort("CArena::shrink_in_place: unknown pointer");
return nullptr;
}
AMREX_ASSERT(m_freelist.find(*busy_it) == m_freelist.end());

if (sz > busy_it->size()) {
amrex::Abort("CArena::shrink_in_place: wrong size. Cannot shrink to a larger size.");
return nullptr;
} else if (sz == busy_it->size()) {
return pt;
} else {
auto leftover_size = busy_it->size() - sz;

void* pt2 = static_cast<char*>(pt) + sz;
Node new_free_node(pt2, busy_it->owner(), leftover_size);

void* pt_end = static_cast<char*>(pt) + busy_it->size();
auto free_it = m_freelist.find(Node(pt_end,nullptr,0));
if ((free_it == m_freelist.end()) ||
! new_free_node.coalescable(*free_it))
{
m_freelist.insert(free_it, new_free_node);
} else {
auto& node = const_cast<Node&>(*free_it);
auto new_size = leftover_size + node.size();
// This is safe because the free list is std::set and the
// modification of `block` does not change the order of elements
// in the container, even though Node's opearator< uses block.
node.block(pt2);
node.size(new_size);
}

const_cast<Node&>(*busy_it).size(sz);

m_actually_used -= leftover_size;

return pt;
}
}

void
Expand Down

0 comments on commit 13d525d

Please sign in to comment.