OSDN Git Service

2004-03-24 Felix Yen <fwy@alumni.brown.edu>
[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     const bool signal = queue.empty();
133     queue.insert(queue.end(), value);
134     if (signal) pthread_cond_signal(&condition);
135   }
136
137 template<typename Container>
138   void
139   Queue<Container>::swap(Container& container)
140   {
141     AutoLock auto_lock(lock);
142     while (queue.empty()) pthread_cond_wait(&condition, &lock);
143     queue.swap(container);
144   }
145
146 class Thread
147
148   // NB: Make this the last data member of an object defining operator()().
149 public:
150   class Attributes
151   {
152   public:
153     Attributes(int state = PTHREAD_CREATE_JOINABLE);
154     ~Attributes() {pthread_attr_destroy(&attributes);}
155
156   public:
157     inline pthread_attr_t* operator&() {return &attributes;}
158
159   private:
160     pthread_attr_t attributes;
161   };
162
163 public:
164   Thread() {thread = pthread_self();}
165   ~Thread();
166
167 public:
168   template <typename ThreadOwner>
169     void create(ThreadOwner* owner);
170
171 private:
172   pthread_t thread;
173 };
174
175 Thread::Attributes::Attributes(int state)
176 {
177   pthread_attr_init(&attributes);
178   pthread_attr_setdetachstate(&attributes, state);
179 }
180
181 Thread::~Thread()
182 {
183   if (!pthread_equal(thread, pthread_self()))
184     pthread_join(thread, 0);
185 }
186
187 template<typename ThreadOwner>
188   void*
189   create_thread(void* _this)
190   {
191     ThreadOwner* owner = static_cast<ThreadOwner*>(_this);
192     (*owner)();
193     return 0;
194   }
195
196 template<typename ThreadOwner>
197   void
198   Thread::create(ThreadOwner* owner)
199   {
200     Thread::Attributes attributes;
201     pthread_create(&thread, &attributes, create_thread<ThreadOwner>, owner);
202   }
203
204 template<typename Container>
205   class Consumer
206   {
207   public:
208     Consumer(Queue<Container>& _queue)
209     : queue(_queue)
210     {thread.create(this);}
211
212   public:
213     void operator()();
214
215   private:
216     Queue<Container>& queue;
217     Thread thread;
218   };
219
220 template<typename Container>
221   void
222   Consumer<Container>::operator()()
223   {
224     for (int j = insert_values * iterations; j > 0;)
225     {
226       Container container;
227       queue.swap(container);
228       j -= container.size();
229     }
230   }
231
232 template<typename TestType>
233   struct Value : public pair<TestType, TestType>
234   {
235     Value()
236     : pair<TestType, TestType>(0, 0)
237     { }
238
239     inline Value operator++() {return ++this->first, *this;}
240     inline operator TestType() const {return this->first;}
241   };
242
243 template<typename Container>
244   class ProducerConsumer : private Queue<Container>
245   {
246   public:
247     ProducerConsumer() {thread.create(this);}
248  
249   public:
250     void operator()();
251
252   private:
253     Thread thread;
254   };
255
256 template<typename Container>
257   void
258   ProducerConsumer<Container>::operator()()
259   {
260     Consumer<Container> consumer(*this);
261     Value<test_type> test_value;
262     for (int j = insert_values * iterations; j-- > 0;)
263       this->push_back(++test_value);
264   }
265
266 template<typename Container>
267   void
268   test_container(Container obj)
269   {
270     using namespace __gnu_test;
271     int status;
272
273     time_counter time;
274     resource_counter resource;
275
276     clear_counters(time, resource);
277     start_counters(time, resource);
278     {
279       ProducerConsumer<Container> pc1;
280       ProducerConsumer<Container> pc2;
281     }
282     stop_counters(time, resource);
283
284     std::ostringstream comment;
285     comment << "iterations: " << iterations << '\t';
286     comment << "type: " << __cxa_demangle(typeid(obj).name(), 0, 0, &status);
287     report_header(__FILE__, comment.str());
288     report_performance(__FILE__, string(), time, resource);
289   }
290
291 int main(void)
292 {
293 #ifdef TEST_T1
294   test_container(vector<test_type, malloc_alloc_type>());
295 #endif
296 #ifdef TEST_T2
297   test_container(vector<test_type, new_alloc_type>());
298 #endif
299 #ifdef TEST_T3
300   test_container(vector<test_type, so_alloc_type>());
301 #endif
302 #ifdef TEST_T4
303   test_container(vector<test_type, bit_alloc_type>());
304 #endif
305 #ifdef TEST_T5
306   test_container(vector<test_type, po_alloc_type>());
307 #endif
308
309 #ifdef TEST_T6
310   test_container(list<test_type, malloc_alloc_type>());
311 #endif
312 #ifdef TEST_T7
313   test_container(list<test_type, new_alloc_type>());
314 #endif
315 #ifdef TEST_T8
316   test_container(list<test_type, so_alloc_type>());
317 #endif
318 #ifdef TEST_T9
319   test_container(list<test_type, bit_alloc_type>());
320 #endif
321 #ifdef TEST_T10
322   test_container(list<test_type, po_alloc_type>());
323 #endif
324
325 #ifdef TEST_T11
326   test_container(map<test_type, test_type, compare_type, malloc_alloc_type>());
327 #endif
328 #ifdef TEST_T12
329   test_container(map<test_type, test_type, compare_type, new_alloc_type>());
330 #endif
331 #ifdef TEST_T13
332   test_container(map<test_type, test_type, compare_type, so_alloc_type>());
333 #endif
334 #ifdef TEST_T14
335   test_container(map<test_type, test_type, compare_type, bit_alloc_type>());
336 #endif
337 #ifdef TEST_T15
338   test_container(map<test_type, test_type, compare_type, po_alloc_type>());
339 #endif
340
341   return 0;
342 }
343