OSDN Git Service

5295e7e1fad2cd2e6cdd9485fefb02d5cd0d8467
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / testsuite / performance / 20_util / allocator / producer_consumer.cc
1 // Copyright (C) 2004 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 2, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING.  If not, write to the Free
16 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 // USA.
18
19 // As a special exception, you may use this file as part of a free software
20 // library without restriction.  Specifically, if other files instantiate
21 // templates or use macros or inline functions from this file, or you compile
22 // this file and link it with other files to produce an executable, this
23 // file does not by itself cause the resulting executable to be covered by
24 // the GNU General Public License.  This exception does not however
25 // invalidate any other reasons why the executable file might be covered by
26 // the GNU General Public License.
27
28 /*
29  * The goal with this application is to compare the performance of
30  * different allocators in a simple producer-consumer scenario.
31  */
32
33 // 2004-02-04 Felix Yen <fwy@alumni.brown.edu>
34
35 #include <vector>
36 #include <list>
37 #include <map>
38 #include <typeinfo>
39 #include <sstream>
40 #include <pthread.h>
41 #include <ext/mt_allocator.h>
42 #include <ext/new_allocator.h>
43 #include <ext/malloc_allocator.h>
44 #include <ext/bitmap_allocator.h>
45 #include <ext/pool_allocator.h>
46 #include <cxxabi.h>
47 #include <testsuite_performance.h>
48
49
50 using namespace std;
51 using __gnu_cxx::__mt_alloc;
52 using __gnu_cxx::new_allocator;
53 using __gnu_cxx::malloc_allocator;
54 using __gnu_cxx::bitmap_allocator;
55 using __gnu_cxx::__pool_alloc;
56 using abi::__cxa_demangle;
57
58 typedef int test_type;
59 typedef less<test_type> compare_type;
60 typedef malloc_allocator<test_type> malloc_alloc_type;
61 typedef new_allocator<test_type> new_alloc_type;
62 typedef __mt_alloc<test_type> so_alloc_type;
63 typedef bitmap_allocator<test_type> bit_alloc_type;
64 typedef __pool_alloc<test_type> po_alloc_type;
65
66 // The number of iterations to be performed.
67 int iterations = 10000;
68
69 // TODO - restore Stefan's comment?  i don't understand it.  -- fwy
70 int insert_values = 128;
71
72 class Lock
73 {
74 public:
75   Lock() {pthread_mutex_init(&mutex, 0);}
76   ~Lock() {pthread_mutex_destroy(&mutex);}
77
78 public:
79   inline pthread_mutex_t* operator&() {return &mutex;}
80
81 public:
82   inline void lock() {pthread_mutex_lock(&mutex);}
83   inline void unlock() {pthread_mutex_unlock(&mutex);}
84
85 private:
86   Lock(const Lock&);
87   Lock& operator=(Lock&);
88
89 private:
90   pthread_mutex_t mutex;
91 };
92
93 class AutoLock
94 {
95 public:
96   AutoLock(Lock& _lock)
97   : lock(_lock)
98   {lock.lock();}
99
100   ~AutoLock() {lock.unlock();}
101
102 private:
103   AutoLock(AutoLock&);
104   AutoLock& operator=(AutoLock&);
105
106 private:
107   Lock& lock;
108 };
109
110 template<typename Container>
111   class Queue
112   {
113   public:
114     Queue() {pthread_cond_init(&condition, 0);}
115     ~Queue() {pthread_cond_destroy(&condition);}
116
117   public:
118     void push_back(const typename Container::value_type& x);
119     void swap(Container& container);
120
121   private:
122     pthread_cond_t condition;
123     Lock lock;
124     Container queue;
125   };
126
127 template<typename Container>
128   void
129   Queue<Container>::push_back(const typename Container::value_type& value)
130   {
131     AutoLock auto_lock(lock);
132     queue.insert(queue.end(), value);
133     if (queue.size() == 1) pthread_cond_signal(&condition);
134   }
135
136 template<typename Container>
137   void
138   Queue<Container>::swap(Container& container)
139   {
140     AutoLock auto_lock(lock);
141     while (queue.empty()) pthread_cond_wait(&condition, &lock);
142     queue.swap(container);
143   }
144
145 class Thread
146
147   // NB: Make this the last data member of an object defining operator()().
148 public:
149   class Attributes
150   {
151   public:
152     Attributes(int state = PTHREAD_CREATE_JOINABLE);
153     ~Attributes() {pthread_attr_destroy(&attributes);}
154
155   public:
156     inline pthread_attr_t* operator&() {return &attributes;}
157
158   private:
159     pthread_attr_t attributes;
160   };
161
162 public:
163   Thread() {thread = pthread_self();}
164   ~Thread();
165
166 public:
167   template <typename ThreadOwner>
168     void create(ThreadOwner* owner);
169
170 private:
171   pthread_t thread;
172 };
173
174 Thread::Attributes::Attributes(int state)
175 {
176   pthread_attr_init(&attributes);
177   pthread_attr_setdetachstate(&attributes, state);
178 }
179
180 Thread::~Thread()
181 {
182   if (!pthread_equal(thread, pthread_self()))
183     pthread_join(thread, 0);
184 }
185
186 template<typename ThreadOwner>
187   void*
188   create_thread(void* _this)
189   {
190     ThreadOwner* owner = static_cast<ThreadOwner*>(_this);
191     (*owner)();
192     return 0;
193   }
194
195 template<typename ThreadOwner>
196   void
197   Thread::create(ThreadOwner* owner)
198   {
199     Thread::Attributes attributes;
200     pthread_create(&thread, &attributes, create_thread<ThreadOwner>, owner);
201   }
202
203 template<typename Container>
204   class Consumer
205   {
206   public:
207     Consumer(Queue<Container>& _queue)
208     : queue(_queue)
209     {thread.create(this);}
210
211   public:
212     void operator()();
213
214   private:
215     Queue<Container>& queue;
216     Thread thread;
217   };
218
219 template<typename Container>
220   void
221   Consumer<Container>::operator()()
222   {
223     for (int j = insert_values * iterations; j > 0;)
224     {
225       Container container;
226       queue.swap(container);
227       j -= container.size();
228     }
229   }
230
231 template<typename TestType>
232   struct Value : public pair<TestType, TestType>
233   {
234     Value()
235     : pair<TestType, TestType>(0, 0)
236     { }
237
238     inline Value operator++() {return ++this->first, *this;}
239     inline operator TestType() const {return this->first;}
240   };
241
242 template<typename Container>
243   class ProducerConsumer : private Queue<Container>
244   {
245   public:
246     ProducerConsumer() {thread.create(this);}
247  
248   public:
249     void operator()();
250
251   private:
252     Thread thread;
253   };
254
255 template<typename Container>
256   void
257   ProducerConsumer<Container>::operator()()
258   {
259     Consumer<Container> consumer(*this);
260     Value<test_type> test_value;
261     for (int j = insert_values * iterations; j-- > 0;)
262       this->push_back(++test_value);
263   }
264
265 template<typename Container>
266   void
267   test_container(Container obj)
268   {
269     using namespace __gnu_test;
270     int status;
271
272     time_counter time;
273     resource_counter resource;
274
275     clear_counters(time, resource);
276     start_counters(time, resource);
277     {
278       ProducerConsumer<Container> pc1;
279       ProducerConsumer<Container> pc2;
280     }
281     stop_counters(time, resource);
282
283     std::ostringstream comment;
284     comment << "iterations: " << iterations << '\t';
285     comment << "type: " << __cxa_demangle(typeid(obj).name(), 0, 0, &status);
286     report_header(__FILE__, comment.str());
287     report_performance(__FILE__, string(), time, resource);
288   }
289
290 int main(void)
291 {
292 #ifdef TEST_T1
293   test_container(vector<test_type, malloc_alloc_type>());
294 #endif
295 #ifdef TEST_T2
296   test_container(vector<test_type, new_alloc_type>());
297 #endif
298 #ifdef TEST_T3
299   test_container(vector<test_type, so_alloc_type>());
300 #endif
301 #ifdef TEST_T4
302   test_container(vector<test_type, bit_alloc_type>());
303 #endif
304 #ifdef TEST_T5
305   test_container(vector<test_type, po_alloc_type>());
306 #endif
307
308 #ifdef TEST_T6
309   test_container(list<test_type, malloc_alloc_type>());
310 #endif
311 #ifdef TEST_T7
312   test_container(list<test_type, new_alloc_type>());
313 #endif
314 #ifdef TEST_T8
315   test_container(list<test_type, so_alloc_type>());
316 #endif
317 #ifdef TEST_T9
318   test_container(list<test_type, bit_alloc_type>());
319 #endif
320 #ifdef TEST_T10
321   test_container(list<test_type, po_alloc_type>());
322 #endif
323
324 #ifdef TEST_T11
325   test_container(map<test_type, test_type, compare_type, malloc_alloc_type>());
326 #endif
327 #ifdef TEST_T12
328   test_container(map<test_type, test_type, compare_type, new_alloc_type>());
329 #endif
330 #ifdef TEST_T13
331   test_container(map<test_type, test_type, compare_type, so_alloc_type>());
332 #endif
333 #ifdef TEST_T14
334   test_container(map<test_type, test_type, compare_type, bit_alloc_type>());
335 #endif
336 #ifdef TEST_T15
337   test_container(map<test_type, test_type, compare_type, po_alloc_type>());
338 #endif
339
340   return 0;
341 }
342