1 /*=============================================================================
2 Copyright (c) 2010 Tim Blechmann
3
4 Use, modification and distribution is subject to the Boost Software
5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8
9 #include <algorithm>
10 #include <vector>
11
12 #include <boost/foreach.hpp>
13 #include "high_resolution_timer.hpp"
14
15 #include <boost/heap/heap_merge.hpp>
16
17 #if defined(__GNUC__) && (!defined __INTEL_COMPILER)
18 #define no_inline __attribute__ ((noinline))
19 #else
20 #define no_inline
21 #endif
22
23 typedef std::vector<int> test_data;
24
25 const int num_benchmarks = 1;
26
make_sequential_test_data(int size)27 inline test_data make_sequential_test_data(int size)
28 {
29 test_data v(size);
30 for (int i = 0; i != size; ++i)
31 v[i] = i;
32 return v;
33 }
34
make_test_data(int size)35 inline test_data make_test_data(int size)
36 {
37 test_data v = make_sequential_test_data(size);
38 std::random_shuffle(v.begin(), v.end());
39 return v;
40 }
41
42 const int max_data = 20;
43
get_data(int index)44 test_data const & get_data(int index)
45 {
46 static std::vector <test_data> data;
47 if (data.empty())
48 for (int i = 0; i != num_benchmarks; ++i)
49 data.push_back(make_test_data((1<<(max_data+1))+1024));
50
51 return data[index];
52 }
53
54
55 #define DEFINE_BENCHMARKS_SELECTOR(SUFFIX) \
56 struct make_##SUFFIX \
57 { \
58 template <typename heap> \
59 struct rebind { \
60 typedef run_##SUFFIX<heap> type; \
61 }; \
62 };
63
64
65 template <typename pri_queue>
fill_heap(pri_queue & q,int index,int size,int offset=0)66 void fill_heap(pri_queue & q, int index, int size, int offset = 0)
67 {
68 test_data const & data = get_data(index);
69
70 for (int i = 0; i != size + 1; ++i) {
71 q.push(data[i]);
72 int top = q.top();
73 q.pop();
74 q.push(top);
75 }
76 }
77
78 template <typename pri_queue,
79 typename handle_container
80 >
fill_heap_with_handles(pri_queue & q,handle_container & handles,int index,int size,int offset=0)81 void fill_heap_with_handles(pri_queue & q, handle_container & handles, int index, int size, int offset = 0)
82 {
83 test_data const & data = get_data(index);
84
85 for (int i = 0; i != size + 1; ++i) {
86 handles[i] = q.push(data[i]);
87
88 if (i > 0) {
89 typename pri_queue::handle_type last = handles[i-1];
90 int val = *last;
91 q.erase(last);
92 handles[i-1] = q.push(val);
93 }
94 }
95 }
96
97
98 template <typename pri_queue>
99 struct run_sequential_push
100 {
run_sequential_pushrun_sequential_push101 run_sequential_push(int size):
102 size(size)
103 {}
104
preparerun_sequential_push105 void prepare(int index)
106 {
107 q.clear();
108 fill_heap(q, index, size);
109 }
110
operator ()run_sequential_push111 no_inline void operator()(int index)
112 {
113 test_data const & data = get_data(index);
114
115 for (int i = 0; i != 16; ++i)
116 q.push(data[(1<<max_data) + i]);
117 }
118
119 pri_queue q;
120 int size;
121 };
122
123 DEFINE_BENCHMARKS_SELECTOR(sequential_push)
124
125 template <typename pri_queue>
126 struct run_sequential_pop
127 {
run_sequential_poprun_sequential_pop128 run_sequential_pop(int size):
129 size(size)
130 {}
131
preparerun_sequential_pop132 void prepare(int index)
133 {
134 q.clear();
135 fill_heap(q, index, size);
136 }
137
operator ()run_sequential_pop138 no_inline void operator()(int index)
139 {
140 for (int i = 0; i != 16; ++i)
141 q.pop();
142 }
143
144 pri_queue q;
145 int size;
146 };
147
148 DEFINE_BENCHMARKS_SELECTOR(sequential_pop)
149
150 template <typename pri_queue>
151 struct run_sequential_increase
152 {
run_sequential_increaserun_sequential_increase153 run_sequential_increase(int size):
154 size(size), handles(size)
155 {}
156
preparerun_sequential_increase157 void prepare(int index)
158 {
159 q.clear();
160 fill_heap_with_handles(q, handles, index, size);
161 }
162
operator ()run_sequential_increase163 no_inline void operator()(int index)
164 {
165 test_data const & data = get_data(index);
166 for (int i = 0; i != 16; ++i)
167 q.increase(handles[i], data[i] + (1<<max_data));
168 }
169
170 pri_queue q;
171 int size;
172 std::vector<typename pri_queue::handle_type> handles;
173 };
174
175 DEFINE_BENCHMARKS_SELECTOR(sequential_increase)
176
177 template <typename pri_queue>
178 struct run_sequential_decrease
179 {
run_sequential_decreaserun_sequential_decrease180 run_sequential_decrease(int size):
181 size(size), handles(size)
182 {}
183
preparerun_sequential_decrease184 void prepare(int index)
185 {
186 q.clear();
187 fill_heap_with_handles(q, handles, index, size);
188 }
189
operator ()run_sequential_decrease190 no_inline void operator()(int index)
191 {
192 test_data const & data = get_data(index);
193 for (int i = 0; i != 16; ++i)
194 q.decrease(handles[i], data[i] + (1<<max_data));
195 }
196
197 pri_queue q;
198 int size;
199 std::vector<typename pri_queue::handle_type> handles;
200 };
201
202 DEFINE_BENCHMARKS_SELECTOR(sequential_decrease)
203
204 template <typename pri_queue>
205 struct run_merge_and_clear
206 {
run_merge_and_clearrun_merge_and_clear207 run_merge_and_clear(int size):
208 size(size)
209 {}
210
preparerun_merge_and_clear211 void prepare(int index)
212 {
213 q.clear();
214 r.clear();
215
216 fill_heap(q, index, size);
217 fill_heap(r, index, size, size);
218 }
219
operator ()run_merge_and_clear220 no_inline void operator()(int index)
221 {
222 boost::heap::heap_merge(q, r);
223 }
224
225 pri_queue q, r;
226 int size;
227 };
228
229 DEFINE_BENCHMARKS_SELECTOR(merge_and_clear)
230
231 template <typename pri_queue>
232 struct run_equivalence
233 {
run_equivalencerun_equivalence234 run_equivalence(int size):
235 size(size)
236 {}
237
preparerun_equivalence238 void prepare(int index)
239 {
240 q.clear();
241 r.clear();
242 s.clear();
243
244 fill_heap(q, index, size);
245 fill_heap(r, index, size, size);
246 fill_heap(s, index, size);
247 }
248
operator ()run_equivalence249 no_inline bool operator()(int index)
250 {
251 return (q == r) ^ (q == s);
252 }
253
254 pri_queue q, r, s;
255 int size;
256 };
257
DEFINE_BENCHMARKS_SELECTOR(equivalence)258 DEFINE_BENCHMARKS_SELECTOR(equivalence)
259
260
261 template <typename benchmark>
262 inline double run_benchmark(benchmark & b)
263 {
264 boost::high_resolution_timer timer;
265 std::vector<double> results;
266
267 for (int i = 0; i != num_benchmarks; ++i)
268 {
269 b.prepare(i);
270 timer.restart();
271 b(i);
272 double t = timer.elapsed();
273 results.push_back(t);
274 }
275
276 return results.at(results.size()/2); // median
277 }
278