diff --git a/doc/tools.rst b/doc/tools.rst index ade730a14369a703b8441618104e0c19cb3948be..243535142b21ef219391f7e9a552b846b58ec60c 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 3469af8c1d5599d7b79e9cbd1f057df912b7d1f3..3491c69db8f6372aa0132f046d7714494081d41e 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<> wrapper( m, "MemoryPool"); wrapper - .def(py::init()) + .def(py::init(), + py::arg("allocator"), + py::arg("leading_bits_in_bin_id")=4 + ) .def("allocate", device_pool_allocate) .def("__call__", device_pool_allocate) // undoc for now diff --git a/test/test_wrapper.py b/test/test_wrapper.py index fa1e1d2714b477278da59df178eb6a8ea8b8b1f1..ea50bd5a9a7f9f5e89b62f9d276d1cdd92f48c6b 100644 --- a/test/test_wrapper.py +++ b/test/test_wrapper.py @@ -551,17 +551,22 @@ def test_mempool(ctx_factory): pool.stop_holding() -def test_mempool_2(): - from pyopencl.tools import MemoryPool +def test_mempool_2(ctx_factory): + from pyopencl.tools import MemoryPool, ImmediateAllocator from random import randrange + context = ctx_factory() + queue = cl.CommandQueue(context) + + pool = MemoryPool(ImmediateAllocator(queue)) + for i in range(2000): s = randrange(1 << 31) >> randrange(32) - bin_nr = MemoryPool.bin_number(s) - asize = MemoryPool.alloc_size(bin_nr) + bin_nr = pool.bin_number(s) + asize = pool.alloc_size(bin_nr) assert asize >= s, s - assert MemoryPool.bin_number(asize) == bin_nr, s + assert pool.bin_number(asize) == bin_nr, s assert asize < asize*(1+1/8)