• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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