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