34#if defined(POPS_HAS_KOKKOS)
36#include <Kokkos_Core.hpp>
40#include <unordered_map>
46 Kokkos::has_shared_space,
47 "pops: the Kokkos backend must provide SharedSpace (unified memory) for the device "
48 "Fab; enable a Cuda/HIP/SYCL backend (or a host backend, where SharedSpace is HostSpace)");
85 static ManagedArena& instance() {
86 static ManagedArena* a =
new ManagedArena();
90 void* allocate(std::size_t bytes) {
97 detail::ensure_kokkos_initialized();
98 std::lock_guard<std::mutex> lk(m_);
99 std::call_once(hook_once_,
101 Kokkos::push_finalize_hook([] { ManagedArena::instance().release_all(); });
103 if (
void* p = pop_ready(bytes))
105 if (pending_count_ > 0) {
109 for (
auto& kv : pending_) {
110 auto& r = ready_[kv.first];
111 r.insert(r.end(), kv.second.begin(), kv.second.end());
115 if (
void* p = pop_ready(bytes))
119 Kokkos::kokkos_malloc<Kokkos::SharedSpace>(
"pops_fab", bytes);
121 throw std::bad_alloc();
129 void deallocate(
void* p, std::size_t bytes) {
132 std::lock_guard<std::mutex> lk(m_);
133 pending_[bytes].push_back(p);
141 std::lock_guard<std::mutex> lk(m_);
142 for (
auto& kv : ready_)
143 for (void* p : kv.second)
144 Kokkos::kokkos_free<Kokkos::SharedSpace>(p);
145 for (
auto& kv : pending_)
146 for (void* p : kv.second)
147 Kokkos::kokkos_free<Kokkos::SharedSpace>(p);
154 std::lock_guard<std::mutex> lk(m_);
155 return ArenaStats{hits_, misses_, fences_, reserved_};
159 void* pop_ready(std::size_t bytes) {
160 auto it = ready_.find(bytes);
161 if (it != ready_.end() && !it->second.empty()) {
162 void* p = it->second.back();
163 it->second.pop_back();
171 std::once_flag hook_once_;
172 std::unordered_map<std::size_t, std::vector<void*>> ready_;
173 std::unordered_map<std::size_t, std::vector<void*>> pending_;
174 long pending_count_ = 0;
175 long hits_ = 0, misses_ = 0, fences_ = 0;
176 std::size_t reserved_ = 0;
180 return ManagedArena::instance().stats();
187struct ManagedAllocator {
188 using value_type = T;
189 ManagedAllocator() noexcept = default;
191 ManagedAllocator(const ManagedAllocator<U>&) noexcept {}
193 T* allocate(std::size_t n) {
194 return static_cast<T*
>(ManagedArena::instance().allocate(n *
sizeof(T)));
196 void deallocate(T* p, std::size_t n)
noexcept {
197 ManagedArena::instance().deallocate(p, n *
sizeof(T));
201template <
class A,
class B>
202bool operator==(
const ManagedAllocator<A>&,
const ManagedAllocator<B>&)
noexcept {
205template <
class A,
class B>
206bool operator!=(
const ManagedAllocator<A>&,
const ManagedAllocator<B>&)
noexcept {
223static_assert(Kokkos::has_shared_host_pinned_space,
224 "pops: the Kokkos backend must provide SharedHostPinnedSpace (pinned host memory) "
225 "for the MPI communication buffers of fill_boundary");
232struct PinnedAllocator {
233 using value_type = T;
234 PinnedAllocator() noexcept = default;
236 PinnedAllocator(const PinnedAllocator<U>&) noexcept {}
238 T* allocate(std::size_t n) {
241 detail::ensure_kokkos_initialized();
242 void* p = Kokkos::kokkos_malloc<Kokkos::SharedHostPinnedSpace>(
"pops_comm", n *
sizeof(T));
244 throw std::bad_alloc();
245 return static_cast<T*
>(p);
247 void deallocate(T* p, std::size_t)
noexcept {
249 Kokkos::kokkos_free<Kokkos::SharedHostPinnedSpace>(p);
252template <
class A,
class B>
253bool operator==(
const PinnedAllocator<A>&,
const PinnedAllocator<B>&)
noexcept {
256template <
class A,
class B>
257bool operator!=(
const PinnedAllocator<A>&,
const PinnedAllocator<B>&)
noexcept {
Shared Kokkos lifecycle: lazy init + device barrier.
Definition amr_hierarchy.hpp:29
ArenaStats arena_stats()
Definition allocator.hpp:277
std::allocator< T > comm_allocator
Definition allocator.hpp:274
std::allocator< T > fab_allocator
Definition allocator.hpp:270
ManagedArena pool statistics: hits/misses/fences and retained bytes.
Definition allocator.hpp:26
long misses
Definition allocator.hpp:28
std::size_t reserved_bytes
Definition allocator.hpp:30
long hits
Definition allocator.hpp:27
long fences
Definition allocator.hpp:29