Skip to content

Commit

Permalink
CArena: shrink_in_place and operator<<
Browse files Browse the repository at this point in the history
Implement CArena::shrink_in_place, which is used by
PODVector::shrink_to_fit. It avoids a new memory allocation and data
movement.

Add operator<< to CArena. This helps debugging.
  • Loading branch information
WeiqunZhang committed Nov 10, 2023
1 parent d364631 commit 4288dff
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 9 deletions.
17 changes: 10 additions & 7 deletions Src/Base/AMReX_CArena.H
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
#include <AMReX_Arena.H>

#include <cstddef>
#include <set>
#include <vector>
#include <functional>
#include <iosfwd>
#include <map>
#include <mutex>
#include <unordered_set>
#include <functional>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

namespace amrex {

Expand Down Expand Up @@ -164,15 +165,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 All @@ -198,6 +199,8 @@ protected:


std::mutex carena_mutex;

friend std::ostream& operator<< (std::ostream& os, const CArena& arena);
};

}
Expand Down
89 changes: 87 additions & 2 deletions Src/Base/AMReX_CArena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace amrex {

#include <utility>
#include <cstring>
#include <iostream>

namespace amrex {

Expand Down Expand Up @@ -203,9 +204,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 operator< 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 Expand Up @@ -439,4 +485,43 @@ CArena::PrintUsage (std::ostream& os, std::string const& name, std::string const
<< m_busylist.size() << " busy blocks, " << m_freelist.size() << " free blocks\n";
}

std::ostream& operator<< (std::ostream& os, const CArena& arena)
{
os << "CArea:\n"
<< " Hunk size: " << arena.m_hunk << "\n"
<< " Memory allocated: " << arena.m_used << "\n"
<< " Memory actually used: " << arena.m_actually_used << "\n";

if (arena.m_alloc.empty()) {
os << " No memory allocations\n";
} else {
os << " List of memory alloations: (address, size)\n";
for (auto const& a : arena.m_alloc) {
os << " " << a.first << ", " << a.second << "\n";
}
}

if (arena.m_freelist.empty()) {
os << " No free nodes\n";
} else {
os << " List of free nodes: (address, owner, size)\n";
for (auto const& a : arena.m_freelist) {
os << " " << a.block() << ", " << a.owner() << ", "
<< a.size() << "\n";
}
}

if (arena.m_busylist.empty()) {
os << " No busy nodes\n";
} else {
os << " List of busy nodes: (address, owner, size)\n";
for (auto const& a : arena.m_busylist) {
os << " " << a.block() << ", " << a.owner() << ", "
<< a.size() << "\n";
}
}

return os;
}

}

0 comments on commit 4288dff

Please sign in to comment.