1 // Copyright (C) 2000, 2001 Stephen Cleary
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <boost/pool/pool_alloc.hpp>
8 #include <boost/pool/object_pool.hpp>
9 
10 #include <iostream>
11 #include <vector>
12 #include <list>
13 #include <set>
14 
15 #include <ctime>
16 #include <cerrno>
17 
18 #include "sys_allocator.hpp"
19 
20 unsigned long num_ints;
21 unsigned long num_loops = 10;
22 unsigned l;
23 
24 template <unsigned N>
25 struct larger_structure
26 {
27   char data[N];
28 };
29 
30 unsigned test_number;
31 
32 template <unsigned N>
timing_test_alloc_larger()33 static void timing_test_alloc_larger()
34 {
35   typedef boost::fast_pool_allocator<larger_structure<N>,
36       boost::default_user_allocator_new_delete,
37       boost::details::pool::null_mutex> alloc;
38   typedef boost::fast_pool_allocator<larger_structure<N> > alloc_sync;
39 
40   double end[1][6];
41   std::clock_t start;
42 
43   start = std::clock();
44   for(l = 0; l < num_loops; ++l)
45   {
46     std::allocator<larger_structure<N> > a;
47     for (unsigned long i = 0; i < num_ints; ++i)
48       a.deallocate(a.allocate(1), 1);
49   }
50   end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
51 
52   start = std::clock();
53   for(l = 0; l < num_loops; ++l)
54   {
55     for (unsigned long i = 0; i < num_ints; ++i)
56       std::free(std::malloc(sizeof(larger_structure<N>)));
57   }
58   end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
59 
60   start = std::clock();
61   for(l = 0; l < num_loops; ++l)
62   {
63     for (unsigned long i = 0; i < num_ints; ++i)
64       delete new (std::nothrow) larger_structure<N>;
65   }
66   end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
67 
68   start = std::clock();
69   for(l = 0; l < num_loops; ++l)
70   {
71     for (unsigned long i = 0; i < num_ints; ++i)
72       alloc::deallocate(alloc::allocate());
73   }
74   end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
75 
76   start = std::clock();
77   for(l = 0; l < num_loops; ++l)
78   {
79     for (unsigned long i = 0; i < num_ints; ++i)
80       alloc_sync::deallocate(alloc_sync::allocate());
81   }
82   end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
83 
84   start = std::clock();
85   for(l = 0; l < num_loops; ++l)
86   {
87     boost::pool<> p(sizeof(larger_structure<N>));
88     for (unsigned long i = 0; i < num_ints; ++i)
89     {
90       void * const t = p.malloc();
91       if (t != 0)
92         p.free(t);
93     }
94   }
95   end[0][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
96 
97   std::cout << "Test " << test_number++ << ": Alloc & Dealloc " << num_ints << " structures of size " << sizeof(larger_structure<N>) << ":" << std::endl;
98   std::cout << "  std::allocator: " << end[0][0] << " seconds" << std::endl;
99   std::cout << "  malloc/free:    " << end[0][1] << " seconds" << std::endl;
100   std::cout << "  new/delete:     " << end[0][2] << " seconds" << std::endl;
101   std::cout << "  Pool Alloc:     " << end[0][3] << " seconds" << std::endl;
102   std::cout << "  Pool /w Sync:   " << end[0][4] << " seconds" << std::endl;
103   std::cout << "  Pool:           " << end[0][5] << " seconds" << std::endl;
104 }
105 
timing_test_alloc()106 static void timing_test_alloc()
107 {
108   typedef boost::fast_pool_allocator<int,
109       boost::default_user_allocator_new_delete,
110       boost::details::pool::null_mutex> alloc;
111   typedef boost::fast_pool_allocator<int> alloc_sync;
112 
113   double end[2][6];
114   std::clock_t start;
115 
116   int ** p = new int*[num_ints];
117 
118   start = std::clock();
119   for(l = 0; l < num_loops; ++l)
120   {
121     std::allocator<int> a;
122     for (unsigned long i = 0; i < num_ints; ++i)
123       a.deallocate(a.allocate(1), 1);
124   }
125   end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
126 
127   start = std::clock();
128   for(l = 0; l < num_loops; ++l)
129   {
130     for (unsigned long i = 0; i < num_ints; ++i)
131       std::free(std::malloc(sizeof(int)));
132   }
133   end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
134 
135   start = std::clock();
136   for(l = 0; l < num_loops; ++l)
137   {
138     for (unsigned long i = 0; i < num_ints; ++i)
139       delete new (std::nothrow) int;
140   }
141   end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
142 
143   start = std::clock();
144   for(l = 0; l < num_loops; ++l)
145   {
146     for (unsigned long i = 0; i < num_ints; ++i)
147       alloc::deallocate(alloc::allocate());
148   }
149   end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
150 
151   start = std::clock();
152   for(l = 0; l < num_loops; ++l)
153   {
154     for (unsigned long i = 0; i < num_ints; ++i)
155       alloc_sync::deallocate(alloc_sync::allocate());
156   }
157   end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
158 
159   start = std::clock();
160   for(l = 0; l < num_loops; ++l)
161   {
162     boost::pool<> p2(sizeof(int));
163     for (unsigned long i = 0; i < num_ints; ++i)
164     {
165       void * const t = p2.malloc();
166       if (t != 0)
167         p2.free(t);
168     }
169   }
170   end[0][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
171 
172 
173   start = std::clock();
174   for(l = 0; l < num_loops; ++l)
175   {
176     std::allocator<int> a;
177     for (unsigned long i = 0; i < num_ints; ++i)
178       p[i] = a.allocate(1);
179     for (unsigned long i = 0; i < num_ints; ++i)
180       a.deallocate(p[i], 1);
181   }
182   end[1][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
183 
184   start = std::clock();
185   for(l = 0; l < num_loops; ++l)
186   {
187     for (unsigned long i = 0; i < num_ints; ++i)
188       p[i] = (int *) std::malloc(sizeof(int));
189     for (unsigned long i = 0; i < num_ints; ++i)
190       std::free(p[i]);
191   }
192   end[1][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
193 
194   start = std::clock();
195   for(l = 0; l < num_loops; ++l)
196   {
197     for (unsigned long i = 0; i < num_ints; ++i)
198       p[i] = new (std::nothrow) int;
199     for (unsigned long i = 0; i < num_ints; ++i)
200       delete p[i];
201   }
202   end[1][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
203 
204   start = std::clock();
205   for(l = 0; l < num_loops; ++l)
206   {
207     for (unsigned long i = 0; i < num_ints; ++i)
208       p[i] = alloc::allocate();
209     for (unsigned long i = 0; i < num_ints; ++i)
210       alloc::deallocate(p[i]);
211   }
212   end[1][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
213 
214   start = std::clock();
215   for(l = 0; l < num_loops; ++l)
216   {
217     for (unsigned long i = 0; i < num_ints; ++i)
218       p[i] = alloc_sync::allocate();
219     for (unsigned long i = 0; i < num_ints; ++i)
220       alloc_sync::deallocate(p[i]);
221   }
222   end[1][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
223 
224   start = std::clock();
225   for(l = 0; l < num_loops; ++l)
226   {
227     boost::pool<> pl(sizeof(int));
228     for (unsigned long i = 0; i < num_ints; ++i)
229       p[i] = reinterpret_cast<int *>(pl.malloc());
230     for (unsigned long i = 0; i < num_ints; ++i)
231       if (p[i] != 0)
232         pl.free(p[i]);
233   }
234   end[1][5] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
235 
236   delete [] p;
237 
238   std::cout << "Test 3: Alloc & Dealloc " << num_ints << " ints:" << std::endl;
239   std::cout << "  std::allocator: " << end[0][0] << " seconds" << std::endl;
240   std::cout << "  malloc/free:    " << end[0][1] << " seconds" << std::endl;
241   std::cout << "  new/delete:     " << end[0][2] << " seconds" << std::endl;
242   std::cout << "  Pool Alloc:     " << end[0][3] << " seconds" << std::endl;
243   std::cout << "  Pool /w Sync:   " << end[0][4] << " seconds" << std::endl;
244   std::cout << "  Pool:           " << end[0][5] << " seconds" << std::endl;
245 
246   std::cout << "Test 4: Alloc " << num_ints << " ints & Dealloc " << num_ints << " ints:" << std::endl;
247   std::cout << "  std::allocator: " << end[1][0] << " seconds" << std::endl;
248   std::cout << "  malloc/free:    " << end[1][1] << " seconds" << std::endl;
249   std::cout << "  new/delete:     " << end[1][2] << " seconds" << std::endl;
250   std::cout << "  Pool Alloc:     " << end[1][3] << " seconds" << std::endl;
251   std::cout << "  Pool /w Sync:   " << end[1][4] << " seconds" << std::endl;
252   std::cout << "  Pool:           " << end[1][5] << " seconds" << std::endl;
253 }
254 
timing_test_containers()255 static void timing_test_containers()
256 {
257   typedef boost::pool_allocator<int,
258       boost::default_user_allocator_new_delete,
259       boost::details::pool::null_mutex> alloc;
260   typedef boost::pool_allocator<int> alloc_sync;
261   typedef boost::fast_pool_allocator<int,
262       boost::default_user_allocator_new_delete,
263       boost::details::pool::null_mutex> fast_alloc;
264   typedef boost::fast_pool_allocator<int> fast_alloc_sync;
265 
266   double end[3][5];
267   std::clock_t start;
268 
269   start = std::clock();
270   for(l = 0; l < num_loops; ++l)
271   {
272     std::vector<int, std::allocator<int> > x;
273     for (unsigned long i = 0; i < num_ints; ++i)
274       x.push_back(0);
275   }
276   end[0][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
277 
278   start = std::clock();
279   for(l = 0; l < num_loops; ++l)
280   {
281     std::vector<int, malloc_allocator<int> > x;
282     for (unsigned long i = 0; i < num_ints; ++i)
283       x.push_back(0);
284   }
285   end[0][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
286 
287   start = std::clock();
288   for(l = 0; l < num_loops; ++l)
289   {
290     std::vector<int, new_delete_allocator<int> > x;
291     for (unsigned long i = 0; i < num_ints; ++i)
292       x.push_back(0);
293   }
294   end[0][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
295 
296   start = std::clock();
297   for(l = 0; l < num_loops; ++l)
298   {
299     std::vector<int, alloc> x;
300     for (unsigned long i = 0; i < num_ints; ++i)
301       x.push_back(0);
302   }
303   end[0][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
304 
305   start = std::clock();
306   for(l = 0; l < num_loops; ++l)
307   {
308     std::vector<int, alloc_sync> x;
309     for (unsigned long i = 0; i < num_ints; ++i)
310       x.push_back(0);
311   }
312   end[0][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
313 
314 
315   start = std::clock();
316   for(l = 0; l < num_loops; ++l)
317   {
318     std::set<int, std::less<int>, std::allocator<int> > x;
319     for (unsigned long i = 0; i < num_ints; ++i)
320       x.insert(0);
321   }
322   end[1][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
323 
324   start = std::clock();
325   for(l = 0; l < num_loops; ++l)
326   {
327     std::set<int, std::less<int>, malloc_allocator<int> > x;
328     for (unsigned long i = 0; i < num_ints; ++i)
329       x.insert(0);
330   }
331   end[1][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
332 
333   start = std::clock();
334   for(l = 0; l < num_loops; ++l)
335   {
336     std::set<int, std::less<int>, new_delete_allocator<int> > x;
337     for (unsigned long i = 0; i < num_ints; ++i)
338       x.insert(0);
339   }
340   end[1][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
341 
342   start = std::clock();
343   for(l = 0; l < num_loops; ++l)
344   {
345     std::set<int, std::less<int>, fast_alloc> x;
346     for (unsigned long i = 0; i < num_ints; ++i)
347       x.insert(0);
348   }
349   end[1][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
350 
351   start = std::clock();
352   for(l = 0; l < num_loops; ++l)
353   {
354     std::set<int, std::less<int>, fast_alloc_sync> x;
355     for (unsigned long i = 0; i < num_ints; ++i)
356       x.insert(0);
357   }
358   end[1][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
359 
360 
361   start = std::clock();
362   for(l = 0; l < num_loops; ++l)
363   {
364     std::list<int, std::allocator<int> > x;
365     for (unsigned long i = 0; i < num_ints; ++i)
366       x.push_back(0);
367   }
368   end[2][0] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
369 
370   start = std::clock();
371   for(l = 0; l < num_loops; ++l)
372   {
373     std::list<int, malloc_allocator<int> > x;
374     for (unsigned long i = 0; i < num_ints; ++i)
375       x.push_back(0);
376   }
377   end[2][1] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
378 
379   start = std::clock();
380   for(l = 0; l < num_loops; ++l)
381   {
382     std::list<int, new_delete_allocator<int> > x;
383     for (unsigned long i = 0; i < num_ints; ++i)
384       x.push_back(0);
385   }
386   end[2][2] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
387 
388   start = std::clock();
389   for(l = 0; l < num_loops; ++l)
390   {
391     std::list<int, fast_alloc> x;
392     for (unsigned long i = 0; i < num_ints; ++i)
393       x.push_back(0);
394   }
395   end[2][3] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
396 
397   start = std::clock();
398   for(l = 0; l < num_loops; ++l)
399   {
400     std::list<int, fast_alloc_sync> x;
401     for (unsigned long i = 0; i < num_ints; ++i)
402       x.push_back(0);
403   }
404   end[2][4] = (std::clock() - start) / ((double) CLOCKS_PER_SEC);
405 
406   std::cout << "Test 0: Insertion & deletion of " << num_ints << " ints in a vector:" << std::endl;
407   std::cout << "  std::allocator: " << end[0][0] << " seconds" << std::endl;
408   std::cout << "  malloc/free:    " << end[0][1] << " seconds" << std::endl;
409   std::cout << "  new/delete:     " << end[0][2] << " seconds" << std::endl;
410   std::cout << "  Pool Alloc:     " << end[0][3] << " seconds" << std::endl;
411   std::cout << "  Pool /w Sync:   " << end[0][4] << " seconds" << std::endl;
412   std::cout << "  Pool:           not possible" << std::endl;
413   std::cout << "Test 1: Insertion & deletion of " << num_ints << " ints in a set:" << std::endl;
414   std::cout << "  std::allocator: " << end[1][0] << " seconds" << std::endl;
415   std::cout << "  malloc/free:    " << end[1][1] << " seconds" << std::endl;
416   std::cout << "  new/delete:     " << end[1][2] << " seconds" << std::endl;
417   std::cout << "  Pool Alloc:     " << end[1][3] << " seconds" << std::endl;
418   std::cout << "  Pool /w Sync:   " << end[1][4] << " seconds" << std::endl;
419   std::cout << "  Pool:           not possible" << std::endl;
420   std::cout << "Test 2: Insertion & deletion of " << num_ints << " ints in a list:" << std::endl;
421   std::cout << "  std::allocator: " << end[2][0] << " seconds" << std::endl;
422   std::cout << "  malloc/free:    " << end[2][1] << " seconds" << std::endl;
423   std::cout << "  new/delete:     " << end[2][2] << " seconds" << std::endl;
424   std::cout << "  Pool Alloc:     " << end[2][3] << " seconds" << std::endl;
425   std::cout << "  Pool /w Sync:   " << end[2][4] << " seconds" << std::endl;
426   std::cout << "  Pool:           not possible" << std::endl;
427 }
428 
main(int argc,char * argv[])429 int main(int argc, char * argv[])
430 {
431   if (argc != 1 && argc != 2)
432   {
433     std::cerr << "Usage: " << argv[0]
434         << " [number_of_ints_to_use_each_try]" << std::endl;
435     return 1;
436   }
437 
438   errno = 0;
439 
440   if (argc == 2)
441   {
442     num_ints = std::strtoul(argv[1], 0, 10);
443     if (errno != 0)
444     {
445       std::cerr << "Cannot convert number \"" << argv[1] << '"' << std::endl;
446       return 2;
447     }
448   }
449   else
450     num_ints = 700000;
451 
452 #ifndef _NDEBUG
453   num_ints /= 100;
454 #endif
455 
456   try
457   {
458     timing_test_containers();
459     timing_test_alloc();
460     test_number = 5;
461     timing_test_alloc_larger<64>();
462     test_number = 6;
463     timing_test_alloc_larger<256>();
464     test_number = 7;
465     timing_test_alloc_larger<4096>();
466   }
467   catch (const std::bad_alloc &)
468   {
469     std::cerr << "Timing tests ran out of memory; try again with a lower value for number of ints"
470         << " (current value is " << num_ints << ")" << std::endl;
471     return 3;
472   }
473   catch (const std::exception & e)
474   {
475     std::cerr << "Error: " << e.what() << std::endl;
476     return 4;
477   }
478   catch (...)
479   {
480     std::cerr << "Unknown error" << std::endl;
481     return 5;
482   }
483 
484   return 0;
485 }
486 
487 /*
488 
489 Output:
490 
491 MSVC 10.0  using mutli-threaded DLL
492 
493  time_pool_alloc.cpp
494      Creating library J:\Cpp\pool\pool\Release\alloc_example.lib and object J:\Cpp\pool\pool\Release\alloc_example.exp
495   Generating code
496   Finished generating code
497   alloc_example.vcxproj -> J:\Cpp\pool\pool\Release\alloc_example.exe
498   Test 0: Insertion & deletion of 700000 ints in a vector:
499     std::allocator: 0.062 seconds
500     malloc/free:    0.078 seconds
501     new/delete:     0.078 seconds
502     Pool Alloc:     0.328 seconds
503     Pool /w Sync:   0.343 seconds
504     Pool:           not possible
505   Test 1: Insertion & deletion of 700000 ints in a set:
506     std::allocator: 0.561 seconds
507     malloc/free:    0.546 seconds
508     new/delete:     0.562 seconds
509     Pool Alloc:     0.109 seconds
510     Pool /w Sync:   0.094 seconds
511     Pool:           not possible
512   Test 2: Insertion & deletion of 700000 ints in a list:
513     std::allocator: 0.671 seconds
514     malloc/free:    0.67 seconds
515     new/delete:     0.671 seconds
516     Pool Alloc:     0.094 seconds
517     Pool /w Sync:   0.093 seconds
518     Pool:           not possible
519   Test 3: Alloc & Dealloc 700000 ints:
520     std::allocator: 0.5 seconds
521     malloc/free:    0.468 seconds
522     new/delete:     0.592 seconds
523     Pool Alloc:     0.032 seconds
524     Pool /w Sync:   0.015 seconds
525     Pool:           0.016 seconds
526   Test 4: Alloc 700000 ints & Dealloc 700000 ints:
527     std::allocator: 0.593 seconds
528     malloc/free:    0.577 seconds
529     new/delete:     0.717 seconds
530     Pool Alloc:     0.032 seconds
531     Pool /w Sync:   0.031 seconds
532     Pool:           0.047 seconds
533   Test 5: Alloc & Dealloc 700000 structures of size 64:
534     std::allocator: 0.499 seconds
535     malloc/free:    0.483 seconds
536     new/delete:     0.624 seconds
537     Pool Alloc:     0.016 seconds
538     Pool /w Sync:   0.031 seconds
539     Pool:           0.016 seconds
540   Test 6: Alloc & Dealloc 700000 structures of size 256:
541     std::allocator: 0.499 seconds
542     malloc/free:    0.484 seconds
543     new/delete:     0.639 seconds
544     Pool Alloc:     0.016 seconds
545     Pool /w Sync:   0.015 seconds
546     Pool:           0.016 seconds
547   Test 7: Alloc & Dealloc 700000 structures of size 4096:
548     std::allocator: 0.515 seconds
549     malloc/free:    0.515 seconds
550     new/delete:     0.639 seconds
551     Pool Alloc:     0.031 seconds
552     Pool /w Sync:   0.016 seconds
553     Pool:           0.016 seconds
554 
555 */
556 
557 
558 
559