//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2005 Peter Kümmel // Copyright (c) 2005 Richard Sposato // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The authors make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // $Id$ // ---------------------------------------------------------------------------- #define LOKI_SMALL_OBJECT_USE_NEW_ARRAY #ifndef LOKI_CLASS_LEVEL_THREADING #define LOKI_CLASS_LEVEL_THREADING #endif #include #include "timer.h" #include #include //#define COMPARE_BOOST_POOL #ifdef COMPARE_BOOST_POOL #include #endif using namespace std; // ---------------------------------------------------------------------------- template class ThisIsASmallObject { char data[N]; }; template struct Base : public ThisIsASmallObject, public T {}; template struct Base : public ThisIsASmallObject {}; // ---------------------------------------------------------------------------- #ifdef COMPARE_BOOST_POOL template class BoostPoolNew : public Base { private: static boost::object_pool< BoostPoolNew > BoostPool; public: /// Throwing single-object new throws bad_alloc when allocation fails. #ifdef _MSC_VER /// @note MSVC complains about non-empty exception specification lists. static void * operator new ( std::size_t ) #else static void * operator new ( std::size_t ) throw ( std::bad_alloc ) #endif { return BoostPool.malloc(); } /// Non-throwing single-object new returns NULL if allocation fails. static void * operator new ( std::size_t, const std::nothrow_t & ) throw () { return BoostPool.malloc(); } /// Placement single-object new merely calls global placement new. inline static void * operator new ( std::size_t size, void * place ) { return ::operator new( size, place ); } /// Single-object delete. static void operator delete ( void * p ) throw () { BoostPool.free( reinterpret_cast< BoostPoolNew * >( p ) ); } /** Non-throwing single-object delete is only called when nothrow new operator is used, and the constructor throws an exception. */ static void operator delete ( void * p, const std::nothrow_t & ) throw() { BoostPool.free( reinterpret_cast< BoostPoolNew * >( p ) ); } /// Placement single-object delete merely calls global placement delete. inline static void operator delete ( void * p, void * place ) { ::operator delete ( p, place ); } /** @note This class does not provide new [] and delete [] operators since the Boost.Pool allocator only works for memory requests of the same size. */ }; template boost::object_pool< BoostPoolNew > BoostPoolNew::BoostPool; #endif // ---------------------------------------------------------------------------- int array_test_nr = 0; double t100_new = 0; double t100_delete = 0; #define LOKI_SMALLOBJ_BENCH(FUNC, CODE_LOOP) \ template \ int FUNC(void**, const int N, int loop, Timer& t, const char* s) \ { \ t.start(); \ /****************************************************************/ \ for (int i=0; i \ int FUNC(void** arrv, const int N, int loop, Timer& t, const char* s) \ { \ \ CODE_DECL; \ T** arr = reinterpret_cast(arrv); \ t.start(); \ /****************************************************************/ \ for (int i=0; i st;st.deallocate(st.allocate(1), 1);) LOKI_SMALLOBJ_BENCH(delete_new_array ,delete[] new T[N];) LOKI_SMALLOBJ_BENCH(delete_new_array_mal,std::free(std::malloc(sizeof(T[TN])));) LOKI_SMALLOBJ_BENCH(delete_new_array_all,std::allocator st;st.deallocate(st.allocate(1), 1);) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_on_arr , , arr[i] = new T; , delete arr[i];) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_on_arr_mal, , arr[i] = static_cast(std::malloc(sizeof(T))); , std::free(arr[i]);) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_on_arr_all, std::allocator st , arr[i]=st.allocate(1); , st.deallocate(arr[i], 1);) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_a_on_a , , arr[i] = new T[TN]; , delete[] arr[i];) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_a_on_a_mal, , arr[i] = static_cast(std::malloc(sizeof(T[TN]))); , std::free(arr[i]);) LOKI_SMALLOBJ_BENCH_ARRAY(new_del_a_on_a_all,std::allocator st , arr[i]=reinterpret_cast(st.allocate(1)); , st.deallocate(reinterpret_cast(arr[i]), 1);) // ---------------------------------------------------------------------------- #ifndef COMPARE_BOOST_POOL #define LOKI_SMALL_OBJECT_BENCH_ABCD(FUNC,N,LOOP,TIMER,MESSAGE) \ array_test_nr = 0; \ cout << MESSAGE << endl; \ FUNC(a,N,LOOP,TIMER,"new :"); \ FUNC(a,N,LOOP,TIMER,"SmallObj :"); \ FUNC(a,N,LOOP,TIMER,"ValueObj :"); \ FUNC##_all(a,N,LOOP,TIMER,"allocator:"); \ FUNC##_mal(a,N,LOOP,TIMER,"malloc :"); \ cout << endl << endl; #else #define LOKI_SMALL_OBJECT_BENCH_ABCD(FUNC,N,LOOP,TIMER,MESSAGE) \ array_test_nr = 0; \ cout << MESSAGE << endl; \ FUNC(a,N,LOOP,TIMER,"new :"); \ FUNC(a,N,LOOP,TIMER,"SmallObj :"); \ FUNC(a,N,LOOP,TIMER,"ValueObj :"); \ FUNC(a,N,LOOP,TIMER,"boost :"); \ FUNC##_all(a,N,LOOP,TIMER,"allocator:"); \ FUNC##_mal(a,N,LOOP,TIMER,"malloc :"); \ cout << endl << endl; #endif // ---------------------------------------------------------------------------- template< unsigned int Size, int loop, template class ThreadingModel, std::size_t chunkSize, std::size_t maxSmallObjectSize, std::size_t objectAlignSize, template class LifetimePolicy, class MutexPolicy > void testSize() { typedef Base A; typedef Base > B; typedef Base > C; typedef Loki::AllocatorSingleton< ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy > AllocatorSingleton; #ifdef COMPARE_BOOST_POOL typedef BoostPoolNew D; #endif assert( (!AllocatorSingleton::IsCorrupted()) ); cout << endl << endl; cout << "Allocator Benchmark Tests with " << Size << " bytes big objects " << endl; cout << endl; cout << "new = global new/delete \tsizeof(A) = " << sizeof(A) << endl; cout << "SmallObj = Loki::SmallObject \tsizeof(B) = " << sizeof(B) << endl; cout << "ValueObj = Loki::SmallValueObject\tsizeof(C) = " << sizeof(C) << endl; #ifdef COMPARE_BOOST_POOL cout << "boost = boost::object_pool \tsizeof(D) = " << sizeof(D) << endl; #endif cout << "allocator= std::allocator \tsizeof(A) = " << sizeof(A) << endl; cout << "malloc = std::malloc/free \tsizeof(A) = " << sizeof(A) << endl; cout << endl << endl; Timer t; const int N = 3; int Narr = 1000*1000; void** a= new void*[Narr]; cout << loop << " times "; LOKI_SMALL_OBJECT_BENCH_ABCD(delete_new ,0,loop,t,"'delete new T'"); assert( (!AllocatorSingleton::IsCorrupted()) ); cout << "N=" << N <<" : " << loop << " times "; LOKI_SMALL_OBJECT_BENCH_ABCD(delete_new_array ,N,loop,t,"'delete[] new T[N]'"); assert( (!AllocatorSingleton::IsCorrupted()) ); cout << "i=0..." << Narr << " : "; LOKI_SMALL_OBJECT_BENCH_ABCD(new_del_on_arr ,0,Narr,t,"1. 'arr[i] = new T' 2. 'delete arr[i]'"); assert( (!AllocatorSingleton::IsCorrupted()) ); cout << "i=0..." << Narr << ", N=" << N <<" : "; LOKI_SMALL_OBJECT_BENCH_ABCD(new_del_a_on_a ,N,Narr,t,"1. 'arr[i] = new T[N]' 2. 'delete[] arr[i]'"); assert( (!AllocatorSingleton::IsCorrupted()) ); delete [] a; cout << "_________________________________________________________________" << endl; assert( (!AllocatorSingleton::IsCorrupted()) ); AllocatorSingleton::ClearExtraMemory(); } // ---------------------------------------------------------------------------- void DoSingleThreadTest (void) { const int loop = 1000*1000; cout << endl; testSize< 2, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 3, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 8, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 9, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 16, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 17, loop, ::Loki::SingleThreaded, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); #if defined(__BORLANDC__) || defined(_MSC_VER) system("PAUSE"); #endif } // ---------------------------------------------------------------------------- #if defined(LOKI_CLASS_LEVEL_THREADING) void DoClassLockTest (void) { const int loop = 1000*1000; cout << endl; testSize< 2, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 3, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 8, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 9, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 16, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); testSize< 17, loop, ::Loki::ClassLevelLockable, 4096, 128, 4, ::Loki::NoDestroy, ::Loki::Mutex >(); #if defined(__BORLANDC__) || defined(_MSC_VER) system("PAUSE"); #endif } #endif // ---------------------------------------------------------------------------- int main() { DoSingleThreadTest(); #if defined(LOKI_CLASS_LEVEL_THREADING) DoClassLockTest(); #endif return 0; } // ----------------------------------------------------------------------------