From a79df54f2c802f7cb5125d0fe29035707224a1a5 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 14 Mar 2019 18:59:08 -0500 Subject: [PATCH 1/3] 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<> 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 -- GitLab From ccb427cc9cecb99b262ca8b8291d366cd8b65e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Fri, 15 Mar 2019 01:34:47 +0100 Subject: [PATCH 2/3] Adjust mempool tests for exposed leading bits --- test/test_wrapper.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/test_wrapper.py b/test/test_wrapper.py index fa1e1d27..f7fa55ee 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(): +def test_mempool_2(ctx_factory): from pyopencl.tools import MemoryPool 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) -- GitLab From 5854a211eb916d7bff372a364739439c08aacdfd Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Thu, 14 Mar 2019 22:10:57 -0500 Subject: [PATCH 3/3] Fix test_mempool_2 --- test/test_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_wrapper.py b/test/test_wrapper.py index f7fa55ee..ea50bd5a 100644 --- a/test/test_wrapper.py +++ b/test/test_wrapper.py @@ -552,7 +552,7 @@ def test_mempool(ctx_factory): def test_mempool_2(ctx_factory): - from pyopencl.tools import MemoryPool + from pyopencl.tools import MemoryPool, ImmediateAllocator from random import randrange context = ctx_factory() -- GitLab