• 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 #define BOOST_TEST_MODULE TestCopy
12 #include <boost/test/unit_test.hpp>
13 
14 #include <list>
15 #include <vector>
16 #include <string>
17 #include <sstream>
18 #include <iterator>
19 #include <iostream>
20 
21 #include <boost/compute/svm.hpp>
22 #include <boost/compute/system.hpp>
23 #include <boost/compute/functional.hpp>
24 #include <boost/compute/command_queue.hpp>
25 #include <boost/compute/algorithm/copy.hpp>
26 #include <boost/compute/algorithm/copy_n.hpp>
27 #include <boost/compute/algorithm/fill.hpp>
28 #include <boost/compute/algorithm/iota.hpp>
29 #include <boost/compute/async/future.hpp>
30 #include <boost/compute/container/vector.hpp>
31 #include <boost/compute/detail/device_ptr.hpp>
32 #include <boost/compute/iterator/detail/swizzle_iterator.hpp>
33 
34 #include "quirks.hpp"
35 #include "check_macros.hpp"
36 #include "context_setup.hpp"
37 
38 namespace bc = boost::compute;
39 namespace compute = boost::compute;
40 
BOOST_AUTO_TEST_CASE(copy_on_device)41 BOOST_AUTO_TEST_CASE(copy_on_device)
42 {
43     float data[] = { 6.1f, 10.2f, 19.3f, 25.4f };
44     bc::vector<float> a(4, context);
45     bc::copy(data, data + 4, a.begin(), queue);
46     CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 19.3f, 25.4f));
47 
48     bc::vector<float> b(4, context);
49     bc::fill(b.begin(), b.end(), 0, queue);
50     CHECK_RANGE_EQUAL(float, 4, b, (0.0f, 0.0f, 0.0f, 0.0f));
51 
52     bc::copy(a.begin(), a.end(), b.begin(), queue);
53     CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f));
54 
55     bc::vector<float> c(context);
56     bc::copy(c.begin(), c.end(), b.begin(), queue);
57     CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f));
58 }
59 
BOOST_AUTO_TEST_CASE(copy_on_device_device_ptr)60 BOOST_AUTO_TEST_CASE(copy_on_device_device_ptr)
61 {
62     float data[] = { 6.1f, 10.2f, 19.3f, 25.4f };
63     bc::vector<float> a(4, context);
64     bc::copy(data, data + 4, a.begin(), queue);
65     CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 19.3f, 25.4f));
66 
67     bc::vector<float> b(4, context);
68     bc::detail::device_ptr<float> b_ptr(b.get_buffer(), size_t(0));
69 
70     // buffer_iterator -> device_ptr
71     bc::copy(a.begin(), a.end(), b_ptr, queue);
72     CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f));
73 
74     bc::vector<float> c(4, context);
75     bc::fill(c.begin(), c.end(), 0.0f, queue);
76     bc::detail::device_ptr<float> c_ptr(c.get_buffer(), size_t(2));
77 
78     // device_ptr -> device_ptr
79     bc::copy(b_ptr, b_ptr + 2, c_ptr, queue);
80     CHECK_RANGE_EQUAL(float, 4, c, (0.0f, 0.0f, 6.1f, 10.2f));
81 
82     // device_ptr -> buffer_iterator
83     bc::copy(c_ptr, c_ptr + 2, a.begin() + 2, queue);
84     CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 6.1f, 10.2f));
85 }
86 
BOOST_AUTO_TEST_CASE(copy_on_host)87 BOOST_AUTO_TEST_CASE(copy_on_host)
88 {
89     int data[] = { 2, 4, 6, 8 };
90     std::vector<int> vector(4);
91     compute::copy(data, data + 4, vector.begin(), queue);
92     CHECK_RANGE_EQUAL(int, 4, vector, (2, 4, 6, 8));
93 }
94 
BOOST_AUTO_TEST_CASE(copy)95 BOOST_AUTO_TEST_CASE(copy)
96 {
97     int data[] = { 1, 2, 5, 6 };
98     bc::vector<int> vector(4, context);
99     bc::copy(data, data + 4, vector.begin(), queue);
100     CHECK_RANGE_EQUAL(int, 4, vector, (1, 2, 5, 6));
101 
102     std::vector<int> host_vector(4);
103     bc::copy(vector.begin(), vector.end(), host_vector.begin(), queue);
104     BOOST_CHECK_EQUAL(host_vector[0], 1);
105     BOOST_CHECK_EQUAL(host_vector[1], 2);
106     BOOST_CHECK_EQUAL(host_vector[2], 5);
107     BOOST_CHECK_EQUAL(host_vector[3], 6);
108 }
109 
BOOST_AUTO_TEST_CASE(empty_copy)110 BOOST_AUTO_TEST_CASE(empty_copy)
111 {
112     int data[] = { 1, 2, 5, 6 };
113     bc::vector<int> a(4, context);
114     bc::vector<int> b(context);
115     std::vector<int> c;
116 
117     bc::copy(data, data + 4, a.begin(), queue);
118     CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6));
119 
120     bc::copy(b.begin(), b.end(), a.begin(), queue);
121     CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6));
122 
123     bc::copy(c.begin(), c.end(), a.begin(), queue);
124     CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6));
125 
126     bc::future<bc::vector<int>::iterator> future =
127         bc::copy_async(c.begin(), c.end(), a.begin(), queue);
128     if(future.valid())
129         future.wait();
130     CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6));
131 }
132 
133 // Test copying from a std::list to a bc::vector. This differs from
134 // the test copying from std::vector because std::list has non-contigous
135 // storage for its data values.
BOOST_AUTO_TEST_CASE(copy_from_host_list)136 BOOST_AUTO_TEST_CASE(copy_from_host_list)
137 {
138     int data[] = { -4, 12, 9, 0 };
139     std::list<int> host_list(data, data + 4);
140 
141     bc::vector<int> vector(4, context);
142     bc::copy(host_list.begin(), host_list.end(), vector.begin(), queue);
143     CHECK_RANGE_EQUAL(int, 4, vector, (-4, 12, 9, 0));
144 }
145 
BOOST_AUTO_TEST_CASE(copy_n_int)146 BOOST_AUTO_TEST_CASE(copy_n_int)
147 {
148     int data[] = { 1, 2, 3, 4, 5 };
149     bc::vector<int> a(data, data + 5, queue);
150 
151     bc::vector<int> b(5, context);
152     bc::fill(b.begin(), b.end(), 0, queue);
153     bc::copy_n(a.begin(), 3, b.begin(), queue);
154     CHECK_RANGE_EQUAL(int, 5, b, (1, 2, 3, 0, 0));
155 
156     bc::copy_n(b.begin(), 4, a.begin(), queue);
157     CHECK_RANGE_EQUAL(int, 5, a, (1, 2, 3, 0, 5));
158 }
159 
BOOST_AUTO_TEST_CASE(copy_swizzle_iterator)160 BOOST_AUTO_TEST_CASE(copy_swizzle_iterator)
161 {
162     using bc::int2_;
163     using bc::int4_;
164 
165     int data[] = { 1, 2, 3, 4,
166                    5, 6, 7, 8,
167                    9, 1, 2, 3,
168                    4, 5, 6, 7 };
169 
170     bc::vector<int4_> input(reinterpret_cast<int4_*>(data),
171                             reinterpret_cast<int4_*>(data) + 4,
172                             queue);
173     BOOST_CHECK_EQUAL(input.size(), size_t(4));
174     CHECK_RANGE_EQUAL(int4_, 4, input,
175         (int4_(1, 2, 3, 4),
176          int4_(5, 6, 7, 8),
177          int4_(9, 1, 2, 3),
178          int4_(4, 5, 6, 7))
179     );
180 
181     bc::vector<int4_> output4(4, context);
182     bc::copy(
183         bc::detail::make_swizzle_iterator<4>(input.begin(), "wzyx"),
184         bc::detail::make_swizzle_iterator<4>(input.end(), "wzyx"),
185         output4.begin(),
186         queue
187     );
188     CHECK_RANGE_EQUAL(int4_, 4, output4,
189         (int4_(4, 3, 2, 1),
190          int4_(8, 7, 6, 5),
191          int4_(3, 2, 1, 9),
192          int4_(7, 6, 5, 4))
193     );
194 
195     bc::vector<int2_> output2(4, context);
196     bc::copy(
197         bc::detail::make_swizzle_iterator<2>(input.begin(), "xz"),
198         bc::detail::make_swizzle_iterator<2>(input.end(), "xz"),
199         output2.begin(),
200         queue
201     );
202     CHECK_RANGE_EQUAL(int2_, 4, output2,
203         (int2_(1, 3),
204          int2_(5, 7),
205          int2_(9, 2),
206          int2_(4, 6))
207     );
208 
209     bc::vector<int> output1(4, context);
210     bc::copy(
211         bc::detail::make_swizzle_iterator<1>(input.begin(), "y"),
212         bc::detail::make_swizzle_iterator<1>(input.end(), "y"),
213         output1.begin(),
214         queue
215     );
216     CHECK_RANGE_EQUAL(int, 4, output1, (2, 6, 1, 5));
217 }
218 
BOOST_AUTO_TEST_CASE(copy_int_async)219 BOOST_AUTO_TEST_CASE(copy_int_async)
220 {
221     // setup host data
222     int host_data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
223     typedef int* host_iterator;
224 
225     // setup device data
226     bc::vector<int> device_data(8, context);
227     typedef bc::vector<int>::iterator device_iterator;
228 
229     // copy data to device
230     bc::future<device_iterator> host_to_device_future =
231         bc::copy_async(host_data, host_data + 8, device_data.begin(), queue);
232 
233     // wait for copy to complete
234     host_to_device_future.wait();
235 
236     // check results
237     CHECK_RANGE_EQUAL(int, 8, device_data, (1, 2, 3, 4, 5, 6, 7, 8));
238     BOOST_VERIFY(host_to_device_future.get() == device_data.end());
239 
240     // fill host data with zeros
241     std::fill(host_data, host_data + 8, int(0));
242 
243     // copy data back to host
244     bc::future<host_iterator> device_to_host_future =
245         bc::copy_async(device_data.begin(), device_data.end(), host_data, queue);
246 
247     // wait for copy to complete
248     device_to_host_future.wait();
249 
250     // check results
251     BOOST_CHECK_EQUAL(host_data[0], int(1));
252     BOOST_CHECK_EQUAL(host_data[1], int(2));
253     BOOST_CHECK_EQUAL(host_data[2], int(3));
254     BOOST_CHECK_EQUAL(host_data[3], int(4));
255     BOOST_CHECK_EQUAL(host_data[4], int(5));
256     BOOST_CHECK_EQUAL(host_data[5], int(6));
257     BOOST_CHECK_EQUAL(host_data[6], int(7));
258     BOOST_CHECK_EQUAL(host_data[7], int(8));
259     BOOST_VERIFY(device_to_host_future.get() == host_data + 8);
260 }
261 
BOOST_AUTO_TEST_CASE(copy_to_back_inserter)262 BOOST_AUTO_TEST_CASE(copy_to_back_inserter)
263 {
264     compute::vector<int> device_vector(5, context);
265     compute::iota(device_vector.begin(), device_vector.end(), 10, queue);
266 
267     std::vector<int> host_vector;
268     compute::copy(
269         device_vector.begin(),
270         device_vector.end(),
271         std::back_inserter(host_vector),
272         queue
273     );
274 
275     BOOST_CHECK_EQUAL(host_vector.size(), size_t(5));
276     BOOST_CHECK_EQUAL(host_vector[0], 10);
277     BOOST_CHECK_EQUAL(host_vector[1], 11);
278     BOOST_CHECK_EQUAL(host_vector[2], 12);
279     BOOST_CHECK_EQUAL(host_vector[3], 13);
280     BOOST_CHECK_EQUAL(host_vector[4], 14);
281 }
282 
BOOST_AUTO_TEST_CASE(copy_to_stringstream)283 BOOST_AUTO_TEST_CASE(copy_to_stringstream)
284 {
285     std::stringstream stream;
286 
287     int data[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
288     compute::vector<int> vector(data, data + 8, queue);
289 
290     compute::copy(
291         vector.begin(),
292         vector.end(),
293         std::ostream_iterator<int>(stream, " "),
294         queue
295     );
296     BOOST_CHECK_EQUAL(stream.str(), std::string("2 3 4 5 6 7 8 9 "));
297 }
298 
BOOST_AUTO_TEST_CASE(check_copy_type)299 BOOST_AUTO_TEST_CASE(check_copy_type)
300 {
301     // copy from host to device and ensure clEnqueueWriteBuffer() is used
302     int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
303     compute::vector<int> a(8, context);
304     compute::future<void> future =
305         compute::copy_async(data, data + 8, a.begin(), queue);
306     BOOST_CHECK(
307         future.get_event().get_command_type() == CL_COMMAND_WRITE_BUFFER
308     );
309     future.wait();
310     CHECK_RANGE_EQUAL(int, 8, a, (1, 2, 3, 4, 5, 6, 7, 8));
311 
312     // copy on the device and ensure clEnqueueCopyBuffer() is used
313     compute::vector<int> b(8, context);
314     future = compute::copy_async(a.begin(), a.end(), b.begin(), queue);
315     BOOST_CHECK(
316         future.get_event().get_command_type() == CL_COMMAND_COPY_BUFFER
317     );
318     future.wait();
319     CHECK_RANGE_EQUAL(int, 8, b, (1, 2, 3, 4, 5, 6, 7, 8));
320 
321     // copy between vectors of different types on the device and ensure
322     // that the copy kernel is used
323     compute::vector<short> c(8, context);
324     future = compute::copy_async(a.begin(), a.end(), c.begin(), queue);
325     BOOST_CHECK(
326         future.get_event().get_command_type() == CL_COMMAND_NDRANGE_KERNEL
327     );
328     future.wait();
329     CHECK_RANGE_EQUAL(short, 8, c, (1, 2, 3, 4, 5, 6, 7, 8));
330 
331     // copy from device to host and ensure clEnqueueReadBuffer() is used
332     future = compute::copy_async(b.begin(), b.end(), data, queue);
333     BOOST_CHECK(
334         future.get_event().get_command_type() == CL_COMMAND_READ_BUFFER
335     );
336     future.wait();
337     CHECK_HOST_RANGE_EQUAL(int, 8, data, (1, 2, 3, 4, 5, 6, 7, 8));
338 }
339 
340 #ifdef BOOST_COMPUTE_CL_VERSION_2_0
BOOST_AUTO_TEST_CASE(copy_svm_ptr)341 BOOST_AUTO_TEST_CASE(copy_svm_ptr)
342 {
343     REQUIRES_OPENCL_VERSION(2, 0);
344 
345     using boost::compute::int_;
346 
347     if(bug_in_svmmemcpy(device)){
348         std::cerr << "skipping copy_svm_ptr test case" << std::endl;
349         return;
350     }
351 
352     int_ data[] = { 1, 3, 2, 4 };
353 
354     compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4);
355     compute::copy(data, data + 4, ptr, queue);
356 
357     int_ output[] = { 0, 0, 0, 0 };
358     compute::copy(ptr, ptr + 4, output, queue);
359     CHECK_HOST_RANGE_EQUAL(int_, 4, output, (1, 3, 2, 4));
360 
361     compute::svm_free(context, ptr);
362 }
363 
BOOST_AUTO_TEST_CASE(copy_async_svm_ptr)364 BOOST_AUTO_TEST_CASE(copy_async_svm_ptr)
365 {
366     REQUIRES_OPENCL_VERSION(2, 0);
367 
368     using boost::compute::int_;
369 
370     if(bug_in_svmmemcpy(device)){
371         std::cerr << "skipping copy_svm_ptr test case" << std::endl;
372         return;
373     }
374 
375     int_ data[] = { 1, 3, 2, 4 };
376 
377     compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4);
378     boost::compute::future<void> future =
379         compute::copy_async(data, data + 4, ptr, queue);
380     future.wait();
381 
382     int_ output[] = { 0, 0, 0, 0 };
383     future =
384         compute::copy_async(ptr, ptr + 4, output, queue);
385     future.wait();
386     CHECK_HOST_RANGE_EQUAL(int_, 4, output, (1, 3, 2, 4));
387 
388     compute::svm_free(context, ptr);
389 }
390 #endif // BOOST_COMPUTE_CL_VERSION_2_0
391 
BOOST_AUTO_TEST_CASE(copy_to_vector_bool)392 BOOST_AUTO_TEST_CASE(copy_to_vector_bool)
393 {
394     using compute::uchar_;
395 
396     compute::vector<uchar_> vec(2, context);
397 
398     // copy to device
399     bool data[] = {true, false};
400     compute::copy(data, data + 2, vec.begin(), queue);
401     BOOST_CHECK(static_cast<bool>(vec[0]) == true);
402     BOOST_CHECK(static_cast<bool>(vec[1]) == false);
403 
404     // copy to host
405     std::vector<bool> host_vec(vec.size());
406     compute::copy(vec.begin(), vec.end(), host_vec.begin(), queue);
407     BOOST_CHECK(host_vec[0] == true);
408     BOOST_CHECK(host_vec[1] == false);
409 }
410 
411 BOOST_AUTO_TEST_SUITE_END()
412