diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/libs/smart_ptr/extras | |
parent | Initial commit. (diff) | |
download | ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/smart_ptr/extras')
8 files changed, 1286 insertions, 0 deletions
diff --git a/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp b/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp new file mode 100644 index 000000000..bb69ae88b --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp @@ -0,0 +1,270 @@ +// +// sp_collector.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +#include <boost/assert.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/detail/lightweight_mutex.hpp> +#include <cstdlib> +#include <map> +#include <deque> +#include <iostream> + +typedef std::map< void const *, std::pair<void *, size_t> > map_type; + +static map_type & get_map() +{ + static map_type m; + return m; +} + +typedef boost::detail::lightweight_mutex mutex_type; + +static mutex_type & get_mutex() +{ + static mutex_type m; + return m; +} + +static void * init_mutex_before_main = &get_mutex(); + +namespace +{ + class X; + + struct count_layout + { + boost::detail::sp_counted_base * pi; + int id; + }; + + struct shared_ptr_layout + { + X * px; + count_layout pn; + }; +} + +// assume 4 byte alignment for pointers when scanning +size_t const pointer_align = 4; + +typedef std::map<void const *, long> map2_type; + +static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2) +{ + unsigned char const * p = static_cast<unsigned char const *>(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0) + { + ++m2[q->pn.pi]; + } + } +} + +typedef std::deque<void const *> open_type; + +static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open) +{ + unsigned char const * p = static_cast<unsigned char const *>(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0) + { + open.push_back(q->pn.pi); + m2.erase(q->pn.pi); + } + } +} + +static void find_unreachable_objects_impl(map_type const & m, map2_type & m2) +{ + // scan objects for shared_ptr members, compute internal counts + + { + std::cout << "... " << m.size() << " objects in m.\n"; + + for(map_type::const_iterator i = m.begin(); i != m.end(); ++i) + { + boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first); + + BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map + + m2[ i->first ]; + + scan_and_count(i->second.first, i->second.second, m, m2); + } + + std::cout << "... " << m2.size() << " objects in m2.\n"; + } + + // mark reachable objects + + { + open_type open; + + for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i) + { + boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first); + if(p->use_count() != i->second) open.push_back(p); + } + + std::cout << "... " << open.size() << " objects in open.\n"; + + for(open_type::iterator j = open.begin(); j != open.end(); ++j) + { + m2.erase(*j); + } + + while(!open.empty()) + { + void const * p = open.front(); + open.pop_front(); + + map_type::const_iterator i = m.find(p); + BOOST_ASSERT(i != m.end()); + + scan_and_mark(i->second.first, i->second.second, m2, open); + } + } + + // m2 now contains the unreachable objects +} + +std::size_t find_unreachable_objects(bool report) +{ + map2_type m2; + +#ifdef BOOST_HAS_THREADS + + // This will work without the #ifdef, but some compilers warn + // that lock is not referenced + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + map_type const & m = get_map(); + + find_unreachable_objects_impl(m, m2); + + if(report) + { + for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) + { + map_type::const_iterator i = m.find(j->first); + BOOST_ASSERT(i != m.end()); + std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n"; + } + } + + return m2.size(); +} + +typedef std::deque< boost::shared_ptr<X> > free_list_type; + +static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free) +{ + unsigned char * p = static_cast<unsigned char *>(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0) + { + boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p); + free.push_back(*ppx); + ppx->reset(); + } + } +} + +void free_unreachable_objects() +{ + free_list_type free; + + { + map2_type m2; + +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + map_type const & m = get_map(); + + find_unreachable_objects_impl(m, m2); + + for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) + { + map_type::const_iterator i = m.find(j->first); + BOOST_ASSERT(i != m.end()); + scan_and_free(i->second.first, i->second.second, m2, free); + } + } + + std::cout << "... about to free " << free.size() << " objects.\n"; +} + +// debug hooks + +namespace boost +{ + +void sp_scalar_constructor_hook(void *) +{ +} + +void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn) +{ +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + get_map()[pn] = std::make_pair(px, size); +} + +void sp_scalar_destructor_hook(void *) +{ +} + +void sp_scalar_destructor_hook(void *, std::size_t, void * pn) +{ +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + get_map().erase(pn); +} + +void sp_array_constructor_hook(void *) +{ +} + +void sp_array_destructor_hook(void *) +{ +} + +} // namespace boost + +#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS) diff --git a/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp b/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp new file mode 100644 index 000000000..31939363b --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp @@ -0,0 +1,243 @@ +// +// sp_debug_hooks.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +#include <boost/assert.hpp> +#include <new> +#include <cstdlib> + +int const m = 2; // m * sizeof(int) must be aligned appropriately + +// magic values to mark heap blocks with + +int const allocated_scalar = 0x1234560C; +int const allocated_array = 0x1234560A; +int const adopted_scalar = 0x0567890C; +int const adopted_array = 0x0567890A; +int const deleted = 0x498769DE; + +using namespace std; // for compilers where things aren't in std + +// operator new + +static new_handler get_new_handler() +{ + new_handler p = set_new_handler(0); + set_new_handler(p); + return p; +} + +static void * allocate(size_t n, int mark) +{ + int * pm; + + for(;;) + { + pm = static_cast<int*>(malloc(n + m * sizeof(int))); + + if(pm != 0) break; + + if(new_handler pnh = get_new_handler()) + { + pnh(); + } + else + { + return 0; + } + } + + *pm = mark; + + return pm + m; +} + +void * operator new(size_t n) throw(bad_alloc) +{ + void * p = allocate(n, allocated_scalar); + +#if !defined(BOOST_NO_EXCEPTIONS) + + if(p == 0) throw bad_alloc(); + +#endif + + return p; +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void * operator new(size_t n, nothrow_t const &) throw() +{ + return allocate(n, allocated_scalar); +} + +#endif + +void * operator new[](size_t n) throw(bad_alloc) +{ + void * p = allocate(n, allocated_array); + +#if !defined(BOOST_NO_EXCEPTIONS) + + if(p == 0) throw bad_alloc(); + +#endif + + return p; +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void * operator new[](size_t n, nothrow_t const &) throw() +{ + return allocate(n, allocated_array); +} + +#endif + +// debug hooks + +namespace boost +{ + +void sp_scalar_constructor_hook(void * p) +{ + if(p == 0) return; + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm != adopted_scalar); // second smart pointer to the same address + BOOST_ASSERT(*pm != allocated_array); // allocated with new[] + BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new + + *pm = adopted_scalar; +} + +void sp_scalar_constructor_hook(void * px, std::size_t, void *) +{ + sp_scalar_constructor_hook(px); +} + +void sp_scalar_destructor_hook(void * p) +{ + if(p == 0) return; + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm == adopted_scalar); // attempt to destroy nonmanaged block + + *pm = allocated_scalar; +} + +void sp_scalar_destructor_hook(void * px, std::size_t, void *) +{ + sp_scalar_destructor_hook(px); +} + +// It is not possible to handle the array hooks in a portable manner. +// The implementation typically reserves a bit of storage for the number +// of objects in the array, and the argument of the array hook isn't +// equal to the return value of operator new[]. + +void sp_array_constructor_hook(void * /* p */) +{ +/* + if(p == 0) return; + + // adjust p depending on the implementation + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm != adopted_array); // second smart array pointer to the same address + BOOST_ASSERT(*pm != allocated_scalar); // allocated with new + BOOST_ASSERT(*pm == allocated_array); // not allocated with new[] + + *pm = adopted_array; +*/ +} + +void sp_array_destructor_hook(void * /* p */) +{ +/* + if(p == 0) return; + + // adjust p depending on the implementation + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm == adopted_array); // attempt to destroy nonmanaged block + + *pm = allocated_array; +*/ +} + +} // namespace boost + +// operator delete + +void operator delete(void * p) throw() +{ + if(p == 0) return; + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm != deleted); // double delete + BOOST_ASSERT(*pm != adopted_scalar); // delete p.get(); + BOOST_ASSERT(*pm != allocated_array); // allocated with new[] + BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new + + *pm = deleted; + + free(pm); +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void operator delete(void * p, nothrow_t const &) throw() +{ + ::operator delete(p); +} + +#endif + +void operator delete[](void * p) throw() +{ + if(p == 0) return; + + int * pm = static_cast<int*>(p); + pm -= m; + + BOOST_ASSERT(*pm != deleted); // double delete + BOOST_ASSERT(*pm != adopted_scalar); // delete p.get(); + BOOST_ASSERT(*pm != allocated_scalar); // allocated with new + BOOST_ASSERT(*pm == allocated_array); // not allocated with new[] + + *pm = deleted; + + free(pm); +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void operator delete[](void * p, nothrow_t const &) throw() +{ + ::operator delete[](p); +} + +#endif + +#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS) diff --git a/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp new file mode 100644 index 000000000..8a504256e --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp @@ -0,0 +1,82 @@ +#include <boost/config.hpp> + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// shared_ptr_mt_test.cpp - tests shared_ptr with multiple threads +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include <vector> + +#include <cstdio> +#include <ctime> + +#include <boost/detail/lightweight_thread.hpp> + +// + +int const n = 1024 * 1024; + +void test( boost::shared_ptr<int> const & pi ) +{ + std::vector< boost::shared_ptr<int> > v; + + for( int i = 0; i < n; ++i ) + { + v.push_back( pi ); + } +} + +int const m = 16; // threads + +#if defined( BOOST_HAS_PTHREADS ) + +char const * thmodel = "POSIX"; + +#else + +char const * thmodel = "Windows"; + +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf( "Using %s threads: %d threads, %d iterations: ", thmodel, m, n ); + + boost::shared_ptr<int> pi( new int(42) ); + + clock_t t = clock(); + + boost::detail::lw_thread_t a[ m ]; + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( test, pi ) ); + } + + for( int j = 0; j < m; ++j ) + { + boost::detail::lw_thread_join( a[j] ); + } + + t = clock() - t; + + printf( "\n\n%.3f seconds.\n", static_cast<double>(t) / CLOCKS_PER_SEC ); + + return 0; +} diff --git a/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp b/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp new file mode 100644 index 000000000..79e62ff43 --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp @@ -0,0 +1,46 @@ +#include <boost/config.hpp> + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// shared_ptr_timing_test.cpp - use to evaluate the impact of thread safety +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/shared_ptr.hpp> +#include <iostream> +#include <vector> +#include <ctime> + +int const n = 8 * 1024 * 1024; + +int main() +{ + using namespace std; + + std::vector< boost::shared_ptr<int> > v; + boost::shared_ptr<int> pi(new int); + + clock_t t = clock(); + + for(int i = 0; i < n; ++i) + { + v.push_back(pi); + } + + t = clock() - t; + + std::cout << static_cast<double>(t) / CLOCKS_PER_SEC << '\n'; + + return 0; +} diff --git a/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp new file mode 100644 index 000000000..750b0b26a --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp @@ -0,0 +1,247 @@ + +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include <boost/config.hpp> + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/locks.hpp> + +#include <boost/detail/lightweight_mutex.hpp> +#include <boost/detail/lightweight_thread.hpp> + +#include <vector> +#include <numeric> +#include <cstdio> +#include <cstdlib> +#include <cstddef> +#include <ctime> + +// + +static void next_value( unsigned & v ) +{ + v = v % 2? 3 * v + 1: v / 2; +} + +struct X +{ + std::vector<unsigned> v_; + + explicit X( std::size_t n ): v_( n ) + { + for( std::size_t i = 0; i < n; ++i ) + { + v_[ i ] = i; + } + } + + unsigned get() const + { + return std::accumulate( v_.begin(), v_.end(), 0 ); + } + + void set() + { + std::for_each( v_.begin(), v_.end(), next_value ); + } +}; + +static boost::shared_ptr<X> ps; + +static boost::detail::lightweight_mutex lm; +static boost::shared_mutex rw; + +enum prim_type +{ + pt_mutex, + pt_rwlock, + pt_atomics +}; + +int read_access( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + { + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + return ps->get(); + } + + case pt_rwlock: + { + boost::shared_lock<boost::shared_mutex> lock( rw ); + return ps->get(); + } + + case pt_atomics: + { + boost::shared_ptr<X> p2 = boost::atomic_load( &ps ); + return p2->get(); + } + } +} + +void write_access( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + { + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + ps->set(); + } + break; + + case pt_rwlock: + { + boost::unique_lock<boost::shared_mutex> lock( rw ); + ps->set(); + } + break; + + case pt_atomics: + { + boost::shared_ptr<X> p1 = boost::atomic_load( &ps ); + + for( ;; ) + { + boost::shared_ptr<X> p2( new X( *p1 ) ); + p2->set(); + + if( boost::atomic_compare_exchange( &ps, &p1, p2 ) ) break; + } + } + break; + } +} + +void worker( int k, prim_type pt, int n, int r ) +{ + ++r; + + unsigned s = 0, nr = 0, nw = 0; + + for( int i = 0; i < n; ++i ) + { + if( i % r ) + { + s += read_access( pt ); + ++nr; + } + else + { + write_access( pt ); + ++s; + ++nw; + } + } + + printf( "Worker %2d: %u:%u, %10u\n", k, nr, nw, s ); +} + +#if defined( BOOST_HAS_PTHREADS ) + char const * thmodel = "POSIX"; +#else + char const * thmodel = "Windows"; +#endif + +char const * pt_to_string( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + + return "mutex"; + + case pt_rwlock: + + return "rwlock"; + + case pt_atomics: + + return "atomics"; + } +} + +static void handle_pt_option( std::string const & opt, prim_type & pt, prim_type pt2 ) +{ + if( opt == pt_to_string( pt2 ) ) + { + pt = pt2; + } +} + +static void handle_int_option( std::string const & opt, std::string const & prefix, int & k, int kmin, int kmax ) +{ + if( opt.substr( 0, prefix.size() ) == prefix ) + { + int v = atoi( opt.substr( prefix.size() ).c_str() ); + + if( v >= kmin && v <= kmax ) + { + k = v; + } + } +} + +int main( int ac, char const * av[] ) +{ + using namespace std; // printf, clock_t, clock + + int m = 4; // threads + int n = 10000; // vector size + int k = 1000000; // iterations + int r = 100; // read/write ratio, r:1 + + prim_type pt = pt_atomics; + + for( int i = 1; i < ac; ++i ) + { + handle_pt_option( av[i], pt, pt_mutex ); + handle_pt_option( av[i], pt, pt_rwlock ); + handle_pt_option( av[i], pt, pt_atomics ); + + handle_int_option( av[i], "n=", n, 1, INT_MAX ); + handle_int_option( av[i], "size=", n, 1, INT_MAX ); + + handle_int_option( av[i], "k=", k, 1, INT_MAX ); + handle_int_option( av[i], "iterations=", k, 1, INT_MAX ); + + handle_int_option( av[i], "m=", m, 1, INT_MAX ); + handle_int_option( av[i], "threads=", m, 1, INT_MAX ); + + handle_int_option( av[i], "r=", r, 1, INT_MAX ); + handle_int_option( av[i], "ratio=", r, 1, INT_MAX ); + } + + printf( "%s: threads=%d size=%d iterations=%d ratio=%d %s\n\n", thmodel, m, n, k, r, pt_to_string( pt ) ); + + ps.reset( new X( n ) ); + + clock_t t = clock(); + + std::vector<boost::detail::lw_thread_t> a( m ); + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( worker, i, pt, k, r ) ); + } + + for( int j = 0; j < m; ++j ) + { + boost::detail::lw_thread_join( a[ j ] ); + } + + t = clock() - t; + + double ts = static_cast<double>( t ) / CLOCKS_PER_SEC; + printf( "%.3f seconds, %.3f accesses per microsecond.\n", ts, m * k / ts / 1e+6 ); +} diff --git a/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp new file mode 100644 index 000000000..32c76c514 --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp @@ -0,0 +1,191 @@ + +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +//#define USE_MUTEX +//#define USE_RWLOCK + +#include <boost/config.hpp> + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#if defined( USE_RWLOCK ) +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/locks.hpp> +#endif + +#include <boost/detail/lightweight_mutex.hpp> +#include <boost/detail/lightweight_test.hpp> +#include <boost/detail/lightweight_thread.hpp> + +#include <cstdio> +#include <ctime> + +// + +int const n = 1024 * 1024; + +struct X +{ + int v_; // version + + unsigned a_; + unsigned b_; + + X(): v_( 0 ), a_( 1 ), b_( 1 ) + { + } + + int get() const + { + return a_ * 7 + b_ * 11; + } + + void set() + { + int tmp = get(); + + b_ = a_; + a_ = tmp; + + ++v_; + } +}; + +static boost::shared_ptr<X> ps( new X ); + +static boost::detail::lightweight_mutex lm; + +#if defined( USE_RWLOCK ) +static boost::shared_mutex rw; +#endif + +static int tr = 0; + +void reader( int r ) +{ + int k = 0; + unsigned s = 0; + + for( int i = 0; i < n; ++k ) + { +#if defined( USE_MUTEX ) + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + + s += ps->get(); + + BOOST_TEST( ps->v_ >= i ); + i = ps->v_; + +#elif defined( USE_RWLOCK ) + + boost::shared_lock<boost::shared_mutex> lock( rw ); + + s += ps->get(); + + BOOST_TEST( ps->v_ >= i ); + i = ps->v_; + +#else + + boost::shared_ptr<X> p2 = boost::atomic_load( &ps ); + + s += p2->get(); + + BOOST_TEST( p2->v_ >= i ); + i = p2->v_; + +#endif + } + + printf( "Reader %d: %9d iterations (%6.3fx), %u\n", r, k, (double)k / n, s ); + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + tr += k; +} + +void writer() +{ + for( int i = 0; i < n; ++i ) + { +#if defined( USE_MUTEX ) + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + + BOOST_TEST( ps->v_ == i ); + ps->set(); + +#elif defined( USE_RWLOCK ) + + boost::unique_lock<boost::shared_mutex> lock( rw ); + + BOOST_TEST( ps->v_ == i ); + ps->set(); + +#else + + boost::shared_ptr<X> p2( new X( *ps ) ); + + BOOST_TEST( p2->v_ == i ); + p2->set(); + + boost::atomic_store( &ps, p2 ); + +#endif + } +} + +#if defined( BOOST_HAS_PTHREADS ) + char const * thmodel = "POSIX"; +#else + char const * thmodel = "Windows"; +#endif + +int const mr = 8; // reader threads +int const mw = 1; // writer thread + +#if defined( USE_MUTEX ) + char const * prim = "mutex"; +#elif defined( USE_RWLOCK ) + char const * prim = "rwlock"; +#else + char const * prim = "atomics"; +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf( "Using %s threads: %dR + %dW threads, %d iterations, %s\n\n", thmodel, mr, mw, n, prim ); + + clock_t t = clock(); + + boost::detail::lw_thread_t a[ mr+mw ]; + + for( int i = 0; i < mr; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( reader, i ) ); + } + + for( int i = mr; i < mr+mw; ++i ) + { + boost::detail::lw_thread_create( a[ i ], writer ); + } + + for( int j = 0; j < mr+mw; ++j ) + { + boost::detail::lw_thread_join( a[ j ] ); + } + + t = clock() - t; + + double ts = static_cast<double>( t ) / CLOCKS_PER_SEC; + printf( "%.3f seconds, %.3f reads per microsecond.\n", ts, tr / ts / 1e+6 ); + + return boost::report_errors(); +} diff --git a/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp new file mode 100644 index 000000000..5b11ff9c6 --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp @@ -0,0 +1,122 @@ +#include <boost/config.hpp> + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// weak_ptr_mt_test.cpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright 2005, 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/bind.hpp> + +#include <vector> + +#include <cstdio> +#include <ctime> +#include <cstdlib> + +#include <boost/detail/lightweight_thread.hpp> + +// + +int const n = 16384; +int const k = 512; // vector size +int const m = 16; // threads + +void test( std::vector< boost::shared_ptr<int> > & v ) +{ + using namespace std; // printf, rand + + std::vector< boost::weak_ptr<int> > w( v.begin(), v.end() ); + + int s = 0, f = 0, r = 0; + + for( int i = 0; i < n; ++i ) + { + // randomly kill a pointer + + v[ rand() % k ].reset(); + ++s; + + for( int j = 0; j < k; ++j ) + { + if( boost::shared_ptr<int> px = w[ j ].lock() ) + { + ++s; + + if( rand() & 4 ) + { + continue; + } + + // rebind anyway with prob. 50% for add_ref_lock() against weak_release() contention + ++f; + } + else + { + ++r; + } + + w[ j ] = v[ rand() % k ]; + } + } + + printf( "\n%d locks, %d forced rebinds, %d normal rebinds.", s, f, r ); +} + +#if defined( BOOST_HAS_PTHREADS ) + +char const * thmodel = "POSIX"; + +#else + +char const * thmodel = "Windows"; + +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf("Using %s threads: %d threads, %d * %d iterations: ", thmodel, m, n, k ); + + std::vector< boost::shared_ptr<int> > v( k ); + + for( int i = 0; i < k; ++i ) + { + v[ i ].reset( new int( 0 ) ); + } + + clock_t t = clock(); + + boost::detail::lw_thread_t a[ m ]; + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( test, v ) ); + } + + v.resize( 0 ); // kill original copies + + for( int j = 0; j < m; ++j ) + { + boost::detail::lw_thread_join( a[j] ); + } + + t = clock() - t; + + printf("\n\n%.3f seconds.\n", static_cast<double>(t) / CLOCKS_PER_SEC); + + return 0; +} diff --git a/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp b/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp new file mode 100644 index 000000000..1c24b0a3b --- /dev/null +++ b/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp @@ -0,0 +1,85 @@ +#include <boost/config.hpp> + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// weak_ptr_timing_test.cpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright 2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + +#include <vector> +#include <cstdio> +#include <ctime> +#include <cstdlib> + +// + +int const n = 29000; +int const k = 2048; + +void test( std::vector< boost::shared_ptr<int> > & v ) +{ + using namespace std; // printf, rand + + std::vector< boost::weak_ptr<int> > w( v.begin(), v.end() ); + + int s = 0, r = 0; + + for( int i = 0; i < n; ++i ) + { + // randomly kill a pointer + + v[ rand() % k ].reset(); + + for( int j = 0; j < k; ++j ) + { + if( boost::shared_ptr<int> px = w[ j ].lock() ) + { + ++s; + } + else + { + ++r; + w[ j ] = v[ rand() % k ]; + } + } + } + + printf( "\n%d locks, %d rebinds.", s, r ); +} + +int main() +{ + using namespace std; // printf, clock_t, clock + + std::vector< boost::shared_ptr<int> > v( k ); + + for( int i = 0; i < k; ++i ) + { + v[ i ].reset( new int( 0 ) ); + } + + clock_t t = clock(); + + test( v ); + + t = clock() - t; + + printf( "\n\n%.3f seconds.\n", static_cast<double>( t ) / CLOCKS_PER_SEC ); + + return 0; +} |