]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/smart_ptr/test/sp_atomic_mt2_test.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / smart_ptr / test / sp_atomic_mt2_test.cpp
1
2 // Copyright (c) 2008 Peter Dimov
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7
8 #include <boost/config.hpp>
9
10 #include <boost/shared_ptr.hpp>
11 #include <boost/bind.hpp>
12
13 #include <boost/thread/shared_mutex.hpp>
14 #include <boost/thread/locks.hpp>
15
16 #include <boost/detail/lightweight_mutex.hpp>
17 #include <boost/detail/lightweight_thread.hpp>
18
19 #include <vector>
20 #include <numeric>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstddef>
24 #include <ctime>
25
26 //
27
28 static void next_value( unsigned & v )
29 {
30 v = v % 2? 3 * v + 1: v / 2;
31 }
32
33 struct X
34 {
35 std::vector<unsigned> v_;
36
37 explicit X( std::size_t n ): v_( n )
38 {
39 for( std::size_t i = 0; i < n; ++i )
40 {
41 v_[ i ] = i;
42 }
43 }
44
45 unsigned get() const
46 {
47 return std::accumulate( v_.begin(), v_.end(), 0 );
48 }
49
50 void set()
51 {
52 std::for_each( v_.begin(), v_.end(), next_value );
53 }
54 };
55
56 static boost::shared_ptr<X> ps;
57
58 static boost::detail::lightweight_mutex lm;
59 static boost::shared_mutex rw;
60
61 enum prim_type
62 {
63 pt_mutex,
64 pt_rwlock,
65 pt_atomics
66 };
67
68 int read_access( prim_type pt )
69 {
70 switch( pt )
71 {
72 case pt_mutex:
73 {
74 boost::detail::lightweight_mutex::scoped_lock lock( lm );
75 return ps->get();
76 }
77
78 case pt_rwlock:
79 {
80 boost::shared_lock<boost::shared_mutex> lock( rw );
81 return ps->get();
82 }
83
84 case pt_atomics:
85 {
86 boost::shared_ptr<X> p2 = boost::atomic_load( &ps );
87 return p2->get();
88 }
89 }
90 }
91
92 void write_access( prim_type pt )
93 {
94 switch( pt )
95 {
96 case pt_mutex:
97 {
98 boost::detail::lightweight_mutex::scoped_lock lock( lm );
99 ps->set();
100 }
101 break;
102
103 case pt_rwlock:
104 {
105 boost::unique_lock<boost::shared_mutex> lock( rw );
106 ps->set();
107 }
108 break;
109
110 case pt_atomics:
111 {
112 boost::shared_ptr<X> p1 = boost::atomic_load( &ps );
113
114 for( ;; )
115 {
116 boost::shared_ptr<X> p2( new X( *p1 ) );
117 p2->set();
118
119 if( boost::atomic_compare_exchange( &ps, &p1, p2 ) ) break;
120 }
121 }
122 break;
123 }
124 }
125
126 void worker( int k, prim_type pt, int n, int r )
127 {
128 ++r;
129
130 unsigned s = 0, nr = 0, nw = 0;
131
132 for( int i = 0; i < n; ++i )
133 {
134 if( i % r )
135 {
136 s += read_access( pt );
137 ++nr;
138 }
139 else
140 {
141 write_access( pt );
142 ++s;
143 ++nw;
144 }
145 }
146
147 printf( "Worker %2d: %u:%u, %10u\n", k, nr, nw, s );
148 }
149
150 #if defined( BOOST_HAS_PTHREADS )
151 char const * thmodel = "POSIX";
152 #else
153 char const * thmodel = "Windows";
154 #endif
155
156 char const * pt_to_string( prim_type pt )
157 {
158 switch( pt )
159 {
160 case pt_mutex:
161
162 return "mutex";
163
164 case pt_rwlock:
165
166 return "rwlock";
167
168 case pt_atomics:
169
170 return "atomics";
171 }
172 }
173
174 static void handle_pt_option( std::string const & opt, prim_type & pt, prim_type pt2 )
175 {
176 if( opt == pt_to_string( pt2 ) )
177 {
178 pt = pt2;
179 }
180 }
181
182 static void handle_int_option( std::string const & opt, std::string const & prefix, int & k, int kmin, int kmax )
183 {
184 if( opt.substr( 0, prefix.size() ) == prefix )
185 {
186 int v = atoi( opt.substr( prefix.size() ).c_str() );
187
188 if( v >= kmin && v <= kmax )
189 {
190 k = v;
191 }
192 }
193 }
194
195 int main( int ac, char const * av[] )
196 {
197 using namespace std; // printf, clock_t, clock
198
199 int m = 4; // threads
200 int n = 10000; // vector size
201 int k = 1000000; // iterations
202 int r = 100; // read/write ratio, r:1
203
204 prim_type pt = pt_atomics;
205
206 for( int i = 1; i < ac; ++i )
207 {
208 handle_pt_option( av[i], pt, pt_mutex );
209 handle_pt_option( av[i], pt, pt_rwlock );
210 handle_pt_option( av[i], pt, pt_atomics );
211
212 handle_int_option( av[i], "n=", n, 1, INT_MAX );
213 handle_int_option( av[i], "size=", n, 1, INT_MAX );
214
215 handle_int_option( av[i], "k=", k, 1, INT_MAX );
216 handle_int_option( av[i], "iterations=", k, 1, INT_MAX );
217
218 handle_int_option( av[i], "m=", m, 1, INT_MAX );
219 handle_int_option( av[i], "threads=", m, 1, INT_MAX );
220
221 handle_int_option( av[i], "r=", r, 1, INT_MAX );
222 handle_int_option( av[i], "ratio=", r, 1, INT_MAX );
223 }
224
225 printf( "%s: threads=%d size=%d iterations=%d ratio=%d %s\n\n", thmodel, m, n, k, r, pt_to_string( pt ) );
226
227 ps.reset( new X( n ) );
228
229 clock_t t = clock();
230
231 std::vector<pthread_t> a( m );
232
233 for( int i = 0; i < m; ++i )
234 {
235 boost::detail::lw_thread_create( a[ i ], boost::bind( worker, i, pt, k, r ) );
236 }
237
238 for( int j = 0; j < m; ++j )
239 {
240 pthread_join( a[ j ], 0 );
241 }
242
243 t = clock() - t;
244
245 double ts = static_cast<double>( t ) / CLOCKS_PER_SEC;
246 printf( "%.3f seconds, %.3f accesses per microsecond.\n", ts, m * k / ts / 1e+6 );
247 }