KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
allocator.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2023 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14#pragma once
15
16#include <cstddef>
17#include <limits>
18#include <memory>
19
20#include <mpi.h>
21
23
24namespace kamping {
25
26/// @brief STL-compatible allocator for requesting memory using the builtin MPI allocator.
27///
28/// Note that this allocator may only be used after initializing MPI.
29///
30/// @tparam T The type to allocate.
31template <typename T>
33public:
34 // Note: this implements all required functionality of a custom allocator,
35 // the rest is inferred.
36 //
37 // This (almost minimal) set of implemented members for the named
38 // requirement `Allocator` matches the ones of Intel's TBB allocator, which
39 // works similar to ours.
40 //
41 // See https://en.cppreference.com/w/cpp/named_req/Allocator for details.
42
43 MPIAllocator() noexcept = default;
44
45 /// @brief Copy constructor for allocators with different value type.
46 ///
47 /// Since the allocator is stateless, we can also copy-assign
48 /// allocators for other types (because this is a noop).
49 template <typename U>
50 MPIAllocator(MPIAllocator<U> const&) noexcept {}
51
52 /// @brief The value type.
53 using value_type = T;
54
55 /// @brief the memory "ownership" can be moved when the container is
56 /// move-assigned. If this would not be the case, container would need to
57 /// free memory using the old allocator and reallocated it using the copied
58 /// allocator.
60
61 /// @brief memory allocated by one allocator instance can always be dellocated
62 /// by another and vice-versa
63 using is_always_equal = std::true_type;
64
65 /// @brief Allocates <tt> n * sizeof(T) </tt> bytes using MPI allocation functions.
66 /// @param n The number of objects to allocate storage for.
67 /// @return Pointer to the allocated memory segment.
68 T* allocate(size_t n) {
69 T* ptr;
70 if (sizeof(value_type) * n > std::numeric_limits<MPI_Aint>::max()) {
71 throw std::runtime_error("Requested allocation exceeds MPI address size.");
72 }
73 MPI_Aint alloc_size = static_cast<MPI_Aint>(sizeof(value_type) * n);
74 int err = MPI_Alloc_mem(alloc_size, MPI_INFO_NULL, &ptr);
75 THROW_IF_MPI_ERROR(err, MPI_Alloc_mem);
76 return ptr;
77 }
78
79 /// @brief Deallocates the storage referenced by the pointer \c p, which must be a pointer obtained by an earlier
80 /// call to \ref allocate().
81 /// @param p Pointer obtained from \ref allocate().
82 void deallocate(T* p, size_t) {
83 // no error handling because the standard disallows throwing exceptions here
84 MPI_Free_mem(p);
85 }
86};
87
88// From https://en.cppreference.com/w/cpp/named_req/Allocator:
89// - true only if the storage allocated by the allocator a1 can be deallocated through a2.
90// - Establishes reflexive, symmetric, and transitive relationship.
91// - Does not throw exceptions.
92template <typename T, typename U>
93bool operator==(MPIAllocator<T> const&, MPIAllocator<U> const&) noexcept {
94 return true;
95}
96
97template <typename T, typename U>
98bool operator!=(MPIAllocator<T> const&, MPIAllocator<U> const&) noexcept {
99 return false;
100}
101} // namespace kamping
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
std::true_type propagate_on_container_move_assignment
the memory "ownership" can be moved when the container is move-assigned. If this would not be the cas...
Definition allocator.hpp:59
T * allocate(size_t n)
Allocates n * sizeof(T) bytes using MPI allocation functions.
Definition allocator.hpp:68
std::true_type is_always_equal
memory allocated by one allocator instance can always be dellocated by another and vice-versa
Definition allocator.hpp:63
MPIAllocator(MPIAllocator< U > const &) noexcept
Copy constructor for allocators with different value type.
Definition allocator.hpp:50
void deallocate(T *p, size_t)
Deallocates the storage referenced by the pointer p, which must be a pointer obtained by an earlier c...
Definition allocator.hpp:82
T value_type
The value type.
Definition allocator.hpp:53
Code for error handling.
#define THROW_IF_MPI_ERROR(error_code, function)
Wrapper around THROWING_KASSERT for MPI errors.
Definition error_handling.hpp:33