test_copy.cpp 12 KB

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