Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r69236 - in sandbox/guild/pool: boost/pool libs/pool/test
From: john_at_[hidden]
Date: 2011-02-24 07:19:49


Author: johnmaddock
Date: 2011-02-24 07:19:47 EST (Thu, 24 Feb 2011)
New Revision: 69236
URL: http://svn.boost.org/trac/boost/changeset/69236

Log:
Some further more advanced fixes for issue #2696:
Applies existing fix to array allocation,
Adds a test case,
Adds a fallback mechanism, so that if allocation fails we shrink the next chunk size.
Refs #2696.

Added:
   sandbox/guild/pool/libs/pool/test/test_bug_2696.cpp (contents, props changed)
Text files modified:
   sandbox/guild/pool/boost/pool/pool.hpp | 76 ++++++++++++++++++++++++++++++++-------
   sandbox/guild/pool/libs/pool/test/Jamfile.v2 | 1
   sandbox/guild/pool/libs/pool/test/test_bug_1252.cpp | 4 +-
   3 files changed, 65 insertions(+), 16 deletions(-)

Modified: sandbox/guild/pool/boost/pool/pool.hpp
==============================================================================
--- sandbox/guild/pool/boost/pool/pool.hpp (original)
+++ sandbox/guild/pool/boost/pool/pool.hpp 2011-02-24 07:19:47 EST (Thu, 24 Feb 2011)
@@ -230,7 +230,7 @@
 template <typename UserAllocator>
 //! \tparam UserAllocator type - the method that the Pool will use to allocate memory from the system.
 class pool: protected simple_segregated_storage < typename UserAllocator::size_type >
-{/*! \class boost::pool::pool
+{/*! \class boost::pool
   \brief A fast memory allocator that guarantees proper alignment of all allocated chunks.
   \details Whenever an object of type pool needs memory from the system,
   it will request it from its UserAllocator template parameter.
@@ -238,7 +238,7 @@
   that is, each time more system memory is allocated,
   the amount of system memory requested is doubled.
 
- Users may control the doubling algorithm by using the following extensions.
+ Users may control the doubling algorithm by using the following foobar extensions:
 
   Users may pass an additional constructor parameter to pool.
   This parameter is of type size_type,
@@ -246,6 +246,15 @@
   the first time that object needs to allocate system memory.
   The default is 32. This parameter may not be 0.
 
+ Users may also pass an optional third parameter to pool's
+ constructor. This parameter is of type size_type,
+ and sets a maximum size for allocated chunks. When this
+ parameter takes the default value of 0, then there is no upper
+ limit on chunk size.
+
+ Finally, if the doubling algorithm results in no memory
+ being allocated, the pool will backtrack just once, halving
+ the chunk size and trying again.
 
 */
   public:
@@ -645,12 +654,23 @@
 { //! No memory in any of our storages; make a new storage,
   //! Allocates chunk in newly malloc aftert resize.
   //! \returns pointer to chunk.
- const size_type partition_size = alloc_size();
- const size_type POD_size = next_size * partition_size +
+ size_type partition_size = alloc_size();
+ size_type POD_size = next_size * partition_size +
       details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
- char * const ptr = (UserAllocator::malloc)(POD_size);
+ char * ptr = (UserAllocator::malloc)(POD_size);
   if (ptr == 0)
- return 0;
+ {
+ if(next_size > 4)
+ {
+ next_size >>= 1;
+ partition_size = alloc_size();
+ POD_size = next_size * partition_size +
+ details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
+ ptr = (UserAllocator::malloc)(POD_size);
+ }
+ if(ptr == 0)
+ return 0;
+ }
   const details::PODptr<size_type> node(ptr, POD_size);
 
   BOOST_USING_STD_MIN();
@@ -674,12 +694,23 @@
 void * pool<UserAllocator>::ordered_malloc_need_resize()
 { //! No memory in any of our storages; make a new storage,
   //! \returns pointer to new chunk.
- const size_type partition_size = alloc_size();
- const size_type POD_size = next_size * partition_size +
+ size_type partition_size = alloc_size();
+ size_type POD_size = next_size * partition_size +
       details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
- char * const ptr = (UserAllocator::malloc)(POD_size);
+ char * ptr = (UserAllocator::malloc)(POD_size);
   if (ptr == 0)
- return 0;
+ {
+ if(next_size > 4)
+ {
+ next_size >>= 1;
+ partition_size = alloc_size();
+ POD_size = next_size * partition_size +
+ details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
+ ptr = (UserAllocator::malloc)(POD_size);
+ }
+ if(ptr == 0)
+ return 0;
+ }
   const details::PODptr<size_type> node(ptr, POD_size);
 
   BOOST_USING_STD_MIN();
@@ -749,11 +780,24 @@
   // Not enough memory in our storages; make a new storage,
   BOOST_USING_STD_MAX();
   next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks);
- const size_type POD_size = next_size * partition_size +
+ size_type POD_size = next_size * partition_size +
       details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
- char * const ptr = (UserAllocator::malloc)(POD_size);
+ char * ptr = (UserAllocator::malloc)(POD_size);
   if (ptr == 0)
- return 0;
+ {
+ if(num_chunks < next_size)
+ {
+ // Try again with just enough memory to do the job, or at least whatever we
+ // allocated last time:
+ next_size >>= 1;
+ next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks);
+ POD_size = next_size * partition_size +
+ details::pool::ct_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type);
+ ptr = (UserAllocator::malloc)(POD_size);
+ }
+ if(ptr == 0)
+ return 0;
+ }
   const details::PODptr<size_type> node(ptr, POD_size);
 
   // Split up block so we can use what wasn't requested.
