• 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