1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifdef _MSC_VER
12 #pragma warning (disable : 4512)
13 #endif
14
15 #include <boost/container/allocator.hpp>
16
17 #define BOOST_CONTAINER_VECTOR_ALLOC_STATS
18
19 #include <boost/container/vector.hpp>
20
21 #undef BOOST_CONTAINER_VECTOR_ALLOC_STATS
22
23 #include <memory> //std::allocator
24 #include <iostream> //std::cout, std::endl
25 #include <cassert> //assert
26
27 #include <boost/timer/timer.hpp>
28 using boost::timer::cpu_timer;
29 using boost::timer::cpu_times;
30 using boost::timer::nanosecond_type;
31
32 namespace bc = boost::container;
33
34 typedef std::allocator<int> StdAllocator;
35 typedef bc::allocator<int, 2> AllocatorPlusV2;
36 typedef bc::allocator<int, 1> AllocatorPlusV1;
37
38 template<class Allocator> struct get_allocator_name;
39
40 template<> struct get_allocator_name<StdAllocator>
getget_allocator_name41 { static const char *get() { return "StdAllocator"; } };
42
43 template<> struct get_allocator_name<AllocatorPlusV2>
getget_allocator_name44 { static const char *get() { return "AllocatorPlusV2"; } };
45
46 template<> struct get_allocator_name<AllocatorPlusV1>
getget_allocator_name47 { static const char *get() { return "AllocatorPlusV1"; } };
48
49 class MyInt
50 {
51 std::size_t int_; //Use a type that will grow on 64 bit machines
52
53 public:
MyInt(int i=0)54 MyInt(int i = 0) : int_(i){}
55
MyInt(const MyInt & other)56 MyInt(const MyInt &other)
57 : int_(other.int_)
58 {}
59
operator =(const MyInt & other)60 MyInt & operator=(const MyInt &other)
61 {
62 int_ = other.int_;
63 return *this;
64 }
65 };
66
print_header()67 void print_header()
68 {
69 std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";"
70 << "num_shrink" << ";" << "shrink_to_fit(ns)" << std::endl;
71 }
72
73 template<class Allocator>
vector_test_template(unsigned int num_iterations,unsigned int num_elements,bool csv_output)74 void vector_test_template(unsigned int num_iterations, unsigned int num_elements, bool csv_output)
75 {
76 typedef typename Allocator::template rebind<MyInt>::other IntAllocator;
77
78 unsigned int capacity = 0;
79 const std::size_t Step = 5;
80 unsigned int num_shrink = 0;
81 (void)capacity;
82
83 cpu_timer timer;
84 timer.resume();
85
86 #ifndef NDEBUG
87 typedef bc::dtl::integral_constant
88 <unsigned, bc::dtl::version<Allocator>::value> alloc_version;
89 #endif
90
91 for(unsigned int r = 0; r != num_iterations; ++r){
92 bc::vector<MyInt, IntAllocator> v(num_elements);
93 v.reset_alloc_stats();
94 num_shrink = 0;
95 for(unsigned int e = num_elements; e != 0; e -= Step){
96 v.erase(v.end() - Step, v.end());
97 v.shrink_to_fit();
98 assert( (alloc_version::value != 2) || (e == Step) || (v.num_shrink > num_shrink) );
99 num_shrink = v.num_shrink;
100 }
101 assert(v.empty());
102 assert(0 == v.capacity());
103 }
104
105 timer.stop();
106 nanosecond_type nseconds = timer.elapsed().wall;
107
108 if(csv_output){
109 std::cout << get_allocator_name<Allocator>::get()
110 << ";"
111 << num_iterations
112 << ";"
113 << num_elements
114 << ";"
115 << num_shrink
116 << ";"
117 << float(nseconds)/(num_iterations*num_elements)
118 << std::endl;
119 }
120 else{
121 std::cout << std::endl
122 << "Allocator: " << get_allocator_name<Allocator>::get()
123 << std::endl
124 << " num_shrink: " << num_shrink
125 << std::endl
126 << " shrink_to_fit ns: "
127 << float(nseconds)/(num_iterations*num_elements)
128 << std::endl << std::endl;
129 }
130 bc::dlmalloc_trim(0);
131 }
132
main(int argc,const char * argv[])133 int main(int argc, const char *argv[])
134 {
135 //#define SINGLE_TEST
136 #define SIMPLE_IT
137 #ifdef SINGLE_TEST
138 #ifdef NDEBUG
139 unsigned int numit [] = { 10 };
140 #else
141 unsigned int numit [] = { 50 };
142 unsigned int numele[] = { 2000 };
143 #endif
144 #elif defined SIMPLE_IT
145 unsigned int numit [] = { 3 };
146 unsigned int numele[] = { 2000 };
147 #else
148 #ifdef NDEBUG
149 unsigned int numit [] = { 100, 1000, 10000 };
150 #else
151 unsigned int numit [] = { 10, 100, 1000 };
152 #endif
153 unsigned int numele [] = { 10000, 2000, 500 };
154 #endif
155
156 bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0);
157
158 if(csv_output){
159 print_header();
160 for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
161 vector_test_template<StdAllocator>(numit[i], numele[i], csv_output);
162 }
163 for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
164 vector_test_template<AllocatorPlusV1>(numit[i], numele[i], csv_output);
165 }
166 for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
167 vector_test_template<AllocatorPlusV2>(numit[i], numele[i], csv_output);
168 }
169 }
170 else{
171 for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
172 std::cout << "\n ----------------------------------- \n"
173 << " Iterations/Elements: " << numit[i] << "/" << numele[i]
174 << "\n ----------------------------------- \n";
175 vector_test_template<StdAllocator>(numit[i], numele[i], csv_output);
176 vector_test_template<AllocatorPlusV1>(numit[i], numele[i], csv_output);
177 vector_test_template<AllocatorPlusV2>(numit[i], numele[i], csv_output);
178 }
179 }
180 return 0;
181 }
182