diff options
Diffstat (limited to 'src/boost/libs/compute/test')
165 files changed, 21184 insertions, 0 deletions
diff --git a/src/boost/libs/compute/test/CMakeLists.txt b/src/boost/libs/compute/test/CMakeLists.txt new file mode 100644 index 00000000..1aa99ff9 --- /dev/null +++ b/src/boost/libs/compute/test/CMakeLists.txt @@ -0,0 +1,236 @@ +# --------------------------------------------------------------------------- +# Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +# +# Distributed under the Boost Software License, Version 1.0 +# See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt +# +# --------------------------------------------------------------------------- + +include_directories(../include) + +set(BOOST_COMPONENTS unit_test_framework) + +if(${BOOST_COMPUTE_USE_CPP11}) + # allow tests to use C++11 features + add_definitions(-DBOOST_COMPUTE_USE_CPP11) +endif() + +if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} system filesystem) + add_definitions(-DBOOST_COMPUTE_USE_OFFLINE_CACHE) +endif() + +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} system thread) +endif() + +if(MSVC AND BOOST_COMPONENTS) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} chrono) +endif() + +if(BOOST_COMPONENTS) + list(REMOVE_DUPLICATES BOOST_COMPONENTS) +endif() +find_package(Boost 1.54 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + +if(NOT MSVC) + add_definitions(-DBOOST_TEST_DYN_LINK) +else() + if(MSVC AND ${BOOST_COMPUTE_BOOST_ALL_DYN_LINK}) + add_definitions(-DBOOST_TEST_DYN_LINK) + endif() +endif() + +# enable automatic kernel compilation error messages for tests +add_definitions(-DBOOST_COMPUTE_DEBUG_KERNEL_COMPILATION) + +# enable code coverage generation (only with GCC for now) +if(${BOOST_COMPUTE_ENABLE_COVERAGE} AND ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + add_definitions(-fprofile-arcs -ftest-coverage) +endif() + +# add path to test data dir +add_definitions(-DBOOST_COMPUTE_TEST_DATA_PATH="${CMAKE_CURRENT_SOURCE_DIR}/data") + +function(add_compute_test TEST_NAME TEST_SOURCE) + get_filename_component(TEST_TARGET ${TEST_SOURCE} NAME_WE) + add_executable(${TEST_TARGET} ${TEST_SOURCE}) + target_link_libraries(${TEST_TARGET} + ${OpenCL_LIBRARIES} + ${Boost_LIBRARIES} + ) + + # link with coverage library + if(${BOOST_COMPUTE_ENABLE_COVERAGE} AND ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + target_link_libraries(${TEST_TARGET} -fprofile-arcs -ftest-coverage) + endif() + + add_test(${TEST_NAME} ${TEST_TARGET}) +endfunction() + +add_compute_test("core.buffer" test_buffer.cpp) +add_compute_test("core.closure" test_closure.cpp) +add_compute_test("core.command_queue" test_command_queue.cpp) +add_compute_test("core.context" test_context.cpp) +add_compute_test("core.device" test_device.cpp) +add_compute_test("core.event" test_event.cpp) +add_compute_test("core.function" test_function.cpp) +add_compute_test("core.kernel" test_kernel.cpp) +add_compute_test("core.pipe" test_pipe.cpp) +add_compute_test("core.platform" test_platform.cpp) +add_compute_test("core.program" test_program.cpp) +add_compute_test("core.system" test_system.cpp) +add_compute_test("core.type_traits" test_type_traits.cpp) +add_compute_test("core.user_event" test_user_event.cpp) + +add_compute_test("utility.extents" test_extents.cpp) +add_compute_test("utility.invoke" test_invoke.cpp) +add_compute_test("utility.program_cache" test_program_cache.cpp) +add_compute_test("utility.wait_list" test_wait_list.cpp) + +add_compute_test("algorithm.accumulate" test_accumulate.cpp) +add_compute_test("algorithm.adjacent_difference" test_adjacent_difference.cpp) +add_compute_test("algorithm.adjacent_find" test_adjacent_find.cpp) +add_compute_test("algorithm.any_all_none_of" test_any_all_none_of.cpp) +add_compute_test("algorithm.binary_search" test_binary_search.cpp) +add_compute_test("algorithm.copy" test_copy.cpp) +add_compute_test("algorithm.copy_type_mismatch" test_copy_type_mismatch.cpp) +add_compute_test("algorithm.copy_if" test_copy_if.cpp) +add_compute_test("algorithm.count" test_count.cpp) +add_compute_test("algorithm.equal" test_equal.cpp) +add_compute_test("algorithm.equal_range" test_equal_range.cpp) +add_compute_test("algorithm.extrema" test_extrema.cpp) +add_compute_test("algorithm.fill" test_fill.cpp) +add_compute_test("algorithm.find" test_find.cpp) +add_compute_test("algorithm.find_end" test_find_end.cpp) +add_compute_test("algorithm.for_each" test_for_each.cpp) +add_compute_test("algorithm.gather" test_gather.cpp) +add_compute_test("algorithm.generate" test_generate.cpp) +add_compute_test("algorithm.includes" test_includes.cpp) +add_compute_test("algorithm.inner_product" test_inner_product.cpp) +add_compute_test("algorithm.inplace_merge" test_inplace_merge.cpp) +add_compute_test("algorithm.inplace_reduce" test_inplace_reduce.cpp) +add_compute_test("algorithm.insertion_sort" test_insertion_sort.cpp) +add_compute_test("algorithm.iota" test_iota.cpp) +add_compute_test("algorithm.is_permutation" test_is_permutation.cpp) +add_compute_test("algorithm.is_sorted" test_is_sorted.cpp) +add_compute_test("algorithm.merge_sort_gpu" test_merge_sort_gpu.cpp) +add_compute_test("algorithm.merge" test_merge.cpp) +add_compute_test("algorithm.mismatch" test_mismatch.cpp) +add_compute_test("algorithm.next_permutation" test_next_permutation.cpp) +add_compute_test("algorithm.nth_element" test_nth_element.cpp) +add_compute_test("algorithm.partial_sum" test_partial_sum.cpp) +add_compute_test("algorithm.partition" test_partition.cpp) +add_compute_test("algorithm.partition_point" test_partition_point.cpp) +add_compute_test("algorithm.prev_permutation" test_prev_permutation.cpp) +add_compute_test("algorithm.radix_sort" test_radix_sort.cpp) +add_compute_test("algorithm.radix_sort_by_key" test_radix_sort_by_key.cpp) +add_compute_test("algorithm.random_fill" test_random_fill.cpp) +add_compute_test("algorithm.random_shuffle" test_random_shuffle.cpp) +add_compute_test("algorithm.reduce" test_reduce.cpp) +add_compute_test("algorithm.reduce_by_key" test_reduce_by_key.cpp) +add_compute_test("algorithm.remove" test_remove.cpp) +add_compute_test("algorithm.replace" test_replace.cpp) +add_compute_test("algorithm.reverse" test_reverse.cpp) +add_compute_test("algorithm.rotate" test_rotate.cpp) +add_compute_test("algorithm.rotate_copy" test_rotate_copy.cpp) +add_compute_test("algorithm.scan" test_scan.cpp) +add_compute_test("algorithm.scatter" test_scatter.cpp) +add_compute_test("algorithm.scatter_if" test_scatter_if.cpp) +add_compute_test("algorithm.search" test_search.cpp) +add_compute_test("algorithm.search_n" test_search_n.cpp) +add_compute_test("algorithm.set_difference" test_set_difference.cpp) +add_compute_test("algorithm.set_intersection" test_set_intersection.cpp) +add_compute_test("algorithm.set_symmetric_difference" test_set_symmetric_difference.cpp) +add_compute_test("algorithm.set_union" test_set_union.cpp) +add_compute_test("algorithm.sort" test_sort.cpp) +add_compute_test("algorithm.sort_by_key" test_sort_by_key.cpp) +add_compute_test("algorithm.stable_partition" test_stable_partition.cpp) +add_compute_test("algorithm.stable_sort" test_stable_sort.cpp) +add_compute_test("algorithm.stable_sort_by_key" test_stable_sort_by_key.cpp) +add_compute_test("algorithm.transform" test_transform.cpp) +add_compute_test("algorithm.transform_if" test_transform_if.cpp) +add_compute_test("algorithm.transform_reduce" test_transform_reduce.cpp) +add_compute_test("algorithm.unique" test_unique.cpp) +add_compute_test("algorithm.unique_copy" test_unique_copy.cpp) +add_compute_test("algorithm.lexicographical_compare" test_lexicographical_compare.cpp) + +add_compute_test("allocator.buffer_allocator" test_buffer_allocator.cpp) +add_compute_test("allocator.pinned_allocator" test_pinned_allocator.cpp) + +add_compute_test("async.wait" test_async_wait.cpp) +add_compute_test("async.wait_guard" test_async_wait_guard.cpp) + +add_compute_test("container.array" test_array.cpp) +add_compute_test("container.dynamic_bitset" test_dynamic_bitset.cpp) +add_compute_test("container.flat_map" test_flat_map.cpp) +add_compute_test("container.flat_set" test_flat_set.cpp) +add_compute_test("container.mapped_view" test_mapped_view.cpp) +add_compute_test("container.stack" test_stack.cpp) +add_compute_test("container.string" test_string.cpp) +add_compute_test("container.valarray" test_valarray.cpp) +add_compute_test("container.vector" test_vector.cpp) + +add_compute_test("exception.context_error" test_context_error.cpp) +add_compute_test("exception.no_device_found" test_no_device_found.cpp) +add_compute_test("exception.opencl_error" test_opencl_error.cpp) +add_compute_test("exception.unsupported_extension" test_unsupported_extension.cpp) + +add_compute_test("functional.as" test_functional_as.cpp) +add_compute_test("functional.bind" test_functional_bind.cpp) +add_compute_test("functional.convert" test_functional_convert.cpp) +add_compute_test("functional.get" test_functional_get.cpp) +add_compute_test("functional.hash" test_functional_hash.cpp) +add_compute_test("functional.identity" test_functional_identity.cpp) +add_compute_test("functional.popcount" test_functional_popcount.cpp) +add_compute_test("functional.unpack" test_functional_unpack.cpp) + +add_compute_test("image.image1d" test_image1d.cpp) +add_compute_test("image.image2d" test_image2d.cpp) +add_compute_test("image.image3d" test_image3d.cpp) +add_compute_test("image.image_sampler" test_image_sampler.cpp) + +add_compute_test("iterator.buffer_iterator" test_buffer_iterator.cpp) +add_compute_test("iterator.constant_iterator" test_constant_iterator.cpp) +add_compute_test("iterator.counting_iterator" test_counting_iterator.cpp) +add_compute_test("iterator.discard_iterator" test_discard_iterator.cpp) +add_compute_test("iterator.function_input_iterator" test_function_input_iterator.cpp) +add_compute_test("iterator.permutation_iterator" test_permutation_iterator.cpp) +add_compute_test("iterator.strided_iterator" test_strided_iterator.cpp) +add_compute_test("iterator.transform_iterator" test_transform_iterator.cpp) +add_compute_test("iterator.zip_iterator" test_zip_iterator.cpp) + +add_compute_test("memory.local_buffer" test_local_buffer.cpp) +add_compute_test("memory.svm_ptr" test_svm_ptr.cpp) + +add_compute_test("random.bernoulli_distribution" test_bernoulli_distribution.cpp) +add_compute_test("random.discrete_distribution" test_discrete_distribution.cpp) +add_compute_test("random.linear_congruential_engine" test_linear_congruential_engine.cpp) +add_compute_test("random.mersenne_twister_engine" test_mersenne_twister_engine.cpp) +add_compute_test("random.threefry_engine" test_threefry_engine.cpp) +add_compute_test("random.normal_distribution" test_normal_distribution.cpp) +add_compute_test("random.uniform_int_distribution" test_uniform_int_distribution.cpp) +add_compute_test("random.uniform_real_distribution" test_uniform_real_distribution.cpp) + +add_compute_test("types.fundamental" test_types.cpp) +add_compute_test("types.complex" test_complex.cpp) +add_compute_test("types.pair" test_pair.cpp) +add_compute_test("types.tuple" test_tuple.cpp) +add_compute_test("types.struct" test_struct.cpp) + +add_compute_test("type_traits.result_of" test_result_of.cpp) + +add_compute_test("experimental.clamp_range" test_clamp_range.cpp) +add_compute_test("experimental.malloc" test_malloc.cpp) +add_compute_test("experimental.sort_by_transform" test_sort_by_transform.cpp) +add_compute_test("experimental.tabulate" test_tabulate.cpp) + +# miscellaneous tests +add_compute_test("misc.amd_cpp_kernel_language" test_amd_cpp_kernel_language.cpp) +add_compute_test("misc.lambda" test_lambda.cpp) +add_compute_test("misc.user_defined_types" test_user_defined_types.cpp) +add_compute_test("misc.literal_conversion" test_literal_conversion.cpp) + +# extra tests (interop tests, linkage tests, etc.) +add_subdirectory(extra) diff --git a/src/boost/libs/compute/test/Jamfile.v2 b/src/boost/libs/compute/test/Jamfile.v2 new file mode 100644 index 00000000..f1a6bfe5 --- /dev/null +++ b/src/boost/libs/compute/test/Jamfile.v2 @@ -0,0 +1,49 @@ +# (C) Copyright 2015: Kyle Lutz +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import testing ; + +lib boost_unit_test_framework ; + +obj has_opencl : check/has_opencl.cpp ; +explicit has_opencl ; + +project + : source-location . + : requirements + <define>BOOST_ALL_NO_LIB=1 + <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS + <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS + <toolset>msvc:<define>NOMINMAX + <toolset>msvc:<cxxflags>/wd4003 # Not enough actual parameters for a BOOST_PP macro + <toolset>msvc:<cxxflags>/wd4244 # Warning C4244: 'initializing': conversion from 'double' to 'int', possible loss of data + <toolset>msvc:<cxxflags>/wd4305 # Warning C4305: 'initializing': truncation from 'double' to 'float' + <toolset>msvc:<cxxflags>/wd4800 # Warning C4800: 'uint32_t' : forcing value to bool 'true' or 'false' (performance warning) + <toolset>msvc:<cxxflags>/wd4838 # Warning C4838: conversion from 'double' to 'float' requires a narrowing conversion + <library>/boost/test//boost_unit_test_framework + + [ check-target-builds has_opencl "OpenCL" : : <build>no ] + ; + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) + : + : + : + <link>shared:<define>BOOST_TEST_DYN_LINK=1 + <host-os>linux:<linkflags>"-lOpenCL" + <host-os>darwin:<linkflags>"-framework OpenCL" + <host-os>freebsd:<linkflags>"-lOpenCL" + ] ; + } + + return $(all_rules) ; +} + +test-suite compute : [ test_all r ] : ; diff --git a/src/boost/libs/compute/test/check/has_opencl.cpp b/src/boost/libs/compute/test/check/has_opencl.cpp new file mode 100644 index 00000000..10769d2b --- /dev/null +++ b/src/boost/libs/compute/test/check/has_opencl.cpp @@ -0,0 +1,11 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017 Kohei Takahashi +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#include <boost/compute/cl.hpp> diff --git a/src/boost/libs/compute/test/check_macros.hpp b/src/boost/libs/compute/test/check_macros.hpp new file mode 100644 index 00000000..f3e609ed --- /dev/null +++ b/src/boost/libs/compute/test/check_macros.hpp @@ -0,0 +1,84 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_TEST_CHECK_MACROS_HPP +#define BOOST_COMPUTE_TEST_CHECK_MACROS_HPP + +#define LIST_ARRAY_VALUES(z, n, data) \ + BOOST_PP_COMMA_IF(n) BOOST_PP_ARRAY_ELEM(n, data) + +// checks 'size' values of 'type' in the device range 'actual` +// against the values given in the array 'expected' +#define CHECK_RANGE_EQUAL(type, size, actual, expected) \ + { \ + type _actual[size]; \ + boost::compute::copy( \ + actual.begin(), actual.begin()+size, _actual, queue \ + ); \ + const type _expected[size] = { \ + BOOST_PP_REPEAT(size, LIST_ARRAY_VALUES, (size, expected)) \ + }; \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + _actual, _actual + size, _expected, _expected + size \ + ); \ + } + +template <typename Left, typename Right, typename ToleranceBaseType> +inline void +equal_close_impl(Left left_begin, + Left left_end, + Right right_begin, + Right right_end, + ToleranceBaseType tolerance) +{ + for(; left_begin != (left_end); ++left_begin, ++right_begin) { + BOOST_CHECK_CLOSE(*left_begin, *right_begin, tolerance); \ + } +} + +#define BOOST_COMPUTE_TEST_CHECK_CLOSE_COLLECTIONS(L_begin, L_end, R_begin, R_end, tolerance) \ + { \ + equal_close_impl(L_begin, L_end, R_begin, R_end, tolerance); \ + } + +#define CHECK_RANGE_CLOSE(type, size, actual, expected, tolerance) \ + { \ + type _actual[size]; \ + boost::compute::copy( \ + actual.begin(), actual.begin()+size, _actual, queue \ + ); \ + const type _expected[size] = { \ + BOOST_PP_REPEAT(size, LIST_ARRAY_VALUES, (size, expected)) \ + }; \ + BOOST_COMPUTE_TEST_CHECK_CLOSE_COLLECTIONS( \ + _actual, _actual + size, _expected, _expected + size, tolerance \ + ); \ + } + +#define CHECK_HOST_RANGE_EQUAL(type, size, actual, expected) \ + { \ + const type _expected[size] = { \ + BOOST_PP_REPEAT(size, LIST_ARRAY_VALUES, (size, expected)) \ + }; \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + actual, actual + size, _expected, _expected + size \ + ); \ + } + +#define CHECK_STRING_EQUAL(actual, expected) \ + { \ + std::string _actual(actual.size(), '\0'); \ + boost::compute::copy( \ + actual.begin(), actual.end(), _actual.begin(), queue \ + ); \ + BOOST_CHECK_EQUAL(_actual, expected); \ + } + +#endif // BOOST_COMPUTE_TEST_CHECK_MACROS_HPP diff --git a/src/boost/libs/compute/test/context_setup.hpp b/src/boost/libs/compute/test/context_setup.hpp new file mode 100644 index 00000000..bff606ec --- /dev/null +++ b/src/boost/libs/compute/test/context_setup.hpp @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Denis Demidov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_TEST_CONTEXT_SETUP_HPP +#define BOOST_COMPUTE_TEST_CONTEXT_SETUP_HPP + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> + +#include "opencl_version_check.hpp" + +struct Context { + boost::compute::device device; + boost::compute::context context; + boost::compute::command_queue queue; + + Context() : + device ( boost::compute::system::default_device() ), + context( boost::compute::system::default_context() ), + queue ( boost::compute::system::default_queue() ) + {} +}; + +BOOST_FIXTURE_TEST_SUITE(compute_test, Context) + +#endif diff --git a/src/boost/libs/compute/test/data/invalid_program.cl b/src/boost/libs/compute/test/data/invalid_program.cl new file mode 100644 index 00000000..3a9de877 --- /dev/null +++ b/src/boost/libs/compute/test/data/invalid_program.cl @@ -0,0 +1,10 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017 Kristian Popov <kristian.popov@outlook.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// +__kernel void foo(__global int *input) { !@#$%^&*() } diff --git a/src/boost/libs/compute/test/data/program.cl b/src/boost/libs/compute/test/data/program.cl new file mode 100644 index 00000000..c8962b88 --- /dev/null +++ b/src/boost/libs/compute/test/data/program.cl @@ -0,0 +1,15 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +__kernel void foobar(__global int* x) +{ + const int gid = get_global_id(0); + x[gid] = gid; +} diff --git a/src/boost/libs/compute/test/data/program.spirv32 b/src/boost/libs/compute/test/data/program.spirv32 Binary files differnew file mode 100644 index 00000000..79eb6153 --- /dev/null +++ b/src/boost/libs/compute/test/data/program.spirv32 diff --git a/src/boost/libs/compute/test/data/program.spirv64 b/src/boost/libs/compute/test/data/program.spirv64 Binary files differnew file mode 100644 index 00000000..57113d41 --- /dev/null +++ b/src/boost/libs/compute/test/data/program.spirv64 diff --git a/src/boost/libs/compute/test/extra/CMakeLists.txt b/src/boost/libs/compute/test/extra/CMakeLists.txt new file mode 100644 index 00000000..4795a6cc --- /dev/null +++ b/src/boost/libs/compute/test/extra/CMakeLists.txt @@ -0,0 +1,81 @@ +# --------------------------------------------------------------------------- +# Copyright (c) 2015 Kyle Lutz <kyle.r.lutz@gmail.com> +# +# Distributed under the Boost Software License, Version 1.0 +# See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt +# +# --------------------------------------------------------------------------- + +# include local test headers +include_directories(..) + +# Check for linkage problems +add_executable(test_multiple_objects + test_multiple_objects1.cpp + test_multiple_objects2.cpp + ) +target_link_libraries(test_multiple_objects + ${OPENCL_LIBRARIES} + ${Boost_LIBRARIES} + ) +# link with coverage library +if(${BOOST_COMPUTE_ENABLE_COVERAGE} AND ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + target_link_libraries(test_multiple_objects -fprofile-arcs -ftest-coverage) +endif() +add_test("misc.multiple_objects" test_multiple_objects) + +# eigen interop tests +if(${BOOST_COMPUTE_HAVE_EIGEN}) + find_package(Eigen REQUIRED) + include_directories(SYSTEM ${EIGEN_INCLUDE_DIRS}) + add_compute_test("interop.eigen" test_interop_eigen.cpp) +endif() + +# opencv interop tests +if(${BOOST_COMPUTE_HAVE_OPENCV}) + find_package(OpenCV REQUIRED) + include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS}) + add_compute_test("interop.opencv" test_interop_opencv.cpp) + target_link_libraries(test_interop_opencv ${OpenCV_LIBS}) +endif() + +# qt interop tests +if(${BOOST_COMPUTE_HAVE_QT}) + # look for Qt4 in the first place + find_package(Qt4 QUIET) + + if(${QT4_FOUND}) + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtOpenGL) + include(${QT_USE_FILE}) + else() + find_package(Qt5Widgets QUIET) + + # look for Qt5 + if(${Qt5Widgets_FOUND}) + find_package(Qt5Core REQUIRED) + find_package(Qt5Widgets REQUIRED) + find_package(Qt5OpenGL REQUIRED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5OpenGL_EXECUTABLE_COMPILE_FLAGS}") + set(QT_LIBRARIES ${Qt5OpenGL_LIBRARIES}) + else() + # no valid Qt framework found + message(FATAL_ERROR "Error: Did not find Qt4 or Qt5") + endif() + endif() + + add_compute_test("interop.qt" test_interop_qt.cpp) + target_link_libraries(test_interop_qt ${QT_LIBRARIES}) + + # the opengl interop test depends on qt to create the opengl context + add_compute_test("interop.opengl" test_interop_opengl.cpp) + target_link_libraries(test_interop_opengl ${QT_LIBRARIES}) +endif() + +# vtk interop tests +if(${BOOST_COMPUTE_HAVE_VTK}) + find_package(VTK REQUIRED) + include(${VTK_USE_FILE}) + add_compute_test("interop.vtk" test_interop_vtk.cpp) + target_link_libraries(test_interop_vtk ${VTK_LIBRARIES}) +endif() diff --git a/src/boost/libs/compute/test/extra/test_interop_eigen.cpp b/src/boost/libs/compute/test/extra/test_interop_eigen.cpp new file mode 100644 index 00000000..a184de9b --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_interop_eigen.cpp @@ -0,0 +1,106 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInteropEigen +#include <boost/test/unit_test.hpp> + +#include <boost/compute/closure.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/interop/eigen.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bcl = boost::compute; + +BOOST_AUTO_TEST_CASE(eigen) +{ + Eigen::MatrixXf mat(3, 3); + mat << 1, 2, 3, + 6, 5, 4, + 7, 8, 9; + + // copy matrix to gpu buffer + bcl::vector<float> vec(9, context); + bcl::eigen_copy_matrix_to_buffer(mat, vec.begin(), queue); + CHECK_RANGE_EQUAL(float, 9, vec, (1, 6, 7, 2, 5, 8, 3, 4, 9)); + + // transpose matrix and then copy to gpu buffer + mat = mat.transpose().eval(); + bcl::eigen_copy_matrix_to_buffer(mat, vec.begin(), queue); + CHECK_RANGE_EQUAL(float, 9, vec, (1, 2, 3, 6, 5, 4, 7, 8, 9)); + + // set matrix to zero and copy data back from gpu buffer + mat.setZero(); + bcl::eigen_copy_buffer_to_matrix(vec.begin(), mat, queue); + BOOST_CHECK(mat.isZero() == false); + BOOST_CHECK_EQUAL(mat.sum(), 45); +} + +BOOST_AUTO_TEST_CASE(eigen_types) +{ + BOOST_CHECK(std::strcmp(bcl::type_name<Eigen::Vector2i>(), "int2") == 0); + BOOST_CHECK(std::strcmp(bcl::type_name<Eigen::Vector2f>(), "float2") == 0); + BOOST_CHECK(std::strcmp(bcl::type_name<Eigen::Vector4f>(), "float4") == 0); + BOOST_CHECK(std::strcmp(bcl::type_name<Eigen::Vector4d>(), "double4") == 0); +} + +BOOST_AUTO_TEST_CASE(multiply_matrix4) +{ + std::vector<Eigen::Vector4f> host_vectors; + std::vector<Eigen::Matrix4f> host_matrices; + + Eigen::Matrix4f matrix; + matrix << 1, 2, 0, 3, + 2, 1, 2, 0, + 0, 3, 1, 2, + 2, 0, 2, 1; + + host_vectors.push_back(Eigen::Vector4f(1, 2, 3, 4)); + host_vectors.push_back(Eigen::Vector4f(4, 3, 2, 1)); + host_vectors.push_back(Eigen::Vector4f(1, 2, 3, 4)); + host_vectors.push_back(Eigen::Vector4f(4, 3, 2, 1)); + + // store the eigen 4x4 matrix as a float16 + bcl::float16_ M = + bcl::eigen_matrix4f_to_float16(matrix); + + // returns the result of M*x + BOOST_COMPUTE_CLOSURE(Eigen::Vector4f, transform4x4, (const Eigen::Vector4f x), (M), + { + float4 r; + r.x = dot(M.s048c, x); + r.y = dot(M.s159d, x); + r.z = dot(M.s26ae, x); + r.w = dot(M.s37bf, x); + return r; + }); + + bcl::vector<Eigen::Vector4f> vectors(4, context); + bcl::vector<Eigen::Vector4f> results(4, context); + + bcl::copy(host_vectors.begin(), host_vectors.end(), vectors.begin(), queue); + + bcl::transform( + vectors.begin(), vectors.end(), results.begin(), transform4x4, queue + ); + + std::vector<Eigen::Vector4f> host_results(4); + bcl::copy(results.begin(), results.end(), host_results.begin(), queue); + + BOOST_CHECK((matrix * host_vectors[0]) == host_results[0]); + BOOST_CHECK((matrix * host_vectors[1]) == host_results[1]); + BOOST_CHECK((matrix * host_vectors[2]) == host_results[2]); + BOOST_CHECK((matrix * host_vectors[3]) == host_results[3]); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/extra/test_interop_opencv.cpp b/src/boost/libs/compute/test/extra/test_interop_opencv.cpp new file mode 100644 index 00000000..4d959360 --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_interop_opencv.cpp @@ -0,0 +1,105 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInteropOpenCV +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/interop/opencv.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bcl = boost::compute; + +BOOST_AUTO_TEST_CASE(opencv_mat_to_buffer) +{ + // create opencv mat + cv::Mat mat(1, 4, CV_32F); + mat.at<float>(0, 0) = 0.0f; + mat.at<float>(0, 1) = 2.5f; + mat.at<float>(0, 2) = 4.1f; + mat.at<float>(0, 3) = 5.6f; + + // copy mat to gpu vector + bcl::vector<float> vector(4, context); + bcl::opencv_copy_mat_to_buffer(mat, vector.begin(), queue); + CHECK_RANGE_EQUAL(float, 4, vector, (0.0f, 2.5f, 4.1f, 5.6f)); + + // reverse gpu vector and copy back to mat + bcl::reverse(vector.begin(), vector.end(), queue); + bcl::opencv_copy_buffer_to_mat(vector.begin(), mat, queue); + BOOST_CHECK_EQUAL(mat.at<float>(0), 5.6f); + BOOST_CHECK_EQUAL(mat.at<float>(1), 4.1f); + BOOST_CHECK_EQUAL(mat.at<float>(2), 2.5f); + BOOST_CHECK_EQUAL(mat.at<float>(3), 0.0f); +} + +BOOST_AUTO_TEST_CASE(opencv_image_format) +{ + // 8-bit uchar BGRA + BOOST_CHECK( + bcl::opencv_get_mat_image_format(cv::Mat(32, 32, CV_8UC4)) == + bcl::image_format(CL_BGRA, CL_UNORM_INT8) + ); + + // 32-bit float + BOOST_CHECK( + bcl::opencv_get_mat_image_format(cv::Mat(32, 32, CV_32F)) == + bcl::image_format(CL_INTENSITY, CL_FLOAT) + ); + + // 32-bit float RGBA + BOOST_CHECK( + bcl::opencv_get_mat_image_format(cv::Mat(32, 32, CV_32FC4)) == + bcl::image_format(CL_RGBA, CL_FLOAT) + ); + + // 16-bit uchar BGRA + BOOST_CHECK( + bcl::opencv_get_mat_image_format(cv::Mat(32, 32, CV_16UC4)) == + bcl::image_format(CL_BGRA, CL_UNORM_INT16) + ); + + // 8-bit uchar + BOOST_CHECK( + bcl::opencv_get_mat_image_format(cv::Mat(32, 32, CV_8UC1)) == + bcl::image_format(CL_INTENSITY, CL_UNORM_INT8) + ); +} + +BOOST_AUTO_TEST_CASE(opencv_float_mat_image2d) +{ + REQUIRES_OPENCL_VERSION(1,2); + + cv::Vec4f pixel; + // create opencv mat + cv::Mat mat(2, 2, CV_32FC4, cv::Scalar(100, 150, 200, 255)); + // transfer image to gpu + bcl::image2d image = + bcl::opencv_create_image2d_with_mat( + mat, + bcl::image2d::read_only, + queue + ); + // copy the data back to cpu + bcl::opencv_copy_image_to_mat(image, mat, queue); + + pixel = mat.at<cv::Vec4f>(1,1); + BOOST_CHECK_EQUAL(pixel[0], 100.0f); + BOOST_CHECK_EQUAL(pixel[1], 150.0f); + BOOST_CHECK_EQUAL(pixel[2], 200.0f); + BOOST_CHECK_EQUAL(pixel[3], 255.0f); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/extra/test_interop_opengl.cpp b/src/boost/libs/compute/test/extra/test_interop_opengl.cpp new file mode 100644 index 00000000..876abfab --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_interop_opengl.cpp @@ -0,0 +1,28 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInteropOpenGL +#include <boost/test/unit_test.hpp> + +#include <boost/compute/interop/opengl.hpp> + +BOOST_AUTO_TEST_CASE(opengl_buffer) +{ +} + +BOOST_AUTO_TEST_CASE(type_name) +{ + BOOST_CHECK_EQUAL( + boost::compute::type_name<boost::compute::opengl_texture>(), "image2d_t" + ); + BOOST_CHECK_EQUAL( + boost::compute::type_name<boost::compute::opengl_renderbuffer>(), "image2d_t" + ); +} diff --git a/src/boost/libs/compute/test/extra/test_interop_qt.cpp b/src/boost/libs/compute/test/extra/test_interop_qt.cpp new file mode 100644 index 00000000..a07f44fb --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_interop_qt.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInteropQt +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/detail/is_contiguous_iterator.hpp> +#include <boost/compute/interop/qt.hpp> + +#include <QList> +#include <QVector> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bcl = boost::compute; + +BOOST_AUTO_TEST_CASE(qimage_format) +{ + BOOST_CHECK( + bcl::qt_qimage_format_to_image_format(QImage::Format_RGB32) == + bcl::image_format(CL_BGRA, CL_UNORM_INT8) + ); +} + +BOOST_AUTO_TEST_CASE(copy_qvector_to_device) +{ + QList<int> qvector; + qvector.append(0); + qvector.append(2); + qvector.append(4); + qvector.append(6); + + bcl::vector<int> vector(4, context); + bcl::copy(qvector.begin(), qvector.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, vector, (0, 2, 4, 6)); +} + +BOOST_AUTO_TEST_CASE(copy_qlist_to_device) +{ + QList<int> list; + list.append(1); + list.append(3); + list.append(5); + list.append(7); + + bcl::vector<int> vector(4, context); + bcl::copy(list.begin(), list.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, vector, (1, 3, 5, 7)); +} + +BOOST_AUTO_TEST_CASE(qvector_of_qpoint) +{ + QVector<QPoint> qt_points; + qt_points.append(QPoint(0, 1)); + qt_points.append(QPoint(2, 3)); + qt_points.append(QPoint(4, 5)); + qt_points.append(QPoint(6, 7)); + + bcl::vector<QPoint> bcl_points(qt_points.size(), context); + bcl::copy(qt_points.begin(), qt_points.end(), bcl_points.begin(), queue); +} + +BOOST_AUTO_TEST_CASE(qvector_of_qpointf) +{ + QVector<QPointF> qt_points; + qt_points.append(QPointF(0.3f, 1.7f)); + qt_points.append(QPointF(2.3f, 3.7f)); + qt_points.append(QPointF(4.3f, 5.7f)); + qt_points.append(QPointF(6.3f, 7.7f)); + + bcl::vector<QPointF> bcl_points(qt_points.size(), context); + bcl::copy(qt_points.begin(), qt_points.end(), bcl_points.begin(), queue); +} + +BOOST_AUTO_TEST_CASE(qvector_iterator) +{ + using boost::compute::detail::is_contiguous_iterator; + + BOOST_STATIC_ASSERT(is_contiguous_iterator<QVector<int>::iterator>::value == true); + BOOST_STATIC_ASSERT(is_contiguous_iterator<QVector<int>::const_iterator>::value == true); + BOOST_STATIC_ASSERT(is_contiguous_iterator<QList<int>::iterator>::value == false); + BOOST_STATIC_ASSERT(is_contiguous_iterator<QList<int>::const_iterator>::value == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/extra/test_interop_vtk.cpp b/src/boost/libs/compute/test/extra/test_interop_vtk.cpp new file mode 100644 index 00000000..ca98790f --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_interop_vtk.cpp @@ -0,0 +1,118 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInteropVTK +#include <boost/test/unit_test.hpp> + +#include <vtkFloatArray.h> +#include <vtkMatrix4x4.h> +#include <vtkNew.h> +#include <vtkPoints.h> +#include <vtkSmartPointer.h> +#include <vtkUnsignedCharArray.h> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/detail/is_contiguous_iterator.hpp> +#include <boost/compute/interop/vtk.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(bounds) +{ + using compute::float4_; + + // create vtk points + vtkNew<vtkPoints> points; + points->InsertNextPoint(0.0, 0.0, 0.0); + points->InsertNextPoint(1.0, 2.0, 1.0); + points->InsertNextPoint(-1.0, -3.0, -1.0); + points->InsertNextPoint(0.5, 2.5, 1.5); + + // copy points to vector on gpu + compute::vector<float4_> vector(points->GetNumberOfPoints(), context); + compute::vtk_copy_points_to_buffer(points.GetPointer(), vector.begin(), queue); + + // compute bounds + double bounds[6]; + compute::vtk_compute_bounds(vector.begin(), vector.end(), bounds, queue); + + // check bounds + BOOST_CHECK_CLOSE(bounds[0], -1.0, 1e-8); + BOOST_CHECK_CLOSE(bounds[1], 1.0, 1e-8); + BOOST_CHECK_CLOSE(bounds[2], -3.0, 1e-8); + BOOST_CHECK_CLOSE(bounds[3], 2.5, 1e-8); + BOOST_CHECK_CLOSE(bounds[4], -1.0, 1e-8); + BOOST_CHECK_CLOSE(bounds[5], 1.5, 1e-8); +} + +BOOST_AUTO_TEST_CASE(copy_uchar_array) +{ + // create vtk uchar vector containing 3 RGBA colors + vtkNew<vtkUnsignedCharArray> array; + array->SetNumberOfComponents(4); + + unsigned char red[4] = { 255, 0, 0, 255 }; + array->InsertNextTupleValue(red); + unsigned char green[4] = { 0, 255, 0, 255 }; + array->InsertNextTupleValue(green); + unsigned char blue[4] = { 0, 0, 255, 255 }; + array->InsertNextTupleValue(blue); + + // create vector<uchar4> on device and copy values from vtk array + compute::vector<compute::uchar4_> vector(3, context); + compute::vtk_copy_data_array_to_buffer( + array.GetPointer(), + compute::make_buffer_iterator<compute::uchar_>(vector.get_buffer(), 0), + queue + ); + + // check values + std::vector<compute::uchar4_> host_vector(3); + compute::copy( + vector.begin(), vector.end(), host_vector.begin(), queue + ); + BOOST_CHECK(host_vector[0] == compute::uchar4_(255, 0, 0, 255)); + BOOST_CHECK(host_vector[1] == compute::uchar4_(0, 255, 0, 255)); + BOOST_CHECK(host_vector[2] == compute::uchar4_(0, 0, 255, 255)); +} + +BOOST_AUTO_TEST_CASE(sort_float_array) +{ + // create vtk float array + vtkNew<vtkFloatArray> array; + array->InsertNextValue(2.5f); + array->InsertNextValue(1.0f); + array->InsertNextValue(6.5f); + array->InsertNextValue(4.0f); + + // create vector on device and copy values from vtk array + compute::vector<float> vector(4, context); + compute::vtk_copy_data_array_to_buffer(array.GetPointer(), vector.begin(), queue); + + // sort values on the gpu + compute::sort(vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(float, 4, vector, (1.0f, 2.5f, 4.0f, 6.5f)); + + // copy sorted values back to the vtk array + compute::vtk_copy_buffer_to_data_array( + vector.begin(), vector.end(), array.GetPointer(), queue + ); + BOOST_CHECK_EQUAL(array->GetValue(0), 1.0f); + BOOST_CHECK_EQUAL(array->GetValue(1), 2.5f); + BOOST_CHECK_EQUAL(array->GetValue(2), 4.0f); + BOOST_CHECK_EQUAL(array->GetValue(3), 6.5f); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/extra/test_multiple_objects1.cpp b/src/boost/libs/compute/test/extra/test_multiple_objects1.cpp new file mode 100644 index 00000000..af80d7c1 --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_multiple_objects1.cpp @@ -0,0 +1,21 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMultipleObjects +#include <boost/test/unit_test.hpp> +#include <boost/compute.hpp> + +bool dummy_function(); + +BOOST_AUTO_TEST_CASE(multiple_objects) +{ + // It is enough if the test compiles. + BOOST_CHECK( dummy_function() ); +} diff --git a/src/boost/libs/compute/test/extra/test_multiple_objects2.cpp b/src/boost/libs/compute/test/extra/test_multiple_objects2.cpp new file mode 100644 index 00000000..8beb8b98 --- /dev/null +++ b/src/boost/libs/compute/test/extra/test_multiple_objects2.cpp @@ -0,0 +1,15 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#include <boost/compute.hpp> + +bool dummy_function() { + return true; +} diff --git a/src/boost/libs/compute/test/opencl_version_check.hpp b/src/boost/libs/compute/test/opencl_version_check.hpp new file mode 100644 index 00000000..2c7ad68a --- /dev/null +++ b/src/boost/libs/compute/test/opencl_version_check.hpp @@ -0,0 +1,20 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Denis Demidov +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_TEST_OPENCL_VERSION_CHECK_HPP +#define BOOST_COMPUTE_TEST_OPENCL_VERSION_CHECK_HPP + +#define REQUIRES_OPENCL_VERSION(major, minor) \ + if (!device.check_version(major, minor)) return + +#define REQUIRES_OPENCL_PLATFORM_VERSION(major, minor) \ + if (!device.platform().check_version(major, minor)) return + +#endif diff --git a/src/boost/libs/compute/test/quirks.hpp b/src/boost/libs/compute/test/quirks.hpp new file mode 100644 index 00000000..adffeb1f --- /dev/null +++ b/src/boost/libs/compute/test/quirks.hpp @@ -0,0 +1,128 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_TEST_QUIRKS_HPP +#define BOOST_COMPUTE_TEST_QUIRKS_HPP + +#include <boost/compute/device.hpp> +#include <boost/compute/platform.hpp> +#include <boost/compute/detail/vendor.hpp> + +// this file contains functions which check for 'quirks' or buggy +// behavior in OpenCL implementations. this allows us to skip certain +// tests when running on buggy platforms. + +// returns true if the device is a POCL device +inline bool is_pocl_device(const boost::compute::device &device) +{ + return device.platform().name() == "Portable Computing Language"; +} + +// returns true if the device is from Apple OpenCL platform +inline bool is_apple_device(const boost::compute::device &device) +{ + return device.platform().name() == "Apple"; +} + +// AMD platforms have a bug when using struct assignment. this affects +// algorithms like fill() when used with pairs/tuples. +// +// see: https://community.amd.com/thread/166622 +inline bool bug_in_struct_assignment(const boost::compute::device &device) +{ + return boost::compute::detail::is_amd_device(device); +} + +// clEnqueueSVMMemcpy() operation does not work on AMD devices. This affects +// copy() algorithm. This bug was fixed in AMD drivers for Windows. +// +// see: https://community.amd.com/thread/190585 +inline bool bug_in_svmmemcpy(const boost::compute::device &device) +{ + #ifdef _WIN32 + return false; + #else + return boost::compute::detail::is_amd_device(device); + #endif +} + +// For CPU devices on Apple platform local memory can not be used when work +// group size is not [1;1;1]. If work group size is greater "Invalid Work Group +// Size" error is thrown. (Apple OpenCL implementation can sometimes reduce +// max work group size for other reasons.) +// When local memory is not used max work group size for CPU devices on Apple +// platform should be [1024;1;1]. +inline bool is_apple_cpu_device(const boost::compute::device &device) +{ + return is_apple_device(device) && (device.type() & ::boost::compute::device::cpu); +} + +// On Apple devices clCreateBuffer does not return NULL and does no set error +// to CL_INVALID_BUFFER_SIZE when size of the buffer memory object is greater +// than CL_DEVICE_MAX_MEM_ALLOC_SIZE. +inline bool bug_in_clcreatebuffer(const boost::compute::device &device) +{ + return is_apple_device(device); +} + +// returns true if the device supports image samplers. +inline bool supports_image_samplers(const boost::compute::device &device) +{ + // POCL does not yet support image samplers and gives the following + // error when attempting to create one: + // + // pocl error: encountered unimplemented part of the OpenCL specs + // in clCreateSampler.c:28 + if(is_pocl_device(device)){ + return false; + } + + return true; +} + +// returns true if the device has remquo() built-in OpenCL function implementation +inline bool has_remquo_func(const boost::compute::device &device) +{ + // POCL does not have it + if(is_pocl_device(device)){ + return false; + } + return true; +} + +// returns true if the device supports clSetMemObjectDestructorCallback +inline bool supports_destructor_callback(const boost::compute::device &device) +{ + // unimplemented in POCL + return !is_pocl_device(device); +} + +// returns true if the device supports clCompileProgram +inline bool supports_compile_program(const boost::compute::device &device) +{ + // unimplemented in POCL + return !is_pocl_device(device); +} + +// returns true if the device supports clLinkProgram +inline bool supports_link_program(const boost::compute::device &device) +{ + // unimplemented in POCL + return !is_pocl_device(device); +} + +// See https://github.com/pocl/pocl/issues/577, POCL fails when a program +// with incorrect code is built for the 2nd time +inline bool pocl_bug_issue_577(const boost::compute::device &device) +{ + return is_pocl_device(device); +} + +#endif // BOOST_COMPUTE_TEST_QUIRKS_HPP diff --git a/src/boost/libs/compute/test/test_accumulate.cpp b/src/boost/libs/compute/test/test_accumulate.cpp new file mode 100644 index 00000000..b77c07df --- /dev/null +++ b/src/boost/libs/compute/test/test_accumulate.cpp @@ -0,0 +1,302 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAccumulate +#include <boost/test/unit_test.hpp> + +#include <numeric> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/accumulate.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/container/mapped_view.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(sum_int) +{ + int data[] = { 2, 4, 6, 8 }; + boost::compute::vector<int> vector(data, data + 4, queue); + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 0, queue), + 20 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), -10, queue), + 10 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 5, queue), + 25 + ); +} + +BOOST_AUTO_TEST_CASE(product_int) +{ + int data[] = { 2, 4, 6, 8 }; + boost::compute::vector<int> vector(data, data + 4, queue); + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + vector.begin(), vector.end(), 1, boost::compute::multiplies<int>(), + queue), + 384 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + vector.begin(), vector.end(), -1, boost::compute::multiplies<int>(), + queue), + -384 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + vector.begin(), vector.end(), 2, boost::compute::multiplies<int>(), + queue), + 768 + ); +} + +BOOST_AUTO_TEST_CASE(quotient_int) +{ + int data[] = { 2, 8, 16 }; + boost::compute::vector<int> vector(data, data + 3, queue); + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + vector.begin(), + vector.end(), + 1024, + boost::compute::divides<int>(), + queue + ), + 4 + ); +} + +BOOST_AUTO_TEST_CASE(sum_counting_iterator) +{ + // sum 0 -> 9 + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + boost::compute::make_counting_iterator(0), + boost::compute::make_counting_iterator(10), + 0, + boost::compute::plus<int>(), + queue + ), + 45 + ); + + // sum 0 -> 9 + 7 + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + boost::compute::make_counting_iterator(0), + boost::compute::make_counting_iterator(10), + 7, + boost::compute::plus<int>(), + queue + ), + 52 + ); + + // sum 15 -> 24 + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + boost::compute::make_counting_iterator(15), + boost::compute::make_counting_iterator(25), + 0, + boost::compute::plus<int>(), + queue + ), + 195 + ); + + // sum -5 -> 10 + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + boost::compute::make_counting_iterator(-5), + boost::compute::make_counting_iterator(10), + 0, + boost::compute::plus<int>(), + queue + ), + 30 + ); + + // sum -5 -> 10 - 2 + BOOST_CHECK_EQUAL( + boost::compute::accumulate( + boost::compute::make_counting_iterator(-5), + boost::compute::make_counting_iterator(10), + -2, + boost::compute::plus<int>(), + queue + ), + 28 + ); +} + +BOOST_AUTO_TEST_CASE(sum_iota) +{ + // size 0 + boost::compute::vector<int> vector(0, context); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 0, queue), + 0 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 4, queue), + 4 + ); + + // size 50 + vector.resize(50); + boost::compute::iota(vector.begin(), vector.end(), 0, queue); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 0, queue), + 1225 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 11, queue), + 1236 + ); + + // size 1000 + vector.resize(1000); + boost::compute::iota(vector.begin(), vector.end(), 0, queue); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 0, queue), + 499500 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), -45, queue), + 499455 + ); + + // size 1025 + vector.resize(1025); + boost::compute::iota(vector.begin(), vector.end(), 0, queue); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 0, queue), + 524800 + ); + + BOOST_CHECK_EQUAL( + boost::compute::accumulate(vector.begin(), vector.end(), 2, queue), + 524802 + ); +} + +BOOST_AUTO_TEST_CASE(min_and_max) +{ + using boost::compute::int2_; + + int data[] = { 5, 3, 1, 6, 4, 2 }; + boost::compute::vector<int> vector(data, data + 6, queue); + + BOOST_COMPUTE_FUNCTION(int2_, min_and_max, (int2_ accumulator, const int value), + { + return (int2)((min)(accumulator.x, value), (max)(accumulator.y, value)); + }); + + int2_ result = boost::compute::accumulate( + vector.begin(), vector.end(), int2_(100, -100), min_and_max, queue + ); + BOOST_CHECK_EQUAL(result[0], 1); + BOOST_CHECK_EQUAL(result[1], 6); +} + +BOOST_AUTO_TEST_CASE(min_max) +{ + float data[] = { 1.2f, 5.5f, 0.1f, 9.6f, 4.2f, 6.7f, 9.0f, 3.4f }; + boost::compute::vector<float> vec(data, data + 8, queue); + + using ::boost::compute::min; + using ::boost::compute::max; + + float min_value = boost::compute::accumulate( + vec.begin(), vec.end(), (std::numeric_limits<float>::max)(), min<float>(), queue + ); + BOOST_CHECK_EQUAL(min_value, 0.1f); + + float max_value = boost::compute::accumulate( + vec.begin(), vec.end(), (std::numeric_limits<float>::min)(), max<float>(), queue + ); + BOOST_CHECK_EQUAL(max_value, 9.6f); + + // find min with init less than any value in the array + min_value = boost::compute::accumulate( + vec.begin(), vec.end(), -1.f, min<float>(), queue + ); + BOOST_CHECK_EQUAL(min_value, -1.f); + + // find max with init greater than any value in the array + max_value = boost::compute::accumulate( + vec.begin(), vec.end(), 10.f, max<float>(), queue + ); + BOOST_CHECK_EQUAL(max_value, 10.f); +} + +template<class T> +void ensure_std_accumulate_equality(const std::vector<T> &data, + boost::compute::command_queue &queue) +{ + boost::compute::mapped_view<T> view(&data[0], data.size(), queue.get_context()); + + BOOST_CHECK_EQUAL( + std::accumulate(data.begin(), data.end(), 0), + boost::compute::accumulate(view.begin(), view.end(), 0, queue) + ); +} + +BOOST_AUTO_TEST_CASE(std_accumulate_equality) +{ + // test accumulate() with int + int data1[] = { 1, 2, 3, 4 }; + std::vector<int> vec1(data1, data1 + 4); + ensure_std_accumulate_equality(vec1, queue); + + vec1.resize(10000); + std::fill(vec1.begin(), vec1.end(), 2); + ensure_std_accumulate_equality(vec1, queue); + + // test accumulate() with float + float data2[] = { 1.2f, 2.3f, 4.5f, 6.7f, 8.9f }; + std::vector<float> vec2(data2, data2 + 5); + ensure_std_accumulate_equality(vec2, queue); + + vec2.resize(10000); + std::fill(vec2.begin(), vec2.end(), 1.01f); + ensure_std_accumulate_equality(vec2, queue); + + // test accumulate() with double + if(device.supports_extension("cl_khr_fp64")){ + double data3[] = { 1.2, 2.3, 4.5, 6.7, 8.9 }; + std::vector<double> vec3(data3, data3 + 5); + ensure_std_accumulate_equality(vec3, queue); + + vec3.resize(10000); + std::fill(vec3.begin(), vec3.end(), 2.02); + ensure_std_accumulate_equality(vec3, queue); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_adjacent_difference.cpp b/src/boost/libs/compute/test/test_adjacent_difference.cpp new file mode 100644 index 00000000..0fca4dab --- /dev/null +++ b/src/boost/libs/compute/test/test_adjacent_difference.cpp @@ -0,0 +1,102 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAdjacentDifference +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/all_of.hpp> +#include <boost/compute/algorithm/adjacent_difference.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(adjacent_difference_int) +{ + using compute::int_; + + compute::vector<int_> a(5, context); + compute::iota(a.begin(), a.end(), 0, queue); + CHECK_RANGE_EQUAL(int_, 5, a, (0, 1, 2, 3, 4)); + + compute::vector<int_> b(5, context); + compute::vector<int_>::iterator iter = + compute::adjacent_difference(a.begin(), a.end(), b.begin(), queue); + BOOST_CHECK(iter == b.end()); + CHECK_RANGE_EQUAL(int_, 5, b, (0, 1, 1, 1, 1)); + + int_ data[] = { 1, 9, 36, 48, 81 }; + compute::copy(data, data + 5, a.begin(), queue); + CHECK_RANGE_EQUAL(int_, 5, a, (1, 9, 36, 48, 81)); + + iter = compute::adjacent_difference(a.begin(), a.end(), b.begin(), queue); + BOOST_CHECK(iter == b.end()); + CHECK_RANGE_EQUAL(int_, 5, b, (1, 8, 27, 12, 33)); +} + +BOOST_AUTO_TEST_CASE(adjacent_difference_first_eq_last) +{ + using compute::int_; + + compute::vector<int_> a(size_t(5), int_(1), queue); + compute::vector<int_> b(size_t(5), int_(0), queue); + compute::vector<int_>::iterator iter = + compute::adjacent_difference(a.begin(), a.begin(), b.begin(), queue); + BOOST_CHECK(iter == b.begin()); + CHECK_RANGE_EQUAL(int_, 5, b, (0, 0, 0, 0, 0)); +} + +BOOST_AUTO_TEST_CASE(adjacent_difference_first_eq_result) +{ + using compute::int_; + + compute::vector<int_> a(5, context); + compute::iota(a.begin(), a.end(), 0, queue); + CHECK_RANGE_EQUAL(int_, 5, a, (0, 1, 2, 3, 4)); + + compute::vector<int_>::iterator iter = + compute::adjacent_difference(a.begin(), a.end(), a.begin(), queue); + BOOST_CHECK(iter == a.end()); + CHECK_RANGE_EQUAL(int_, 5, a, (0, 1, 1, 1, 1)); +} + +BOOST_AUTO_TEST_CASE(all_same) +{ + using compute::int_; + + compute::vector<int_> input(1000, context); + compute::fill(input.begin(), input.end(), 42, queue); + + compute::vector<int_> output(input.size(), context); + + compute::adjacent_difference( + input.begin(), input.end(), output.begin(), queue + ); + + int_ first; + compute::copy_n(output.begin(), 1, &first, queue); + BOOST_CHECK_EQUAL(first, 42); + + using compute::lambda::_1; + + BOOST_CHECK( + compute::all_of(output.begin() + 1, output.end(), _1 == 0, queue) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_adjacent_find.cpp b/src/boost/libs/compute/test/test_adjacent_find.cpp new file mode 100644 index 00000000..bfb864e4 --- /dev/null +++ b/src/boost/libs/compute/test/test_adjacent_find.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAdjacentFind +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/adjacent_find.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(adjacent_find_int) +{ + int data[] = { 1, 3, 5, 5, 6, 7, 7, 8 }; + compute::vector<int> vec(data, data + 8, queue); + + compute::vector<int>::iterator iter = + compute::adjacent_find(vec.begin(), vec.end(), queue); + BOOST_CHECK(iter == vec.begin() + 2); +} + +BOOST_AUTO_TEST_CASE(adjacent_find_int2) +{ + using compute::int2_; + + compute::vector<int2_> vec(context); + vec.push_back(int2_(1, 2), queue); + vec.push_back(int2_(3, 4), queue); + vec.push_back(int2_(5, 6), queue); + vec.push_back(int2_(7, 8), queue); + vec.push_back(int2_(7, 8), queue); + + compute::vector<int2_>::iterator iter = + compute::adjacent_find(vec.begin(), vec.end(), queue); + BOOST_CHECK(iter == vec.begin() + 3); +} + +BOOST_AUTO_TEST_CASE(adjacent_find_iota) +{ + compute::vector<int> vec(2048, context); + compute::iota(vec.begin(), vec.end(), 1, queue); + BOOST_VERIFY( + compute::adjacent_find(vec.begin(), vec.end(), queue) == vec.end() + ); +} + +BOOST_AUTO_TEST_CASE(adjacent_find_fill) +{ + compute::vector<int> vec(2048, context); + compute::fill(vec.begin(), vec.end(), 7, queue); + BOOST_VERIFY( + compute::adjacent_find(vec.begin(), vec.end(), queue) == vec.begin() + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_amd_cpp_kernel_language.cpp b/src/boost/libs/compute/test/test_amd_cpp_kernel_language.cpp new file mode 100644 index 00000000..4a3c31f8 --- /dev/null +++ b/src/boost/libs/compute/test/test_amd_cpp_kernel_language.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAmdCppKernel +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/kernel.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/detail/vendor.hpp> +#include <boost/compute/utility/source.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(amd_template_function) +{ + if(!compute::detail::is_amd_device(device)){ + std::cerr << "skipping amd_template_function test: c++ static kernel " + "language is only supported on AMD devices." << std::endl; + return; + } + + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + template<typename T> + inline T square(const T x) + { + return x * x; + } + + template<typename T> + __kernel void square_kernel(__global T *data) + { + const uint i = get_global_id(0); + data[i] = square(data[i]); + } + + template __attribute__((mangled_name(square_kernel_int))) + __kernel void square_kernel(__global int *data); + ); + + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vec(data, data + 4, queue); + + compute::program square_program = + compute::program::build_with_source(source, context, "-x clc++"); + + compute::kernel square_kernel(square_program, "square_kernel_int"); + square_kernel.set_arg(0, vec); + + queue.enqueue_1d_range_kernel(square_kernel, 0, vec.size(), 4); + + CHECK_RANGE_EQUAL(int, 4, vec, (1, 4, 9, 16)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_any_all_none_of.cpp b/src/boost/libs/compute/test/test_any_all_none_of.cpp new file mode 100644 index 00000000..29391af3 --- /dev/null +++ b/src/boost/libs/compute/test/test_any_all_none_of.cpp @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAnyAllNoneOf +#include <boost/test/unit_test.hpp> + +#include <limits> +#include <cmath> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/all_of.hpp> +#include <boost/compute/algorithm/any_of.hpp> +#include <boost/compute/algorithm/none_of.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(any_all_none_of) +{ + int data[] = { 1, 2, 3, 4, 5, 6 }; + bc::vector<int> v(data, data + 6, queue); + + using ::boost::compute::_1; + + BOOST_CHECK(bc::any_of(v.begin(), v.end(), _1 == 6) == true); + BOOST_CHECK(bc::any_of(v.begin(), v.end(), _1 == 9) == false); + BOOST_CHECK(bc::none_of(v.begin(), v.end(), _1 == 6) == false); + BOOST_CHECK(bc::none_of(v.begin(), v.end(), _1 == 9) == true); + BOOST_CHECK(bc::all_of(v.begin(), v.end(), _1 == 6) == false); + BOOST_CHECK(bc::all_of(v.begin(), v.end(), _1 < 9) == true); + BOOST_CHECK(bc::all_of(v.begin(), v.end(), _1 < 6) == false); + BOOST_CHECK(bc::all_of(v.begin(), v.end(), _1 >= 1) == true); +} + +BOOST_AUTO_TEST_CASE(any_nan_inf) +{ + using ::boost::compute::_1; + using ::boost::compute::lambda::isinf; + using ::boost::compute::lambda::isnan; + using ::boost::compute::lambda::isfinite; + + float nan = std::sqrt(-1.f); + float inf = std::numeric_limits<float>::infinity(); + + float data[] = { 1.2f, 2.3f, nan, nan, 3.4f, inf, 4.5f, inf }; + compute::vector<float> vector(data, data + 8, queue); + + BOOST_CHECK(compute::any_of(vector.begin(), vector.end(), + isinf(_1) || isnan(_1), queue) == true); + BOOST_CHECK(compute::any_of(vector.begin(), vector.end(), + isfinite(_1), queue) == true); + BOOST_CHECK(compute::all_of(vector.begin(), vector.end(), + isfinite(_1), queue) == false); + BOOST_CHECK(compute::all_of(vector.begin(), vector.begin() + 2, + isfinite(_1), queue) == true); + BOOST_CHECK(compute::all_of(vector.begin() + 2, vector.begin() + 4, + isnan(_1), queue) == true); + BOOST_CHECK(compute::none_of(vector.begin(), vector.end(), + isinf(_1), queue) == false); + BOOST_CHECK(compute::none_of(vector.begin(), vector.begin() + 4, + isinf(_1), queue) == true); +} + +BOOST_AUTO_TEST_CASE(any_of_doctest) +{ + using boost::compute::lambda::_1; + + int data[] = { 1, 2, 3, 4 }; + boost::compute::vector<int> v(data, data + 4, queue); + + bool result = +//! [any_of] +boost::compute::any_of(v.begin(), v.end(), _1 < 0, queue); +//! [any_of] + + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_array.cpp b/src/boost/libs/compute/test/test_array.cpp new file mode 100644 index 00000000..7b203f76 --- /dev/null +++ b/src/boost/libs/compute/test/test_array.cpp @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestArray +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/array.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(concept_check) +{ + BOOST_CONCEPT_ASSERT((boost::Container<boost::compute::array<int, 3> >)); +// BOOST_CONCEPT_ASSERT((boost::SequenceConcept<boost::compute::array<int, 3> >)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<boost::compute::array<int, 3>::iterator>)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<boost::compute::array<int, 3>::const_iterator>)); +} + +BOOST_AUTO_TEST_CASE(size) +{ + boost::compute::array<int, 0> empty_array(context); + BOOST_CHECK_EQUAL(empty_array.size(), size_t(0)); + + boost::compute::array<int, 10> array10(context); + BOOST_CHECK_EQUAL(array10.size(), size_t(10)); +} + +BOOST_AUTO_TEST_CASE(at) +{ + boost::compute::array<int, 3> array(context); + array[0] = 3; + array[1] = -2; + array[2] = 5; + BOOST_CHECK_EQUAL(array.at(0), 3); + BOOST_CHECK_EQUAL(array.at(1), -2); + BOOST_CHECK_EQUAL(array.at(2), 5); + BOOST_CHECK_THROW(array.at(3), std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(copy_from_vector) +{ + int data[] = { 3, 6, 9, 12 }; + boost::compute::vector<int> vector(data, data + 4, queue); + + boost::compute::array<int, 4> array(context); + boost::compute::copy(vector.begin(), vector.end(), array.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, array, (3, 6, 9, 12)); +} + +BOOST_AUTO_TEST_CASE(fill) +{ + boost::compute::array<int, 4> array(context); + array.fill(0); + CHECK_RANGE_EQUAL(int, 4, array, (0, 0, 0, 0)); + + array.fill(17); + CHECK_RANGE_EQUAL(int, 4, array, (17, 17, 17, 17)); +} + +BOOST_AUTO_TEST_CASE(swap) +{ + int data[] = { 1, 2, 6, 9 }; + boost::compute::array<int, 4> a(context); + boost::compute::copy(data, data + 4, a.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 6, 9)); + + boost::compute::array<int, 4> b(context); + b.fill(3); + CHECK_RANGE_EQUAL(int, 4, b, (3, 3, 3, 3)); + + a.swap(b); + CHECK_RANGE_EQUAL(int, 4, a, (3, 3, 3, 3)); + CHECK_RANGE_EQUAL(int, 4, b, (1, 2, 6, 9)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_async_wait.cpp b/src/boost/libs/compute/test/test_async_wait.cpp new file mode 100644 index 00000000..0b9eebab --- /dev/null +++ b/src/boost/libs/compute/test/test_async_wait.cpp @@ -0,0 +1,72 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAsyncWait +#include <boost/test/unit_test.hpp> + +#include <boost/compute/async/future.hpp> +#include <boost/compute/async/wait.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(empty) +{ +} + +#ifndef BOOST_COMPUTE_NO_VARIADIC_TEMPLATES +BOOST_AUTO_TEST_CASE(wait_for_copy) +{ + // wait list + compute::wait_list events; + + // create host data array + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + // create vector on the device + compute::vector<int> vector(8, context); + + // fill vector with 9's + compute::future<void> fill_future = + compute::fill_async(vector.begin(), vector.end(), 9, queue); + + // wait for fill() to complete + compute::wait_for_all(fill_future); + + // check data on the device + CHECK_RANGE_EQUAL(int, 8, vector, (9, 9, 9, 9, 9, 9, 9, 9)); + + // copy each pair of values independently and asynchronously + compute::event copy1 = queue.enqueue_write_buffer_async( + vector.get_buffer(), 0 * sizeof(int), 2 * sizeof(int), data + 0 + ); + compute::event copy2 = queue.enqueue_write_buffer_async( + vector.get_buffer(), 2 * sizeof(int), 2 * sizeof(int), data + 2 + ); + compute::event copy3 = queue.enqueue_write_buffer_async( + vector.get_buffer(), 4 * sizeof(int), 2 * sizeof(int), data + 4 + ); + compute::event copy4 = queue.enqueue_write_buffer_async( + vector.get_buffer(), 6 * sizeof(int), 2 * sizeof(int), data + 6 + ); + + // wait for all copies to complete + compute::wait_for_all(copy1, copy2, copy3, copy4); + + // check data on the device + CHECK_RANGE_EQUAL(int, 8, vector, (1, 2, 3, 4, 5, 6, 7, 8)); +} +#endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_async_wait_guard.cpp b/src/boost/libs/compute/test/test_async_wait_guard.cpp new file mode 100644 index 00000000..626d25bb --- /dev/null +++ b/src/boost/libs/compute/test/test_async_wait_guard.cpp @@ -0,0 +1,51 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestAsyncWaitGuard +#include <boost/test/unit_test.hpp> + +#include <boost/compute/async/future.hpp> +#include <boost/compute/async/wait_guard.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +static size_t wait_num = 0; + +struct waitable_object +{ + void wait() + { + wait_num++; + } +}; + +BOOST_AUTO_TEST_CASE(wait_guard_test) +{ + waitable_object waitable; + + BOOST_CHECK(wait_num == 0); + { + compute::wait_guard<waitable_object> waitable_object_guard(waitable); + } + BOOST_CHECK(wait_num == 1); + { + compute::wait_guard<waitable_object> waitable_object_guard1(waitable); + compute::wait_guard<waitable_object> waitable_object_guard2(waitable); + } + BOOST_CHECK(wait_num == 3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_bernoulli_distribution.cpp b/src/boost/libs/compute/test/test_bernoulli_distribution.cpp new file mode 100644 index 00000000..3172a83a --- /dev/null +++ b/src/boost/libs/compute/test/test_bernoulli_distribution.cpp @@ -0,0 +1,39 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestBernoulliDistribution +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/bernoulli_distribution.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(bernoulli_distribution_doctest) +{ + boost::compute::vector<bool> vec(10, context); + +//! [generate] +// initialize the default random engine +boost::compute::default_random_engine engine(queue); + +// setup the bernoulli distribution to produce booleans +// with parameter p = 0.25 +boost::compute::bernoulli_distribution<float> distribution(0.25f); + +// generate the random values and store them to 'vec' +distribution.generate(vec.begin(), vec.end(), engine, queue); +//! [generate] +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_binary_search.cpp b/src/boost/libs/compute/test/test_binary_search.cpp new file mode 100644 index 00000000..43e4fcff --- /dev/null +++ b/src/boost/libs/compute/test/test_binary_search.cpp @@ -0,0 +1,102 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestBinarySearch +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/binary_search.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/lower_bound.hpp> +#include <boost/compute/algorithm/upper_bound.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(binary_search_int) +{ + // test data = { 1, ..., 2, ..., 4, 4, 5, 7, ..., 9, ..., 10 } + boost::compute::vector<int> vector(size_t(4096), int(1), queue); + boost::compute::vector<int>::iterator first = vector.begin() + 128; + boost::compute::vector<int>::iterator last = first + (1024 - 128); + boost::compute::fill(first, last, int(2), queue); + last.write(4, queue); last++; + last.write(4, queue); last++; + last.write(5, queue); last++; + first = last; + last = first + 127; + boost::compute::fill(first, last, 7, queue); + first = last; + last = vector.end() - 1; + boost::compute::fill(first, last, 9, queue); + last.write(10, queue); + queue.finish(); + + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(0), queue) == false); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(1), queue) == true); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(2), queue) == true); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(3), queue) == false); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(4), queue) == true); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(5), queue) == true); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(6), queue) == false); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(7), queue) == true); + BOOST_CHECK(boost::compute::binary_search(vector.begin(), vector.end(), int(8), queue) == false); +} + +BOOST_AUTO_TEST_CASE(range_bounds_int) +{ + // test data = { 1, ..., 2, ..., 4, 4, 5, 7, ..., 9, ..., 10 } + boost::compute::vector<int> vector(size_t(4096), int(1), queue); + boost::compute::vector<int>::iterator first = vector.begin() + 128; + boost::compute::vector<int>::iterator last = first + (1024 - 128); + boost::compute::fill(first, last, int(2), queue); + last.write(4, queue); last++; // 1024 + last.write(4, queue); last++; // 1025 + last.write(5, queue); last++; // 1026 + first = last; + last = first + 127; + boost::compute::fill(first, last, 7, queue); + first = last; + last = vector.end() - 1; + boost::compute::fill(first, last, 9, queue); + last.write(10, queue); + queue.finish(); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(0), queue) == vector.begin()); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(0), queue) == vector.begin()); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(1), queue) == vector.begin()); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(1), queue) == vector.begin() + 128); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(2), queue) == vector.begin() + 128); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(2), queue) == vector.begin() + 1024); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(4), queue) == vector.begin() + 1024); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(4), queue) == vector.begin() + 1026); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(5), queue) == vector.begin() + 1026); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(5), queue) == vector.begin() + 1027); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(6), queue) == vector.begin() + 1027); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(6), queue) == vector.begin() + 1027); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(7), queue) == vector.begin() + 1027); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(7), queue) == vector.begin() + (1027 + 127)); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(9), queue) == vector.begin() + (1027 + 127)); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(9), queue) == vector.end() - 1); + + BOOST_CHECK(boost::compute::lower_bound(vector.begin(), vector.end(), int(10), queue) == vector.end() - 1); + BOOST_CHECK(boost::compute::upper_bound(vector.begin(), vector.end(), int(10), queue) == vector.end()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_buffer.cpp b/src/boost/libs/compute/test/test_buffer.cpp new file mode 100644 index 00000000..e86c41be --- /dev/null +++ b/src/boost/libs/compute/test/test_buffer.cpp @@ -0,0 +1,213 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestBuffer +#include <boost/test/unit_test.hpp> + +#include <boost/compute/buffer.hpp> +#include <boost/compute/system.hpp> +#include <boost/bind.hpp> + +#ifdef BOOST_COMPUTE_USE_CPP11 +#include <mutex> +#include <future> +#endif // BOOST_COMPUTE_USE_CPP11 + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(size) +{ + bc::buffer buffer(context, 100); + BOOST_CHECK_EQUAL(buffer.size(), size_t(100)); + BOOST_VERIFY(buffer.max_size() > buffer.size()); +} + +BOOST_AUTO_TEST_CASE(cl_context) +{ + bc::buffer buffer(context, 100); + BOOST_VERIFY(buffer.get_context() == context); +} + +BOOST_AUTO_TEST_CASE(equality_operator) +{ + bc::buffer a(context, 10); + bc::buffer b(context, 10); + BOOST_VERIFY(a == a); + BOOST_VERIFY(b == b); + BOOST_VERIFY(!(a == b)); + BOOST_VERIFY(a != b); + + a = b; + BOOST_VERIFY(a == b); + BOOST_VERIFY(!(a != b)); +} + +BOOST_AUTO_TEST_CASE(construct_from_cl_mem) +{ + // create cl_mem + cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, 16, 0, 0); + BOOST_VERIFY(mem); + + // create boost::compute::buffer + boost::compute::buffer buffer(mem); + + // check buffer + BOOST_CHECK(buffer.get() == mem); + BOOST_CHECK(buffer.get_context() == context); + BOOST_CHECK_EQUAL(buffer.size(), size_t(16)); + + // cleanup cl_mem + clReleaseMemObject(mem); +} + +BOOST_AUTO_TEST_CASE(reference_count) +{ + using boost::compute::uint_; + + boost::compute::buffer buf(context, 16); + BOOST_CHECK_GE(buf.reference_count(), uint_(1)); +} + +BOOST_AUTO_TEST_CASE(get_size) +{ + boost::compute::buffer buf(context, 16); + BOOST_CHECK_EQUAL(buf.size(), size_t(16)); + BOOST_CHECK_EQUAL(buf.get_info<CL_MEM_SIZE>(), size_t(16)); + BOOST_CHECK_EQUAL(buf.get_info<size_t>(CL_MEM_SIZE), size_t(16)); +} + +#ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES +BOOST_AUTO_TEST_CASE(move_constructor) +{ + boost::compute::buffer buffer1(context, 16); + BOOST_CHECK(buffer1.get() != 0); + BOOST_CHECK_EQUAL(buffer1.size(), size_t(16)); + + boost::compute::buffer buffer2(std::move(buffer1)); + BOOST_CHECK(buffer1.get() == 0); + BOOST_CHECK(buffer2.get() != 0); + BOOST_CHECK_EQUAL(buffer2.size(), size_t(16)); +} +#endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES + +BOOST_AUTO_TEST_CASE(clone_buffer) +{ + boost::compute::buffer buffer1(context, 16); + boost::compute::buffer buffer2 = buffer1.clone(queue); + BOOST_CHECK(buffer1.get() != buffer2.get()); + BOOST_CHECK_EQUAL(buffer1.size(), buffer2.size()); + BOOST_CHECK(buffer1.get_memory_flags() == buffer2.get_memory_flags()); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_1 +#ifdef BOOST_COMPUTE_USE_CPP11 +std::mutex callback_mutex; +std::condition_variable callback_condition_variable; + +static void BOOST_COMPUTE_CL_CALLBACK +destructor_callback_function(cl_mem, void *user_data) +{ + std::lock_guard<std::mutex> lock(callback_mutex); + + bool *flag = static_cast<bool *>(user_data); + *flag = true; + + callback_condition_variable.notify_one(); +} + +BOOST_AUTO_TEST_CASE(destructor_callback) +{ + REQUIRES_OPENCL_VERSION(1,2); + + if(!supports_destructor_callback(device)) + { + return; + } + + bool invoked = false; + { + boost::compute::buffer buf(context, 128); + buf.set_destructor_callback(destructor_callback_function, &invoked); + } + + std::unique_lock<std::mutex> lock(callback_mutex); + callback_condition_variable.wait_for( + lock, std::chrono::seconds(1), [&](){ return invoked; } + ); + BOOST_CHECK(invoked == true); +} + +static void BOOST_COMPUTE_CL_CALLBACK +destructor_templated_callback_function(bool *flag) +{ + std::lock_guard<std::mutex> lock(callback_mutex); + *flag = true; + callback_condition_variable.notify_one(); +} + +BOOST_AUTO_TEST_CASE(destructor_templated_callback) +{ + REQUIRES_OPENCL_VERSION(1,2); + + if(!supports_destructor_callback(device)) + { + return; + } + + bool invoked = false; + { + boost::compute::buffer buf(context, 128); + buf.set_destructor_callback(boost::bind(destructor_templated_callback_function, &invoked)); + } + + std::unique_lock<std::mutex> lock(callback_mutex); + callback_condition_variable.wait_for( + lock, std::chrono::seconds(1), [&](){ return invoked; } + ); + + BOOST_CHECK(invoked == true); +} + +#endif // BOOST_COMPUTE_USE_CPP11 + +BOOST_AUTO_TEST_CASE(create_subbuffer) +{ + REQUIRES_OPENCL_VERSION(1, 1); + + size_t base_addr_align = device.get_info<CL_DEVICE_MEM_BASE_ADDR_ALIGN>() / 8; + size_t multiplier = 16; + size_t buffer_size = base_addr_align * multiplier; + size_t subbuffer_size = 64; + boost::compute::buffer buffer(context, buffer_size); + + for(size_t i = 0; i < multiplier; ++i) + { + boost::compute::buffer subbuffer = buffer.create_subbuffer( + boost::compute::buffer::read_write, base_addr_align * i, subbuffer_size); + BOOST_CHECK(buffer.get() != subbuffer.get()); + BOOST_CHECK_EQUAL(subbuffer.size(), subbuffer_size); + } +} + +#endif // BOOST_COMPUTE_CL_VERSION_1_1 + +BOOST_AUTO_TEST_CASE(create_buffer_doctest) +{ +//! [constructor] +boost::compute::buffer buf(context, 32 * sizeof(float)); +//! [constructor] + + BOOST_CHECK_EQUAL(buf.size(), 32 * sizeof(float)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_buffer_allocator.cpp b/src/boost/libs/compute/test/test_buffer_allocator.cpp new file mode 100644 index 00000000..abc8c6aa --- /dev/null +++ b/src/boost/libs/compute/test/test_buffer_allocator.cpp @@ -0,0 +1,29 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestBufferAllocator +#include <boost/test/unit_test.hpp> + +#include <boost/compute/allocator/buffer_allocator.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(allocate) +{ + compute::buffer_allocator<int> allocator(context); + + typedef compute::buffer_allocator<int>::pointer pointer; + pointer x = allocator.allocate(10); + allocator.deallocate(x, 10); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_buffer_iterator.cpp b/src/boost/libs/compute/test/test_buffer_iterator.cpp new file mode 100644 index 00000000..eb448188 --- /dev/null +++ b/src/boost/libs/compute/test/test_buffer_iterator.cpp @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestBufferIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + compute::buffer_iterator<int>::value_type, int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + compute::buffer_iterator<float>::value_type, float + >::value + )); +} + +BOOST_AUTO_TEST_CASE(reverse_external_buffer_doctest) +{ + int data[] = { 1, 2, 3 }; + compute::buffer buffer(context, 3 * sizeof(int)); + queue.enqueue_write_buffer(buffer, 0, 3 * sizeof(int), data); + + cl_mem external_mem_obj = buffer.get(); + +//! [reverse_external_buffer] +// create a buffer object wrapping the cl_mem object +boost::compute::buffer buf(external_mem_obj); + +// reverse the values in the buffer +boost::compute::reverse( + boost::compute::make_buffer_iterator<int>(buf, 0), + boost::compute::make_buffer_iterator<int>(buf, 3), + queue +); +//! [reverse_external_buffer] + + queue.enqueue_read_buffer(buf, 0, 3 * sizeof(int), data); + BOOST_CHECK_EQUAL(data[0], 3); + BOOST_CHECK_EQUAL(data[1], 2); + BOOST_CHECK_EQUAL(data[2], 1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_clamp_range.cpp b/src/boost/libs/compute/test/test_clamp_range.cpp new file mode 100644 index 00000000..985ae2d6 --- /dev/null +++ b/src/boost/libs/compute/test/test_clamp_range.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestClampRange +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/experimental/clamp_range.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(clamp_float_range) +{ + float data[] = { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f }; + compute::vector<float> input(data, data + 8, queue); + + compute::vector<float> result(8, context); + compute::experimental::clamp_range( + input.begin(), + input.end(), + result.begin(), + 3.f, // low + 6.f, // high + queue + ); + CHECK_RANGE_EQUAL( + float, 8, result, + (3.f, 3.f, 3.f, 4.f, 5.f, 6.f, 6.f, 6.f) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_closure.cpp b/src/boost/libs/compute/test/test_closure.cpp new file mode 100644 index 00000000..0747cec7 --- /dev/null +++ b/src/boost/libs/compute/test/test_closure.cpp @@ -0,0 +1,223 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestClosure +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/closure.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/algorithm/transform_reduce.hpp> +#include <boost/compute/container/array.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(add_two) +{ + int two = 2; + BOOST_COMPUTE_CLOSURE(int, add_two, (int x), (two), + { + return x + two; + }); + + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), add_two, queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (3, 4, 5, 6)); +} + +BOOST_AUTO_TEST_CASE(add_two_and_pi) +{ + int two = 2; + float pi = 3.14f; + BOOST_COMPUTE_CLOSURE(float, add_two_and_pi, (float x), (two, pi), + { + return x + two + pi; + }); + + float data[] = { 1.9f, 2.2f, 3.4f, 4.7f }; + compute::vector<float> vector(data, data + 4, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), add_two_and_pi, queue + ); + + std::vector<float> results(4); + compute::copy(vector.begin(), vector.end(), results.begin(), queue); + BOOST_CHECK_CLOSE(results[0], 7.04f, 1e-6); + BOOST_CHECK_CLOSE(results[1], 7.34f, 1e-6); + BOOST_CHECK_CLOSE(results[2], 8.54f, 1e-6); + BOOST_CHECK_CLOSE(results[3], 9.84f, 1e-6); +} + +BOOST_AUTO_TEST_CASE(add_y) +{ + // setup input and output vectors + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> input(data, data + 4, queue); + compute::vector<int> output(4, context); + + // make closure which adds 'y' to each value + int y = 2; + BOOST_COMPUTE_CLOSURE(int, add_y, (int x), (y), + { + return x + y; + }); + + compute::transform( + input.begin(), input.end(), output.begin(), add_y, queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (3, 4, 5, 6)); + + // change y and run again + y = 4; + + compute::transform( + input.begin(), input.end(), output.begin(), add_y, queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (5, 6, 7, 8)); +} + +BOOST_AUTO_TEST_CASE(scale_add_vec) +{ + const int N = 10; + float s = 4.5; + compute::vector<float> a(N, context); + compute::vector<float> b(N, context); + a.assign(N, 1.0f, queue); + b.assign(N, 2.0f, queue); + + BOOST_COMPUTE_CLOSURE(float, scaleAddVec, (float b, float a), (s), + { + return b * s + a; + }); + compute::transform(b.begin(), b.end(), a.begin(), b.begin(), scaleAddVec, queue); +} + +BOOST_AUTO_TEST_CASE(capture_vector) +{ + int data[] = { 6, 7, 8, 9 }; + compute::vector<int> vec(data, data + 4, queue); + + BOOST_COMPUTE_CLOSURE(int, get_vec, (int i), (vec), + { + return vec[i]; + }); + + // run using a counting iterator to copy from vec to output + compute::vector<int> output(4, context); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + get_vec, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (6, 7, 8, 9)); + + // fill vec with 4's and run again + compute::fill(vec.begin(), vec.end(), 4, queue); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + get_vec, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (4, 4, 4, 4)); +} + +BOOST_AUTO_TEST_CASE(capture_array) +{ + int data[] = { 1, 2, 3, 4 }; + compute::array<int, 4> array(context); + compute::copy(data, data + 4, array.begin(), queue); + + BOOST_COMPUTE_CLOSURE(int, negative_array_value, (int i), (array), + { + return -array[i]; + }); + + compute::vector<int> output(4, context); + compute::transform( + compute::make_counting_iterator(0), + compute::make_counting_iterator(4), + output.begin(), + negative_array_value, + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (-1, -2, -3, -4)); +} + +BOOST_AUTO_TEST_CASE(triangle_area) +{ + using compute::uint4_; + using compute::float4_; + + compute::vector<uint4_> triangle_indices(context); + compute::vector<float4_> triangle_vertices(context); + + triangle_vertices.push_back(float4_(0, 0, 0, 1), queue); + triangle_vertices.push_back(float4_(1, 1, 0, 1), queue); + triangle_vertices.push_back(float4_(1, 0, 0, 1), queue); + triangle_vertices.push_back(float4_(2, 0, 0, 1), queue); + + triangle_indices.push_back(uint4_(0, 1, 2, 0), queue); + triangle_indices.push_back(uint4_(2, 1, 3, 0), queue); + + queue.finish(); + + BOOST_COMPUTE_CLOSURE(float, triangle_area, (const uint4_ i), (triangle_vertices), + { + // load triangle vertices + const float4 a = triangle_vertices[i.x]; + const float4 b = triangle_vertices[i.y]; + const float4 c = triangle_vertices[i.z]; + + // return area of triangle + return length(cross(b-a, c-a)) / 2; + }); + + // compute area of each triangle + compute::vector<float> triangle_areas(triangle_indices.size(), context); + + compute::transform( + triangle_indices.begin(), + triangle_indices.end(), + triangle_areas.begin(), + triangle_area, + queue + ); + + // compute total area of all triangles + float total_area = 0; + + compute::transform_reduce( + triangle_indices.begin(), + triangle_indices.end(), + &total_area, + triangle_area, + compute::plus<float>(), + queue + ); + BOOST_CHECK_CLOSE(total_area, 1.f, 1e-6); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_command_queue.cpp b/src/boost/libs/compute/test/test_command_queue.cpp new file mode 100644 index 00000000..dc409795 --- /dev/null +++ b/src/boost/libs/compute/test/test_command_queue.cpp @@ -0,0 +1,352 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestCommandQueue +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/kernel.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> +#include <boost/compute/detail/diagnostic.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(get_context) +{ + BOOST_VERIFY(queue.get_context() == context); + BOOST_VERIFY(queue.get_info<CL_QUEUE_CONTEXT>() == context.get()); +} + +BOOST_AUTO_TEST_CASE(get_device) +{ + BOOST_VERIFY(queue.get_info<CL_QUEUE_DEVICE>() == device.get()); +} + +BOOST_AUTO_TEST_CASE(equality_operator) +{ + compute::command_queue queue1(context, device); + BOOST_CHECK(queue1 == queue1); + + compute::command_queue queue2 = queue1; + BOOST_CHECK(queue1 == queue2); + + compute::command_queue queue3(context, device); + BOOST_CHECK(queue1 != queue3); +} + +BOOST_AUTO_TEST_CASE(event_profiling) +{ + bc::command_queue queue(context, device, bc::command_queue::enable_profiling); + + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + bc::buffer buffer(context, sizeof(data)); + + bc::event event = + queue.enqueue_write_buffer_async(buffer, + 0, + sizeof(data), + static_cast<const void *>(data)); + queue.finish(); + + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_queued); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_submit); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_start); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_end); +} + +BOOST_AUTO_TEST_CASE(kernel_profiling) +{ + // create queue with profiling enabled + boost::compute::command_queue queue( + context, device, boost::compute::command_queue::enable_profiling + ); + + // input data + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::buffer buffer(context, sizeof(data)); + + // copy input data to device + queue.enqueue_write_buffer(buffer, 0, sizeof(data), data); + + // setup kernel + const char source[] = + "__kernel void iscal(__global int *buffer, int alpha)\n" + "{\n" + " buffer[get_global_id(0)] *= alpha;\n" + "}\n"; + + boost::compute::program program = + boost::compute::program::create_with_source(source, context); + program.build(); + + boost::compute::kernel kernel(program, "iscal"); + kernel.set_arg(0, buffer); + kernel.set_arg(1, 2); + + // execute kernel + size_t global_work_offset = 0; + size_t global_work_size = 8; + + boost::compute::event event = + queue.enqueue_nd_range_kernel(kernel, + size_t(1), + &global_work_offset, + &global_work_size, + 0); + + // wait until kernel is finished + event.wait(); + + // check profiling information + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_queued); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_submit); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_start); + event.get_profiling_info<cl_ulong>(bc::event::profiling_command_end); + + // read results back to host + queue.enqueue_read_buffer(buffer, 0, sizeof(data), data); + + // check results + BOOST_CHECK_EQUAL(data[0], 2); + BOOST_CHECK_EQUAL(data[1], 4); + BOOST_CHECK_EQUAL(data[2], 6); + BOOST_CHECK_EQUAL(data[3], 8); + BOOST_CHECK_EQUAL(data[4], 10); + BOOST_CHECK_EQUAL(data[5], 12); + BOOST_CHECK_EQUAL(data[6], 14); + BOOST_CHECK_EQUAL(data[7], 16); +} + +BOOST_AUTO_TEST_CASE(construct_from_cl_command_queue) +{ + // create cl_command_queue + cl_command_queue cl_queue; +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 + if (device.check_version(2, 0)){ // runtime check + cl_queue = + clCreateCommandQueueWithProperties(context, device.id(), 0, 0); + } else +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + { + // Suppress deprecated declarations warning + BOOST_COMPUTE_DISABLE_DEPRECATED_DECLARATIONS(); + cl_queue = + clCreateCommandQueue(context, device.id(), 0, 0); + BOOST_COMPUTE_ENABLE_DEPRECATED_DECLARATIONS(); + } + BOOST_VERIFY(cl_queue); + + // create boost::compute::command_queue + boost::compute::command_queue queue(cl_queue); + + // check queue + BOOST_CHECK(queue.get_context() == context); + BOOST_CHECK(cl_command_queue(queue) == cl_queue); + + // cleanup cl_command_queue + clReleaseCommandQueue(cl_queue); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_1 +BOOST_AUTO_TEST_CASE(write_buffer_rect) +{ + REQUIRES_OPENCL_VERSION(1, 1); + + // skip this test on AMD GPUs due to a buggy implementation + // of the clEnqueueWriteBufferRect() function + if(device.vendor() == "Advanced Micro Devices, Inc." && + device.type() & boost::compute::device::gpu){ + std::cerr << "skipping write_buffer_rect test on AMD GPU" << std::endl; + return; + } + + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::buffer buffer(context, 8 * sizeof(int)); + + // copy every other value to the buffer + size_t buffer_origin[] = { 0, 0, 0 }; + size_t host_origin[] = { 0, 0, 0 }; + size_t region[] = { sizeof(int), sizeof(int), 1 }; + + queue.enqueue_write_buffer_rect( + buffer, + buffer_origin, + host_origin, + region, + sizeof(int), + 0, + 2 * sizeof(int), + 0, + data + ); + + // check output values + int output[4]; + queue.enqueue_read_buffer(buffer, 0, 4 * sizeof(int), output); + BOOST_CHECK_EQUAL(output[0], 1); + BOOST_CHECK_EQUAL(output[1], 3); + BOOST_CHECK_EQUAL(output[2], 5); + BOOST_CHECK_EQUAL(output[3], 7); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_1 + +static bool nullary_kernel_executed = false; + +static void nullary_kernel() +{ + nullary_kernel_executed = true; +} + +BOOST_AUTO_TEST_CASE(native_kernel) +{ + cl_device_exec_capabilities exec_capabilities = + device.get_info<CL_DEVICE_EXECUTION_CAPABILITIES>(); + if(!(exec_capabilities & CL_EXEC_NATIVE_KERNEL)){ + std::cerr << "skipping native_kernel test: " + << "device does not support CL_EXEC_NATIVE_KERNEL" + << std::endl; + return; + } + + compute::vector<int> vector(1000, context); + compute::fill(vector.begin(), vector.end(), 42, queue); + BOOST_CHECK_EQUAL(nullary_kernel_executed, false); + queue.enqueue_native_kernel(&nullary_kernel); + queue.finish(); + BOOST_CHECK_EQUAL(nullary_kernel_executed, true); +} + +BOOST_AUTO_TEST_CASE(copy_with_wait_list) +{ + int data1[] = { 1, 3, 5, 7 }; + int data2[] = { 2, 4, 6, 8 }; + + compute::buffer buf1(context, 4 * sizeof(int)); + compute::buffer buf2(context, 4 * sizeof(int)); + + compute::event write_event1 = + queue.enqueue_write_buffer_async(buf1, 0, buf1.size(), data1); + + compute::event write_event2 = + queue.enqueue_write_buffer_async(buf2, 0, buf2.size(), data2); + + compute::event read_event1 = + queue.enqueue_read_buffer_async(buf1, 0, buf1.size(), data2, write_event1); + + compute::event read_event2 = + queue.enqueue_read_buffer_async(buf2, 0, buf2.size(), data1, write_event2); + + read_event1.wait(); + read_event2.wait(); + + CHECK_HOST_RANGE_EQUAL(int, 4, data1, (2, 4, 6, 8)); + CHECK_HOST_RANGE_EQUAL(int, 4, data2, (1, 3, 5, 7)); +} + +#ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +BOOST_AUTO_TEST_CASE(enqueue_kernel_with_extents) +{ + using boost::compute::dim; + using boost::compute::uint_; + + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void foo(__global int *output1, __global int *output2) + { + output1[get_global_id(0)] = get_local_id(0); + output2[get_global_id(1)] = get_local_id(1); + } + ); + + compute::kernel kernel = + compute::kernel::create_with_source(source, "foo", context); + + compute::vector<uint_> output1(4, context); + compute::vector<uint_> output2(4, context); + + kernel.set_arg(0, output1); + kernel.set_arg(1, output2); + + queue.enqueue_nd_range_kernel(kernel, dim(0, 0), dim(4, 4), dim(1, 1)); + + CHECK_RANGE_EQUAL(int, 4, output1, (0, 0, 0, 0)); + CHECK_RANGE_EQUAL(int, 4, output2, (0, 0, 0, 0)); + + // Maximum number of work-items that can be specified in each + // dimension of the work-group to clEnqueueNDRangeKernel. + std::vector<size_t> max_work_item_sizes = + device.get_info<CL_DEVICE_MAX_WORK_ITEM_SIZES>(); + + if(max_work_item_sizes[0] < size_t(2)) { + return; + } + + queue.enqueue_nd_range_kernel(kernel, dim(0, 0), dim(4, 4), dim(2, 1)); + + CHECK_RANGE_EQUAL(int, 4, output1, (0, 1, 0, 1)); + CHECK_RANGE_EQUAL(int, 4, output2, (0, 0, 0, 0)); + + if(max_work_item_sizes[1] < size_t(2)) { + return; + } + + queue.enqueue_nd_range_kernel(kernel, dim(0, 0), dim(4, 4), dim(2, 2)); + + CHECK_RANGE_EQUAL(int, 4, output1, (0, 1, 0, 1)); + CHECK_RANGE_EQUAL(int, 4, output2, (0, 1, 0, 1)); +} +#endif // BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(get_default_device_queue) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + boost::compute::command_queue default_device_queue( + context, device, + boost::compute::command_queue::on_device | + boost::compute::command_queue::on_device_default | + boost::compute::command_queue::enable_out_of_order_execution + ); + BOOST_CHECK_NO_THROW(queue.get_info<CL_QUEUE_DEVICE_DEFAULT>()); + BOOST_CHECK_EQUAL( + queue.get_default_device_queue(), + default_device_queue + ); +} + +BOOST_AUTO_TEST_CASE(set_as_default_device_queue) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + boost::compute::command_queue new_default_device_queue( + context, device, + boost::compute::command_queue::on_device | + boost::compute::command_queue::enable_out_of_order_execution + ); + new_default_device_queue.set_as_default_device_queue(); + BOOST_CHECK_EQUAL( + queue.get_default_device_queue(), + new_default_device_queue + ); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_complex.cpp b/src/boost/libs/compute/test/test_complex.cpp new file mode 100644 index 00000000..35e143d1 --- /dev/null +++ b/src/boost/libs/compute/test/test_complex.cpp @@ -0,0 +1,173 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestComplex +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/complex.hpp> +#include <boost/compute/type_traits/type_name.hpp> + +#include "context_setup.hpp" + +// copies a vector of complex<float>'s on the host to the device +BOOST_AUTO_TEST_CASE(copy_complex_vector) +{ + std::vector<std::complex<float> > host_vector; + host_vector.push_back(std::complex<float>(1.0f, 2.0f)); + host_vector.push_back(std::complex<float>(-2.0f, 1.0f)); + host_vector.push_back(std::complex<float>(1.0f, -2.0f)); + host_vector.push_back(std::complex<float>(-2.0f, -1.0f)); + + boost::compute::vector<std::complex<float> > device_vector(context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + queue.finish(); + BOOST_CHECK_EQUAL(std::complex<float>(device_vector[0]), std::complex<float>(1.0f, 2.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(device_vector[1]), std::complex<float>(-2.0f, 1.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(device_vector[2]), std::complex<float>(1.0f, -2.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(device_vector[3]), std::complex<float>(-2.0f, -1.0f)); +} + +// fills a vector of complex<float>'s on the device with a constant value +BOOST_AUTO_TEST_CASE(fill_complex_vector) +{ + boost::compute::vector<std::complex<float> > vector(6, context); + boost::compute::fill( + vector.begin(), + vector.end(), + std::complex<float>(2.0f, 5.0f), + queue + ); + queue.finish(); + BOOST_CHECK_EQUAL(std::complex<float>(vector[0]), std::complex<float>(2.0f, 5.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(vector[1]), std::complex<float>(2.0f, 5.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(vector[2]), std::complex<float>(2.0f, 5.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(vector[3]), std::complex<float>(2.0f, 5.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(vector[4]), std::complex<float>(2.0f, 5.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(vector[5]), std::complex<float>(2.0f, 5.0f)); +} + +// extracts the real and imag components of a vector of complex<float>'s using +// transform with the real() and imag() functions +BOOST_AUTO_TEST_CASE(extract_real_and_imag) +{ + boost::compute::vector<std::complex<float> > vector(context); + vector.push_back(std::complex<float>(1.0f, 3.0f), queue); + vector.push_back(std::complex<float>(3.0f, 1.0f), queue); + vector.push_back(std::complex<float>(5.0f, -1.0f), queue); + vector.push_back(std::complex<float>(7.0f, -3.0f), queue); + vector.push_back(std::complex<float>(9.0f, -5.0f), queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(5)); + + boost::compute::vector<float> reals(5, context); + boost::compute::transform( + vector.begin(), + vector.end(), + reals.begin(), + boost::compute::real<float>(), + queue + ); + queue.finish(); + BOOST_CHECK_EQUAL(float(reals[0]), float(1.0f)); + BOOST_CHECK_EQUAL(float(reals[1]), float(3.0f)); + BOOST_CHECK_EQUAL(float(reals[2]), float(5.0f)); + BOOST_CHECK_EQUAL(float(reals[3]), float(7.0f)); + BOOST_CHECK_EQUAL(float(reals[4]), float(9.0f)); + + boost::compute::vector<float> imags(5, context); + boost::compute::transform( + vector.begin(), + vector.end(), + imags.begin(), + boost::compute::imag<float>(), + queue + ); + queue.finish(); + BOOST_CHECK_EQUAL(float(imags[0]), float(3.0f)); + BOOST_CHECK_EQUAL(float(imags[1]), float(1.0f)); + BOOST_CHECK_EQUAL(float(imags[2]), float(-1.0f)); + BOOST_CHECK_EQUAL(float(imags[3]), float(-3.0f)); + BOOST_CHECK_EQUAL(float(imags[4]), float(-5.0f)); +} + +// compute the complex conjugate of a vector of complex<float>'s +BOOST_AUTO_TEST_CASE(complex_conj) +{ + boost::compute::vector<std::complex<float> > input(context); + input.push_back(std::complex<float>(1.0f, 3.0f), queue); + input.push_back(std::complex<float>(3.0f, 1.0f), queue); + input.push_back(std::complex<float>(5.0f, -1.0f), queue); + input.push_back(std::complex<float>(7.0f, -3.0f), queue); + input.push_back(std::complex<float>(9.0f, -5.0f), queue); + BOOST_CHECK_EQUAL(input.size(), size_t(5)); + + boost::compute::vector<std::complex<float> > output(5, context); + boost::compute::transform( + input.begin(), + input.end(), + output.begin(), + boost::compute::conj<float>(), + queue + ); + queue.finish(); + BOOST_CHECK_EQUAL(std::complex<float>(output[0]), std::complex<float>(1.0f, -3.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(output[1]), std::complex<float>(3.0f, -1.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(output[2]), std::complex<float>(5.0f, 1.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(output[3]), std::complex<float>(7.0f, 3.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(output[4]), std::complex<float>(9.0f, 5.0f)); +} + +// check type_name() for std::complex +BOOST_AUTO_TEST_CASE(complex_type_name) +{ + BOOST_CHECK( + std::strcmp( + boost::compute::type_name<std::complex<float> >(), + "float2" + ) == 0 + ); +} + +BOOST_AUTO_TEST_CASE(transform_multiply) +{ + boost::compute::vector<std::complex<float> > x(context); + x.push_back(std::complex<float>(1.0f, 2.0f), queue); + x.push_back(std::complex<float>(-2.0f, 5.0f), queue); + + boost::compute::vector<std::complex<float> > y(context); + y.push_back(std::complex<float>(3.0f, 4.0f), queue); + y.push_back(std::complex<float>(2.0f, -1.0f), queue); + + boost::compute::vector<std::complex<float> > z(2, context); + + // z = x * y + boost::compute::transform( + x.begin(), + x.end(), + y.begin(), + z.begin(), + boost::compute::multiplies<std::complex<float> >(), + queue + ); + queue.finish(); + + BOOST_CHECK_EQUAL(std::complex<float>(z[0]), std::complex<float>(-5.0f, 10.0f)); + BOOST_CHECK_EQUAL(std::complex<float>(z[1]), std::complex<float>(1.0f, 12.0f)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_constant_iterator.cpp b/src/boost/libs/compute/test/test_constant_iterator.cpp new file mode 100644 index 00000000..96cf29db --- /dev/null +++ b/src/boost/libs/compute/test/test_constant_iterator.cpp @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestConstantIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::constant_iterator<int>::value_type, + int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::constant_iterator<float>::value_type, + float + >::value + )); +} + +BOOST_AUTO_TEST_CASE(distance) +{ + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_constant_iterator(128, 0), + boost::compute::make_constant_iterator(128, 10) + ), + std::ptrdiff_t(10) + ); + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_constant_iterator(256, 5), + boost::compute::make_constant_iterator(256, 10) + ), + std::ptrdiff_t(5) + ); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + boost::compute::vector<int> vector(10, context); + + boost::compute::copy( + boost::compute::make_constant_iterator(42, 0), + boost::compute::make_constant_iterator(42, 10), + vector.begin(), + queue + ); + CHECK_RANGE_EQUAL( + int, 10, vector, + (42, 42, 42, 42, 42, 42, 42, 42, 42, 42) + ); +} + +BOOST_AUTO_TEST_CASE(fill_with_copy_doctest) +{ +//! [fill_with_copy] +using boost::compute::make_constant_iterator; + +boost::compute::vector<int> result(5, context); + +boost::compute::copy( + make_constant_iterator(42, 0), + make_constant_iterator(42, result.size()), + result.begin(), + queue +); + +// result == { 42, 42, 42, 42, 42 } +//! [fill_with_copy] + + CHECK_RANGE_EQUAL(int, 5, result, (42, 42, 42, 42, 42)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_context.cpp b/src/boost/libs/compute/test/test_context.cpp new file mode 100644 index 00000000..8155dd2e --- /dev/null +++ b/src/boost/libs/compute/test/test_context.cpp @@ -0,0 +1,67 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestContext +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/context.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(construct_from_cl_context) +{ + cl_device_id id = device.id(); + + // create cl_context + cl_context ctx = clCreateContext(0, 1, &id, 0, 0, 0); + BOOST_VERIFY(ctx); + + // create boost::compute::context + boost::compute::context context(ctx); + + // check context + BOOST_CHECK(cl_context(context) == ctx); + + // cleanup cl_context + clReleaseContext(ctx); +} + +#ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES +BOOST_AUTO_TEST_CASE(move_constructor) +{ + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context1(device); + BOOST_VERIFY(cl_context(context1) != cl_context()); + + boost::compute::context context2(std::move(context1)); + BOOST_VERIFY(cl_context(context2) != cl_context()); + BOOST_VERIFY(cl_context(context1) == cl_context()); +} +#endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES + +BOOST_AUTO_TEST_CASE(multiple_devices) +{ + const std::vector<compute::platform> &platforms = compute::system::platforms(); + for(size_t i = 0; i < platforms.size(); i++){ + const compute::platform &platform = platforms[i]; + + // create a context for containing all devices in the platform + compute::context ctx(platform.devices()); + + // check device count + BOOST_CHECK_EQUAL(ctx.get_devices().size(), platform.device_count()); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_context_error.cpp b/src/boost/libs/compute/test/test_context_error.cpp new file mode 100644 index 00000000..29186479 --- /dev/null +++ b/src/boost/libs/compute/test/test_context_error.cpp @@ -0,0 +1,25 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Fabian Köhler <fabian2804@googlemail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestContextError +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/exception/context_error.hpp> + +BOOST_AUTO_TEST_CASE(what) +{ + boost::compute::context context = boost::compute::system::default_context(); + boost::compute::context_error error(&context, "Test", 0, 0); + BOOST_CHECK_EQUAL(std::string(error.what()), std::string("Test")); + BOOST_CHECK(*error.get_context_ptr() == context); + BOOST_CHECK(error.get_private_info_ptr() == 0); + BOOST_CHECK(error.get_private_info_size() == 0); +} diff --git a/src/boost/libs/compute/test/test_copy.cpp b/src/boost/libs/compute/test/test_copy.cpp new file mode 100644 index 00000000..1ceb7853 --- /dev/null +++ b/src/boost/libs/compute/test/test_copy.cpp @@ -0,0 +1,411 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestCopy +#include <boost/test/unit_test.hpp> + +#include <list> +#include <vector> +#include <string> +#include <sstream> +#include <iterator> +#include <iostream> + +#include <boost/compute/svm.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/async/future.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/detail/device_ptr.hpp> +#include <boost/compute/iterator/detail/swizzle_iterator.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(copy_on_device) +{ + float data[] = { 6.1f, 10.2f, 19.3f, 25.4f }; + bc::vector<float> a(4, context); + bc::copy(data, data + 4, a.begin(), queue); + CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 19.3f, 25.4f)); + + bc::vector<float> b(4, context); + bc::fill(b.begin(), b.end(), 0, queue); + CHECK_RANGE_EQUAL(float, 4, b, (0.0f, 0.0f, 0.0f, 0.0f)); + + bc::copy(a.begin(), a.end(), b.begin(), queue); + CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f)); + + bc::vector<float> c(context); + bc::copy(c.begin(), c.end(), b.begin(), queue); + CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f)); +} + +BOOST_AUTO_TEST_CASE(copy_on_device_device_ptr) +{ + float data[] = { 6.1f, 10.2f, 19.3f, 25.4f }; + bc::vector<float> a(4, context); + bc::copy(data, data + 4, a.begin(), queue); + CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 19.3f, 25.4f)); + + bc::vector<float> b(4, context); + bc::detail::device_ptr<float> b_ptr(b.get_buffer(), size_t(0)); + + // buffer_iterator -> device_ptr + bc::copy(a.begin(), a.end(), b_ptr, queue); + CHECK_RANGE_EQUAL(float, 4, b, (6.1f, 10.2f, 19.3f, 25.4f)); + + bc::vector<float> c(4, context); + bc::fill(c.begin(), c.end(), 0.0f, queue); + bc::detail::device_ptr<float> c_ptr(c.get_buffer(), size_t(2)); + + // device_ptr -> device_ptr + bc::copy(b_ptr, b_ptr + 2, c_ptr, queue); + CHECK_RANGE_EQUAL(float, 4, c, (0.0f, 0.0f, 6.1f, 10.2f)); + + // device_ptr -> buffer_iterator + bc::copy(c_ptr, c_ptr + 2, a.begin() + 2, queue); + CHECK_RANGE_EQUAL(float, 4, a, (6.1f, 10.2f, 6.1f, 10.2f)); +} + +BOOST_AUTO_TEST_CASE(copy_on_host) +{ + int data[] = { 2, 4, 6, 8 }; + std::vector<int> vector(4); + compute::copy(data, data + 4, vector.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, vector, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + int data[] = { 1, 2, 5, 6 }; + bc::vector<int> vector(4, context); + bc::copy(data, data + 4, vector.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, vector, (1, 2, 5, 6)); + + std::vector<int> host_vector(4); + bc::copy(vector.begin(), vector.end(), host_vector.begin(), queue); + BOOST_CHECK_EQUAL(host_vector[0], 1); + BOOST_CHECK_EQUAL(host_vector[1], 2); + BOOST_CHECK_EQUAL(host_vector[2], 5); + BOOST_CHECK_EQUAL(host_vector[3], 6); +} + +BOOST_AUTO_TEST_CASE(empty_copy) +{ + int data[] = { 1, 2, 5, 6 }; + bc::vector<int> a(4, context); + bc::vector<int> b(context); + std::vector<int> c; + + bc::copy(data, data + 4, a.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6)); + + bc::copy(b.begin(), b.end(), a.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6)); + + bc::copy(c.begin(), c.end(), a.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6)); + + bc::future<bc::vector<int>::iterator> future = + bc::copy_async(c.begin(), c.end(), a.begin(), queue); + if(future.valid()) + future.wait(); + CHECK_RANGE_EQUAL(int, 4, a, (1, 2, 5, 6)); +} + +// Test copying from a std::list to a bc::vector. This differs from +// the test copying from std::vector because std::list has non-contigous +// storage for its data values. +BOOST_AUTO_TEST_CASE(copy_from_host_list) +{ + int data[] = { -4, 12, 9, 0 }; + std::list<int> host_list(data, data + 4); + + bc::vector<int> vector(4, context); + bc::copy(host_list.begin(), host_list.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int, 4, vector, (-4, 12, 9, 0)); +} + +BOOST_AUTO_TEST_CASE(copy_n_int) +{ + int data[] = { 1, 2, 3, 4, 5 }; + bc::vector<int> a(data, data + 5, queue); + + bc::vector<int> b(5, context); + bc::fill(b.begin(), b.end(), 0, queue); + bc::copy_n(a.begin(), 3, b.begin(), queue); + CHECK_RANGE_EQUAL(int, 5, b, (1, 2, 3, 0, 0)); + + bc::copy_n(b.begin(), 4, a.begin(), queue); + CHECK_RANGE_EQUAL(int, 5, a, (1, 2, 3, 0, 5)); +} + +BOOST_AUTO_TEST_CASE(copy_swizzle_iterator) +{ + using bc::int2_; + using bc::int4_; + + int data[] = { 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 1, 2, 3, + 4, 5, 6, 7 }; + + bc::vector<int4_> input(reinterpret_cast<int4_*>(data), + reinterpret_cast<int4_*>(data) + 4, + queue); + BOOST_CHECK_EQUAL(input.size(), size_t(4)); + CHECK_RANGE_EQUAL(int4_, 4, input, + (int4_(1, 2, 3, 4), + int4_(5, 6, 7, 8), + int4_(9, 1, 2, 3), + int4_(4, 5, 6, 7)) + ); + + bc::vector<int4_> output4(4, context); + bc::copy( + bc::detail::make_swizzle_iterator<4>(input.begin(), "wzyx"), + bc::detail::make_swizzle_iterator<4>(input.end(), "wzyx"), + output4.begin(), + queue + ); + CHECK_RANGE_EQUAL(int4_, 4, output4, + (int4_(4, 3, 2, 1), + int4_(8, 7, 6, 5), + int4_(3, 2, 1, 9), + int4_(7, 6, 5, 4)) + ); + + bc::vector<int2_> output2(4, context); + bc::copy( + bc::detail::make_swizzle_iterator<2>(input.begin(), "xz"), + bc::detail::make_swizzle_iterator<2>(input.end(), "xz"), + output2.begin(), + queue + ); + CHECK_RANGE_EQUAL(int2_, 4, output2, + (int2_(1, 3), + int2_(5, 7), + int2_(9, 2), + int2_(4, 6)) + ); + + bc::vector<int> output1(4, context); + bc::copy( + bc::detail::make_swizzle_iterator<1>(input.begin(), "y"), + bc::detail::make_swizzle_iterator<1>(input.end(), "y"), + output1.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 4, output1, (2, 6, 1, 5)); +} + +BOOST_AUTO_TEST_CASE(copy_int_async) +{ + // setup host data + int host_data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + typedef int* host_iterator; + + // setup device data + bc::vector<int> device_data(8, context); + typedef bc::vector<int>::iterator device_iterator; + + // copy data to device + bc::future<device_iterator> host_to_device_future = + bc::copy_async(host_data, host_data + 8, device_data.begin(), queue); + + // wait for copy to complete + host_to_device_future.wait(); + + // check results + CHECK_RANGE_EQUAL(int, 8, device_data, (1, 2, 3, 4, 5, 6, 7, 8)); + BOOST_VERIFY(host_to_device_future.get() == device_data.end()); + + // fill host data with zeros + std::fill(host_data, host_data + 8, int(0)); + + // copy data back to host + bc::future<host_iterator> device_to_host_future = + bc::copy_async(device_data.begin(), device_data.end(), host_data, queue); + + // wait for copy to complete + device_to_host_future.wait(); + + // check results + BOOST_CHECK_EQUAL(host_data[0], int(1)); + BOOST_CHECK_EQUAL(host_data[1], int(2)); + BOOST_CHECK_EQUAL(host_data[2], int(3)); + BOOST_CHECK_EQUAL(host_data[3], int(4)); + BOOST_CHECK_EQUAL(host_data[4], int(5)); + BOOST_CHECK_EQUAL(host_data[5], int(6)); + BOOST_CHECK_EQUAL(host_data[6], int(7)); + BOOST_CHECK_EQUAL(host_data[7], int(8)); + BOOST_VERIFY(device_to_host_future.get() == host_data + 8); +} + +BOOST_AUTO_TEST_CASE(copy_to_back_inserter) +{ + compute::vector<int> device_vector(5, context); + compute::iota(device_vector.begin(), device_vector.end(), 10, queue); + + std::vector<int> host_vector; + compute::copy( + device_vector.begin(), + device_vector.end(), + std::back_inserter(host_vector), + queue + ); + + BOOST_CHECK_EQUAL(host_vector.size(), size_t(5)); + BOOST_CHECK_EQUAL(host_vector[0], 10); + BOOST_CHECK_EQUAL(host_vector[1], 11); + BOOST_CHECK_EQUAL(host_vector[2], 12); + BOOST_CHECK_EQUAL(host_vector[3], 13); + BOOST_CHECK_EQUAL(host_vector[4], 14); +} + +BOOST_AUTO_TEST_CASE(copy_to_stringstream) +{ + std::stringstream stream; + + int data[] = { 2, 3, 4, 5, 6, 7, 8, 9 }; + compute::vector<int> vector(data, data + 8, queue); + + compute::copy( + vector.begin(), + vector.end(), + std::ostream_iterator<int>(stream, " "), + queue + ); + BOOST_CHECK_EQUAL(stream.str(), std::string("2 3 4 5 6 7 8 9 ")); +} + +BOOST_AUTO_TEST_CASE(check_copy_type) +{ + // copy from host to device and ensure clEnqueueWriteBuffer() is used + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> a(8, context); + compute::future<void> future = + compute::copy_async(data, data + 8, a.begin(), queue); + BOOST_CHECK( + future.get_event().get_command_type() == CL_COMMAND_WRITE_BUFFER + ); + future.wait(); + CHECK_RANGE_EQUAL(int, 8, a, (1, 2, 3, 4, 5, 6, 7, 8)); + + // copy on the device and ensure clEnqueueCopyBuffer() is used + compute::vector<int> b(8, context); + future = compute::copy_async(a.begin(), a.end(), b.begin(), queue); + BOOST_CHECK( + future.get_event().get_command_type() == CL_COMMAND_COPY_BUFFER + ); + future.wait(); + CHECK_RANGE_EQUAL(int, 8, b, (1, 2, 3, 4, 5, 6, 7, 8)); + + // copy between vectors of different types on the device and ensure + // that the copy kernel is used + compute::vector<short> c(8, context); + future = compute::copy_async(a.begin(), a.end(), c.begin(), queue); + BOOST_CHECK( + future.get_event().get_command_type() == CL_COMMAND_NDRANGE_KERNEL + ); + future.wait(); + CHECK_RANGE_EQUAL(short, 8, c, (1, 2, 3, 4, 5, 6, 7, 8)); + + // copy from device to host and ensure clEnqueueReadBuffer() is used + future = compute::copy_async(b.begin(), b.end(), data, queue); + BOOST_CHECK( + future.get_event().get_command_type() == CL_COMMAND_READ_BUFFER + ); + future.wait(); + CHECK_HOST_RANGE_EQUAL(int, 8, data, (1, 2, 3, 4, 5, 6, 7, 8)); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 +BOOST_AUTO_TEST_CASE(copy_svm_ptr) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using boost::compute::int_; + + if(bug_in_svmmemcpy(device)){ + std::cerr << "skipping copy_svm_ptr test case" << std::endl; + return; + } + + int_ data[] = { 1, 3, 2, 4 }; + + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + compute::copy(data, data + 4, ptr, queue); + + int_ output[] = { 0, 0, 0, 0 }; + compute::copy(ptr, ptr + 4, output, queue); + CHECK_HOST_RANGE_EQUAL(int_, 4, output, (1, 3, 2, 4)); + + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(copy_async_svm_ptr) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using boost::compute::int_; + + if(bug_in_svmmemcpy(device)){ + std::cerr << "skipping copy_svm_ptr test case" << std::endl; + return; + } + + int_ data[] = { 1, 3, 2, 4 }; + + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + boost::compute::future<void> future = + compute::copy_async(data, data + 4, ptr, queue); + future.wait(); + + int_ output[] = { 0, 0, 0, 0 }; + future = + compute::copy_async(ptr, ptr + 4, output, queue); + future.wait(); + CHECK_HOST_RANGE_EQUAL(int_, 4, output, (1, 3, 2, 4)); + + compute::svm_free(context, ptr); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + +BOOST_AUTO_TEST_CASE(copy_to_vector_bool) +{ + using compute::uchar_; + + compute::vector<uchar_> vec(2, context); + + // copy to device + bool data[] = {true, false}; + compute::copy(data, data + 2, vec.begin(), queue); + BOOST_CHECK(static_cast<bool>(vec[0]) == true); + BOOST_CHECK(static_cast<bool>(vec[1]) == false); + + // copy to host + std::vector<bool> host_vec(vec.size()); + compute::copy(vec.begin(), vec.end(), host_vec.begin(), queue); + BOOST_CHECK(host_vec[0] == true); + BOOST_CHECK(host_vec[1] == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_copy_if.cpp b/src/boost/libs/compute/test/test_copy_if.cpp new file mode 100644 index 00000000..2a65bb08 --- /dev/null +++ b/src/boost/libs/compute/test/test_copy_if.cpp @@ -0,0 +1,119 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestCopyIf +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/copy_if.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(copy_if_int) +{ + int data[] = { 1, 6, 3, 5, 8, 2, 4 }; + bc::vector<int> input(data, data + 7, queue); + + bc::vector<int> output(input.size(), context); + bc::fill(output.begin(), output.end(), -1, queue); + + using ::boost::compute::_1; + + bc::vector<int>::iterator iter = + bc::copy_if(input.begin(), input.end(), + output.begin(), _1 < 5, queue); + BOOST_VERIFY(iter == output.begin() + 4); + CHECK_RANGE_EQUAL(int, 7, output, (1, 3, 2, 4, -1, -1, -1)); + + bc::fill(output.begin(), output.end(), 42, queue); + iter = + bc::copy_if(input.begin(), input.end(), + output.begin(), _1 * 2 >= 10, queue); + BOOST_VERIFY(iter == output.begin() + 3); + CHECK_RANGE_EQUAL(int, 7, output, (6, 5, 8, 42, 42, 42, 42)); +} + +BOOST_AUTO_TEST_CASE(copy_if_odd) +{ + int data[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 5 }; + bc::vector<int> input(data, data + 10, queue); + + using ::boost::compute::_1; + + bc::vector<int> odds(input.size(), context); + bc::vector<int>::iterator odds_end = + bc::copy_if(input.begin(), input.end(), + odds.begin(), _1 % 2 == 1, queue); + BOOST_CHECK(odds_end == odds.begin() + 6); + CHECK_RANGE_EQUAL(int, 6, odds, (1, 3, 5, 1, 3, 5)); + + bc::vector<int> evens(input.size(), context); + bc::vector<int>::iterator evens_end = + bc::copy_if(input.begin(), input.end(), + evens.begin(), _1 % 2 == 0, queue); + BOOST_CHECK(evens_end == evens.begin() + 4); + CHECK_RANGE_EQUAL(int, 4, evens, (2, 4, 2, 4)); +} + +BOOST_AUTO_TEST_CASE(clip_points_below_plane) +{ + float data[] = { 1.0f, 2.0f, 3.0f, 0.0f, + -1.0f, 2.0f, 3.0f, 0.0f, + -2.0f, -3.0f, 4.0f, 0.0f, + 4.0f, -3.0f, 2.0f, 0.0f }; + bc::vector<bc::float4_> points(reinterpret_cast<bc::float4_ *>(data), + reinterpret_cast<bc::float4_ *>(data) + 4, + queue); + + // create output vector filled with (0, 0, 0, 0) + bc::vector<bc::float4_> output(points.size(), context); + bc::fill(output.begin(), output.end(), + bc::float4_(0.0f, 0.0f, 0.0f, 0.0f), queue); + + // define the plane (at origin, +X normal) + bc::float4_ plane_origin(0.0f, 0.0f, 0.0f, 0.0f); + bc::float4_ plane_normal(1.0f, 0.0f, 0.0f, 0.0f); + + using ::boost::compute::_1; + using ::boost::compute::lambda::dot; + + bc::vector<bc::float4_>::const_iterator iter = + bc::copy_if(points.begin(), + points.end(), + output.begin(), + dot(_1 - plane_origin, plane_normal) > 0.0f, + queue); + BOOST_CHECK(iter == output.begin() + 2); +} + +BOOST_AUTO_TEST_CASE(copy_index_if_int) +{ + int data[] = { 1, 6, 3, 5, 8, 2, 4 }; + compute::vector<int> input(data, data + 7, queue); + + compute::vector<int> output(input.size(), context); + compute::fill(output.begin(), output.end(), -1, queue); + + using ::boost::compute::_1; + using ::boost::compute::detail::copy_index_if; + + compute::vector<int>::iterator iter = + copy_index_if(input.begin(), input.end(), output.begin(), + _1 < 5, queue); + BOOST_VERIFY(iter == output.begin() + 4); + CHECK_RANGE_EQUAL(int, 7, output, (0, 2, 5, 6, -1, -1, -1)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_copy_type_mismatch.cpp b/src/boost/libs/compute/test/test_copy_type_mismatch.cpp new file mode 100644 index 00000000..49305a6d --- /dev/null +++ b/src/boost/libs/compute/test/test_copy_type_mismatch.cpp @@ -0,0 +1,1380 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2016 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +// Undefining BOOST_COMPUTE_USE_OFFLINE_CACHE macro as we want to modify cached +// parameters for copy algorithm without any undesirable consequences (like +// saving modified values of those parameters). +#ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE + #undef BOOST_COMPUTE_USE_OFFLINE_CACHE +#endif + +#define BOOST_TEST_MODULE TestCopyTypeMismatch +#include <boost/test/unit_test.hpp> + +#include <list> +#include <vector> +#include <string> +#include <sstream> +#include <iterator> +#include <iostream> + +#include <boost/compute/svm.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/async/future.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/detail/device_ptr.hpp> +#include <boost/compute/memory/svm_ptr.hpp> +#include <boost/compute/detail/parameter_cache.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(is_same_ignore_const) +{ + BOOST_STATIC_ASSERT(( + boost::compute::detail::is_same_value_type< + std::vector<int>::iterator, + compute::buffer_iterator<int> + >::value + )); + BOOST_STATIC_ASSERT(( + boost::compute::detail::is_same_value_type< + std::vector<int>::const_iterator, + compute::buffer_iterator<int> + >::value + )); + BOOST_STATIC_ASSERT(( + boost::compute::detail::is_same_value_type< + std::vector<int>::iterator, + compute::buffer_iterator<const int> + >::value + )); + BOOST_STATIC_ASSERT(( + boost::compute::detail::is_same_value_type< + std::vector<int>::const_iterator, + compute::buffer_iterator<const int> + >::value + )); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_double) +{ + if(!device.supports_extension("cl_khr_fp64")) { + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + using compute::double_; + using compute::float_; + + float_ host[] = { 6.1f, 10.2f, 19.3f, 25.4f }; + bc::vector<double_> device_vector(4, context); + + // copy host float data to double device vector + bc::copy(host, host + 4, device_vector.begin(), queue); + CHECK_RANGE_EQUAL(double_, 4, device_vector, (6.1f, 10.2f, 19.3f, 25.4f)); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + bc::copy(host, host + 4, device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +// HOST -> DEVICE + +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int_mapping_device_vector) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(4, context); + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_device_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + // copy host float data to int device vector + bc::copy(host, host + 4, device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int_convert_on_host) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by casting input data on host and performing + // normal copy host->device (since types match now) + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + bc::copy(host, host + 4, device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int_with_transform) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by mapping input data to the device memory + // and using transform operation for casting & copying + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 0); + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + bc::copy(host, host + 4, device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_async_to_device_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + compute::future<void> future = + bc::copy_async(host, host + 4, device_vector.begin(), queue); + future.wait(); + + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +BOOST_AUTO_TEST_CASE(copy_async_to_device_float_to_int_empty) +{ + using compute::int_; + using compute::float_; + + float_ host[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<int_> device_vector(size_t(4), int_(1), queue); + + // copy nothing to int device vector + compute::future<bc::vector<int_>::iterator > future = + bc::copy_async(host, host, device_vector.begin(), queue); + if(future.valid()) { + future.wait(); + } + + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + int_(1), + int_(1), + int_(1), + int_(1) + ) + ); +} + +// Test copying from a std::list to a bc::vector. This differs from +// the test copying from std::vector because std::list has non-contiguous +// storage for its data values. +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int_list_device_map) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_device_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + std::list<float_> host(data, data + 4); + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + bc::copy(host.begin(), host.end(), device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +// Test copying from a std::list to a bc::vector. This differs from +// the test copying from std::vector because std::list has non-contiguous +// storage for its data values. +BOOST_AUTO_TEST_CASE(copy_to_device_float_to_int_list_convert_on_host) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by casting input data on host and performing + // normal copy host->device (since types match now) + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + std::list<float_> host(data, data + 4); + bc::vector<int_> device_vector(4, context); + + // copy host float data to int device vector + bc::copy(host.begin(), host.end(), device_vector.begin(), queue); + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +// SVM requires OpenCL 2.0 +#if defined(BOOST_COMPUTE_CL_VERSION_2_0) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) +BOOST_AUTO_TEST_CASE(copy_to_device_svm_float_to_int_map) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_device_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + float_ host[] = { 5.1f, -10.3f, 19.4f, 26.7f }; + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int device vector + bc::copy(host, host + 4, ptr, queue); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(5.1f), + static_cast<int_>(-10.3f), + static_cast<int_>(19.4f), + static_cast<int_>(26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_svm_float_to_int_convert_on_host) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + if(bug_in_svmmemcpy(device)){ + std::cerr << "skipping svmmemcpy test case" << std::endl; + return; + } + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by casting input data on host and performing + // normal copy host->device (since types match now) + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ host[] = { 0.1f, 10.3f, 9.4f, -26.7f }; + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int device vector + bc::copy(host, host + 4, ptr, queue); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(0.1f), + static_cast<int_>(10.3f), + static_cast<int_>(9.4f), + static_cast<int_>(-26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_device_svm_float_to_int_with_transform) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_device_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by mapping input data to the device memory + // and using transform operation (copy kernel) for casting & copying + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 0); + + float_ host[] = { 4.1f, -11.3f, 219.4f, -26.7f }; + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int device vector + bc::copy(host, host + 4, ptr, queue); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(4.1f), + static_cast<int_>(-11.3f), + static_cast<int_>(219.4f), + static_cast<int_>(-26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_async_to_device_svm_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::uint_; + using compute::float_; + + float_ host[] = { 44.1f, -14.3f, 319.4f, -26.7f }; + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int device vector + compute::future<void> future = + bc::copy_async(host, host + 4, ptr, queue); + future.wait(); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(44.1f), + static_cast<int_>(-14.3f), + static_cast<int_>(319.4f), + static_cast<int_>(-26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); +} +#endif + +// DEVICE -> DEVICE + +BOOST_AUTO_TEST_CASE(copy_on_device_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_fvector(data, data + 4, queue); + bc::vector<int_> device_ivector(4, context); + + // copy device float vector to device int vector + bc::copy( + device_fvector.begin(), + device_fvector.end(), + device_ivector.begin(), + queue + ); + + CHECK_RANGE_EQUAL( + int_, + 4, + device_ivector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +BOOST_AUTO_TEST_CASE(copy_async_on_device_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_fvector(data, data + 4, queue); + bc::vector<int_> device_ivector(4, context); + + // copy device float vector to device int vector + compute::future<void> future = + bc::copy_async( + device_fvector.begin(), + device_fvector.end(), + device_ivector.begin(), + queue + ); + future.wait(); + + CHECK_RANGE_EQUAL( + int_, + 4, + device_ivector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +BOOST_AUTO_TEST_CASE(copy_async_on_device_float_to_int_empty) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_fvector(data, data + 4, queue); + bc::vector<int_> device_ivector(size_t(4), int_(1), queue); + + // copy device float vector to device int vector + compute::future<void> future = + bc::copy_async( + device_fvector.begin(), + device_fvector.begin(), + device_ivector.begin(), + queue + ); + if(future.valid()) { + future.wait(); + } + + CHECK_RANGE_EQUAL( + int_, + 4, + device_ivector, + ( + int_(1), + int_(1), + int_(1), + int_(1) + ) + ); +} + +// SVM requires OpenCL 2.0 +#if defined(BOOST_COMPUTE_CL_VERSION_2_0) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) +BOOST_AUTO_TEST_CASE(copy_on_device_buffer_to_svm_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 65.1f, -110.2f, -19.3f, 26.7f }; + bc::vector<float_> device_vector(data, data + 4, queue); + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int svm memory + bc::copy(device_vector.begin(), device_vector.end(), ptr, queue); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(65.1f), + static_cast<int_>(-110.2f), + static_cast<int_>(-19.3f), + static_cast<int_>(26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(copy_on_device_svm_to_buffer_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, 11.2f, 19.3f, 6.7f }; + bc::vector<int_> device_vector(4, context); + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm data to int device vector + bc::copy(ptr, ptr + 4, device_vector.begin(), queue); + + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(6.1f), + static_cast<int_>(11.2f), + static_cast<int_>(19.3f), + static_cast<int_>(6.7f) + ) + ); + + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(copy_on_device_svm_to_svm_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 0.1f, -10.2f, -1.3f, 2.7f }; + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + compute::svm_ptr<int_> ptr2 = compute::svm_alloc<int_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm to int svm + bc::copy(ptr, ptr + 4, ptr2, queue); + + queue.enqueue_svm_map(ptr2.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr2.get()), + ( + static_cast<int_>(0.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(-1.3f), + static_cast<int_>(2.7f) + ) + ); + queue.enqueue_svm_unmap(ptr2.get()).wait(); + + compute::svm_free(context, ptr); + compute::svm_free(context, ptr2); +} + +BOOST_AUTO_TEST_CASE(copy_async_on_device_buffer_to_svm_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 65.1f, -110.2f, -19.3f, 26.7f }; + bc::vector<float_> device_vector(data, data + 4, queue); + compute::svm_ptr<int_> ptr = compute::svm_alloc<int_>(context, 4); + + // copy host float data to int svm memory + compute::future<bc::svm_ptr<int_> > future = + bc::copy_async(device_vector.begin(), device_vector.end(), ptr, queue); + future.wait(); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr.get()), + ( + static_cast<int_>(65.1f), + static_cast<int_>(-110.2f), + static_cast<int_>(-19.3f), + static_cast<int_>(26.7f) + ) + ); + queue.enqueue_svm_unmap(ptr.get()).wait(); + + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(copy_async_on_device_svm_to_buffer_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 65.1f, -110.2f, -19.3f, 26.7f }; + bc::vector<int_> device_vector(4, context); + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm data to int device vector + compute::future<bc::vector<int_>::iterator > future = + bc::copy_async(ptr, ptr + 4, device_vector.begin(), queue); + future.wait(); + + CHECK_RANGE_EQUAL( + int_, + 4, + device_vector, + ( + static_cast<int_>(65.1f), + static_cast<int_>(-110.2f), + static_cast<int_>(-19.3f), + static_cast<int_>(26.7f) + ) + ); + + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(copy_async_on_device_svm_to_svm_float_to_int) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::float_; + + float_ data[] = { 0.1f, -10.2f, -1.3f, 2.7f }; + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + compute::svm_ptr<int_> ptr2 = compute::svm_alloc<int_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm to int svm + compute::future<bc::svm_ptr<int_> > future = + bc::copy_async(ptr, ptr + 4, ptr2, queue); + future.wait(); + + queue.enqueue_svm_map(ptr2.get(), 4 * sizeof(cl_int), CL_MAP_READ); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + static_cast<int_*>(ptr2.get()), + ( + static_cast<int_>(0.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(-1.3f), + static_cast<int_>(2.7f) + ) + ); + queue.enqueue_svm_unmap(ptr2.get()).wait(); + + compute::svm_free(context, ptr); + compute::svm_free(context, ptr2); +} +#endif + +// DEVICE -> HOST + +BOOST_AUTO_TEST_CASE(copy_to_host_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::vector<int_> host_vector(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_vector.begin(), queue); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +BOOST_AUTO_TEST_CASE(copy_to_host_float_to_int_map) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_host_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::vector<int_> host_vector(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_vector.begin(), queue); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_host_float_to_int_convert_on_host) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by copying input device vector to temporary + // host vector of the same type and then copying from that temporary + // vector to result using std::copy() + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::vector<int_> host_vector(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_vector.begin(), queue); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_host_float_to_int_convert_on_device) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by mapping output data to the device memory + // and using transform operation for casting & copying + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 0); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::vector<int_> host_vector(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_vector.begin(), queue); + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +// Test copying from a bc::vector to a std::list . This differs from +// the test copying to std::vector because std::list has non-contiguous +// storage for its data values. +BOOST_AUTO_TEST_CASE(copy_to_host_list_float_to_int_map) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_host_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::list<int_> host_list(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_list.begin(), queue); + + int_ expected[4] = { + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + }; + BOOST_CHECK_EQUAL_COLLECTIONS( + host_list.begin(), host_list.end(), + expected, expected + 4 + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +// Test copying from a bc::vector to a std::list . This differs from +// the test copying to std::vector because std::list has non-contiguous +// storage for its data values. +BOOST_AUTO_TEST_CASE(copy_to_host_list_float_to_int_covert_on_host) +{ + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by copying input device vector to temporary + // host vector of the same type and then copying from that temporary + // vector to result using std::copy() + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + + std::list<int_> host_list(4); + // copy device float vector to int host vector + bc::copy(device_vector.begin(), device_vector.end(), host_list.begin(), queue); + int_ expected[4] = { + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + }; + BOOST_CHECK_EQUAL_COLLECTIONS( + host_list.begin(), host_list.end(), + expected, expected + 4 + ); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_async_to_host_float_to_int) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + std::vector<int_> host_vector(device_vector.size()); + + // copy device float vector to host int vector + compute::future<void> future = + bc::copy_async( + device_vector.begin(), + device_vector.end(), + host_vector.begin(), + queue + ); + future.wait(); + + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(-10.2f), + static_cast<int_>(19.3f), + static_cast<int_>(25.4f) + ) + ); +} + +BOOST_AUTO_TEST_CASE(copy_async_to_host_float_to_int_empty) +{ + using compute::int_; + using compute::float_; + + float_ data[] = { 6.1f, -10.2f, 19.3f, 25.4f }; + bc::vector<float_> device_vector(data, data + 4, queue); + std::vector<int_> host_vector(device_vector.size(), int_(1)); + + // copy device float vector to host int vector + compute::future<void> future = + bc::copy_async( + device_vector.begin(), + device_vector.begin(), + host_vector.begin(), + queue + ); + if(future.valid()) { + future.wait(); + } + + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + int_(1), + int_(1), + int_(1), + int_(1) + ) + ); +} + +// SVM requires OpenCL 2.0 +#if defined(BOOST_COMPUTE_CL_VERSION_2_0) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) +BOOST_AUTO_TEST_CASE(copy_to_host_svm_float_to_int_map) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + + // force copy_to_host_map (mapping device vector to the host) + parameters->set(cache_key, "map_copy_threshold", 1024); + + float_ data[] = { 6.1f, 1.2f, 1.3f, -66.7f }; + std::vector<int_> host_vector(4, 0); + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm data to int host vector + bc::copy(ptr, ptr + 4, host_vector.begin(), queue); + + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(1.2f), + static_cast<int_>(1.3f), + static_cast<int_>(-66.7f) + ) + ); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_host_svm_float_to_int_convert_on_host) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + if(bug_in_svmmemcpy(device)){ + std::cerr << "skipping svmmemcpy test case" << std::endl; + return; + } + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by copying input device vector to temporary + // host vector of the same type and then copying from that temporary + // vector to result using std::copy() + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 1024); + + float_ data[] = { 6.1f, 1.2f, 1.3f, 766.7f }; + std::vector<int_> host_vector(4, 0); + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm data to int host vector + bc::copy(ptr, ptr + 4, host_vector.begin(), queue); + + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(6.1f), + static_cast<int_>(1.2f), + static_cast<int_>(1.3f), + static_cast<int_>(766.7f) + ) + ); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(copy_to_host_svm_float_to_int_transform) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + using compute::int_; + using compute::uint_; + using compute::float_; + + std::string cache_key = + std::string("__boost_compute_copy_to_host_float_int"); + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "map_copy_threshold", 0); + uint_ direct_copy_threshold = + parameters->get(cache_key, "direct_copy_threshold", 0); + + // force copying by copying input device vector to temporary + // host vector of the same type and then copying from that temporary + // vector to result using std::copy() + parameters->set(cache_key, "map_copy_threshold", 0); + parameters->set(cache_key, "direct_copy_threshold", 0); + + float_ data[] = { 0.1f, 11.2f, 1.3f, -66.7f }; + std::vector<int_> host_vector(4, 0); + compute::svm_ptr<float_> ptr = compute::svm_alloc<float_>(context, 4); + + queue.enqueue_svm_map(ptr.get(), 4 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 4; i++) { + static_cast<float_*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()).wait(); + + // copy host float svm data to int host vector + bc::copy(ptr, ptr + 4, host_vector.begin(), queue); + + CHECK_HOST_RANGE_EQUAL( + int_, + 4, + host_vector.begin(), + ( + static_cast<int_>(0.1f), + static_cast<int_>(11.2f), + static_cast<int_>(1.3f), + static_cast<int_>(-66.7f) + ) + ); + + compute::svm_free(context, ptr); + + // restore + parameters->set(cache_key, "map_copy_threshold", map_copy_threshold); + parameters->set(cache_key, "direct_copy_threshold", direct_copy_threshold); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_count.cpp b/src/boost/libs/compute/test/test_count.cpp new file mode 100644 index 00000000..d1fb3aea --- /dev/null +++ b/src/boost/libs/compute/test/test_count.cpp @@ -0,0 +1,221 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestCount +#include <boost/test/unit_test.hpp> + +#include <string> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/count.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_iterator.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(count_int) +{ + int data[] = { 1, 2, 1, 2, 3 }; + bc::vector<int> vector(data, data + 5, queue); + BOOST_CHECK_EQUAL(bc::count(vector.begin(), vector.end(), 1, queue), size_t(2)); + BOOST_CHECK_EQUAL(bc::count(vector.begin(), vector.end(), 2, queue), size_t(2)); + BOOST_CHECK_EQUAL(bc::count(vector.begin(), vector.end(), 3, queue), size_t(1)); + BOOST_CHECK_EQUAL(bc::count(vector.begin() + 1, vector.end(), 1, queue), size_t(1)); + BOOST_CHECK_EQUAL(bc::count(vector.begin() + 1, vector.end() - 1, 3, queue), size_t(0)); + BOOST_CHECK_EQUAL(bc::count(vector.begin() + 1, vector.end() - 1, 2, queue), size_t(2)); +} + +BOOST_AUTO_TEST_CASE(count_constant_int_range) +{ + BOOST_CHECK_EQUAL( + bc::count(bc::make_constant_iterator(18, 0), + bc::make_constant_iterator(18, 5), + 18, + queue), + size_t(5) + ); + + BOOST_CHECK_EQUAL( + bc::count(bc::make_constant_iterator(19, 0), + bc::make_constant_iterator(19, 5), + 18, + queue), + size_t(0) + ); +} + +BOOST_AUTO_TEST_CASE(count_if_greater_than_two) +{ + float data[] = { 1.0f, 2.5f, -1.0f, 3.0f, 5.0f, -8.0f }; + bc::vector<float> vector(data, data + 5, queue); + + BOOST_CHECK_EQUAL( + bc::count_if(vector.begin(), vector.end(), bc::_1 > 2.0f, queue), + size_t(3) + ); +} + +BOOST_AUTO_TEST_CASE(count_int4) +{ + int data[] = { 1, 2, 3, 4, + 4, 5, 6, 7, + 7, 8, 9, 1, + 1, 2, 3, 4, + 4, 5, 6, 7, + 0, 3, 2, 2 }; + bc::vector<bc::int4_> vector(reinterpret_cast<bc::int4_ *>(data), + reinterpret_cast<bc::int4_ *>(data) + 6, + queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(6)); + + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(1, 2, 3, 4), queue), + size_t(2) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(4, 5, 6, 7), queue), + size_t(2) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(7, 8, 9, 1), queue), + size_t(1) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(0, 3, 2, 2), queue), + size_t(1) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(3, 4, 4, 5), queue), + size_t(0) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(1, 2, 3, 0), queue), + size_t(0) + ); + BOOST_CHECK_EQUAL( + bc::count(vector.begin(), vector.end(), bc::int4_(1, 9, 8, 7), queue), + size_t(0) + ); +} + +BOOST_AUTO_TEST_CASE(count_newlines) +{ + std::string string = "abcdefg\nhijklmn\nopqrs\ntuv\nwxyz\n"; + compute::vector<char> data(string.size(), context); + compute::copy(string.begin(), string.end(), data.begin(), queue); + + BOOST_CHECK_EQUAL( + compute::count(data.begin(), data.end(), '\n', queue), + size_t(5) + ); +} + +BOOST_AUTO_TEST_CASE(count_uchar) +{ + using boost::compute::uchar_; + + unsigned char data[] = { 0x00, 0x10, 0x2F, 0x10, 0x01, 0x00, 0x01, 0x00 }; + compute::vector<uchar_> vector(8, context); + compute::copy(data, data + 8, vector.begin(), queue); + + BOOST_CHECK_EQUAL( + compute::count(vector.begin(), vector.end(), 0x00, queue), + size_t(3) + ); + BOOST_CHECK_EQUAL( + compute::count(vector.begin(), vector.end(), 0x10, queue), + size_t(2) + ); + BOOST_CHECK_EQUAL( + compute::count(vector.begin(), vector.end(), 0x2F, queue), + size_t(1) + ); + BOOST_CHECK_EQUAL( + compute::count(vector.begin(), vector.end(), 0x01, queue), + size_t(2) + ); + BOOST_CHECK_EQUAL( + compute::count(vector.begin(), vector.end(), 0xFF, queue), + size_t(0) + ); +} + +BOOST_AUTO_TEST_CASE(count_vector_component) +{ + int data[] = { + 1, 2, + 3, 4, + 5, 6, + 7, 8 + }; + + using boost::compute::int2_; + + compute::vector<int2_> vector(4, context); + compute::copy( + reinterpret_cast<int2_ *>(data), + reinterpret_cast<int2_ *>(data) + 4, + vector.begin(), + queue + ); + + using boost::compute::lambda::_1; + using boost::compute::lambda::get; + + BOOST_CHECK_EQUAL( + compute::count_if(vector.begin(), vector.end(), get<0>(_1) < 4, queue), + size_t(2) + ); + BOOST_CHECK_EQUAL( + compute::count_if(vector.begin(), vector.end(), get<1>(_1) > 3, queue), + size_t(3) + ); +} + +BOOST_AUTO_TEST_CASE(count_if_odd) +{ + compute::vector<int> vec(2048, context); + compute::iota(vec.begin(), vec.end(), 0, queue); + + BOOST_COMPUTE_FUNCTION(bool, is_odd, (int x), + { + return x & 1; + }); + + BOOST_CHECK_EQUAL( + compute::count_if(vec.begin(), vec.end(), is_odd, queue), vec.size() / 2 + ); +} + +BOOST_AUTO_TEST_CASE(count_if_with_reduce) +{ + compute::vector<int> vec(2048, context); + compute::iota(vec.begin(), vec.end(), 0, queue); + + using boost::compute::lambda::_1; + + BOOST_CHECK_EQUAL( + compute::detail::count_if_with_reduce( + vec.begin(), vec.end(), _1 > 1024, queue + ), + size_t(1023) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_counting_iterator.cpp b/src/boost/libs/compute/test/test_counting_iterator.cpp new file mode 100644 index 00000000..46c24ad4 --- /dev/null +++ b/src/boost/libs/compute/test/test_counting_iterator.cpp @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestCountingIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::counting_iterator<int>::value_type, + int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::counting_iterator<float>::value_type, + float + >::value + )); +} + +BOOST_AUTO_TEST_CASE(distance) +{ + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_counting_iterator(0), + boost::compute::make_counting_iterator(10) + ), + std::ptrdiff_t(10) + ); + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_counting_iterator(5), + boost::compute::make_counting_iterator(10) + ), + std::ptrdiff_t(5) + ); + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_counting_iterator(-5), + boost::compute::make_counting_iterator(5) + ), + std::ptrdiff_t(10) + ); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + boost::compute::vector<int> vector(10, context); + + boost::compute::copy( + boost::compute::make_counting_iterator(1), + boost::compute::make_counting_iterator(11), + vector.begin(), + queue + ); + CHECK_RANGE_EQUAL( + int, 10, vector, + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + ); +} + +BOOST_AUTO_TEST_CASE(iota_with_copy_doctest) +{ +//! [iota_with_copy] +using boost::compute::make_counting_iterator; + +boost::compute::vector<int> result(5, context); + +boost::compute::copy( + make_counting_iterator(1), make_counting_iterator(6), result.begin(), queue +); + +// result == { 1, 2, 3, 4, 5 } +//! [iota_with_copy] + + CHECK_RANGE_EQUAL(int, 5, result, (1, 2, 3, 4, 5)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_device.cpp b/src/boost/libs/compute/test/test_device.cpp new file mode 100644 index 00000000..bc370c1e --- /dev/null +++ b/src/boost/libs/compute/test/test_device.cpp @@ -0,0 +1,293 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestDevice +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/device.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/detail/nvidia_compute_capability.hpp> + +#include "opencl_version_check.hpp" + +BOOST_AUTO_TEST_CASE(null_device) +{ + boost::compute::device null; + BOOST_CHECK(null.id() == cl_device_id()); + BOOST_CHECK(null.get() == cl_device_id()); +} + +BOOST_AUTO_TEST_CASE(default_device_doctest) +{ +//! [default_gpu] +boost::compute::device gpu = boost::compute::system::default_device(); +//! [default_gpu] + + BOOST_CHECK(gpu.id()); +} + +BOOST_AUTO_TEST_CASE(device_platform) +{ + boost::compute::platform p = boost::compute::system::platforms().at(0); + BOOST_CHECK(p == p.devices().at(0).platform()); +} + +BOOST_AUTO_TEST_CASE(get_device_name) +{ + boost::compute::device gpu = boost::compute::system::default_device(); + if(gpu.id()){ + BOOST_CHECK(!gpu.name().empty()); + } +} + +BOOST_AUTO_TEST_CASE(equality_operator) +{ + boost::compute::device device1 = boost::compute::system::default_device(); + BOOST_CHECK(device1 == device1); + + boost::compute::device device2 = device1; + BOOST_CHECK(device1 == device2); +} + +BOOST_AUTO_TEST_CASE(get_max_work_item_sizes) +{ + boost::compute::device device = boost::compute::system::default_device(); + + std::vector<size_t> max_work_item_sizes = + device.get_info<std::vector<size_t> >(CL_DEVICE_MAX_WORK_ITEM_SIZES); + BOOST_CHECK_GE(max_work_item_sizes.size(), size_t(3)); + BOOST_CHECK_GE(max_work_item_sizes[0], size_t(1)); + BOOST_CHECK_GE(max_work_item_sizes[1], size_t(1)); + BOOST_CHECK_GE(max_work_item_sizes[2], size_t(1)); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_2 + +// returns true if the device supports the partitioning type +bool supports_partition_type(const boost::compute::device &device, + cl_device_partition_property type) +{ + const std::vector<cl_device_partition_property> properties = + device.get_info<std::vector<cl_device_partition_property> >( + CL_DEVICE_PARTITION_PROPERTIES + ); + + return std::find(properties.begin(), + properties.end(), + type) != properties.end(); +} + +BOOST_AUTO_TEST_CASE(partition_device_equally) +{ + // get default device and ensure it has at least two compute units + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(1,2); + + if(device.compute_units() < 2){ + std::cout << "skipping test: " + << "device does not have enough compute units" + << std::endl; + return; + } + + // check that the device supports partitioning equally + if(!supports_partition_type(device, CL_DEVICE_PARTITION_EQUALLY)){ + std::cout << "skipping test: " + << "device does not support CL_DEVICE_PARTITION_EQUALLY" + << std::endl; + return; + } + + // ensure device is not a sub-device + BOOST_CHECK(device.is_subdevice() == false); + + // partition default device into sub-devices with one compute unit each + std::vector<boost::compute::device> + sub_devices = device.partition_equally(1); + BOOST_CHECK_EQUAL(sub_devices.size(), size_t(device.compute_units())); + + // verify each of the sub-devices + for(size_t i = 0; i < sub_devices.size(); i++){ + const boost::compute::device &sub_device = sub_devices[i]; + + // ensure parent device id is correct + cl_device_id parent_id = + sub_device.get_info<cl_device_id>(CL_DEVICE_PARENT_DEVICE); + BOOST_CHECK(parent_id == device.id()); + + // ensure device is a sub-device + BOOST_CHECK(sub_device.is_subdevice() == true); + + // check number of compute units + BOOST_CHECK_EQUAL(sub_device.compute_units(), size_t(1)); + } +} + +// used to sort devices by number of compute units +bool compare_compute_units(const boost::compute::device &a, + const boost::compute::device &b) +{ + return a.compute_units() < b.compute_units(); +} + +BOOST_AUTO_TEST_CASE(partition_by_counts) +{ + // get default device and ensure it has at least four compute units + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(1,2); + + if(device.compute_units() < 4){ + std::cout << "skipping test: " + << "device does not have enough compute units" + << std::endl; + return; + } + + // check that the device supports partitioning by counts + if(!supports_partition_type(device, CL_DEVICE_PARTITION_BY_COUNTS)){ + std::cout << "skipping test: " + << "device does not support CL_DEVICE_PARTITION_BY_COUNTS" + << std::endl; + return; + } + + // ensure device is not a sub-device + BOOST_CHECK(device.is_subdevice() == false); + + // create vector of sub-device compute unit counts + std::vector<size_t> counts; + counts.push_back(2); + counts.push_back(1); + counts.push_back(1); + + // partition default device into sub-devices according to counts + std::vector<boost::compute::device> + sub_devices = device.partition_by_counts(counts); + BOOST_CHECK_EQUAL(sub_devices.size(), size_t(3)); + + // sort sub-devices by number of compute units (see issue #185) + std::sort(sub_devices.begin(), sub_devices.end(), compare_compute_units); + + // verify each of the sub-devices + BOOST_CHECK_EQUAL(sub_devices[0].compute_units(), size_t(1)); + BOOST_CHECK_EQUAL(sub_devices[1].compute_units(), size_t(1)); + BOOST_CHECK_EQUAL(sub_devices[2].compute_units(), size_t(2)); +} + +BOOST_AUTO_TEST_CASE(partition_by_affinity_domain) +{ + // get default device and ensure it has at least two compute units + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(1,2); + + if(device.compute_units() < 2){ + std::cout << "skipping test: " + << "device does not have enough compute units" + << std::endl; + return; + } + + // check that the device supports splitting by affinity domains + if(!supports_partition_type(device, CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE)){ + std::cout << "skipping test: " + << "device does not support partitioning by affinity domain" + << std::endl; + return; + } + + // ensure device is not a sub-device + BOOST_CHECK(device.is_subdevice() == false); + + std::vector<boost::compute::device> sub_devices = + device.partition_by_affinity_domain( + CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE); + BOOST_CHECK(sub_devices.size() > 0); + BOOST_CHECK(sub_devices[0].is_subdevice() == true); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_2 + +BOOST_AUTO_TEST_CASE(nvidia_compute_capability) +{ + boost::compute::device device = boost::compute::system::default_device(); + int major, minor; + boost::compute::detail::get_nvidia_compute_capability(device, major, minor); + boost::compute::detail::check_nvidia_compute_capability(device, 3, 0); +} + +BOOST_AUTO_TEST_CASE(get_info_specializations) +{ + boost::compute::device device = boost::compute::system::default_device(); + + std::cout << device.get_info<CL_DEVICE_NAME>() << std::endl; +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(get_host_timer) +{ + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(2, 1); + + BOOST_CHECK(device.get_host_timer() != 0); + + #ifndef BOOST_COMPUTE_NO_HDR_CHRONO + typedef std::chrono::milliseconds stdms; + BOOST_CHECK(device.get_host_timer<stdms>().count() != 0); + #endif + + #ifndef BOOST_COMPUTE_NO_BOOST_CHRONO + typedef boost::chrono::milliseconds bms; + BOOST_CHECK(device.get_host_timer<bms>().count() != 0); + #endif +} + +BOOST_AUTO_TEST_CASE(get_device_and_host_timer) +{ + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(2, 1); + + typedef std::pair<boost::compute::ulong_, boost::compute::ulong_> dah_timer; + dah_timer timer; + BOOST_CHECK_NO_THROW(timer = device.get_device_and_host_timer()); + BOOST_CHECK(timer.first != 0); + BOOST_CHECK(timer.second != 0); + + #ifndef BOOST_COMPUTE_NO_HDR_CHRONO + typedef std::chrono::milliseconds stdms; + BOOST_CHECK(device.get_device_and_host_timer<stdms>().first.count() != 0); + BOOST_CHECK(device.get_device_and_host_timer<stdms>().second.count() != 0); + #endif + + #ifndef BOOST_COMPUTE_NO_BOOST_CHRONO + typedef boost::chrono::milliseconds bms; + BOOST_CHECK(device.get_device_and_host_timer<bms>().first.count() != 0); + BOOST_CHECK(device.get_device_and_host_timer<bms>().second.count() != 0); + #endif +} + +BOOST_AUTO_TEST_CASE(get_info_opencl21_queries) +{ + boost::compute::device device = boost::compute::system::default_device(); + + REQUIRES_OPENCL_VERSION(2, 1); + + BOOST_CHECK(!device.get_info<CL_DEVICE_IL_VERSION>().empty()); + BOOST_CHECK(device.get_info<CL_DEVICE_MAX_NUM_SUB_GROUPS>() > 0); + BOOST_CHECK_NO_THROW( + device.get_info<CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS>() + ); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_1 diff --git a/src/boost/libs/compute/test/test_discard_iterator.cpp b/src/boost/libs/compute/test/test_discard_iterator.cpp new file mode 100644 index 00000000..94a3d700 --- /dev/null +++ b/src/boost/libs/compute/test/test_discard_iterator.cpp @@ -0,0 +1,94 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestDiscardIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/copy_if.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/discard_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::discard_iterator::value_type, void + >::value + )); +} + +BOOST_AUTO_TEST_CASE(distance) +{ + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_discard_iterator(0), + boost::compute::make_discard_iterator(10) + ), + std::ptrdiff_t(10) + ); + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_discard_iterator(5), + boost::compute::make_discard_iterator(10) + ), + std::ptrdiff_t(5) + ); +} + +BOOST_AUTO_TEST_CASE(discard_copy) +{ + boost::compute::vector<int> vector(10, context); + boost::compute::fill(vector.begin(), vector.end(), 42, queue); + + boost::compute::copy( + vector.begin(), vector.end(), + boost::compute::make_discard_iterator(), + queue + ); +} + +BOOST_AUTO_TEST_CASE(discard_copy_if) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::vector<int> vector(data, data + 8, queue); + + using boost::compute::lambda::_1; + + boost::compute::discard_iterator end = boost::compute::copy_if( + vector.begin(), vector.end(), + boost::compute::make_discard_iterator(), + _1 > 4, + queue + ); + BOOST_CHECK(std::distance(boost::compute::discard_iterator(), end) == 4); +} + +BOOST_AUTO_TEST_CASE(discard_fill) +{ + boost::compute::fill( + boost::compute::make_discard_iterator(0), + boost::compute::make_discard_iterator(100), + 42, + queue + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_discrete_distribution.cpp b/src/boost/libs/compute/test/test_discrete_distribution.cpp new file mode 100644 index 00000000..6c4b8d71 --- /dev/null +++ b/src/boost/libs/compute/test/test_discrete_distribution.cpp @@ -0,0 +1,237 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestDiscreteDistribution +#include <boost/test/unit_test.hpp> + +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/discrete_distribution.hpp> +#include <boost/compute/lambda.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(discrete_distribution_doctest) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + boost::compute::vector<uint_> vec(100, context); + +//! [generate] +// initialize the default random engine +boost::compute::default_random_engine engine(queue); + +// initialize weights +int weights[] = {2, 2}; + +// setup the discrete distribution to produce integers 0 and 1 +// with equal weights +boost::compute::discrete_distribution<uint_> distribution(weights, weights+2); + +// generate the random values and store them to 'vec' +distribution.generate(vec.begin(), vec.end(), engine, queue); +// ! [generate] + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 > 1, queue + ), + size_t(0) + ); +} + +BOOST_AUTO_TEST_CASE(discrete_distribution) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + size_t size = 100; + boost::compute::vector<uint_> vec(size, context); + + // initialize the default random engine + boost::compute::default_random_engine engine(queue); + + // initialize weights + int weights[] = {10, 40, 40, 10}; + + // setup the discrete distribution + boost::compute::discrete_distribution<uint_> distribution( + weights, weights + 4 + ); + + std::vector<double> p = distribution.probabilities(); + BOOST_CHECK_CLOSE(p[0], double(0.1), 0.001); + BOOST_CHECK_CLOSE(p[1], double(0.4), 0.001); + BOOST_CHECK_CLOSE(p[2], double(0.4), 0.001); + BOOST_CHECK_CLOSE(p[3], double(0.1), 0.001); + + BOOST_CHECK_EQUAL((distribution.min)(), uint_(0)); + BOOST_CHECK_EQUAL((distribution.max)(), uint_(3)); + + // generate the random values and store them to 'vec' + distribution.generate(vec.begin(), vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 < 4, queue + ), + size + ); +} + +BOOST_AUTO_TEST_CASE(discrete_distribution_default_ctor) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + size_t size = 100; + boost::compute::vector<uint_> vec(size, context); + + // initialize the default random engine + boost::compute::default_random_engine engine(queue); + + // call default constructor + boost::compute::discrete_distribution<uint_> distribution; + + std::vector<double> p = distribution.probabilities(); + BOOST_CHECK_CLOSE(p[0], double(1), 0.001); + + // generate the random values and store them to 'vec' + distribution.generate(vec.begin(), vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 == 0, queue + ), + size + ); +} + +BOOST_AUTO_TEST_CASE(discrete_distribution_one_weight) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + size_t size = 100; + boost::compute::vector<uint_> vec(size, context); + + // initialize the default random engine + boost::compute::default_random_engine engine(queue); + + std::vector<int> weights(1, 1); + // call default constructor + boost::compute::discrete_distribution<uint_> distribution( + weights.begin(), weights.end() + ); + + std::vector<double> p = distribution.probabilities(); + BOOST_CHECK_CLOSE(p[0], double(1), 0.001); + + BOOST_CHECK_EQUAL((distribution.min)(), uint_(0)); + BOOST_CHECK_EQUAL((distribution.max)(), uint_(0)); + + // generate the random values and store them to 'vec' + distribution.generate(vec.begin(), vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 == 0, queue + ), + size + ); +} + +BOOST_AUTO_TEST_CASE(discrete_distribution_empty_weights) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + size_t size = 100; + boost::compute::vector<uint_> vec(size, context); + + // initialize the default random engine + boost::compute::default_random_engine engine(queue); + + std::vector<int> weights; + // weights.begin() == weights.end() + boost::compute::discrete_distribution<uint_> distribution( + weights.begin(), weights.end() + ); + + std::vector<double> p = distribution.probabilities(); + BOOST_CHECK_CLOSE(p[0], double(1), 0.001); + + BOOST_CHECK_EQUAL((distribution.min)(), uint_(0)); + BOOST_CHECK_EQUAL((distribution.max)(), uint_(0)); + + // generate the random values and store them to 'vec' + distribution.generate(vec.begin(), vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 == 0, queue + ), + size + ); +} + +BOOST_AUTO_TEST_CASE(discrete_distribution_uchar) +{ + using boost::compute::uchar_; + using boost::compute::uint_; + using boost::compute::lambda::_1; + + size_t size = 100; + boost::compute::vector<uchar_> uchar_vec(size, context); + boost::compute::vector<uint_> uint_vec(size, context); + + // initialize the default random engine + boost::compute::default_random_engine engine(queue); + + // initialize weights + std::vector<int> weights(258, 0); + weights[257] = 1; + + // setup the discrete distribution + boost::compute::discrete_distribution<uchar_> distribution( + weights.begin(), weights.end() + ); + + BOOST_CHECK_EQUAL((distribution.min)(), uchar_(0)); + BOOST_CHECK_EQUAL((distribution.max)(), uchar_(255)); + + // generate the random uchar_ values to the uchar_ vector + distribution.generate(uchar_vec.begin(), uchar_vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + uchar_vec.begin(), uchar_vec.end(), _1 == uchar_(1), queue + ), + size + ); + + // generate the random uchar_ values to the uint_ vector + distribution.generate(uint_vec.begin(), uint_vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + uint_vec.begin(), uint_vec.end(), _1 == uint_(1), queue + ), + size + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_dynamic_bitset.cpp b/src/boost/libs/compute/test/test_dynamic_bitset.cpp new file mode 100644 index 00000000..1afb905b --- /dev/null +++ b/src/boost/libs/compute/test/test_dynamic_bitset.cpp @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestDynamicBitset +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/dynamic_bitset.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(set_and_test) +{ + compute::dynamic_bitset<> bits(1024, queue); + + bits.set(1, queue); + BOOST_CHECK(bits.test(1, queue) == true); + BOOST_CHECK(bits.test(2, queue) == false); + + bits.set(1, false, queue); + BOOST_CHECK(bits.test(1, queue) == false); + BOOST_CHECK(bits.test(2, queue) == false); +} + +BOOST_AUTO_TEST_CASE(count) +{ + compute::dynamic_bitset<> bits(1024, queue); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(0)); + + bits.set(1, queue); + bits.set(8, queue); + bits.set(129, queue); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(3)); + + bits.set(8, false, queue); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(2)); + + bits.reset(queue); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(0)); +} + +BOOST_AUTO_TEST_CASE(resize) +{ + compute::dynamic_bitset<> bits(0, queue); + BOOST_CHECK_EQUAL(bits.size(), size_t(0)); + BOOST_CHECK_EQUAL(bits.empty(), true); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(0)); + + bits.resize(100, queue); + BOOST_CHECK_EQUAL(bits.size(), size_t(100)); + BOOST_CHECK_EQUAL(bits.empty(), false); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(0)); + + bits.set(42, true, queue); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(1)); + + bits.resize(0, queue); + BOOST_CHECK_EQUAL(bits.size(), size_t(0)); + BOOST_CHECK_EQUAL(bits.empty(), true); + BOOST_CHECK_EQUAL(bits.count(queue), size_t(0)); +} + +BOOST_AUTO_TEST_CASE(none_and_any) +{ + compute::dynamic_bitset<> bits(1024, queue); + BOOST_CHECK(bits.any(queue) == false); + BOOST_CHECK(bits.none(queue) == true); + + bits.set(1023, queue); + BOOST_CHECK(bits.any(queue) == true); + BOOST_CHECK(bits.none(queue) == false); + + bits.set(1023, false, queue); + BOOST_CHECK(bits.any(queue) == false); + BOOST_CHECK(bits.none(queue) == true); + + bits.set(1, queue); + BOOST_CHECK(bits.any(queue) == true); + BOOST_CHECK(bits.none(queue) == false); + + bits.reset(queue); + BOOST_CHECK(bits.any(queue) == false); + BOOST_CHECK(bits.none(queue) == true); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_equal.cpp b/src/boost/libs/compute/test/test_equal.cpp new file mode 100644 index 00000000..0b568c91 --- /dev/null +++ b/src/boost/libs/compute/test/test_equal.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestEqual +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/equal.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/container/string.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(equal_int) +{ + int data1[] = { 1, 2, 3, 4, 5, 6 }; + int data2[] = { 1, 2, 3, 7, 5, 6 }; + + boost::compute::vector<int> vector1(data1, data1 + 6, queue); + boost::compute::vector<int> vector2(data2, data2 + 6, queue); + + BOOST_CHECK(boost::compute::equal(vector1.begin(), vector1.end(), + vector2.begin(), queue) == false); + BOOST_CHECK(boost::compute::equal(vector1.begin(), vector1.begin() + 2, + vector2.begin(), queue) == true); + BOOST_CHECK(boost::compute::equal(vector1.begin() + 4, vector1.end(), + vector2.begin() + 4, queue) == true); +} + +BOOST_AUTO_TEST_CASE(equal_string) +{ + boost::compute::string a = "abcdefghijk"; + boost::compute::string b = "abcdefghijk"; + boost::compute::string c = "abcdezghijk"; + + BOOST_CHECK(boost::compute::equal(a.begin(), a.end(), b.begin(), queue) == true); + BOOST_CHECK(boost::compute::equal(a.begin(), a.end(), c.begin(), queue) == false); +} + +BOOST_AUTO_TEST_CASE(equal_different_range_sizes) +{ + boost::compute::vector<int> a(10, context); + boost::compute::vector<int> b(20, context); + + boost::compute::fill(a.begin(), a.end(), 3, queue); + boost::compute::fill(b.begin(), b.end(), 3, queue); + + BOOST_CHECK(boost::compute::equal(a.begin(), a.end(), b.begin(), b.end(), queue) == false); + BOOST_CHECK(boost::compute::equal(a.begin(), a.end(), a.begin(), a.end(), queue) == true); + BOOST_CHECK(boost::compute::equal(b.begin(), b.end(), a.begin(), a.end(), queue) == false); + BOOST_CHECK(boost::compute::equal(b.begin(), b.end(), b.begin(), b.end(), queue) == true); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_equal_range.cpp b/src/boost/libs/compute/test/test_equal_range.cpp new file mode 100644 index 00000000..981d22ca --- /dev/null +++ b/src/boost/libs/compute/test/test_equal_range.cpp @@ -0,0 +1,73 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestEqualRange +#include <boost/test/unit_test.hpp> + +#include <utility> +#include <iterator> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/equal_range.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(equal_range_int) +{ + int data[] = { 1, 2, 2, 2, 3, 3, 4, 5 }; + boost::compute::vector<int> vector(data, data + 8, queue); + + typedef boost::compute::vector<int>::iterator iterator; + + std::pair<iterator, iterator> range0 = + boost::compute::equal_range(vector.begin(), vector.end(), int(0), queue); + BOOST_CHECK(range0.first == vector.begin()); + BOOST_CHECK(range0.second == vector.begin()); + BOOST_CHECK_EQUAL(std::distance(range0.first, range0.second), ptrdiff_t(0)); + + std::pair<iterator, iterator> range1 = + boost::compute::equal_range(vector.begin(), vector.end(), int(1), queue); + BOOST_CHECK(range1.first == vector.begin()); + BOOST_CHECK(range1.second == vector.begin() + 1); + BOOST_CHECK_EQUAL(std::distance(range1.first, range1.second), ptrdiff_t(1)); + + std::pair<iterator, iterator> range2 = + boost::compute::equal_range(vector.begin(), vector.end(), int(2), queue); + BOOST_CHECK(range2.first == vector.begin() + 1); + BOOST_CHECK(range2.second == vector.begin() + 4); + BOOST_CHECK_EQUAL(std::distance(range2.first, range2.second), ptrdiff_t(3)); + + std::pair<iterator, iterator> range3 = + boost::compute::equal_range(vector.begin(), vector.end(), int(3), queue); + BOOST_CHECK(range3.first == vector.begin() + 4); + BOOST_CHECK(range3.second == vector.begin() + 6); + BOOST_CHECK_EQUAL(std::distance(range3.first, range3.second), ptrdiff_t(2)); + + std::pair<iterator, iterator> range4 = + boost::compute::equal_range(vector.begin(), vector.end(), int(4), queue); + BOOST_CHECK(range4.first == vector.begin() + 6); + BOOST_CHECK(range4.second == vector.begin() + 7); + BOOST_CHECK_EQUAL(std::distance(range4.first, range4.second), ptrdiff_t(1)); + + std::pair<iterator, iterator> range5 = + boost::compute::equal_range(vector.begin(), vector.end(), int(5), queue); + BOOST_CHECK(range5.first == vector.begin() + 7); + BOOST_CHECK(range5.second == vector.end()); + BOOST_CHECK_EQUAL(std::distance(range5.first, range5.second), ptrdiff_t(1)); + + std::pair<iterator, iterator> range6 = + boost::compute::equal_range(vector.begin(), vector.end(), int(6), queue); + BOOST_CHECK(range6.first == vector.end()); + BOOST_CHECK(range6.second == vector.end()); + BOOST_CHECK_EQUAL(std::distance(range6.first, range6.second), ptrdiff_t(0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_event.cpp b/src/boost/libs/compute/test/test_event.cpp new file mode 100644 index 00000000..9077c2a2 --- /dev/null +++ b/src/boost/libs/compute/test/test_event.cpp @@ -0,0 +1,143 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestEvent +#include <boost/test/unit_test.hpp> + +#include <vector> + +#ifdef BOOST_COMPUTE_USE_CPP11 +#include <mutex> +#include <future> +#endif // BOOST_COMPUTE_USE_CPP11 + +#include <boost/compute/async/future.hpp> +#include <boost/compute/event.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(null_event) +{ + boost::compute::event null; + BOOST_CHECK(null.get() == cl_event()); +} + +#if defined(BOOST_COMPUTE_CL_VERSION_1_1) && defined(BOOST_COMPUTE_USE_CPP11) +std::mutex callback_mutex; +std::condition_variable callback_condition_variable; +static bool callback_invoked = false; + +static void BOOST_COMPUTE_CL_CALLBACK +callback(cl_event event, cl_int status, void *user_data) +{ + std::lock_guard<std::mutex> lock(callback_mutex); + callback_invoked = true; + callback_condition_variable.notify_one(); +} + +BOOST_AUTO_TEST_CASE(event_callback) +{ + REQUIRES_OPENCL_VERSION(1,2); + + // ensure callback has not yet been executed + BOOST_CHECK_EQUAL(callback_invoked, false); + + // enqueue marker and set callback to be invoked + boost::compute::event marker = queue.enqueue_marker(); + marker.set_callback(callback); + marker.wait(); + + // wait up to one second for the callback to be executed + std::unique_lock<std::mutex> lock(callback_mutex); + callback_condition_variable.wait_for( + lock, std::chrono::seconds(1), [&](){ return callback_invoked; } + ); + + // ensure callback has been executed + BOOST_CHECK_EQUAL(callback_invoked, true); +} + +BOOST_AUTO_TEST_CASE(lambda_callback) +{ + REQUIRES_OPENCL_VERSION(1,2); + + bool lambda_invoked = false; + + boost::compute::event marker = queue.enqueue_marker(); + marker.set_callback([&](){ + std::lock_guard<std::mutex> lock(callback_mutex); + lambda_invoked = true; + callback_condition_variable.notify_one(); + }); + marker.wait(); + + // wait up to one second for the callback to be executed + std::unique_lock<std::mutex> lock(callback_mutex); + callback_condition_variable.wait_for( + lock, std::chrono::seconds(1), [&](){ return lambda_invoked; } + ); + BOOST_CHECK_EQUAL(lambda_invoked, true); +} + +BOOST_AUTO_TEST_CASE(future_then_callback) +{ + REQUIRES_OPENCL_VERSION(1,2); + + bool callback_invoked = false; + + boost::compute::future<void> future(queue.enqueue_marker()); + future.then([&](){ + std::lock_guard<std::mutex> lock(callback_mutex); + callback_invoked = true; + callback_condition_variable.notify_one(); + }); + future.wait(); + + // wait up to one second for the callback to be executed + std::unique_lock<std::mutex> lock(callback_mutex); + callback_condition_variable.wait_for( + lock, std::chrono::seconds(1), [&](){ return callback_invoked; } + ); + BOOST_CHECK_EQUAL(callback_invoked, true); +} + +void BOOST_COMPUTE_CL_CALLBACK +event_promise_fulfiller_callback(cl_event event, cl_int status, void *user_data) +{ + auto *promise = static_cast<std::promise<void> *>(user_data); + promise->set_value(); + delete promise; +} + +BOOST_AUTO_TEST_CASE(event_to_std_future) +{ + REQUIRES_OPENCL_VERSION(1,2); + + // enqueue an asynchronous copy to the device + std::vector<float> vector(1000, 3.14f); + boost::compute::buffer buffer(context, 1000 * sizeof(float)); + auto event = queue.enqueue_write_buffer_async( + buffer, 0, 1000 * sizeof(float), vector.data() + ); + + // create a promise and future to be set by the callback + auto *promise = new std::promise<void>; + std::future<void> future = promise->get_future(); + event.set_callback(event_promise_fulfiller_callback, CL_COMPLETE, promise); + + // ensure commands are submitted to the device before waiting + queue.flush(); + + // wait for future to become ready + future.wait(); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_1 + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_extents.cpp b/src/boost/libs/compute/test/test_extents.cpp new file mode 100644 index 00000000..38ab092f --- /dev/null +++ b/src/boost/libs/compute/test/test_extents.cpp @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestExtents +#include <boost/test/unit_test.hpp> + +#include <algorithm> +#include <vector> + +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/extents.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +#ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +BOOST_AUTO_TEST_CASE(initialize) +{ + compute::extents<1> one(1); + BOOST_CHECK_EQUAL(one[0], size_t(1)); + + compute::extents<3> xyz = compute::dim(1, 2, 3); + BOOST_CHECK_EQUAL(xyz[0], size_t(1)); + BOOST_CHECK_EQUAL(xyz[1], size_t(2)); + BOOST_CHECK_EQUAL(xyz[2], size_t(3)); +} +#endif + +BOOST_AUTO_TEST_CASE(size) +{ + BOOST_CHECK_EQUAL(compute::extents<1>().size(), size_t(1)); + BOOST_CHECK_EQUAL(compute::extents<2>().size(), size_t(2)); + BOOST_CHECK_EQUAL(compute::extents<3>().size(), size_t(3)); +} + +BOOST_AUTO_TEST_CASE(subscript_operator) +{ + compute::extents<3> xyz; + BOOST_CHECK_EQUAL(xyz[0], size_t(0)); + BOOST_CHECK_EQUAL(xyz[1], size_t(0)); + BOOST_CHECK_EQUAL(xyz[2], size_t(0)); + + xyz[0] = size_t(10); + xyz[1] = size_t(20); + xyz[2] = size_t(30); + BOOST_CHECK_EQUAL(xyz[0], size_t(10)); + BOOST_CHECK_EQUAL(xyz[1], size_t(20)); + BOOST_CHECK_EQUAL(xyz[2], size_t(30)); +} + +#ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +BOOST_AUTO_TEST_CASE(data) +{ + compute::extents<3> xyz = compute::dim(5, 6, 7); + BOOST_CHECK_EQUAL(xyz.data()[0], size_t(5)); + BOOST_CHECK_EQUAL(xyz.data()[1], size_t(6)); + BOOST_CHECK_EQUAL(xyz.data()[2], size_t(7)); +} + +BOOST_AUTO_TEST_CASE(linear) +{ + compute::extents<2> uv = compute::dim(16, 16); + BOOST_CHECK_EQUAL(uv.linear(), size_t(256)); +} + +BOOST_AUTO_TEST_CASE(equality_operator) +{ + BOOST_CHECK(compute::dim(10, 20) == compute::dim(10, 20)); + BOOST_CHECK(compute::dim(20, 10) != compute::dim(10, 20)); +} + +BOOST_AUTO_TEST_CASE(empty_dim) +{ + BOOST_CHECK(compute::dim<0>() == compute::dim()); + BOOST_CHECK(compute::dim<1>() == compute::dim(0)); + BOOST_CHECK(compute::dim<2>() == compute::dim(0, 0)); + BOOST_CHECK(compute::dim<3>() == compute::dim(0, 0, 0)); +} + +BOOST_AUTO_TEST_CASE(copy_to_vector) +{ + compute::extents<3> exts = compute::dim(4, 5, 6); + + std::vector<size_t> vec(3); + std::copy(exts.begin(), exts.end(), vec.begin()); + BOOST_CHECK_EQUAL(vec[0], size_t(4)); + BOOST_CHECK_EQUAL(vec[1], size_t(5)); + BOOST_CHECK_EQUAL(vec[2], size_t(6)); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_extrema.cpp b/src/boost/libs/compute/test/test_extrema.cpp new file mode 100644 index 00000000..7f339d66 --- /dev/null +++ b/src/boost/libs/compute/test/test_extrema.cpp @@ -0,0 +1,396 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +// Undefining BOOST_COMPUTE_USE_OFFLINE_CACHE macro as we want to modify cached +// parameters for copy algorithm without any undesirable consequences (like +// saving modified values of those parameters). +#ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE + #undef BOOST_COMPUTE_USE_OFFLINE_CACHE +#endif + +#define BOOST_TEST_MODULE TestExtrema +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/max_element.hpp> +#include <boost/compute/algorithm/min_element.hpp> +#include <boost/compute/algorithm/minmax_element.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/transform_iterator.hpp> +#include <boost/compute/detail/parameter_cache.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(empyt_min) +{ + using boost::compute::int_; + + boost::compute::vector<int_> vector(size_t(16), int_(0), queue); + boost::compute::vector<int_>::iterator min_iter = + boost::compute::min_element(vector.begin(), vector.begin(), queue); + BOOST_CHECK(min_iter == vector.begin()); + + min_iter = + boost::compute::min_element(vector.begin(), vector.begin() + 1, queue); + BOOST_CHECK(min_iter == vector.begin()); +} + +BOOST_AUTO_TEST_CASE(int_min_max) +{ + using boost::compute::int_; + using boost::compute::uint_; + + boost::compute::vector<int_> vector(size_t(4096), int_(0), queue); + boost::compute::iota(vector.begin(), (vector.begin() + 512), 1, queue); + boost::compute::fill((vector.end() - 512), vector.end(), 513, queue); + + boost::compute::vector<int_>::iterator min_iter = + boost::compute::min_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(min_iter == vector.begin() + 512); + BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0); + BOOST_CHECK_EQUAL(min_iter.read(queue), 0); + + boost::compute::vector<int_>::iterator max_iter = + boost::compute::max_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(max_iter == vector.end() - 512); + BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513); + BOOST_CHECK_EQUAL(max_iter.read(queue), 513); + + // compare function + boost::compute::less<int_> lessint; + + // test minmax_element + std::pair< + boost::compute::vector<int_>::iterator, + boost::compute::vector<int_>::iterator + > minmax_iter = + boost::compute::minmax_element(vector.begin(), vector.end(), queue); + BOOST_CHECK_EQUAL((minmax_iter.first).read(queue), 0); + BOOST_CHECK_EQUAL((minmax_iter.second).read(queue), 513); + + minmax_iter = + boost::compute::minmax_element(vector.begin(), vector.end(), lessint, queue); + BOOST_CHECK_EQUAL((minmax_iter.first).read(queue), 0); + BOOST_CHECK_EQUAL((minmax_iter.second).read(queue), 513); + + // find_extrama_on_cpu + + // make sure find_extrama_on_cpu is used, no serial_find_extrema + std::string cache_key = + "__boost_find_extrema_cpu_4"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_find_extrema_threshold", 0); + // force find_extrama_on_cpu + parameters->set(cache_key, "serial_find_extrema_threshold", 16); + + min_iter = boost::compute::detail::find_extrema_on_cpu( + vector.begin(), vector.end(), lessint, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 512); + BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0); + BOOST_CHECK_EQUAL(min_iter.read(queue), 0); + + max_iter = boost::compute::detail::find_extrema_on_cpu( + vector.begin(), vector.end(), lessint, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.end() - 512); + BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513); + BOOST_CHECK_EQUAL(max_iter.read(queue), 513); + + // restore + parameters->set(cache_key, "serial_find_extrema_threshold", map_copy_threshold); + + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all further tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + // find_extrama_with_reduce + min_iter = boost::compute::detail::find_extrema_with_reduce( + vector.begin(), vector.end(), lessint, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 512); + BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0); + BOOST_CHECK_EQUAL(min_iter.read(queue), 0); + + max_iter = boost::compute::detail::find_extrema_with_reduce( + vector.begin(), vector.end(), lessint, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.end() - 512); + BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513); + BOOST_CHECK_EQUAL(max_iter.read(queue), 513); + + // find_extram_with_atomics + min_iter = boost::compute::detail::find_extrema_with_atomics( + vector.begin(), vector.end(), lessint, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 512); + BOOST_CHECK_EQUAL((vector.begin() + 512).read(queue), 0); + BOOST_CHECK_EQUAL(min_iter.read(queue), 0); + + max_iter = boost::compute::detail::find_extrema_with_atomics( + vector.begin(), vector.end(), lessint, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.end() - 512); + BOOST_CHECK_EQUAL((vector.end() - 512).read(queue), 513); + BOOST_CHECK_EQUAL(max_iter.read(queue), 513); +} + +BOOST_AUTO_TEST_CASE(int2_min_max_custom_comparision_function) +{ + using boost::compute::int2_; + using boost::compute::uint_; + + boost::compute::vector<int2_> vector(context); + vector.push_back(int2_(1, 10), queue); + vector.push_back(int2_(2, -100), queue); + vector.push_back(int2_(3, 30), queue); + vector.push_back(int2_(4, 20), queue); + vector.push_back(int2_(5, 5), queue); + vector.push_back(int2_(6, -80), queue); + vector.push_back(int2_(7, 21), queue); + vector.push_back(int2_(8, -5), queue); + + BOOST_COMPUTE_FUNCTION(bool, compare_second, (const int2_ a, const int2_ b), + { + return a.y < b.y; + }); + + boost::compute::vector<int2_>::iterator min_iter = + boost::compute::min_element( + vector.begin(), vector.end(), compare_second, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100)); + + boost::compute::vector<int2_>::iterator max_iter = + boost::compute::max_element( + vector.begin(), vector.end(), compare_second, queue + ); + BOOST_CHECK(max_iter == vector.begin() + 2); + BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30)); + + // find_extrama_on_cpu + + // make sure find_extrama_on_cpu is used, no serial_find_extrema + std::string cache_key = + "__boost_find_extrema_cpu_8"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_find_extrema_threshold", 0); + // force find_extrama_on_cpu + parameters->set(cache_key, "serial_find_extrema_threshold", 16); + + min_iter = boost::compute::detail::find_extrema_on_cpu( + vector.begin(), vector.end(), compare_second, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100)); + + max_iter = boost::compute::detail::find_extrema_on_cpu( + vector.begin(), vector.end(), compare_second, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.begin() + 2); + BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30)); + + // restore + parameters->set(cache_key, "serial_find_extrema_threshold", map_copy_threshold); + + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all further tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + // find_extrama_with_reduce + min_iter = boost::compute::detail::find_extrema_with_reduce( + vector.begin(), vector.end(), compare_second, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100)); + + max_iter = boost::compute::detail::find_extrema_with_reduce( + vector.begin(), vector.end(), compare_second, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.begin() + 2); + BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30)); + + // find_extram_with_atomics + min_iter = boost::compute::detail::find_extrema_with_atomics( + vector.begin(), vector.end(), compare_second, true /* find minimum */, queue + ); + BOOST_CHECK(min_iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*min_iter, int2_(2, -100)); + + max_iter = boost::compute::detail::find_extrema_with_atomics( + vector.begin(), vector.end(), compare_second, false /* find minimum */, queue + ); + BOOST_CHECK(max_iter == vector.begin() + 2); + BOOST_CHECK_EQUAL(*max_iter, int2_(3, 30)); +} + +BOOST_AUTO_TEST_CASE(iota_min_max) +{ + boost::compute::vector<int> vector(5000, context); + + // fill with 0 -> 4999 + boost::compute::iota(vector.begin(), vector.end(), 0, queue); + + boost::compute::vector<int>::iterator min_iter = + boost::compute::min_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(min_iter == vector.begin()); + BOOST_CHECK_EQUAL(*min_iter, 0); + + boost::compute::vector<int>::iterator max_iter = + boost::compute::max_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(max_iter == vector.end() - 1); + BOOST_CHECK_EQUAL(*max_iter, 4999); + + min_iter = + boost::compute::min_element( + vector.begin() + 1000, + vector.end() - 1000, + queue + ); + BOOST_CHECK(min_iter == vector.begin() + 1000); + BOOST_CHECK_EQUAL(*min_iter, 1000); + + max_iter = + boost::compute::max_element( + vector.begin() + 1000, + vector.end() - 1000, + queue + ); + BOOST_CHECK(max_iter == vector.begin() + 3999); + BOOST_CHECK_EQUAL(*max_iter, 3999); + + // fill with -2500 -> 2499 + boost::compute::iota(vector.begin(), vector.end(), -2500, queue); + min_iter = + boost::compute::min_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(min_iter == vector.begin()); + BOOST_CHECK_EQUAL(*min_iter, -2500); + + max_iter = + boost::compute::max_element(vector.begin(), vector.end(), queue); + BOOST_CHECK(max_iter == vector.end() - 1); + BOOST_CHECK_EQUAL(*max_iter, 2499); +} + +// uses max_element() and length() to find the longest 2d vector +BOOST_AUTO_TEST_CASE(max_vector_length) +{ + float data[] = { -1.5f, 3.2f, + 10.0f, 0.0f, + -4.2f, 2.0f, + 0.0f, 0.5f, + 1.9f, 1.9f }; + boost::compute::vector<boost::compute::float2_> vector( + reinterpret_cast<boost::compute::float2_ *>(data), + reinterpret_cast<boost::compute::float2_ *>(data) + 5, + queue + ); + + // find length of the longest vector + typedef boost::compute::transform_iterator< + boost::compute::vector<boost::compute::float2_>::iterator, + boost::compute::length<boost::compute::float2_> + > length_transform_iter; + + length_transform_iter max_iter = + boost::compute::max_element( + boost::compute::make_transform_iterator( + vector.begin(), + boost::compute::length<boost::compute::float2_>() + ), + boost::compute::make_transform_iterator( + vector.end(), + boost::compute::length<boost::compute::float2_>() + ), + queue + ); + BOOST_CHECK( + max_iter == boost::compute::make_transform_iterator( + vector.begin() + 1, + boost::compute::length<boost::compute::float2_>() + ) + ); + BOOST_CHECK(max_iter.base() == vector.begin() + 1); + BOOST_CHECK_EQUAL(*max_iter, float(10.0)); + + // find length of the shortest vector + length_transform_iter min_iter = + boost::compute::min_element( + boost::compute::make_transform_iterator( + vector.begin(), + boost::compute::length<boost::compute::float2_>() + ), + boost::compute::make_transform_iterator( + vector.end(), + boost::compute::length<boost::compute::float2_>() + ), + queue + ); + BOOST_CHECK( + min_iter == boost::compute::make_transform_iterator( + vector.begin() + 3, + boost::compute::length<boost::compute::float2_>() + ) + ); + BOOST_CHECK(min_iter.base() == vector.begin() + 3); + BOOST_CHECK_EQUAL(*min_iter, float(0.5)); +} + +// uses max_element() and popcount() to find the value with the most 1 bits +BOOST_AUTO_TEST_CASE(max_bits_set) +{ + using boost::compute::uint_; + + uint_ data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + boost::compute::vector<uint_> vector(data, data + 10, queue); + + boost::compute::vector<uint_>::iterator iter = + boost::compute::max_element( + boost::compute::make_transform_iterator( + vector.begin(), + boost::compute::popcount<uint_>() + ), + boost::compute::make_transform_iterator( + vector.end(), + boost::compute::popcount<uint_>() + ), + queue + ).base(); + + BOOST_CHECK(iter == vector.begin() + 7); + BOOST_CHECK_EQUAL(uint_(*iter), uint_(7)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_fill.cpp b/src/boost/libs/compute/test/test_fill.cpp new file mode 100644 index 00000000..bc58e6cb --- /dev/null +++ b/src/boost/libs/compute/test/test_fill.cpp @@ -0,0 +1,333 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFill +#include <boost/test/unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/mpl/list.hpp> + +#include <iostream> + +#include <boost/compute/algorithm/equal.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/fill_n.hpp> +#include <boost/compute/async/future.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/svm.hpp> +#include <boost/compute/type_traits.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +typedef boost::mpl::list + <bc::char_, bc::uchar_, bc::int_, bc::uint_, + bc::long_, bc::ulong_, bc::float_, bc::double_> + scalar_types; + +template<class T> +inline void test_fill(T v1, T v2, T v3, bc::command_queue queue) { + if(boost::is_same<typename bc::scalar_type<T>::type, bc::double_>::value && + !queue.get_device().supports_extension("cl_khr_fp64")) { + std::cerr << "Skipping test_fill<" << bc::type_name<T>() << ">() " + "on device which doesn't support cl_khr_fp64" << std::endl; + return; + } + + bc::vector<T> vector(4, queue.get_context()); + bc::fill(vector.begin(), vector.end(), v1, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v1, v1, v1, v1)); + + vector.resize(1000, queue); + bc::fill(vector.begin(), vector.end(), v2, queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.front(), v2); + BOOST_CHECK_EQUAL(vector.back(), v2); + + bc::fill(vector.begin() + 500, vector.end(), v3, queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.front(), v2); + BOOST_CHECK_EQUAL(vector[499], v2); + BOOST_CHECK_EQUAL(vector[500], v3); + BOOST_CHECK_EQUAL(vector.back(), v3); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_scalar, S, scalar_types ) +{ + S v1 = S(1.5f); + S v2 = S(2.5f); + S v3 = S(42.0f); + test_fill(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_vec2, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 2>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + + T v1 = T(s1, s2); + T v2 = T(s3, s4); + T v3 = T(s2, s1); + test_fill(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_vec4, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 4>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + + T v1 = T(s1, s2, s3, s4); + T v2 = T(s3, s4, s1, s2); + T v3 = T(s4, s3, s2, s1); + test_fill(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_vec8, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 8>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + S s5 = S(122.5f); + S s6 = S(131.5f); + S s7 = S(142.0f); + S s8 = S(254.0f); + + T v1 = T(s1, s2, s3, s4, s5, s6, s7, s8); + T v2 = T(s3, s4, s1, s2, s7, s8, s5, s6); + T v3 = T(s4, s3, s2, s1, s8, s7, s6, s5); + test_fill(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_vec16, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 16>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + S s5 = S(122.5f); + S s6 = S(131.5f); + S s7 = S(142.0f); + S s8 = S(254.0f); + + T v1 = T(s1, s2, s3, s4, s5, s6, s7, s8, s1, s2, s3, s4, s5, s6, s7, s8); + T v2 = T(s3, s4, s1, s2, s7, s8, s5, s6, s4, s3, s2, s1, s8, s7, s6, s5); + T v3 = T(s4, s3, s2, s1, s8, s7, s6, s5, s8, s7, s6, s5, s4, s3, s2, s1); + test_fill(v1, v2, v3, queue); +} + +template<class T> +inline void test_fill_n(T v1, T v2, T v3, bc::command_queue queue) { + if(boost::is_same<typename bc::scalar_type<T>::type, bc::double_>::value && + !queue.get_device().supports_extension("cl_khr_fp64")) { + std::cerr << "Skipping test_fill_n<" << bc::type_name<T>() << ">() " + "on device which doesn't support cl_khr_fp64" << std::endl; + return; + } + + bc::vector<T> vector(4, queue.get_context()); + bc::fill_n(vector.begin(), 4, v1, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v1, v1, v1, v1)); + + bc::fill_n(vector.begin(), 3, v2, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v2, v2, v2, v1)); + + bc::fill_n(vector.begin() + 1, 2, v3, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v2, v3, v3, v1)); + + bc::fill_n(vector.begin(), 4, v2, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v2, v2, v2, v2)); + + // fill last element + bc::fill_n(vector.end() - 1, 1, v3, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v2, v2, v2, v3)); + + // fill first element + bc::fill_n(vector.begin(), 1, v1, queue); + queue.finish(); + CHECK_RANGE_EQUAL(T, 4, vector, (v1, v2, v2, v3)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_n_scalar, S, scalar_types ) +{ + S v1 = S(1.5f); + S v2 = S(2.5f); + S v3 = S(42.0f); + test_fill_n(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_n_vec2, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 2>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + + T v1 = T(s1, s2); + T v2 = T(s3, s4); + T v3 = T(s2, s1); + test_fill_n(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_n_vec4, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 4>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + + T v1 = T(s1, s2, s3, s4); + T v2 = T(s3, s4, s1, s2); + T v3 = T(s4, s3, s2, s1); + test_fill_n(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_n_vec8, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 8>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + S s5 = S(122.5f); + S s6 = S(131.5f); + S s7 = S(142.0f); + S s8 = S(254.0f); + + T v1 = T(s1, s2, s3, s4, s5, s6, s7, s8); + T v2 = T(s3, s4, s1, s2, s7, s8, s5, s6); + T v3 = T(s4, s3, s2, s1, s8, s7, s6, s5); + test_fill_n(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE( fill_n_vec16, S, scalar_types ) +{ + typedef typename bc::make_vector_type<S, 16>::type T; + S s1 = S(1.5f); + S s2 = S(2.5f); + S s3 = S(42.0f); + S s4 = S(84.0f); + S s5 = S(122.5f); + S s6 = S(131.5f); + S s7 = S(142.0f); + S s8 = S(254.0f); + + T v1 = T(s1, s2, s3, s4, s5, s6, s7, s8, s1, s2, s3, s4, s5, s6, s7, s8); + T v2 = T(s3, s4, s1, s2, s7, s8, s5, s6, s4, s3, s2, s1, s8, s7, s6, s5); + T v3 = T(s4, s3, s2, s1, s8, s7, s6, s5, s8, s7, s6, s5, s4, s3, s2, s1); + test_fill_n(v1, v2, v3, queue); +} + +BOOST_AUTO_TEST_CASE(check_fill_type) +{ + bc::vector<int> vector(5, context); + bc::future<void> future = + bc::fill_async(vector.begin(), vector.end(), 42, queue); + future.wait(); + + #ifdef BOOST_COMPUTE_CL_VERSION_1_2 + BOOST_CHECK_EQUAL( + future.get_event().get_command_type(), + device.check_version(1,2) ? CL_COMMAND_FILL_BUFFER : CL_COMMAND_NDRANGE_KERNEL + ); + #else + BOOST_CHECK( + future.get_event().get_command_type() == CL_COMMAND_NDRANGE_KERNEL + ); + #endif +} + +BOOST_AUTO_TEST_CASE(fill_clone_buffer) +{ + int data[] = { 1, 2, 3, 4 }; + bc::vector<int> vec(data, data + 4, queue); + CHECK_RANGE_EQUAL(int, 4, vec, (1, 2, 3, 4)); + + bc::buffer cloned_buffer = vec.get_buffer().clone(queue); + BOOST_CHECK( + bc::equal( + vec.begin(), + vec.end(), + bc::make_buffer_iterator<int>(cloned_buffer, 0), + queue + ) + ); + + bc::fill(vec.begin(), vec.end(), 5, queue); + BOOST_CHECK( + !bc::equal( + vec.begin(), + vec.end(), + bc::make_buffer_iterator<int>(cloned_buffer, 0), + queue + ) + ); + + bc::fill( + bc::make_buffer_iterator<int>(cloned_buffer, 0), + bc::make_buffer_iterator<int>(cloned_buffer, 4), + 5, + queue + ); + BOOST_CHECK( + bc::equal( + vec.begin(), + vec.end(), + bc::make_buffer_iterator<int>(cloned_buffer, 0), + queue + ) + ); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 +BOOST_AUTO_TEST_CASE(fill_svm_buffer) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + size_t size = 4; + bc::svm_ptr<cl_int> ptr = + bc::svm_alloc<cl_int>(context, size * sizeof(cl_int)); + bc::fill_n(ptr, size * sizeof(cl_int), 42, queue); + + queue.enqueue_svm_map(ptr.get(), size * sizeof(cl_int), CL_MAP_READ); + for(size_t i = 0; i < size; i++) { + BOOST_CHECK_EQUAL(static_cast<cl_int*>(ptr.get())[i], 42); + } + queue.enqueue_svm_unmap(ptr.get()); + + bc::svm_free(context, ptr); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + +BOOST_AUTO_TEST_CASE(empty_fill) +{ + bc::vector<int> vec(0, context); + bc::fill(vec.begin(), vec.end(), 42, queue); + bc::fill_async(vec.begin(), vec.end(), 42, queue); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_find.cpp b/src/boost/libs/compute/test/test_find.cpp new file mode 100644 index 00000000..d17823f8 --- /dev/null +++ b/src/boost/libs/compute/test/test_find.cpp @@ -0,0 +1,107 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFind +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/find.hpp> +#include <boost/compute/algorithm/find_if.hpp> +#include <boost/compute/algorithm/find_if_not.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_buffer_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(find_int) +{ + int data[] = { 9, 15, 1, 4, 9, 9, 4, 15, 12, 1 }; + bc::vector<int> vector(data, data + 10, queue); + + bc::vector<int>::iterator iter = + bc::find(vector.begin(), vector.end(), 4, queue); + BOOST_CHECK(iter == vector.begin() + 3); + BOOST_CHECK_EQUAL(*iter, 4); + + iter = bc::find(vector.begin(), vector.end(), 12, queue); + BOOST_CHECK(iter == vector.begin() + 8); + BOOST_CHECK_EQUAL(*iter, 12); + + iter = bc::find(vector.begin(), vector.end(), 1, queue); + BOOST_CHECK(iter == vector.begin() + 2); + BOOST_CHECK_EQUAL(*iter, 1); + + iter = bc::find(vector.begin(), vector.end(), 9, queue); + BOOST_CHECK(iter == vector.begin()); + BOOST_CHECK_EQUAL(*iter, 9); + + iter = bc::find(vector.begin(), vector.end(), 100, queue); + BOOST_CHECK(iter == vector.end()); +} + +BOOST_AUTO_TEST_CASE(find_int2) +{ + using bc::int2_; + + int data[] = { 1, 2, 4, 5, 7, 8 }; + bc::vector<int2_> vector( + reinterpret_cast<int2_ *>(data), + reinterpret_cast<int2_ *>(data) + 3, + queue + ); + CHECK_RANGE_EQUAL(int2_, 3, vector, (int2_(1, 2), int2_(4, 5), int2_(7, 8))); + + bc::vector<int2_>::iterator iter = + bc::find(vector.begin(), vector.end(), int2_(4, 5), queue); + BOOST_CHECK(iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*iter, int2_(4, 5)); + + iter = bc::find(vector.begin(), vector.end(), int2_(10, 11), queue); + BOOST_CHECK(iter == vector.end()); +} + +BOOST_AUTO_TEST_CASE(find_if_not_int) +{ + int data[] = { 2, 4, 6, 8, 1, 3, 5, 7, 9 }; + bc::vector<int> vector(data, data + 9, queue); + + bc::vector<int>::iterator iter = + bc::find_if_not(vector.begin(), vector.end(), bc::_1 == 2, queue); + BOOST_CHECK(iter == vector.begin() + 1); + BOOST_CHECK_EQUAL(*iter, 4); +} + +BOOST_AUTO_TEST_CASE(find_point_by_distance) +{ + using boost::compute::float2_; + using boost::compute::lambda::_1; + using boost::compute::lambda::distance; + + float2_ points[] = { + float2_(0, 0), float2_(2, 2), float2_(4, 4), float2_(8, 8) + }; + compute::vector<float2_> vec(points, points + 4, queue); + + compute::vector<float2_>::iterator iter = + compute::find_if(vec.begin(), vec.end(), distance(_1, float2_(5, 5)) < 1.5f, queue); + BOOST_CHECK(iter == vec.begin() + 2); + + float2_ value; + compute::copy_n(iter, 1, &value, queue); + BOOST_CHECK_EQUAL(value, float2_(4, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_find_end.cpp b/src/boost/libs/compute/test/test_find_end.cpp new file mode 100644 index 00000000..6ef050d0 --- /dev/null +++ b/src/boost/libs/compute/test/test_find_end.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFindEnd +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/find_end.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(find_end_int) +{ + bc::int_ data[] = {1, 4, 2, 6, 3, 2, 6, 3, 4, 6}; + bc::vector<bc::int_> vectort(data, data + 10, queue); + + bc::int_ datap[] = {2, 6}; + bc::vector<bc::int_> vectorp(datap, datap + 2, queue); + + bc::vector<bc::int_>::iterator iter = + bc::find_end(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.begin() + 5); + + vectorp.insert(vectorp.begin() + 1, bc::int_(9), queue); + + iter = + bc::find_end(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.end()); +} + +BOOST_AUTO_TEST_CASE(find_end_string) +{ + bc::char_ text[] = "sdabababacabskjabacab"; + bc::vector<bc::char_> vectort(text, text + 21, queue); + + bc::char_ pattern[] = "aba"; + bc::vector<bc::char_> vectorp(pattern, pattern + 3, queue); + + bc::vector<bc::char_>::iterator iter = + bc::find_end(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == (vectort.begin() + 15)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_flat_map.cpp b/src/boost/libs/compute/test/test_flat_map.cpp new file mode 100644 index 00000000..c1f96aa8 --- /dev/null +++ b/src/boost/libs/compute/test/test_flat_map.cpp @@ -0,0 +1,147 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFlatMap +#include <boost/test/unit_test.hpp> + +#include <utility> + +#include <boost/concept_check.hpp> + +#include <boost/compute/source.hpp> +#include <boost/compute/container/flat_map.hpp> +#include <boost/compute/type_traits/type_name.hpp> +#include <boost/compute/type_traits/type_definition.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(concept_check) +{ + BOOST_CONCEPT_ASSERT((boost::Container<boost::compute::flat_map<int, float> >)); +// BOOST_CONCEPT_ASSERT((boost::SimpleAssociativeContainer<boost::compute::flat_map<int, float> >)); +// BOOST_CONCEPT_ASSERT((boost::UniqueAssociativeContainer<boost::compute::flat_map<int, float> >)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<boost::compute::flat_map<int, float>::iterator>)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<boost::compute::flat_map<int, float>::const_iterator>)); +} + +BOOST_AUTO_TEST_CASE(insert) +{ + boost::compute::flat_map<int, float> map(context); + map.insert(std::make_pair(1, 1.1f), queue); + map.insert(std::make_pair(-1, -1.1f), queue); + map.insert(std::make_pair(3, 3.3f), queue); + map.insert(std::make_pair(2, 2.2f), queue); + BOOST_CHECK_EQUAL(map.size(), size_t(4)); + BOOST_CHECK(map.find(-1) == map.begin() + 0); + BOOST_CHECK(map.find(1) == map.begin() + 1); + BOOST_CHECK(map.find(2) == map.begin() + 2); + BOOST_CHECK(map.find(3) == map.begin() + 3); + + map.insert(std::make_pair(2, -2.2f), queue); + BOOST_CHECK_EQUAL(map.size(), size_t(4)); +} + +BOOST_AUTO_TEST_CASE(at) +{ + boost::compute::flat_map<int, float> map(context); + map.insert(std::make_pair(1, 1.1f), queue); + map.insert(std::make_pair(4, 4.4f), queue); + map.insert(std::make_pair(3, 3.3f), queue); + map.insert(std::make_pair(2, 2.2f), queue); + BOOST_CHECK_EQUAL(float(map.at(1)), float(1.1f)); + BOOST_CHECK_EQUAL(float(map.at(2)), float(2.2f)); + BOOST_CHECK_EQUAL(float(map.at(3)), float(3.3f)); + BOOST_CHECK_EQUAL(float(map.at(4)), float(4.4f)); +} + +BOOST_AUTO_TEST_CASE(index_operator) +{ + boost::compute::flat_map<int, float> map; + map[1] = 1.1f; + map[2] = 2.2f; + map[3] = 3.3f; + map[4] = 4.4f; + BOOST_CHECK_EQUAL(float(map[1]), float(1.1f)); + BOOST_CHECK_EQUAL(float(map[2]), float(2.2f)); + BOOST_CHECK_EQUAL(float(map[3]), float(3.3f)); + BOOST_CHECK_EQUAL(float(map[4]), float(4.4f)); +} + +BOOST_AUTO_TEST_CASE(custom_kernel) +{ + typedef boost::compute::flat_map<int, float> MapType; + + // map from int->float on device + MapType map(context); + map.insert(std::make_pair(1, 1.2f), queue); + map.insert(std::make_pair(3, 3.4f), queue); + map.insert(std::make_pair(5, 5.6f), queue); + map.insert(std::make_pair(7, 7.8f), queue); + + // simple linear search for key in map + const char lookup_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void lookup(__global const MapType *map, + const int map_size, + const KeyType key, + __global ValueType *result) + { + for(int i = 0; i < map_size; i++){ + if(map[i].first == key){ + *result = map[i].second; + break; + } + } + } + ); + + // create program source + std::stringstream source; + + // add type definition for map type + source << boost::compute::type_definition<MapType::value_type>(); + + // add lookup function source + source << lookup_source; + + // create lookup program + boost::compute::program lookup_program = + boost::compute::program::create_with_source(source.str(), context); + + // program build options + std::stringstream options; + options << "-DMapType=" << boost::compute::type_name<MapType::value_type>() + << " -DKeyType=" << boost::compute::type_name<MapType::key_type>() + << " -DValueType=" << boost::compute::type_name<MapType::mapped_type>(); + + // build lookup program with options + lookup_program.build(options.str()); + + // create buffer for result value + boost::compute::vector<float> result(1, context); + + // create lookup kernel + boost::compute::kernel lookup_kernel = lookup_program.create_kernel("lookup"); + + // set kernel arguments + lookup_kernel.set_arg(0, map.begin().get_buffer()); // map buffer + lookup_kernel.set_arg<boost::compute::int_>( + 1, static_cast<boost::compute::int_>(map.size()) + ); // map size + lookup_kernel.set_arg<MapType::key_type>(2, 5); // key + lookup_kernel.set_arg(3, result.get_buffer()); // result buffer + + // run kernel with a single work-item + queue.enqueue_task(lookup_kernel); + + // check result from buffer + BOOST_CHECK_EQUAL(result.begin().read(queue), 5.6f); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_flat_set.cpp b/src/boost/libs/compute/test/test_flat_set.cpp new file mode 100644 index 00000000..798bf4ce --- /dev/null +++ b/src/boost/libs/compute/test/test_flat_set.cpp @@ -0,0 +1,136 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFlatSet +#include <boost/test/unit_test.hpp> + +#include <utility> + +#include <boost/concept_check.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/container/flat_set.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(concept_check) +{ + BOOST_CONCEPT_ASSERT((boost::Container<bc::flat_set<int> >)); +// BOOST_CONCEPT_ASSERT((boost::SimpleAssociativeContainer<bc::flat_set<int> >)); +// BOOST_CONCEPT_ASSERT((boost::UniqueAssociativeContainer<bc::flat_set<int> >)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<bc::flat_set<int>::iterator>)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<bc::flat_set<int>::const_iterator>)); +} + +BOOST_AUTO_TEST_CASE(insert) +{ + bc::flat_set<int> set(context); + typedef bc::flat_set<int>::iterator iterator; + std::pair<iterator, bool> location = set.insert(12, queue); + queue.finish(); + BOOST_CHECK(location.first == set.begin()); + BOOST_CHECK(location.second == true); + BOOST_CHECK_EQUAL(*location.first, 12); + BOOST_CHECK_EQUAL(set.size(), size_t(1)); + + location = set.insert(12, queue); + queue.finish(); + BOOST_CHECK(location.first == set.begin()); + BOOST_CHECK(location.second == false); + BOOST_CHECK_EQUAL(set.size(), size_t(1)); + + location = set.insert(4, queue); + queue.finish(); + BOOST_CHECK(location.first == set.begin()); + BOOST_CHECK(location.second == true); + BOOST_CHECK_EQUAL(set.size(), size_t(2)); + + location = set.insert(12, queue); + queue.finish(); + BOOST_CHECK(location.first == set.begin() + 1); + BOOST_CHECK(location.second == false); + BOOST_CHECK_EQUAL(set.size(), size_t(2)); + + location = set.insert(9, queue); + queue.finish(); + BOOST_CHECK(location.first == set.begin() + 1); + BOOST_CHECK(location.second == true); + BOOST_CHECK_EQUAL(set.size(), size_t(3)); +} + +BOOST_AUTO_TEST_CASE(erase) +{ + bc::flat_set<int> set(context); + typedef bc::flat_set<int>::iterator iterator; + set.insert(1, queue); + set.insert(2, queue); + set.insert(3, queue); + set.insert(4, queue); + set.insert(5, queue); + queue.finish(); + BOOST_CHECK_EQUAL(set.size(), size_t(5)); + + iterator i = set.erase(set.begin(), queue); + queue.finish(); + BOOST_CHECK(i == set.begin() + 1); + BOOST_CHECK_EQUAL(set.size(), size_t(4)); + BOOST_CHECK_EQUAL(*set.begin(), 2); + + size_t count = set.erase(3, queue); + queue.finish(); + BOOST_CHECK_EQUAL(count, size_t(1)); + BOOST_CHECK_EQUAL(set.size(), size_t(3)); + BOOST_CHECK_EQUAL(*set.begin(), 2); + + count = set.erase(9, queue); + queue.finish(); + BOOST_CHECK_EQUAL(count, size_t(0)); + BOOST_CHECK_EQUAL(set.size(), size_t(3)); + BOOST_CHECK_EQUAL(*set.begin(), 2); + + i = set.erase(set.begin() + 1, queue); + queue.finish(); + BOOST_CHECK(i == set.begin() + 2); + BOOST_CHECK_EQUAL(set.size(), size_t(2)); + BOOST_CHECK_EQUAL(*set.begin(), 2); + BOOST_CHECK_EQUAL(*(set.end() - 1), 5); + + set.erase(set.begin(), set.end(), queue); + queue.finish(); + BOOST_CHECK_EQUAL(set.size(), size_t(0)); +} + +BOOST_AUTO_TEST_CASE(clear) +{ + bc::flat_set<float> set; + BOOST_CHECK(set.empty() == true); + BOOST_CHECK_EQUAL(set.size(), size_t(0)); + + set.clear(); + BOOST_CHECK(set.empty() == true); + BOOST_CHECK_EQUAL(set.size(), size_t(0)); + + set.insert(3.14f); + BOOST_CHECK(set.empty() == false); + BOOST_CHECK_EQUAL(set.size(), size_t(1)); + + set.insert(4.184f); + BOOST_CHECK(set.empty() == false); + BOOST_CHECK_EQUAL(set.size(), size_t(2)); + + set.clear(); + BOOST_CHECK(set.empty() == true); + BOOST_CHECK_EQUAL(set.size(), size_t(0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_for_each.cpp b/src/boost/libs/compute/test/test_for_each.cpp new file mode 100644 index 00000000..d695738e --- /dev/null +++ b/src/boost/libs/compute/test/test_for_each.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestForEach +#include <boost/test/unit_test.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/for_each.hpp> +#include <boost/compute/algorithm/for_each_n.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(for_each_nop) +{ + bc::vector<int> vector(4, context); + bc::iota(vector.begin(), vector.end(), 0, queue); + + BOOST_COMPUTE_FUNCTION(void, nop, (int ignored), {}); + + bc::for_each(vector.begin(), vector.end(), nop, queue); + queue.finish(); +} + +BOOST_AUTO_TEST_CASE(for_each_n_nop) +{ + bc::vector<int> vector(4, context); + bc::iota(vector.begin(), vector.end(), 0, queue); + + BOOST_COMPUTE_FUNCTION(void, nop, (int ignored), {}); + + bc::for_each_n(vector.begin(), vector.size(), nop, queue); + queue.finish(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_function.cpp b/src/boost/libs/compute/test/test_function.cpp new file mode 100644 index 00000000..63889dcb --- /dev/null +++ b/src/boost/libs/compute/test/test_function.cpp @@ -0,0 +1,209 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunction +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/accumulate.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/generate.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/zip_iterator.hpp> +#include <boost/compute/types/pair.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(add_three) +{ + BOOST_COMPUTE_FUNCTION(int, add_three, (int x), + { + return x + 3; + }); + + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), add_three, queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (4, 5, 6, 7)); +} + +BOOST_AUTO_TEST_CASE(sum_odd_values) +{ + BOOST_COMPUTE_FUNCTION(int, add_odd_value, (int sum, int value), + { + if(value & 1){ + return sum + value; + } + else { + return sum + 0; + } + }); + + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> vector(data, data + 8, queue); + + int result = compute::accumulate( + vector.begin(), vector.end(), 0, add_odd_value, queue + ); + BOOST_CHECK_EQUAL(result, 16); +} + +BOOST_AUTO_TEST_CASE(sort_pairs) +{ + if(device.vendor() == "NVIDIA" && device.platform().name() == "Apple"){ + // FIXME: this test currently segfaults on NVIDIA GPUs on Apple + std::cerr << "skipping sort_pairs test on NVIDIA GPU on Apple platform" << std::endl; + return; + } + + std::vector<std::pair<int, float> > data; + data.push_back(std::make_pair(1, 2.3f)); + data.push_back(std::make_pair(0, 4.2f)); + data.push_back(std::make_pair(2, 1.0f)); + + compute::vector<std::pair<int, float> > vector(data.begin(), data.end(), queue); + + // sort by first component + BOOST_COMPUTE_FUNCTION(bool, compare_first, (std::pair<int, float> a, std::pair<int, float> b), + { + return a.first < b.first; + }); + + compute::sort(vector.begin(), vector.end(), compare_first, queue); + compute::copy(vector.begin(), vector.end(), data.begin(), queue); + BOOST_CHECK(data[0] == std::make_pair(0, 4.2f)); + BOOST_CHECK(data[1] == std::make_pair(1, 2.3f)); + BOOST_CHECK(data[2] == std::make_pair(2, 1.0f)); + + // sort by second component + BOOST_COMPUTE_FUNCTION(bool, compare_second, (std::pair<int, float> a, std::pair<int, float> b), + { + return a.second < b.second; + }); + + compute::sort(vector.begin(), vector.end(), compare_second, queue); + compute::copy(vector.begin(), vector.end(), data.begin(), queue); + BOOST_CHECK(data[0] == std::make_pair(2, 1.0f)); + BOOST_CHECK(data[1] == std::make_pair(1, 2.3f)); + BOOST_CHECK(data[2] == std::make_pair(0, 4.2f)); +} + +BOOST_AUTO_TEST_CASE(transform_zip_iterator) +{ + float float_data[] = { 1.f, 2.f, 3.f, 4.f }; + compute::vector<float> input_floats(float_data, float_data + 4, queue); + + int int_data[] = { 2, 4, 6, 8 }; + compute::vector<int> input_ints(int_data, int_data + 4, queue); + + compute::vector<float> results(4, context); + + BOOST_COMPUTE_FUNCTION(float, tuple_pown, (boost::tuple<float, int> x), + { + return pown(boost_tuple_get(x, 0), boost_tuple_get(x, 1)); + }); + + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input_floats.begin(), input_ints.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input_floats.end(), input_ints.end()) + ), + results.begin(), + tuple_pown, + queue + ); + + float results_data[4]; + compute::copy(results.begin(), results.end(), results_data, queue); + BOOST_CHECK_CLOSE(results_data[0], 1.f, 1e-4); + BOOST_CHECK_CLOSE(results_data[1], 16.f, 1e-4); + BOOST_CHECK_CLOSE(results_data[2], 729.f, 1e-4); + BOOST_CHECK_CLOSE(results_data[3], 65536.f, 1e-4); +} + +static BOOST_COMPUTE_FUNCTION(int, static_function, (int x), +{ + return x + 5; +}); + +BOOST_AUTO_TEST_CASE(test_static_function) +{ + int data[] = { 1, 2, 3, 4}; + compute::vector<int> vec(data, data + 4, queue); + + compute::transform( + vec.begin(), vec.end(), vec.begin(), static_function, queue + ); + CHECK_RANGE_EQUAL(int, 4, vec, (6, 7, 8, 9)); +} + +template<class T> +inline compute::function<T(T)> make_negate_function() +{ + BOOST_COMPUTE_FUNCTION(T, negate, (const T x), + { + return -x; + }); + + return negate; +} + +BOOST_AUTO_TEST_CASE(test_templated_function) +{ + int int_data[] = { 1, 2, 3, 4 }; + compute::vector<int> int_vec(int_data, int_data + 4, queue); + + compute::function<int(int)> negate_int = make_negate_function<int>(); + compute::transform( + int_vec.begin(), int_vec.end(), int_vec.begin(), negate_int, queue + ); + CHECK_RANGE_EQUAL(int, 4, int_vec, (-1, -2, -3, -4)); + + float float_data[] = { 1.1f, 2.2f, 3.3f, 4.4f }; + compute::vector<float> float_vec(float_data, float_data + 4, queue); + + compute::function<float(float)> negate_float = make_negate_function<float>(); + compute::transform( + float_vec.begin(), float_vec.end(), float_vec.begin(), negate_float, queue + ); + CHECK_RANGE_EQUAL(float, 4, float_vec, (-1.1f, -2.2f, -3.3f, -4.4f)); +} + +BOOST_AUTO_TEST_CASE(define) +{ + BOOST_COMPUTE_FUNCTION(int, return_number, (), + { + return NUMBER; + }); + return_number.define("NUMBER", "4"); + + compute::vector<int> vec(1, context); + compute::generate(vec.begin(), vec.end(), return_number, queue); + CHECK_RANGE_EQUAL(int, 1, vec, (4)); + + return_number.define("NUMBER", "2"); + compute::generate(vec.begin(), vec.end(), return_number, queue); + CHECK_RANGE_EQUAL(int, 1, vec, (2)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_function_input_iterator.cpp b/src/boost/libs/compute/test/test_function_input_iterator.cpp new file mode 100644 index 00000000..b5c315f7 --- /dev/null +++ b/src/boost/libs/compute/test/test_function_input_iterator.cpp @@ -0,0 +1,50 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionInputIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/function_input_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(generate_42_doctest) +{ + boost::compute::vector<int> result(4, context); + +//! [generate_42] +BOOST_COMPUTE_FUNCTION(int, ret42, (), +{ + return 42; +}); + +boost::compute::copy( + boost::compute::make_function_input_iterator(ret42, 0), + boost::compute::make_function_input_iterator(ret42, result.size()), + result.begin(), + queue +); + +// result == { 42, 42, 42, 42 } +//! [generate_42] + + CHECK_RANGE_EQUAL(int, 4, result, (42, 42, 42, 42)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_as.cpp b/src/boost/libs/compute/test/test_functional_as.cpp new file mode 100644 index 00000000..f1318b0a --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_as.cpp @@ -0,0 +1,59 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalAs +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/as.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(roundtrip_int_float) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> input(8, context); + compute::copy_n(data, 8, input.begin(), queue); + + // convert int -> float + compute::vector<float> output(8, context); + compute::transform( + input.begin(), + input.end(), + output.begin(), + compute::as<float>(), + queue + ); + + // zero out input + compute::fill(input.begin(), input.end(), 0, queue); + + // convert float -> int + compute::transform( + output.begin(), + output.end(), + input.begin(), + compute::as<int>(), + queue + ); + + // check values + CHECK_RANGE_EQUAL( + int, 8, input, (1, 2, 3, 4, 5, 6, 7, 8) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_bind.cpp b/src/boost/libs/compute/test/test_functional_bind.cpp new file mode 100644 index 00000000..327232d8 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_bind.cpp @@ -0,0 +1,237 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalBind +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/algorithm/find_if.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/bind.hpp> +#include <boost/compute/functional/common.hpp> +#include <boost/compute/functional/operator.hpp> +#include <boost/compute/types/struct.hpp> + +// simple test struct +struct data_struct +{ + int int_value; + float float_value; +}; + +BOOST_COMPUTE_ADAPT_STRUCT(data_struct, data_struct, (int_value, float_value)) + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +using compute::placeholders::_1; +using compute::placeholders::_2; + +BOOST_AUTO_TEST_CASE(transform_plus_two) +{ + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(4, context); + compute::copy_n(data, 4, vector.begin(), queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(compute::plus<int>(), _1, 2), + queue + ); + + CHECK_RANGE_EQUAL(int, 4, vector, (3, 4, 5, 6)); +} + +BOOST_AUTO_TEST_CASE(transform_pow_two) +{ + float data[] = { 2, 3, 4, 5 }; + compute::vector<float> vector(4, context); + compute::copy_n(data, 4, vector.begin(), queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(compute::pow<float>(), 2.0f, _1), + queue + ); + + compute::copy(vector.begin(), vector.end(), data, queue); + BOOST_CHECK_CLOSE(data[0], 4.0f, 1e-4); + BOOST_CHECK_CLOSE(data[1], 8.0f, 1e-4); + BOOST_CHECK_CLOSE(data[2], 16.0f, 1e-4); + BOOST_CHECK_CLOSE(data[3], 32.0f, 1e-4); +} + +BOOST_AUTO_TEST_CASE(find_if_equal) +{ + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(4, context); + compute::copy_n(data, 4, vector.begin(), queue); + + BOOST_CHECK( + compute::find_if( + vector.begin(), vector.end(), + compute::bind(compute::equal_to<int>(), _1, 3), + queue + ) == vector.begin() + 2 + ); +} + +BOOST_AUTO_TEST_CASE(compare_less_than) +{ + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + int count = boost::compute::count_if( + vector.begin(), vector.end(), + compute::bind(compute::less<int>(), _1, int(3)), + queue + ); + BOOST_CHECK_EQUAL(count, 2); + + count = boost::compute::count_if( + vector.begin(), vector.end(), + compute::bind(compute::less<int>(), int(3), _1), + queue + ); + BOOST_CHECK_EQUAL(count, 1); +} + +BOOST_AUTO_TEST_CASE(subtract_ranges) +{ + int data1[] = { 1, 2, 3, 4 }; + int data2[] = { 4, 3, 2, 1 }; + + compute::vector<int> vector1(data1, data1 + 4, queue); + compute::vector<int> vector2(data2, data2 + 4, queue); + + compute::vector<int> result(4, context); + + compute::transform( + vector1.begin(), + vector1.end(), + vector2.begin(), + result.begin(), + compute::bind(compute::minus<int>(), _1, _2), + queue + ); + CHECK_RANGE_EQUAL(int, 4, result, (-3, -1, 1, 3)); + + compute::transform( + vector1.begin(), + vector1.end(), + vector2.begin(), + result.begin(), + compute::bind(compute::minus<int>(), _2, _1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, result, (3, 1, -1, -3)); + + compute::transform( + vector1.begin(), + vector1.end(), + vector2.begin(), + result.begin(), + compute::bind(compute::minus<int>(), 5, _1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, result, (4, 3, 2, 1)); + + compute::transform( + vector1.begin(), + vector1.end(), + vector2.begin(), + result.begin(), + compute::bind(compute::minus<int>(), 5, _2), + queue + ); + CHECK_RANGE_EQUAL(int, 4, result, (1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_CASE(clamp_values) +{ + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(compute::clamp<int>(), _1, 2, 3), + queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (2, 2, 3, 3)); +} + +BOOST_AUTO_TEST_CASE(bind_custom_function) +{ + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + BOOST_COMPUTE_FUNCTION(int, x_if_odd_else_y, (int x, int y), + { + if(x & 1) + return x; + else + return y; + }); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(x_if_odd_else_y, _1, 9), + queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (1, 9, 3, 9)); + + compute::copy( + data, data + 4, vector.begin(), queue + ); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(x_if_odd_else_y, 2, _1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_CASE(bind_struct) +{ + if(bug_in_struct_assignment(device)){ + std::cerr << "skipping bind_struct test" << std::endl; + return; + } + + BOOST_COMPUTE_FUNCTION(int, add_struct_value, (int x, data_struct s), + { + return s.int_value + x; + }); + + data_struct data; + data.int_value = 3; + data.float_value = 4.56f; + + int input[] = { 1, 2, 3, 4 }; + compute::vector<int> vec(input, input + 4, queue); + + compute::transform( + vec.begin(), vec.end(), vec.begin(), + compute::bind(add_struct_value, _1, data), + queue + ); + CHECK_RANGE_EQUAL(int, 4, vec, (4, 5, 6, 7)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_convert.cpp b/src/boost/libs/compute/test/test_functional_convert.cpp new file mode 100644 index 00000000..b3303af3 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_convert.cpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalConvert +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/convert.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(convert_int_float) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> input(8, context); + compute::copy_n(data, 8, input.begin(), queue); + + compute::vector<float> output(8, context); + compute::transform( + input.begin(), + input.end(), + output.begin(), + compute::convert<float>(), + queue + ); + CHECK_RANGE_EQUAL( + float, 8, output, (1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_get.cpp b/src/boost/libs/compute/test/test_functional_get.cpp new file mode 100644 index 00000000..9536145e --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_get.cpp @@ -0,0 +1,83 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalGet +#include <boost/test/unit_test.hpp> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/types/pair.hpp> +#include <boost/compute/types/tuple.hpp> +#include <boost/compute/types/fundamental.hpp> +#include <boost/compute/functional/get.hpp> +#include <boost/compute/type_traits/result_of.hpp> + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(get_vector_result_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<0>(compute::float4_) + >::type, + float + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<1>(compute::int2_) + >::type, + int + >::value + )); +} + +BOOST_AUTO_TEST_CASE(get_pair_result_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<0>(std::pair<int, float>) + >::type, + int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<1>(std::pair<compute::float2_, compute::char4_>) + >::type, + compute::char4_ + >::value + )); +} + +BOOST_AUTO_TEST_CASE(get_tuple_result_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<0>(boost::tuple<int, int, double>) + >::type, + int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::result_of< + compute::get<2>(boost::tuple<char, int, float>) + >::type, + float + >::value + )); +} diff --git a/src/boost/libs/compute/test/test_functional_hash.cpp b/src/boost/libs/compute/test/test_functional_hash.cpp new file mode 100644 index 00000000..e6e1c112 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_hash.cpp @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalHash +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/hash.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(hash_int) +{ + using compute::ulong_; + + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> input_values(data, data + 4, queue); + compute::vector<ulong_> hash_values(4, context); + + compute::transform( + input_values.begin(), + input_values.end(), + hash_values.begin(), + compute::hash<int>(), + queue + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_identity.cpp b/src/boost/libs/compute/test/test_functional_identity.cpp new file mode 100644 index 00000000..93534c05 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_identity.cpp @@ -0,0 +1,39 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalIdentity +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/identity.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(copy_with_identity_transform) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> input(data, data + 8, queue); + compute::vector<int> output(8, context); + + compute::transform( + input.begin(), input.end(), output.begin(), compute::identity<int>(), queue + ); + + CHECK_RANGE_EQUAL( + int, 8, output, (1, 2, 3, 4, 5, 6, 7, 8) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_popcount.cpp b/src/boost/libs/compute/test/test_functional_popcount.cpp new file mode 100644 index 00000000..4a15a508 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_popcount.cpp @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalPopcount +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/popcount.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +typedef boost::mpl::list< + compute::uchar_, compute::ushort_, compute::uint_, compute::ulong_ +> popcount_test_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(popcount, T, popcount_test_types) +{ + compute::vector<T> vec(context); + vec.push_back(0x00, queue); + vec.push_back(0x01, queue); + vec.push_back(0x03, queue); + vec.push_back(0xff, queue); + + compute::vector<int> popcounts(vec.size(), context); + compute::transform( + vec.begin(), vec.end(), popcounts.begin(), compute::popcount<T>(), queue + ); + CHECK_RANGE_EQUAL(int, 4, popcounts, (0, 1, 2, 8)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_functional_unpack.cpp b/src/boost/libs/compute/test/test_functional_unpack.cpp new file mode 100644 index 00000000..98460071 --- /dev/null +++ b/src/boost/libs/compute/test/test_functional_unpack.cpp @@ -0,0 +1,99 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestFunctionalUnpack +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/zip_iterator.hpp> +#include <boost/compute/functional/detail/unpack.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(plus_int) +{ + int data1[] = { 1, 3, 5, 7 }; + int data2[] = { 2, 4, 6, 8 }; + + compute::vector<int> input1(4, context); + compute::vector<int> input2(4, context); + + compute::copy_n(data1, 4, input1.begin(), queue); + compute::copy_n(data2, 4, input2.begin(), queue); + + compute::vector<int> output(4, context); + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input1.begin(), input2.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input1.end(), input2.end()) + ), + output.begin(), + compute::detail::unpack(compute::plus<int>()), + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (3, 7, 11, 15)); +} + +BOOST_AUTO_TEST_CASE(fma_float) +{ + float data1[] = { 1, 3, 5, 7 }; + float data2[] = { 2, 4, 6, 8 }; + float data3[] = { 0, 9, 1, 2 }; + + compute::vector<float> input1(4, context); + compute::vector<float> input2(4, context); + compute::vector<float> input3(4, context); + + compute::copy_n(data1, 4, input1.begin(), queue); + compute::copy_n(data2, 4, input2.begin(), queue); + compute::copy_n(data3, 4, input3.begin(), queue); + + compute::vector<int> output(4, context); + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input1.begin(), input2.begin(), input3.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input1.end(), input2.end(), input3.begin()) + ), + output.begin(), + compute::detail::unpack(compute::fma<float>()), + queue + ); +} + +BOOST_AUTO_TEST_CASE(subtract_int2) +{ + using compute::int2_; + + int data[] = { 4, 2, 5, 1, 6, 3, 7, 0 }; + compute::vector<int2_> input(4, context); + compute::copy_n(reinterpret_cast<int2_ *>(data), 4, input.begin(), queue); + + compute::vector<int> output(4, context); + compute::transform( + input.begin(), + input.end(), + output.begin(), + compute::detail::unpack(compute::minus<int>()), + queue + ); + CHECK_RANGE_EQUAL(int, 4, output, (2, 4, 3, 7)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_gather.cpp b/src/boost/libs/compute/test/test_gather.cpp new file mode 100644 index 00000000..2d6af2c8 --- /dev/null +++ b/src/boost/libs/compute/test/test_gather.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestGather +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_if.hpp> +#include <boost/compute/algorithm/gather.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(gather_int) +{ + int input_data[] = { 1, 2, 3, 4, 5 }; + compute::vector<int> input(input_data, input_data + 5, queue); + + int indices_data[] = { 0, 4, 1, 3, 2 }; + compute::vector<int> indices(indices_data, indices_data + 5, queue); + + compute::vector<int> output(5, context); + compute::gather( + indices.begin(), indices.end(), input.begin(), output.begin(), queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (1, 5, 2, 4, 3)); + + compute::gather( + indices.begin() + 1, indices.end(), input.begin(), output.begin(), queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (5, 2, 4, 3, 3)); +} + +BOOST_AUTO_TEST_CASE(copy_index_then_gather) +{ + // input data + int data[] = { 1, 4, 3, 2, 5, 9, 8, 7 }; + compute::vector<int> input(data, data + 8, queue); + + // function returning true if the input is odd + BOOST_COMPUTE_FUNCTION(bool, is_odd, (int x), + { + return x % 2 != 0; + }); + + // copy indices of all odd values + compute::vector<int> odds(5, context); + compute::detail::copy_index_if( + input.begin(), input.end(), odds.begin(), is_odd, queue + ); + CHECK_RANGE_EQUAL(int, 5, odds, (0, 2, 4, 5, 7)); + + // gather all odd values + compute::vector<int> odd_values(5, context); + compute::gather( + odds.begin(), odds.end(), input.begin(), odd_values.begin(), queue + ); + CHECK_RANGE_EQUAL(int, 5, odd_values, (1, 3, 5, 9, 7)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_generate.cpp b/src/boost/libs/compute/test/test_generate.cpp new file mode 100644 index 00000000..aeec0a72 --- /dev/null +++ b/src/boost/libs/compute/test/test_generate.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestGenerate +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/generate.hpp> +#include <boost/compute/algorithm/generate_n.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/pair.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(generate4) +{ + bc::vector<int> vector(4, context); + bc::fill(vector.begin(), vector.end(), 2, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (2, 2, 2, 2)); + + BOOST_COMPUTE_FUNCTION(int, ret4, (void), + { + return 4; + }); + + bc::generate(vector.begin(), vector.end(), ret4, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (4, 4, 4, 4)); +} + +BOOST_AUTO_TEST_CASE(generate_pair) +{ + if(bug_in_struct_assignment(device)){ + std::cerr << "skipping generate_pair test" << std::endl; + return; + } + + // in order to use std::pair<T1, T2> with BOOST_COMPUTE_FUNCTION() macro we + // need a typedef. otherwise the commas in the type declaration screw it up. + typedef std::pair<int, float> pair_type; + + bc::vector<pair_type> vector(3, context); + + BOOST_COMPUTE_FUNCTION(pair_type, generate_pair, (void), + { + return boost_make_pair(int, 2, float, 3.14f); + }); + + bc::generate(vector.begin(), vector.end(), generate_pair, queue); + + // check results + std::vector<pair_type> host_vector(3); + bc::copy(vector.begin(), vector.end(), host_vector.begin(), queue); + BOOST_CHECK(host_vector[0] == std::make_pair(2, 3.14f)); + BOOST_CHECK(host_vector[1] == std::make_pair(2, 3.14f)); + BOOST_CHECK(host_vector[2] == std::make_pair(2, 3.14f)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_image1d.cpp b/src/boost/libs/compute/test/test_image1d.cpp new file mode 100644 index 00000000..364d19ed --- /dev/null +++ b/src/boost/libs/compute/test/test_image1d.cpp @@ -0,0 +1,70 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestImage1D +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/image/image1d.hpp> +#include <boost/compute/utility/dim.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(image1d_get_supported_formats) +{ + const std::vector<compute::image_format> formats = + compute::image1d::get_supported_formats(context); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_2 +BOOST_AUTO_TEST_CASE(fill_image1d) +{ + REQUIRES_OPENCL_VERSION(1, 2); // device OpenCL version check + + // single-channel unsigned char + compute::image_format format(CL_R, CL_UNSIGNED_INT8); + + if(!compute::image1d::is_supported_format(format, context)){ + std::cerr << "skipping fill_image1d test, image format not supported" << std::endl; + return; + } + + compute::image1d img(context, 64, format); + + BOOST_CHECK_EQUAL(img.width(), size_t(64)); + BOOST_CHECK(img.size() == compute::dim(64)); + BOOST_CHECK(img.format() == format); + + // fill image with '128' + compute::uint4_ fill_color(128, 0, 0, 0); + queue.enqueue_fill_image(img, &fill_color, img.origin(), img.size()); + + // read value of first pixel + compute::uchar_ first_pixel = 0; + queue.enqueue_read_image(img, compute::dim(0), compute::dim(1), &first_pixel); + BOOST_CHECK_EQUAL(first_pixel, compute::uchar_(128)); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_2 + +// check type_name() for image1d +BOOST_AUTO_TEST_CASE(image1d_type_name) +{ + BOOST_CHECK( + std::strcmp( + boost::compute::type_name<boost::compute::image1d>(), "image1d_t" + ) == 0 + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_image2d.cpp b/src/boost/libs/compute/test/test_image2d.cpp new file mode 100644 index 00000000..2ae56c47 --- /dev/null +++ b/src/boost/libs/compute/test/test_image2d.cpp @@ -0,0 +1,226 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestImage2D +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/image/image2d.hpp> +#include <boost/compute/utility/dim.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(image2d_get_supported_formats) +{ + const std::vector<compute::image_format> formats = + compute::image2d::get_supported_formats(context); +} + +BOOST_AUTO_TEST_CASE(create_image_doctest) +{ + try { +//! [create_image] +// create 8-bit RGBA image format +boost::compute::image_format rgba8(CL_RGBA, CL_UNSIGNED_INT8); + +// create 640x480 image object +boost::compute::image2d img(context, 640, 480, rgba8); +//! [create_image] + + // verify image has been created and format is correct + BOOST_CHECK(img.get() != cl_mem()); + BOOST_CHECK(img.format() == rgba8); + BOOST_CHECK_EQUAL(img.width(), size_t(640)); + BOOST_CHECK_EQUAL(img.height(), size_t(480)); + } + catch(compute::opencl_error &e){ + if(e.error_code() == CL_IMAGE_FORMAT_NOT_SUPPORTED){ + // image format not supported by device + return; + } + + // some other error, rethrow + throw; + } +} + +BOOST_AUTO_TEST_CASE(get_info) +{ + compute::image_format format(CL_RGBA, CL_UNSIGNED_INT8); + + if(!compute::image2d::is_supported_format(format, context)){ + std::cerr << "skipping get_info test, image format not supported" << std::endl; + return; + } + + compute::image2d image( + context, 48, 64, format, compute::image2d::read_only + ); + + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_WIDTH), size_t(48)); + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_HEIGHT), size_t(64)); + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_DEPTH), size_t(0)); + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_ROW_PITCH), size_t(48*4)); + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_SLICE_PITCH), size_t(0)); + BOOST_CHECK_EQUAL(image.get_info<size_t>(CL_IMAGE_ELEMENT_SIZE), size_t(4)); + + BOOST_CHECK(image.format() == format); + BOOST_CHECK_EQUAL(image.width(), size_t(48)); + BOOST_CHECK_EQUAL(image.height(), size_t(64)); +} + +BOOST_AUTO_TEST_CASE(clone_image) +{ + compute::image_format format(CL_RGBA, CL_UNORM_INT8); + + if(!compute::image2d::is_supported_format(format, context)){ + std::cerr << "skipping clone_image test, image format not supported" << std::endl; + return; + } + + // image data + unsigned int data[] = { 0x0000ffff, 0xff00ffff, + 0x00ff00ff, 0xffffffff }; + + // create image on the device + compute::image2d image(context, 2, 2, format); + + // ensure we have a valid image object + BOOST_REQUIRE(image.get() != cl_mem()); + + // copy image data to the device + queue.enqueue_write_image(image, image.origin(), image.size(), data); + + // clone image + compute::image2d copy = image.clone(queue); + + // ensure image format is the same + BOOST_CHECK(copy.format() == image.format()); + + // read cloned image data back to the host + unsigned int cloned_data[4]; + queue.enqueue_read_image(copy, image.origin(), image.size(), cloned_data); + + // ensure original data and cloned data are the same + BOOST_CHECK_EQUAL(cloned_data[0], data[0]); + BOOST_CHECK_EQUAL(cloned_data[1], data[1]); + BOOST_CHECK_EQUAL(cloned_data[2], data[2]); + BOOST_CHECK_EQUAL(cloned_data[3], data[3]); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_2 +BOOST_AUTO_TEST_CASE(fill_image) +{ + REQUIRES_OPENCL_VERSION(1, 2); // device OpenCL version check + + compute::image_format format(CL_RGBA, CL_UNSIGNED_INT8); + + if(!compute::image2d::is_supported_format(format, context)){ + std::cerr << "skipping fill_image test, image format not supported" << std::endl; + return; + } + + compute::image2d img(context, 640, 480, format); + + // fill image with black + compute::uint4_ black(0, 0, 0, 255); + queue.enqueue_fill_image(img, &black, img.origin(), img.size()); + + // read value of first pixel + compute::uchar4_ first_pixel; + queue.enqueue_read_image(img, compute::dim(0), compute::dim(1), &first_pixel); + BOOST_CHECK_EQUAL(first_pixel, compute::uchar4_(0, 0, 0, 255)); + + // fill image with white + compute::uint4_ white(255, 255, 255, 255); + queue.enqueue_fill_image(img, &white, img.origin(), img.size()); + + // read value of first pixel + queue.enqueue_read_image(img, compute::dim(0), compute::dim(1), &first_pixel); + BOOST_CHECK_EQUAL(first_pixel, compute::uchar4_(255, 255, 255, 255)); +} +#endif + +// check type_name() for image2d +BOOST_AUTO_TEST_CASE(image2d_type_name) +{ + BOOST_CHECK( + std::strcmp( + boost::compute::type_name<boost::compute::image2d>(), "image2d_t" + ) == 0 + ); +} + +BOOST_AUTO_TEST_CASE(map_image) +{ + compute::image_format format(CL_RGBA, CL_UNSIGNED_INT8); + + if(!compute::image2d::is_supported_format(format, context)){ + std::cerr << "skipping clone_image test, image format not supported" << std::endl; + return; + } + + // create image on the device + compute::image2d image(context, 2, 2, format); + + // ensure we have a valid image object + BOOST_REQUIRE(image.get() != cl_mem()); + + size_t row_pitch = 0; + size_t slice_pitch = 0; + + // write map image + compute::uint_* ptr = static_cast<compute::uint_*>( + queue.enqueue_map_image(image, CL_MAP_WRITE, image.origin(), + image.size(), row_pitch, slice_pitch) + ); + + BOOST_CHECK_EQUAL(row_pitch, size_t(2*4)); + + // image data + compute::uint_ data[] = { 0x0000ffff, 0xff00ffff, + 0x00ff00ff, 0xffffffff }; + + // copy data to image + for(size_t i = 0; i < 4; i++){ + *(ptr+i) = data[i]; + } + + // unmap + queue.enqueue_unmap_image(image, static_cast<void*>(ptr)); + + // read map image + compute::event map_event; + ptr = static_cast<compute::uint_*>( + queue.enqueue_map_image_async(image, CL_MAP_READ, image.origin(), + image.size(), row_pitch, slice_pitch, + map_event) + ); + + map_event.wait(); + + BOOST_CHECK(map_event.get_status() == CL_COMPLETE); + BOOST_CHECK_EQUAL(row_pitch, size_t(2*4)); + + // checking + for(size_t i = 0; i < 4; i++){ + BOOST_CHECK_EQUAL(*(ptr+i), data[i]); + } + + // unmap + queue.enqueue_unmap_image(image, static_cast<void*>(ptr)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_image3d.cpp b/src/boost/libs/compute/test/test_image3d.cpp new file mode 100644 index 00000000..ee1cc15d --- /dev/null +++ b/src/boost/libs/compute/test/test_image3d.cpp @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestImage3D +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/image/image3d.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(image3d_get_supported_formats) +{ + const std::vector<compute::image_format> formats = + compute::image3d::get_supported_formats(context); +} + +// check type_name() for image3d +BOOST_AUTO_TEST_CASE(image3d_type_name) +{ + BOOST_CHECK( + std::strcmp( + boost::compute::type_name<boost::compute::image3d>(), "image3d_t" + ) == 0 + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_image_sampler.cpp b/src/boost/libs/compute/test/test_image_sampler.cpp new file mode 100644 index 00000000..14b01381 --- /dev/null +++ b/src/boost/libs/compute/test/test_image_sampler.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestImageSampler +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/image/image_sampler.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(get_context) +{ + if(!supports_image_samplers(device)){ + std::cerr << "skipping get_context test" << std::endl; + return; + } + + compute::image_sampler sampler(context, true, CL_ADDRESS_NONE, CL_FILTER_NEAREST); + BOOST_CHECK(sampler.get_context() == context); +} + +BOOST_AUTO_TEST_CASE(get_info) +{ + if(!supports_image_samplers(device)){ + std::cerr << "skipping get_info test" << std::endl; + return; + } + + compute::image_sampler sampler(context, true, CL_ADDRESS_NONE, CL_FILTER_NEAREST); + BOOST_CHECK_EQUAL(sampler.get_info<bool>(CL_SAMPLER_NORMALIZED_COORDS), true); + BOOST_CHECK_EQUAL( + sampler.get_info<cl_addressing_mode>(CL_SAMPLER_ADDRESSING_MODE), + cl_addressing_mode(CL_ADDRESS_NONE) + ); + BOOST_CHECK_EQUAL( + sampler.get_info<cl_filter_mode>(CL_SAMPLER_FILTER_MODE), + cl_filter_mode(CL_FILTER_NEAREST) + ); + + sampler = compute::image_sampler(context, false, CL_ADDRESS_CLAMP, CL_FILTER_LINEAR); + BOOST_CHECK_EQUAL(sampler.get_info<bool>(CL_SAMPLER_NORMALIZED_COORDS), false); + BOOST_CHECK_EQUAL( + sampler.get_info<cl_addressing_mode>(CL_SAMPLER_ADDRESSING_MODE), + cl_addressing_mode(CL_ADDRESS_CLAMP) + ); + BOOST_CHECK_EQUAL( + sampler.get_info<cl_filter_mode>(CL_SAMPLER_FILTER_MODE), + cl_filter_mode(CL_FILTER_LINEAR) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_includes.cpp b/src/boost/libs/compute/test/test_includes.cpp new file mode 100644 index 00000000..9ecc42d0 --- /dev/null +++ b/src/boost/libs/compute/test/test_includes.cpp @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestIncludes +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/includes.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(includes_int) +{ + int dataset1[] = {1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 10}; + bc::vector<bc::int_> set1(dataset1, dataset1 + 12, queue); + + int dataset2[] = {2, 4, 5, 6}; + bc::vector<bc::int_> set2(dataset2, dataset2 + 4, queue); + + bool includes = bc::includes(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 4, queue); + BOOST_VERIFY(includes == true); + + set2[3] = 7; + includes = bc::includes(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 4, queue); + BOOST_VERIFY(includes == false); +} + +BOOST_AUTO_TEST_CASE(includes_string) +{ + char string1[] = "abcccdddeeff"; + bc::vector<bc::char_> set1(string1, string1 + 12, queue); + + char string2[] = "bccdf"; + bc::vector<bc::char_> set2(string2, string2 + 5, queue); + + bool includes = bc::includes(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 5, queue); + BOOST_VERIFY(includes == true); + + set2[0] = 'g'; + includes = bc::includes(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 4, queue); + BOOST_VERIFY(includes == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_inner_product.cpp b/src/boost/libs/compute/test/test_inner_product.cpp new file mode 100644 index 00000000..0c2d82c6 --- /dev/null +++ b/src/boost/libs/compute/test/test_inner_product.cpp @@ -0,0 +1,53 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInnerProduct +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/inner_product.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(inner_product_int) +{ + int data1[] = { 1, 2, 3, 4 }; + bc::vector<int> input1(data1, data1 + 4, queue); + + int data2[] = { 10, 20, 30, 40 }; + bc::vector<int> input2(data2, data2 + 4, queue); + + int product = bc::inner_product(input1.begin(), + input1.end(), + input2.begin(), + 0, + queue); + BOOST_CHECK_EQUAL(product, 300); +} + +BOOST_AUTO_TEST_CASE(inner_product_counting_iterator) +{ + BOOST_CHECK_EQUAL( + boost::compute::inner_product( + boost::compute::make_counting_iterator<int>(0), + boost::compute::make_counting_iterator<int>(100), + boost::compute::make_counting_iterator<int>(0), + 0, + queue + ), + 328350 + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_inplace_merge.cpp b/src/boost/libs/compute/test/test_inplace_merge.cpp new file mode 100644 index 00000000..f328ec15 --- /dev/null +++ b/src/boost/libs/compute/test/test_inplace_merge.cpp @@ -0,0 +1,47 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInplaceMerge +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/inplace_merge.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(simple_merge_int) +{ + int data[] = { 1, 3, 5, 7, 2, 4, 6, 8 }; + compute::vector<int> vector(data, data + 8, queue); + + // merge each half in-place + compute::inplace_merge( + vector.begin(), + vector.begin() + 4, + vector.end(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, vector, (1, 2, 3, 4, 5, 6, 7, 8)); + + // run again on already sorted list + compute::inplace_merge( + vector.begin(), + vector.begin() + 4, + vector.end(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, vector, (1, 2, 3, 4, 5, 6, 7, 8)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_inplace_reduce.cpp b/src/boost/libs/compute/test/test_inplace_reduce.cpp new file mode 100644 index 00000000..a0706e3a --- /dev/null +++ b/src/boost/libs/compute/test/test_inplace_reduce.cpp @@ -0,0 +1,138 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInplaceReduce +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/detail/inplace_reduce.hpp> +#include <boost/compute/container/vector.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(sum_int) +{ + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all inplace_reduce tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + int data[] = { 1, 5, 3, 4, 9, 3, 5, 3 }; + boost::compute::vector<int> vector(data, data + 8, queue); + + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(33)); + + vector.assign(data, data + 8); + vector.push_back(3); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(36)); +} + +BOOST_AUTO_TEST_CASE(multiply_int) +{ + if(is_apple_cpu_device(device)) { + return; + } + + int data[] = { 1, 5, 3, 4, 9, 3, 5, 3 }; + boost::compute::vector<int> vector(data, data + 8, queue); + + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::multiplies<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(24300)); + + vector.assign(data, data + 8); + vector.push_back(3); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::multiplies<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(72900)); +} + +BOOST_AUTO_TEST_CASE(reduce_iota) +{ + if(is_apple_cpu_device(device)) { + return; + } + + // 1 value + boost::compute::vector<int> vector(1, context); + boost::compute::iota(vector.begin(), vector.end(), int(0), queue); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(0)); + + // 1000 values + vector.resize(1000); + boost::compute::iota(vector.begin(), vector.end(), int(0), queue); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(499500)); + + // 2499 values + vector.resize(2499); + boost::compute::iota(vector.begin(), vector.end(), int(0), queue); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(3121251)); + + // 4096 values + vector.resize(4096); + boost::compute::iota(vector.begin(), vector.end(), int(0), queue); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(8386560)); + + // 5000 values + vector.resize(5000); + boost::compute::iota(vector.begin(), vector.end(), int(0), queue); + boost::compute::detail::inplace_reduce(vector.begin(), + vector.end(), + boost::compute::plus<int>(), + queue); + queue.finish(); + BOOST_CHECK_EQUAL(int(vector[0]), int(12497500)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_insertion_sort.cpp b/src/boost/libs/compute/test/test_insertion_sort.cpp new file mode 100644 index 00000000..a9088b5a --- /dev/null +++ b/src/boost/libs/compute/test/test_insertion_sort.cpp @@ -0,0 +1,171 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInsertionSort +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/detail/insertion_sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(sort_char_vector) +{ + using boost::compute::char_; + + char_ data[] = { 'c', 'a', '0', '7', 'B', 'F', '\0', '$' }; + boost::compute::vector<char_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(char_, 8, vector, ('\0', '$', '0', '7', 'B', 'F', 'a', 'c')); +} + +BOOST_AUTO_TEST_CASE(sort_uchar_vector) +{ + using boost::compute::uchar_; + + uchar_ data[] = { 0x12, 0x00, 0xFF, 0xB4, 0x80, 0x32, 0x64, 0xA2 }; + boost::compute::vector<uchar_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uchar_, 8, vector, (0x00, 0x12, 0x32, 0x64, 0x80, 0xA2, 0xB4, 0xFF)); +} + +BOOST_AUTO_TEST_CASE(sort_short_vector) +{ + using boost::compute::short_; + + short_ data[] = { -4, 152, -94, 963, 31002, -456, 0, -2113 }; + boost::compute::vector<short_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(short_, 8, vector, (-2113, -456, -94, -4, 0, 152, 963, 31002)); +} + +BOOST_AUTO_TEST_CASE(sort_ushort_vector) +{ + using boost::compute::ushort_; + + ushort_ data[] = { 4, 152, 94, 963, 63202, 34560, 0, 2113 }; + boost::compute::vector<ushort_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ushort_, 8, vector, (0, 4, 94, 152, 963, 2113, 34560, 63202)); +} + +BOOST_AUTO_TEST_CASE(sort_int_vector) +{ + int data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + boost::compute::vector<int> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(int, 8, vector, (-5000, -456, -4, 0, 152, 963, 1112, 75321)); +} + +BOOST_AUTO_TEST_CASE(sort_uint_vector) +{ + using boost::compute::uint_; + + uint_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<uint_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uint_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_long_vector) +{ + using boost::compute::long_; + + long_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<long_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(long_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_ulong_vector) +{ + using boost::compute::ulong_; + + ulong_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<ulong_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ulong_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_float_vector) +{ + float data[] = { -6023.0f, 152.5f, -63.0f, 1234567.0f, 11.2f, + -5000.1f, 0.0f, 14.0f, -8.25f, -0.0f }; + boost::compute::vector<float> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + float, 10, vector, + (-6023.0f, -5000.1f, -63.0f, -8.25f, -0.0f, 0.0f, 11.2f, 14.0f, 152.5f, 1234567.0f) + ); +} + +BOOST_AUTO_TEST_CASE(sort_double_vector) +{ + if(!device.supports_extension("cl_khr_fp64")){ + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + double data[] = { -6023.0, 152.5, -63.0, 1234567.0, 11.2, + -5000.1, 0.0, 14.0, -8.25, -0.0 }; + boost::compute::vector<double> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::serial_insertion_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + double, 10, vector, + (-6023.0, -5000.1, -63.0, -8.25, -0.0, 0.0, 11.2, 14.0, 152.5, 1234567.0) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_invoke.cpp b/src/boost/libs/compute/test/test_invoke.cpp new file mode 100644 index 00000000..87f3f265 --- /dev/null +++ b/src/boost/libs/compute/test/test_invoke.cpp @@ -0,0 +1,59 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://kylelutz.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestInvoke +#include <boost/test/unit_test.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/functional/integer.hpp> +#include <boost/compute/functional/math.hpp> +#include <boost/compute/utility/invoke.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(invoke_builtin) +{ + BOOST_CHECK_EQUAL(compute::invoke(compute::abs<int>(), queue, -3), 3); + BOOST_CHECK_CLOSE(compute::invoke(compute::pow<float>(), queue, 2.f, 8.f), 256.f, 1e-4); +} + +BOOST_AUTO_TEST_CASE(invoke_function) +{ + BOOST_COMPUTE_FUNCTION(int, plus_two, (int x), + { + return x + 2; + }); + + BOOST_CHECK_EQUAL(compute::invoke(plus_two, queue, 2), 4); + + BOOST_COMPUTE_FUNCTION(float, get_max, (float x, float y), + { + if(x > y) + return x; + else + return y; + }); + + BOOST_CHECK_EQUAL(compute::invoke(get_max, queue, 10.f, 20.f), 20.f); +} + +BOOST_AUTO_TEST_CASE(invoke_lambda) +{ + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + + BOOST_CHECK_EQUAL(compute::invoke(_1 / 2, queue, 4), 2); + BOOST_CHECK_EQUAL(compute::invoke(_1 * _2 + 1, queue, 3, 3), 10); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_iota.cpp b/src/boost/libs/compute/test/test_iota.cpp new file mode 100644 index 00000000..345decec --- /dev/null +++ b/src/boost/libs/compute/test/test_iota.cpp @@ -0,0 +1,90 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestIota +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/context.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/permutation_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(iota_int) +{ + bc::vector<int> vector(4, context); + bc::iota(vector.begin(), vector.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (0, 1, 2, 3)); + + bc::iota(vector.begin(), vector.end(), 10, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (10, 11, 12, 13)); + + bc::iota(vector.begin() + 2, vector.end(), -5, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (10, 11, -5, -4)); + + bc::iota(vector.begin(), vector.end() - 2, 4, queue); + CHECK_RANGE_EQUAL(int, 4, vector, (4, 5, -5, -4)); +} + +BOOST_AUTO_TEST_CASE(iota_doctest) +{ + boost::compute::vector<int> vec(3, context); + +//! [iota] +boost::compute::iota(vec.begin(), vec.end(), 0, queue); +//! [iota] + + CHECK_RANGE_EQUAL(int, 3, vec, (0, 1, 2)); +} + +BOOST_AUTO_TEST_CASE(iota_permutation_iterator) +{ + bc::vector<int> output(5, context); + bc::fill(output.begin(), output.end(), 0, queue); + + int map_data[] = { 2, 0, 1, 4, 3 }; + bc::vector<int> map(map_data, map_data + 5, queue); + + bc::iota( + bc::make_permutation_iterator(output.begin(), map.begin()), + bc::make_permutation_iterator(output.end(), map.end()), + 1, + queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (2, 3, 1, 5, 4)); +} + +BOOST_AUTO_TEST_CASE(iota_uint) +{ + bc::vector<bc::uint_> vector(4, context); + bc::iota(vector.begin(), vector.end(), bc::uint_(0), queue); + CHECK_RANGE_EQUAL(bc::uint_, 4, vector, (0, 1, 2, 3)); +} + +BOOST_AUTO_TEST_CASE(iota_char) +{ + bc::vector<bc::char_> vector(4, context); + bc::iota(vector.begin(), vector.end(), bc::uint_(0), queue); + CHECK_RANGE_EQUAL(bc::char_, 4, vector, (0, 1, 2, 3)); +} + +BOOST_AUTO_TEST_CASE(iota_uchar) +{ + bc::vector<bc::uchar_> vector(4, context); + bc::iota(vector.begin(), vector.end(), bc::uint_(0), queue); + CHECK_RANGE_EQUAL(bc::uchar_, 4, vector, (0, 1, 2, 3)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_is_permutation.cpp b/src/boost/libs/compute/test/test_is_permutation.cpp new file mode 100644 index 00000000..542a5d0b --- /dev/null +++ b/src/boost/libs/compute/test/test_is_permutation.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestIsPermutation +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/is_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(is_permutation_int) +{ + bc::int_ dataset1[] = {1, 3, 1, 2, 5}; + bc::vector<bc::int_> vector1(dataset1, dataset1 + 5, queue); + + bc::int_ dataset2[] = {3, 1, 5, 1, 2}; + bc::vector<bc::int_> vector2(dataset2, dataset2 + 5, queue); + + bool result = + bc::is_permutation(vector1.begin(), vector1.begin() + 5, + vector2.begin(), vector2.begin() + 5, queue); + + BOOST_VERIFY(result == true); + + vector2.begin().write(bc::int_(1), queue); + + result = bc::is_permutation(vector1.begin(), vector1.begin() + 5, + vector2.begin(), vector2.begin() + 5, + queue); + + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_CASE(is_permutation_string) +{ + bc::char_ dataset1[] = "abade"; + bc::vector<bc::char_> vector1(dataset1, dataset1 + 5, queue); + + bc::char_ dataset2[] = "aadeb"; + bc::vector<bc::char_> vector2(dataset2, dataset2 + 5, queue); + + bool result = + bc::is_permutation(vector1.begin(), vector1.begin() + 5, + vector2.begin(), vector2.begin() + 5, queue); + + BOOST_VERIFY(result == true); + + vector2.begin().write(bc::char_('b'), queue); + + result = bc::is_permutation(vector1.begin(), vector1.begin() + 5, + vector2.begin(), vector2.begin() + 5, + queue); + + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_is_sorted.cpp b/src/boost/libs/compute/test/test_is_sorted.cpp new file mode 100644 index 00000000..55e75ac1 --- /dev/null +++ b/src/boost/libs/compute/test/test_is_sorted.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestIsSorted +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(is_sorted_int) +{ + compute::vector<int> vec(context); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); + + vec.push_back(1, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); + + vec.push_back(2, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); + + vec.push_back(0, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue) == false); + + vec.push_back(-2, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue) == false); + + compute::sort(vec.begin(), vec.end(), queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); +} + +BOOST_AUTO_TEST_CASE(is_sorted_ones) +{ + compute::vector<int> vec(2048, context); + compute::fill(vec.begin(), vec.end(), 1, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); +} + +BOOST_AUTO_TEST_CASE(is_sorted_iota) +{ + // create vector with values from 1..1000 + compute::vector<int> vec(1000, context); + compute::iota(vec.begin(), vec.end(), 1, queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); + + // reverse the range + compute::reverse(vec.begin(), vec.end(), queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue) == false); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), compute::greater<int>(), queue)); + + // reverse it back + compute::reverse(vec.begin(), vec.end(), queue); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), queue)); + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), compute::greater<int>(), queue) == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_kernel.cpp b/src/boost/libs/compute/test/test_kernel.cpp new file mode 100644 index 00000000..2ab13b8a --- /dev/null +++ b/src/boost/libs/compute/test/test_kernel.cpp @@ -0,0 +1,335 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestKernel +#include <boost/test/unit_test.hpp> + +#include <boost/compute/buffer.hpp> +#include <boost/compute/kernel.hpp> +#include <boost/compute/types.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/utility/source.hpp> + +#include "context_setup.hpp" +#include "check_macros.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(name) +{ + compute::kernel foo = compute::kernel::create_with_source( + "__kernel void foo(int x) { }", "foo", context + ); + BOOST_CHECK_EQUAL(foo.name(), "foo"); + + compute::kernel bar = compute::kernel::create_with_source( + "__kernel void bar(float x) { }", "bar", context + ); + BOOST_CHECK_EQUAL(bar.name(), "bar"); +} + +BOOST_AUTO_TEST_CASE(arity) +{ + compute::kernel foo = compute::kernel::create_with_source( + "__kernel void foo(int x) { }", "foo", context + ); + BOOST_CHECK_EQUAL(foo.arity(), size_t(1)); + + compute::kernel bar = compute::kernel::create_with_source( + "__kernel void bar(float x, float y) { }", "bar", context + ); + BOOST_CHECK_EQUAL(bar.arity(), size_t(2)); + + compute::kernel baz = compute::kernel::create_with_source( + "__kernel void baz(char x, char y, char z) { }", "baz", context + ); + BOOST_CHECK_EQUAL(baz.arity(), size_t(3)); +} + +BOOST_AUTO_TEST_CASE(set_buffer_arg) +{ + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void foo(__global int *x, __global int *y) + { + x[get_global_id(0)] = -y[get_global_id(0)]; + } + ); + + compute::kernel foo = + compute::kernel::create_with_source(source, "foo", context); + + compute::buffer x(context, 16); + compute::buffer y(context, 16); + + foo.set_arg(0, x); + foo.set_arg(1, y.get()); +} + +BOOST_AUTO_TEST_CASE(get_work_group_info) +{ + const char source[] = + "__kernel void sum(__global const float *input,\n" + " __global float *output)\n" + "{\n" + " __local float scratch[16];\n" + " const uint gid = get_global_id(0);\n" + " const uint lid = get_local_id(0);\n" + " if(lid < 16)\n" + " scratch[lid] = input[gid];\n" + "}\n"; + + compute::program program = + compute::program::create_with_source(source, context); + + program.build(); + + compute::kernel kernel = program.create_kernel("sum"); + + using compute::ulong_; + + // get local memory size + kernel.get_work_group_info<ulong_>(device, CL_KERNEL_LOCAL_MEM_SIZE); + + // check work group size + size_t work_group_size = + kernel.get_work_group_info<size_t>(device, CL_KERNEL_WORK_GROUP_SIZE); + BOOST_CHECK(work_group_size >= 1); +} + +#ifndef BOOST_COMPUTE_NO_VARIADIC_TEMPLATES +BOOST_AUTO_TEST_CASE(kernel_set_args) +{ + compute::kernel k = compute::kernel::create_with_source( + "__kernel void test(int x, float y, char z) { }", "test", context + ); + + k.set_args(4, 2.4f, 'a'); +} +#endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES + +// Originally failed to compile on macOS (several types are resolved differently) +BOOST_AUTO_TEST_CASE(kernel_set_args_mac) +{ + compute::kernel k = compute::kernel::create_with_source( + "__kernel void test(unsigned int a, unsigned long b) { }", "test", context + ); + + compute::uint_ a; + compute::ulong_ b; + + k.set_arg(0, a); + k.set_arg(1, b); +} + + +#ifdef BOOST_COMPUTE_CL_VERSION_1_2 +BOOST_AUTO_TEST_CASE(get_arg_info) +{ + REQUIRES_OPENCL_VERSION(1, 2); + + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void sum_kernel(__global const int *input, + const uint size, + __global int *result) + { + int sum = 0; + for(uint i = 0; i < size; i++){ + sum += input[i]; + } + *result = sum; + } + ); + + compute::program program = + compute::program::create_with_source(source, context); + + program.build("-cl-kernel-arg-info"); + + compute::kernel kernel = program.create_kernel("sum_kernel"); + + BOOST_CHECK_EQUAL(kernel.get_info<CL_KERNEL_NUM_ARGS>(), compute::uint_(3)); + + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(0, CL_KERNEL_ARG_TYPE_NAME), "int*"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(0, CL_KERNEL_ARG_NAME), "input"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(1, CL_KERNEL_ARG_TYPE_NAME), "uint"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(1, CL_KERNEL_ARG_NAME), "size"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(2, CL_KERNEL_ARG_TYPE_NAME), "int*"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<std::string>(2, CL_KERNEL_ARG_NAME), "result"); + + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_TYPE_NAME>(0), "int*"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_NAME>(0), "input"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_TYPE_NAME>(1), "uint"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_NAME>(1), "size"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_TYPE_NAME>(2), "int*"); + BOOST_CHECK_EQUAL(kernel.get_arg_info<CL_KERNEL_ARG_NAME>(2), "result"); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_2 + +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 +#ifndef CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE_KHR + #define CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE_KHR CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE +#endif +#ifndef CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR + #define CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE +#endif +BOOST_AUTO_TEST_CASE(get_sub_group_info_ext) +{ + compute::kernel k = compute::kernel::create_with_source( + "__kernel void test(float x) { }", "test", context + ); + + // get_sub_group_info(const device&, cl_kernel_sub_group_info, const std::vector<size_t>) + std::vector<size_t> local_work_size(2, size_t(64)); + boost::optional<size_t> count = k.get_sub_group_info<size_t>( + device, + CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR, + local_work_size + ); + + #ifdef BOOST_COMPUTE_CL_VERSION_2_1 + if(device.check_version(2, 1)) + { + BOOST_CHECK(count); + } + else + #endif // BOOST_COMPUTE_CL_VERSION_2_1 + if(device.check_version(2, 0) && device.supports_extension("cl_khr_subgroups")) + { + // for device with cl_khr_subgroups it should return some value + BOOST_CHECK(count); + } + else + { + // for device without cl_khr_subgroups ext it should return null optional + BOOST_CHECK(count == boost::none); + } + + // get_sub_group_info(const device&, cl_kernel_sub_group_info, const size_t, const void *) + count = k.get_sub_group_info<size_t>( + device, + CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR, + 2 * sizeof(size_t), + &local_work_size[0] + ); + + #ifdef BOOST_COMPUTE_CL_VERSION_2_1 + if(device.check_version(2, 1)) + { + BOOST_CHECK(count); + } + else + #endif // BOOST_COMPUTE_CL_VERSION_2_1 + if(device.check_version(2, 0) && device.supports_extension("cl_khr_subgroups")) + { + // for device with cl_khr_subgroups it should return some value + BOOST_CHECK(count); + } + else + { + // for device without cl_khr_subgroups ext it should return null optional + BOOST_CHECK(count == boost::none); + } +} +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(get_sub_group_info_core) +{ + compute::kernel k = compute::kernel::create_with_source( + "__kernel void test(float x) { }", "test", context + ); + + // get_sub_group_info(const device&, cl_kernel_sub_group_info, const size_t) + boost::optional<std::vector<size_t>> local_size = + k.get_sub_group_info<std::vector<size_t> >( + device, + CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, + size_t(1) + ); + + if(device.check_version(2, 1)) + { + // for 2.1 devices it should return some value + BOOST_CHECK(local_size); + BOOST_CHECK(local_size.value().size() == 3); + } + else + { + // for 1.x and 2.0 devices it should return null optional, + // because CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT is not + // supported by cl_khr_subgroups (2.0 ext) + BOOST_CHECK(local_size == boost::none); + } + + // get_sub_group_info(const device&, cl_kernel_sub_group_info, const size_t) + boost::optional<size_t> local_size_simple = + k.get_sub_group_info<size_t>( + device, + CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, + size_t(1) + ); + + if(device.check_version(2, 1)) + { + // for 2.1 devices it should return some value + BOOST_CHECK(local_size_simple); + } + else + { + // for 1.x and 2.0 devices it should return null optional, + // because CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT is not + // supported by cl_khr_subgroups (2.0 ext) + BOOST_CHECK(local_size_simple == boost::none); + } + + // get_sub_group_info(const device&, cl_kernel_sub_group_info) + boost::optional<size_t> max = + k.get_sub_group_info<size_t>( + device, + CL_KERNEL_MAX_NUM_SUB_GROUPS + ); + + if(device.check_version(2, 1)) + { + // for 2.1 devices it should return some value + BOOST_CHECK(max); + } + else + { + // for 1.x and 2.0 devices it should return null optional, + // because CL_KERNEL_MAX_NUM_SUB_GROUPS is not + // supported by cl_khr_subgroups (2.0 ext) + BOOST_CHECK(max == boost::none); + } +} +#endif // BOOST_COMPUTE_CL_VERSION_2_1 + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(clone_kernel) +{ + REQUIRES_OPENCL_PLATFORM_VERSION(2, 1); + + compute::kernel k1 = compute::kernel::create_with_source( + "__kernel void test(__global int * x) { x[get_global_id(0)] = get_global_id(0); }", + "test", context + ); + + compute::buffer x(context, 5 * sizeof(compute::int_)); + k1.set_arg(0, x); + + // Clone k1 kernel + compute::kernel k2 = k1.clone(); + // After clone k2 0th argument (__global float * x) should be set, + // so we should be able to enqueue k2 kernel without problems + queue.enqueue_1d_range_kernel(k2, 0, x.size() / sizeof(compute::int_), 0).wait(); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_1 + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_lambda.cpp b/src/boost/libs/compute/test/test_lambda.cpp new file mode 100644 index 00000000..5fa72ac3 --- /dev/null +++ b/src/boost/libs/compute/test/test_lambda.cpp @@ -0,0 +1,617 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestLambda +#include <boost/test/unit_test.hpp> + +#include <boost/tuple/tuple_io.hpp> +#include <boost/tuple/tuple_comparison.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/for_each.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/bind.hpp> +#include <boost/compute/iterator/zip_iterator.hpp> +#include <boost/compute/types/pair.hpp> +#include <boost/compute/types/tuple.hpp> + +#include "check_macros.hpp" +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(squared_plus_one) +{ + bc::vector<int> vector(context); + vector.push_back(1, queue); + vector.push_back(2, queue); + vector.push_back(3, queue); + vector.push_back(4, queue); + vector.push_back(5, queue); + + // multiply each value by itself and add one + bc::transform(vector.begin(), + vector.end(), + vector.begin(), + (bc::_1 * bc::_1) + 1, + queue); + CHECK_RANGE_EQUAL(int, 5, vector, (2, 5, 10, 17, 26)); +} + +BOOST_AUTO_TEST_CASE(abs_int) +{ + bc::vector<int> vector(context); + vector.push_back(-1, queue); + vector.push_back(-2, queue); + vector.push_back(3, queue); + vector.push_back(-4, queue); + vector.push_back(5, queue); + + bc::transform(vector.begin(), + vector.end(), + vector.begin(), + abs(bc::_1), + queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 3, 4, 5)); +} + +template<class Result, class Expr> +void check_lambda_result(const Expr &) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + typename ::boost::compute::lambda::result_of<Expr>::type, + Result + >::value + )); +} + +template<class Result, class Expr, class Arg1> +void check_lambda_result(const Expr &, const Arg1 &) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + typename ::boost::compute::lambda::result_of< + Expr, + typename boost::tuple<Arg1> + >::type, + Result + >::value + )); +} + +template<class Result, class Expr, class Arg1, class Arg2> +void check_lambda_result(const Expr &, const Arg1 &, const Arg2 &) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + typename ::boost::compute::lambda::result_of< + Expr, + typename boost::tuple<Arg1, Arg2> + >::type, + Result + >::value + )); +} + +template<class Result, class Expr, class Arg1, class Arg2, class Arg3> +void check_lambda_result(const Expr &, const Arg1 &, const Arg2 &, const Arg3 &) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + typename ::boost::compute::lambda::result_of< + Expr, + typename boost::tuple<Arg1, Arg2, Arg3> + >::type, + Result + >::value + )); +} + +BOOST_AUTO_TEST_CASE(result_of) +{ + using ::boost::compute::lambda::_1; + using ::boost::compute::lambda::_2; + using ::boost::compute::lambda::_3; + + namespace proto = ::boost::proto; + + using boost::compute::int_; + + check_lambda_result<int_>(proto::lit(1)); + check_lambda_result<int_>(proto::lit(1) + 2); + check_lambda_result<float>(proto::lit(1.2f)); + check_lambda_result<float>(proto::lit(1) + 1.2f); + check_lambda_result<float>(proto::lit(1) / 2 + 1.2f); + + using boost::compute::float4_; + using boost::compute::int4_; + + check_lambda_result<int_>(_1, int_(1)); + check_lambda_result<float>(_1, float(1.2f)); + check_lambda_result<float4_>(_1, float4_(1, 2, 3, 4)); + check_lambda_result<float4_>(2.0f * _1, float4_(1, 2, 3, 4)); + check_lambda_result<float4_>(_1 * 2.0f, float4_(1, 2, 3, 4)); + + check_lambda_result<float>(dot(_1, _2), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0)); + check_lambda_result<float>(dot(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + check_lambda_result<float>(distance(_1, _2), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0)); + check_lambda_result<float>(distance(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + + check_lambda_result<float>(length(_1), float4_(3, 2, 1, 0)); + + check_lambda_result<float4_>(cross(_1, _2), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0)); + check_lambda_result<float4_>(cross(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + + check_lambda_result<float4_>(max(_1, _2), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3)); + check_lambda_result<float4_>(max(_1, float(1.0f)), float4_(0, 1, 2, 3)); + check_lambda_result<int4_>(max(_1, int4_(3, 2, 1, 0)), int4_(0, 1, 2, 3)); + check_lambda_result<int4_>(max(_1, int_(1)), int4_(0, 1, 2, 3)); + check_lambda_result<float4_>(min(_1, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3)); + + check_lambda_result<float4_>(step(_1, _2), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3)); + check_lambda_result<int4_>(step(_1, _2), float(3.0f), int4_(0, 1, 2, 3)); + + check_lambda_result<float4_>( + smoothstep(_1, _2, _3), + float4_(3, 2, 1, 0), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3) + ); + check_lambda_result<int4_>( + smoothstep(_1, _2, _3), + float(2.0f), float(3.0f), int4_(0, 1, 2, 3) + ); + + check_lambda_result<int4_>(bc::lambda::isinf(_1), float4_(0, 1, 2, 3)); + + check_lambda_result<int>(_1 + 2, int(2)); + check_lambda_result<float>(_1 + 2, float(2.2f)); + + check_lambda_result<int>(_1 + _2, int(1), int(2)); + check_lambda_result<float>(_1 + _2, int(1), float(2.2f)); + + check_lambda_result<int>(_1 + _1, int(1)); + check_lambda_result<float>(_1 * _1, float(1)); + + using boost::compute::lambda::get; + + check_lambda_result<float>(get<0>(_1), float4_(1, 2, 3, 4)); + check_lambda_result<bool>(get<0>(_1) < 1.f, float4_(1, 2, 3, 4)); + check_lambda_result<bool>(_1 < 1.f, float(2)); + + using boost::compute::lambda::make_pair; + + check_lambda_result<int>(get<0>(make_pair(_1, _2)), int(1), float(1.2f)); + check_lambda_result<float>(get<1>(make_pair(_1, _2)), int(1), float(1.2f)); + check_lambda_result<std::pair<int, float> >(make_pair(_1, _2), int(1), float(1.2f)); + + using boost::compute::lambda::make_tuple; + + check_lambda_result<boost::tuple<int> >(make_tuple(_1), int(1)); + check_lambda_result<boost::tuple<int, float> >(make_tuple(_1, _2), int(1), float(1.2f)); + check_lambda_result<boost::tuple<int, int> >(make_tuple(_1, _1), int(1)); + check_lambda_result<boost::tuple<int, float> >(make_tuple(_1, _2), int(1), float(1.4f)); + check_lambda_result<boost::tuple<char, int, float> >( + make_tuple(_1, _2, _3), char('a'), int(2), float(3.4f) + ); + check_lambda_result<boost::tuple<int, int, int> >( + make_tuple(_1, _1, _1), int(1), float(1.4f) + ); + check_lambda_result<boost::tuple<int, float, int, float, int> >( + make_tuple(_1, _2, _1, _2, _1), int(1), float(1.4f) + ); +} + +BOOST_AUTO_TEST_CASE(make_function_from_lamdba) +{ + using boost::compute::lambda::_1; + + int data[] = { 2, 4, 6, 8, 10 }; + compute::vector<int> vector(data, data + 5, queue); + + compute::function<int(int)> f = _1 * 2 + 3; + + compute::transform( + vector.begin(), vector.end(), vector.begin(), f, queue + ); + CHECK_RANGE_EQUAL(int, 5, vector, (7, 11, 15, 19, 23)); +} + +BOOST_AUTO_TEST_CASE(make_function_from_binary_lamdba) +{ + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + using boost::compute::lambda::abs; + + int data1[] = { 2, 4, 6, 8, 10 }; + int data2[] = { 10, 8, 6, 4, 2 }; + compute::vector<int> vec1(data1, data1 + 5, queue); + compute::vector<int> vec2(data2, data2 + 5, queue); + compute::vector<int> result(5, context); + + compute::function<int(int, int)> f = abs(_1 - _2); + + compute::transform( + vec1.begin(), vec1.end(), vec2.begin(), result.begin(), f, queue + ); + CHECK_RANGE_EQUAL(int, 5, result, (8, 4, 0, 4, 8)); +} + +BOOST_AUTO_TEST_CASE(lambda_binary_function_with_pointer_modf) +{ + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + using boost::compute::lambda::abs; + + bc::float_ data1[] = { 2.2f, 4.2f, 6.3f, 8.3f, 10.2f }; + compute::vector<bc::float_> vec1(data1, data1 + 5, queue); + compute::vector<bc::float_> vec2(size_t(5), context); + compute::vector<bc::float_> result(5, context); + + compute::transform( + bc::make_transform_iterator(vec1.begin(), _1 + 0.01f), + bc::make_transform_iterator(vec1.end(), _1 + 0.01f), + vec2.begin(), + result.begin(), + bc::lambda::modf(_1, _2), + queue + ); + CHECK_RANGE_CLOSE(bc::float_, 5, result, (0.21f, 0.21f, 0.31f, 0.31f, 0.21f), 0.01f); + CHECK_RANGE_CLOSE(bc::float_, 5, vec2, (2, 4, 6, 8, 10), 0.01f); +} + +BOOST_AUTO_TEST_CASE(lambda_tenary_function_with_pointer_remquo) +{ + if(!has_remquo_func(device)) + { + return; + } + + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + using boost::compute::lambda::get; + + bc::float_ data1[] = { 2.2f, 4.2f, 6.3f, 8.3f, 10.2f }; + bc::float_ data2[] = { 4.4f, 4.2f, 6.3f, 16.6f, 10.2f }; + compute::vector<bc::float_> vec1(data1, data1 + 5, queue); + compute::vector<bc::float_> vec2(data2, data2 + 5, queue); + compute::vector<bc::int_> vec3(size_t(5), context); + compute::vector<bc::float_> result(5, context); + + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(vec1.begin(), vec2.begin(), vec3.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(vec1.end(), vec2.end(), vec3.end()) + ), + result.begin(), + bc::lambda::remquo(get<0>(_1), get<1>(_1), get<2>(_1)), + queue + ); + CHECK_RANGE_CLOSE(bc::float_, 5, result, (2.2f, 0.0f, 0.0f, 8.3f, 0.0f), 0.01f); + CHECK_RANGE_EQUAL(bc::int_, 5, vec3, (0, 1, 1, 0, 1)); +} + +BOOST_AUTO_TEST_CASE(lambda_get_vector) +{ + using boost::compute::_1; + using boost::compute::int2_; + using boost::compute::lambda::get; + + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int2_> vector(4, context); + + compute::copy( + reinterpret_cast<int2_ *>(data), + reinterpret_cast<int2_ *>(data) + 4, + vector.begin(), + queue + ); + + // extract first component of each vector + compute::vector<int> first_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + first_component.begin(), + get<0>(_1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_component, (1, 3, 5, 7)); + + // extract second component of each vector + compute::vector<int> second_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + first_component.begin(), + get<1>(_1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_component, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(lambda_get_pair) +{ + using boost::compute::_1; + using boost::compute::lambda::get; + + compute::vector<std::pair<int, float> > vector(context); + vector.push_back(std::make_pair(1, 1.2f), queue); + vector.push_back(std::make_pair(3, 3.4f), queue); + vector.push_back(std::make_pair(5, 5.6f), queue); + vector.push_back(std::make_pair(7, 7.8f), queue); + + // extract first compoenent of each pair + compute::vector<int> first_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + first_component.begin(), + get<0>(_1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_component, (1, 3, 5, 7)); + + // extract second compoenent of each pair + compute::vector<float> second_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + second_component.begin(), + get<1>(_1), + queue + ); + CHECK_RANGE_EQUAL(float, 4, second_component, (1.2f, 3.4f, 5.6f, 7.8f)); +} + +BOOST_AUTO_TEST_CASE(lambda_get_tuple) +{ + using boost::compute::_1; + using boost::compute::lambda::get; + + compute::vector<boost::tuple<int, char, float> > vector(context); + + vector.push_back(boost::make_tuple(1, 'a', 1.2f), queue); + vector.push_back(boost::make_tuple(3, 'b', 3.4f), queue); + vector.push_back(boost::make_tuple(5, 'c', 5.6f), queue); + vector.push_back(boost::make_tuple(7, 'd', 7.8f), queue); + + // extract first component of each tuple + compute::vector<int> first_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + first_component.begin(), + get<0>(_1), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_component, (1, 3, 5, 7)); + + // extract second component of each tuple + compute::vector<char> second_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + second_component.begin(), + get<1>(_1), + queue + ); + CHECK_RANGE_EQUAL(char, 4, second_component, ('a', 'b', 'c', 'd')); + + // extract third component of each tuple + compute::vector<float> third_component(4, context); + compute::transform( + vector.begin(), + vector.end(), + third_component.begin(), + get<2>(_1), + queue + ); + CHECK_RANGE_EQUAL(float, 4, third_component, (1.2f, 3.4f, 5.6f, 7.8f)); +} + +BOOST_AUTO_TEST_CASE(lambda_get_zip_iterator) +{ + using boost::compute::_1; + using boost::compute::lambda::get; + + float data[] = { 1.2f, 2.3f, 3.4f, 4.5f, 5.6f, 6.7f, 7.8f, 9.0f }; + compute::vector<float> input(8, context); + compute::copy(data, data + 8, input.begin(), queue); + + compute::vector<float> output(8, context); + + compute::for_each( + compute::make_zip_iterator( + boost::make_tuple(input.begin(), output.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input.end(), output.end()) + ), + get<1>(_1) = get<0>(_1), + queue + ); + CHECK_RANGE_EQUAL(float, 8, output, + (1.2f, 2.3f, 3.4f, 4.5f, 5.6f, 6.7f, 7.8f, 9.0f) + ); +} + +BOOST_AUTO_TEST_CASE(lambda_make_pair) +{ + using boost::compute::_1; + using boost::compute::_2; + using boost::compute::lambda::make_pair; + + int int_data[] = { 1, 3, 5, 7 }; + float float_data[] = { 1.2f, 2.3f, 3.4f, 4.5f }; + + compute::vector<int> int_vector(int_data, int_data + 4, queue); + compute::vector<float> float_vector(float_data, float_data + 4, queue); + compute::vector<std::pair<int, float> > output_vector(4, context); + + compute::transform( + int_vector.begin(), + int_vector.end(), + float_vector.begin(), + output_vector.begin(), + make_pair(_1 - 1, 0 - _2), + queue + ); + + std::vector<std::pair<int, float> > host_vector(4); + compute::copy_n(output_vector.begin(), 4, host_vector.begin(), queue); + BOOST_CHECK(host_vector[0] == std::make_pair(0, -1.2f)); + BOOST_CHECK(host_vector[1] == std::make_pair(2, -2.3f)); + BOOST_CHECK(host_vector[2] == std::make_pair(4, -3.4f)); + BOOST_CHECK(host_vector[3] == std::make_pair(6, -4.5f)); +} + +BOOST_AUTO_TEST_CASE(lambda_make_tuple) +{ + using boost::compute::_1; + using boost::compute::lambda::get; + using boost::compute::lambda::make_tuple; + + std::vector<boost::tuple<int, float> > data; + data.push_back(boost::make_tuple(2, 1.2f)); + data.push_back(boost::make_tuple(4, 2.4f)); + data.push_back(boost::make_tuple(6, 4.6f)); + data.push_back(boost::make_tuple(8, 6.8f)); + + compute::vector<boost::tuple<int, float> > input_vector(4, context); + compute::copy(data.begin(), data.end(), input_vector.begin(), queue); + + // reverse the elements in the tuple + compute::vector<boost::tuple<float, int> > output_vector(4, context); + + compute::transform( + input_vector.begin(), + input_vector.end(), + output_vector.begin(), + make_tuple(get<1>(_1), get<0>(_1)), + queue + ); + + std::vector<boost::tuple<float, int> > host_vector(4); + compute::copy_n(output_vector.begin(), 4, host_vector.begin(), queue); + BOOST_CHECK_EQUAL(host_vector[0], boost::make_tuple(1.2f, 2)); + BOOST_CHECK_EQUAL(host_vector[1], boost::make_tuple(2.4f, 4)); + BOOST_CHECK_EQUAL(host_vector[2], boost::make_tuple(4.6f, 6)); + BOOST_CHECK_EQUAL(host_vector[3], boost::make_tuple(6.8f, 8)); + + // duplicate each element in the tuple + compute::vector<boost::tuple<int, int, float, float> > doubled_vector(4, context); + compute::transform( + input_vector.begin(), + input_vector.end(), + doubled_vector.begin(), + make_tuple(get<0>(_1), get<0>(_1), get<1>(_1), get<1>(_1)), + queue + ); + + std::vector<boost::tuple<int, int, float, float> > doubled_host_vector(4); + compute::copy_n(doubled_vector.begin(), 4, doubled_host_vector.begin(), queue); + BOOST_CHECK_EQUAL(doubled_host_vector[0], boost::make_tuple(2, 2, 1.2f, 1.2f)); + BOOST_CHECK_EQUAL(doubled_host_vector[1], boost::make_tuple(4, 4, 2.4f, 2.4f)); + BOOST_CHECK_EQUAL(doubled_host_vector[2], boost::make_tuple(6, 6, 4.6f, 4.6f)); + BOOST_CHECK_EQUAL(doubled_host_vector[3], boost::make_tuple(8, 8, 6.8f, 6.8f)); +} + +BOOST_AUTO_TEST_CASE(bind_lambda_function) +{ + using compute::placeholders::_1; + namespace lambda = compute::lambda; + + int data[] = { 1, 2, 3, 4 }; + compute::vector<int> vector(data, data + 4, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), + compute::bind(lambda::_1 * lambda::_2, _1, 2), + queue + ); + CHECK_RANGE_EQUAL(int, 4, vector, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(lambda_function_with_uint_args) +{ + compute::uint_ host_data[] = { 1, 3, 5, 7, 9 }; + compute::vector<compute::uint_> device_vector(host_data, host_data + 5, queue); + + using boost::compute::lambda::clamp; + using compute::lambda::_1; + + compute::transform( + device_vector.begin(), device_vector.end(), + device_vector.begin(), + clamp(_1, compute::uint_(4), compute::uint_(6)), + queue + ); + CHECK_RANGE_EQUAL(compute::uint_, 5, device_vector, (4, 4, 5, 6, 6)); +} + +BOOST_AUTO_TEST_CASE(lambda_function_with_short_args) +{ + compute::short_ host_data[] = { 1, 3, 5, 7, 9 }; + compute::vector<compute::short_> device_vector(host_data, host_data + 5, queue); + + using boost::compute::lambda::clamp; + using compute::lambda::_1; + + compute::transform( + device_vector.begin(), device_vector.end(), + device_vector.begin(), + clamp(_1, compute::short_(4), compute::short_(6)), + queue + ); + CHECK_RANGE_EQUAL(compute::short_, 5, device_vector, (4, 4, 5, 6, 6)); +} + +BOOST_AUTO_TEST_CASE(lambda_function_with_uchar_args) +{ + compute::uchar_ host_data[] = { 1, 3, 5, 7, 9 }; + compute::vector<compute::uchar_> device_vector(host_data, host_data + 5, queue); + + using boost::compute::lambda::clamp; + using compute::lambda::_1; + + compute::transform( + device_vector.begin(), device_vector.end(), + device_vector.begin(), + clamp(_1, compute::uchar_(4), compute::uchar_(6)), + queue + ); + CHECK_RANGE_EQUAL(compute::uchar_, 5, device_vector, (4, 4, 5, 6, 6)); +} + +BOOST_AUTO_TEST_CASE(lambda_function_with_char_args) +{ + compute::char_ host_data[] = { 1, 3, 5, 7, 9 }; + compute::vector<compute::char_> device_vector(host_data, host_data + 5, queue); + + using boost::compute::lambda::clamp; + using compute::lambda::_1; + + compute::transform( + device_vector.begin(), device_vector.end(), + device_vector.begin(), + clamp(_1, compute::char_(4), compute::char_(6)), + queue + ); + CHECK_RANGE_EQUAL(compute::char_, 5, device_vector, (4, 4, 5, 6, 6)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_lexicographical_compare.cpp b/src/boost/libs/compute/test/test_lexicographical_compare.cpp new file mode 100644 index 00000000..45daa92a --- /dev/null +++ b/src/boost/libs/compute/test/test_lexicographical_compare.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Mageswaran.D <mageswaran1989@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestLexicographicalCompare +#include <boost/test/unit_test.hpp> + +#include <boost/compute/container/string.hpp> +#include <boost/compute/container/basic_string.hpp> +#include <boost/compute/algorithm/lexicographical_compare.hpp> + +#include "context_setup.hpp" +#include "check_macros.hpp" + +BOOST_AUTO_TEST_CASE(lexicographical_compare_string) +{ + boost::compute::string a = "abcdefghijk"; + boost::compute::string b = "abcdefghijk"; + boost::compute::string c = "abcdefghija"; + boost::compute::string d = "zabcdefghij"; + + BOOST_CHECK(boost::compute::lexicographical_compare(a.begin(), + a.end(), + b.begin(), + b.end()) == false); + + BOOST_CHECK(boost::compute::lexicographical_compare(c.begin(), + c.end(), + a.begin(), + a.end()) == true); + + BOOST_CHECK(boost::compute::lexicographical_compare(c.begin(), + c.end(), + d.begin(), + d.end()) == true); +} + +BOOST_AUTO_TEST_CASE(lexicographical_compare_number) +{ + int data1[] = { 1, 2, 3, 4, 5, 6 }; + int data2[] = { 9, 2, 3, 4, 5, 6 }; + int data3[] = { 1, 2, 3, 4, 5 }; + int data4[] = { 9, 2, 3, 4, 5, 100 }; + + boost::compute::vector<int> vector1(data1, data1 + 6, queue); + boost::compute::vector<int> vector2(data2, data2 + 6, queue); + boost::compute::vector<int> vector3(data3, data3 + 5, queue); + boost::compute::vector<int> vector4(data4, data4 + 6, queue); + + BOOST_CHECK(boost::compute::lexicographical_compare(vector1.begin(), + vector1.end(), + vector2.begin(), + vector2.end(), + queue) == true); + + BOOST_CHECK(boost::compute::lexicographical_compare(vector1.begin(), + vector1.end(), + vector3.begin(), + vector3.end(), + queue) == false); + + BOOST_CHECK(boost::compute::lexicographical_compare(vector3.begin(), + vector3.end(), + vector4.begin(), + vector4.end(), + queue) == true); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_linear_congruential_engine.cpp b/src/boost/libs/compute/test/test_linear_congruential_engine.cpp new file mode 100644 index 00000000..25438c7f --- /dev/null +++ b/src/boost/libs/compute/test/test_linear_congruential_engine.cpp @@ -0,0 +1,120 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestLinearCongruentialEngine +#include <boost/test/unit_test.hpp> + +#include <boost/compute/random/linear_congruential_engine.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(generate_uint) +{ + using boost::compute::uint_; + + boost::compute::linear_congruential_engine<uint_> rng(queue); + + boost::compute::vector<uint_> vector(10, context); + + rng.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(1099087573), + uint_(2291457337), + uint_(4026424941), + uint_(420705969), + uint_(2250972997), + uint_(153107049), + uint_(3581708125), + uint_(1733142113), + uint_(3008982197), + uint_(3237988505)) + ); +} + +BOOST_AUTO_TEST_CASE(discard_uint) +{ + using boost::compute::uint_; + + boost::compute::linear_congruential_engine<uint_> rng(queue); + + boost::compute::vector<uint_> vector(5, context); + + rng.discard(5, queue); + rng.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 5, vector, + (uint_(153107049), + uint_(3581708125), + uint_(1733142113), + uint_(3008982197), + uint_(3237988505)) + ); +} + +BOOST_AUTO_TEST_CASE(copy_ctor) +{ + using boost::compute::uint_; + + boost::compute::linear_congruential_engine<uint_> rng(queue); + boost::compute::linear_congruential_engine<uint_> rng_copy(rng); + + boost::compute::vector<uint_> vector(10, context); + + rng_copy.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(1099087573), + uint_(2291457337), + uint_(4026424941), + uint_(420705969), + uint_(2250972997), + uint_(153107049), + uint_(3581708125), + uint_(1733142113), + uint_(3008982197), + uint_(3237988505)) + ); +} + +BOOST_AUTO_TEST_CASE(assign_op) +{ + using boost::compute::uint_; + + boost::compute::linear_congruential_engine<uint_> rng(queue); + boost::compute::linear_congruential_engine<uint_> rng_copy(queue); + + boost::compute::vector<uint_> vector(10, context); + + rng_copy.discard(5, queue); + rng_copy = rng; + rng_copy.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(1099087573), + uint_(2291457337), + uint_(4026424941), + uint_(420705969), + uint_(2250972997), + uint_(153107049), + uint_(3581708125), + uint_(1733142113), + uint_(3008982197), + uint_(3237988505)) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_literal_conversion.cpp b/src/boost/libs/compute/test/test_literal_conversion.cpp new file mode 100644 index 00000000..09898d44 --- /dev/null +++ b/src/boost/libs/compute/test/test_literal_conversion.cpp @@ -0,0 +1,72 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2016 Jason Rhinelander <jason@imaginary.ca> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestLiteralConversion +#include <boost/test/unit_test.hpp> + +#include <string> +#include <sstream> +#include <vector> + +#include <boost/compute/detail/literal.hpp> + +BOOST_AUTO_TEST_CASE(literal_conversion_float) +{ + std::vector<float> values, roundtrip; + values.push_back(1.2345679f); + values.push_back(1.2345680f); + values.push_back(1.2345681f); + for (size_t i = 0; i < values.size(); i++) { + std::string literal = boost::compute::detail::make_literal(values[i]); + // Check that we got something in the literal, and that at least the first + // 6 characters (5 digits) look good + BOOST_CHECK_EQUAL(literal.substr(0, 6), "1.2345"); + + // libc++ stream extraction fails on a value such as "1.2f" rather than extracting 1.2 + // and leaving the f; so check the "f", then slice it off for the extraction below: + BOOST_CHECK_EQUAL(literal.substr(literal.length()-1), "f"); + + std::istringstream iss(literal.substr(0, literal.length()-1)); + float x; + iss >> x; + roundtrip.push_back(x); + } + BOOST_CHECK_EQUAL(values[0], roundtrip[0]); + BOOST_CHECK_EQUAL(values[1], roundtrip[1]); + BOOST_CHECK_EQUAL(values[2], roundtrip[2]); +} + +BOOST_AUTO_TEST_CASE(literal_conversion_double) +{ + std::vector<double> values, roundtrip; + values.push_back(1.2345678901234567); + values.push_back(1.2345678901234569); + values.push_back(1.2345678901234571); + for (size_t i = 0; i < values.size(); i++) { + std::string literal = boost::compute::detail::make_literal(values[i]); + // Check that we got something in the literal, and that at least the first + // 11 characters (10 digits) look good + BOOST_CHECK_EQUAL(literal.substr(0, 11), "1.234567890"); + + // Stuff the literal into a stream then extract it, and make sure we get a numerically + // identical result. (Since there is no suffix, we don't have to worry about removing the + // suffix like we have to above, for float--but we also check to make sure there is no + // (unextracted) suffix). + std::istringstream iss(literal); + double x; + std::string suffix; + iss >> x >> suffix; + BOOST_CHECK_EQUAL(suffix, ""); + roundtrip.push_back(x); + } + BOOST_CHECK_EQUAL(values[0], roundtrip[0]); + BOOST_CHECK_EQUAL(values[1], roundtrip[1]); + BOOST_CHECK_EQUAL(values[2], roundtrip[2]); +} diff --git a/src/boost/libs/compute/test/test_local_buffer.cpp b/src/boost/libs/compute/test/test_local_buffer.cpp new file mode 100644 index 00000000..69e5389a --- /dev/null +++ b/src/boost/libs/compute/test/test_local_buffer.cpp @@ -0,0 +1,80 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestLocalBuffer +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/core.hpp> +#include <boost/compute/memory/local_buffer.hpp> +#include <boost/compute/utility/source.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(local_buffer_arg) +{ + if(device.get_info<CL_DEVICE_LOCAL_MEM_TYPE>() != CL_LOCAL){ + std::cerr << "skipping local buffer arg test: " + << "device does not support local memory" << std::endl; + return; + } + + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void foo(__local float *local_buffer, + __global float *global_buffer) + { + const uint gid = get_global_id(0); + const uint lid = get_local_id(0); + + local_buffer[lid] = gid; + + global_buffer[gid] = local_buffer[lid]; + } + ); + + // create and build program + compute::program program = + compute::program::build_with_source(source, context); + + // create kernel + compute::kernel kernel = program.create_kernel("foo"); + + // setup kernel arguments + compute::buffer global_buf(context, 128 * sizeof(float)); + kernel.set_arg(0, compute::local_buffer<float>(32)); + kernel.set_arg(1, global_buf); + + // some implementations don't correctly report dynamically-set local buffer sizes + if(kernel.get_work_group_info<cl_ulong>(device, CL_KERNEL_LOCAL_MEM_SIZE) == 0){ + std::cerr << "skipping checks for local memory size, device reports " + << "zero after setting dynamically-sized local buffer size" + << std::endl; + return; + } + + // check actual memory size + BOOST_CHECK_GE( + kernel.get_work_group_info<cl_ulong>(device, CL_KERNEL_LOCAL_MEM_SIZE), + 32 * sizeof(float) + ); + + // increase local buffer size and check new actual local memory size + kernel.set_arg(0, compute::local_buffer<float>(64)); + + BOOST_CHECK_GE( + kernel.get_work_group_info<cl_ulong>(device, CL_KERNEL_LOCAL_MEM_SIZE), + 64 * sizeof(float) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_malloc.cpp b/src/boost/libs/compute/test/test_malloc.cpp new file mode 100644 index 00000000..212200d9 --- /dev/null +++ b/src/boost/libs/compute/test/test_malloc.cpp @@ -0,0 +1,40 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMalloc +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/experimental/malloc.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(malloc_int) +{ + bc::experimental::device_ptr<int> ptr = bc::experimental::malloc<int>(5, context); + + int input_data[] = { 2, 5, 8, 3, 6 }; + bc::copy(input_data, input_data + 5, ptr, queue); + + int output_data[5]; + bc::copy(ptr, ptr + 5, output_data, queue); + + BOOST_CHECK_EQUAL(output_data[0], 2); + BOOST_CHECK_EQUAL(output_data[1], 5); + BOOST_CHECK_EQUAL(output_data[2], 8); + BOOST_CHECK_EQUAL(output_data[3], 3); + BOOST_CHECK_EQUAL(output_data[4], 6); + + bc::experimental::free(ptr); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_mapped_view.cpp b/src/boost/libs/compute/test/test_mapped_view.cpp new file mode 100644 index 00000000..c862a75e --- /dev/null +++ b/src/boost/libs/compute/test/test_mapped_view.cpp @@ -0,0 +1,70 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMappedView +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/algorithm/reduce.hpp> +#include <boost/compute/container/mapped_view.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(fill) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + for(int i = 0; i < 8; i++){ + BOOST_CHECK_EQUAL(data[i], i+1); + } + + compute::mapped_view<int> view(data, 8, context); + compute::fill(view.begin(), view.end(), 4, queue); + + view.map(CL_MAP_READ, queue); + for(int i = 0; i < 8; i++){ + BOOST_CHECK_EQUAL(data[i], 4); + } + view.unmap(queue); +} + +BOOST_AUTO_TEST_CASE(sort) +{ + int data[] = { 5, 2, 3, 1, 8, 7, 4, 9 }; + compute::mapped_view<int> view(data, 8, context); + + compute::sort(view.begin(), view.end(), queue); + + view.map(CL_MAP_READ, queue); + BOOST_CHECK_EQUAL(data[0], 1); + BOOST_CHECK_EQUAL(data[7], 9); + view.unmap(queue); +} + +BOOST_AUTO_TEST_CASE(mapped_view_reduce_doctest) +{ +//! [reduce] +// create data array on the host +int data[] = { 5, 2, 3, 1, 8, 7, 4, 9 }; +boost::compute::mapped_view<int> view(data, 8, context); + +// use reduce() to calculate the sum on the device +int sum = 0; +boost::compute::reduce(view.begin(), view.end(), &sum, queue); +//! [reduce] + + BOOST_CHECK_EQUAL(sum, 39); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_merge.cpp b/src/boost/libs/compute/test/test_merge.cpp new file mode 100644 index 00000000..df3b12dc --- /dev/null +++ b/src/boost/libs/compute/test/test_merge.cpp @@ -0,0 +1,167 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMerge +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/types/pair.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/merge.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/lambda.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(simple_merge_int) +{ + int data1[] = { 1, 3, 5, 7 }; + int data2[] = { 2, 4, 6, 8 }; + + boost::compute::vector<int> v1(4, context); + boost::compute::vector<int> v2(4, context); + boost::compute::vector<int> v3(8, context); + + boost::compute::copy_n(data1, 4, v1.begin(), queue); + boost::compute::copy_n(data2, 4, v2.begin(), queue); + boost::compute::fill(v3.begin(), v3.end(), 0, queue); + + // merge v1 with v2 into v3 + boost::compute::merge( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, v3, (1, 2, 3, 4, 5, 6, 7, 8)); + + // merge v2 with v1 into v3 + boost::compute::merge( + v2.begin(), v2.end(), + v1.begin(), v1.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, v3, (1, 2, 3, 4, 5, 6, 7, 8)); + + // merge v1 with v1 into v3 + boost::compute::merge( + v1.begin(), v1.end(), + v1.begin(), v1.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, v3, (1, 1, 3, 3, 5, 5, 7, 7)); + + // merge v2 with v2 into v3 + boost::compute::merge( + v2.begin(), v2.end(), + v2.begin(), v2.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 8, v3, (2, 2, 4, 4, 6, 6, 8, 8)); + + // merge v1 with empty range into v3 + boost::compute::merge( + v1.begin(), v1.end(), + v1.begin(), v1.begin(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 4, v3, (1, 3, 5, 7)); + + // merge v2 with empty range into v3 + boost::compute::merge( + v1.begin(), v1.begin(), + v2.begin(), v2.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 4, v3, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(merge_pairs) +{ + std::vector<std::pair<int, float> > data1; + std::vector<std::pair<int, float> > data2; + + data1.push_back(std::make_pair(0, 0.1f)); + data1.push_back(std::make_pair(2, 2.1f)); + data1.push_back(std::make_pair(4, 4.1f)); + data1.push_back(std::make_pair(6, 6.1f)); + data2.push_back(std::make_pair(1, 1.1f)); + data2.push_back(std::make_pair(3, 3.1f)); + data2.push_back(std::make_pair(5, 5.1f)); + data2.push_back(std::make_pair(7, 7.1f)); + + std::vector<std::pair<int, float> > data3(data1.size() + data2.size()); + std::fill(data3.begin(), data3.end(), std::make_pair(-1, -1.f)); + + boost::compute::vector<std::pair<int, float> > v1(data1.size(), context); + boost::compute::vector<std::pair<int, float> > v2(data2.size(), context); + boost::compute::vector<std::pair<int, float> > v3(data3.size(), context); + + boost::compute::copy(data1.begin(), data1.end(), v1.begin(), queue); + boost::compute::copy(data2.begin(), data2.end(), v2.begin(), queue); + + using ::boost::compute::lambda::_1; + using ::boost::compute::lambda::_2; + using ::boost::compute::lambda::get; + + boost::compute::merge( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin(), + get<0>(_1) < get<0>(_2), + queue + ); + + boost::compute::copy(v3.begin(), v3.end(), data3.begin(), queue); + + BOOST_CHECK(v3[0] == std::make_pair(0, 0.1f)); + BOOST_CHECK(v3[1] == std::make_pair(1, 1.1f)); + BOOST_CHECK(v3[2] == std::make_pair(2, 2.1f)); + BOOST_CHECK(v3[3] == std::make_pair(3, 3.1f)); + BOOST_CHECK(v3[4] == std::make_pair(4, 4.1f)); + BOOST_CHECK(v3[5] == std::make_pair(5, 5.1f)); + BOOST_CHECK(v3[6] == std::make_pair(6, 6.1f)); + BOOST_CHECK(v3[7] == std::make_pair(7, 7.1f)); +} + +BOOST_AUTO_TEST_CASE(merge_floats) +{ + float data1[] = { 1.1f, 2.2f, 3.3f, 4.4f, + 5.5f, 6.6f, 7.7f, 8.8f }; + float data2[] = { 1.0f, 2.0f, 3.9f, 4.9f, + 6.8f, 6.9f, 7.0f, 7.1f }; + + boost::compute::vector<float> v1(8, context); + boost::compute::vector<float> v2(8, context); + boost::compute::vector<float> v3(v1.size() + v2.size(), context); + + boost::compute::copy_n(data1, 8, v1.begin(), queue); + boost::compute::copy_n(data2, 8, v2.begin(), queue); + boost::compute::fill(v3.begin(), v3.end(), 0.f, queue); + + boost::compute::merge( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin(), + queue + ); + CHECK_RANGE_EQUAL(float, 16, v3, + (1.0f, 1.1f, 2.0f, 2.2f, 3.3f, 3.9f, 4.4f, 4.9f, + 5.5f, 6.6f, 6.8f, 6.9f, 7.0f, 7.1f, 7.7f, 8.8f) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_merge_sort_gpu.cpp b/src/boost/libs/compute/test/test_merge_sort_gpu.cpp new file mode 100644 index 00000000..5b857aca --- /dev/null +++ b/src/boost/libs/compute/test/test_merge_sort_gpu.cpp @@ -0,0 +1,374 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2016 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMergeSortOnGPU +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/detail/merge_sort_on_gpu.hpp> +#include <boost/compute/container/vector.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(sort_small_vector_char) +{ + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all merge_sort_on_gpu tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + using boost::compute::char_; + ::boost::compute::greater<char_> greater; + ::boost::compute::less<char_> less; + + char_ data[] = { 'c', 'a', '0', '7', 'B', 'F', '\0', '$' }; + boost::compute::vector<char_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + // < + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), less, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), less, queue) + ); + CHECK_RANGE_EQUAL(char_, 8, vector, ('\0', '$', '0', '7', 'B', 'F', 'a', 'c')); + + // > + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), greater, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), greater, queue) + ); + CHECK_RANGE_EQUAL(char_, 8, vector, ('c', 'a', 'F', 'B', '7', '0', '$', '\0')); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_int) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::int_; + ::boost::compute::greater<int_> greater; + ::boost::compute::less<int_> less; + + const int_ size = 748; + std::vector<int_> data(size); + for(int_ i = 0; i < size; i++){ + data[i] = i%2 ? i : -i; + } + + boost::compute::vector<int_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK(!boost::compute::is_sorted(vector.begin(), vector.end(), queue)); + + // < + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), less, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), less, queue) + ); + + // > + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), greater, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), greater, queue) + ); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_ulong) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::ulong_; + ::boost::compute::greater<ulong_> greater; + ::boost::compute::less<ulong_> less; + + const ulong_ size = 260; + std::vector<ulong_> data(size); + for(ulong_ i = 0; i < size; i++){ + data[i] = i%2 ? i : i * i; + } + + boost::compute::vector<ulong_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK(!boost::compute::is_sorted(vector.begin(), vector.end(), queue)); + + // < + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), less, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), less, queue) + ); + + // > + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), greater, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), greater, queue) + ); +} + + +BOOST_AUTO_TEST_CASE(sort_mid_vector_float) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::float_; + ::boost::compute::greater<float_> greater; + ::boost::compute::less<float_> less; + + const int size = 513; + std::vector<float_> data(size); + for(int i = 0; i < size; i++){ + data[i] = float_(i%2 ? i : -i); + } + + boost::compute::vector<float_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK(!boost::compute::is_sorted(vector.begin(), vector.end(), queue)); + + // < + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), less, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), less, queue) + ); + + // > + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), greater, queue + ); + queue.finish(); + + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), greater, queue) + ); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_double) +{ + if(is_apple_cpu_device(device)) { + return; + } + + if(!device.supports_extension("cl_khr_fp64")){ + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + using boost::compute::double_; + ::boost::compute::greater<double_> greater; + ::boost::compute::less<double_> less; + + const int size = 1023; + std::vector<double_> data(size); + for(int i = 0; i < size; i++){ + data[i] = double_(i%2 ? i : -i); + } + + boost::compute::vector<double_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK(!boost::compute::is_sorted(vector.begin(), vector.end(), queue)); + + // < + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), less, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), less, queue) + ); + + // > + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), greater, queue + ); + queue.finish(); + + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), greater, queue) + ); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_int_custom_comparison_func) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::int_; + ::boost::compute::greater<int_> greater; + ::boost::compute::less<int_> less; + + const int_ size = 1024; + std::vector<int_> data(size); + for(int_ i = 0; i < size; i++){ + data[i] = i%2 ? size - i : i - size; + } + + BOOST_COMPUTE_FUNCTION(bool, abs_sort, (int_ a, int_ b), + { + return abs(a) < abs(b); + }); + + boost::compute::vector<int_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK( + !boost::compute::is_sorted(vector.begin(), vector.end(), abs_sort, queue) + ); + + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), abs_sort, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), abs_sort, queue) + ); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_int2) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::int2_; + using boost::compute::int_; + ::boost::compute::greater<int2_> greater; + ::boost::compute::less<int2_> less; + + const int_ size = 1024; + std::vector<int2_> data(size); + for(int_ i = 0; i < size; i++){ + data[i] = i%2 ? int2_(i, i) : int2_(i - size, i - size); + } + + BOOST_COMPUTE_FUNCTION(bool, abs_sort, (int2_ a, int2_ b), + { + return abs(a.x + a.y) < abs(b.x + b.y); + }); + + boost::compute::vector<int2_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK( + !boost::compute::is_sorted(vector.begin(), vector.end(), abs_sort, queue) + ); + + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), abs_sort, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), abs_sort, queue) + ); +} + +BOOST_AUTO_TEST_CASE(sort_mid_vector_long8) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::long8_; + using boost::compute::long_; + ::boost::compute::greater<long8_> greater; + ::boost::compute::less<long8_> less; + + const long_ size = 256; + std::vector<long8_> data(size); + for(long_ i = 0; i < size; i++){ + data[i] = i%2 ? long8_(i) : long8_(i * i); + } + + BOOST_COMPUTE_FUNCTION(bool, comp, (long8_ a, long8_ b), + { + return a.s0 < b.s3; + }); + + boost::compute::vector<long8_> vector(data.begin(), data.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK( + !boost::compute::is_sorted(vector.begin(), vector.end(), comp, queue) + ); + + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), comp, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), comp, queue) + ); +} + +BOOST_AUTO_TEST_CASE(stable_sort_vector_int2) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::int2_; + + int2_ data[] = { + int2_(8, 3), int2_(5, 1), + int2_(2, 1), int2_(6, 1), + int2_(8, 1), int2_(7, 1), + int2_(4, 1), int2_(8, 2) + }; + + BOOST_COMPUTE_FUNCTION(bool, comp, (int2_ a, int2_ b), + { + return a.x < b.x; + }); + + boost::compute::vector<int2_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), 8); + BOOST_CHECK( + !boost::compute::is_sorted(vector.begin(), vector.end(), comp, queue) + ); + + // + boost::compute::detail::merge_sort_on_gpu( + vector.begin(), vector.end(), comp, true /*stable*/, queue + ); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), comp, queue) + ); + CHECK_RANGE_EQUAL( + int2_, 8, vector, + ( + int2_(2, 1), int2_(4, 1), + int2_(5, 1), int2_(6, 1), + int2_(7, 1), int2_(8, 3), + int2_(8, 1), int2_(8, 2) + ) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_mersenne_twister_engine.cpp b/src/boost/libs/compute/test/test_mersenne_twister_engine.cpp new file mode 100644 index 00000000..c286c257 --- /dev/null +++ b/src/boost/libs/compute/test/test_mersenne_twister_engine.cpp @@ -0,0 +1,120 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMersenneTwisterEngine +#include <boost/test/unit_test.hpp> + +#include <boost/compute/random/mersenne_twister_engine.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(generate_uint) +{ + using boost::compute::uint_; + + boost::compute::mt19937 rng(queue); + + boost::compute::vector<uint_> vector(10, context); + + rng.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(3499211612), + uint_(581869302), + uint_(3890346734), + uint_(3586334585), + uint_(545404204), + uint_(4161255391), + uint_(3922919429), + uint_(949333985), + uint_(2715962298), + uint_(1323567403)) + ); +} + +BOOST_AUTO_TEST_CASE(discard_uint) +{ + using boost::compute::uint_; + + boost::compute::mt19937 rng(queue); + + boost::compute::vector<uint_> vector(5, context); + + rng.discard(5, queue); + rng.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 5, vector, + (uint_(4161255391), + uint_(3922919429), + uint_(949333985), + uint_(2715962298), + uint_(1323567403)) + ); +} + +BOOST_AUTO_TEST_CASE(copy_ctor) +{ + using boost::compute::uint_; + + boost::compute::mt19937 rng(queue); + boost::compute::mt19937 rng_copy(rng); + + boost::compute::vector<uint_> vector(10, context); + + rng_copy.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(3499211612), + uint_(581869302), + uint_(3890346734), + uint_(3586334585), + uint_(545404204), + uint_(4161255391), + uint_(3922919429), + uint_(949333985), + uint_(2715962298), + uint_(1323567403)) + ); +} + +BOOST_AUTO_TEST_CASE(assign_op) +{ + using boost::compute::uint_; + + boost::compute::mt19937 rng(queue); + boost::compute::mt19937 rng_copy(queue); + + boost::compute::vector<uint_> vector(10, context); + + rng_copy.discard(5, queue); + rng_copy = rng; + rng_copy.generate(vector.begin(), vector.end(), queue); + + CHECK_RANGE_EQUAL( + uint_, 10, vector, + (uint_(3499211612), + uint_(581869302), + uint_(3890346734), + uint_(3586334585), + uint_(545404204), + uint_(4161255391), + uint_(3922919429), + uint_(949333985), + uint_(2715962298), + uint_(1323567403)) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_mismatch.cpp b/src/boost/libs/compute/test/test_mismatch.cpp new file mode 100644 index 00000000..32d900c6 --- /dev/null +++ b/src/boost/libs/compute/test/test_mismatch.cpp @@ -0,0 +1,64 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestMismatch +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/mismatch.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(mismatch_int) +{ + int data1[] = { 1, 2, 3, 4, 5, 6 }; + int data2[] = { 1, 2, 3, 7, 5, 6 }; + + boost::compute::vector<int> vector1(data1, data1 + 6, queue); + boost::compute::vector<int> vector2(data2, data2 + 6, queue); + + typedef boost::compute::vector<int>::iterator iter; + + std::pair<iter, iter> location = + boost::compute::mismatch(vector1.begin(), vector1.end(), + vector2.begin(), queue); + BOOST_CHECK(location.first == vector1.begin() + 3); + BOOST_CHECK_EQUAL(int(*location.first), int(4)); + BOOST_CHECK(location.second == vector2.begin() + 3); + BOOST_CHECK_EQUAL(int(*location.second), int(7)); +} + +BOOST_AUTO_TEST_CASE(mismatch_different_range_sizes) +{ + boost::compute::vector<int> a(10, context); + boost::compute::vector<int> b(20, context); + + boost::compute::fill(a.begin(), a.end(), 3, queue); + boost::compute::fill(b.begin(), b.end(), 3, queue); + + typedef boost::compute::vector<int>::iterator iter; + + std::pair<iter, iter> location; + + location = boost::compute::mismatch( + a.begin(), a.end(), b.begin(), b.end(), queue + ); + BOOST_CHECK(location.first == a.end()); + BOOST_CHECK(location.second == b.begin() + 10); + + location = boost::compute::mismatch( + b.begin(), b.end(), a.begin(), a.end(), queue + ); + BOOST_CHECK(location.first == b.begin() + 10); + BOOST_CHECK(location.second == a.end()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_next_permutation.cpp b/src/boost/libs/compute/test/test_next_permutation.cpp new file mode 100644 index 00000000..b76c3811 --- /dev/null +++ b/src/boost/libs/compute/test/test_next_permutation.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestNextPermutation +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/next_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(next_permutation_int) +{ + int dataset[] = {1, 3, 4, 2, 5}; + bc::vector<bc::int_> vector(dataset, dataset + 5, queue); + + bool result = + bc::next_permutation(vector.begin(), vector.begin() + 5, queue); + + CHECK_RANGE_EQUAL(int, 5, vector, (1, 3, 4, 5, 2)); + BOOST_VERIFY(result == true); + + vector[0] = 10; vector[1] = 9; vector[2] = 6; + + result = bc::next_permutation(vector.begin(), vector.begin() + 5, queue); + + CHECK_RANGE_EQUAL(int, 5, vector, (2, 5, 6, 9, 10)); + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_CASE(next_permutation_string) +{ + char dataset[] = "aaab"; + bc::vector<bc::char_> vector(dataset, dataset + 4, queue); + + bool result = + bc::next_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'a', 'b', 'a')); + BOOST_VERIFY(result == true); + + result = bc::next_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'b', 'a', 'a')); + BOOST_VERIFY(result == true); + + result = bc::next_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('b', 'a', 'a', 'a')); + BOOST_VERIFY(result == true); + + result = bc::next_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'a', 'a', 'b')); + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_no_device_found.cpp b/src/boost/libs/compute/test/test_no_device_found.cpp new file mode 100644 index 00000000..91a48870 --- /dev/null +++ b/src/boost/libs/compute/test/test_no_device_found.cpp @@ -0,0 +1,31 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2015 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestNoDeviceFound +#include <boost/test/unit_test.hpp> + +#include <boost/compute/exception/no_device_found.hpp> + +void throw_no_device_found() +{ + throw boost::compute::no_device_found(); +} + +BOOST_AUTO_TEST_CASE(what) +{ + try { + throw_no_device_found(); + + BOOST_REQUIRE(false); // should not get here + } + catch(boost::compute::no_device_found& e){ + BOOST_CHECK_EQUAL(std::string(e.what()), "No OpenCL device found"); + } +} diff --git a/src/boost/libs/compute/test/test_normal_distribution.cpp b/src/boost/libs/compute/test/test_normal_distribution.cpp new file mode 100644 index 00000000..bb8a93ca --- /dev/null +++ b/src/boost/libs/compute/test/test_normal_distribution.cpp @@ -0,0 +1,84 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestNormalDistribution +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/normal_distribution.hpp> +#include <boost/compute/lambda.hpp> + +#include <boost/accumulators/accumulators.hpp> +#include <boost/accumulators/statistics/mean.hpp> +#include <boost/accumulators/statistics/stats.hpp> +#include <boost/accumulators/statistics/variance.hpp> + +#include "context_setup.hpp" + +template<class Stats, class T> +boost::accumulators::accumulator_set<T, Stats> +accumulate_statistics(const boost::compute::vector<T>& vector, + boost::compute::command_queue& queue) { + // copy vector to the host + std::vector<T> host_vector(vector.size()); + boost::compute::copy( + vector.begin(), vector.end(), host_vector.begin(), queue + ); + + // compute desired statistics and return accumulator object + return std::for_each( + host_vector.begin(), + host_vector.end(), + boost::accumulators::accumulator_set<T, Stats>() + ); +} + +BOOST_AUTO_TEST_CASE(normal_distribution_doctest) +{ + using boost::compute::lambda::_1; + + boost::compute::vector<float> vec(10, context); + +//! [generate] +// initialize the default random engine +boost::compute::default_random_engine engine(queue); + +// setup the normal distribution to produce floats centered at 5 +boost::compute::normal_distribution<float> distribution(5.0f, 1.0f); + +// generate the random values and store them to 'vec' +distribution.generate(vec.begin(), vec.end(), engine, queue); +//! [generate] +} + +BOOST_AUTO_TEST_CASE(normal_distribution_statistics) +{ + // generate normally distributed random numbers + const size_t n = 10000; + boost::compute::vector<float> vec(n, context); + boost::compute::default_random_engine engine(queue); + boost::compute::normal_distribution<float> distribution(10.0f, 2.0f); + distribution.generate(vec.begin(), vec.end(), engine, queue); + + // compute mean and standard deviation + using namespace boost::accumulators; + accumulator_set<float, stats<tag::variance> > acc = + accumulate_statistics<stats<tag::variance> >(vec, queue); + + // check mean and standard deviation are what we expect + BOOST_CHECK_CLOSE(mean(acc), 10.f, 0.5f); + BOOST_CHECK_CLOSE(std::sqrt(variance(acc)), 2.f, 0.5f); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_nth_element.cpp b/src/boost/libs/compute/test/test_nth_element.cpp new file mode 100644 index 00000000..ac072732 --- /dev/null +++ b/src/boost/libs/compute/test/test_nth_element.cpp @@ -0,0 +1,113 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestNthElement +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/is_partitioned.hpp> +#include <boost/compute/algorithm/nth_element.hpp> +#include <boost/compute/algorithm/partition_point.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(nth_element_int) +{ + int data[] = { 9, 15, 1, 4, 9, 9, 4, 15, 12, 1 }; + boost::compute::vector<int> vector(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::nth_element( + vector.begin(), vector.begin() + 5, vector.end(), queue + ); + + BOOST_CHECK_EQUAL(vector[5], 9); + BOOST_VERIFY(boost::compute::is_partitioned( + vector.begin(), vector.end(), boost::compute::_1 <= 9, queue + )); + BOOST_VERIFY(boost::compute::partition_point( + vector.begin(), vector.end(), boost::compute::_1 <= 9, queue + ) > vector.begin() + 5); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::nth_element( + vector.begin(), vector.end(), vector.end(), queue + ); + CHECK_RANGE_EQUAL(int, 10, vector, (9, 15, 1, 4, 9, 9, 4, 15, 12, 1)); +} + +BOOST_AUTO_TEST_CASE(nth_element_median) +{ + int data[] = { 5, 6, 4, 3, 2, 6, 7, 9, 3 }; + boost::compute::vector<int> v(9, context); + boost::compute::copy_n(data, 9, v.begin(), queue); + + boost::compute::nth_element(v.begin(), v.begin() + 4, v.end(), queue); + + BOOST_CHECK_EQUAL(v[4], 5); + BOOST_VERIFY(boost::compute::is_partitioned( + v.begin(), v.end(), boost::compute::_1 <= 5, queue + )); + BOOST_VERIFY(boost::compute::partition_point( + v.begin(), v.end(), boost::compute::_1 <= 5, queue + ) > v.begin() + 4); +} + +BOOST_AUTO_TEST_CASE(nth_element_second_largest) +{ + int data[] = { 5, 6, 4, 3, 2, 6, 7, 9, 3 }; + boost::compute::vector<int> v(9, context); + boost::compute::copy_n(data, 9, v.begin(), queue); + + boost::compute::nth_element(v.begin(), v.begin() + 1, v.end(), queue); + + BOOST_CHECK_EQUAL(v[1], 3); + BOOST_VERIFY(boost::compute::is_partitioned( + v.begin(), v.end(), boost::compute::_1 <= 3, queue + )); + BOOST_VERIFY(boost::compute::partition_point( + v.begin(), v.end(), boost::compute::_1 <= 3, queue + ) > v.begin() + 1); +} + +BOOST_AUTO_TEST_CASE(nth_element_comparator) +{ + int data[] = { 9, 15, 1, 4, 9, 9, 4, 15, 12, 1 }; + boost::compute::vector<int> vector(10, context); + + boost::compute::less<int> less_than; + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::nth_element( + vector.begin(), vector.begin() + 5, vector.end(), less_than, queue + ); + BOOST_CHECK_EQUAL(vector[5], 9); + BOOST_VERIFY(boost::compute::is_partitioned( + vector.begin(), vector.end(), boost::compute::_1 <= 9, queue + )); + BOOST_VERIFY(boost::compute::partition_point( + vector.begin(), vector.end(), boost::compute::_1 <= 9, queue + ) > vector.begin() + 5); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::nth_element( + vector.begin(), vector.end(), vector.end(), less_than, queue + ); + CHECK_RANGE_EQUAL(int, 10, vector, (9, 15, 1, 4, 9, 9, 4, 15, 12, 1)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_opencl_error.cpp b/src/boost/libs/compute/test/test_opencl_error.cpp new file mode 100644 index 00000000..6735b44a --- /dev/null +++ b/src/boost/libs/compute/test/test_opencl_error.cpp @@ -0,0 +1,35 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestOpenCLError +#include <boost/test/unit_test.hpp> + +#include <boost/compute/exception/opencl_error.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(error_to_string) +{ + using boost::compute::opencl_error; + + BOOST_CHECK_EQUAL(opencl_error::to_string(CL_SUCCESS), "Success"); + BOOST_CHECK_EQUAL(opencl_error::to_string(CL_INVALID_VALUE), "Invalid Value"); + BOOST_CHECK_EQUAL(opencl_error::to_string(-123456), "Unknown OpenCL Error (-123456)"); +} + +BOOST_AUTO_TEST_CASE(error_code) +{ + boost::compute::opencl_error e(CL_INVALID_DEVICE); + BOOST_CHECK_EQUAL(e.error_code(), CL_INVALID_DEVICE); + BOOST_CHECK_EQUAL(e.error_string(), "Invalid Device"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_pair.cpp b/src/boost/libs/compute/test/test_pair.cpp new file mode 100644 index 00000000..055ed920 --- /dev/null +++ b/src/boost/libs/compute/test/test_pair.cpp @@ -0,0 +1,194 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPair +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/find.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/get.hpp> +#include <boost/compute/functional/field.hpp> +#include <boost/compute/types/pair.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(vector_pair_int_float) +{ + boost::compute::vector<std::pair<int, float> > vector(context); + vector.push_back(std::make_pair(1, 1.1f), queue); + vector.push_back(std::make_pair(2, 2.2f), queue); + vector.push_back(std::make_pair(3, 3.3f), queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.size(), size_t(3)); + BOOST_CHECK(vector[0] == std::make_pair(1, 1.1f)); + BOOST_CHECK(vector[1] == std::make_pair(2, 2.2f)); + BOOST_CHECK(vector[2] == std::make_pair(3, 3.3f)); +} + +BOOST_AUTO_TEST_CASE(copy_pair_vector) +{ + boost::compute::vector<std::pair<int, float> > input(context); + input.push_back(std::make_pair(1, 2.0f), queue); + input.push_back(std::make_pair(3, 4.0f), queue); + input.push_back(std::make_pair(5, 6.0f), queue); + input.push_back(std::make_pair(7, 8.0f), queue); + queue.finish(); + BOOST_CHECK_EQUAL(input.size(), size_t(4)); + + boost::compute::vector<std::pair<int, float> > output(4, context); + boost::compute::copy(input.begin(), input.end(), output.begin(), queue); + queue.finish(); + BOOST_CHECK(output[0] == std::make_pair(1, 2.0f)); + BOOST_CHECK(output[1] == std::make_pair(3, 4.0f)); + BOOST_CHECK(output[2] == std::make_pair(5, 6.0f)); + BOOST_CHECK(output[3] == std::make_pair(7, 8.0f)); +} + +BOOST_AUTO_TEST_CASE(fill_pair_vector) +{ + if(bug_in_struct_assignment(device)){ + std::cerr << "skipping fill_pair_vector test" << std::endl; + return; + } + + boost::compute::vector<std::pair<int, float> > vector(5, context); + boost::compute::fill(vector.begin(), vector.end(), std::make_pair(4, 2.0f), queue); + queue.finish(); + BOOST_CHECK(vector[0] == std::make_pair(4, 2.0f)); + BOOST_CHECK(vector[1] == std::make_pair(4, 2.0f)); + BOOST_CHECK(vector[2] == std::make_pair(4, 2.0f)); + BOOST_CHECK(vector[3] == std::make_pair(4, 2.0f)); + BOOST_CHECK(vector[4] == std::make_pair(4, 2.0f)); +} + +BOOST_AUTO_TEST_CASE(fill_char_pair_vector) +{ + if(bug_in_struct_assignment(device)){ + std::cerr << "skipping fill_char_pair_vector test" << std::endl; + return; + } + + std::pair<char, unsigned char> value('c', static_cast<unsigned char>(127)); + boost::compute::vector<std::pair<char, unsigned char> > vector(5, context); + boost::compute::fill(vector.begin(), vector.end(), value, queue); + queue.finish(); + BOOST_CHECK(vector[0] == value); + BOOST_CHECK(vector[1] == value); + BOOST_CHECK(vector[2] == value); + BOOST_CHECK(vector[3] == value); + BOOST_CHECK(vector[4] == value); +} + +BOOST_AUTO_TEST_CASE(transform_pair_get) +{ + boost::compute::vector<std::pair<int, float> > input(context); + input.push_back(std::make_pair(1, 2.0f), queue); + input.push_back(std::make_pair(3, 4.0f), queue); + input.push_back(std::make_pair(5, 6.0f), queue); + input.push_back(std::make_pair(7, 8.0f), queue); + queue.finish(); + + boost::compute::vector<int> first_output(4, context); + boost::compute::transform( + input.begin(), + input.end(), + first_output.begin(), + ::boost::compute::get<0>(), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_output, (1, 3, 5, 7)); + + boost::compute::vector<float> second_output(4, context); + boost::compute::transform( + input.begin(), + input.end(), + second_output.begin(), + ::boost::compute::get<1>(), + queue + ); + CHECK_RANGE_EQUAL(float, 4, second_output, (2.0f, 4.0f, 6.0f, 8.0f)); +} + +BOOST_AUTO_TEST_CASE(transform_pair_field) +{ + boost::compute::vector<std::pair<int, float> > input(context); + input.push_back(std::make_pair(1, 2.0f), queue); + input.push_back(std::make_pair(3, 4.0f), queue); + input.push_back(std::make_pair(5, 6.0f), queue); + input.push_back(std::make_pair(7, 8.0f), queue); + + boost::compute::vector<int> first_output(4, context); + boost::compute::transform( + input.begin(), + input.end(), + first_output.begin(), + boost::compute::field<int>("first"), + queue + ); + CHECK_RANGE_EQUAL(int, 4, first_output, (1, 3, 5, 7)); + + boost::compute::vector<float> second_output(4, context); + boost::compute::transform( + input.begin(), + input.end(), + second_output.begin(), + boost::compute::field<float>("second"), + queue + ); + CHECK_RANGE_EQUAL(float, 4, second_output, (2.0f, 4.0f, 6.0f, 8.0f)); +} + +BOOST_AUTO_TEST_CASE(find_vector_pair) +{ + boost::compute::vector<std::pair<int, float> > vector(context); + vector.push_back(std::make_pair(1, 1.1f), queue); + vector.push_back(std::make_pair(2, 2.2f), queue); + vector.push_back(std::make_pair(3, 3.3f), queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(3)); + + BOOST_CHECK( + boost::compute::find( + boost::compute::make_transform_iterator( + vector.begin(), + boost::compute::get<0>() + ), + boost::compute::make_transform_iterator( + vector.end(), + boost::compute::get<0>() + ), + int(2), + queue + ).base() == vector.begin() + 1 + ); + + BOOST_CHECK( + boost::compute::find( + boost::compute::make_transform_iterator( + vector.begin(), + boost::compute::get<1>() + ), + boost::compute::make_transform_iterator( + vector.end(), + boost::compute::get<1>() + ), + float(3.3f), + queue + ).base() == vector.begin() + 2 + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_partial_sum.cpp b/src/boost/libs/compute/test/test_partial_sum.cpp new file mode 100644 index 00000000..f8d82922 --- /dev/null +++ b/src/boost/libs/compute/test/test_partial_sum.cpp @@ -0,0 +1,41 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPartialSum +#include <boost/test/unit_test.hpp> + +#include <vector> +#include <numeric> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/partial_sum.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(partial_sum_int) +{ + int data[] = { 1, 2, 5, 3, 9, 1, 4, 2 }; + bc::vector<int> a(8, context); + bc::copy(data, data + 8, a.begin(), queue); + + bc::vector<int> b(a.size(), context); + bc::vector<int>::iterator iter = + bc::partial_sum(a.begin(), a.end(), b.begin(), queue); + BOOST_CHECK(iter == b.end()); + CHECK_RANGE_EQUAL(int, 8, b, (1, 3, 8, 11, 20, 21, 25, 27)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_partition.cpp b/src/boost/libs/compute/test/test_partition.cpp new file mode 100644 index 00000000..b6faac8d --- /dev/null +++ b/src/boost/libs/compute/test/test_partition.cpp @@ -0,0 +1,82 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPartition +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/partition.hpp> +#include <boost/compute/algorithm/partition_copy.hpp> +#include <boost/compute/algorithm/is_partitioned.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(partition_float_vector) +{ + bc::vector<float> vector(context); + vector.push_back(1.0f, queue); + vector.push_back(2.0f, queue); + vector.push_back(-1.0f, queue); + vector.push_back(-2.0f, queue); + vector.push_back(3.0f, queue); + vector.push_back(4.0f, queue); + vector.push_back(-3.0f, queue); + vector.push_back(-4.0f, queue); + + // verify is_partitioned() + BOOST_VERIFY(bc::is_partitioned(vector.begin(), + vector.end(), + bc::signbit_<float>(), + queue) == false); + + // partition by signbit + bc::vector<float>::iterator iter = bc::partition(vector.begin(), + vector.end(), + bc::signbit_<float>(), + queue); + queue.finish(); + BOOST_VERIFY(iter == vector.begin() + 4); + BOOST_CHECK_LT(vector[0], 0.0f); + BOOST_CHECK_LT(vector[1], 0.0f); + BOOST_CHECK_LT(vector[2], 0.0f); + BOOST_CHECK_LT(vector[3], 0.0f); + BOOST_CHECK_GT(vector[4], 0.0f); + BOOST_CHECK_GT(vector[5], 0.0f); + BOOST_CHECK_GT(vector[6], 0.0f); + BOOST_CHECK_GT(vector[7], 0.0f); + + // verify is_partitioned() + BOOST_VERIFY(bc::is_partitioned(vector.begin(), + vector.end(), + bc::signbit_<float>(), + queue) == true); +} + +BOOST_AUTO_TEST_CASE(partition_small_vector) +{ + bc::vector<float> vector(context); + bc::partition(vector.begin(), vector.end(), bc::signbit_<float>(), queue); + + vector.push_back(1.0f, queue); + bc::partition(vector.begin(), vector.end(), bc::signbit_<float>(), queue); + CHECK_RANGE_EQUAL(float, 1, vector, (1.0f)); + + vector.push_back(-1.0f, queue); + bc::partition(vector.begin(), vector.end(), bc::signbit_<float>(), queue); + CHECK_RANGE_EQUAL(float, 2, vector, (-1.0f, 1.0f)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_partition_point.cpp b/src/boost/libs/compute/test/test_partition_point.cpp new file mode 100644 index 00000000..5cee7e9f --- /dev/null +++ b/src/boost/libs/compute/test/test_partition_point.cpp @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPartitionPoint +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/partition_point.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(partition_point_int) +{ + int dataset[] = {1, 1, 5, 2, 4, -2, 0, -1, 0, -1}; + bc::vector<bc::int_> vector(dataset, dataset + 10, queue); + + bc::vector<bc::int_>::iterator iter = + bc::partition_point(vector.begin(), vector.begin() + 10, + bc::_1 > 0, queue); + + BOOST_VERIFY(iter == vector.begin()+5); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_permutation_iterator.cpp b/src/boost/libs/compute/test/test_permutation_iterator.cpp new file mode 100644 index 00000000..ee6488c3 --- /dev/null +++ b/src/boost/libs/compute/test/test_permutation_iterator.cpp @@ -0,0 +1,110 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPermutationIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/types.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> +#include <boost/compute/iterator/permutation_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(value_type) +{ + using boost::compute::float4_; + + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::permutation_iterator< + boost::compute::buffer_iterator<float>, + boost::compute::buffer_iterator<int> + >::value_type, + float + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::permutation_iterator< + boost::compute::buffer_iterator<float4_>, + boost::compute::buffer_iterator<short> + >::value_type, + float4_ + >::value + )); +} + +BOOST_AUTO_TEST_CASE(base_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::permutation_iterator< + boost::compute::buffer_iterator<int>, + boost::compute::buffer_iterator<int> + >::base_type, + boost::compute::buffer_iterator<int> + >::value + )); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + int input_data[] = { 3, 4, 2, 1, 5 }; + boost::compute::vector<int> input(input_data, input_data + 5, queue); + + int map_data[] = { 3, 2, 0, 1, 4 }; + boost::compute::vector<int> map(map_data, map_data + 5, queue); + + boost::compute::vector<int> output(5, context); + boost::compute::copy( + boost::compute::make_permutation_iterator(input.begin(), map.begin()), + boost::compute::make_permutation_iterator(input.end(), map.end()), + output.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (1, 2, 3, 4, 5)); +} + +BOOST_AUTO_TEST_CASE(reverse_range_doctest) +{ + int values_data[] = { 10, 20, 30, 40 }; + int indices_data[] = { 3, 2, 1, 0 }; + + boost::compute::vector<int> values(values_data, values_data + 4, queue); + boost::compute::vector<int> indices(indices_data, indices_data + 4, queue); + + boost::compute::vector<int> result(4, context); + +//! [reverse_range] +// values = { 10, 20, 30, 40 } +// indices = { 3, 2, 1, 0 } + +boost::compute::copy( + boost::compute::make_permutation_iterator(values.begin(), indices.begin()), + boost::compute::make_permutation_iterator(values.end(), indices.end()), + result.begin(), + queue +); + +// result == { 40, 30, 20, 10 } +//! [reverse_range] + + CHECK_RANGE_EQUAL(int, 4, result, (40, 30, 20, 10)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_pinned_allocator.cpp b/src/boost/libs/compute/test/test_pinned_allocator.cpp new file mode 100644 index 00000000..ca34c034 --- /dev/null +++ b/src/boost/libs/compute/test/test_pinned_allocator.cpp @@ -0,0 +1,27 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPinnedAllocator +#include <boost/test/unit_test.hpp> + +#include <boost/compute/allocator/pinned_allocator.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(vector_with_pinned_allocator) +{ + compute::vector<int, compute::pinned_allocator<int> > vector(context); + vector.push_back(12, queue); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_pipe.cpp b/src/boost/libs/compute/test/test_pipe.cpp new file mode 100644 index 00000000..25e61c8d --- /dev/null +++ b/src/boost/libs/compute/test/test_pipe.cpp @@ -0,0 +1,36 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPipe +#include <boost/test/unit_test.hpp> + +#include <boost/compute/core.hpp> +#include <boost/compute/pipe.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(empty) +{ +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 +BOOST_AUTO_TEST_CASE(create_pipe) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + compute::pipe pipe(context, 16 * sizeof(float), 128); + BOOST_CHECK_EQUAL(pipe.get_info<CL_PIPE_PACKET_SIZE>(), 64); + BOOST_CHECK_EQUAL(pipe.get_info<CL_PIPE_MAX_PACKETS>(), 128); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_platform.cpp b/src/boost/libs/compute/test/test_platform.cpp new file mode 100644 index 00000000..76cfaecb --- /dev/null +++ b/src/boost/libs/compute/test/test_platform.cpp @@ -0,0 +1,45 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPlatform +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/platform.hpp> +#include <boost/compute/system.hpp> + +BOOST_AUTO_TEST_CASE(platform_id) +{ + boost::compute::platform platform = + boost::compute::system::platforms().front(); + + boost::compute::platform platform_copy(platform.id()); + + BOOST_CHECK(platform == platform_copy); + BOOST_CHECK(platform.id() == platform_copy.id()); +} + +BOOST_AUTO_TEST_CASE(platform_supports_extension) +{ + boost::compute::platform platform = + boost::compute::system::platforms().front(); + + std::string extensions = platform.get_info<CL_PLATFORM_EXTENSIONS>(); + if(extensions.empty()){ + std::cerr << "platform doesn't support any extensions" << std::endl; + return; + } + + size_t space = extensions.find(' '); + std::string first_extension = extensions.substr(0, space); + BOOST_CHECK(platform.supports_extension(first_extension) == true); + BOOST_CHECK(platform.supports_extension("invalid_extension_name") == false); +} diff --git a/src/boost/libs/compute/test/test_prev_permutation.cpp b/src/boost/libs/compute/test/test_prev_permutation.cpp new file mode 100644 index 00000000..b6edf4cf --- /dev/null +++ b/src/boost/libs/compute/test/test_prev_permutation.cpp @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestPrevPermutation +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/prev_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(prev_permutation_int) +{ + int dataset[] = {1, 3, 4, 2, 5}; + bc::vector<bc::int_> vector(dataset, dataset + 5, queue); + + bool result = + bc::prev_permutation(vector.begin(), vector.begin() + 5, queue); + + CHECK_RANGE_EQUAL(int, 5, vector, (1, 3, 2, 5, 4)); + BOOST_VERIFY(result == true); + + vector[1] = 1; vector[4] = 6; + + result = bc::prev_permutation(vector.begin(), vector.begin() + 5, queue); + + CHECK_RANGE_EQUAL(int, 5, vector, (6, 5, 2, 1, 1)); + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_CASE(prev_permutation_string) +{ + char dataset[] = "baaa"; + bc::vector<bc::char_> vector(dataset, dataset + 4, queue); + + bool result = + bc::prev_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'b', 'a', 'a')); + BOOST_VERIFY(result == true); + + result = bc::prev_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'a', 'b', 'a')); + BOOST_VERIFY(result == true); + + result = bc::prev_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('a', 'a', 'a', 'b')); + BOOST_VERIFY(result == true); + + result = bc::prev_permutation(vector.begin(), vector.begin() + 4, queue); + + CHECK_RANGE_EQUAL(char, 4, vector, ('b', 'a', 'a', 'a')); + BOOST_VERIFY(result == false); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_program.cpp b/src/boost/libs/compute/test/test_program.cpp new file mode 100644 index 00000000..7172c5e2 --- /dev/null +++ b/src/boost/libs/compute/test/test_program.cpp @@ -0,0 +1,401 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestProgram +#include <boost/test/unit_test.hpp> + +// disable the automatic kernel compilation debug messages. this allows the +// test for program to check that compilation error exceptions are properly +// thrown when invalid kernel code is passed to program::build(). +#undef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION + +#include <boost/compute/exception/program_build_failure.hpp> +#include <boost/compute/kernel.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/utility/source.hpp> + +#include "quirks.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +const char source[] = + "__kernel void foo(__global float *x, const uint n) { }\n" + "__kernel void bar(__global int *x, __global int *y) { }\n"; + + +BOOST_AUTO_TEST_CASE(get_program_info) +{ + // create program + boost::compute::program program = + boost::compute::program::create_with_source(source, context); + + // build program + program.build(); + + // check program info +#ifndef BOOST_COMPUTE_USE_OFFLINE_CACHE + BOOST_CHECK(program.source().empty() == false); +#endif + BOOST_CHECK(program.get_context() == context); +} + +BOOST_AUTO_TEST_CASE(program_source) +{ + // create program from source + boost::compute::program program = + boost::compute::program::create_with_source(source, context); + + BOOST_CHECK_EQUAL(std::string(source), program.source()); +} + +BOOST_AUTO_TEST_CASE(program_multiple_sources) +{ + std::vector<std::string> sources; + sources.push_back("__kernel void foo(__global int* x) { }\n"); + sources.push_back("__kernel void bar(__global float* y) { }\n"); + + // create program from sources + boost::compute::program program = + boost::compute::program::create_with_source(sources, context); + program.build(); + + boost::compute::kernel foo = program.create_kernel("foo"); + boost::compute::kernel bar = program.create_kernel("bar"); +} + +BOOST_AUTO_TEST_CASE(program_source_no_file) +{ + // create program from a non-existant source file + // and verifies it throws. + BOOST_CHECK_THROW(boost::compute::program program = + boost::compute::program::create_with_source_file + (std::string(), context), + std::ios_base::failure); +} + +BOOST_AUTO_TEST_CASE(create_kernel) +{ + boost::compute::program program = + boost::compute::program::create_with_source(source, context); + program.build(); + + boost::compute::kernel foo = program.create_kernel("foo"); + boost::compute::kernel bar = program.create_kernel("bar"); + + // try to create a kernel that doesn't exist + BOOST_CHECK_THROW(program.create_kernel("baz"), boost::compute::opencl_error); +} + +BOOST_AUTO_TEST_CASE(create_with_binary) +{ + // create program from source + boost::compute::program source_program = + boost::compute::program::create_with_source(source, context); + source_program.build(); + + // create kernels in source program + boost::compute::kernel source_foo_kernel = source_program.create_kernel("foo"); + boost::compute::kernel source_bar_kernel = source_program.create_kernel("bar"); + + // check source kernels + BOOST_CHECK_EQUAL(source_foo_kernel.name(), std::string("foo")); + BOOST_CHECK_EQUAL(source_bar_kernel.name(), std::string("bar")); + + // get binary + std::vector<unsigned char> binary = source_program.binary(); + + // create program from binary + boost::compute::program binary_program = + boost::compute::program::create_with_binary(binary, context); + binary_program.build(); + + // create kernels in binary program + boost::compute::kernel binary_foo_kernel = binary_program.create_kernel("foo"); + boost::compute::kernel binary_bar_kernel = binary_program.create_kernel("bar"); + + // check binary kernels + BOOST_CHECK_EQUAL(binary_foo_kernel.name(), std::string("foo")); + BOOST_CHECK_EQUAL(binary_bar_kernel.name(), std::string("bar")); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(create_with_il) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + size_t device_address_space_size = device.address_bits(); + std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH); + if(device_address_space_size == 64) + { + file_path += "/program.spirv64"; + } + else + { + file_path += "/program.spirv32"; + } + + // create program from il + boost::compute::program il_program; + BOOST_CHECK_NO_THROW( + il_program = boost::compute::program::create_with_il_file( + file_path, context + ) + ); + BOOST_CHECK_NO_THROW(il_program.build()); + + // create kernel (to check if program was loaded correctly) + BOOST_CHECK_NO_THROW(il_program.create_kernel("foobar")); +} + +BOOST_AUTO_TEST_CASE(get_program_il_binary) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + size_t device_address_space_size = device.address_bits(); + std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH); + if(device_address_space_size == 64) + { + file_path += "/program.spirv64"; + } + else + { + file_path += "/program.spirv32"; + } + + // create program from il + boost::compute::program il_program; + BOOST_CHECK_NO_THROW( + il_program = boost::compute::program::create_with_il_file( + file_path, context + ) + ); + BOOST_CHECK_NO_THROW(il_program.build()); + + std::vector<unsigned char> il_binary; + BOOST_CHECK_NO_THROW(il_binary = il_program.il_binary()); + + // create program from loaded il binary + BOOST_CHECK_NO_THROW( + il_program = boost::compute::program::create_with_il(il_binary, context) + ); + BOOST_CHECK_NO_THROW(il_program.build()); + + // create kernel (to check if program was loaded correctly) + BOOST_CHECK_NO_THROW(il_program.create_kernel("foobar")); +} + +BOOST_AUTO_TEST_CASE(get_program_il_binary_empty) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + boost::compute::program program; + BOOST_CHECK_NO_THROW( + program = boost::compute::program::create_with_source(source, context) + ); + BOOST_CHECK_NO_THROW(program.build()); + + std::vector<unsigned char> il_binary; + il_binary = program.il_binary(); + BOOST_CHECK(il_binary.empty()); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_1 + +BOOST_AUTO_TEST_CASE(create_with_source_doctest) +{ +//! [create_with_source] +std::string source = "__kernel void foo(__global int *data) { }"; + +boost::compute::program foo_program = + boost::compute::program::create_with_source(source, context); +//! [create_with_source] + + foo_program.build(); +} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_2 +BOOST_AUTO_TEST_CASE(compile_and_link) +{ + REQUIRES_OPENCL_VERSION(1,2); + + if(!supports_compile_program(device) || !supports_link_program(device)) { + return; + } + + // create the library program + const char library_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // for some reason the apple opencl compilers complains if a prototype + // for the square() function is not available, so we add it here + T square(T); + + // generic square function definition + T square(T x) { return x * x; } + ); + + compute::program library_program = + compute::program::create_with_source(library_source, context); + + library_program.compile("-DT=int"); + + // create the kernel program + const char kernel_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // forward declare square function + extern int square(int); + + // square kernel definition + __kernel void square_kernel(__global int *x) + { + x[0] = square(x[0]); + } + ); + + compute::program square_program = + compute::program::create_with_source(kernel_source, context); + + square_program.compile(); + + // link the programs + std::vector<compute::program> programs; + programs.push_back(library_program); + programs.push_back(square_program); + + compute::program linked_program = + compute::program::link(programs, context); + + // create the square kernel + compute::kernel square_kernel = + linked_program.create_kernel("square_kernel"); + BOOST_CHECK_EQUAL(square_kernel.name(), "square_kernel"); +} + +BOOST_AUTO_TEST_CASE(compile_and_link_with_headers) +{ + REQUIRES_OPENCL_VERSION(1,2); + + if(!supports_compile_program(device) || !supports_link_program(device)) { + return; + } + + // create the header programs + const char square_header_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + T square(T x) { return x * x; } + ); + const char div2_header_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + T div2(T x) { return x / 2; } + ); + + compute::program square_header_program = + compute::program::create_with_source(square_header_source, context); + compute::program div2_header_program = + compute::program::create_with_source(div2_header_source, context); + + // create the kernel program + const char kernel_source[] = + "#include \"square.h\"\n" + "#include \"div2.h\"\n" + "__kernel void squareby2_kernel(__global int *x)" + "{" + " x[0] = div2(square(x[0]));" + "}"; + + compute::program square_program = + compute::program::create_with_source(kernel_source, context); + + std::vector<std::pair<std::string, compute::program> > header_programs; + header_programs.push_back(std::make_pair("square.h", square_header_program)); + header_programs.push_back(std::make_pair("div2.h", div2_header_program)); + + square_program.compile("-DT=int", header_programs); + + // link program + std::vector<compute::program> programs; + programs.push_back(square_program); + + compute::program linked_program = + compute::program::link(programs, context); + + // create the square kernel + compute::kernel square_kernel = + linked_program.create_kernel("squareby2_kernel"); + BOOST_CHECK_EQUAL(square_kernel.name(), "squareby2_kernel"); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_2 + +BOOST_AUTO_TEST_CASE(build_log) +{ + const char invalid_source[] = + "__kernel void foo(__global int *input) { !@#$%^&*() }"; + + compute::program invalid_program = + compute::program::create_with_source(invalid_source, context); + + try { + invalid_program.build(); + + // should not get here + BOOST_CHECK(false); + } + catch(compute::opencl_error&){ + std::string log = invalid_program.build_log(); + BOOST_CHECK(!log.empty()); + } +} + +BOOST_AUTO_TEST_CASE(program_build_exception) +{ + const char invalid_source[] = + "__kernel void foo(__global int *input) { !@#$%^&*() }"; + + compute::program invalid_program = + compute::program::create_with_source(invalid_source, context); + + BOOST_CHECK_THROW(invalid_program.build(), + compute::program_build_failure); + + try { + // POCL bug: https://github.com/pocl/pocl/issues/577 + if(pocl_bug_issue_577(device)) + { + invalid_program = + compute::program::create_with_source(invalid_source, context); + } + invalid_program.build(); + + // should not get here + BOOST_CHECK(false); + } + catch(compute::program_build_failure& e){ + BOOST_CHECK(e.build_log() == invalid_program.build_log()); + } + catch(...) + { + // should not get here + BOOST_CHECK(false); + } +} + +BOOST_AUTO_TEST_CASE(build_with_source_exception) +{ + const char invalid_source[] = + "__kernel void foo(__global int *input) { !@#$%^&*() }"; + + BOOST_CHECK_THROW(compute::program::build_with_source(invalid_source, context), + compute::program_build_failure); +} + +BOOST_AUTO_TEST_CASE(build_with_source_file_exception) +{ + std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH "/invalid_program.cl"); + BOOST_CHECK_THROW(compute::program::build_with_source_file(file_path, context), + compute::program_build_failure); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_program_cache.cpp b/src/boost/libs/compute/test/test_program_cache.cpp new file mode 100644 index 00000000..446e9a87 --- /dev/null +++ b/src/boost/libs/compute/test/test_program_cache.cpp @@ -0,0 +1,99 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestProgramCache +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/utility/program_cache.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(setup) +{ + // get default context + compute::context ctx = context; + + // get program cache + boost::shared_ptr<compute::program_cache> cache = + compute::program_cache::get_global_cache(ctx); + + // try to load a null string + BOOST_CHECK(cache->get(std::string()) == boost::none); + + // try to load a non-existant program + BOOST_CHECK(cache->get("nonexistant") == boost::none); + + // create and store a program + const char p1_source[] = + "__kernel void add(__global int *a, int x)\n" + "{\n" + " a[get_global_id(0)] += x;\n" + "}\n"; + compute::program p1 = + compute::program::create_with_source(p1_source, ctx); + p1.build(); + cache->insert("p1", p1); + + // try to load the program + BOOST_CHECK(cache->get("p1") == p1); + + // create a copy of the context + compute::context ctx_copy = ctx; + + // check that they both have the same cl_context + BOOST_CHECK(ctx_copy.get() == ctx.get()); + + // check that the cache is the same + boost::shared_ptr<compute::program_cache> cache_copy = + compute::program_cache::get_global_cache(ctx_copy); + BOOST_CHECK(cache_copy == cache); + + // try to load the program again + BOOST_CHECK(cache_copy->get("p1") == p1); +} + +BOOST_AUTO_TEST_CASE(evict) +{ + // create cache with capacity of four and insert four programs + compute::program_cache cache(4); + cache.insert("a", compute::program()); + cache.insert("b", compute::program()); + cache.insert("c", compute::program()); + cache.insert("d", compute::program()); + + // check that all four programs still reside in the cache + BOOST_CHECK(cache.get("a") != boost::none); + BOOST_CHECK(cache.get("b") != boost::none); + BOOST_CHECK(cache.get("c") != boost::none); + BOOST_CHECK(cache.get("d") != boost::none); + + // insert fifth program which should evict the oldest ("a") + cache.insert("e", compute::program()); + + // check that "a" has been evicted and that "e" is now present + BOOST_CHECK(cache.get("a") == boost::none); + BOOST_CHECK(cache.get("b") != boost::none); + BOOST_CHECK(cache.get("c") != boost::none); + BOOST_CHECK(cache.get("d") != boost::none); + BOOST_CHECK(cache.get("e") != boost::none); + + // clear cache and ensure no program objects are found + cache.clear(); + BOOST_CHECK(cache.get("a") == boost::none); + BOOST_CHECK(cache.get("b") == boost::none); + BOOST_CHECK(cache.get("c") == boost::none); + BOOST_CHECK(cache.get("d") == boost::none); + BOOST_CHECK(cache.get("e") == boost::none); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_radix_sort.cpp b/src/boost/libs/compute/test/test_radix_sort.cpp new file mode 100644 index 00000000..d43deae2 --- /dev/null +++ b/src/boost/libs/compute/test/test_radix_sort.cpp @@ -0,0 +1,543 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRadixSort +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/detail/radix_sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +const bool descending = false; + +BOOST_AUTO_TEST_CASE(sort_char_vector) +{ + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all radix_sort tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + using boost::compute::char_; + + char_ data[] = { 'c', 'a', '0', '7', 'B', 'F', '\0', '$' }; + boost::compute::vector<char_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(char_, 8, vector, ('\0', '$', '0', '7', 'B', 'F', 'a', 'c')); +} + +BOOST_AUTO_TEST_CASE(sort_uchar_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::uchar_; + + uchar_ data[] = { 0x12, 0x00, 0xFF, 0xB4, 0x80, 0x32, 0x64, 0xA2 }; + boost::compute::vector<uchar_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uchar_, 8, vector, (0x00, 0x12, 0x32, 0x64, 0x80, 0xA2, 0xB4, 0xFF)); +} + +BOOST_AUTO_TEST_CASE(sort_short_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::short_; + + short_ data[] = { -4, 152, -94, 963, 31002, -456, 0, -2113 }; + boost::compute::vector<short_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(short_, 8, vector, (-2113, -456, -94, -4, 0, 152, 963, 31002)); +} + +BOOST_AUTO_TEST_CASE(sort_ushort_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::ushort_; + + ushort_ data[] = { 4, 152, 94, 963, 63202, 34560, 0, 2113 }; + boost::compute::vector<ushort_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ushort_, 8, vector, (0, 4, 94, 152, 963, 2113, 34560, 63202)); +} + +BOOST_AUTO_TEST_CASE(sort_int_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + int data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + boost::compute::vector<int> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(int, 8, vector, (-5000, -456, -4, 0, 152, 963, 1112, 75321)); +} + +BOOST_AUTO_TEST_CASE(sort_uint_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::uint_; + + uint_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<uint_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uint_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_long_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::long_; + + long_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<long_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(long_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_ulong_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::ulong_; + + ulong_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<ulong_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ulong_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_float_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + float data[] = { -6023.0f, 152.5f, -63.0f, 1234567.0f, 11.2f, + -5000.1f, 0.0f, 14.0f, -8.25f, -0.0f }; + boost::compute::vector<float> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + float, 10, vector, + (-6023.0f, -5000.1f, -63.0f, -8.25f, -0.0f, 0.0f, 11.2f, 14.0f, 152.5f, 1234567.0f) + ); + + // copy data, sort, and check again (to check program caching) + boost::compute::copy(data, data + 10, vector.begin(), queue); + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + float, 10, vector, + (-6023.0f, -5000.1f, -63.0f, -8.25f, -0.0f, 0.0f, 11.2f, 14.0f, 152.5f, 1234567.0f) + ); +} + +BOOST_AUTO_TEST_CASE(sort_double_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + if(!device.supports_extension("cl_khr_fp64")){ + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + double data[] = { -6023.0, 152.5, -63.0, 1234567.0, 11.2, + -5000.1, 0.0, 14.0, -8.25, -0.0 }; + boost::compute::vector<double> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::detail::radix_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + double, 10, vector, + (-6023.0, -5000.1, -63.0, -8.25, -0.0, 0.0, 11.2, 14.0, 152.5, 1234567.0) + ); +} + +BOOST_AUTO_TEST_CASE(sort_char_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::char_; + + char_ data[] = { 'c', 'a', '0', '7', 'B', 'F', '\0', '$' }; + boost::compute::vector<char_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<char_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<char_>(), queue + )); + + CHECK_RANGE_EQUAL( + char_, 8, vector, + ('c', 'a', 'F', 'B', '7', '0', '$', '\0') + ); +} + +BOOST_AUTO_TEST_CASE(sort_uchar_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::uchar_; + + uchar_ data[] = { 0x12, 0x00, 0xFF, 0xB4, 0x80, 0x32, 0x64, 0xA2 }; + boost::compute::vector<uchar_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<uchar_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<uchar_>(), queue + )); + + CHECK_RANGE_EQUAL( + uchar_, 8, vector, + (0xFF, 0xB4, 0xA2, 0x80, 0x64, 0x32, 0x12, 0x00) + ); +} + +BOOST_AUTO_TEST_CASE(sort_short_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::short_; + + short_ data[] = { -4, 152, -94, 963, 31002, -456, 0, -2113 }; + boost::compute::vector<short_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<short_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<short_>(), queue + )); + + CHECK_RANGE_EQUAL( + short_, 8, vector, + (31002, 963, 152, 0, -4, -94, -456, -2113) + ); +} + +BOOST_AUTO_TEST_CASE(sort_ushort_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::ushort_; + + ushort_ data[] = { 4, 152, 94, 963, 63202, 34560, 0, 2113 }; + boost::compute::vector<ushort_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<ushort_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<ushort_>(), queue + )); + + CHECK_RANGE_EQUAL( + ushort_, 8, vector, + (63202, 34560, 2113, 963, 152, 94, 4, 0) + ); +} + +BOOST_AUTO_TEST_CASE(sort_int_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::int_; + + int_ data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + boost::compute::vector<int_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<int_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<int_>(), queue + )); + + CHECK_RANGE_EQUAL( + int_, 8, vector, + (75321, 1112, 963, 152, 0, -4, -456, -5000) + ); +} + +BOOST_AUTO_TEST_CASE(sort_uint_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::uint_; + + uint_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<uint_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<uint_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<uint_>(), queue + )); + + CHECK_RANGE_EQUAL( + uint_, 8, vector, + (4000000, 123456, 102030, 9852, 1988, 562, 500, 0) + ); +} + +BOOST_AUTO_TEST_CASE(sort_long_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::long_; + + long_ data[] = { -500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<long_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<long_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<long_>(), queue + )); + + CHECK_RANGE_EQUAL( + long_, 8, vector, + (4000000, 123456, 102030, 9852, 1988, 562, 0, -500) + ); +} + +BOOST_AUTO_TEST_CASE(sort_ulong_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + using boost::compute::ulong_; + + ulong_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<ulong_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<ulong_>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<ulong_>(), queue + )); + + CHECK_RANGE_EQUAL( + ulong_, 8, vector, + (4000000, 123456, 102030, 9852, 1988, 562, 500, 0) + ); +} + +BOOST_AUTO_TEST_CASE(sort_float_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + float data[] = { + -6023.0f, 152.5f, -63.0f, 1234567.0f, 11.2f, + -5000.1f, 0.0f, 14.0f, -8.25f, -0.0f + }; + + boost::compute::vector<float> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<float>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<float>(), queue + )); + + CHECK_RANGE_EQUAL( + float, 10, vector, + (1234567.0f, 152.5f, 14.0f, 11.2f, 0.0f, -0.0f, -8.25f, -63.0f, -5000.1f, -6023.0f) + ); + + // copy data, sort, and check again (to check program caching) + boost::compute::copy(data, data + 10, vector.begin(), queue); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<float>(), queue + )); + CHECK_RANGE_EQUAL( + float, 10, vector, + (1234567.0f, 152.5f, 14.0f, 11.2f, 0.0f, -0.0f, -8.25f, -63.0f, -5000.1f, -6023.0f) + ); +} + +BOOST_AUTO_TEST_CASE(sort_double_vector_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + if(!device.supports_extension("cl_khr_fp64")){ + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + double data[] = { + -6023.0, 152.5, -63.0, 1234567.0, 11.2, -5000.1, 0.0, 14.0, -8.25, -0.0 + }; + + boost::compute::vector<double> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + + BOOST_CHECK(!boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<double>(), queue + )); + boost::compute::detail::radix_sort( + vector.begin(), vector.end(), descending, queue + ); + BOOST_CHECK(boost::compute::is_sorted( + vector.begin(), vector.end(), boost::compute::greater<double>(), queue + )); + + CHECK_RANGE_EQUAL( + double, 10, vector, + (1234567.0, 152.5, 14.0, 11.2, 0.0, -0.0, -8.25, -63.0, -5000.1, -6023.0) + ); +} + +BOOST_AUTO_TEST_CASE(sort_partial_vector) +{ + if(is_apple_cpu_device(device)) { + return; + } + + int data[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + boost::compute::vector<int> vec(data, data + 10, queue); + + boost::compute::detail::radix_sort(vec.begin() + 2, vec.end() - 2, queue); + CHECK_RANGE_EQUAL(int, 10, vec, (9, 8, 2, 3, 4, 5, 6, 7, 1, 0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_radix_sort_by_key.cpp b/src/boost/libs/compute/test/test_radix_sort_by_key.cpp new file mode 100644 index 00000000..cc86d4ba --- /dev/null +++ b/src/boost/libs/compute/test/test_radix_sort_by_key.cpp @@ -0,0 +1,311 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2016 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRadixSortByKey +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/detail/radix_sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +const bool descending = false; + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_int_by_int) +{ + if(is_apple_cpu_device(device)) { + std::cerr + << "skipping all radix_sort_by_key tests due to Apple platform" + << " behavior when local memory is used on a CPU device" + << std::endl; + return; + } + + compute::int_ keys_data[] = { 10, 9, 2, 7, 6, -1, 4, 2, 2, 10 }; + compute::int_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::int_> values(values_data, values_data + 10, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::detail::radix_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::int_, 10, keys, + (-1, 2, 2, 2, 4, 6, 7, 9, 10, 10) // keys + // ( 6, 3, 8, 9, 7, 5, 4, 2, 1, 10) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 10, values, + // (-1, 2, 2, 2, 4, 6, 7, 9, 10, 10) keys + ( 6, 3, 8, 9, 7, 5, 4, 2, 1, 10) // values + ); +} + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_int_by_int_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::int_ keys_data[] = { 10, 9, 2, 7, 6, -1, 4, 2, 2, 10 }; + compute::int_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::int_> values(values_data, values_data + 10, queue); + + BOOST_CHECK( + !compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::int_>(), queue + ) + ); + compute::detail::radix_sort_by_key( + keys.begin(), keys.end(), values.begin(), descending, queue + ); + BOOST_CHECK( + compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::int_>(), queue + ) + ); + + CHECK_RANGE_EQUAL( + compute::int_, 10, keys, + (10, 10, 9, 7, 6, 4, 2, 2, 2, -1) // keys + // ( 1, 10, 2, 4, 5, 7, 3, 8, 9, 6) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 10, values, + // (10, 10, 9, 7, 6, 4, 2, 2, 2, -1) // keys + ( 1, 10, 2, 4, 5, 7, 3, 8, 9, 6) // values + ); +} + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_uint_by_uint) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::uint_ keys_data[] = { 10, 9, 2, 7, 6, 1, 4, 2, 2, 10 }; + compute::uint_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::uint_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::uint_> values(values_data, values_data + 10, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::detail::radix_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::uint_, 10, keys, + (1, 2, 2, 2, 4, 6, 7, 9, 10, 10) // keys + // (6, 3, 8, 9, 7, 5, 4, 2, 1, 10) values + ); + CHECK_RANGE_EQUAL( + compute::uint_, 10, values, + // (1, 2, 2, 2, 4, 6, 7, 9, 10, 10) keys + (6, 3, 8, 9, 7, 5, 4, 2, 1, 10) // values + ); +} + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_uint_by_uint_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::uint_ keys_data[] = { 10, 9, 2, 7, 6, 1, 4, 2, 2, 10 }; + compute::uint_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::uint_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::uint_> values(values_data, values_data + 10, queue); + + BOOST_CHECK( + !compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::uint_>(), queue + ) + ); + compute::detail::radix_sort_by_key( + keys.begin(), keys.end(), values.begin(), descending, queue + ); + BOOST_CHECK( + compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::uint_>(), queue + ) + ); + + CHECK_RANGE_EQUAL( + compute::uint_, 10, keys, + (10, 10, 9, 7, 6, 4, 2, 2, 2, 1) // keys + // ( 1, 10, 2, 4, 5, 7, 3, 8, 9, 6) values + ); + CHECK_RANGE_EQUAL( + compute::uint_, 10, values, + // (10, 10, 9, 7, 6, 4, 2, 2, 2, 1) // keys + ( 1, 10, 2, 4, 5, 7, 3, 8, 9, 6) // values + ); +} + + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_int_by_float) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::float_ keys_data[] = { 10., 5.5, 10., 7., 5.5}; + compute::int_ values_data[] = { 1, 200, -10, 2, 4 }; + + compute::vector<compute::float_> keys(keys_data, keys_data + 5, queue); + compute::vector<compute::uint_> values(values_data, values_data + 5, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::detail::radix_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::float_, 5, keys, + (5.5, 5.5, 7., 10., 10.) // keys + // (200, 4, 2, 1, -10) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 5, values, + // (5.5, 5.5, 7., 10., 10.) keys + (200, 4, 2, 1, -10) // values + ); +} + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_int_by_float_desc) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::float_ keys_data[] = { 10., 5.5, 10., 7., 5.5}; + compute::int_ values_data[] = { 1, 200, -10, 2, 4 }; + + compute::vector<compute::float_> keys(keys_data, keys_data + 5, queue); + compute::vector<compute::uint_> values(values_data, values_data + 5, queue); + + BOOST_CHECK( + !compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::float_>(), queue + ) + ); + compute::detail::radix_sort_by_key( + keys.begin(), keys.end(), values.begin(), descending, queue + ); + BOOST_CHECK( + compute::is_sorted( + keys.begin(), keys.end(), compute::greater<compute::float_>(), queue + ) + ); + + CHECK_RANGE_EQUAL( + compute::float_, 5, keys, + (10., 10., 7., 5.5, 5.5) // keys + // ( 1, -10, 2, 200, 4) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 5, values, + // (10., 10., 7., 5.5, 5.5) // keys + ( 1, -10, 2, 200, 4) // values + ); +} + + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_char_by_int) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::int_ keys_data[] = { 6, 1, 1, 3, 4, 7, 5, 1 }; + compute::char_ values_data[] = { 'g', 'c', 'b', 'd', 'e', 'h', 'f', 'a' }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 8, queue); + compute::vector<compute::char_> values(values_data, values_data + 8, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::detail::radix_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::int_, 8, keys, + (1, 1, 1, 3, 4, 5, 6, 7) + ); + CHECK_RANGE_EQUAL( + compute::char_, 8, values, + ('c', 'b', 'a', 'd', 'e', 'f', 'g', 'h') + ); +} + +// radix_sort_by_key should be stable +BOOST_AUTO_TEST_CASE(stable_radix_sort_int2_by_int) +{ + if(is_apple_cpu_device(device)) { + return; + } + + compute::int_ keys_data[] = { 6, 1, 1, 3, 4, 7, 5, 1 }; + compute::int2_ values_data[] = { + compute::int2_(1, 1), // 6 + compute::int2_(1, 2), // 1 + compute::int2_(1, 3), // 1 + compute::int2_(1, 4), // 3 + compute::int2_(1, 5), // 4 + compute::int2_(1, 6), // 7 + compute::int2_(1, 7), // 5 + compute::int2_(1, 8) // 1 + }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 8, queue); + compute::vector<compute::int2_> values(values_data, values_data + 8, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::detail::radix_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::int_, 8, keys, + (1, 1, 1, 3, 4, 5, 6, 7) + ); + CHECK_RANGE_EQUAL( + compute::int2_, 8, values, + ( + compute::int2_(1, 2), + compute::int2_(1, 3), + compute::int2_(1, 8), + compute::int2_(1, 4), + compute::int2_(1, 5), + compute::int2_(1, 7), + compute::int2_(1, 1), + compute::int2_(1, 6) + ) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_random_fill.cpp b/src/boost/libs/compute/test/test_random_fill.cpp new file mode 100644 index 00000000..8d890e7d --- /dev/null +++ b/src/boost/libs/compute/test/test_random_fill.cpp @@ -0,0 +1,76 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRandomFill +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/algorithm/detail/random_fill.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/lambda.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(random_fill_float) +{ + using compute::lambda::_1; + + compute::vector<float> vector(10, context); + + // fill with values between 0 and 1 + compute::detail::random_fill( + vector.begin(), + vector.end(), + 0.0f, + 1.0f, + queue + ); + + BOOST_CHECK_EQUAL( + compute::count_if( + vector.begin(), vector.end(), _1 < 0.0f || _1 > 1.0f, queue + ), + size_t(0) + ); + + // fill with values between 5 and 10 + compute::detail::random_fill( + vector.begin(), + vector.end(), + 5.0f, + 10.0f, + queue + ); + + BOOST_CHECK_EQUAL( + compute::count_if( + vector.begin(), vector.end(), _1 < 5.0f || _1 > 10.0f, queue + ), + size_t(0) + ); + + // fill with values between -25 and 25 + compute::detail::random_fill( + vector.begin(), vector.end(), -25.0f, 25.0f, queue + ); + + BOOST_CHECK_EQUAL( + compute::count_if( + vector.begin(), vector.end(), _1 < -25.0f || _1 > 25.0f, queue + ), + size_t(0) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_random_shuffle.cpp b/src/boost/libs/compute/test/test_random_shuffle.cpp new file mode 100644 index 00000000..69885aba --- /dev/null +++ b/src/boost/libs/compute/test/test_random_shuffle.cpp @@ -0,0 +1,54 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRandomShuffle +#include <boost/test/unit_test.hpp> + +#include <set> +#include <iterator> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/random_shuffle.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(shuffle_int_vector) +{ + bc::vector<int> vector(context); + vector.push_back(1, queue); + vector.push_back(9, queue); + vector.push_back(19, queue); + vector.push_back(29, queue); + queue.finish(); + + std::set<int> original_values; + for(size_t i = 0; i < vector.size(); i++){ + original_values.insert(vector[i]); + } + BOOST_CHECK_EQUAL(original_values.size(), size_t(4)); + + bc::random_shuffle(vector.begin(), vector.end(), queue); + + std::set<int> shuffled_values; + bc::copy( + vector.begin(), + vector.end(), + std::inserter(shuffled_values, shuffled_values.begin()), + queue + ); + BOOST_CHECK_EQUAL(shuffled_values.size(), size_t(4)); + BOOST_VERIFY(original_values == shuffled_values); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_reduce.cpp b/src/boost/libs/compute/test/test_reduce.cpp new file mode 100644 index 00000000..c3855061 --- /dev/null +++ b/src/boost/libs/compute/test/test_reduce.cpp @@ -0,0 +1,298 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestReduce +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/reduce.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_iterator.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> +#include <boost/compute/iterator/transform_iterator.hpp> +#include <boost/compute/types/complex.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(reduce_int) +{ + int data[] = { 1, 5, 9, 13, 17 }; + compute::vector<int> vector(data, data + 5, queue); + int sum; + compute::reduce(vector.begin(), vector.end(), &sum, compute::plus<int>(), queue); + BOOST_CHECK_EQUAL(sum, 45); + + int product; + compute::reduce(vector.begin(), vector.end(), &product, compute::multiplies<int>(), queue); + BOOST_CHECK_EQUAL(product, 9945); +} + +BOOST_AUTO_TEST_CASE(reduce_empty_vector) +{ + compute::vector<short> vector(context); + + short sum = 0; + compute::reduce(vector.begin(), vector.end(), &sum, queue); + BOOST_CHECK_EQUAL(sum, short(0)); +} + +BOOST_AUTO_TEST_CASE(reduce_doctest) +{ + int data[] = { 1, 2, 3, 4 }; + boost::compute::vector<int> vec(data, data + 4, queue); + +//! [sum_int] +int sum = 0; +boost::compute::reduce(vec.begin(), vec.end(), &sum, queue); +//! [sum_int] + + BOOST_CHECK_EQUAL(sum, 10); +} + +BOOST_AUTO_TEST_CASE(reduce_twos) +{ + using compute::uint_; + + compute::vector<uint_> vector(8, context); + compute::fill(vector.begin(), vector.end(), uint_(2), queue); + + uint_ sum; + compute::reduce(vector.begin(), vector.end(), &sum, compute::plus<uint_>(), queue); + BOOST_CHECK_EQUAL(sum, uint_(16)); + + uint_ product; + compute::reduce(vector.begin(), vector.end(), &product, compute::multiplies<uint_>(), queue); + BOOST_CHECK_EQUAL(product, uint_(256)); +} + +BOOST_AUTO_TEST_CASE(reduce_on_device) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> input(data, data + 8, queue); + compute::vector<int> result(2, context); + compute::reduce(input.begin(), input.begin() + 4, result.begin(), queue); + compute::reduce(input.begin() + 4, input.end(), result.end() - 1, queue); + CHECK_RANGE_EQUAL(int, 2, result, (10, 26)); +} + +BOOST_AUTO_TEST_CASE(reduce_int_min_max) +{ + int data[] = { 11, 5, 92, 13, 42 }; + compute::vector<int> vector(data, data + 5, queue); + int min_value; + compute::reduce( + vector.begin(), + vector.end(), + &min_value, + compute::min<int>(), + queue + ); + BOOST_CHECK_EQUAL(min_value, 5); + + int max_value; + compute::reduce( + vector.begin(), + vector.end(), + &max_value, + compute::max<int>(), + queue + ); + BOOST_CHECK_EQUAL(max_value, 92); +} + +BOOST_AUTO_TEST_CASE(reduce_int2) +{ + std::vector<compute::int2_> data; + for(int i = 0; i < 6; i++){ + compute::int2_ value; + value[0] = i + 1; + value[1] = 2 * i + 1; + data.push_back(value); + } + + compute::vector<compute::int2_> vector(data.begin(), data.end(), queue); + + compute::int2_ sum; + compute::reduce( + vector.begin(), + vector.end(), + &sum, + queue + ); + BOOST_CHECK_EQUAL(sum, compute::int2_(21, 36)); +} + +BOOST_AUTO_TEST_CASE(reduce_pinned_vector) +{ + int data[] = { 2, 5, 8, 11, 15 }; + std::vector<int> vector(data, data + 5); + + compute::buffer buffer(context, + vector.size() * sizeof(int), + compute::buffer::read_only | compute::buffer::use_host_ptr, + &vector[0]); + + int sum; + compute::reduce( + compute::make_buffer_iterator<int>(buffer, 0), + compute::make_buffer_iterator<int>(buffer, 5), + &sum, + compute::plus<int>() + ); + BOOST_CHECK_EQUAL(sum, 41); +} + +BOOST_AUTO_TEST_CASE(reduce_constant_iterator) +{ + int result; + compute::reduce( + compute::make_constant_iterator(1, 0), + compute::make_constant_iterator(1, 5), + &result, + queue + ); + BOOST_CHECK_EQUAL(result, 5); + + compute::reduce( + compute::make_constant_iterator(3, 0), + compute::make_constant_iterator(3, 5), + &result, + queue + ); + BOOST_CHECK_EQUAL(result, 15); + + compute::reduce( + compute::make_constant_iterator(2, 0), + compute::make_constant_iterator(2, 5), + &result, + compute::multiplies<int>(), + queue + ); + BOOST_CHECK_EQUAL(result, 32); +} + +BOOST_AUTO_TEST_CASE(reduce_counting_iterator) +{ + int result; + compute::reduce( + compute::make_counting_iterator(1), + compute::make_counting_iterator(10), + &result, + queue + ); + BOOST_CHECK_EQUAL(result, 45); + + compute::reduce( + compute::make_counting_iterator(1), + compute::make_counting_iterator(5), + &result, + compute::multiplies<int>(), + queue + ); + BOOST_CHECK_EQUAL(result, 24); +} + +BOOST_AUTO_TEST_CASE(reduce_transform_iterator) +{ + using ::boost::compute::_1; + + int data[] = { 1, 3, 5, 7, 9 }; + compute::vector<int> vector(data, data + 5, queue); + + int sum; + compute::reduce( + compute::make_transform_iterator(vector.begin(), _1 + 1), + compute::make_transform_iterator(vector.end(), _1 + 1), + &sum, + queue + ); + BOOST_CHECK_EQUAL(sum, 30); + + compute::reduce( + compute::make_transform_iterator(vector.begin(), _1 > 4), + compute::make_transform_iterator(vector.end(), _1 > 4), + &sum, + compute::plus<int>(), + queue + ); + BOOST_CHECK_EQUAL(sum, 3); + + compute::reduce( + compute::make_transform_iterator(vector.begin(), _1 * _1), + compute::make_transform_iterator(vector.end(), _1 * _1), + &sum, + queue + ); + BOOST_CHECK_EQUAL(sum, 165); +} + +BOOST_AUTO_TEST_CASE(reduce_complex) +{ + std::vector<std::complex<float> > data; + data.push_back(std::complex<float>(1, 2)); + data.push_back(std::complex<float>(2, 4)); + data.push_back(std::complex<float>(3, 6)); + data.push_back(std::complex<float>(4, 8)); + + compute::vector<std::complex<float> > vector(data.size(), context); + compute::copy(data.begin(), data.end(), vector.begin(), queue); + + std::complex<float> result; + compute::reduce( + vector.begin(), vector.end(), &result, queue + ); + BOOST_CHECK(result == std::complex<float>(10, 20)); + + compute::reduce( + vector.begin(), vector.end(), &result, compute::plus<std::complex<float> >(), queue + ); + BOOST_CHECK(result == std::complex<float>(10, 20)); + + compute::reduce( + vector.begin(), vector.end(), &result, compute::multiplies<std::complex<float> >(), queue + ); + BOOST_CHECK(result == std::complex<float>(-168, -576)); +} + +BOOST_AUTO_TEST_CASE(reduce_uchar_to_float) +{ + compute::vector<compute::uchar_> data(context); + data.push_back(250, queue); + data.push_back(250, queue); + float sum = 0; + compute::reduce(data.begin(), data.end(), &sum, compute::plus<float>(), queue); + BOOST_CHECK_EQUAL(sum, 500); +} + +// Test case for https://github.com/boostorg/compute/issues/746 +BOOST_AUTO_TEST_CASE(buffer_reference_count_test) +{ + using compute::uint_; + + compute::vector<uint_> vector(8, context); + const compute::buffer& b = vector.get_buffer(); + uint_ rc1 = b.get_info<CL_MEM_REFERENCE_COUNT>(); + { + compute::fill(vector.begin(), vector.end(), uint_(2), queue); + + uint_ product; + compute::reduce(vector.begin(), vector.end(), &product, compute::multiplies<uint_>(), queue); + BOOST_CHECK_EQUAL(product, uint_(256)); + } + uint_ rc2 = b.get_info<CL_MEM_REFERENCE_COUNT>(); + BOOST_CHECK_EQUAL(rc1, rc2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_reduce_by_key.cpp b/src/boost/libs/compute/test/test_reduce_by_key.cpp new file mode 100644 index 00000000..df34250f --- /dev/null +++ b/src/boost/libs/compute/test/test_reduce_by_key.cpp @@ -0,0 +1,210 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2015 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestReduceByKey +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/inclusive_scan.hpp> +#include <boost/compute/algorithm/reduce_by_key.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(reduce_by_key_int) +{ +//! [reduce_by_key_int] +// setup keys and values +int keys[] = { 0, 2, -3, -3, -3, -3, -3, 4 }; +int data[] = { 1, 1, 1, 1, 1, 2, 5, 1 }; + +boost::compute::vector<int> keys_input(keys, keys + 8, queue); +boost::compute::vector<int> values_input(data, data + 8, queue); + +boost::compute::vector<int> keys_output(8, context); +boost::compute::vector<int> values_output(8, context); +// reduce by key +boost::compute::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); +// keys_output = { 0, 2, -3, 4 } +// values_output = { 1, 1, 10, 1 } +//! [reduce_by_key_int] + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 2, -3, 4)); + CHECK_RANGE_EQUAL(int, 4, values_output, (1, 1, 10, 1)); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_int_long_vector) +{ + size_t size = 1024; + bc::vector<int> keys_input(size, int(0), queue); + bc::vector<int> values_input(size, int(1), queue); + + bc::vector<int> keys_output(size, context); + bc::vector<int> values_output(size, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 1, keys_output, (0)); + CHECK_RANGE_EQUAL(int, 1, values_output, (static_cast<int>(size))); + + keys_input[137] = 1; + keys_input[677] = 1; + keys_input[1001] = 1; + bc::inclusive_scan(keys_input.begin(), keys_input.end(), keys_input.begin(), queue); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 1, 2, 3)); + CHECK_RANGE_EQUAL(int, 4, values_output, (137, 540, 324, 23)); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_empty_vector) +{ + bc::vector<int> keys_input(context); + bc::vector<int> values_input(context); + + bc::vector<int> keys_output(context); + bc::vector<int> values_output(context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + BOOST_CHECK(keys_output.empty()); + BOOST_CHECK(values_output.empty()); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_int_one_key_value) +{ + int keys[] = { 22 }; + int data[] = { -9 }; + + bc::vector<int> keys_input(keys, keys + 1, queue); + bc::vector<int> values_input(data, data + 1, queue); + + bc::vector<int> keys_output(1, context); + bc::vector<int> values_output(1, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 1, keys_output, (22)); + CHECK_RANGE_EQUAL(int, 1, values_output, (-9)); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_int_min_max) +{ + int keys[] = { 0, 2, 2, 3, 3, 3, 3, 3, 4 }; + int data[] = { 1, 2, 1, -3, 1, 4, 2, 5, 77 }; + + bc::vector<int> keys_input(keys, keys + 9, queue); + bc::vector<int> values_input(data, data + 9, queue); + + bc::vector<int> keys_output(9, context); + bc::vector<int> values_output(9, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), bc::min<int>(), + bc::equal_to<int>(), queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 2, 3, 4)); + CHECK_RANGE_EQUAL(int, 4, values_output, (1, 1, -3, 77)); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), bc::max<int>(), + bc::equal_to<int>(), queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 2, 3, 4)); + CHECK_RANGE_EQUAL(int, 4, values_output, (1, 2, 5, 77)); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_float_max) +{ + int keys[] = { 0, 2, 2, 3, 3, 3, 3, 3, 4 }; + float data[] = { 1.0, 2.0, -1.5, -3.0, 1.0, -0.24, 2, 5, 77.1 }; + + bc::vector<int> keys_input(keys, keys + 9, queue); + bc::vector<float> values_input(data, data + 9, queue); + + bc::vector<int> keys_output(9, context); + bc::vector<float> values_output(9, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), bc::max<float>(), + queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 2, 3, 4)); + BOOST_CHECK_CLOSE(float(values_output[0]), 1.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(values_output[1]), 2.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(values_output[2]), 5.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(values_output[3]), 77.1f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_int2) +{ + using bc::int2_; + + int keys[] = { 0, 2, 3, 3, 3, 3, 4, 4 }; + int2_ data[] = { + int2_(0, 1), int2_(-3, 2), int2_(0, 1), int2_(0, 1), + int2_(-3, 0), int2_(0, 0), int2_(-3, 2), int2_(-7, -2) + }; + + bc::vector<int> keys_input(keys, keys + 8, queue); + bc::vector<int2_> values_input(data, data + 8, queue); + + bc::vector<int> keys_output(8, context); + bc::vector<int2_> values_output(8, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 2, 3, 4)); + CHECK_RANGE_EQUAL(int2_, 4, values_output, + (int2_(0, 1), int2_(-3, 2), int2_(-3, 2), int2_(-10, 0))); +} + +BOOST_AUTO_TEST_CASE(reduce_by_key_int2_long_vector) +{ + using bc::int2_; + + size_t size = 1024; + bc::vector<int> keys_input(size, int(0), queue); + bc::vector<int2_> values_input(size, int2_(1, -1), queue); + + bc::vector<int> keys_output(size, context); + bc::vector<int2_> values_output(size, context); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 1, keys_output, (0)); + CHECK_RANGE_EQUAL(int2_, 1, values_output, (int2_(int(size), -int(size)))); + + keys_input[137] = 1; + keys_input[677] = 1; + keys_input[1001] = 1; + bc::inclusive_scan(keys_input.begin(), keys_input.end(), keys_input.begin(), queue); + + bc::reduce_by_key(keys_input.begin(), keys_input.end(), values_input.begin(), + keys_output.begin(), values_output.begin(), queue); + + CHECK_RANGE_EQUAL(int, 4, keys_output, (0, 1, 2, 3)); + CHECK_RANGE_EQUAL(int2_, 4, values_output, + (int2_(137, -137), int2_(540, -540), int2_(324, -324), int2_(23, -23))); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_remove.cpp b/src/boost/libs/compute/test/test_remove.cpp new file mode 100644 index 00000000..5cb980bd --- /dev/null +++ b/src/boost/libs/compute/test/test_remove.cpp @@ -0,0 +1,55 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRemove +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/remove.hpp> +#include <boost/compute/algorithm/remove_if.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(remove_int) +{ + int data[] = { 1, 2, 1, 3, 2, 4, 3, 4, 5 }; + bc::vector<int> vector(data, data + 9, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(9)); + + // remove 2's + bc::vector<int>::const_iterator iter = + bc::remove(vector.begin(), vector.end(), 2, queue); + BOOST_VERIFY(iter == vector.begin() + 7); + CHECK_RANGE_EQUAL(int, 7, vector, (1, 1, 3, 4, 3, 4, 5)); + + // remove 4's + iter = bc::remove(vector.begin(), vector.begin() + 7, 4, queue); + BOOST_VERIFY(iter == vector.begin() + 5); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 1, 3, 3, 5)); + + // remove 1's + iter = bc::remove(vector.begin(), vector.begin() + 5, 1, queue); + BOOST_VERIFY(iter == vector.begin() + 3); + CHECK_RANGE_EQUAL(int, 3, vector, (3, 3, 5)); + + // remove 5's + iter = bc::remove(vector.begin(), vector.begin() + 3, 5, queue); + BOOST_VERIFY(iter == vector.begin() + 2); + CHECK_RANGE_EQUAL(int, 2, vector, (3, 3)); + + // remove 3's + iter = bc::remove(vector.begin(), vector.begin() + 2, 3, queue); + BOOST_VERIFY(iter == vector.begin()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_replace.cpp b/src/boost/libs/compute/test/test_replace.cpp new file mode 100644 index 00000000..6ce5ffd6 --- /dev/null +++ b/src/boost/libs/compute/test/test_replace.cpp @@ -0,0 +1,53 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestReplace +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/replace.hpp> +#include <boost/compute/algorithm/replace_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(replace_int) +{ + bc::vector<int> vector(5, context); + bc::iota(vector.begin(), vector.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (0, 1, 2, 3, 4)); + + bc::replace(vector.begin(), vector.end(), 2, 6, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (0, 1, 6, 3, 4)); +} + +BOOST_AUTO_TEST_CASE(replace_copy_int) +{ + bc::vector<int> a(5, context); + bc::iota(a.begin(), a.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 5, a, (0, 1, 2, 3, 4)); + + bc::vector<int> b(5, context); + bc::vector<int>::iterator iter = + bc::replace_copy(a.begin(), a.end(), b.begin(), 3, 9, queue); + BOOST_CHECK(iter == b.end()); + CHECK_RANGE_EQUAL(int, 5, b, (0, 1, 2, 9, 4)); + + // ensure 'a' was not modified + CHECK_RANGE_EQUAL(int, 5, a, (0, 1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_result_of.cpp b/src/boost/libs/compute/test/test_result_of.cpp new file mode 100644 index 00000000..e964c4de --- /dev/null +++ b/src/boost/libs/compute/test/test_result_of.cpp @@ -0,0 +1,40 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestResultOf +#include <boost/test/unit_test.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/functional/operator.hpp> +#include <boost/compute/type_traits/result_of.hpp> + +BOOST_AUTO_TEST_CASE(result_of_function) +{ + using boost::compute::function; + using boost::compute::result_of; + + BOOST_STATIC_ASSERT(( + boost::is_same<result_of<function<int()>()>::type, int>::value + )); +} + +BOOST_AUTO_TEST_CASE(result_of_operators) +{ + using boost::compute::plus; + using boost::compute::minus; + using boost::compute::result_of; + + BOOST_STATIC_ASSERT(( + boost::is_same<result_of<plus<int>(int, int)>::type, int>::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same<result_of<minus<int>(int, int)>::type, int>::value + )); +} diff --git a/src/boost/libs/compute/test/test_reverse.cpp b/src/boost/libs/compute/test/test_reverse.cpp new file mode 100644 index 00000000..03ffe639 --- /dev/null +++ b/src/boost/libs/compute/test/test_reverse.cpp @@ -0,0 +1,93 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestReverse +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/algorithm/reverse_copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(reverse_int) +{ + bc::vector<int> vector(5, context); + bc::iota(vector.begin(), vector.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (0, 1, 2, 3, 4)); + + bc::reverse(vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(int, 5, vector, (4, 3, 2, 1, 0)); + + bc::reverse(vector.begin() + 1, vector.end(), queue); + CHECK_RANGE_EQUAL(int, 5, vector, (4, 0, 1, 2, 3)); + + bc::reverse(vector.begin() + 1, vector.end() - 1, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (4, 2, 1, 0, 3)); + + bc::reverse(vector.begin(), vector.end() - 2, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 4, 0, 3)); + + vector.resize(6, queue); + bc::iota(vector.begin(), vector.end(), 10, queue); + CHECK_RANGE_EQUAL(int, 6, vector, (10, 11, 12, 13, 14, 15)); + + bc::reverse(vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(int, 6, vector, (15, 14, 13, 12, 11, 10)); + + bc::reverse(vector.begin() + 3, vector.end(), queue); + CHECK_RANGE_EQUAL(int, 6, vector, (15, 14, 13, 10, 11, 12)); + + bc::reverse(vector.begin() + 1, vector.end() - 2, queue); + CHECK_RANGE_EQUAL(int, 6, vector, (15, 10, 13, 14, 11, 12)); +} + +BOOST_AUTO_TEST_CASE(reverse_copy_int) +{ + bc::vector<int> a(5, context); + bc::iota(a.begin(), a.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 5, a, (0, 1, 2, 3, 4)); + + bc::vector<int> b(5, context); + bc::vector<int>::iterator iter = + bc::reverse_copy(a.begin(), a.end(), b.begin(), queue); + BOOST_CHECK(iter == b.end()); + CHECK_RANGE_EQUAL(int, 5, b, (4, 3, 2, 1, 0)); + + iter = bc::reverse_copy(b.begin() + 1, b.end(), a.begin() + 1, queue); + BOOST_CHECK(iter == a.end()); + CHECK_RANGE_EQUAL(int, 5, a, (0, 0, 1, 2, 3)); + + iter = bc::reverse_copy(a.begin(), a.end() - 1, b.begin(), queue); + BOOST_CHECK(iter == (b.end() - 1)); + CHECK_RANGE_EQUAL(int, 5, b, (2, 1, 0, 0, 0)); +} + +BOOST_AUTO_TEST_CASE(reverse_copy_counting_iterator) +{ + bc::vector<int> vector(5, context); + bc::reverse_copy( + bc::make_counting_iterator(1), + bc::make_counting_iterator(6), + vector.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, vector, (5, 4, 3, 2, 1)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_rotate.cpp b/src/boost/libs/compute/test/test_rotate.cpp new file mode 100644 index 00000000..cedec5d0 --- /dev/null +++ b/src/boost/libs/compute/test/test_rotate.cpp @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRotate +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/rotate.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(rotate_trivial) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate(vector.begin(), vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(int, 10, vector, (1, 4, 2, 6, 3, 2, 5, 3, 4, 6)); + + boost::compute::rotate(vector.begin(), vector.end(), vector.end(), queue); + CHECK_RANGE_EQUAL(int, 10, vector, (1, 4, 2, 6, 3, 2, 5, 3, 4, 6)); +} + +BOOST_AUTO_TEST_CASE(rotate_1) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate(vector.begin(), vector.begin()+1, vector.end(), queue); + CHECK_RANGE_EQUAL(int, 10, vector, (4, 2, 6, 3, 2, 5, 3, 4, 6, 1)); +} + +BOOST_AUTO_TEST_CASE(rotate_4) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate(vector.begin(), vector.begin()+4, vector.end(), queue); + CHECK_RANGE_EQUAL(int, 10, vector, (3, 2, 5, 3, 4, 6, 1, 4, 2, 6)); +} + +BOOST_AUTO_TEST_CASE(rotate_9) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate(vector.begin(), vector.begin()+9, vector.end(), queue); + CHECK_RANGE_EQUAL(int, 10, vector, (6, 1, 4, 2, 6, 3, 2, 5, 3, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_rotate_copy.cpp b/src/boost/libs/compute/test/test_rotate_copy.cpp new file mode 100644 index 00000000..14f67d7f --- /dev/null +++ b/src/boost/libs/compute/test/test_rotate_copy.cpp @@ -0,0 +1,73 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestRotateCopy +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/rotate_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(rotate_copy_trivial) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + boost::compute::vector<int> result(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate_copy(vector.begin(), vector.begin(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int, 10, result, (1, 4, 2, 6, 3, 2, 5, 3, 4, 6)); + + boost::compute::rotate_copy(vector.begin(), vector.end(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int, 10, result, (1, 4, 2, 6, 3, 2, 5, 3, 4, 6)); +} + +BOOST_AUTO_TEST_CASE(rotate_copy_1) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + boost::compute::vector<int> result(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate_copy(vector.begin(), vector.begin()+1, vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int, 10, result, (4, 2, 6, 3, 2, 5, 3, 4, 6, 1)); +} + +BOOST_AUTO_TEST_CASE(rotate_copy_4) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + boost::compute::vector<int> result(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate_copy(vector.begin(), vector.begin()+4, vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int, 10, result, (3, 2, 5, 3, 4, 6, 1, 4, 2, 6)); +} + +BOOST_AUTO_TEST_CASE(rotate_copy_9) +{ + int data[] = {1, 4, 2, 6, 3, 2, 5, 3, 4, 6}; + boost::compute::vector<int> vector(10, context); + boost::compute::vector<int> result(10, context); + + boost::compute::copy_n(data, 10, vector.begin(), queue); + + boost::compute::rotate_copy(vector.begin(), vector.begin()+9, vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int, 10, result, (6, 1, 4, 2, 6, 3, 2, 5, 3, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_scan.cpp b/src/boost/libs/compute/test/test_scan.cpp new file mode 100644 index 00000000..1504ea06 --- /dev/null +++ b/src/boost/libs/compute/test/test_scan.cpp @@ -0,0 +1,490 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +// Undefining BOOST_COMPUTE_USE_OFFLINE_CACHE macro as we want to modify cached +// parameters for copy algorithm without any undesirable consequences (like +// saving modified values of those parameters). +#ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE + #undef BOOST_COMPUTE_USE_OFFLINE_CACHE +#endif + +#define BOOST_TEST_MODULE TestScan +#include <boost/test/unit_test.hpp> + +#include <numeric> +#include <functional> +#include <vector> + +#include <boost/compute/functional.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/exclusive_scan.hpp> +#include <boost/compute/algorithm/inclusive_scan.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> +#include <boost/compute/iterator/transform_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(inclusive_scan_int) +{ + using boost::compute::uint_; + using boost::compute::int_; + + int_ data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + bc::vector<int_> vector(data, data + 12, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(12)); + + bc::vector<int_> result(12, context); + BOOST_CHECK_EQUAL(result.size(), size_t(12)); + + // inclusive scan + bc::inclusive_scan(vector.begin(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, result, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66)); + + // in-place inclusive scan + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + bc::inclusive_scan(vector.begin(), vector.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66)); + + // scan_on_cpu + + bc::copy(data, data + 12, vector.begin(), queue); + + // make sure parallel scan_on_cpu is used, no serial_scan + std::string cache_key = + "__boost_scan_cpu_4"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_scan_threshold", 0); + // force parallel scan_on_cpu + parameters->set(cache_key, "serial_scan_threshold", 0); + + // inclusive scan + bc::inclusive_scan(vector.begin(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, result, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66)); + + // in-place inclusive scan + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + bc::inclusive_scan(vector.begin(), vector.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66)); + + // restore + parameters->set(cache_key, "serial_scan_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_int) +{ + using boost::compute::uint_; + using boost::compute::int_; + + int_ data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + bc::vector<int_> vector(data, data + 12, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(12)); + + bc::vector<int_> result(size_t(12), int_(0), queue); + BOOST_CHECK_EQUAL(result.size(), size_t(12)); + + // exclusive scan + bc::exclusive_scan(vector.begin(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, result, (0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // in-place exclusive scan + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + bc::exclusive_scan(vector.begin(), vector.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // scan_on_cpu + bc::copy(data, data + 12, vector.begin(), queue); + + // make sure parallel scan_on_cpu is used, no serial_scan + std::string cache_key = + "__boost_scan_cpu_4"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_scan_threshold", 0); + // force parallel scan_on_cpu + parameters->set(cache_key, "serial_scan_threshold", 0); + + // exclusive scan + bc::exclusive_scan(vector.begin(), vector.end(), result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, result, (0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // in-place exclusive scan + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + bc::exclusive_scan(vector.begin(), vector.end(), vector.begin(), queue); + CHECK_RANGE_EQUAL(int_, 12, vector, (0, 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // restore + parameters->set(cache_key, "serial_scan_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_int2) +{ + using boost::compute::int_; + using boost::compute::uint_; + using boost::compute::int2_; + + int_ data[] = { 1, 2, + 3, 4, + 5, 6, + 7, 8, + 9, 0 }; + + boost::compute::vector<int2_> input(reinterpret_cast<int2_*>(data), + reinterpret_cast<int2_*>(data) + 5, + queue); + BOOST_CHECK_EQUAL(input.size(), size_t(5)); + + boost::compute::vector<int2_> output(5, context); + boost::compute::inclusive_scan(input.begin(), input.end(), output.begin(), + queue); + CHECK_RANGE_EQUAL( + int2_, 5, output, + (int2_(1, 2), int2_(4, 6), int2_(9, 12), int2_(16, 20), int2_(25, 20)) + ); + + // scan_on_cpu + + // make sure parallel scan_on_cpu is used, no serial_scan + std::string cache_key = + "__boost_scan_cpu_8"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_scan_threshold", 0); + // force parallel scan_on_cpu + parameters->set(cache_key, "serial_scan_threshold", 0); + + boost::compute::inclusive_scan(input.begin(), input.end(), output.begin(), + queue); + CHECK_RANGE_EQUAL( + int2_, 5, output, + (int2_(1, 2), int2_(4, 6), int2_(9, 12), int2_(16, 20), int2_(25, 20)) + ); + + // restore + parameters->set(cache_key, "serial_scan_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_counting_iterator) +{ + using boost::compute::int_; + using boost::compute::uint_; + + bc::vector<int_> result(10, context); + bc::inclusive_scan(bc::make_counting_iterator(1), + bc::make_counting_iterator(11), + result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 10, result, (1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // scan_on_cpu + + // make sure parallel scan_on_cpu is used, no serial_scan + std::string cache_key = + "__boost_scan_cpu_4"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_scan_threshold", 0); + // force parallel scan_on_cpu + parameters->set(cache_key, "serial_scan_threshold", 0); + + bc::inclusive_scan(bc::make_counting_iterator(1), + bc::make_counting_iterator(11), + result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 10, result, (1, 3, 6, 10, 15, 21, 28, 36, 45, 55)); + + // restore + parameters->set(cache_key, "serial_scan_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_counting_iterator) +{ + using boost::compute::int_; + using boost::compute::uint_; + + bc::vector<int_> result(10, context); + bc::exclusive_scan(bc::make_counting_iterator(1), + bc::make_counting_iterator(11), + result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 10, result, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45)); + + // scan_on_cpu + + // make sure parallel scan_on_cpu is used, no serial_scan + std::string cache_key = + "__boost_scan_cpu_4"; + boost::shared_ptr<bc::detail::parameter_cache> parameters = + bc::detail::parameter_cache::get_global_cache(device); + + // save + uint_ map_copy_threshold = + parameters->get(cache_key, "serial_scan_threshold", 0); + // force parallel scan_on_cpu + parameters->set(cache_key, "serial_scan_threshold", 0); + + bc::exclusive_scan(bc::make_counting_iterator(1), + bc::make_counting_iterator(11), + result.begin(), queue); + CHECK_RANGE_EQUAL(int_, 10, result, (0, 1, 3, 6, 10, 15, 21, 28, 36, 45)); + + // restore + parameters->set(cache_key, "serial_scan_threshold", map_copy_threshold); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_transform_iterator) +{ + float data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + bc::vector<float> input(data, data + 5, queue); + bc::vector<float> output(5, context); + + // normal inclusive scan of the input + bc::inclusive_scan(input.begin(), input.end(), output.begin(), queue); + queue.finish(); + BOOST_CHECK_CLOSE(float(output[0]), 1.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[1]), 3.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[2]), 6.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[3]), 10.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[4]), 15.0f, 1e-4f); + + // inclusive scan of squares of the input + using ::boost::compute::_1; + + bc::inclusive_scan(bc::make_transform_iterator(input.begin(), pown(_1, 2)), + bc::make_transform_iterator(input.end(), pown(_1, 2)), + output.begin(), queue); + queue.finish(); + BOOST_CHECK_CLOSE(float(output[0]), 1.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[1]), 5.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[2]), 14.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[3]), 30.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(output[4]), 55.0f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_doctest) +{ +//! [inclusive_scan_int] +// setup input +int data[] = { 1, 2, 3, 4 }; +boost::compute::vector<int> input(data, data + 4, queue); + +// setup output +boost::compute::vector<int> output(4, context); + +// scan values +boost::compute::inclusive_scan( + input.begin(), input.end(), output.begin(), queue +); + +// output = [ 1, 3, 6, 10 ] +//! [inclusive_scan_int] + + CHECK_RANGE_EQUAL(int, 4, output, (1, 3, 6, 10)); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_doctest) +{ +//! [exclusive_scan_int] +// setup input +int data[] = { 1, 2, 3, 4 }; +boost::compute::vector<int> input(data, data + 4, queue); + +// setup output +boost::compute::vector<int> output(4, context); + +// scan values +boost::compute::exclusive_scan( + input.begin(), input.end(), output.begin(), queue +); + +// output = [ 0, 1, 3, 6 ] +//! [exclusive_scan_int] + + CHECK_RANGE_EQUAL(int, 4, output, (0, 1, 3, 6)); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_int_multiplies) +{ +//! [inclusive_scan_int_multiplies] +// setup input +int data[] = { 1, 2, 1, 2, 3 }; +boost::compute::vector<int> input(data, data + 5, queue); + +// setup output +boost::compute::vector<int> output(5, context); + +// inclusive scan with multiplication +boost::compute::inclusive_scan( + input.begin(), input.end(), output.begin(), + boost::compute::multiplies<int>(), queue +); + +// output = [1, 2, 2, 4, 12] +//! [inclusive_scan_int_multiplies] + + BOOST_CHECK_EQUAL(input.size(), size_t(5)); + BOOST_CHECK_EQUAL(output.size(), size_t(5)); + + CHECK_RANGE_EQUAL(int, 5, output, (1, 2, 2, 4, 12)); + + // in-place inclusive scan + CHECK_RANGE_EQUAL(int, 5, input, (1, 2, 1, 2, 3)); + boost::compute::inclusive_scan(input.begin(), input.end(), input.begin(), + boost::compute::multiplies<int>(), queue); + CHECK_RANGE_EQUAL(int, 5, input, (1, 2, 2, 4, 12)); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_int_multiplies) +{ +//! [exclusive_scan_int_multiplies] +// setup input +int data[] = { 1, 2, 1, 2, 3 }; +boost::compute::vector<int> input(data, data + 5, queue); + +// setup output +boost::compute::vector<int> output(5, context); + +// exclusive_scan with multiplication +// initial value equals 10 +boost::compute::exclusive_scan( + input.begin(), input.end(), output.begin(), + int(10), boost::compute::multiplies<int>(), queue +); + +// output = [10, 10, 20, 20, 40] +//! [exclusive_scan_int_multiplies] + + BOOST_CHECK_EQUAL(input.size(), size_t(5)); + BOOST_CHECK_EQUAL(output.size(), size_t(5)); + + CHECK_RANGE_EQUAL(int, 5, output, (10, 10, 20, 20, 40)); + + // in-place exclusive scan + CHECK_RANGE_EQUAL(int, 5, input, (1, 2, 1, 2, 3)); + bc::exclusive_scan(input.begin(), input.end(), input.begin(), + int(10), bc::multiplies<int>(), queue); + CHECK_RANGE_EQUAL(int, 5, input, (10, 10, 20, 20, 40)); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_int_multiplies_long_vector) +{ + size_t size = 1000; + bc::vector<int> device_vector(size, int(2), queue); + BOOST_CHECK_EQUAL(device_vector.size(), size); + bc::inclusive_scan(device_vector.begin(), device_vector.end(), + device_vector.begin(), bc::multiplies<int>(), queue); + + std::vector<int> host_vector(size, 2); + BOOST_CHECK_EQUAL(host_vector.size(), size); + bc::copy(device_vector.begin(), device_vector.end(), + host_vector.begin(), queue); + + std::vector<int> test(size, 2); + BOOST_CHECK_EQUAL(test.size(), size); + std::partial_sum(test.begin(), test.end(), + test.begin(), std::multiplies<int>()); + + BOOST_CHECK_EQUAL_COLLECTIONS(host_vector.begin(), host_vector.end(), + test.begin(), test.end()); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_int_multiplies_long_vector) +{ + size_t size = 1000; + bc::vector<int> device_vector(size, int(2), queue); + BOOST_CHECK_EQUAL(device_vector.size(), size); + bc::exclusive_scan(device_vector.begin(), device_vector.end(), + device_vector.begin(), int(10), bc::multiplies<int>(), + queue); + + std::vector<int> host_vector(size, 2); + BOOST_CHECK_EQUAL(host_vector.size(), size); + bc::copy(device_vector.begin(), device_vector.end(), + host_vector.begin(), queue); + + std::vector<int> test(size, 2); + BOOST_CHECK_EQUAL(test.size(), size); + test[0] = 10; + std::partial_sum(test.begin(), test.end(), + test.begin(), std::multiplies<int>()); + + BOOST_CHECK_EQUAL_COLLECTIONS(host_vector.begin(), host_vector.end(), + test.begin(), test.end()); +} + +BOOST_AUTO_TEST_CASE(inclusive_scan_int_custom_function) +{ + BOOST_COMPUTE_FUNCTION(int, multi, (int x, int y), + { + return x * y * 2; + }); + + int data[] = { 1, 2, 1, 2, 3 }; + bc::vector<int> vector(data, data + 5, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(5)); + + bc::vector<int> result(5, context); + BOOST_CHECK_EQUAL(result.size(), size_t(5)); + + // inclusive scan + bc::inclusive_scan(vector.begin(), vector.end(), result.begin(), + multi, queue); + CHECK_RANGE_EQUAL(int, 5, result, (1, 4, 8, 32, 192)); + + // in-place inclusive scan + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 1, 2, 3)); + bc::inclusive_scan(vector.begin(), vector.end(), vector.begin(), + multi, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 4, 8, 32, 192)); +} + +BOOST_AUTO_TEST_CASE(exclusive_scan_int_custom_function) +{ + BOOST_COMPUTE_FUNCTION(int, multi, (int x, int y), + { + return x * y * 2; + }); + + int data[] = { 1, 2, 1, 2, 3 }; + bc::vector<int> vector(data, data + 5, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(5)); + + bc::vector<int> result(5, context); + BOOST_CHECK_EQUAL(result.size(), size_t(5)); + + // exclusive_scan + bc::exclusive_scan(vector.begin(), vector.end(), result.begin(), + int(1), multi, queue); + CHECK_RANGE_EQUAL(int, 5, result, (1, 2, 8, 16, 64)); + + // in-place exclusive scan + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 1, 2, 3)); + bc::exclusive_scan(vector.begin(), vector.end(), vector.begin(), + int(1), multi, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 8, 16, 64)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_scatter.cpp b/src/boost/libs/compute/test/test_scatter.cpp new file mode 100644 index 00000000..00c74b22 --- /dev/null +++ b/src/boost/libs/compute/test/test_scatter.cpp @@ -0,0 +1,57 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestScatter +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/scatter.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_buffer_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(scatter_int) +{ + int input_data[] = { 1, 2, 3, 4, 5 }; + bc::vector<int> input(input_data, input_data + 5, queue); + + int map_data[] = { 0, 4, 1, 3, 2 }; + bc::vector<int> map(map_data, map_data + 5, queue); + + bc::vector<int> output(5, context); + bc::scatter(input.begin(), input.end(), map.begin(), output.begin(), queue); + CHECK_RANGE_EQUAL(int, 5, output, (1, 3, 5, 4, 2)); +} + +BOOST_AUTO_TEST_CASE(scatter_constant_indices) +{ + int input_data[] = { 1, 2, 3, 4, 5 }; + bc::vector<int> input(input_data, input_data + 5, queue); + + int map_data[] = { 0, 4, 1, 3, 2 }; + bc::buffer map_buffer(context, + 5 * sizeof(int), + bc::buffer::read_only | bc::buffer::use_host_ptr, + map_data); + + bc::vector<int> output(5, context); + bc::scatter(input.begin(), + input.end(), + bc::make_constant_buffer_iterator<int>(map_buffer, 0), + output.begin(), + queue); + CHECK_RANGE_EQUAL(int, 5, output, (1, 3, 5, 4, 2)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_scatter_if.cpp b/src/boost/libs/compute/test/test_scatter_if.cpp new file mode 100644 index 00000000..1233f8c8 --- /dev/null +++ b/src/boost/libs/compute/test/test_scatter_if.cpp @@ -0,0 +1,141 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2015 Jakub Pola <jakub.pola@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestScatterIf +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/scatter_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_buffer_iterator.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> +#include <boost/compute/functional.hpp> +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(scatter_if_int) +{ + int input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + bc::vector<int> input(input_data, input_data + 10, queue); + + int map_data[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + bc::vector<int> map(map_data, map_data + 10, queue); + + int stencil_data[] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + + bc::vector<bc::uint_> stencil(stencil_data, stencil_data + 10, queue); + + bc::vector<int> output(input.size(), -1, queue); + + bc::scatter_if(input.begin(), input.end(), + map.begin(), stencil.begin(), + output.begin(), + queue); + + CHECK_RANGE_EQUAL(int, 10, output, (9, -1, 7, -1, 5, -1, 3, -1, 1, -1) ); +} + +BOOST_AUTO_TEST_CASE(scatter_if_constant_indices) +{ + int input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + bc::vector<int> input(input_data, input_data + 10, queue); + + int map_data[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + bc::buffer map_buffer(context, + 10 * sizeof(int), + bc::buffer::read_only | bc::buffer::use_host_ptr, + map_data); + + int stencil_data[] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + bc::buffer stencil_buffer(context, + 10 * sizeof(bc::uint_), + bc::buffer::read_only | bc::buffer::use_host_ptr, + stencil_data); + + bc::vector<int> output(input.size(), -1, queue); + + bc::scatter_if(input.begin(), + input.end(), + bc::make_constant_buffer_iterator<int>(map_buffer, 0), + bc::make_constant_buffer_iterator<int>(stencil_buffer, 0), + output.begin(), + queue); + + CHECK_RANGE_EQUAL(int, 10, output, (9, -1, 7, -1, 5, -1, 3, -1, 1, -1) ); +} + + +BOOST_AUTO_TEST_CASE(scatter_if_function) +{ + int input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + bc::vector<int> input(input_data, input_data + 10, queue); + + int map_data[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + bc::vector<int> map(map_data, map_data + 10, queue); + + int stencil_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + bc::vector<bc::uint_> stencil(stencil_data, stencil_data + 10, queue); + + bc::vector<int> output(input.size(), -1, queue); + + BOOST_COMPUTE_FUNCTION(int, gt_than_5, (int x), + { + if (x > 5) + return true; + else + return false; + }); + + bc::scatter_if(input.begin(), + input.end(), + map.begin(), + stencil.begin(), + output.begin(), + gt_than_5, + queue); + + CHECK_RANGE_EQUAL(int, 10, output, (9, 8, 7, 6, -1, -1, -1, -1, -1, -1) ); +} + + +BOOST_AUTO_TEST_CASE(scatter_if_counting_iterator) +{ + int input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + bc::vector<int> input(input_data, input_data + 10, queue); + + int map_data[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + bc::vector<int> map(map_data, map_data + 10, queue); + + bc::vector<int> output(input.size(), -1, queue); + + BOOST_COMPUTE_FUNCTION(int, gt_than_5, (int x), + { + if (x > 5) + return true; + else + return false; + }); + + bc::scatter_if(input.begin(), + input.end(), + map.begin(), + bc::make_counting_iterator<int>(0), + output.begin(), + gt_than_5, + queue); + + CHECK_RANGE_EQUAL(int, 10, output, (9, 8, 7, 6, -1, -1, -1, -1, -1, -1) ); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_search.cpp b/src/boost/libs/compute/test/test_search.cpp new file mode 100644 index 00000000..51943625 --- /dev/null +++ b/src/boost/libs/compute/test/test_search.cpp @@ -0,0 +1,72 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSearch +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/search.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(search_int) +{ + int data[] = {1, 4, 2, 6, 3, 2, 6, 3, 4, 6, 6}; + bc::vector<bc::int_> vectort(data, data + 11, queue); + + int datap[] = {2, 6}; + bc::vector<bc::int_> vectorp(datap, datap + 2, queue); + + bc::vector<bc::int_>::iterator iter = + bc::search(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.begin() + 2); + + vectorp[1] = 9; + + iter = + bc::search(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.begin() + 11); + + vectorp[0] = 6; + vectorp[1] = 6; + + iter = + bc::search(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.begin() + 9); +} + +BOOST_AUTO_TEST_CASE(search_string) +{ + char text[] = "sdabababacabskjabacab"; + bc::vector<bc::char_> vectort(text, text + 21, queue); + + char pattern[] = "aba"; + bc::vector<bc::char_> vectorp(pattern, pattern + 3, queue); + + bc::vector<bc::char_>::iterator iter = + bc::search(vectort.begin(), vectort.end(), + vectorp.begin(), vectorp.end(), queue); + + BOOST_CHECK(iter == vectort.begin() + 2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_search_n.cpp b/src/boost/libs/compute/test/test_search_n.cpp new file mode 100644 index 00000000..c8b5af07 --- /dev/null +++ b/src/boost/libs/compute/test/test_search_n.cpp @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSearchN +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/search_n.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(search_int) +{ + int data[] = {1, 2, 2, 2, 3, 2, 2, 2, 4, 6, 6}; + bc::vector<bc::int_> vectort(data, data + 11, queue); + + bc::vector<bc::int_>::iterator iter = + bc::search_n(vectort.begin(), vectort.end(), 3, 2, queue); + + BOOST_CHECK(iter == vectort.begin() + 1); + + iter = + bc::search_n(vectort.begin(), vectort.end(), 5, 2, queue); + + BOOST_CHECK(iter == vectort.begin() + 11); + + iter = + bc::search_n(vectort.begin(), vectort.end(), 2, 6, queue); + + BOOST_CHECK(iter == vectort.begin() + 9); +} + +BOOST_AUTO_TEST_CASE(search_string) +{ + char text[] = "asaaababaaca"; + bc::vector<bc::char_> vectort(text, text + 12, queue); + + bc::vector<bc::char_>::iterator iter = + bc::search_n(vectort.begin(), vectort.end(), 2, 'a', queue); + + BOOST_CHECK(iter == vectort.begin() + 2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_set_difference.cpp b/src/boost/libs/compute/test/test_set_difference.cpp new file mode 100644 index 00000000..d6ecb0a3 --- /dev/null +++ b/src/boost/libs/compute/test/test_set_difference.cpp @@ -0,0 +1,62 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSetDifference +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/set_difference.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(set_difference_int) +{ + int dataset1[] = {1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 10}; + bc::vector<bc::int_> set1(dataset1, dataset1 + 12, queue); + + int dataset2[] = {0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 13}; + bc::vector<bc::int_> set2(dataset2, dataset2 + 12, queue); + + bc::vector<bc::uint_>result(7, queue.get_context()); + + bc::vector<bc::uint_>::iterator iter = + bc::set_difference(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 12, + result.begin(), queue); + + CHECK_RANGE_EQUAL(int, 7, result, (1, 1, 2, 2, 3, 3, 10)); + BOOST_VERIFY(iter == result.begin()+7); +} + +BOOST_AUTO_TEST_CASE(set_difference_string) +{ + char string1[] = "abcccdddeeff"; + bc::vector<bc::char_> set1(string1, string1 + 12, queue); + + char string2[] = "bccdfgh"; + bc::vector<bc::char_> set2(string2, string2 + 7, queue); + + bc::vector<bc::char_>result(7, queue.get_context()); + + bc::vector<bc::char_>::iterator iter = + bc::set_difference(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 7, + result.begin(), queue); + + CHECK_RANGE_EQUAL(char, 7, result, ('a', 'c', 'd', 'd', 'e', 'e', 'f')); + BOOST_VERIFY(iter == result.begin()+7); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_set_intersection.cpp b/src/boost/libs/compute/test/test_set_intersection.cpp new file mode 100644 index 00000000..b33007b7 --- /dev/null +++ b/src/boost/libs/compute/test/test_set_intersection.cpp @@ -0,0 +1,62 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSetIntersection +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/set_intersection.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(set_intersection_int) +{ + int dataset1[] = {1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 10}; + bc::vector<bc::int_> set1(dataset1, dataset1 + 12, queue); + + int dataset2[] = {0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 13}; + bc::vector<bc::int_> set2(dataset2, dataset2 + 12, queue); + + bc::vector<bc::uint_>result(10, queue.get_context()); + + bc::vector<bc::uint_>::iterator iter = + bc::set_intersection(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 12, + result.begin(), queue); + + CHECK_RANGE_EQUAL(int, 5, result, (2, 2, 4, 5, 6)); + BOOST_VERIFY(iter == result.begin()+5); +} + +BOOST_AUTO_TEST_CASE(set_intersection_string) +{ + char string1[] = "abcccdddeeff"; + bc::vector<bc::char_> set1(string1, string1 + 12, queue); + + char string2[] = "bccdfgh"; + bc::vector<bc::char_> set2(string2, string2 + 7, queue); + + bc::vector<bc::char_>result(5, queue.get_context()); + + bc::vector<bc::char_>::iterator iter = + bc::set_intersection(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 7, + result.begin(), queue); + + CHECK_RANGE_EQUAL(char, 5, result, ('b', 'c', 'c', 'd', 'f')); + BOOST_VERIFY(iter == result.begin()+5); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_set_symmetric_difference.cpp b/src/boost/libs/compute/test/test_set_symmetric_difference.cpp new file mode 100644 index 00000000..f90a34b2 --- /dev/null +++ b/src/boost/libs/compute/test/test_set_symmetric_difference.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSetSymmetricDifference +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/set_symmetric_difference.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(set_symmetric_difference_int) +{ + int dataset1[] = {1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 10}; + bc::vector<bc::int_> set1(dataset1, dataset1 + 12, queue); + + int dataset2[] = {0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 13}; + bc::vector<bc::int_> set2(dataset2, dataset2 + 12, queue); + + bc::vector<bc::uint_>result(14, queue.get_context()); + + bc::vector<bc::uint_>::iterator iter = + bc::set_symmetric_difference(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 12, + result.begin(), queue); + + CHECK_RANGE_EQUAL(int, 14, result, (0, 1, 1, 2, 2, 3, 3, 8, + 8, 9, 9, 9, 10, 13)); + BOOST_VERIFY(iter == result.begin()+14); +} + +BOOST_AUTO_TEST_CASE(set_symmetric_difference_string) +{ + char string1[] = "abcccdddeeff"; + bc::vector<bc::char_> set1(string1, string1 + 12, queue); + + char string2[] = "bccdfgh"; + bc::vector<bc::char_> set2(string2, string2 + 7, queue); + + bc::vector<bc::char_>result(9, queue.get_context()); + + bc::vector<bc::char_>::iterator iter = + bc::set_symmetric_difference(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 7, + result.begin(), queue); + + CHECK_RANGE_EQUAL(char, 9, result, ('a', 'c', 'd', 'd', 'e', 'e', 'f', 'g', 'h')); + BOOST_VERIFY(iter == result.begin()+9); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_set_union.cpp b/src/boost/libs/compute/test/test_set_union.cpp new file mode 100644 index 00000000..f3c6dedb --- /dev/null +++ b/src/boost/libs/compute/test/test_set_union.cpp @@ -0,0 +1,64 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSetUnion +#include <boost/test/unit_test.hpp> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/set_union.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(set_union_int) +{ + int dataset1[] = {1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 6, 10}; + bc::vector<bc::int_> set1(dataset1, dataset1 + 12, queue); + + int dataset2[] = {0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 13}; + bc::vector<bc::int_> set2(dataset2, dataset2 + 12, queue); + + bc::vector<bc::uint_>result(19, queue.get_context()); + + bc::vector<bc::uint_>::iterator iter = + bc::set_union(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 12, + result.begin(), queue); + + CHECK_RANGE_EQUAL(int, 19, result, (0, 1, 1, 2, 2, 2, 2, 3, 3, 4, + 5, 6, 8, 8, 9, 9, 9, 10, 13)); + BOOST_VERIFY(iter == result.begin()+19); +} + +BOOST_AUTO_TEST_CASE(set_union_string) +{ + char string1[] = "abcccdddeeff"; + bc::vector<bc::char_> set1(string1, string1 + 12, queue); + + char string2[] = "bccdfgh"; + bc::vector<bc::char_> set2(string2, string2 + 7, queue); + + bc::vector<bc::char_>result(14, queue.get_context()); + + bc::vector<bc::char_>::iterator iter = + bc::set_union(set1.begin(), set1.begin() + 12, + set2.begin(), set2.begin() + 7, + result.begin(), queue); + + CHECK_RANGE_EQUAL(char, 14, result, ('a', 'b', 'c', 'c', 'c', 'd', 'd', 'd', + 'e', 'e', 'f', 'f', 'g', 'h')); + BOOST_VERIFY(iter == result.begin()+14); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_sort.cpp b/src/boost/libs/compute/test/test_sort.cpp new file mode 100644 index 00000000..3b3a76f7 --- /dev/null +++ b/src/boost/libs/compute/test/test_sort.cpp @@ -0,0 +1,367 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSort +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/struct.hpp> + +struct Particle +{ + Particle(): x(0.f), y(0.f) { } + Particle(float _x, float _y): x(_x), y(_y) { } + + float x; + float y; +}; + +// adapt struct for OpenCL +BOOST_COMPUTE_ADAPT_STRUCT(Particle, Particle, (x, y)) + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +// test trivial sorting of zero and one element vectors +BOOST_AUTO_TEST_CASE(sort_int_0_and_1) +{ + boost::compute::vector<int> vec(context); + BOOST_CHECK_EQUAL(vec.size(), size_t(0)); + BOOST_CHECK(boost::compute::is_sorted(vec.begin(), vec.end(), queue) == true); + boost::compute::sort(vec.begin(), vec.end(), queue); + + vec.push_back(11, queue); + BOOST_CHECK_EQUAL(vec.size(), size_t(1)); + BOOST_CHECK(boost::compute::is_sorted(vec.begin(), vec.end(), queue) == true); + boost::compute::sort(vec.begin(), vec.end(), queue); +} + +// test sorting of two element int vectors +BOOST_AUTO_TEST_CASE(sort_int_2) +{ + int data[] = { 4, 2 }; + boost::compute::vector<int> vec(data, data + 2, queue); + + // check that vec is unsorted + BOOST_CHECK(boost::compute::is_sorted(vec.begin(), vec.end(), queue) == false); + + // sort vec + boost::compute::sort(vec.begin(), vec.end(), queue); + + // check that vec is sorted + BOOST_CHECK(boost::compute::is_sorted(vec.begin(), vec.end(), queue) == true); + + // sort already sorted vec and ensure it is still sorted + boost::compute::sort(vec.begin(), vec.end()); + BOOST_CHECK(boost::compute::is_sorted(vec.begin(), vec.end(), queue) == true); +} + +BOOST_AUTO_TEST_CASE(sort_float_3) +{ + float data[] = { 2.3f, 0.1f, 1.2f }; + boost::compute::vector<float> vec(data, data + 3, queue); + boost::compute::sort(vec.begin(), vec.end(), queue); + CHECK_RANGE_EQUAL(float, 3, vec, (0.1f, 1.2f, 2.3f)); +} + +BOOST_AUTO_TEST_CASE(sort_char_vector) +{ + using boost::compute::char_; + + char_ data[] = { 'c', 'a', '0', '7', 'B', 'F', '\0', '$' }; + boost::compute::vector<char_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(char_, 8, vector, ('\0', '$', '0', '7', 'B', 'F', 'a', 'c')); +} + +BOOST_AUTO_TEST_CASE(sort_uchar_vector) +{ + using boost::compute::uchar_; + + uchar_ data[] = { 0x12, 0x00, 0xFF, 0xB4, 0x80, 0x32, 0x64, 0xA2 }; + boost::compute::vector<uchar_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uchar_, 8, vector, (0x00, 0x12, 0x32, 0x64, 0x80, 0xA2, 0xB4, 0xFF)); +} + +BOOST_AUTO_TEST_CASE(sort_short_vector) +{ + using boost::compute::short_; + + short_ data[] = { -4, 152, -94, 963, 31002, -456, 0, -2113 }; + boost::compute::vector<short_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(short_, 8, vector, (-2113, -456, -94, -4, 0, 152, 963, 31002)); +} + +BOOST_AUTO_TEST_CASE(sort_ushort_vector) +{ + using boost::compute::ushort_; + + ushort_ data[] = { 4, 152, 94, 963, 63202, 34560, 0, 2113 }; + boost::compute::vector<ushort_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ushort_, 8, vector, (0, 4, 94, 152, 963, 2113, 34560, 63202)); +} + +BOOST_AUTO_TEST_CASE(sort_int_vector) +{ + int data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + boost::compute::vector<int> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(int, 8, vector, (-5000, -456, -4, 0, 152, 963, 1112, 75321)); +} + +BOOST_AUTO_TEST_CASE(sort_uint_vector) +{ + using boost::compute::uint_; + + uint_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<uint_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(uint_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_long_vector) +{ + using boost::compute::long_; + + long_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<long_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(long_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_ulong_vector) +{ + using boost::compute::ulong_; + + ulong_ data[] = { 500, 1988, 123456, 562, 0, 4000000, 9852, 102030 }; + boost::compute::vector<ulong_> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(ulong_, 8, vector, (0, 500, 562, 1988, 9852, 102030, 123456, 4000000)); +} + +BOOST_AUTO_TEST_CASE(sort_float_vector) +{ + float data[] = { -6023.0f, 152.5f, -63.0f, 1234567.0f, 11.2f, + -5000.1f, 0.0f, 14.0f, -8.25f, -0.0f }; + boost::compute::vector<float> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + float, 10, vector, + (-6023.0f, -5000.1f, -63.0f, -8.25f, -0.0f, 0.0f, 11.2f, 14.0f, 152.5f, 1234567.0f) + ); +} + +BOOST_AUTO_TEST_CASE(sort_double_vector) +{ + if(!device.supports_extension("cl_khr_fp64")){ + std::cout << "skipping test: device does not support double" << std::endl; + return; + } + + double data[] = { -6023.0, 152.5, -63.0, 1234567.0, 11.2, + -5000.1, 0.0, 14.0, -8.25, -0.0 }; + boost::compute::vector<double> vector(data, data + 10, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(10)); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + boost::compute::sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(boost::compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL( + double, 10, vector, + (-6023.0, -5000.1, -63.0, -8.25, -0.0, 0.0, 11.2, 14.0, 152.5, 1234567.0) + ); + +} + +BOOST_AUTO_TEST_CASE(reverse_sort_int_vector) +{ + int data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + boost::compute::vector<int> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + + boost::compute::sort(vector.begin(), vector.end(), + boost::compute::greater<int>(), queue); + CHECK_RANGE_EQUAL(int, 8, vector, (75321, 1112, 963, 152, 0, -4, -456, -5000)); +} + +BOOST_AUTO_TEST_CASE(sort_vectors_by_length) +{ + using boost::compute::float2_; + using boost::compute::lambda::_1; + using boost::compute::lambda::_2; + + float data[] = { 1.0f, 0.2f, + 1.3f, 1.0f, + 6.7f, 0.0f, + 5.2f, 3.4f, + 1.4f, 1.4f }; + + // create vector on device containing vectors + boost::compute::vector<float2_> vector( + reinterpret_cast<float2_ *>(data), + reinterpret_cast<float2_ *>(data) + 5, + queue + ); + + // sort vectors by length + boost::compute::sort( + vector.begin(), + vector.end(), + length(_1) < length(_2), + queue + ); + + // copy sorted values back to host + boost::compute::copy( + vector.begin(), + vector.end(), + reinterpret_cast<float2_ *>(data), + queue + ); + + // check values + BOOST_CHECK_EQUAL(data[0], 1.0f); + BOOST_CHECK_EQUAL(data[1], 0.2f); + BOOST_CHECK_EQUAL(data[2], 1.3f); + BOOST_CHECK_EQUAL(data[3], 1.0f); + BOOST_CHECK_EQUAL(data[4], 1.4f); + BOOST_CHECK_EQUAL(data[5], 1.4f); + BOOST_CHECK_EQUAL(data[6], 5.2f); + BOOST_CHECK_EQUAL(data[7], 3.4f); + BOOST_CHECK_EQUAL(data[8], 6.7f); + BOOST_CHECK_EQUAL(data[9], 0.0f); +} + +BOOST_AUTO_TEST_CASE(sort_host_vector) +{ + int data[] = { 5, 2, 3, 6, 7, 4, 0, 1 }; + std::vector<int> vector(data, data + 8); + boost::compute::sort(vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(int, 8, vector, (0, 1, 2, 3, 4, 5, 6, 7)); +} + +BOOST_AUTO_TEST_CASE(sort_custom_struct) +{ + // function to compare particles by their x-coordinate + BOOST_COMPUTE_FUNCTION(bool, sort_by_x, (Particle a, Particle b), + { + return a.x < b.x; + }); + + std::vector<Particle> particles; + particles.push_back(Particle(0.1f, 0.f)); + particles.push_back(Particle(-0.4f, 0.f)); + particles.push_back(Particle(10.0f, 0.f)); + particles.push_back(Particle(0.001f, 0.f)); + + boost::compute::vector<Particle> vector(4, context); + boost::compute::copy(particles.begin(), particles.end(), vector.begin(), queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(4)); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), + sort_by_x, queue) == false + ); + + boost::compute::sort(vector.begin(), vector.end(), sort_by_x, queue); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), + sort_by_x, queue) == true + ); + boost::compute::copy(vector.begin(), vector.end(), particles.begin(), queue); + BOOST_CHECK_CLOSE(particles[0].x, -0.4f, 0.1); + BOOST_CHECK_CLOSE(particles[1].x, 0.001f, 0.1); + BOOST_CHECK_CLOSE(particles[2].x, 0.1f, 0.1); + BOOST_CHECK_CLOSE(particles[3].x, 10.0f, 0.1); +} + +BOOST_AUTO_TEST_CASE(sort_int2) +{ + using bc::int2_; + + BOOST_COMPUTE_FUNCTION(bool, sort_int2, (int2_ a, int2_ b), + { + return a.x < b.x; + }); + + const size_t size = 100; + std::vector<int2_> host(size, int2_(0, 0)); + host[0] = int2_(100.f, 0.f); + host[size/4] = int2_(20.f, 0.f); + host[(size*3)/4] = int2_(9.f, 0.f); + host[size-3] = int2_(-10.0f, 0.f); + host[size/2+1] = int2_(-10.0f, -1.f); + + boost::compute::vector<int2_> vector(size, context); + boost::compute::copy(host.begin(), host.end(), vector.begin(), queue); + BOOST_CHECK_EQUAL(vector.size(), size); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), + sort_int2, queue) == false + ); + + boost::compute::sort(vector.begin(), vector.end(), sort_int2, queue); + BOOST_CHECK( + boost::compute::is_sorted(vector.begin(), vector.end(), + sort_int2, queue) == true + ); + boost::compute::copy(vector.begin(), vector.end(), host.begin(), queue); + BOOST_CHECK_CLOSE(host[0][0], -10.f, 0.1); + BOOST_CHECK_CLOSE(host[1][0], -10.f, 0.1); + BOOST_CHECK_CLOSE(host[(size - 3)][0], 9.f, 0.1); + BOOST_CHECK_CLOSE(host[(size - 2)][0], 20.f, 0.1); + BOOST_CHECK_CLOSE(host[(size - 1)][0], 100.f, 0.1); + BOOST_CHECK_NE(host[0], host[1]); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_sort_by_key.cpp b/src/boost/libs/compute/test/test_sort_by_key.cpp new file mode 100644 index 00000000..978d81d3 --- /dev/null +++ b/src/boost/libs/compute/test/test_sort_by_key.cpp @@ -0,0 +1,207 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSortByKey +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/sort_by_key.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/struct.hpp> + +struct custom_struct +{ + boost::compute::int_ x; + boost::compute::int_ y; + boost::compute::float2_ zw; +}; + +BOOST_COMPUTE_ADAPT_STRUCT(custom_struct, custom_struct, (x, y, zw)) + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +// test trivial sorting of zero element vectors +BOOST_AUTO_TEST_CASE(sort_int_0) +{ + compute::vector<int> keys(context); + compute::vector<int> values(context); + BOOST_CHECK_EQUAL(keys.size(), size_t(0)); + BOOST_CHECK_EQUAL(values.size(), size_t(0)); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end()) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end()) == true); + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); +} + +// test trivial sorting of one element vectors +BOOST_AUTO_TEST_CASE(sort_int_1) +{ + int keys_data[] = { 11 }; + int values_data[] = { 100 }; + + compute::vector<int> keys(keys_data, keys_data + 1, queue); + compute::vector<int> values(values_data, values_data + 1, queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == true); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); +} + +// test trivial sorting of two element vectors +BOOST_AUTO_TEST_CASE(sort_int_2) +{ + int keys_data[] = { 4, 2 }; + int values_data[] = { 42, 24 }; + + compute::vector<int> keys(keys_data, keys_data + 2, queue); + compute::vector<int> values(values_data, values_data + 2, queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == false); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == false); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == true); +} + +BOOST_AUTO_TEST_CASE(sort_char_by_int) +{ + int keys_data[] = { 6, 2, 1, 3, 4, 7, 5, 0 }; + compute::char_ values_data[] = { 'g', 'c', 'b', 'd', 'e', 'h', 'f', 'a' }; + + compute::vector<int> keys(keys_data, keys_data + 8, queue); + compute::vector<compute::char_> values(values_data, values_data + 8, queue); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + CHECK_RANGE_EQUAL(int, 8, keys, (0, 1, 2, 3, 4, 5, 6, 7)); + CHECK_RANGE_EQUAL(compute::char_, 8, values, ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')); +} + +BOOST_AUTO_TEST_CASE(sort_int_and_float) +{ + int n = 1024; + std::vector<int> host_keys(n); + std::vector<float> host_values(n); + for(int i = 0; i < n; i++){ + host_keys[i] = n - i; + host_values[i] = (n - i) / 2.f; + } + + compute::vector<int> keys(host_keys.begin(), host_keys.end(), queue); + compute::vector<float> values(host_values.begin(), host_values.end(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == false); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == false); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == true); +} + +BOOST_AUTO_TEST_CASE(sort_int_and_float_custom_comparison_func) +{ + using boost::compute::int_; + using boost::compute::float_; + + int n = 1024; + std::vector<int_> host_keys(n); + std::vector<float_> host_values(n); + for(int i = 0; i < n; i++){ + host_keys[i] = n - i; + host_values[i] = (n - i) / 2.f; + } + + BOOST_COMPUTE_FUNCTION(bool, sort_int, (int_ a, int_ b), + { + return a < b; + }); + + compute::vector<int_> keys(host_keys.begin(), host_keys.end(), queue); + compute::vector<float_> values(host_values.begin(), host_values.end(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), sort_int, queue) == false); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == false); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), sort_int, queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), sort_int, queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue) == true); +} + +BOOST_AUTO_TEST_CASE(sort_int_and_float2) +{ + using boost::compute::int_; + using boost::compute::float2_; + + int n = 1024; + std::vector<int_> host_keys(n); + std::vector<float2_> host_values(n); + for(int i = 0; i < n; i++){ + host_keys[i] = n - i; + host_values[i] = float2_((n - i) / 2.f); + } + + BOOST_COMPUTE_FUNCTION(bool, sort_float2, (float2_ a, float2_ b), + { + return a.x < b.x; + }); + + compute::vector<int_> keys(host_keys.begin(), host_keys.end(), queue); + compute::vector<float2_> values(host_values.begin(), host_values.end(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == false); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), sort_float2, queue) == false); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), sort_float2, queue) == true); +} + +BOOST_AUTO_TEST_CASE(sort_custom_struct_by_int) +{ + using boost::compute::int_; + using boost::compute::float2_; + + int_ n = 1024; + std::vector<int_> host_keys(n); + std::vector<custom_struct> host_values(n); + for(int_ i = 0; i < n; i++){ + host_keys[i] = n - i; + host_values[i].x = n - i; + host_values[i].y = n - i; + host_values[i].zw = float2_((n - i) / 0.5f); + } + + BOOST_COMPUTE_FUNCTION(bool, sort_custom_struct, (custom_struct a, custom_struct b), + { + return a.x < b.x; + }); + + compute::vector<int_> keys(host_keys.begin(), host_keys.end(), queue); + compute::vector<custom_struct> values(host_values.begin(), host_values.end(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == false); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), sort_custom_struct, queue) == false); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue) == true); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), sort_custom_struct, queue) == true); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_sort_by_transform.cpp b/src/boost/libs/compute/test/test_sort_by_transform.cpp new file mode 100644 index 00000000..25076060 --- /dev/null +++ b/src/boost/libs/compute/test/test_sort_by_transform.cpp @@ -0,0 +1,110 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSortByTransform +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/experimental/sort_by_transform.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(sort_int_by_abs) +{ + int data[] = { 1, -2, 4, -3, 0, 5, -8, -9 }; + compute::vector<int> vector(data, data + 8, queue); + + compute::experimental::sort_by_transform( + vector.begin(), + vector.end(), + compute::abs<int>(), + compute::less<int>(), + queue + ); + + CHECK_RANGE_EQUAL(int, 8, vector, (0, 1, -2, -3, 4, 5, -8, -9)); +} + +BOOST_AUTO_TEST_CASE(sort_vectors_by_length) +{ + using compute::float4_; + + float data[] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 1.0f, 0.0f, + 3.0f, 2.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f + }; + + compute::vector<float4_> vector(4, context); + compute::copy_n( + reinterpret_cast<float4_ *>(data), 4, vector.begin(), queue + ); + + compute::experimental::sort_by_transform( + vector.begin(), + vector.end(), + compute::length<float4_>(), + compute::less<float>(), + queue + ); + + std::vector<float4_> host_vector(4); + compute::copy( + vector.begin(), vector.end(), host_vector.begin(), queue + ); + BOOST_CHECK_EQUAL(host_vector[0], float4_(0.0f, 0.0f, 0.5f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[1], float4_(1.0f, 0.0f, 0.0f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[2], float4_(0.0f, 1.0f, 1.0f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[3], float4_(3.0f, 2.0f, 1.0f, 0.0f)); +} + +BOOST_AUTO_TEST_CASE(sort_vectors_by_component) +{ + using compute::float4_; + + float data[] = { + 1.0f, 2.0f, 3.0f, 0.0f, + 9.0f, 8.0f, 7.0f, 0.0f, + 4.0f, 5.0f, 6.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f + }; + + compute::vector<float4_> vector(4, context); + compute::copy_n( + reinterpret_cast<float4_ *>(data), 4, vector.begin(), queue + ); + + // sort by y-component + compute::experimental::sort_by_transform( + vector.begin(), + vector.end(), + compute::get<1>(), + compute::less<float>(), + queue + ); + + std::vector<float4_> host_vector(4); + compute::copy( + vector.begin(), vector.end(), host_vector.begin(), queue + ); + BOOST_CHECK_EQUAL(host_vector[0], float4_(0.0f, 0.0f, 0.0f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[1], float4_(1.0f, 2.0f, 3.0f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[2], float4_(4.0f, 5.0f, 6.0f, 0.0f)); + BOOST_CHECK_EQUAL(host_vector[3], float4_(9.0f, 8.0f, 7.0f, 0.0f)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_stable_partition.cpp b/src/boost/libs/compute/test/test_stable_partition.cpp new file mode 100644 index 00000000..08f1fc23 --- /dev/null +++ b/src/boost/libs/compute/test/test_stable_partition.cpp @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestStablePartition +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/stable_partition.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(partition_int) +{ + int dataset[] = {1, 1, -2, 0, 5, -1, 2, 4, 0, -1}; + bc::vector<bc::int_> vector(dataset, dataset + 10, queue); + + bc::vector<bc::int_>::iterator iter = + bc::stable_partition(vector.begin(), vector.begin() + 10, + bc::_1 > 0, queue); + + CHECK_RANGE_EQUAL(int, 10, vector, (1, 1, 5, 2, 4, -2, 0, -1, 0, -1)); + BOOST_VERIFY(iter == vector.begin()+5); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_stable_sort.cpp b/src/boost/libs/compute/test/test_stable_sort.cpp new file mode 100644 index 00000000..d0c573c7 --- /dev/null +++ b/src/boost/libs/compute/test/test_stable_sort.cpp @@ -0,0 +1,92 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestStableSort +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/stable_sort.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(sort_int_vector) +{ + int data[] = { -4, 152, -5000, 963, 75321, -456, 0, 1112 }; + compute::vector<int> vector(data, data + 8, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(8)); + BOOST_CHECK(compute::is_sorted(vector.begin(), vector.end(), queue) == false); + + compute::stable_sort(vector.begin(), vector.end(), queue); + BOOST_CHECK(compute::is_sorted(vector.begin(), vector.end(), queue) == true); + CHECK_RANGE_EQUAL(int, 8, vector, (-5000, -456, -4, 0, 152, 963, 1112, 75321)); + + // sort reversed + compute::stable_sort(vector.begin(), vector.end(), compute::greater<int>(), queue); + CHECK_RANGE_EQUAL(int, 8, vector, (75321, 1112, 963, 152, 0, -4, -456, -5000)); +} + +BOOST_AUTO_TEST_CASE(sort_int2) +{ + using compute::int2_; + + // device vector of int2's + compute::vector<int2_> vec(context); + vec.push_back(int2_(2, 1), queue); + vec.push_back(int2_(2, 2), queue); + vec.push_back(int2_(1, 2), queue); + vec.push_back(int2_(1, 1), queue); + + // function comparing the first component of each int2 + BOOST_COMPUTE_FUNCTION(bool, compare_first, (int2_ a, int2_ b), + { + return a.x < b.x; + }); + + // ensure vector is not sorted + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), compare_first, queue) == false); + + // sort elements based on their first component + compute::stable_sort(vec.begin(), vec.end(), compare_first, queue); + + // ensure vector is now sorted + BOOST_CHECK(compute::is_sorted(vec.begin(), vec.end(), compare_first, queue) == true); + + // check sorted vector order + std::vector<int2_> result(vec.size()); + compute::copy(vec.begin(), vec.end(), result.begin(), queue); + BOOST_CHECK_EQUAL(result[0], int2_(1, 2)); + BOOST_CHECK_EQUAL(result[1], int2_(1, 1)); + BOOST_CHECK_EQUAL(result[2], int2_(2, 1)); + BOOST_CHECK_EQUAL(result[3], int2_(2, 2)); + + // function comparing the second component of each int2 + BOOST_COMPUTE_FUNCTION(bool, compare_second, (int2_ a, int2_ b), + { + return a.y < b.y; + }); + + // sort elements based on their second component + compute::stable_sort(vec.begin(), vec.end(), compare_second, queue); + + // check sorted vector order + compute::copy(vec.begin(), vec.end(), result.begin(), queue); + BOOST_CHECK_EQUAL(result[0], int2_(1, 1)); + BOOST_CHECK_EQUAL(result[1], int2_(2, 1)); + BOOST_CHECK_EQUAL(result[2], int2_(1, 2)); + BOOST_CHECK_EQUAL(result[3], int2_(2, 2)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_stable_sort_by_key.cpp b/src/boost/libs/compute/test/test_stable_sort_by_key.cpp new file mode 100644 index 00000000..0ed7b6a9 --- /dev/null +++ b/src/boost/libs/compute/test/test_stable_sort_by_key.cpp @@ -0,0 +1,206 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2016 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestStableSortByKey +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/stable_sort_by_key.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(empty_int_by_int) +{ + compute::vector<compute::int_> keys(size_t(0), compute::int_(0), queue); + compute::vector<compute::int_> values(size_t(0), compute::int_(0), queue); + + BOOST_CHECK_EQUAL(keys.size(), size_t(0)); + BOOST_CHECK_EQUAL(values.size(), size_t(0)); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue)); + + compute::stable_sort_by_key( + keys.begin(), keys.end(), values.begin(), queue + ); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end())); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end())); +} + +BOOST_AUTO_TEST_CASE(one_element_int_by_int) +{ + compute::int_ keys_data[] = { 1 }; + compute::int_ values_data[] = { 2 }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 1, queue); + compute::vector<compute::int_> values(values_data, values_data + 1, queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue)); + + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + BOOST_CHECK(compute::is_sorted(values.begin(), values.end(), queue)); +} + +BOOST_AUTO_TEST_CASE(two_elements_int_by_int) +{ + compute::int_ keys_data[] = { 1, -1 }; + compute::int_ values_data[] = { -10, 1 }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 2, queue); + compute::vector<compute::int_> values(values_data, values_data + 2, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); +} + +BOOST_AUTO_TEST_CASE(stable_sort_int_by_int) +{ + compute::int_ keys_data[] = { 10, 9, 2, 7, 6, -1, 4, 2, 2, 10 }; + compute::int_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::int_> values(values_data, values_data + 10, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::int_, 10, keys, + (-1, 2, 2, 2, 4, 6, 7, 9, 10, 10) // keys + // ( 6, 3, 8, 9, 7, 5, 4, 2, 1, 10) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 10, values, + // (-1, 2, 2, 2, 4, 6, 7, 9, 10, 10) keys + ( 6, 3, 8, 9, 7, 5, 4, 2, 1, 10) // values + ); +} + +BOOST_AUTO_TEST_CASE(stable_sort_uint_by_uint) +{ + compute::uint_ keys_data[] = { 10, 9, 2, 7, 6, 1, 4, 2, 2, 10 }; + compute::uint_ values_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + compute::vector<compute::uint_> keys(keys_data, keys_data + 10, queue); + compute::vector<compute::uint_> values(values_data, values_data + 10, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::uint_, 10, keys, + (1, 2, 2, 2, 4, 6, 7, 9, 10, 10) // keys + // (6, 3, 8, 9, 7, 5, 4, 2, 1, 10) values + ); + CHECK_RANGE_EQUAL( + compute::uint_, 10, values, + // (1, 2, 2, 2, 4, 6, 7, 9, 10, 10) keys + (6, 3, 8, 9, 7, 5, 4, 2, 1, 10) // values + ); +} + +BOOST_AUTO_TEST_CASE(stable_sort_int_by_float) +{ + compute::float_ keys_data[] = { 10., 5.5, 10., 7., 5.5}; + compute::int_ values_data[] = { 1, 200, -10, 2, 4 }; + + compute::vector<compute::float_> keys(keys_data, keys_data + 5, queue); + compute::vector<compute::uint_> values(values_data, values_data + 5, queue); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), queue)); + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), queue)); + + CHECK_RANGE_EQUAL( + compute::float_, 5, keys, + (5.5, 5.5, 7., 10., 10.) // keys + // (200, 4, 2, 1, -10) values + ); + CHECK_RANGE_EQUAL( + compute::int_, 5, values, + // (5.5, 5.5, 7., 10., 10.) keys + (200, 4, 2, 1, -10) // values + ); +} + +BOOST_AUTO_TEST_CASE(stable_sort_char_by_int) +{ + compute::int_ keys_data[] = { 6, 1, 1, 3, 4, 7, 5, 1 }; + compute::char_ values_data[] = { 'g', 'c', 'b', 'd', 'e', 'h', 'f', 'a' }; + + compute::vector<compute::int_> keys(keys_data, keys_data + 8, queue); + compute::vector<compute::char_> values(values_data, values_data + 8, queue); + + compute::sort_by_key(keys.begin(), keys.end(), values.begin(), queue); + + CHECK_RANGE_EQUAL( + compute::int_, 8, keys, + (1, 1, 1, 3, 4, 5, 6, 7) + ); + CHECK_RANGE_EQUAL( + compute::char_, 8, values, + ('c', 'b', 'a', 'd', 'e', 'f', 'g', 'h') + ); +} + +BOOST_AUTO_TEST_CASE(stable_sort_mid_uint_by_uint) +{ + using boost::compute::int_; + + const int_ size = 128; + std::vector<int_> keys_data(size); + std::vector<int_> values_data(size); + for(int_ i = 0; i < size; i++){ + keys_data[i] = -i; + values_data[i] = -i; + } + + keys_data[size/2] = -256; + keys_data[size - 2] = -256; + keys_data[size - 1] = -256; + values_data[size/2] = 3; + values_data[size - 2] = 1; + values_data[size - 1] = 2; + + compute::vector<int_> keys(keys_data.begin(), keys_data.end(), queue); + compute::vector<int_> values(values_data.begin(), values_data.end(), queue); + + // less function for float + BOOST_COMPUTE_FUNCTION(bool, comp, (int_ a, int_ b), + { + return a < b; + }); + + BOOST_CHECK(!compute::is_sorted(keys.begin(), keys.end(), comp, queue)); + compute::stable_sort_by_key(keys.begin(), keys.end(), values.begin(), comp, queue); + BOOST_CHECK(compute::is_sorted(keys.begin(), keys.end(), comp, queue)); + + BOOST_CHECK(keys.begin().read(queue) == -256); + BOOST_CHECK((keys.begin() + 1).read(queue) == -256); + BOOST_CHECK((keys.begin() + 2).read(queue) == -256); + + BOOST_CHECK(values.begin().read(queue) == 3); + BOOST_CHECK((values.begin() + 1).read(queue) == 1); + BOOST_CHECK((values.begin() + 2).read(queue) == 2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_stack.cpp b/src/boost/libs/compute/test/test_stack.cpp new file mode 100644 index 00000000..fffedcc2 --- /dev/null +++ b/src/boost/libs/compute/test/test_stack.cpp @@ -0,0 +1,50 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestStack +#include <boost/test/unit_test.hpp> + +#include <boost/compute/container/stack.hpp> + +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(size) +{ + bc::stack<int> stack; + BOOST_CHECK_EQUAL(stack.size(), size_t(0)); + + stack.push(1); + stack.push(2); + stack.push(3); + BOOST_CHECK_EQUAL(stack.size(), size_t(3)); +} + +BOOST_AUTO_TEST_CASE(push_and_pop) +{ + bc::stack<int> stack; + stack.push(1); + stack.push(2); + stack.push(3); + + BOOST_CHECK_EQUAL(stack.top(), 3); + BOOST_CHECK_EQUAL(stack.size(), size_t(3)); + stack.pop(); + BOOST_CHECK_EQUAL(stack.top(), 2); + BOOST_CHECK_EQUAL(stack.size(), size_t(2)); + stack.pop(); + BOOST_CHECK_EQUAL(stack.top(), 1); + BOOST_CHECK_EQUAL(stack.size(), size_t(1)); + stack.pop(); + BOOST_CHECK_EQUAL(stack.size(), size_t(0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_strided_iterator.cpp b/src/boost/libs/compute/test/test_strided_iterator.cpp new file mode 100644 index 00000000..e05e8b2e --- /dev/null +++ b/src/boost/libs/compute/test/test_strided_iterator.cpp @@ -0,0 +1,194 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2015 Jakub Szuppe <j.szuppe@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestStridedIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> +#include <boost/compute/iterator/strided_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::strided_iterator< + boost::compute::buffer_iterator<int> + >::value_type, + int + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::strided_iterator< + boost::compute::buffer_iterator<float> + >::value_type, + float + >::value + )); +} + +BOOST_AUTO_TEST_CASE(base_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::strided_iterator< + boost::compute::buffer_iterator<int> + >::base_type, + boost::compute::buffer_iterator<int> + >::value + )); +} + +BOOST_AUTO_TEST_CASE(distance) +{ + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::vector<int> vec(data, data + 8, queue); + + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_strided_iterator(vec.begin(), 1), + boost::compute::make_strided_iterator(vec.end(), 1) + ), + std::ptrdiff_t(8) + ); + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_strided_iterator(vec.begin(), 2), + boost::compute::make_strided_iterator(vec.end(), 2) + ), + std::ptrdiff_t(4) + ); + + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_strided_iterator(vec.begin(), 3), + boost::compute::make_strided_iterator(vec.begin()+6, 3) + ), + std::ptrdiff_t(2) + ); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + boost::compute::int_ data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::vector<boost::compute::int_> vec(data, data + 8, queue); + + boost::compute::vector<boost::compute::int_> result(4, context); + + // copy every other element to result + boost::compute::copy( + boost::compute::make_strided_iterator(vec.begin(), 2), + boost::compute::make_strided_iterator(vec.end(), 2), + result.begin(), + queue + ); + CHECK_RANGE_EQUAL(boost::compute::int_, 4, result, (1, 3, 5, 7)); + + // copy every 3rd element to result + boost::compute::copy( + boost::compute::make_strided_iterator(vec.begin(), 3), + boost::compute::make_strided_iterator(vec.begin()+9, 3), + result.begin(), + queue + ); + CHECK_RANGE_EQUAL(boost::compute::int_, 3, result, (1, 4, 7)); +} + +BOOST_AUTO_TEST_CASE(make_strided_iterator_end) +{ + boost::compute::int_ data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + boost::compute::vector<boost::compute::int_> vec(data, data + 8, queue); + + // stride equals 3 + typedef boost::compute::vector<boost::compute::int_>::iterator IterType; + boost::compute::strided_iterator<IterType> end = + boost::compute::make_strided_iterator_end(vec.begin(), + vec.end(), + 3); + + // end should be vec.begin() + 9 which is one step after last element + // accessible through strided_iterator, i.e. vec.begin()+6 + BOOST_CHECK(boost::compute::make_strided_iterator(vec.begin()+9, 3) == + end); + + // stride equals 2 + end = boost::compute::make_strided_iterator_end(vec.begin(), + vec.end(), + 2); + // end should be vec.end(), because vector size is divisible by 2 + BOOST_CHECK(boost::compute::make_strided_iterator(vec.end(), 2) == end); + + // stride equals 1000 + end = boost::compute::make_strided_iterator_end(vec.begin(), + vec.end(), + 1000); + // end should be vec.begin() + 1000, because stride > vector size + BOOST_CHECK(boost::compute::make_strided_iterator(vec.begin()+1000, 1000) == + end); + + + // test boost::compute::make_strided_iterator_end with copy(..) + + boost::compute::vector<boost::compute::int_> result(4, context); + + // copy every other element to result + boost::compute::copy( + boost::compute::make_strided_iterator(vec.begin()+1, 2), + boost::compute::make_strided_iterator_end(vec.begin()+1, vec.end(), 2), + result.begin(), + queue + ); + CHECK_RANGE_EQUAL(boost::compute::int_, 4, result, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(iterator_tag) +{ + typedef bc::buffer_iterator<bc::float_> i_type; + + BOOST_STATIC_ASSERT(( + boost::is_same< + std::iterator_traits< + i_type + >::iterator_category, + std::iterator_traits< + bc::strided_iterator<i_type> + >::iterator_category + >::value + )); +} + +BOOST_AUTO_TEST_CASE(std_distance) +{ + bc::vector<bc::float_> vec( + size_t(300), + bc::float_(1.1f), + queue + ); + + bc::strided_iterator<bc::buffer_iterator<bc::float_> > begin(vec.begin(), 1); + bc::strided_iterator<bc::buffer_iterator<bc::float_> > end(vec.end(), 1); + + BOOST_CHECK_EQUAL(std::distance(begin, end), 300); + BOOST_CHECK_EQUAL(std::distance(end, begin), -300); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_string.cpp b/src/boost/libs/compute/test/test_string.cpp new file mode 100644 index 00000000..4406df7f --- /dev/null +++ b/src/boost/libs/compute/test/test_string.cpp @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestString +#include <boost/test/unit_test.hpp> + +#include <boost/compute/container/string.hpp> +#include <boost/compute/container/basic_string.hpp> +#include <boost/test/output_test_stream.hpp> + +#include "context_setup.hpp" +#include "check_macros.hpp" + +using boost::test_tools::output_test_stream; + +BOOST_AUTO_TEST_CASE(empty) +{ + boost::compute::string str; + BOOST_VERIFY(str.empty()); +} + +BOOST_AUTO_TEST_CASE(swap) +{ + // boost::compute::string currently uses only default_queue, default_context, + // default_device so this overrides queue variable set in + // BOOST_FIXTURE_TEST_SUITE(compute_test, Context) in context_setup.hpp + // in case it is not the default_queue + boost::compute::command_queue& queue = + boost::compute::system::default_queue(); + + boost::compute::string str1 = "compute"; + boost::compute::string str2 = "boost"; + BOOST_VERIFY(!str2.empty()); + BOOST_VERIFY(!str2.empty()); + str1.swap(str2); + // this macro uses queue variable and it must be default_queue + CHECK_STRING_EQUAL(str1, "boost"); + CHECK_STRING_EQUAL(str2, "compute"); + str1.clear(); + str1.swap(str2); + CHECK_STRING_EQUAL(str1, "compute"); + CHECK_STRING_EQUAL(str2, ""); + str2.swap(str1); + CHECK_STRING_EQUAL(str1, ""); + CHECK_STRING_EQUAL(str2, "compute"); + str1.swap(str1); + CHECK_STRING_EQUAL(str1, ""); +} + +BOOST_AUTO_TEST_CASE(size) +{ + boost::compute::string str = "string"; + BOOST_VERIFY(!str.empty()); + BOOST_CHECK_EQUAL(str.size(), size_t(6)); + BOOST_CHECK_EQUAL(str.length(), size_t(6)); +} + +BOOST_AUTO_TEST_CASE(find_doctest) +{ +//! [string_find] +boost::compute::string str = "boost::compute::string"; +int pos = str.find("::"); +//! [string_find] + boost::compute::string pattern = "string"; + BOOST_VERIFY(!str.empty()); + BOOST_CHECK_EQUAL(str.find('o'), 1); + BOOST_CHECK_NE(str.find('o'), 2); + BOOST_CHECK_EQUAL(str.find(pattern), 16); + BOOST_CHECK_EQUAL(pos, 5); + BOOST_CHECK_EQUAL(str.find("@#$"), size_t(-1)); +} + +BOOST_AUTO_TEST_CASE(outStream) +{ + output_test_stream output; + boost::compute::string str = "string"; + output<<str; + BOOST_CHECK(output.is_equal("string")); + BOOST_VERIFY(!output.is_equal("!@$%")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_struct.cpp b/src/boost/libs/compute/test/test_struct.cpp new file mode 100644 index 00000000..d7a7b650 --- /dev/null +++ b/src/boost/libs/compute/test/test_struct.cpp @@ -0,0 +1,165 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#include <boost/compute/config.hpp> + +#define BOOST_TEST_MODULE TestStruct +#include <boost/test/unit_test.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/find_if.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/field.hpp> +#include <boost/compute/types/struct.hpp> +#include <boost/compute/type_traits/type_name.hpp> +#include <boost/compute/type_traits/type_definition.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// example code defining an atom class +namespace chemistry { + +struct Atom +{ + Atom(float _x, float _y, float _z, int _number) + : x(_x), y(_y), z(_z), number(_number) + { + } + + float x; + float y; + float z; + int number; +}; + +} // end chemistry namespace + +// adapt the chemistry::Atom class +BOOST_COMPUTE_ADAPT_STRUCT(chemistry::Atom, Atom, (x, y, z, number)) + +struct StructWithArray { + int value; + int array[3]; +}; + +BOOST_COMPUTE_ADAPT_STRUCT(StructWithArray, StructWithArray, (value, array)) + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(atom_type_name) +{ + BOOST_CHECK(std::strcmp(compute::type_name<chemistry::Atom>(), "Atom") == 0); +} + +BOOST_AUTO_TEST_CASE(atom_struct) +{ + std::vector<chemistry::Atom> atoms; + atoms.push_back(chemistry::Atom(1.f, 0.f, 0.f, 1)); + atoms.push_back(chemistry::Atom(0.f, 1.f, 0.f, 1)); + atoms.push_back(chemistry::Atom(0.f, 0.f, 0.f, 8)); + + compute::vector<chemistry::Atom> vec(atoms.size(), context); + compute::copy(atoms.begin(), atoms.end(), vec.begin(), queue); + + // find the oxygen atom + BOOST_COMPUTE_FUNCTION(bool, is_oxygen, (chemistry::Atom atom), + { + return atom.number == 8; + }); + + compute::vector<chemistry::Atom>::iterator iter = + compute::find_if(vec.begin(), vec.end(), is_oxygen, queue); + BOOST_CHECK(iter == vec.begin() + 2); + + // copy the atomic numbers to another vector + compute::vector<int> atomic_numbers(vec.size(), context); + compute::transform( + vec.begin(), vec.end(), + atomic_numbers.begin(), + compute::field<int>("number"), + queue + ); + CHECK_RANGE_EQUAL(int, 3, atomic_numbers, (1, 1, 8)); +} + +BOOST_AUTO_TEST_CASE(custom_kernel) +{ + std::vector<chemistry::Atom> data; + data.push_back(chemistry::Atom(1.f, 0.f, 0.f, 1)); + data.push_back(chemistry::Atom(0.f, 1.f, 0.f, 1)); + data.push_back(chemistry::Atom(0.f, 0.f, 0.f, 8)); + + compute::vector<chemistry::Atom> atoms(data.size(), context); + compute::copy(data.begin(), data.end(), atoms.begin(), queue); + + std::string source = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void custom_kernel(__global const Atom *atoms, + __global float *distances) + { + const uint i = get_global_id(0); + const __global Atom *atom = &atoms[i]; + + const float4 center = { 0, 0, 0, 0 }; + const float4 position = { atom->x, atom->y, atom->z, 0 }; + + distances[i] = distance(position, center); + } + ); + + // add type definition for Atom to the start of the program source + source = compute::type_definition<chemistry::Atom>() + "\n" + source; + + compute::program program = + compute::program::build_with_source(source, context); + + compute::vector<float> distances(atoms.size(), context); + + compute::kernel custom_kernel = program.create_kernel("custom_kernel"); + custom_kernel.set_arg(0, atoms); + custom_kernel.set_arg(1, distances); + + queue.enqueue_1d_range_kernel(custom_kernel, 0, atoms.size(), 1); +} + +// Creates a StructWithArray containing 'x', 'y', 'z'. +StructWithArray make_struct_with_array(int x, int y, int z) +{ + StructWithArray s; + s.value = 0; + s.array[0] = x; + s.array[1] = y; + s.array[2] = z; + return s; +} + +BOOST_AUTO_TEST_CASE(struct_with_array) +{ + compute::vector<StructWithArray> structs(context); + + structs.push_back(make_struct_with_array(1, 2, 3), queue); + structs.push_back(make_struct_with_array(4, 5, 6), queue); + structs.push_back(make_struct_with_array(7, 8, 9), queue); + + BOOST_COMPUTE_FUNCTION(int, sum_array, (StructWithArray x), + { + return x.array[0] + x.array[1] + x.array[2]; + }); + + compute::vector<int> results(structs.size(), context); + compute::transform( + structs.begin(), structs.end(), results.begin(), sum_array, queue + ); + CHECK_RANGE_EQUAL(int, 3, results, (6, 15, 24)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_svm_ptr.cpp b/src/boost/libs/compute/test/test_svm_ptr.cpp new file mode 100644 index 00000000..1546deb7 --- /dev/null +++ b/src/boost/libs/compute/test/test_svm_ptr.cpp @@ -0,0 +1,156 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSvmPtr +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/core.hpp> +#include <boost/compute/svm.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/source.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(empty) +{ +} + +#ifdef BOOST_COMPUTE_CL_VERSION_2_0 +BOOST_AUTO_TEST_CASE(alloc) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + compute::svm_ptr<cl_int> ptr = compute::svm_alloc<cl_int>(context, 8); + compute::svm_free(context, ptr); +} + +BOOST_AUTO_TEST_CASE(svmmemcpy) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + if(bug_in_svmmemcpy(device)){ + std::cerr << "skipping svmmemcpy test case" << std::endl; + return; + } + + cl_int input[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + cl_int output[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + compute::svm_ptr<cl_int> ptr = compute::svm_alloc<cl_int>(context, 8); + compute::svm_ptr<cl_int> ptr2 = compute::svm_alloc<cl_int>(context, 8); + + // copying from and to host mem + queue.enqueue_svm_memcpy(ptr.get(), input, 8 * sizeof(cl_int)); + queue.enqueue_svm_memcpy(output, ptr.get(), 8 * sizeof(cl_int)); + queue.finish(); + + CHECK_HOST_RANGE_EQUAL(cl_int, 8, output, (1, 2, 3, 4, 5, 6, 7, 8)); + + // copying between svm mem + queue.enqueue_svm_memcpy(ptr2.get(), ptr.get(), 8 * sizeof(cl_int)); + queue.enqueue_svm_memcpy(output, ptr2.get(), 8 * sizeof(cl_int)); + queue.finish(); + + CHECK_HOST_RANGE_EQUAL(cl_int, 8, output, (1, 2, 3, 4, 5, 6, 7, 8)); + + compute::svm_free(context, ptr); + compute::svm_free(context, ptr2); +} + +BOOST_AUTO_TEST_CASE(sum_svm_kernel) +{ + REQUIRES_OPENCL_VERSION(2, 0); + + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void sum_svm_mem(__global const int *ptr, __global int *result) + { + int sum = 0; + for(uint i = 0; i < 8; i++){ + sum += ptr[i]; + } + *result = sum; + } + ); + + compute::program program = + compute::program::build_with_source(source, context, "-cl-std=CL2.0"); + + compute::kernel sum_svm_mem_kernel = program.create_kernel("sum_svm_mem"); + + cl_int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::svm_ptr<cl_int> ptr = compute::svm_alloc<cl_int>(context, 8); + queue.enqueue_svm_map(ptr.get(), 8 * sizeof(cl_int), CL_MAP_WRITE); + for(size_t i = 0; i < 8; i ++) { + static_cast<cl_int*>(ptr.get())[i] = data[i]; + } + queue.enqueue_svm_unmap(ptr.get()); + + compute::vector<cl_int> result(1, context); + + sum_svm_mem_kernel.set_arg(0, ptr); + sum_svm_mem_kernel.set_arg(1, result); + queue.enqueue_task(sum_svm_mem_kernel); + + queue.finish(); + BOOST_CHECK_EQUAL(result[0], (36)); + + compute::svm_free(context, ptr); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_0 + +#ifdef BOOST_COMPUTE_CL_VERSION_2_1 +BOOST_AUTO_TEST_CASE(migrate) +{ + REQUIRES_OPENCL_VERSION(2, 1); + + compute::svm_ptr<cl_int> ptr = + compute::svm_alloc<cl_int>(context, 8); + + // Migrate to device + std::vector<const void*> ptrs(1, ptr.get()); + std::vector<size_t> sizes(1, 8 * sizeof(cl_int)); + queue.enqueue_svm_migrate_memory(ptrs, sizes).wait(); + + // Set on device + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void foo(__global int *ptr) + { + for(int i = 0; i < 8; i++){ + ptr[i] = i; + } + } + ); + compute::program program = + compute::program::build_with_source(source, context, "-cl-std=CL2.0"); + compute::kernel foo_kernel = program.create_kernel("foo"); + foo_kernel.set_arg(0, ptr); + queue.enqueue_task(foo_kernel).wait(); + + // Migrate to host + queue.enqueue_svm_migrate_memory( + ptr.get(), 0, boost::compute::command_queue::migrate_to_host + ).wait(); + + // Check + CHECK_HOST_RANGE_EQUAL( + cl_int, 8, + static_cast<cl_int*>(ptr.get()), + (0, 1, 2, 3, 4, 5, 6, 7) + ); + compute::svm_free(context, ptr); +} +#endif // BOOST_COMPUTE_CL_VERSION_2_1 + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_system.cpp b/src/boost/libs/compute/test/test_system.cpp new file mode 100644 index 00000000..afc45fe6 --- /dev/null +++ b/src/boost/libs/compute/test/test_system.cpp @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestSystem +#include <boost/test/unit_test.hpp> + +#include <boost/compute/device.hpp> +#include <boost/compute/system.hpp> + +BOOST_AUTO_TEST_CASE(platform_count) +{ + BOOST_CHECK(boost::compute::system::platform_count() >= 1); +} + +BOOST_AUTO_TEST_CASE(device_count) +{ + BOOST_CHECK(boost::compute::system::device_count() >= 1); +} + +BOOST_AUTO_TEST_CASE(default_device) +{ + boost::compute::device device = boost::compute::system::default_device(); + BOOST_CHECK(device.id() != cl_device_id()); +} + +BOOST_AUTO_TEST_CASE(find_device) +{ + boost::compute::device device = boost::compute::system::default_device(); + const std::string &name = device.name(); + BOOST_CHECK(boost::compute::system::find_device(name).name() == device.name()); +} diff --git a/src/boost/libs/compute/test/test_tabulate.cpp b/src/boost/libs/compute/test/test_tabulate.cpp new file mode 100644 index 00000000..6ef82f45 --- /dev/null +++ b/src/boost/libs/compute/test/test_tabulate.cpp @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTabulate +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/experimental/tabulate.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(tabulate_negative_int) +{ + BOOST_COMPUTE_FUNCTION(int, negate, (int x), + { + return -x; + }); + + compute::vector<int> vector(10, context); + compute::experimental::tabulate(vector.begin(), vector.end(), negate, queue); + CHECK_RANGE_EQUAL(int, 10, vector, (0, -1, -2, -3, -4, -5, -6, -7, -8, -9)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_threefry_engine.cpp b/src/boost/libs/compute/test/test_threefry_engine.cpp new file mode 100644 index 00000000..3eddce73 --- /dev/null +++ b/src/boost/libs/compute/test/test_threefry_engine.cpp @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Muhammad Junaid Muzammil <mjunaidmuzammil@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://kylelutz.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestThreefry +#include <boost/test/unit_test.hpp> + +#include <boost/compute/random/threefry_engine.hpp> +#include <boost/compute/container/vector.hpp> + +#include <boost/compute/random/uniform_real_distribution.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(generate_uint) +{ + using boost::compute::uint_; + + boost::compute::threefry_engine<> random_engine(queue); + boost::compute::vector<uint_> random_values(19, context); + + random_engine.generate(random_values.begin(), random_values.end(), queue); + queue.finish(); + CHECK_RANGE_EQUAL( + uint_, 19, random_values, + (uint_(0x6b200159), + uint_(0x99ba4efe), + uint_(0x508efb2c), + uint_(0xc0de3f32), + uint_(0x64a626ec), + uint_(0xfc15e573), + uint_(0xb8abc4d1), + uint_(0x537eb86), + uint_(0xac6dc2bb), + uint_(0xa7adb3c3), + uint_(0x5641e094), + uint_(0xe4ab4fd), + uint_(0xa53c1ce9), + uint_(0xabcf1dba), + uint_(0x2677a25a), + uint_(0x76cf5efc), + uint_(0x2d08247f), + uint_(0x815480f1), + uint_(0x2d1fa53a)) + ); +} + +BOOST_AUTO_TEST_CASE(generate_float) +{ + using boost::compute::float_; + + boost::compute::threefry_engine<> random_engine(queue); + boost::compute::uniform_real_distribution<float_> random_distribution(0.f, 4.f); + + boost::compute::vector<float_> random_values(1024, context); + random_distribution.generate( + random_values.begin(), random_values.end(), random_engine, queue + ); + + std::vector<float_> random_values_host(1024); + boost::compute::copy( + random_values.begin(), random_values.end(), + random_values_host.begin(), + queue + ); + queue.finish(); + + double sum = 0.0; + for(size_t i = 0; i < random_values_host.size(); i++) + { + BOOST_CHECK_LT(random_values_host[i], 4.0f); + BOOST_CHECK_GE(random_values_host[i], 0.0f); + sum += random_values_host[i]; + } + double mean = sum / random_values_host.size(); + // For 1024 it can be 10% off + BOOST_CHECK_CLOSE(mean, 2.0f, 10.0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_transform.cpp b/src/boost/libs/compute/test/test_transform.cpp new file mode 100644 index 00000000..81b95c0e --- /dev/null +++ b/src/boost/libs/compute/test/test_transform.cpp @@ -0,0 +1,324 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTransform +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/counting_iterator.hpp> +#include <boost/compute/functional/field.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(transform_int_abs) +{ + int data[] = { 1, -2, -3, -4, 5 }; + bc::vector<int> vector(data, data + 5, queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, -2, -3, -4, 5)); + + bc::transform(vector.begin(), + vector.end(), + vector.begin(), + bc::abs<int>(), + queue); + CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 3, 4, 5)); +} + +BOOST_AUTO_TEST_CASE(transform_float_sqrt) +{ + float data[] = { 1.0f, 4.0f, 9.0f, 16.0f }; + bc::vector<float> vector(data, data + 4, queue); + CHECK_RANGE_EQUAL(float, 4, vector, (1.0f, 4.0f, 9.0f, 16.0f)); + + bc::transform(vector.begin(), + vector.end(), + vector.begin(), + bc::sqrt<float>(), + queue); + queue.finish(); + BOOST_CHECK_CLOSE(float(vector[0]), 1.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(vector[1]), 2.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(vector[2]), 3.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(vector[3]), 4.0f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(transform_float_clamp) +{ + float data[] = { 10.f, 20.f, 30.f, 40.f, 50.f }; + bc::vector<float> vector(data, data + 5, queue); + CHECK_RANGE_EQUAL(float, 5, vector, (10.0f, 20.0f, 30.0f, 40.0f, 50.0f)); + + bc::transform(vector.begin(), + vector.end(), + vector.begin(), + clamp(bc::_1, 15.f, 45.f), + queue); + CHECK_RANGE_EQUAL(float, 5, vector, (15.0f, 20.0f, 30.0f, 40.0f, 45.0f)); +} + +BOOST_AUTO_TEST_CASE(transform_add_int) +{ + int data1[] = { 1, 2, 3, 4 }; + bc::vector<int> input1(data1, data1 + 4, queue); + + int data2[] = { 10, 20, 30, 40 }; + bc::vector<int> input2(data2, data2 + 4, queue); + + bc::vector<int> output(4, context); + bc::transform(input1.begin(), + input1.end(), + input2.begin(), + output.begin(), + bc::plus<int>(), + queue); + CHECK_RANGE_EQUAL(int, 4, output, (11, 22, 33, 44)); + + bc::transform(input1.begin(), + input1.end(), + input2.begin(), + output.begin(), + bc::multiplies<int>(), + queue); + CHECK_RANGE_EQUAL(int, 4, output, (10, 40, 90, 160)); +} + +BOOST_AUTO_TEST_CASE(transform_pow4) +{ + float data[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + bc::vector<float> vector(data, data + 4, queue); + CHECK_RANGE_EQUAL(float, 4, vector, (1.0f, 2.0f, 3.0f, 4.0f)); + + bc::vector<float> result(4, context); + bc::transform(vector.begin(), + vector.end(), + result.begin(), + pown(bc::_1, 4), + queue); + queue.finish(); + BOOST_CHECK_CLOSE(float(result[0]), 1.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[1]), 16.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[2]), 81.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[3]), 256.0f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(transform_custom_function) +{ + float data[] = { 9.0f, 7.0f, 5.0f, 3.0f }; + bc::vector<float> vector(data, data + 4, queue); + + BOOST_COMPUTE_FUNCTION(float, pow3add4, (float x), + { + return pow(x, 3.0f) + 4.0f; + }); + + bc::vector<float> result(4, context); + bc::transform(vector.begin(), + vector.end(), + result.begin(), + pow3add4, + queue); + queue.finish(); + BOOST_CHECK_CLOSE(float(result[0]), 733.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[1]), 347.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[2]), 129.0f, 1e-4f); + BOOST_CHECK_CLOSE(float(result[3]), 31.0f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(extract_vector_component) +{ + using bc::int2_; + + int data[] = { 1, 2, + 3, 4, + 5, 6, + 7, 8 }; + bc::vector<int2_> vector( + reinterpret_cast<int2_ *>(data), + reinterpret_cast<int2_ *>(data) + 4, + queue + ); + CHECK_RANGE_EQUAL( + int2_, 4, vector, + (int2_(1, 2), int2_(3, 4), int2_(5, 6), int2_(7, 8)) + ); + + bc::vector<int> x_components(4, context); + bc::transform(vector.begin(), + vector.end(), + x_components.begin(), + bc::get<0>(), + queue); + CHECK_RANGE_EQUAL(int, 4, x_components, (1, 3, 5, 7)); + + bc::vector<int> y_components(4, context); + bc::transform(vector.begin(), + vector.end(), + y_components.begin(), + bc::get<1>(), + queue); + CHECK_RANGE_EQUAL(int, 4, y_components, (2, 4, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(transform_pinned_vector) +{ + int data[] = { 2, -3, 4, -5, 6, -7 }; + std::vector<int> vector(data, data + 6); + + bc::buffer buffer(context, + vector.size() * sizeof(int), + bc::buffer::read_write | bc::buffer::use_host_ptr, + &vector[0]); + + bc::transform(bc::make_buffer_iterator<int>(buffer, 0), + bc::make_buffer_iterator<int>(buffer, 6), + bc::make_buffer_iterator<int>(buffer, 0), + bc::abs<int>(), + queue); + + void *ptr = queue.enqueue_map_buffer(buffer, + bc::command_queue::map_read, + 0, + buffer.size()); + BOOST_VERIFY(ptr == &vector[0]); + BOOST_CHECK_EQUAL(vector[0], 2); + BOOST_CHECK_EQUAL(vector[1], 3); + BOOST_CHECK_EQUAL(vector[2], 4); + BOOST_CHECK_EQUAL(vector[3], 5); + BOOST_CHECK_EQUAL(vector[4], 6); + BOOST_CHECK_EQUAL(vector[5], 7); + queue.enqueue_unmap_buffer(buffer, ptr); +} + +BOOST_AUTO_TEST_CASE(transform_popcount) +{ + using boost::compute::uint_; + + uint_ data[] = { 0, 1, 2, 3, 4, 45, 127, 5000, 789, 15963 }; + bc::vector<uint_> input(data, data + 10, queue); + bc::vector<uint_> output(input.size(), context); + + bc::transform( + input.begin(), + input.end(), + output.begin(), + bc::popcount<uint_>(), + queue + ); + CHECK_RANGE_EQUAL(uint_, 10, output, (0, 1, 1, 2, 1, 4, 7, 5, 5, 10)); +} + +// generates the first 25 fibonacci numbers in parallel using the +// rounding-based fibonacci formula +BOOST_AUTO_TEST_CASE(generate_fibonacci_sequence) +{ + using boost::compute::uint_; + + boost::compute::vector<uint_> sequence(25, context); + + BOOST_COMPUTE_FUNCTION(uint_, nth_fibonacci, (const uint_ n), + { + const float golden_ratio = (1.f + sqrt(5.f)) / 2.f; + return floor(pown(golden_ratio, n) / sqrt(5.f) + 0.5f); + }); + + boost::compute::transform( + boost::compute::make_counting_iterator(uint_(0)), + boost::compute::make_counting_iterator(uint_(sequence.size())), + sequence.begin(), + nth_fibonacci, + queue + ); + CHECK_RANGE_EQUAL( + uint_, 25, sequence, + (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, + 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368) + ); +} + +BOOST_AUTO_TEST_CASE(field) +{ + using compute::uint2_; + using compute::uint4_; + using compute::field; + + unsigned int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<uint4_> input( + reinterpret_cast<uint4_ *>(data), + reinterpret_cast<uint4_ *>(data) + 2, + queue + ); + compute::vector<uint2_> output(input.size(), context); + + compute::transform( + input.begin(), + input.end(), + output.begin(), + compute::field<uint2_>("xz"), + queue + ); + + queue.finish(); + + BOOST_CHECK_EQUAL(uint2_(output[0]), uint2_(1, 3)); + BOOST_CHECK_EQUAL(uint2_(output[1]), uint2_(5, 7)); +} + +BOOST_AUTO_TEST_CASE(transform_abs_doctest) +{ +//! [transform_abs] +int data[] = { -1, -2, -3, -4 }; +boost::compute::vector<int> vec(data, data + 4, queue); + +using boost::compute::abs; + +// calculate the absolute value for each element in-place +boost::compute::transform( + vec.begin(), vec.end(), vec.begin(), abs<int>(), queue +); + +// vec == { 1, 2, 3, 4 } +//! [transform_abs] + + CHECK_RANGE_EQUAL(int, 4, vec, (1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_CASE(abs_if_odd) +{ + // return absolute value only for odd values + BOOST_COMPUTE_FUNCTION(int, abs_if_odd, (int x), + { + if(x & 1){ + return abs(x); + } + else { + return x; + } + }); + + int data[] = { -2, -3, -4, -5, -6, -7, -8, -9 }; + compute::vector<int> vector(data, data + 8, queue); + + compute::transform( + vector.begin(), vector.end(), vector.begin(), abs_if_odd, queue + ); + + CHECK_RANGE_EQUAL(int, 8, vector, (-2, +3, -4, +5, -6, +7, -8, +9)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_transform_if.cpp b/src/boost/libs/compute/test/test_transform_if.cpp new file mode 100644 index 00000000..fc371327 --- /dev/null +++ b/src/boost/libs/compute/test/test_transform_if.cpp @@ -0,0 +1,40 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTransformIf +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/transform_if.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(transform_if_odd) +{ + using boost::compute::abs; + using boost::compute::lambda::_1; + + int data[] = { -2, -3, -4, -5, -6, -7, -8, -9 }; + compute::vector<int> input(data, data + 8, queue); + compute::vector<int> output(input.size(), context); + + compute::vector<int>::iterator end = compute::transform_if( + input.begin(), input.end(), output.begin(), abs<int>(), _1 % 2 != 0, queue + ); + BOOST_CHECK_EQUAL(std::distance(output.begin(), end), 4); + + CHECK_RANGE_EQUAL(int, 4, output, (+3, +5, +7, +9)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_transform_iterator.cpp b/src/boost/libs/compute/test/test_transform_iterator.cpp new file mode 100644 index 00000000..6c77bf75 --- /dev/null +++ b/src/boost/libs/compute/test/test_transform_iterator.cpp @@ -0,0 +1,108 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTransformIterator +#include <boost/test/unit_test.hpp> + +#include <iterator> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/types.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> +#include <boost/compute/iterator/transform_iterator.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(value_type) +{ + using boost::compute::float4_; + + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::transform_iterator< + boost::compute::buffer_iterator<float>, + boost::compute::sqrt<float> + >::value_type, + float + >::value + )); + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::transform_iterator< + boost::compute::buffer_iterator<float4_>, + boost::compute::length<float4_> + >::value_type, + float + >::value + )); +} + +BOOST_AUTO_TEST_CASE(base_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::transform_iterator< + boost::compute::buffer_iterator<int>, boost::compute::abs<int> + >::base_type, + boost::compute::buffer_iterator<int> + >::value + )); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + int data[] = { 1, -2, 3, -4, 5 }; + boost::compute::vector<int> a(data, data + 5, queue); + + boost::compute::vector<int> b(5, context); + boost::compute::copy( + boost::compute::make_transform_iterator( + a.begin(), + boost::compute::abs<int>() + ), + boost::compute::make_transform_iterator( + a.end(), + boost::compute::abs<int>() + ), + b.begin(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, b, (1, 2, 3, 4, 5)); +} + +BOOST_AUTO_TEST_CASE(copy_abs_doctest) +{ + int data[] = { -1, -2, -3, -4 }; + boost::compute::vector<int> input(data, data + 4, queue); + boost::compute::vector<int> output(4, context); + +//! [copy_abs] +// use abs() from boost.compute +using boost::compute::abs; + +// copy the absolute value for each element in input to output +boost::compute::copy( + boost::compute::make_transform_iterator(input.begin(), abs<int>()), + boost::compute::make_transform_iterator(input.end(), abs<int>()), + output.begin(), + queue +); +//! [copy_abs] + + CHECK_RANGE_EQUAL(int, 4, output, (1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_transform_reduce.cpp b/src/boost/libs/compute/test/test_transform_reduce.cpp new file mode 100644 index 00000000..5766862d --- /dev/null +++ b/src/boost/libs/compute/test/test_transform_reduce.cpp @@ -0,0 +1,101 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTransformReduce +#include <boost/test/unit_test.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/transform_reduce.hpp> +#include <boost/compute/container/vector.hpp> + +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(sum_abs_int_doctest) +{ + using boost::compute::abs; + using boost::compute::plus; + + int data[] = { 1, -2, -3, -4, 5 }; + compute::vector<int> vec(data, data + 5, queue); + +//! [sum_abs_int] +int sum = 0; +boost::compute::transform_reduce( + vec.begin(), vec.end(), &sum, abs<int>(), plus<int>(), queue +); +//! [sum_abs_int] + + BOOST_CHECK_EQUAL(sum, 15); +} + +BOOST_AUTO_TEST_CASE(multiply_vector_length) +{ + float data[] = { 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 4.0f, 0.0f }; + compute::vector<compute::float4_> vector( + reinterpret_cast<compute::float4_ *>(data), + reinterpret_cast<compute::float4_ *>(data) + 3, + queue + ); + + float product; + compute::transform_reduce( + vector.begin(), + vector.end(), + &product, + compute::length<compute::float4_>(), + compute::multiplies<float>(), + queue + ); + BOOST_CHECK_CLOSE(product, 24.0f, 1e-4f); +} + +BOOST_AUTO_TEST_CASE(mean_and_std_dev) +{ + using compute::lambda::_1; + using compute::lambda::pow; + + float data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + compute::vector<float> vector(data, data + 10, queue); + + float sum; + compute::reduce( + vector.begin(), + vector.end(), + &sum, + compute::plus<float>(), + queue + ); + + float mean = sum / vector.size(); + BOOST_CHECK_CLOSE(mean, 5.5f, 1e-4); + + compute::transform_reduce( + vector.begin(), + vector.end(), + &sum, + pow(_1 - mean, 2), + compute::plus<float>(), + queue + ); + + float variance = sum / vector.size(); + BOOST_CHECK_CLOSE(variance, 8.25f, 1e-4); + + float std_dev = std::sqrt(variance); + BOOST_CHECK_CLOSE(std_dev, 2.8722813232690143, 1e-4); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_tuple.cpp b/src/boost/libs/compute/test/test_tuple.cpp new file mode 100644 index 00000000..ece24a37 --- /dev/null +++ b/src/boost/libs/compute/test/test_tuple.cpp @@ -0,0 +1,141 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTuple +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/tuple/tuple.hpp> +#include <boost/tuple/tuple_io.hpp> +#include <boost/tuple/tuple_comparison.hpp> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/find.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/tuple.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(vector_tuple_int_float) +{ + boost::compute::vector<boost::tuple<int, float> > vector(context); + + vector.push_back(boost::make_tuple(1, 2.1f), queue); + vector.push_back(boost::make_tuple(2, 3.2f), queue); + vector.push_back(boost::make_tuple(3, 4.3f), queue); +} + +BOOST_AUTO_TEST_CASE(copy_vector_tuple) +{ + // create vector of tuples on device + boost::compute::vector<boost::tuple<char, int, float> > input(context); + input.push_back(boost::make_tuple('a', 1, 2.3f), queue); + input.push_back(boost::make_tuple('c', 3, 4.5f), queue); + input.push_back(boost::make_tuple('f', 6, 7.8f), queue); + + // copy on device + boost::compute::vector<boost::tuple<char, int, float> > output(context); + + boost::compute::copy( + input.begin(), + input.end(), + output.begin(), + queue + ); + + // copy to host + std::vector<boost::tuple<char, int, float> > host_output(3); + + boost::compute::copy( + input.begin(), + input.end(), + host_output.begin(), + queue + ); + + // check tuple data + BOOST_CHECK_EQUAL(host_output[0], boost::make_tuple('a', 1, 2.3f)); + BOOST_CHECK_EQUAL(host_output[1], boost::make_tuple('c', 3, 4.5f)); + BOOST_CHECK_EQUAL(host_output[2], boost::make_tuple('f', 6, 7.8f)); +} + +BOOST_AUTO_TEST_CASE(extract_tuple_elements) +{ + compute::vector<boost::tuple<char, int, float> > vector(context); + vector.push_back(boost::make_tuple('a', 1, 2.3f), queue); + vector.push_back(boost::make_tuple('c', 3, 4.5f), queue); + vector.push_back(boost::make_tuple('f', 6, 7.8f), queue); + + compute::vector<char> chars(3, context); + compute::transform( + vector.begin(), vector.end(), chars.begin(), compute::get<0>(), queue + ); + CHECK_RANGE_EQUAL(char, 3, chars, ('a', 'c', 'f')); + + compute::vector<int> ints(3, context); + compute::transform( + vector.begin(), vector.end(), ints.begin(), compute::get<1>(), queue + ); + CHECK_RANGE_EQUAL(int, 3, ints, (1, 3, 6)); + + compute::vector<float> floats(3, context); + compute::transform( + vector.begin(), vector.end(), floats.begin(), compute::get<2>(), queue + ); + CHECK_RANGE_EQUAL(float, 3, floats, (2.3f, 4.5f, 7.8f)); +} + +BOOST_AUTO_TEST_CASE(fill_tuple_vector) +{ + if(bug_in_struct_assignment(device)){ + std::cerr << "skipping fill_tuple_vector test" << std::endl; + return; + } + + compute::vector<boost::tuple<char, int, float> > vector(5, context); + compute::fill(vector.begin(), vector.end(), boost::make_tuple('z', 4, 3.14f), queue); + + std::vector<boost::tuple<char, int, float> > host_output(5); + compute::copy(vector.begin(), vector.end(), host_output.begin(), queue); + BOOST_CHECK_EQUAL(host_output[0], boost::make_tuple('z', 4, 3.14f)); + BOOST_CHECK_EQUAL(host_output[1], boost::make_tuple('z', 4, 3.14f)); + BOOST_CHECK_EQUAL(host_output[2], boost::make_tuple('z', 4, 3.14f)); + BOOST_CHECK_EQUAL(host_output[3], boost::make_tuple('z', 4, 3.14f)); + BOOST_CHECK_EQUAL(host_output[4], boost::make_tuple('z', 4, 3.14f)); +} + +#ifndef BOOST_COMPUTE_NO_VARIADIC_TEMPLATES +BOOST_AUTO_TEST_CASE(variadic_tuple) +{ + BOOST_CHECK_EQUAL( + (compute::type_name<boost::tuple<char, short, int, float> >()), + "boost_tuple_char_short_int_float_t" + ); +} +#endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES + +#ifndef BOOST_COMPUTE_NO_STD_TUPLE +BOOST_AUTO_TEST_CASE(std_tuple) +{ + BOOST_CHECK_EQUAL( + (compute::type_name<std::tuple<char, short, int, float>>()), + "std_tuple_char_short_int_float_t" + ); +} +#endif // BOOST_COMPUTE_NO_STD_TUPLE + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_type_traits.cpp b/src/boost/libs/compute/test/test_type_traits.cpp new file mode 100644 index 00000000..9654a286 --- /dev/null +++ b/src/boost/libs/compute/test/test_type_traits.cpp @@ -0,0 +1,131 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTypeTraits +#include <boost/test/unit_test.hpp> + +#include <set> +#include <list> +#include <vector> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> + +#include <boost/compute/types.hpp> +#include <boost/compute/type_traits.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> +#include <boost/compute/iterator/constant_iterator.hpp> +#include <boost/compute/detail/is_buffer_iterator.hpp> +#include <boost/compute/detail/is_contiguous_iterator.hpp> + +namespace bc = boost::compute; + +BOOST_AUTO_TEST_CASE(scalar_type) +{ + BOOST_STATIC_ASSERT((boost::is_same<bc::scalar_type<bc::int_>::type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::scalar_type<bc::int2_>::type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::scalar_type<bc::float_>::type, float>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::scalar_type<bc::float4_>::type, float>::value)); +} + +BOOST_AUTO_TEST_CASE(vector_size) +{ + BOOST_STATIC_ASSERT(bc::vector_size<bc::int_>::value == 1); + BOOST_STATIC_ASSERT(bc::vector_size<bc::int2_>::value == 2); + BOOST_STATIC_ASSERT(bc::vector_size<bc::float_>::value == 1); + BOOST_STATIC_ASSERT(bc::vector_size<bc::float4_>::value == 4); +} + +BOOST_AUTO_TEST_CASE(is_vector_type) +{ + BOOST_STATIC_ASSERT(bc::is_vector_type<bc::int_>::value == false); + BOOST_STATIC_ASSERT(bc::is_vector_type<bc::int2_>::value == true); + BOOST_STATIC_ASSERT(bc::is_vector_type<bc::float_>::value == false); + BOOST_STATIC_ASSERT(bc::is_vector_type<bc::float4_>::value == true); +} + +BOOST_AUTO_TEST_CASE(make_vector_type) +{ + BOOST_STATIC_ASSERT((boost::is_same<bc::make_vector_type<cl_uint, 2>::type, bc::uint2_>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::make_vector_type<int, 4>::type, bc::int4_>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::make_vector_type<float, 8>::type, bc::float8_>::value)); + BOOST_STATIC_ASSERT((boost::is_same<bc::make_vector_type<bc::char_, 16>::type, bc::char16_>::value)); +} + +BOOST_AUTO_TEST_CASE(is_fundamental_type) +{ + BOOST_STATIC_ASSERT((bc::is_fundamental<int>::value == true)); + BOOST_STATIC_ASSERT((bc::is_fundamental<bc::int_>::value == true)); + BOOST_STATIC_ASSERT((bc::is_fundamental<bc::int2_>::value == true)); + BOOST_STATIC_ASSERT((bc::is_fundamental<float>::value == true)); + BOOST_STATIC_ASSERT((bc::is_fundamental<bc::float_>::value == true)); + BOOST_STATIC_ASSERT((bc::is_fundamental<bc::float4_>::value == true)); + + BOOST_STATIC_ASSERT((bc::is_fundamental<std::pair<int, float> >::value == false)); + BOOST_STATIC_ASSERT((bc::is_fundamental<std::complex<float> >::value == false)); +} + +BOOST_AUTO_TEST_CASE(type_name) +{ + // scalar types + BOOST_CHECK(std::strcmp(bc::type_name<bc::char_>(), "char") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::uchar_>(), "uchar") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::short_>(), "short") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::ushort_>(), "ushort") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::int_>(), "int") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::uint_>(), "uint") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::long_>(), "long") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::ulong_>(), "ulong") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::float_>(), "float") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::double_>(), "double") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bool>(), "bool") == 0); + + // vector types + BOOST_CHECK(std::strcmp(bc::type_name<bc::char16_>(), "char16") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::uint4_>(), "uint4") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::ulong8_>(), "ulong8") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::float2_>(), "float2") == 0); + BOOST_CHECK(std::strcmp(bc::type_name<bc::double4_>(), "double4") == 0); +} + +BOOST_AUTO_TEST_CASE(is_contiguous_iterator) +{ + using boost::compute::detail::is_contiguous_iterator; + + BOOST_STATIC_ASSERT(is_contiguous_iterator<int *>::value == true); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::vector<int>::iterator>::value == true); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::vector<int>::const_iterator>::value == true); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::list<int>::iterator>::value == false); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::set<int>::iterator>::value == false); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::insert_iterator<std::set<int> > >::value == false); + BOOST_STATIC_ASSERT(is_contiguous_iterator<std::back_insert_iterator<std::vector<int> > >::value == false); +} + +BOOST_AUTO_TEST_CASE(is_buffer_iterator) +{ + using boost::compute::detail::is_buffer_iterator; + + BOOST_STATIC_ASSERT(is_buffer_iterator<boost::compute::buffer_iterator<int> >::value == true); + BOOST_STATIC_ASSERT(is_buffer_iterator<boost::compute::constant_iterator<int> >::value == false); +} + +BOOST_AUTO_TEST_CASE(is_device_iterator) +{ + using boost::compute::is_device_iterator; + + BOOST_STATIC_ASSERT(is_device_iterator<boost::compute::buffer_iterator<int> >::value == true); + BOOST_STATIC_ASSERT(is_device_iterator<const boost::compute::buffer_iterator<int> >::value == true); + BOOST_STATIC_ASSERT(is_device_iterator<boost::compute::constant_iterator<int> >::value == true); + BOOST_STATIC_ASSERT(is_device_iterator<const boost::compute::constant_iterator<int> >::value == true); + BOOST_STATIC_ASSERT(is_device_iterator<float *>::value == false); + BOOST_STATIC_ASSERT(is_device_iterator<const float *>::value == false); + BOOST_STATIC_ASSERT(is_device_iterator<std::vector<int>::iterator>::value == false); + BOOST_STATIC_ASSERT(is_device_iterator<const std::vector<int>::iterator>::value == false); +} diff --git a/src/boost/libs/compute/test/test_types.cpp b/src/boost/libs/compute/test/test_types.cpp new file mode 100644 index 00000000..3ee0e791 --- /dev/null +++ b/src/boost/libs/compute/test/test_types.cpp @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestTypes +#include <boost/test/unit_test.hpp> + +#include <string> +#include <sstream> + +#include <boost/compute/types/fundamental.hpp> + +BOOST_AUTO_TEST_CASE(vector_ctor) +{ + boost::compute::int4_ i4(1, 2, 3, 4); + BOOST_CHECK(i4 == boost::compute::int4_(1, 2, 3, 4)); + BOOST_CHECK_EQUAL(i4, boost::compute::int4_(1, 2, 3, 4)); + BOOST_CHECK_EQUAL(i4[0], 1); + BOOST_CHECK_EQUAL(i4[1], 2); + BOOST_CHECK_EQUAL(i4[2], 3); + BOOST_CHECK_EQUAL(i4[3], 4); + + i4 = boost::compute::int4_(1); + BOOST_CHECK(i4 == boost::compute::int4_(1, 1, 1, 1)); + BOOST_CHECK(i4 == (boost::compute::vector_type<int, size_t(4)>(1))); + BOOST_CHECK_EQUAL(i4, boost::compute::int4_(1, 1, 1, 1)); + BOOST_CHECK_EQUAL(i4[0], 1); + BOOST_CHECK_EQUAL(i4[1], 1); + BOOST_CHECK_EQUAL(i4[2], 1); + BOOST_CHECK_EQUAL(i4[3], 1); +} + +BOOST_AUTO_TEST_CASE(vector_string) +{ + std::stringstream stream; + stream << boost::compute::int2_(1, 2); + BOOST_CHECK_EQUAL(stream.str(), std::string("int2(1, 2)")); +} + +BOOST_AUTO_TEST_CASE(vector_accessors_basic) +{ + boost::compute::float4_ v; + v.x = 1; + v.y = 2; + v.z = 3; + v.w = 4; + BOOST_CHECK(v == boost::compute::float4_(1, 2, 3, 4)); +} + +BOOST_AUTO_TEST_CASE(vector_accessors_all) +{ + boost::compute::int2_ i2(1, 2); + BOOST_CHECK_EQUAL(i2.x, 1); + BOOST_CHECK_EQUAL(i2.y, 2); + + boost::compute::int4_ i4(1, 2, 3, 4); + BOOST_CHECK_EQUAL(i4.x, 1); + BOOST_CHECK_EQUAL(i4.y, 2); + BOOST_CHECK_EQUAL(i4.z, 3); + BOOST_CHECK_EQUAL(i4.w, 4); + + boost::compute::int8_ i8(1, 2, 3, 4, 5, 6, 7, 8); + BOOST_CHECK_EQUAL(i8.s0, 1); + BOOST_CHECK_EQUAL(i8.s1, 2); + BOOST_CHECK_EQUAL(i8.s2, 3); + BOOST_CHECK_EQUAL(i8.s3, 4); + BOOST_CHECK_EQUAL(i8.s4, 5); + BOOST_CHECK_EQUAL(i8.s5, 6); + BOOST_CHECK_EQUAL(i8.s6, 7); + BOOST_CHECK_EQUAL(i8.s7, 8); + + boost::compute::int16_ i16( + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16); + BOOST_CHECK_EQUAL(i16.s0, 1); + BOOST_CHECK_EQUAL(i16.s1, 2); + BOOST_CHECK_EQUAL(i16.s2, 3); + BOOST_CHECK_EQUAL(i16.s3, 4); + BOOST_CHECK_EQUAL(i16.s4, 5); + BOOST_CHECK_EQUAL(i16.s5, 6); + BOOST_CHECK_EQUAL(i16.s6, 7); + BOOST_CHECK_EQUAL(i16.s7, 8); + BOOST_CHECK_EQUAL(i16.s8, 9); + BOOST_CHECK_EQUAL(i16.s9, 10); + BOOST_CHECK_EQUAL(i16.sa, 11); + BOOST_CHECK_EQUAL(i16.sb, 12); + BOOST_CHECK_EQUAL(i16.sc, 13); + BOOST_CHECK_EQUAL(i16.sd, 14); + BOOST_CHECK_EQUAL(i16.se, 15); + BOOST_CHECK_EQUAL(i16.sf, 16); +} diff --git a/src/boost/libs/compute/test/test_uniform_int_distribution.cpp b/src/boost/libs/compute/test/test_uniform_int_distribution.cpp new file mode 100644 index 00000000..55338a28 --- /dev/null +++ b/src/boost/libs/compute/test/test_uniform_int_distribution.cpp @@ -0,0 +1,77 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUniformIntDistribution +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/uniform_int_distribution.hpp> +#include <boost/compute/lambda.hpp> + +#include "context_setup.hpp" + +namespace compute=boost::compute; + +BOOST_AUTO_TEST_CASE(uniform_int_distribution_doctest) +{ + using boost::compute::uint_; + using boost::compute::lambda::_1; + + boost::compute::vector<uint_> vec(128, context); + +//! [generate] +// initialize the default random engine +boost::compute::default_random_engine engine(queue); + +// setup the uniform distribution to produce integers 0 and 1 +boost::compute::uniform_int_distribution<uint_> distribution(0, 1); + +// generate the random values and store them to 'vec' +distribution.generate(vec.begin(), vec.end(), engine, queue); +//! [generate] + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 > 1, queue + ), + size_t(0) + ); +} + +BOOST_AUTO_TEST_CASE(issue159) { + using boost::compute::lambda::_1; + + boost::compute::vector<int> input(10, context); + + // generate random numbers between 1 and 10 + compute::default_random_engine rng(queue); + compute::uniform_int_distribution<int> d(1, 10); + d.generate(input.begin(), input.end(), rng, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + input.begin(), input.end(), _1 > 10, queue + ), + size_t(0) + ); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + input.begin(), input.end(), _1 < 1, queue + ), + size_t(0) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_uniform_real_distribution.cpp b/src/boost/libs/compute/test/test_uniform_real_distribution.cpp new file mode 100644 index 00000000..d5394427 --- /dev/null +++ b/src/boost/libs/compute/test/test_uniform_real_distribution.cpp @@ -0,0 +1,105 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUniformRealDistribution +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/function.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/uniform_real_distribution.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/types/fundamental.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(uniform_real_distribution_doctest) +{ + using boost::compute::lambda::_1; + + boost::compute::vector<float> vec(128, context); + +//! [generate] +// initialize the default random engine +boost::compute::default_random_engine engine(queue); + +// setup the uniform distribution to produce floats between 1 and 100 +boost::compute::uniform_real_distribution<float> distribution(1.0f, 100.0f); + +// generate the random values and store them to 'vec' +distribution.generate(vec.begin(), vec.end(), engine, queue); +//! [generate] + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 < 1.0f || _1 >= 100.0f, queue + ), + size_t(0) + ); +} + +template<class T> +class range_test_engine +{ +public: + explicit range_test_engine(boost::compute::command_queue &queue) { + (void) queue; + } + + template<class OutputIterator, class Function> + void generate(OutputIterator first, OutputIterator last, Function op, boost::compute::command_queue &queue) + { + boost::compute::vector<T> tmp(std::distance(first, last), queue.get_context()); + + BOOST_COMPUTE_FUNCTION(T, max_random, (const T x), + { + if(get_global_id(0) < 1) + return (ValueType) MAX_RANDOM; + else + return (ValueType) 0; + }); + + max_random.define("MAX_RANDOM", "UINT_MAX"); + max_random.define("ValueType", boost::compute::type_name<T>()); + + boost::compute::transform(tmp.begin(), tmp.end(), tmp.begin(), max_random, queue); + boost::compute::transform(tmp.begin(), tmp.end(), first, op, queue); + } +}; + +// For checking if result is in the correct range [low, hi) +BOOST_AUTO_TEST_CASE(uniform_real_distribution_range) +{ + using boost::compute::lambda::_1; + + boost::compute::vector<float> vec(32, context); + + // initialize the range_test_engine + range_test_engine<boost::compute::uint_> engine(queue); + + // setup the uniform distribution to produce floats between 0.9 and 1.0 + boost::compute::uniform_real_distribution<float> distribution(0.9f, 1.0f); + + // generate the random values and store them to 'vec' + distribution.generate(vec.begin(), vec.end(), engine, queue); + + BOOST_CHECK_EQUAL( + boost::compute::count_if( + vec.begin(), vec.end(), _1 < 0.9f || _1 >= 1.0f, queue + ), + size_t(0) + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_unique.cpp b/src/boost/libs/compute/test/test_unique.cpp new file mode 100644 index 00000000..f754323b --- /dev/null +++ b/src/boost/libs/compute/test/test_unique.cpp @@ -0,0 +1,96 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUnique +#include <boost/test/unit_test.hpp> + +#include <boost/compute/function.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/algorithm/none_of.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/algorithm/unique.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(unique_int) +{ + int data[] = {1, 6, 6, 4, 2, 2, 4}; + + compute::vector<int> input(data, data + 7, queue); + + compute::vector<int>::iterator iter = + compute::unique(input.begin(), input.end(), queue); + + BOOST_VERIFY(iter == input.begin() + 5); + CHECK_RANGE_EQUAL(int, 7, input, (1, 6, 4, 2, 4, 2, 4)); +} + +BOOST_AUTO_TEST_CASE(all_same_float) +{ + compute::vector<float> vec(1024, context); + compute::fill(vec.begin(), vec.end(), 3.14f, queue); + + compute::vector<float>::iterator iter = + compute::unique(vec.begin(), vec.end(), queue); + + BOOST_VERIFY(iter == vec.begin() + 1); + + float first; + compute::copy_n(vec.begin(), 1, &first, queue); + BOOST_CHECK_EQUAL(first, 3.14f); +} + +BOOST_AUTO_TEST_CASE(unique_even_uints) +{ + using compute::uint_; + + // create vector filled with [0, 1, 2, ...] + compute::vector<uint_> vec(1024, context); + compute::iota(vec.begin(), vec.end(), 0, queue); + + // all should be unique + compute::vector<uint_>::iterator iter = compute::unique( + vec.begin(), vec.end(), queue + ); + BOOST_VERIFY(iter == vec.end()); + + // if odd, return the prior even number, else return the number + BOOST_COMPUTE_FUNCTION(uint_, odd_to_even, (uint_ x), + { + if(x & 1){ + return x - 1; + } + else { + return x; + } + }); + + // set all odd numbers the previous even number + compute::transform( + vec.begin(), vec.end(), vec.begin(), odd_to_even, queue + ); + + // now the vector should contain [0, 0, 2, 2, 4, 4, ...] + iter = compute::unique(vec.begin(), vec.end(), queue); + BOOST_VERIFY(iter == vec.begin() + (vec.size() / 2)); + + // ensure all of the values are even + BOOST_COMPUTE_FUNCTION(bool, is_odd, (uint_ x), + { + return x & 1; + }); + BOOST_VERIFY(compute::none_of(vec.begin(), vec.end(), is_odd, queue)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_unique_copy.cpp b/src/boost/libs/compute/test/test_unique_copy.cpp new file mode 100644 index 00000000..eaaf55e1 --- /dev/null +++ b/src/boost/libs/compute/test/test_unique_copy.cpp @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUniqueCopy +#include <boost/test/unit_test.hpp> + +#include <boost/compute/algorithm/unique_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(unique_copy_int) +{ + int data[] = {1, 6, 6, 4, 2, 2, 4}; + + bc::vector<int> input(data, data + 7, queue); + bc::vector<int> result(5, context); + + bc::vector<int>::iterator iter = + bc::unique_copy(input.begin(), input.end(), result.begin(), queue); + + BOOST_VERIFY(iter == result.begin() + 5); + CHECK_RANGE_EQUAL(int, 5, result, (1, 6, 4, 2, 4)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_unsupported_extension.cpp b/src/boost/libs/compute/test/test_unsupported_extension.cpp new file mode 100644 index 00000000..d87198d0 --- /dev/null +++ b/src/boost/libs/compute/test/test_unsupported_extension.cpp @@ -0,0 +1,18 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Fabian Köhler <fabian2804@googlemail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// +#define BOOST_TEST_MODULE TestUnsupportedExtension +#include <boost/test/unit_test.hpp> +#include <boost/compute/exception/unsupported_extension_error.hpp> + +BOOST_AUTO_TEST_CASE(unsupported_extension_error_what) +{ + boost::compute::unsupported_extension_error error("CL_DUMMY_EXTENSION"); + BOOST_CHECK_EQUAL(std::string(error.what()), std::string("OpenCL extension CL_DUMMY_EXTENSION not supported")); +} diff --git a/src/boost/libs/compute/test/test_user_defined_types.cpp b/src/boost/libs/compute/test/test_user_defined_types.cpp new file mode 100644 index 00000000..d9f75169 --- /dev/null +++ b/src/boost/libs/compute/test/test_user_defined_types.cpp @@ -0,0 +1,122 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUserDefinedTypes +#include <boost/test/unit_test.hpp> + +#include <iostream> + +#include <boost/compute/function.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/struct.hpp> + +namespace compute = boost::compute; + +// user-defined data type containing two int's and a float +struct UDD +{ + int a; + int b; + float c; +}; + +// make UDD available to OpenCL +BOOST_COMPUTE_ADAPT_STRUCT(UDD, UDD, (a, b, c)) + +// comparison operator for UDD +bool operator==(const UDD &lhs, const UDD &rhs) +{ + return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c; +} + +// output stream operator for UDD +std::ostream& operator<<(std::ostream &stream, const UDD &x) +{ + return stream << "(" << x.a << ", " << x.b << ", " << x.c << ")"; +} + +// function to generate a random UDD on the host +UDD rand_UDD() +{ + UDD udd; + udd.a = rand() % 100; + udd.b = rand() % 100; + udd.c = (float)(rand() % 100) / 1.3f; + + return udd; +} + +// function to compare two UDD's on the host by their first component +bool compare_UDD_host(const UDD &lhs, const UDD &rhs) +{ + return lhs.a < rhs.a; +} + +// function to compate two UDD's on the device by their first component +BOOST_COMPUTE_FUNCTION(bool, compare_UDD_device, (UDD lhs, UDD rhs), +{ + return lhs.a < rhs.a; +}); + +#include "check_macros.hpp" +#include "context_setup.hpp" + +// see: issue #11 (https://github.com/boostorg/compute/issues/11) +BOOST_AUTO_TEST_CASE(issue_11) +{ + if(device.vendor() == "NVIDIA" && device.platform().name() == "Apple"){ + // FIXME: this test currently segfaults on NVIDIA GPUs on Apple + std::cerr << "skipping issue test on NVIDIA GPU on Apple platform" << std::endl; + return; + } + + // create vector of random values on the host + std::vector<UDD> host_vector(10); + std::generate(host_vector.begin(), host_vector.end(), rand_UDD); + + // transfer the values to the device + compute::vector<UDD> device_vector(host_vector.size(), context); + compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // sort values on the device + compute::sort( + device_vector.begin(), + device_vector.end(), + compare_UDD_device, + queue + ); + + // sort values on the host + std::sort( + host_vector.begin(), + host_vector.end(), + compare_UDD_host + ); + + // copy sorted device values back to the host + std::vector<UDD> tmp(10); + compute::copy( + device_vector.begin(), + device_vector.end(), + tmp.begin(), + queue + ); + + // verify sorted values + for(size_t i = 0; i < host_vector.size(); i++){ + BOOST_CHECK_EQUAL(tmp[i], host_vector[i]); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_user_event.cpp b/src/boost/libs/compute/test/test_user_event.cpp new file mode 100644 index 00000000..2afbd146 --- /dev/null +++ b/src/boost/libs/compute/test/test_user_event.cpp @@ -0,0 +1,35 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestUserEvent +#include <boost/test/unit_test.hpp> + +#include <boost/compute/user_event.hpp> + +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(empty){} + +#ifdef BOOST_COMPUTE_CL_VERSION_1_1 +BOOST_AUTO_TEST_CASE(user_event) +{ + REQUIRES_OPENCL_VERSION(1, 1); + + boost::compute::user_event event(context); + BOOST_CHECK(event.get() != cl_event()); + BOOST_CHECK(event.status() != CL_COMPLETE); + + event.set_status(CL_COMPLETE); + event.wait(); + BOOST_CHECK(event.status() == CL_COMPLETE); +} +#endif // BOOST_COMPUTE_CL_VERSION_1_1 + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_valarray.cpp b/src/boost/libs/compute/test/test_valarray.cpp new file mode 100644 index 00000000..f6c97673 --- /dev/null +++ b/src/boost/libs/compute/test/test_valarray.cpp @@ -0,0 +1,361 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestValarray +#include <boost/test/unit_test.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/container/valarray.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +BOOST_AUTO_TEST_CASE(size) +{ + boost::compute::valarray<float> array; + BOOST_CHECK_EQUAL(array.size(), size_t(0)); + + array.resize(10); + BOOST_CHECK_EQUAL(array.size(), size_t(10)); +} + +BOOST_AUTO_TEST_CASE(at) +{ + int data[] = { 1, 2, 3, 4, 5 }; + boost::compute::valarray<int> array(data, 5); + BOOST_CHECK_EQUAL(array.size(), size_t(5)); + + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(int(array[0]), int(1)); + BOOST_CHECK_EQUAL(int(array[1]), int(2)); + BOOST_CHECK_EQUAL(int(array[2]), int(3)); + BOOST_CHECK_EQUAL(int(array[3]), int(4)); + BOOST_CHECK_EQUAL(int(array[4]), int(5)); +} + +BOOST_AUTO_TEST_CASE(min_and_max) +{ + int data[] = { 5, 2, 3, 7, 1, 9, 6, 5 }; + boost::compute::valarray<int> array(data, 8); + BOOST_CHECK_EQUAL(array.size(), size_t(8)); + + BOOST_CHECK_EQUAL((array.min)(), int(1)); + BOOST_CHECK_EQUAL((array.max)(), int(9)); +} + +BOOST_AUTO_TEST_CASE(sum) +{ + int data[] = { 1, 2, 3, 4 }; + boost::compute::valarray<int> array(data, 4); + boost::compute::system::finish(); + + BOOST_CHECK_EQUAL(array.size(), size_t(4)); + BOOST_CHECK_EQUAL(array.sum(), int(10)); +} + +BOOST_AUTO_TEST_CASE(apply) +{ + int data[] = { -1, 2, -3, 4 }; + boost::compute::valarray<int> array(data, 4); + + boost::compute::abs<int> abs; + boost::compute::valarray<int> result = array.apply(abs); + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(int(result[0]), int(1)); + BOOST_CHECK_EQUAL(int(result[1]), int(2)); + BOOST_CHECK_EQUAL(int(result[2]), int(3)); + BOOST_CHECK_EQUAL(int(result[3]), int(4)); +} + +/// \internal_ +/// Tests for compound assignment operators that works for floating +/// point types. +#define BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name) \ +BOOST_AUTO_TEST_CASE(op_name##_ca_operator_no_fp) \ +{ \ + float data[] = { 1, 2, 3, 4 }; \ + boost::compute::valarray<float> array1(data, 4); \ + boost::compute::valarray<float> array2(data, 4); \ + boost::compute::system::finish(); \ + \ + array1 op##= 1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(array1[0]), float(1.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[1]), float(2.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[2]), float(3.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[3]), float(4.0f op 1.0f), 1e-4f); \ + \ + array1 = boost::compute::valarray<float>(data, 4); \ + boost::compute::system::finish(); \ + \ + array1 op##= array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(array1[0]), float(1.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[1]), float(2.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[2]), float(3.0f op 3.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array1[3]), float(4.0f op 4.0f), 1e-4f); \ + \ + array2 op##= array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(array2[0]), float(1.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array2[1]), float(2.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array2[2]), float(3.0f op 3.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(array2[3]), float(4.0f op 4.0f), 1e-4f); \ + \ +} + +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT(+, plus) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT(-, minus) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT(*, multiplies) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT(/, divides) + +#undef BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT + +/// \internal_ +/// Tests for compound assignment operators that does NOT work for floating +/// point types. +/// Note: modulo operator works only for integer types. +#define BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(op, op_name) \ +BOOST_AUTO_TEST_CASE(op_name##_ca_operator) \ +{ \ + int data[] = { 1, 2, 3, 4 }; \ + boost::compute::valarray<int> array1(data, 4); \ + boost::compute::valarray<int> array2(data, 4); \ + boost::compute::system::finish(); \ + \ + array1 op##= 1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(array1[0]), int(1 op 1)); \ + BOOST_CHECK_EQUAL(int(array1[1]), int(2 op 1)); \ + BOOST_CHECK_EQUAL(int(array1[2]), int(3 op 1)); \ + BOOST_CHECK_EQUAL(int(array1[3]), int(4 op 1)); \ + \ + array1 = boost::compute::valarray<int>(data, 4); \ + boost::compute::system::finish(); \ + \ + array1 op##= array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(array1[0]), int(1 op 1)); \ + BOOST_CHECK_EQUAL(int(array1[1]), int(2 op 2)); \ + BOOST_CHECK_EQUAL(int(array1[2]), int(3 op 3)); \ + BOOST_CHECK_EQUAL(int(array1[3]), int(4 op 4)); \ + \ + array2 op##= array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(array2[0]), int(1 op 1)); \ + BOOST_CHECK_EQUAL(int(array2[1]), int(2 op 2)); \ + BOOST_CHECK_EQUAL(int(array2[2]), int(3 op 3)); \ + BOOST_CHECK_EQUAL(int(array2[3]), int(4 op 4)); \ + \ +} + +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(%, modulus) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(^, bit_xor) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(&, bit_and) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(|, bit_or) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(<<, shift_left) +BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(>>, shift_right) + +#undef BOOST_COMPUTE_TEST_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP + +BOOST_AUTO_TEST_CASE(unary_plus_operator) +{ + int data[] = { 1, 2, 3, 4 }; + boost::compute::valarray<int> array(data, 4); + boost::compute::system::finish(); + + boost::compute::valarray<int> result = +array; + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(int(result[0]), +(int(1))); + BOOST_CHECK_EQUAL(int(result[1]), +(int(2))); + BOOST_CHECK_EQUAL(int(result[2]), +(int(3))); + BOOST_CHECK_EQUAL(int(result[3]), +(int(4))); +} + +BOOST_AUTO_TEST_CASE(unary_minus_operator) +{ + int data[] = { -1, 2, 0, 4 }; + boost::compute::valarray<int> array(data, 4); + boost::compute::system::finish(); + + boost::compute::valarray<int> result = -array; + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(int(result[0]), int(1)); + BOOST_CHECK_EQUAL(int(result[1]), int(-2)); + BOOST_CHECK_EQUAL(int(result[2]), int(0)); + BOOST_CHECK_EQUAL(int(result[3]), int(-4)); +} + +BOOST_AUTO_TEST_CASE(unary_bitwise_not_operator) +{ + int data[] = { 1, 2, 3, 4 }; + boost::compute::valarray<int> array(data, 4); + boost::compute::system::finish(); + + boost::compute::valarray<int> result = ~array; + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(int(result[0]), ~(int(1))); + BOOST_CHECK_EQUAL(int(result[1]), ~(int(2))); + BOOST_CHECK_EQUAL(int(result[2]), ~(int(3))); + BOOST_CHECK_EQUAL(int(result[3]), ~(int(4))); +} + +BOOST_AUTO_TEST_CASE(unary_logical_not_operator) +{ + int data[] = { 1, -2, 0, 4 }; + boost::compute::valarray<int> array(data, 4); + boost::compute::system::finish(); + + boost::compute::valarray<char> result = !array; + boost::compute::system::finish(); + BOOST_CHECK_EQUAL(bool(result[0]), !(int(1))); + BOOST_CHECK_EQUAL(bool(result[1]), !(int(-2))); + BOOST_CHECK_EQUAL(bool(result[2]), !(int(0))); + BOOST_CHECK_EQUAL(bool(result[3]), !(int(4))); +} + +/// \internal_ +/// Tests for binary operators that works for floating +/// point types. +#define BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR(op, op_name) \ +BOOST_AUTO_TEST_CASE(op_name##_binary_operator) \ +{ \ + float data1[] = { 1, 2, 3, 4 }; \ + float data2[] = { 4, 2, 3, 0 }; \ + boost::compute::valarray<float> array1(data1, 4); \ + boost::compute::valarray<float> array2(data2, 4); \ + boost::compute::system::finish(); \ + \ + boost::compute::valarray<float> result = 2.0f op array1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(result[0]), float(2.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[1]), float(2.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[2]), float(2.0f op 3.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[3]), float(2.0f op 4.0f), 1e-4f); \ + \ + result = array1 op 2.0f; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(result[0]), float(1.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[1]), float(2.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[2]), float(3.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[3]), float(4.0f op 2.0f), 1e-4f); \ + \ + result = array2 op array1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_CLOSE(float(result[0]), float(4.0f op 1.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[1]), float(2.0f op 2.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[2]), float(3.0f op 3.0f), 1e-4f); \ + BOOST_CHECK_CLOSE(float(result[3]), float(0.0f op 4.0f), 1e-4f); \ +} + +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR(+, plus) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR(-, minus) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR(*, multiplies) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR(/, divides) + +#undef BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR + +/// \internal_ +/// Tests for compound assignment operators that does NOT work for floating +/// point types. +/// Note: modulo operator works only for integer types. +#define BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(op, op_name) \ +BOOST_AUTO_TEST_CASE(op_name##_binary_operator) \ +{ \ + int data1[] = { 1, 2, 3, 4 }; \ + int data2[] = { 4, 5, 2, 1 }; \ + boost::compute::valarray<int> array1(data1, 4); \ + boost::compute::valarray<int> array2(data2, 4); \ + boost::compute::system::finish(); \ + \ + boost::compute::valarray<int> result = 5 op array1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(result[0]), int(5 op 1)); \ + BOOST_CHECK_EQUAL(int(result[1]), int(5 op 2)); \ + BOOST_CHECK_EQUAL(int(result[2]), int(5 op 3)); \ + BOOST_CHECK_EQUAL(int(result[3]), int(5 op 4)); \ + \ + result = array1 op 5; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(result[0]), int(1 op 5)); \ + BOOST_CHECK_EQUAL(int(result[1]), int(2 op 5)); \ + BOOST_CHECK_EQUAL(int(result[2]), int(3 op 5)); \ + BOOST_CHECK_EQUAL(int(result[3]), int(4 op 5)); \ + \ + result = array1 op array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(int(result[0]), int(1 op 4)); \ + BOOST_CHECK_EQUAL(int(result[1]), int(2 op 5)); \ + BOOST_CHECK_EQUAL(int(result[2]), int(3 op 2)); \ + BOOST_CHECK_EQUAL(int(result[3]), int(4 op 1)); \ +} + +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(^, bit_xor) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(&, bit_and) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(|, bit_or) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(<<, shift_left) +BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP(>>, shift_right) + +#undef BOOST_COMPUTE_TEST_VALARRAY_BINARY_OPERATOR_NO_FP + +/// \internal_ +/// Macro for generating tests for valarray comparison operators. +#define BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(op, op_name) \ +BOOST_AUTO_TEST_CASE(op_name##_comparision_operator) \ +{ \ + int data1[] = { 1, 2, 0, 4 }; \ + int data2[] = { 4, 0, 2, 1 }; \ + boost::compute::valarray<int> array1(data1, 4); \ + boost::compute::valarray<int> array2(data2, 4); \ + boost::compute::system::finish(); \ + \ + boost::compute::valarray<char> result = 2 op array1; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(bool(result[0]), bool(2 op 1)); \ + BOOST_CHECK_EQUAL(bool(result[1]), bool(2 op 2)); \ + BOOST_CHECK_EQUAL(bool(result[2]), bool(2 op 0)); \ + BOOST_CHECK_EQUAL(bool(result[3]), bool(2 op 4)); \ + \ + result = array1 op 2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(bool(result[0]), bool(1 op 2)); \ + BOOST_CHECK_EQUAL(bool(result[1]), bool(2 op 2)); \ + BOOST_CHECK_EQUAL(bool(result[2]), bool(0 op 2)); \ + BOOST_CHECK_EQUAL(bool(result[3]), bool(4 op 2)); \ + \ + result = array1 op array2; \ + boost::compute::system::finish(); \ + BOOST_CHECK_EQUAL(bool(result[0]), bool(1 op 4)); \ + BOOST_CHECK_EQUAL(bool(result[1]), bool(2 op 0)); \ + BOOST_CHECK_EQUAL(bool(result[2]), bool(0 op 2)); \ + BOOST_CHECK_EQUAL(bool(result[3]), bool(4 op 1)); \ +} + +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(==, equal_to) +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(!=, not_equal_to) +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(>, greater) +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(<, less) +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(>=, greater_equal) +BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(<=, less_equal) + +/// \internal_ +/// Macro for generating tests for valarray binary logical operators. +#define BOOST_COMPUTE_TEST_VALARRAY_LOGICAL_OPERATOR(op, op_name) \ + BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR(op, op_name) + +BOOST_COMPUTE_TEST_VALARRAY_LOGICAL_OPERATOR(&&, logical_and) +BOOST_COMPUTE_TEST_VALARRAY_LOGICAL_OPERATOR(||, logical_or) + +#undef BOOST_COMPUTE_TEST_VALARRAY_LOGICAL_OPERATOR + +#undef BOOST_COMPUTE_TEST_VALARRAY_COMPARISON_OPERATOR + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_vector.cpp b/src/boost/libs/compute/test/test_vector.cpp new file mode 100644 index 00000000..c3dd8b79 --- /dev/null +++ b/src/boost/libs/compute/test/test_vector.cpp @@ -0,0 +1,502 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestVector +#include <boost/test/unit_test.hpp> +#include <boost/concept_check.hpp> + +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/find.hpp> +#include <boost/compute/algorithm/remove.hpp> +#include <boost/compute/allocator/pinned_allocator.hpp> +#include <boost/compute/container/vector.hpp> + +#include "quirks.hpp" +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace bc = boost::compute; +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(concept_check) +{ + BOOST_CONCEPT_ASSERT((boost::Container<bc::vector<int> >)); + //BOOST_CONCEPT_ASSERT((boost::SequenceConcept<bc::vector<int> >)); + BOOST_CONCEPT_ASSERT((boost::ReversibleContainer<bc::vector<int> >)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<bc::vector<int>::iterator>)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<bc::vector<int>::const_iterator>)); +} + +BOOST_AUTO_TEST_CASE(size) +{ + bc::vector<int> empty_vector(context); + BOOST_CHECK_EQUAL(empty_vector.size(), size_t(0)); + BOOST_CHECK_EQUAL(empty_vector.empty(), true); + + bc::vector<int> int_vector(10, context); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(10)); + BOOST_CHECK_EQUAL(int_vector.empty(), false); +} + +BOOST_AUTO_TEST_CASE(resize) +{ + bc::vector<int> int_vector(10, context); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(10)); + + int_vector.resize(20, queue); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(20)); + + int_vector.resize(5, queue); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(5)); +} + +BOOST_AUTO_TEST_CASE(reserve) +{ + const float growth_factor = 1.5f; + + bc::vector<int> int_vector(10, context); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(10)); + BOOST_CHECK_EQUAL(int_vector.capacity(), size_t(10)); + + int_vector.reserve(20, queue); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(10)); + BOOST_CHECK_EQUAL(int_vector.capacity(), size_t(20 * growth_factor)); + + int_vector.reserve(5, queue); + BOOST_CHECK_EQUAL(int_vector.size(), size_t(10)); + BOOST_CHECK_EQUAL(int_vector.capacity(), size_t(20 * growth_factor)); +} + +BOOST_AUTO_TEST_CASE(array_operator) +{ + bc::vector<int> vector(10, context); + bc::fill(vector.begin(), vector.end(), 0, queue); + CHECK_RANGE_EQUAL(int, 10, vector, (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + + bc::fill(vector.begin(), vector.end(), 42, queue); + CHECK_RANGE_EQUAL(int, 10, vector, (42, 42, 42, 42, 42, 42, 42, 42, 42, 42)); + + vector[0] = 9; + CHECK_RANGE_EQUAL(int, 10, vector, (9, 42, 42, 42, 42, 42, 42, 42, 42, 42)); +} + +BOOST_AUTO_TEST_CASE(front_and_back) +{ + int int_data[] = { 1, 2, 3, 4, 5 }; + bc::vector<int> int_vector(5, context); + bc::copy(int_data, int_data + 5, int_vector.begin(), queue); + queue.finish(); + BOOST_CHECK_EQUAL(int_vector.front(), 1); + BOOST_CHECK_EQUAL(int_vector.back(), 5); + + bc::fill(int_vector.begin(), int_vector.end(), 10, queue); + queue.finish(); + BOOST_CHECK_EQUAL(int_vector.front(), 10); + BOOST_CHECK_EQUAL(int_vector.back(), 10); + + float float_data[] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f }; + bc::vector<float> float_vector(5, context); + bc::copy(float_data, float_data + 5, float_vector.begin(), queue); + queue.finish(); + BOOST_CHECK_EQUAL(float_vector.front(), 1.1f); + BOOST_CHECK_EQUAL(float_vector.back(), 5.5f); +} + +BOOST_AUTO_TEST_CASE(host_iterator_constructor) +{ + std::vector<int> host_vector; + host_vector.push_back(10); + host_vector.push_back(20); + host_vector.push_back(30); + host_vector.push_back(40); + + bc::vector<int> device_vector(host_vector.begin(), host_vector.end(), + queue); + CHECK_RANGE_EQUAL(int, 4, device_vector, (10, 20, 30, 40)); +} + +BOOST_AUTO_TEST_CASE(device_iterator_constructor) +{ + int data[] = { 1, 5, 10, 15 }; + bc::vector<int> a(data, data + 4, queue); + CHECK_RANGE_EQUAL(int, 4, a, (1, 5, 10, 15)); + + bc::vector<int> b(a.begin(), a.end(), queue); + CHECK_RANGE_EQUAL(int, 4, b, (1, 5, 10, 15)); +} + +BOOST_AUTO_TEST_CASE(push_back) +{ + bc::vector<int> vector(context); + BOOST_VERIFY(vector.empty()); + + vector.push_back(12, queue); + BOOST_VERIFY(!vector.empty()); + BOOST_CHECK_EQUAL(vector.size(), size_t(1)); + CHECK_RANGE_EQUAL(int, 1, vector, (12)); + + vector.push_back(24, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(2)); + CHECK_RANGE_EQUAL(int, 2, vector, (12, 24)); + + vector.push_back(36, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(3)); + CHECK_RANGE_EQUAL(int, 3, vector, (12, 24, 36)); + + for(int i = 0; i < 100; i++){ + vector.push_back(i, queue); + } + queue.finish(); + BOOST_CHECK_EQUAL(vector.size(), size_t(103)); + BOOST_CHECK_EQUAL(vector[0], 12); + BOOST_CHECK_EQUAL(vector[1], 24); + BOOST_CHECK_EQUAL(vector[2], 36); + BOOST_CHECK_EQUAL(vector[102], 99); +} + +BOOST_AUTO_TEST_CASE(at) +{ + bc::vector<int> vector(context); + vector.push_back(1, queue); + vector.push_back(2, queue); + vector.push_back(3, queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.at(0), 1); + BOOST_CHECK_EQUAL(vector.at(1), 2); + BOOST_CHECK_EQUAL(vector.at(2), 3); + BOOST_CHECK_THROW(vector.at(3), std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(erase) +{ + int data[] = { 1, 2, 5, 7, 9 }; + bc::vector<int> vector(data, data + 5, queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.size(), size_t(5)); + + vector.erase(vector.begin() + 1, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, vector, (1, 5, 7, 9)); + + vector.erase(vector.begin() + 2, vector.end(), queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(2)); + CHECK_RANGE_EQUAL(int, 2, vector, (1, 5)); +} + +BOOST_AUTO_TEST_CASE(max_size) +{ + bc::vector<int> vector(100, context); + BOOST_CHECK_EQUAL(vector.size(), size_t(100)); + BOOST_VERIFY(vector.max_size() > vector.size()); +} + +#ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES +BOOST_AUTO_TEST_CASE(move_ctor) +{ + int data[] = { 11, 12, 13, 14 }; + bc::vector<int> a(data, data + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + bc::vector<int> b(std::move(a)); + BOOST_CHECK(a.size() == 0); + BOOST_CHECK(a.get_buffer().get() == 0); + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); +} + +BOOST_AUTO_TEST_CASE(move_ctor_custom_alloc) +{ + int data[] = { 11, 12, 13, 14 }; + bc::vector<int, bc::pinned_allocator<int> > a(data, data + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + bc::vector<int, bc::pinned_allocator<int> > b(std::move(a)); + BOOST_CHECK(a.size() == 0); + BOOST_CHECK(a.get_buffer().get() == 0); + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); +} +#endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES + +#ifdef BOOST_COMPUTE_USE_CPP11 +#ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +BOOST_AUTO_TEST_CASE(initializer_list_ctor) +{ + // ctor with std::initializer_list<T> always uses + // default_queue in this case + bc::vector<int> vector = { 2, -4, 6, 8 }; + BOOST_CHECK_EQUAL(vector.size(), size_t(4)); + BOOST_CHECK_EQUAL(vector[0], 2); + BOOST_CHECK_EQUAL(vector[1], -4); + BOOST_CHECK_EQUAL(vector[2], 6); + BOOST_CHECK_EQUAL(vector[3], 8); +} +#endif // BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +#endif // BOOST_COMPUTE_USE_CPP11 + +BOOST_AUTO_TEST_CASE(vector_double) +{ + if(!device.supports_extension("cl_khr_fp64")){ + return; + } + + bc::vector<double> vector(context); + vector.push_back(1.21, queue); + vector.push_back(3.14, queue); + vector.push_back(7.89, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(3)); + CHECK_RANGE_EQUAL(double, 3, vector, (1.21, 3.14, 7.89)); + + bc::vector<double> other(vector.begin(), vector.end(), queue); + CHECK_RANGE_EQUAL(double, 3, other, (1.21, 3.14, 7.89)); + + bc::fill(other.begin(), other.end(), 8.95, queue); + CHECK_RANGE_EQUAL(double, 3, other, (8.95, 8.95, 8.95)); +} + +BOOST_AUTO_TEST_CASE(vector_iterator) +{ + bc::vector<int> vector(context); + vector.push_back(2, queue); + vector.push_back(4, queue); + vector.push_back(6, queue); + vector.push_back(8, queue); + queue.finish(); + BOOST_CHECK_EQUAL(vector.size(), size_t(4)); + BOOST_CHECK_EQUAL(vector[0], 2); + BOOST_CHECK_EQUAL(*vector.begin(), 2); + BOOST_CHECK_EQUAL(vector.begin()[0], 2); + BOOST_CHECK_EQUAL(vector[1], 4); + BOOST_CHECK_EQUAL(*(vector.begin()+1), 4); + BOOST_CHECK_EQUAL(vector.begin()[1], 4); + BOOST_CHECK_EQUAL(vector[2], 6); + BOOST_CHECK_EQUAL(*(vector.begin()+2), 6); + BOOST_CHECK_EQUAL(vector.begin()[2], 6); + BOOST_CHECK_EQUAL(vector[3], 8); + BOOST_CHECK_EQUAL(*(vector.begin()+3), 8); + BOOST_CHECK_EQUAL(vector.begin()[3], 8); +} + +BOOST_AUTO_TEST_CASE(vector_erase_remove) +{ + int data[] = { 2, 6, 3, 4, 2, 4, 5, 6, 1 }; + bc::vector<int> vector(data, data + 9, queue); + BOOST_CHECK_EQUAL(vector.size(), size_t(9)); + + // remove 4's + vector.erase(bc::remove(vector.begin(), vector.end(), 4, queue), vector.end()); + BOOST_CHECK_EQUAL(vector.size(), size_t(7)); + BOOST_VERIFY(bc::find(vector.begin(), vector.end(), 4, queue) == vector.end()); + + // remove 2's + vector.erase(bc::remove(vector.begin(), vector.end(), 2, queue), vector.end()); + BOOST_CHECK_EQUAL(vector.size(), size_t(5)); + BOOST_VERIFY(bc::find(vector.begin(), vector.end(), 2, queue) == vector.end()); + + // remove 6's + vector.erase(bc::remove(vector.begin(), vector.end(), 6, queue), vector.end()); + BOOST_CHECK_EQUAL(vector.size(), size_t(3)); + BOOST_VERIFY(bc::find(vector.begin(), vector.end(), 6, queue) == vector.end()); + + // check the rest of the values + CHECK_RANGE_EQUAL(int, 3, vector, (3, 5, 1)); +} + +// see issue #132 (https://github.com/boostorg/compute/issues/132) +BOOST_AUTO_TEST_CASE(swap_between_contexts) +{ + compute::context ctx1(device); + compute::context ctx2(device); + + compute::vector<int> vec1(32, ctx1); + compute::vector<int> vec2(32, ctx2); + + BOOST_CHECK(vec1.get_allocator().get_context() == ctx1); + BOOST_CHECK(vec2.get_allocator().get_context() == ctx2); + + vec1.swap(vec2); + + BOOST_CHECK(vec1.get_allocator().get_context() == ctx2); + BOOST_CHECK(vec2.get_allocator().get_context() == ctx1); + + vec1.resize(64); + vec2.resize(64); +} + +BOOST_AUTO_TEST_CASE(assign_from_std_vector) +{ + std::vector<int> host_vector; + host_vector.push_back(1); + host_vector.push_back(9); + host_vector.push_back(7); + host_vector.push_back(9); + + compute::vector<int> device_vector(context); + device_vector.assign(host_vector.begin(), host_vector.end(), queue); + BOOST_CHECK_EQUAL(device_vector.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, device_vector, (1, 9, 7, 9)); +} + +BOOST_AUTO_TEST_CASE(assign_constant_value) +{ + compute::vector<float> device_vector(10, context); + device_vector.assign(3, 6.28f, queue); + BOOST_CHECK_EQUAL(device_vector.size(), size_t(3)); + CHECK_RANGE_EQUAL(float, 3, device_vector, (6.28f, 6.28f, 6.28f)); +} + +BOOST_AUTO_TEST_CASE(resize_throw_exception) +{ + if(bug_in_clcreatebuffer(device)) { + std::cerr + << "skipping resize_throw_exception test on Apple platform" + << std::endl; + return; + } + + // create vector with eight items + int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + compute::vector<int> vec(data, data + 8, queue); + + // try to resize to 2x larger than the global memory size + BOOST_CHECK_THROW( + vec.resize((device.global_memory_size() / sizeof(int)) * 2), + boost::compute::opencl_error + ); + + // ensure vector data is still the same + BOOST_CHECK_EQUAL(vec.size(), size_t(8)); + CHECK_RANGE_EQUAL(int, 8, vec, (1, 2, 3, 4, 5, 6, 7, 8)); +} + +BOOST_AUTO_TEST_CASE(copy_ctor_custom_alloc) +{ + int data[] = { 11, 12, 13, 14 }; + bc::vector<int, bc::pinned_allocator<int> > a(data, data + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + bc::vector<int, bc::pinned_allocator<int> > b(a, queue); + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); +} + +BOOST_AUTO_TEST_CASE(copy_ctor_different_alloc) +{ + int data[] = { 11, 12, 13, 14 }; + bc::vector<int> a(data, data + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + bc::vector<int, bc::pinned_allocator<int> > b(a, queue); + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); + + std::vector<int> host_vector; + host_vector.push_back(1); + host_vector.push_back(9); + host_vector.push_back(7); + host_vector.push_back(9); + + bc::vector<int, bc::pinned_allocator<int> > c(host_vector, queue); + BOOST_CHECK_EQUAL(c.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, c, (1, 9, 7, 9)); +} + +BOOST_AUTO_TEST_CASE(assignment_operator) +{ + int adata[] = { 11, 12, 13, 14 }; + bc::vector<int> a(adata, adata + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + bc::vector<int> b = a; + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); + + bc::vector<int, bc::pinned_allocator<int> > c(context); + c = b; + BOOST_CHECK_EQUAL(c.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, c, (11, 12, 13, 14)); + + int ddata[] = { 21, 22, 23 }; + bc::vector<int, bc::pinned_allocator<int> > d(ddata, ddata + 3, queue); + BOOST_CHECK_EQUAL(d.size(), size_t(3)); + CHECK_RANGE_EQUAL(int, 3, d, (21, 22, 23)); + + a = d; + BOOST_CHECK_EQUAL(a.size(), size_t(3)); + CHECK_RANGE_EQUAL(int, 3, a, (21, 22, 23)); + + std::vector<int> host_vector; + host_vector.push_back(1); + host_vector.push_back(9); + host_vector.push_back(7); + host_vector.push_back(9); + + d = host_vector; + BOOST_CHECK_EQUAL(d.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, d, (1, 9, 7, 9)); +} + +BOOST_AUTO_TEST_CASE(swap_ctor_custom_alloc) +{ + int adata[] = { 11, 12, 13, 14 }; + bc::vector<int, bc::pinned_allocator<int> > a(adata, adata + 4, queue); + BOOST_CHECK_EQUAL(a.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, a, (11, 12, 13, 14)); + + int bdata[] = { 21, 22, 23 }; + bc::vector<int, bc::pinned_allocator<int> > b(bdata, bdata + 3, queue); + BOOST_CHECK_EQUAL(b.size(), size_t(3)); + CHECK_RANGE_EQUAL(int, 3, b, (21, 22, 23)); + + a.swap(b); + BOOST_CHECK_EQUAL(a.size(), size_t(3)); + CHECK_RANGE_EQUAL(int, 3, a, (21, 22, 23)); + BOOST_CHECK_EQUAL(b.size(), size_t(4)); + CHECK_RANGE_EQUAL(int, 4, b, (11, 12, 13, 14)); +} + +BOOST_AUTO_TEST_CASE(shrink_to_fit) +{ + bc::vector<bc::int_> int_vector(5, context); + BOOST_CHECK_EQUAL(int_vector.size(), 5); + BOOST_CHECK(int_vector.capacity() >= 5); + + int_vector.reserve(15); + BOOST_CHECK_EQUAL(int_vector.size(), 5); + BOOST_CHECK(int_vector.capacity() >= 15); + + int_vector.shrink_to_fit(); + BOOST_CHECK_EQUAL(int_vector.size(), 5); + BOOST_CHECK_EQUAL(int_vector.capacity(), 5); + + int_vector.clear(); + BOOST_CHECK_EQUAL(int_vector.size(), 0); + BOOST_CHECK_EQUAL(int_vector.capacity(), 5); + + int_vector.shrink_to_fit(); + BOOST_CHECK_EQUAL(int_vector.size(), 0); + BOOST_CHECK_EQUAL(int_vector.capacity(), 0); + + int_vector.reserve(15); + BOOST_CHECK_EQUAL(int_vector.size(), 0); + BOOST_CHECK(int_vector.capacity() >= 15); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_wait_list.cpp b/src/boost/libs/compute/test/test_wait_list.cpp new file mode 100644 index 00000000..f6e0570a --- /dev/null +++ b/src/boost/libs/compute/test/test_wait_list.cpp @@ -0,0 +1,82 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestWaitList +#include <boost/test/unit_test.hpp> + +#include <algorithm> +#include <vector> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/async/future.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/wait_list.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(create_wait_list) +{ + compute::wait_list events; + BOOST_CHECK_EQUAL(events.size(), size_t(0)); + BOOST_CHECK_EQUAL(events.empty(), true); + BOOST_CHECK(events.get_event_ptr() == 0); +} + +#ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST +BOOST_AUTO_TEST_CASE(create_wait_list_from_initializer_list) +{ + compute::event event0; + compute::event event1; + compute::event event2; + compute::wait_list events = { event0, event1, event2 }; + BOOST_CHECK_EQUAL(events.size(), size_t(3)); + CHECK_RANGE_EQUAL(compute::event, 3, events, (event0, event1, event2)); +} +#endif // BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST + +BOOST_AUTO_TEST_CASE(insert_future) +{ + // create vector on the host + std::vector<int> host_vector(4); + std::fill(host_vector.begin(), host_vector.end(), 7); + + // create vector on the device + compute::vector<int> device_vector(4, context); + + // create wait list + compute::wait_list events; + + // copy values to device + compute::future<void> future = compute::copy_async( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // add future event to the wait list + events.insert(future); + BOOST_CHECK_EQUAL(events.size(), size_t(1)); + BOOST_CHECK(events.get_event_ptr() != 0); + + // wait for copy to complete + events.wait(); + + // check values + CHECK_RANGE_EQUAL(int, 4, device_vector, (7, 7, 7, 7)); + + // clear the event list + events.clear(); + BOOST_CHECK_EQUAL(events.size(), size_t(0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/compute/test/test_zip_iterator.cpp b/src/boost/libs/compute/test/test_zip_iterator.cpp new file mode 100644 index 00000000..ae76d580 --- /dev/null +++ b/src/boost/libs/compute/test/test_zip_iterator.cpp @@ -0,0 +1,232 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE TestZipIterator +#include <boost/test/unit_test.hpp> + +#include <boost/type_traits.hpp> +#include <boost/static_assert.hpp> +#include <boost/tuple/tuple_io.hpp> +#include <boost/tuple/tuple_comparison.hpp> + +#include <boost/compute/functional.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/constant_iterator.hpp> +#include <boost/compute/iterator/zip_iterator.hpp> +#include <boost/compute/types/tuple.hpp> + +#include "check_macros.hpp" +#include "context_setup.hpp" + +namespace compute = boost::compute; + +BOOST_AUTO_TEST_CASE(value_type) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + boost::compute::zip_iterator< + boost::tuple< + boost::compute::buffer_iterator<float>, + boost::compute::buffer_iterator<int> + > + >::value_type, + boost::tuple<float, int> + >::value + )); +} + +BOOST_AUTO_TEST_CASE(distance) +{ + boost::compute::vector<char> char_vector(5, context); + boost::compute::vector<int> int_vector(5, context); + + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.begin(), + int_vector.begin() + ) + ), + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.end(), + int_vector.end() + ) + ) + ), + ptrdiff_t(5) + ); + + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.begin(), + int_vector.begin() + ) + ) + 1, + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.end(), + int_vector.end() + ) + ) - 1 + ), + ptrdiff_t(3) + ); + + BOOST_CHECK_EQUAL( + std::distance( + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.begin() + 2, + int_vector.begin() + 2 + ) + ), + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.end() - 1, + int_vector.end() - 1 + ) + ) + ), + ptrdiff_t(2) + ); +} + +BOOST_AUTO_TEST_CASE(copy) +{ + // create three separate vectors of three different types + char char_data[] = { 'x', 'y', 'z' }; + boost::compute::vector<char> char_vector(char_data, char_data + 3, queue); + + int int_data[] = { 4, 7, 9 }; + boost::compute::vector<int> int_vector(int_data, int_data + 3, queue); + + float float_data[] = { 3.2f, 4.5f, 7.6f }; + boost::compute::vector<float> float_vector(float_data, float_data + 3, queue); + + // zip all three vectors into a single tuple vector + boost::compute::vector<boost::tuple<char, int, float> > tuple_vector(3, context); + + boost::compute::copy( + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.begin(), + int_vector.begin(), + float_vector.begin() + ) + ), + boost::compute::make_zip_iterator( + boost::make_tuple( + char_vector.end(), + int_vector.end(), + float_vector.end() + ) + ), + tuple_vector.begin(), + queue + ); + + // copy tuple vector to host + std::vector<boost::tuple<char, int, float> > host_vector(3); + + boost::compute::copy( + tuple_vector.begin(), + tuple_vector.end(), + host_vector.begin(), + queue + ); + + // check tuple values + BOOST_CHECK_EQUAL(host_vector[0], boost::make_tuple('x', 4, 3.2f)); + BOOST_CHECK_EQUAL(host_vector[1], boost::make_tuple('y', 7, 4.5f)); + BOOST_CHECK_EQUAL(host_vector[2], boost::make_tuple('z', 9, 7.6f)); +} + +BOOST_AUTO_TEST_CASE(zip_iterator_get) +{ + int data1[] = { 0, 2, 4, 6, 8 }; + int data2[] = { 1, 3, 5, 7, 9 }; + + compute::vector<int> input1(data1, data1 + 5, queue); + compute::vector<int> input2(data2, data2 + 5, queue); + compute::vector<int> output(5, context); + + // extract first component from (input1) + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input1.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input1.end()) + ), + output.begin(), + compute::get<0>(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (0, 2, 4, 6, 8)); + + // extract first component from (input2, input1) + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input2.begin(), input1.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input2.end(), input1.end()) + ), + output.begin(), + compute::get<0>(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (1, 3, 5, 7, 9)); + + // extract second component from (input1, input2, input1) + compute::transform( + compute::make_zip_iterator( + boost::make_tuple(input1.begin(), input2.begin(), input1.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(input1.end(), input2.end(), input1.end()) + ), + output.begin(), + compute::get<1>(), + queue + ); + CHECK_RANGE_EQUAL(int, 5, output, (1, 3, 5, 7, 9)); +} + +BOOST_AUTO_TEST_CASE(zip_constant_iterator) +{ + compute::vector<int> result(4, context); + + compute::transform( + compute::make_zip_iterator( + boost::make_tuple( + compute::make_constant_iterator(7) + ) + ), + compute::make_zip_iterator( + boost::make_tuple( + compute::make_constant_iterator(7, result.size()) + ) + ), + result.begin(), + compute::get<0>(), + queue + ); + + CHECK_RANGE_EQUAL(int, 4, result, (7, 7, 7, 7)); +} + +BOOST_AUTO_TEST_SUITE_END() |