bf05807b2f8865b0abc1e1c859f84eb8f44b5359
[libcds.git] / tests / unit / alloc / linux_scale.cpp
1 //$$CDS-header$$
2
3 // Linux scalability allocator test
4
5 #include "alloc/michael_allocator.h"
6
7 #include <cds/os/timer.h>
8 #include <cds/os/topology.h>
9
10 #include "cppunit/thread.h"
11
12 namespace memory {
13
14     static size_t s_nPassCount = 10000000;
15     static size_t s_nMaxBlockSize = 64 * 1024 - 16;
16     static size_t s_nMaxThreadCount = 64;
17
18     static size_t s_nPassPerThread;
19
20 #    define TEST_ALLOC(X, CLASS)    void X() { test< CLASS >(false)     ; }
21 #    define TEST_ALLOC_STAT(X, CLASS)    void X() { test< CLASS >(true) ; }
22
23     class Linux_Scale: public CppUnitMini::TestCase
24     {
25         template <class ALLOC>
26         class Thread: public CppUnitMini::TestThread
27         {
28             ALLOC&      m_Alloc;
29             size_t      m_nSize;
30
31             virtual Thread *    clone()
32             {
33                 return new Thread( *this );
34             }
35         public:
36
37         public:
38             Thread( CppUnitMini::ThreadPool& pool, ALLOC& a, size_t nSize )
39                 : CppUnitMini::TestThread( pool )
40                 , m_Alloc( a )
41                 , m_nSize( nSize )
42             {}
43             Thread( Thread& src )
44                 : CppUnitMini::TestThread( src )
45                 , m_Alloc( src.m_Alloc )
46                 , m_nSize( src.m_nSize )
47             {}
48
49             Linux_Scale&  getTest()
50             {
51                 return reinterpret_cast<Linux_Scale&>( m_Pool.m_Test );
52             }
53
54             virtual void init() { cds::threading::Manager::attachThread()   ; }
55             virtual void fini() { cds::threading::Manager::detachThread()   ; }
56
57             virtual void test()
58             {
59                 for ( size_t i = 0; i < s_nPassPerThread; ++i ) {
60                     typename ALLOC::value_type * p = m_Alloc.allocate( m_nSize / sizeof( typename ALLOC::value_type ), nullptr );
61                     CPPUNIT_ASSERT( p != nullptr );
62                     if ( m_nSize < 32 )
63                         memset( p, 0, m_nSize );
64                     else {
65                         memset( p, 0, 16 );
66                         memset( ((char *)p) + m_nSize * sizeof(*p) - 16, 0, 16 );
67                     }
68                     CPPUNIT_ASSERT( (reinterpret_cast<cds::uptr_atomic_t>(p) & (ALLOC::alignment - 1)) == 0 );
69                     m_Alloc.deallocate( p, 1 );
70                 }
71             }
72         };
73
74         template <class ALLOC>
75         void test( size_t nThreadCount, size_t nSize )
76         {
77             cds::OS::Timer    timer;
78
79             ALLOC alloc;
80
81             CPPUNIT_MSG( "   Block size=" << nSize );
82             s_nPassPerThread = s_nPassCount / nThreadCount;
83
84             CppUnitMini::ThreadPool pool( *this );
85             pool.add( new Thread<ALLOC>( pool, alloc, nSize ), nThreadCount );
86             pool.run();
87             CPPUNIT_MSG( "      Duration=" << pool.avgDuration() );
88         }
89
90         template <class ALLOC>
91         void test( size_t nThreadCount )
92         {
93             CPPUNIT_MSG( "Thread count=" << nThreadCount );
94             for ( size_t sz = 1; sz < s_nMaxBlockSize; sz *= 2 ) {
95                 test<ALLOC>( nThreadCount, sz );
96             }
97         }
98
99         template <class ALLOC>
100         void test( bool bStat )
101         {
102             for ( size_t nThreadCount = 1; nThreadCount <= s_nMaxThreadCount; nThreadCount *= 2 ) {
103                 summary_stat stBegin;
104                 if ( bStat )
105                     ALLOC::stat(stBegin);
106
107                 test<ALLOC>( nThreadCount );
108
109                 summary_stat    stEnd;
110                 if ( bStat ) {
111                     ALLOC::stat( stEnd );
112
113                     std::cout << "\nStatistics:\n"
114                         << stEnd
115 ;
116                     stEnd -= stBegin;
117                     std::cout << "\nDelta statistics:\n"
118                         << stEnd
119 ;
120                 }
121             }
122         }
123
124         void setUpParams( const CppUnitMini::TestCfg& cfg )
125         {
126             s_nPassCount = cfg.getULong( "PassCount", 10000000 );
127             s_nMaxBlockSize = cfg.getULong( "MaxBlockSize", 64 * 1024 - 16 );
128             s_nMaxThreadCount = cfg.getUInt( "MaxThreadCount", 64 );
129             if ( s_nMaxThreadCount == 0 )
130                 s_nMaxThreadCount = cds::OS::topology::processor_count() * 2;
131         }
132
133         typedef MichaelAlignHeap_Stat<char, 64>      t_MichaelAlignHeap_Stat;
134         typedef MichaelAlignHeap_NoStat<char,64>     t_MichaelAlignHeap_NoStat;
135         typedef system_aligned_allocator<char, 64>   t_system_aligned_allocator;
136
137         TEST_ALLOC_STAT( michael_heap_stat,      MichaelHeap_Stat<char> )
138         TEST_ALLOC( michael_heap_nostat,    MichaelHeap_NoStat<char> )
139         TEST_ALLOC( std_alloc,              std_allocator<char> )
140
141         TEST_ALLOC_STAT( michael_alignheap_stat,     t_MichaelAlignHeap_Stat )
142         TEST_ALLOC( michael_alignheap_nostat,   t_MichaelAlignHeap_NoStat )
143         TEST_ALLOC( system_aligned_alloc,       t_system_aligned_allocator )
144
145         CPPUNIT_TEST_SUITE( Linux_Scale )
146             CPPUNIT_TEST( michael_heap_nostat )
147             CPPUNIT_TEST( michael_heap_stat )
148             CPPUNIT_TEST( std_alloc )
149
150             CPPUNIT_TEST( system_aligned_alloc )
151             CPPUNIT_TEST( michael_alignheap_stat )
152             CPPUNIT_TEST( michael_alignheap_nostat )
153         CPPUNIT_TEST_SUITE_END();
154     };
155
156 }   // namespace memory
157 CPPUNIT_TEST_SUITE_REGISTRATION( memory::Linux_Scale );