• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10 
11 // Undefining BOOST_COMPUTE_USE_OFFLINE_CACHE macro as we want to modify cached
12 // parameters for copy algorithm without any undesirable consequences (like
13 // saving modified values of those parameters).
14 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
15     #undef BOOST_COMPUTE_USE_OFFLINE_CACHE
16 #endif
17 
18 #define BOOST_TEST_MODULE TestExtrema
19 #include <boost/test/unit_test.hpp>
20 
21 #include <boost/compute/system.hpp>
22 #include <boost/compute/command_queue.hpp>
23 #include <boost/compute/algorithm/copy.hpp>
24 #include <boost/compute/algorithm/iota.hpp>
25 #include <boost/compute/algorithm/fill.hpp>
26 #include <boost/compute/algorithm/max_element.hpp>
27 #include <boost/compute/algorithm/min_element.hpp>
28 #include <boost/compute/algorithm/minmax_element.hpp>
29 #include <boost/compute/container/vector.hpp>
30 #include <boost/compute/iterator/transform_iterator.hpp>
31 #include <boost/compute/detail/parameter_cache.hpp>
32 
33 #include "quirks.hpp"
34 #include "context_setup.hpp"
35 
36 namespace bc = boost::compute;
37 namespace compute = boost::compute;
38 
BOOST_AUTO_TEST_CASE(empyt_min)39 BOOST_AUTO_TEST_CASE(empyt_min)
40 {
41     using boost::compute::int_;
42 
43     boost::compute::vector<int_> vector(size_t(16), int_(0), queue);
44     boost::compute::vector<int_>::iterator min_iter =
45         boost::compute::min_element(vector.begin(), vector.begin(), queue);
46     BOOST_CHECK(min_iter == vector.begin());
47 
48     min_iter =
49         boost::compute::min_element(vector.begin(), vector.begin() + 1, queue);
50     BOOST_CHECK(min_iter == vector.begin());
51 }
52 
BOOST_AUTO_TEST_CASE(int_min_max)53 BOOST_AUTO_TEST_CASE(int_min_max)
54 {
55     using boost::compute::int_;
56     using boost::compute::uint_;
57 
58     boost::compute::vector<int_> vector(size_t(4096), int_(0), queue);
59     boost::compute::iota(vector.begin(), (vector.begin() + 512), 1, queue);
60     boost::compute::fill((vector.end() - 512), vector.end(), 513, queue);
61 
62     boost::compute::vector<int_>::iterator min_iter =
63         boost::compute::min_element(vector.begin(), vector.end(), queue);
64     BOOST_CHECK(min_iter == vector.begin() + 512);
65     BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0);
66     BOOST_CHECK_EQUAL(min_iter.read(queue), 0);
67 
68     boost::compute::vector<int_>::iterator max_iter =
69         boost::compute::max_element(vector.begin(), vector.end(), queue);
70     BOOST_CHECK(max_iter == vector.end() - 512);
71     BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513);
72     BOOST_CHECK_EQUAL(max_iter.read(queue), 513);
73 
74     // compare function
75     boost::compute::less<int_> lessint;
76 
77     // test minmax_element
78     std::pair<
79         boost::compute::vector<int_>::iterator,
80         boost::compute::vector<int_>::iterator
81     > minmax_iter =
82         boost::compute::minmax_element(vector.begin(), vector.end(), queue);
83     BOOST_CHECK_EQUAL((minmax_iter.first).read(queue), 0);
84     BOOST_CHECK_EQUAL((minmax_iter.second).read(queue), 513);
85 
86     minmax_iter =
87         boost::compute::minmax_element(vector.begin(), vector.end(), lessint, queue);
88     BOOST_CHECK_EQUAL((minmax_iter.first).read(queue), 0);
89     BOOST_CHECK_EQUAL((minmax_iter.second).read(queue), 513);
90 
91     // find_extrama_on_cpu
92 
93     // make sure find_extrama_on_cpu is used, no serial_find_extrema
94     std::string cache_key =
95         "__boost_find_extrema_cpu_4";
96     boost::shared_ptr<bc::detail::parameter_cache> parameters =
97         bc::detail::parameter_cache::get_global_cache(device);
98 
99     // save
100     uint_ map_copy_threshold =
101         parameters->get(cache_key, "serial_find_extrema_threshold", 0);
102     // force find_extrama_on_cpu
103     parameters->set(cache_key, "serial_find_extrema_threshold", 16);
104 
105     min_iter = boost::compute::detail::find_extrema_on_cpu(
106         vector.begin(), vector.end(), lessint, true /* find minimum */, queue
107     );
108     BOOST_CHECK(min_iter == vector.begin() + 512);
109     BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0);
110     BOOST_CHECK_EQUAL(min_iter.read(queue), 0);
111 
112     max_iter = boost::compute::detail::find_extrema_on_cpu(
113         vector.begin(), vector.end(), lessint, false /* find minimum */, queue
114     );
115     BOOST_CHECK(max_iter == vector.end() - 512);
116     BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513);
117     BOOST_CHECK_EQUAL(max_iter.read(queue), 513);
118 
119     // restore
120     parameters->set(cache_key, "serial_find_extrema_threshold", map_copy_threshold);
121 
122     if(is_apple_cpu_device(device)) {
123         std::cerr
124             << "skipping all further tests due to Apple platform"
125             << " behavior when local memory is used on a CPU device"
126             << std::endl;
127         return;
128     }
129 
130     // find_extrama_with_reduce
131     min_iter = boost::compute::detail::find_extrema_with_reduce(
132         vector.begin(), vector.end(), lessint, true /* find minimum */, queue
133     );
134     BOOST_CHECK(min_iter == vector.begin() + 512);
135     BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0);
136     BOOST_CHECK_EQUAL(min_iter.read(queue), 0);
137 
138     max_iter = boost::compute::detail::find_extrema_with_reduce(
139         vector.begin(), vector.end(), lessint, false /* find minimum */, queue
140     );
141     BOOST_CHECK(max_iter == vector.end() - 512);
142     BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513);
143     BOOST_CHECK_EQUAL(max_iter.read(queue), 513);
144 
145     // find_extram_with_atomics
146     min_iter = boost::compute::detail::find_extrema_with_atomics(
147         vector.begin(), vector.end(), lessint, true /* find minimum */, queue
148     );
149     BOOST_CHECK(min_iter == vector.begin() + 512);
150     BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0);
151     BOOST_CHECK_EQUAL(min_iter.read(queue), 0);
152 
153     max_iter = boost::compute::detail::find_extrema_with_atomics(
154         vector.begin(), vector.end(), lessint, false /* find minimum */, queue
155     );
156     BOOST_CHECK(max_iter == vector.end() - 512);
157     BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513);
158     BOOST_CHECK_EQUAL(max_iter.read(queue), 513);
159 }
160 
BOOST_AUTO_TEST_CASE(int2_min_max_custom_comparision_function)161 BOOST_AUTO_TEST_CASE(int2_min_max_custom_comparision_function)
162 {
163     using boost::compute::int2_;
164     using boost::compute::uint_;
165 
166     boost::compute::vector<int2_> vector(context);
167     vector.push_back(int2_(1, 10), queue);
168     vector.push_back(int2_(2, -100), queue);
169     vector.push_back(int2_(3, 30), queue);
170     vector.push_back(int2_(4, 20), queue);
171     vector.push_back(int2_(5, 5), queue);
172     vector.push_back(int2_(6, -80), queue);
173     vector.push_back(int2_(7, 21), queue);
174     vector.push_back(int2_(8, -5), queue);
175 
176     BOOST_COMPUTE_FUNCTION(bool, compare_second, (const int2_ a, const int2_ b),
177     {
178         return a.y < b.y;
179     });
180 
181     boost::compute::vector<int2_>::iterator min_iter =
182         boost::compute::min_element(
183             vector.begin(), vector.end(), compare_second, queue
184          );
185     BOOST_CHECK(min_iter == vector.begin() + 1);
186     BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100));
187 
188     boost::compute::vector<int2_>::iterator max_iter =
189         boost::compute::max_element(
190             vector.begin(), vector.end(), compare_second, queue
191         );
192     BOOST_CHECK(max_iter == vector.begin() + 2);
193     BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30));
194 
195     // find_extrama_on_cpu
196 
197     // make sure find_extrama_on_cpu is used, no serial_find_extrema
198     std::string cache_key =
199         "__boost_find_extrema_cpu_8";
200     boost::shared_ptr<bc::detail::parameter_cache> parameters =
201         bc::detail::parameter_cache::get_global_cache(device);
202 
203     // save
204     uint_ map_copy_threshold =
205         parameters->get(cache_key, "serial_find_extrema_threshold", 0);
206     // force find_extrama_on_cpu
207     parameters->set(cache_key, "serial_find_extrema_threshold", 16);
208 
209     min_iter = boost::compute::detail::find_extrema_on_cpu(
210         vector.begin(), vector.end(), compare_second, true /* find minimum */, queue
211     );
212     BOOST_CHECK(min_iter == vector.begin() + 1);
213     BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100));
214 
215     max_iter = boost::compute::detail::find_extrema_on_cpu(
216         vector.begin(), vector.end(), compare_second, false /* find minimum */, queue
217     );
218     BOOST_CHECK(max_iter == vector.begin() + 2);
219     BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30));
220 
221     // restore
222     parameters->set(cache_key, "serial_find_extrema_threshold", map_copy_threshold);
223 
224     if(is_apple_cpu_device(device)) {
225         std::cerr
226             << "skipping all further tests due to Apple platform"
227             << " behavior when local memory is used on a CPU device"
228             << std::endl;
229         return;
230     }
231 
232     // find_extrama_with_reduce
233     min_iter = boost::compute::detail::find_extrema_with_reduce(
234         vector.begin(), vector.end(), compare_second, true /* find minimum */, queue
235     );
236     BOOST_CHECK(min_iter == vector.begin() + 1);
237     BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100));
238 
239     max_iter = boost::compute::detail::find_extrema_with_reduce(
240         vector.begin(), vector.end(), compare_second, false /* find minimum */, queue
241     );
242     BOOST_CHECK(max_iter == vector.begin() + 2);
243     BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30));
244 
245     // find_extram_with_atomics
246     min_iter = boost::compute::detail::find_extrema_with_atomics(
247         vector.begin(), vector.end(), compare_second, true /* find minimum */, queue
248     );
249     BOOST_CHECK(min_iter == vector.begin() + 1);
250     BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100));
251 
252     max_iter = boost::compute::detail::find_extrema_with_atomics(
253         vector.begin(), vector.end(), compare_second, false /* find minimum */, queue
254     );
255     BOOST_CHECK(max_iter == vector.begin() + 2);
256     BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30));
257 }
258 
BOOST_AUTO_TEST_CASE(iota_min_max)259 BOOST_AUTO_TEST_CASE(iota_min_max)
260 {
261     boost::compute::vector<int> vector(5000, context);
262 
263     // fill with 0 -> 4999
264     boost::compute::iota(vector.begin(), vector.end(), 0, queue);
265 
266     boost::compute::vector<int>::iterator min_iter =
267         boost::compute::min_element(vector.begin(), vector.end(), queue);
268     BOOST_CHECK(min_iter == vector.begin());
269     BOOST_CHECK_EQUAL(*min_iter, 0);
270 
271     boost::compute::vector<int>::iterator max_iter =
272         boost::compute::max_element(vector.begin(), vector.end(), queue);
273     BOOST_CHECK(max_iter == vector.end() - 1);
274     BOOST_CHECK_EQUAL(*max_iter, 4999);
275 
276     min_iter =
277         boost::compute::min_element(
278             vector.begin() + 1000,
279             vector.end() - 1000,
280             queue
281         );
282     BOOST_CHECK(min_iter == vector.begin() + 1000);
283     BOOST_CHECK_EQUAL(*min_iter, 1000);
284 
285     max_iter =
286         boost::compute::max_element(
287             vector.begin() + 1000,
288             vector.end() - 1000,
289             queue
290         );
291     BOOST_CHECK(max_iter == vector.begin() + 3999);
292     BOOST_CHECK_EQUAL(*max_iter, 3999);
293 
294     // fill with -2500 -> 2499
295     boost::compute::iota(vector.begin(), vector.end(), -2500, queue);
296     min_iter =
297         boost::compute::min_element(vector.begin(), vector.end(), queue);
298     BOOST_CHECK(min_iter == vector.begin());
299     BOOST_CHECK_EQUAL(*min_iter, -2500);
300 
301     max_iter =
302         boost::compute::max_element(vector.begin(), vector.end(), queue);
303     BOOST_CHECK(max_iter == vector.end() - 1);
304     BOOST_CHECK_EQUAL(*max_iter, 2499);
305 }
306 
307 // uses max_element() and length() to find the longest 2d vector
BOOST_AUTO_TEST_CASE(max_vector_length)308 BOOST_AUTO_TEST_CASE(max_vector_length)
309 {
310     float data[] = { -1.5f, 3.2f,
311                      10.0f, 0.0f,
312                      -4.2f, 2.0f,
313                      0.0f, 0.5f,
314                      1.9f, 1.9f };
315     boost::compute::vector<boost::compute::float2_> vector(
316         reinterpret_cast<boost::compute::float2_ *>(data),
317         reinterpret_cast<boost::compute::float2_ *>(data) + 5,
318         queue
319     );
320 
321     // find length of the longest vector
322     typedef boost::compute::transform_iterator<
323                 boost::compute::vector<boost::compute::float2_>::iterator,
324                 boost::compute::length<boost::compute::float2_>
325             > length_transform_iter;
326 
327     length_transform_iter max_iter =
328         boost::compute::max_element(
329             boost::compute::make_transform_iterator(
330                 vector.begin(),
331                 boost::compute::length<boost::compute::float2_>()
332             ),
333             boost::compute::make_transform_iterator(
334                 vector.end(),
335                 boost::compute::length<boost::compute::float2_>()
336             ),
337             queue
338         );
339     BOOST_CHECK(
340         max_iter == boost::compute::make_transform_iterator(
341                         vector.begin() + 1,
342                         boost::compute::length<boost::compute::float2_>()
343                     )
344     );
345     BOOST_CHECK(max_iter.base() == vector.begin() + 1);
346     BOOST_CHECK_EQUAL(*max_iter, float(10.0));
347 
348     // find length of the shortest vector
349     length_transform_iter min_iter =
350         boost::compute::min_element(
351             boost::compute::make_transform_iterator(
352                 vector.begin(),
353                 boost::compute::length<boost::compute::float2_>()
354             ),
355             boost::compute::make_transform_iterator(
356                 vector.end(),
357                 boost::compute::length<boost::compute::float2_>()
358             ),
359             queue
360         );
361     BOOST_CHECK(
362         min_iter == boost::compute::make_transform_iterator(
363                         vector.begin() + 3,
364                         boost::compute::length<boost::compute::float2_>()
365                     )
366     );
367     BOOST_CHECK(min_iter.base() == vector.begin() + 3);
368     BOOST_CHECK_EQUAL(*min_iter, float(0.5));
369 }
370 
371 // uses max_element() and popcount() to find the value with the most 1 bits
BOOST_AUTO_TEST_CASE(max_bits_set)372 BOOST_AUTO_TEST_CASE(max_bits_set)
373 {
374     using boost::compute::uint_;
375 
376     uint_ data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
377     boost::compute::vector<uint_> vector(data, data + 10, queue);
378 
379     boost::compute::vector<uint_>::iterator iter =
380         boost::compute::max_element(
381             boost::compute::make_transform_iterator(
382                 vector.begin(),
383                 boost::compute::popcount<uint_>()
384             ),
385             boost::compute::make_transform_iterator(
386                 vector.end(),
387                 boost::compute::popcount<uint_>()
388             ),
389             queue
390         ).base();
391 
392     BOOST_CHECK(iter == vector.begin() + 7);
393     BOOST_CHECK_EQUAL(uint_(*iter), uint_(7));
394 }
395 
396 BOOST_AUTO_TEST_SUITE_END()
397