Added copyright and license
[libcds.git] / tests / unit / alloc / linux_scale.cpp
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 // Linux scalability allocator test
32
33 #include "alloc/michael_allocator.h"
34
35 #include <cds/os/timer.h>
36 #include <cds/os/topology.h>
37
38 #include "cppunit/thread.h"
39
40 namespace memory {
41
42     static size_t s_nPassCount = 10000000;
43     static size_t s_nMaxBlockSize = 64 * 1024 - 16;
44     static size_t s_nMaxThreadCount = 64;
45
46     static size_t s_nPassPerThread;
47
48 #    define TEST_ALLOC(X, CLASS)    void X() { test< CLASS >(false)     ; }
49 #    define TEST_ALLOC_STAT(X, CLASS)    void X() { test< CLASS >(true) ; }
50
51     class Linux_Scale: public CppUnitMini::TestCase
52     {
53         template <class ALLOC>
54         class Thread: public CppUnitMini::TestThread
55         {
56             ALLOC&      m_Alloc;
57             size_t      m_nSize;
58
59             virtual Thread *    clone()
60             {
61                 return new Thread( *this );
62             }
63         public:
64
65         public:
66             Thread( CppUnitMini::ThreadPool& pool, ALLOC& a, size_t nSize )
67                 : CppUnitMini::TestThread( pool )
68                 , m_Alloc( a )
69                 , m_nSize( nSize )
70             {}
71             Thread( Thread& src )
72                 : CppUnitMini::TestThread( src )
73                 , m_Alloc( src.m_Alloc )
74                 , m_nSize( src.m_nSize )
75             {}
76
77             Linux_Scale&  getTest()
78             {
79                 return reinterpret_cast<Linux_Scale&>( m_Pool.m_Test );
80             }
81
82             virtual void init() { cds::threading::Manager::attachThread()   ; }
83             virtual void fini() { cds::threading::Manager::detachThread()   ; }
84
85             virtual void test()
86             {
87                 for ( size_t i = 0; i < s_nPassPerThread; ++i ) {
88                     typename ALLOC::value_type * p = m_Alloc.allocate( m_nSize / sizeof( typename ALLOC::value_type ), nullptr );
89                     CPPUNIT_ASSERT( p != nullptr );
90                     if ( m_nSize < 32 )
91                         memset( p, 0, m_nSize );
92                     else {
93                         memset( p, 0, 16 );
94                         memset( ((char *)p) + m_nSize * sizeof(*p) - 16, 0, 16 );
95                     }
96                     CPPUNIT_ASSERT( (reinterpret_cast<uintptr_t>(p) & (ALLOC::alignment - 1)) == 0 );
97                     m_Alloc.deallocate( p, 1 );
98                 }
99             }
100         };
101
102         template <class ALLOC>
103         void test( size_t nThreadCount, size_t nSize )
104         {
105             cds::OS::Timer    timer;
106
107             ALLOC alloc;
108
109             CPPUNIT_MSG( "   Block size=" << nSize );
110             s_nPassPerThread = s_nPassCount / nThreadCount;
111
112             CppUnitMini::ThreadPool pool( *this );
113             pool.add( new Thread<ALLOC>( pool, alloc, nSize ), nThreadCount );
114             pool.run();
115             CPPUNIT_MSG( "      Duration=" << pool.avgDuration() );
116         }
117
118         template <class ALLOC>
119         void test( size_t nThreadCount )
120         {
121             CPPUNIT_MSG( "Thread count=" << nThreadCount );
122             for ( size_t sz = 1; sz < s_nMaxBlockSize; sz *= 2 ) {
123                 test<ALLOC>( nThreadCount, sz );
124             }
125         }
126
127         template <class ALLOC>
128         void test( bool bStat )
129         {
130             for ( size_t nThreadCount = 1; nThreadCount <= s_nMaxThreadCount; nThreadCount *= 2 ) {
131                 summary_stat stBegin;
132                 if ( bStat )
133                     ALLOC::stat(stBegin);
134
135                 test<ALLOC>( nThreadCount );
136
137                 summary_stat    stEnd;
138                 if ( bStat ) {
139                     ALLOC::stat( stEnd );
140
141                     std::cout << "\nStatistics:\n"
142                         << stEnd;
143                     stEnd -= stBegin;
144                     std::cout << "\nDelta statistics:\n"
145                         << stEnd;
146                 }
147             }
148         }
149
150         void setUpParams( const CppUnitMini::TestCfg& cfg )
151         {
152             s_nPassCount = cfg.getULong( "PassCount", 10000000 );
153             s_nMaxBlockSize = cfg.getULong( "MaxBlockSize", 64 * 1024 - 16 );
154             s_nMaxThreadCount = cfg.getUInt( "MaxThreadCount", 64 );
155             if ( s_nMaxThreadCount == 0 )
156                 s_nMaxThreadCount = cds::OS::topology::processor_count() * 2;
157         }
158
159         typedef MichaelAlignHeap_Stat<char, 64>      t_MichaelAlignHeap_Stat;
160         typedef MichaelAlignHeap_NoStat<char,64>     t_MichaelAlignHeap_NoStat;
161         typedef system_aligned_allocator<char, 64>   t_system_aligned_allocator;
162
163         TEST_ALLOC_STAT( michael_heap_stat,      MichaelHeap_Stat<char> )
164         TEST_ALLOC( michael_heap_nostat,    MichaelHeap_NoStat<char> )
165         TEST_ALLOC( std_alloc,              std_allocator<char> )
166
167         TEST_ALLOC_STAT( michael_alignheap_stat,     t_MichaelAlignHeap_Stat )
168         TEST_ALLOC( michael_alignheap_nostat,   t_MichaelAlignHeap_NoStat )
169         TEST_ALLOC( system_aligned_alloc,       t_system_aligned_allocator )
170
171         CPPUNIT_TEST_SUITE( Linux_Scale )
172             CPPUNIT_TEST( michael_heap_nostat )
173             CPPUNIT_TEST( michael_heap_stat )
174             CPPUNIT_TEST( std_alloc )
175
176             CPPUNIT_TEST( system_aligned_alloc )
177             CPPUNIT_TEST( michael_alignheap_stat )
178             CPPUNIT_TEST( michael_alignheap_nostat )
179         CPPUNIT_TEST_SUITE_END();
180     };
181
182 }   // namespace memory
183 CPPUNIT_TEST_SUITE_REGISTRATION( memory::Linux_Scale );