Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FB Allocator #327

Merged
merged 5 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading