From a79df54f2c802f7cb5125d0fe29035707224a1a5 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Thu, 14 Mar 2019 18:59:08 -0500 Subject: [PATCH] Make leading bits used by mem pool configurable, document --- doc/tools.rst | 25 ++++++++++++++++++++++++- src/mempool.hpp | 36 +++++++++++++++++++++--------------- src/wrap_mempool.cpp | 9 ++++++--- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/doc/tools.rst b/doc/tools.rst index ade730a1..24353514 100644 --- a/doc/tools.rst +++ b/doc/tools.rst @@ -68,7 +68,7 @@ not complicated:: Allocate a :class:`pyopencl.Buffer` of the given *size*. -.. class:: MemoryPool(allocator) +.. class:: MemoryPool(allocator[, leading_bits_in_bin_id]) A memory pool for OpenCL device memory. *allocator* must be an instance of one of the above classes, and should be an :class:`ImmediateAllocator`. @@ -76,6 +76,29 @@ not complicated:: by the allocator immediately, and not in the OpenCL-typical deferred manner. + .. note:: + + The current implementation of the memory pool will retain allocated + memory after it is returned by the application and keep it in a bin + identified by the leading *leading_bits_in_bin_id* bits of the + allocation size. To ensure that allocations within each bin are + interchangeable, allocation sizes are rounded up to the largest size + that shares the leading bits of the requested allocation size. + + The current default value of *leading_bits_in_bin_id* is + four, but this may change in future versions and is not + guaranteed. + + *leading_bits_in_bin_id* must be passed by keyword, + and its role is purely advisory. It is not guaranteed + that future versions of the pool will use the + same allocation scheme and/or honor *leading_bits_in_bin_id*. + + .. versionchanged:: 2019.1 + + Current bin allocation behavior documented, *leading_bits_in_bin_id* + added. + .. attribute:: held_blocks The number of unused blocks being held by this pool. diff --git a/src/mempool.hpp b/src/mempool.hpp index 3469af8c..3491c69d 100644 --- a/src/mempool.hpp +++ b/src/mempool.hpp @@ -91,11 +91,13 @@ namespace PYGPU_PACKAGE bool m_stop_holding; int m_trace; + unsigned m_leading_bits_in_bin_id; + public: - memory_pool(Allocator const &alloc=Allocator()) + memory_pool(Allocator const &alloc=Allocator(), unsigned leading_bits_in_bin_id=4) : m_allocator(alloc.copy()), m_held_blocks(0), m_active_blocks(0), m_stop_holding(false), - m_trace(false) + m_trace(false), m_leading_bits_in_bin_id(leading_bits_in_bin_id) { if (m_allocator->is_deferred()) { @@ -109,17 +111,21 @@ namespace PYGPU_PACKAGE virtual ~memory_pool() { free_held(); } - static const unsigned mantissa_bits = 2; - static const unsigned mantissa_mask = (1 << mantissa_bits) - 1; + private: + unsigned mantissa_mask() const + { + return (1 << m_leading_bits_in_bin_id) - 1; + } - static bin_nr_t bin_number(size_type size) + public: + bin_nr_t bin_number(size_type size) { signed l = bitlog2(size); - size_type shifted = signed_right_shift(size, l-signed(mantissa_bits)); - if (size && (shifted & (1 << mantissa_bits)) == 0) + size_type shifted = signed_right_shift(size, l-signed(m_leading_bits_in_bin_id)); + if (size && (shifted & (1 << m_leading_bits_in_bin_id)) == 0) throw std::runtime_error("memory_pool::bin_number: bitlog2 fault"); - size_type chopped = shifted & mantissa_mask; - return l << mantissa_bits | chopped; + size_type chopped = shifted & mantissa_mask(); + return l << m_leading_bits_in_bin_id | chopped; } void set_trace(bool flag) @@ -130,19 +136,19 @@ namespace PYGPU_PACKAGE --m_trace; } - static size_type alloc_size(bin_nr_t bin) + size_type alloc_size(bin_nr_t bin) { - bin_nr_t exponent = bin >> mantissa_bits; - bin_nr_t mantissa = bin & mantissa_mask; + bin_nr_t exponent = bin >> m_leading_bits_in_bin_id; + bin_nr_t mantissa = bin & mantissa_mask(); size_type ones = signed_left_shift(1, - signed(exponent)-signed(mantissa_bits) + signed(exponent)-signed(m_leading_bits_in_bin_id) ); if (ones) ones -= 1; size_type head = signed_left_shift( - (1<<mantissa_bits) | mantissa, - signed(exponent)-signed(mantissa_bits)); + (1<<m_leading_bits_in_bin_id) | mantissa, + signed(exponent)-signed(m_leading_bits_in_bin_id)); if (ones & head) throw std::runtime_error("memory_pool::alloc_size: bit-counting fault"); return head | ones; diff --git a/src/wrap_mempool.cpp b/src/wrap_mempool.cpp index a6db0924..31cae81e 100644 --- a/src/wrap_mempool.cpp +++ b/src/wrap_mempool.cpp @@ -238,8 +238,8 @@ namespace wrapper .def_property_readonly("held_blocks", &cls::held_blocks) .def_property_readonly("active_blocks", &cls::active_blocks) - .DEF_SIMPLE_STATIC_METHOD(bin_number) - .DEF_SIMPLE_STATIC_METHOD(alloc_size) + .DEF_SIMPLE_METHOD(bin_number) + .DEF_SIMPLE_METHOD(alloc_size) .DEF_SIMPLE_METHOD(free_held) .DEF_SIMPLE_METHOD(stop_holding) ; @@ -293,7 +293,10 @@ void pyopencl_expose_mempool(py::module &m) cls, /* boost::noncopyable, */ std::shared_ptr<cls>> wrapper( m, "MemoryPool"); wrapper - .def(py::init<cl_allocator_base const &>()) + .def(py::init<cl_allocator_base const &, unsigned>(), + py::arg("allocator"), + py::arg("leading_bits_in_bin_id")=4 + ) .def("allocate", device_pool_allocate) .def("__call__", device_pool_allocate) // undoc for now -- GitLab