@@ -761,7 +805,11 @@
     store().add_ordered_block(node.begin() + num_chunks * partition_size,
         node.element_size() - num_chunks * partition_size, partition_size);
 
- next_size <<= 1;
+ BOOST_USING_STD_MIN();
+ if(!max_size)
+ next_size <<= 1;
+ else if( next_size*partition_size/requested_size < max_size)
+ next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size);
 
   // insert it into the list,
   // handle border case.

Modified: sandbox/guild/pool/libs/pool/test/Jamfile.v2
==============================================================================
--- sandbox/guild/pool/libs/pool/test/Jamfile.v2 (original)
+++ sandbox/guild/pool/libs/pool/test/Jamfile.v2 2011-02-24 07:19:47 EST (Thu, 24 Feb 2011)
@@ -28,6 +28,7 @@
     [ run test_bug_3349.cpp ]
     [ run test_bug_4960.cpp ]
     [ run test_bug_1252.cpp ]
+ [ run test_bug_2696.cpp ]
     ;
 
 

Modified: sandbox/guild/pool/libs/pool/test/test_bug_1252.cpp
==============================================================================
--- sandbox/guild/pool/libs/pool/test/test_bug_1252.cpp (original)
+++ sandbox/guild/pool/libs/pool/test/test_bug_1252.cpp 2011-02-24 07:19:47 EST (Thu, 24 Feb 2011)
@@ -37,7 +37,7 @@
    unsigned limit = 100000;
    for(unsigned i = 0; i < limit; ++i)
    {
- void* ptr = p.malloc();
+ void* ptr = (p.malloc)();
       BOOST_TEST(reinterpret_cast<std::size_t>(ptr) % align == 0);
       // Trample over the memory just to be sure the allocated block is big enough,
       // if it's not, we'll trample over the next block as well (and our internal housekeeping).
@@ -49,7 +49,7 @@
 int main()
 {
    boost::pool<limited_allocator_new_delete> po(1501);
- void* p = po.malloc();
+ void* p = (po.malloc)();
    BOOST_TEST(p != 0);
 
    test_alignment(char(0));

Added: sandbox/guild/pool/libs/pool/test/test_bug_2696.cpp
==============================================================================
--- (empty file)
+++ sandbox/guild/pool/libs/pool/test/test_bug_2696.cpp 2011-02-24 07:19:47 EST (Thu, 24 Feb 2011)
@@ -0,0 +1,61 @@
+/* Copyright (C) 2011 John Maddock
+*
+* Use, modification and distribution is subject to the
+* Boost Software License, Version 1.0. (See accompanying
+* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+*/
+
+// Test of bug #2656 (https://svn.boost.org/trac/boost/ticket/2656)
+
+#include <boost/pool/pool.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+struct limited_allocator_new_delete
+{
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes)
+ {
+ static const unsigned max_size = 4 * 40 + sizeof(void*) + 2 * sizeof(std::size_t);
+ if(bytes > max_size)
+ return 0;
+ return new (std::nothrow) char[bytes];
+ }
+ static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block)
+ {
+ delete [] block;
+ }
+};
+
+int main()
+{
+ boost::pool<limited_allocator_new_delete> p1(4, 10, 40);
+ for(int i = 1; i <= 40; ++i)
+ BOOST_TEST((p1.ordered_malloc)(i));
+ BOOST_TEST(p1.ordered_malloc(42) == 0);
+ //
+ // If the largest block is 40, and we start with 10, we get 10+20+40 elements before
+ // we actually run out of memory:
+ //
+ boost::pool<limited_allocator_new_delete> p2(4, 10, 40);
+ for(int i = 1; i <= 70; ++i)
+ BOOST_TEST((p2.malloc)());
+ boost::pool<limited_allocator_new_delete> p2b(4, 10, 40);
+ for(int i = 1; i <= 100; ++i)
+ BOOST_TEST((p2b.ordered_malloc)());
+ //
+ // Try again with no explicit upper limit:
+ //
+ boost::pool<limited_allocator_new_delete> p3(4);
+ for(int i = 1; i <= 40; ++i)
+ BOOST_TEST((p3.ordered_malloc)(i));
+ BOOST_TEST(p3.ordered_malloc(42) == 0);
+ boost::pool<limited_allocator_new_delete> p4(4, 10);
+ for(int i = 1; i <= 100; ++i)
+ BOOST_TEST((p4.ordered_malloc)());
+ boost::pool<limited_allocator_new_delete> p5(4, 10);
+ for(int i = 1; i <= 100; ++i)
+ BOOST_TEST((p5.malloc)());
+ return boost::report_errors();
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk