std::pmr for s3select memory management?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The s3select library uses a cool custom arena allocator for a lot of
its small allocations, so they can be mostly satisfied without locking
and freed all at once at the end of a query. This allocator is only
currently used for the AST nodes and functions, though, and doesn't
cover allocations from std library types like string/map/vector.

I was looking more closely at the std::pmr library from c++17 as a way
to use this custom allocator with the std containers. I found that it
also provides a
https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource
class with similar properties to this custom arena allocator:

  "The class std::pmr::monotonic_buffer_resource is a special-purpose
memory resource class that releases the allocated memory only when the
resource is destroyed. It is intended for very fast memory allocations
in situations where memory is used to build up a few objects and then
is released all at once.

  monotonic_buffer_resource can be constructed with an initial buffer.
If there is no initial buffer, or if the buffer is exhausted,
additional buffers are obtained from an upstream memory resource
supplied at construction. The size of buffers obtained follows a
geometric progression.

  monotonic_buffer_resource is not thread-safe."

I think the ideal s3select interface would take a
std::pmr::memory_resource* as input, so the application could pass in
whatever allocation strategy it wanted. Radosgw could choose to use
std::pmr::monotonic_buffer_resource directly, a derived
memory_resource that wraps it, a custom memory_resource that uses the
existing logic in class s3select_allocator, or even nullptr to use the
default new/delete resource.

Integration of std::pmr in s3select could come in two parts: one for
use with std library types, and one for the general allocation of
things like our AST nodes and functions.

For the std containers, we can replace types like std::vector with
their aliases in namespace std::pmr - i.e. std::pmr::vector<T> is just
a std::vector<T, std::pmr::polymorphic_allocator<T>>. When
constructing these container types, we'd just have to pass a pointer
to its memory_resource as the allocator argument. That would also
require passing the pointer to the constructors of any types that have
std containers as members.

For general allocations, we can use std::unique_ptr<> with a custom
Deleter that frees its memory back to the std::pmr::memory_resource it
came from, and a helper function like pmr_allocate_unique<T>() that
takes a std::pmr::memory_resource pointer, allocates/constructs a T
using the std::pmr::polymorphic_allocator<T>, and returns it as a
unique_ptr. Use of unique_ptr means that the object lifetimes are
managed automatically, instead of having to track all allocations in a
list with a cleanup step that calls their destructors.

Here's what the unique_ptr stuff looks like:

#include <memory>
#include <memory_resource>

// a unique_ptr Deleter that frees memory from a polymorphic memory resource
class pmr_deleter {
  std::pmr::memory_resource* r;
 public:
  pmr_deleter(std::pmr::memory_resource* r = nullptr) : r(r) {}

  template <typename T>
  void operator()(T* ptr) const {
    std::pmr::polymorphic_allocator<T> alloc{r};
    alloc.destroy(ptr);
    alloc.deallocate(ptr, 1);
  }
};

// a unique_ptr alias for pmr-allocated pointers
template <typename T>
using pmr_unique_ptr = std::unique_ptr<T, pmr_deleter>;

template <typename T, typename ...Args>
pmr_unique_ptr<T> pmr_allocate_unique(std::pmr::memory_resource* r,
Args&& ...args)
{
  std::pmr::polymorphic_allocator<T> alloc{r};
  auto p = alloc.allocate(1);
  try {
    alloc.construct(p, std::forward<Args>(args)...); // may throw
    return {p, r};
  } catch (const std::exception&) {
    alloc.deallocate(p, 1);
    throw;
  }
}
_______________________________________________
Dev mailing list -- dev@xxxxxxx
To unsubscribe send an email to dev-leave@xxxxxxx



[Index of Archives]     [CEPH Users]     [Ceph Devel]     [Ceph Large]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux