Skip to content

Commit

Permalink
Merge pull request #327 from LLNL/feature/fb_allocator
Browse files Browse the repository at this point in the history
Update FB Allocator
  • Loading branch information
KIwabuchi authored Aug 16, 2024
2 parents 7e9a3b1 + 7aa5bf6 commit fc5d7e8
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 93 deletions.
191 changes: 98 additions & 93 deletions include/metall/container/fallback_allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,42 @@

namespace metall::container {

/// \brief A STL compatible allocator which fallbacks to a heap allocator (e.g.,
/// malloc()) if its constructor receives no argument to construct the stateful
/// allocator instance.
/// \tparam stateful_allocator The stateful allocator type. It must not be
/// \brief A Metall STL compatible allocator which fallbacks to a heap allocator
/// (e.g., malloc()) if its constructor receives no argument to construct the
/// stateful allocator (Metall's normal STL compatible allocator) instance.
/// \tparam StatefulAllocator The stateful allocator type. It must not be
/// default constructible.
template <typename stateful_allocator>
template <typename StatefulAllocator>
class fallback_allocator_adaptor {
// Check if the stateful_allocator takes arugments in its constructor
static_assert(!std::is_constructible<stateful_allocator>::value,
// Check if the StatefulAllocator takes arguments in its constructor
static_assert(!std::is_constructible<StatefulAllocator>::value,
"The stateful allocator must not be default constructible");

private:
template <typename T>
using other_stateful_allocatorator_type = typename std::allocator_traits<
stateful_allocator>::template rebind_alloc<T>;
using other_stateful_allocator_type = typename std::allocator_traits<
StatefulAllocator>::template rebind_alloc<T>;

public:
// -------------------- //
// Public types and static values
// -------------------- //
using stateful_allocatorator_type = typename std::remove_const<
typename std::remove_reference<stateful_allocator>::type>::type;
using stateful_allocator_type = typename std::remove_const<
typename std::remove_reference<StatefulAllocator>::type>::type;

using value_type = typename stateful_allocatorator_type::value_type;
using pointer = typename stateful_allocatorator_type::pointer;
using const_pointer = typename stateful_allocatorator_type::const_pointer;
using void_pointer = typename stateful_allocatorator_type::void_pointer;
using value_type = typename stateful_allocator_type::value_type;
using pointer = typename stateful_allocator_type::pointer;
using const_pointer = typename stateful_allocator_type::const_pointer;
using void_pointer = typename stateful_allocator_type::void_pointer;
using const_void_pointer =
typename stateful_allocatorator_type::const_void_pointer;
using difference_type = typename stateful_allocatorator_type::difference_type;
using size_type = typename stateful_allocatorator_type::size_type;
typename stateful_allocator_type::const_void_pointer;
using difference_type = typename stateful_allocator_type::difference_type;
using size_type = typename stateful_allocator_type::size_type;

/// \brief Makes another allocator type for type T2
template <typename T2>
struct rebind {
using other =
fallback_allocator_adaptor<other_stateful_allocatorator_type<T2>>;
using other = fallback_allocator_adaptor<other_stateful_allocator_type<T2>>;
};

public:
Expand All @@ -58,30 +57,30 @@ class fallback_allocator_adaptor {

/// \brief Default constructor which falls back on the regular allocator
/// (i.e., malloc()).
fallback_allocator_adaptor() noexcept : m_stateful_allocatorator(nullptr) {}
fallback_allocator_adaptor() noexcept : m_stateful_allocator(nullptr) {}

/// \brief Construct a new instance using an instance of
/// fallback_allocator_adaptor with any stateful_allocatorator type.
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// fallback_allocator_adaptor with any stateful_allocator type.
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor(
fallback_allocator_adaptor<stateful_allocatorator_type2>
fallback_allocator_adaptor<stateful_allocator_type2>
allocator_instance) noexcept
: m_stateful_allocatorator(allocator_instance.stateful_allocatorator()) {}
: m_stateful_allocator(allocator_instance.get_stateful_allocator()) {}

/// \brief Construct a new instance using an instance of any
/// stateful_allocatorator.
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// stateful_allocator.
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor(
stateful_allocatorator_type2 allocator_instance) noexcept
: m_stateful_allocatorator(allocator_instance) {}
stateful_allocator_type2 allocator_instance) noexcept
: m_stateful_allocator(allocator_instance) {}

/// \brief Copy constructor
fallback_allocator_adaptor(const fallback_allocator_adaptor &other) noexcept =
Expand All @@ -96,28 +95,28 @@ class fallback_allocator_adaptor {
const fallback_allocator_adaptor &) noexcept = default;

/// \brief Copy assign operator, using an instance of
/// fallback_allocator_adaptor with any stateful_allocatorator type
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// fallback_allocator_adaptor with any stateful_allocator type
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor &operator=(
const fallback_allocator_adaptor<stateful_allocatorator_type2>
const fallback_allocator_adaptor<stateful_allocator_type2>
&other) noexcept {
m_stateful_allocatorator = other.stateful_allocatorator();
m_stateful_allocator = other.stateful_allocator();
return *this;
}

/// \brief Copy assign operator for any stateful_allocatorator
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// \brief Copy assign operator for any stateful_allocator
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor &operator=(
const stateful_allocatorator_type2 &allocator_instance) noexcept {
m_stateful_allocatorator = allocator_instance;
const stateful_allocator_type2 &allocator_instance) noexcept {
m_stateful_allocator = allocator_instance;
return *this;
}

Expand All @@ -126,37 +125,36 @@ class fallback_allocator_adaptor {
fallback_allocator_adaptor &&other) noexcept = default;

/// \brief Move assign operator, using an instance of
/// fallback_allocator_adaptor with any stateful_allocatorator type
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// fallback_allocator_adaptor with any stateful_allocator type
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor &operator=(
fallback_allocator_adaptor<stateful_allocatorator_type2>
&&other) noexcept {
m_stateful_allocatorator = std::move(other.stateful_allocatorator());
fallback_allocator_adaptor<stateful_allocator_type2> &&other) noexcept {
m_stateful_allocator = std::move(other.stateful_allocator());
return *this;
}

/// \brief Move assign operator for any stateful_allocatorator
template <typename stateful_allocatorator_type2,
std::enable_if_t<
std::is_constructible<stateful_allocator,
stateful_allocatorator_type2>::value,
int> = 0>
/// \brief Move assign operator for any stateful_allocator
template <
typename stateful_allocator_type2,
std::enable_if_t<std::is_constructible<stateful_allocator_type,
stateful_allocator_type2>::value,
int> = 0>
fallback_allocator_adaptor &operator=(
stateful_allocatorator_type2 &&allocator_instance) noexcept {
m_stateful_allocatorator = std::move(allocator_instance);
stateful_allocator_type2 &&allocator_instance) noexcept {
m_stateful_allocator = std::move(allocator_instance);
return *this;
}

/// \brief Allocates n * sizeof(T) bytes of storage
/// \param n The size to allocation
/// \return Returns a pointer
pointer allocate(const size_type n) const {
if (priv_stateful_allocatorator_available()) {
return m_stateful_allocatorator.allocate(n);
if (priv_stateful_allocator_available()) {
return m_stateful_allocator.allocate(n);
}
return priv_fallback_allocate(n);
}
Expand All @@ -165,8 +163,8 @@ class fallback_allocator_adaptor {
/// \param ptr A pointer to the storage
/// \param size The size of the storage
void deallocate(pointer ptr, const size_type size) const {
if (priv_stateful_allocatorator_available()) {
m_stateful_allocatorator.deallocate(ptr, size);
if (priv_stateful_allocator_available()) {
m_stateful_allocator.deallocate(ptr, size);
} else {
priv_fallback_deallocate(ptr);
}
Expand All @@ -175,7 +173,7 @@ class fallback_allocator_adaptor {
/// \brief The size of the theoretical maximum allocation size
/// \return The size of the theoretical maximum allocation size
size_type max_size() const noexcept {
return m_stateful_allocatorator.max_size();
return m_stateful_allocator.max_size();
}

/// \brief Constructs an object of T
Expand All @@ -184,8 +182,8 @@ class fallback_allocator_adaptor {
/// \param args The constructor arguments to use
template <class... Args>
void construct(const pointer &ptr, Args &&...args) const {
if (priv_stateful_allocatorator_available()) {
m_stateful_allocatorator.construct(ptr, std::forward<Args>(args)...);
if (priv_stateful_allocator_available()) {
m_stateful_allocator.construct(ptr, std::forward<Args>(args)...);
} else {
priv_fallback_construct(ptr, std::forward<Args>(args)...);
}
Expand All @@ -194,28 +192,35 @@ class fallback_allocator_adaptor {
/// \brief Deconstruct an object of T
/// \param ptr A pointer to the object
void destroy(const pointer &ptr) const {
if (priv_stateful_allocatorator_available()) {
m_stateful_allocatorator.destroy(ptr);
if (priv_stateful_allocator_available()) {
m_stateful_allocator.destroy(ptr);
} else {
priv_fallback_destroy(ptr);
}
}

// ---------- This class's unique public functions ---------- //
stateful_allocatorator_type &stateful_allocatorator() {
return m_stateful_allocatorator;

/// \brief Returns a reference to the stateful allocator.
stateful_allocator_type &get_stateful_allocator() { return m_stateful_allocator; }

/// \brief Returns a const reference to the stateful allocator.
const stateful_allocator_type &get_stateful_allocator() const {
return m_stateful_allocator;
}

const stateful_allocatorator_type &stateful_allocatorator() const {
return m_stateful_allocatorator;
/// \brief Returns true if the stateful allocator is available.
/// \return Returns true if the stateful allocator is available.
bool stateful_allocator_available() const {
return priv_stateful_allocator_available();
}

private:
// -------------------- //
// Private methods
// -------------------- //
auto priv_stateful_allocatorator_available() const {
return !!(m_stateful_allocatorator.get_pointer_to_manager_kernel());
auto priv_stateful_allocator_available() const {
return !!(m_stateful_allocator.get_pointer_to_manager_kernel());
}

pointer priv_fallback_allocate(const size_type n) const {
Expand Down Expand Up @@ -246,21 +251,21 @@ class fallback_allocator_adaptor {
// -------------------- //
// Private fields
// -------------------- //
stateful_allocatorator_type m_stateful_allocatorator;
stateful_allocator_type m_stateful_allocator;
};

template <typename stateful_allocatorator_type>
template <typename stateful_allocator_type>
inline bool operator==(
const fallback_allocator_adaptor<stateful_allocatorator_type> &rhd,
const fallback_allocator_adaptor<stateful_allocatorator_type> &lhd) {
const fallback_allocator_adaptor<stateful_allocator_type> &rhd,
const fallback_allocator_adaptor<stateful_allocator_type> &lhd) {
// Return true if they point to the same manager kernel
return rhd.stateful_allocatorator() == lhd.stateful_allocatorator();
return rhd.get_stateful_allocator() == lhd.get_stateful_allocator();
}

template <typename stateful_allocatorator_type>
template <typename stateful_allocator_type>
inline bool operator!=(
const fallback_allocator_adaptor<stateful_allocatorator_type> &rhd,
const fallback_allocator_adaptor<stateful_allocatorator_type> &lhd) {
const fallback_allocator_adaptor<stateful_allocator_type> &rhd,
const fallback_allocator_adaptor<stateful_allocator_type> &lhd) {
return !(rhd == lhd);
}

Expand Down
21 changes: 21 additions & 0 deletions test/container/fallback_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,27 @@ TEST(FallbackAllocatorAdaptorTest, Types) {
alloc);
GTEST_ASSERT_EQ(alloc, a2);
}

{
metall::manager manager(metall::create_only, dir_path(),
1UL << 27UL);
auto allocator = fb_alloc_type<int>(manager.get_allocator<int>());
ASSERT_EQ(allocator.get_stateful_allocator(), manager.get_allocator<int>());
}
}

TEST(FallbackAllocatorAdaptorTest, Availability) {
{
fb_alloc_type<int> allocator;
ASSERT_TRUE(!allocator.stateful_allocator_available());
}

{
metall::manager manager(metall::create_only, dir_path(),
1UL << 27UL);
auto allocator = fb_alloc_type<int>(manager.get_allocator<int>());
ASSERT_TRUE(allocator.stateful_allocator_available());
}
}

TEST(FallbackAllocatorAdaptorTest, Exception) {
Expand Down

0 comments on commit fc5d7e8

Please sign in to comment.