diff options
Diffstat (limited to 'src/boost/libs/compute')
324 files changed, 34564 insertions, 0 deletions
diff --git a/src/boost/libs/compute/CMakeLists.txt b/src/boost/libs/compute/CMakeLists.txt new file mode 100644 index 00000000..71e7722e --- /dev/null +++ b/src/boost/libs/compute/CMakeLists.txt @@ -0,0 +1,129 @@ +# --------------------------------------------------------------------------- +# 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 +# +# --------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 2.8) + +project(BoostCompute) + +set(CMAKE_MODULE_PATH ${BoostCompute_SOURCE_DIR}/cmake) +if (CMAKE_VERSION VERSION_LESS "3.1.0") + list(APPEND CMAKE_MODULE_PATH "${BoostCompute_SOURCE_DIR}/cmake/opencl") +endif() + +# find OpenCL +find_package(OpenCL REQUIRED) +include_directories(SYSTEM ${OpenCL_INCLUDE_DIRS}) + +# find Boost +find_package(Boost 1.54 REQUIRED) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + +# optional support for c++11 +option(BOOST_COMPUTE_USE_CPP11 "Use C++11 features" OFF) +if(NOT MSVC) + if(${BOOST_COMPUTE_USE_CPP11}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() +endif() + +# optional support for offline-caching +option(BOOST_COMPUTE_USE_OFFLINE_CACHE "Use offline cache for OpenCL program binaries" OFF) +if(${BOOST_COMPUTE_USE_OFFLINE_CACHE}) + add_definitions(-DBOOST_COMPUTE_USE_OFFLINE_CACHE) +endif() + +# thread-safety options +option(BOOST_COMPUTE_THREAD_SAFE "Compile with BOOST_COMPUTE_THREAD_SAFE defined" OFF) +if(${BOOST_COMPUTE_THREAD_SAFE}) + add_definitions(-DBOOST_COMPUTE_THREAD_SAFE) + if(${BOOST_COMPUTE_USE_CPP11}) + if(MSVC) + if (MSVC_VERSION GREATER 1800) + add_definitions(-DBOOST_COMPUTE_HAVE_THREAD_LOCAL) + endif() + else() + add_definitions(-DBOOST_COMPUTE_HAVE_THREAD_LOCAL) + endif() + endif() +endif() + +# optional third-party libraries +option(BOOST_COMPUTE_HAVE_EIGEN "Have Eigen" OFF) +option(BOOST_COMPUTE_HAVE_OPENCV "Have OpenCV" OFF) +option(BOOST_COMPUTE_HAVE_QT "Have Qt" OFF) +option(BOOST_COMPUTE_HAVE_VTK "Have VTK" OFF) +option(BOOST_COMPUTE_HAVE_CUDA "Have CUDA" OFF) +option(BOOST_COMPUTE_HAVE_TBB "Have TBB" OFF) +option(BOOST_COMPUTE_HAVE_BOLT "Have BOLT" OFF) + +include_directories(include) + +if(${OpenCL_HEADER_CL_EXT_FOUND}) + add_definitions(-DBOOST_COMPUTE_HAVE_HDR_CL_EXT) +endif() + +if(WIN32) + # optional support for boost dynamic libraries + option(BOOST_COMPUTE_BOOST_ALL_DYN_LINK "Use boost dynamic link libraries" OFF) + if(${BOOST_COMPUTE_BOOST_ALL_DYN_LINK}) + add_definitions(-DBOOST_ALL_DYN_LINK) + else() + # for default use statis libs + set(Boost_USE_STATIC_LIBS ON) + endif() + link_directories(${Boost_LIBRARY_DIRS}) +endif() + +# compiler options +option(BOOST_COMPUTE_ENABLE_COVERAGE "Enable code coverage generation" OFF) + +# Visual Studio C++ +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_SCL_SECURE_NO_WARNINGS) + add_definitions(-DNOMINMAX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4003") # Not enough actual parameters for a BOOST_PP macro + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244") # Warning C4244: 'initializing': conversion from 'double' to 'int', possible loss of data + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4305") # Warning C4305: 'initializing': truncation from 'double' to 'float' + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800") # Warning C4800: 'uint32_t' : forcing value to bool 'true' or 'false' (performance warning) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4838") # Warning C4838: conversion from 'double' to 'float' requires a narrowing conversion +endif() + +option(BOOST_COMPUTE_BUILD_TESTS "Build the Boost.Compute tests" OFF) +if(${BOOST_COMPUTE_BUILD_TESTS}) + enable_testing() + add_subdirectory(test) +endif() + +option(BOOST_COMPUTE_BUILD_BENCHMARKS "Build the Boost.Compute benchmarks" OFF) +if(${BOOST_COMPUTE_BUILD_BENCHMARKS}) + add_subdirectory(perf) +endif() + +option(BOOST_COMPUTE_BUILD_EXAMPLES "Build the Boost.Compute examples" OFF) +if(${BOOST_COMPUTE_BUILD_EXAMPLES}) + add_subdirectory(example) +endif() + +# configure cmake config file +configure_file( + cmake/BoostComputeConfig.cmake.in + ${BoostCompute_BINARY_DIR}/BoostComputeConfig.cmake + @ONLY +) + +# install cmake config file +install( + FILES ${BoostCompute_BINARY_DIR}/BoostComputeConfig.cmake + DESTINATION lib/cmake/BoostCompute +) + +# install header files +install(DIRECTORY include/boost DESTINATION include/compute) diff --git a/src/boost/libs/compute/CONTRIBUTING.md b/src/boost/libs/compute/CONTRIBUTING.md new file mode 100644 index 00000000..d8b5fa23 --- /dev/null +++ b/src/boost/libs/compute/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to Boost.Compute # + +## Reporting Issues ## + +We value your feedback about issues you encounter. The more information you +provide the easier it is for developers to resolve the problem. + +Issues should be reported to the [issue tracker]( +https://github.com/boostorg/compute/issues?state=open). + +Issues can also be used to submit feature requests. + +## Submitting Pull Requests ## + +Base your changes on `master` but submit your pull-request to `develop`. This +can be changed by clicking the "Edit" button on the pull-request page. The +develop branch is used for integration and testing of changes before merging +into the stable `master` branch. + +Please try to rebase your changes on the current master branch before +submitting. This keeps the git history cleaner and easier to understand. + +## Coding Style ## + +* Indentation is four-spaces (not tabs) +* Try to keep line-length under 80 characters +* Follow the STL/Boost naming conventions (e.g. lower case with underscores) +* When in doubt, match the style of existing code +* Otherwise, do whatever you want + +Also see the [Boost Library Requirements] +(http://www.boost.org/development/requirements.html)). + +## Running Tests ## + +To build the tests you must enable the `BOOST_COMPUTE_BUILD_TESTS` option in +`cmake`. The tests can be run by executing the `ctest` command from the build +directory. + +Please report any tests failures to the issue tracker along with the test +output and information on your system and compute device. + +## Support ## + +Feel free to send an email to kyle.r.lutz@gmail.com with any problems or +questions. diff --git a/src/boost/libs/compute/LICENSE_1_0.txt b/src/boost/libs/compute/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/src/boost/libs/compute/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/boost/libs/compute/README.md b/src/boost/libs/compute/README.md new file mode 100644 index 00000000..f8556116 --- /dev/null +++ b/src/boost/libs/compute/README.md @@ -0,0 +1,90 @@ +# Boost.Compute # + +[![Build Status](https://travis-ci.org/boostorg/compute.svg?branch=master)](https://travis-ci.org/boostorg/compute) +[![Build status](https://ci.appveyor.com/api/projects/status/4s2nvfc97m7w23oi/branch/master?svg=true)](https://ci.appveyor.com/project/jszuppe/compute/branch/master) +[![Coverage Status](https://coveralls.io/repos/boostorg/compute/badge.svg?branch=master)](https://coveralls.io/r/boostorg/compute) +[![Gitter](https://badges.gitter.im/boostorg/compute.svg)](https://gitter.im/boostorg/compute?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +Boost.Compute is a GPU/parallel-computing library for C++ based on OpenCL. + +The core library is a thin C++ wrapper over the OpenCL API and provides +access to compute devices, contexts, command queues and memory buffers. + +On top of the core library is a generic, STL-like interface providing common +algorithms (e.g. `transform()`, `accumulate()`, `sort()`) along with common +containers (e.g. `vector<T>`, `flat_set<T>`). It also features a number of +extensions including parallel-computing algorithms (e.g. `exclusive_scan()`, +`scatter()`, `reduce()`) and a number of fancy iterators (e.g. +`transform_iterator<>`, `permutation_iterator<>`, `zip_iterator<>`). + +The full documentation is available at http://boostorg.github.io/compute/. + +## Example ## + +The following example shows how to sort a vector of floats on the GPU: + +```c++ +#include <vector> +#include <algorithm> +#include <boost/compute.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get the default compute device + compute::device gpu = compute::system::default_device(); + + // create a compute context and command queue + compute::context ctx(gpu); + compute::command_queue queue(ctx, gpu); + + // generate random numbers on the host + std::vector<float> host_vector(1000000); + std::generate(host_vector.begin(), host_vector.end(), rand); + + // create vector on the device + compute::vector<float> device_vector(1000000, ctx); + + // copy data to the device + compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // sort data on the device + compute::sort( + device_vector.begin(), device_vector.end(), queue + ); + + // copy data back to the host + compute::copy( + device_vector.begin(), device_vector.end(), host_vector.begin(), queue + ); + + return 0; +} +``` + +Boost.Compute is a header-only library, so no linking is required. The example +above can be compiled with: + +`g++ -I/path/to/compute/include sort.cpp -lOpenCL` + +More examples can be found in the [tutorial]( +http://boostorg.github.io/compute/boost_compute/tutorial.html) and under the +[examples](https://github.com/boostorg/compute/tree/master/example) directory. + +## Support ## +Questions about the library (both usage and development) can be posted to the +[mailing list](https://groups.google.com/forum/#!forum/boost-compute). + +Bugs and feature requests can be reported through the [issue tracker]( +https://github.com/boostorg/compute/issues?state=open). + +Also feel free to send me an email with any problems, questions, or feedback. + +## Help Wanted ## +The Boost.Compute project is currently looking for additional developers with +interest in parallel computing. + +Please send an email to Kyle Lutz (kyle.r.lutz@gmail.com) for more information. diff --git a/src/boost/libs/compute/cmake/BoostComputeConfig.cmake.in b/src/boost/libs/compute/cmake/BoostComputeConfig.cmake.in new file mode 100644 index 00000000..5f03d0db --- /dev/null +++ b/src/boost/libs/compute/cmake/BoostComputeConfig.cmake.in @@ -0,0 +1,6 @@ +# Config file for Boost.Compute (https://github.com/boostorg/compute) +# +# Sets the following variables: +# BoostCompute_INCLUDE_DIRS - include directories for Boost.Compute + +set(BoostCompute_INCLUDE_DIRS "@CMAKE_INSTALL_PREFIX@/include/compute") diff --git a/src/boost/libs/compute/cmake/FindBolt.cmake b/src/boost/libs/compute/cmake/FindBolt.cmake new file mode 100644 index 00000000..0820de0d --- /dev/null +++ b/src/boost/libs/compute/cmake/FindBolt.cmake @@ -0,0 +1,149 @@ +############################################################################ +# © 2012,2014 Advanced Micro Devices, Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################ + +# Locate an BOLT implementation. +# +# Defines the following variables: +# +# BOLT_FOUND - Found an Bolt imlementation +# +# Also defines the library variables below as normal +# variables. +# +# BOLT_LIBRARIES - These contain debug/optimized keywords when a debugging library is found +# BOLT_INCLUDE_DIRS - All relevant Bolt include directories +# +# Accepts the following variables as input: +# +# BOLT_ROOT - (as a CMake or environment variable) +# The root directory of an BOLT installation +# +# FIND_LIBRARY_USE_LIB64_PATHS - Global property that controls whether FindBOLT should search for +# 64bit or 32bit libs +# +#----------------------- +# Example Usage: +# +# find_package(BOLT REQUIRED) +# include_directories(${BOLT_INCLUDE_DIRS}) +# +# add_executable(foo foo.cc) +# target_link_libraries(foo ${BOLT_LIBRARIES}) +# +#----------------------- + +# This module helps to use BOLT_FIND_COMPONENTS, BOLT_FIND_REQUIRED, BOLT_FIND_QUIETLY +include( FindPackageHandleStandardArgs ) + +# Search for 64bit libs if FIND_LIBRARY_USE_LIB64_PATHS is set to true in the global environment, 32bit libs else +get_property( LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ) + +# Debug print statements +#message( "BOLT_LIBRARY_PATH_SUFFIXES: ${BOLT_LIBRARY_PATH_SUFFIXES}" ) +#message( "ENV{BOLT_ROOT}: $ENV{BOLT_ROOT}" ) +#message( "BOLT_FIND_COMPONENTS: ${BOLT_FIND_COMPONENTS}" ) +#message( "BOLT_FIND_REQUIRED: ${BOLT_FIND_REQUIRED}" ) + +# Set the component to find if the user does not specify explicitely +if( NOT BOLT_FIND_COMPONENTS ) + set( BOLT_FIND_COMPONENTS CL ) +endif( ) +if(WIN32) +if( MSVC_VERSION VERSION_LESS 1600 ) + set( myMSVCVer "vc90" ) +elseif( MSVC_VERSION VERSION_LESS 1700 ) + set( myMSVCVer "vc100" ) +elseif( MSVC_VERSION VERSION_LESS 1800 ) + set( myMSVCVer "vc110" ) +else() + set( myMSVCVer "vc120" ) +endif( ) +else() + set( myMSVCVer "gcc" ) +endif() + +if(WIN32) + set( BoltLibName "clBolt.runtime.${myMSVCVer}") + set( LIB_EXT "lib") +else() + set( BoltLibName "libclBolt.runtime.${myMSVCVer}") + set( LIB_EXT "a") +endif() + +# Eventually, Bolt may support multiple backends, but for now it only supports CL +list( FIND BOLT_FIND_COMPONENTS CL find_CL ) +if( NOT find_CL EQUAL -1 ) + set( BOLT_LIBNAME_BASE ${BoltLibName} ) +endif( ) + +if( NOT find_CL EQUAL -1 ) + # Find and set the location of main BOLT static lib file + find_library( BOLT_LIBRARY_STATIC_RELEASE + NAMES ${BOLT_LIBNAME_BASE}.${LIB_EXT} + HINTS + ${BOLT_ROOT} + ENV BOLT_ROOT + DOC "BOLT static library path" + PATH_SUFFIXES lib + ) + mark_as_advanced( BOLT_LIBRARY_STATIC_RELEASE ) + + # Find and set the location of main BOLT static lib file + find_library( BOLT_LIBRARY_STATIC_DEBUG + NAMES ${BOLT_LIBNAME_BASE}.debug.${LIB_EXT} + HINTS + ${BOLT_ROOT} + ENV BOLT_ROOT + DOC "BOLT static library path" + PATH_SUFFIXES lib + ) + mark_as_advanced( BOLT_LIBRARY_STATIC_DEBUG ) + + if( BOLT_LIBRARY_STATIC_RELEASE ) + set( BOLT_LIBRARY_STATIC optimized ${BOLT_LIBRARY_STATIC_RELEASE} ) + else( ) + set( BOLT_LIBRARY_STATIC "" ) + message( "${BOLT_LIBNAME_BASE}.${LIB_EXT}: Release static bolt library not found" ) + endif( ) + + if( BOLT_LIBRARY_STATIC_DEBUG ) + set( BOLT_LIBRARY_STATIC ${BOLT_LIBRARY_STATIC} debug ${BOLT_LIBRARY_STATIC_DEBUG} ) + else( ) + message( "${BOLT_LIBNAME_BASE}.debug.${LIB_EXT}: Debug static bolt library not found" ) + endif( ) + + find_path( BOLT_INCLUDE_DIRS + NAMES bolt/cl/bolt.h + HINTS + ${BOLT_ROOT} + ENV BOLT_ROOT + DOC "BOLT header file path" + PATH_SUFFIXES include + ) + mark_as_advanced( BOLT_INCLUDE_DIRS ) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS( BOLT DEFAULT_MSG BOLT_LIBRARY_STATIC BOLT_INCLUDE_DIRS ) +endif( ) + +if( BOLT_FOUND ) + list( APPEND BOLT_LIBRARIES ${BOLT_LIBRARY_STATIC} ) +else( ) + if( NOT BOLT_FIND_QUIETLY ) + message( WARNING "FindBOLT could not find the BOLT library" ) + message( STATUS "Did you remember to set the BOLT_ROOT environment variable?" ) + endif( ) +endif() diff --git a/src/boost/libs/compute/cmake/FindEigen.cmake b/src/boost/libs/compute/cmake/FindEigen.cmake new file mode 100644 index 00000000..2cd3e12c --- /dev/null +++ b/src/boost/libs/compute/cmake/FindEigen.cmake @@ -0,0 +1,160 @@ +# Ceres Solver - A fast non-linear least squares minimizer +# Copyright 2013 Google Inc. All rights reserved. +# http://code.google.com/p/ceres-solver/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Author: alexs.mac@gmail.com (Alex Stewart) +# + +# FindEigen.cmake - Find Eigen library, version >= 3. +# +# This module defines the following variables: +# +# EIGEN_FOUND: TRUE iff Eigen is found. +# EIGEN_INCLUDE_DIRS: Include directories for Eigen. +# +# EIGEN_VERSION: Extracted from Eigen/src/Core/util/Macros.h +# EIGEN_WORLD_VERSION: Equal to 3 if EIGEN_VERSION = 3.2.0 +# EIGEN_MAJOR_VERSION: Equal to 2 if EIGEN_VERSION = 3.2.0 +# EIGEN_MINOR_VERSION: Equal to 0 if EIGEN_VERSION = 3.2.0 +# +# The following variables control the behaviour of this module: +# +# EIGEN_INCLUDE_DIR_HINTS: List of additional directories in which to +# search for eigen includes, e.g: /timbuktu/eigen3. +# +# The following variables are also defined by this module, but in line with +# CMake recommended FindPackage() module style should NOT be referenced directly +# by callers (use the plural variables detailed above instead). These variables +# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which +# are NOT re-called (i.e. search for library is not repeated) if these variables +# are set with valid values _in the CMake cache_. This means that if these +# variables are set directly in the cache, either by the user in the CMake GUI, +# or by the user passing -DVAR=VALUE directives to CMake when called (which +# explicitly defines a cache variable), then they will be used verbatim, +# bypassing the HINTS variables and other hard-coded search locations. +# +# EIGEN_INCLUDE_DIR: Include directory for CXSparse, not including the +# include directory of any dependencies. + +# Called if we failed to find Eigen or any of it's required dependencies, +# unsets all public (designed to be used externally) variables and reports +# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument. +MACRO(EIGEN_REPORT_NOT_FOUND REASON_MSG) + UNSET(EIGEN_FOUND) + UNSET(EIGEN_INCLUDE_DIRS) + # Make results of search visible in the CMake GUI if Eigen has not + # been found so that user does not have to toggle to advanced view. + MARK_AS_ADVANCED(CLEAR EIGEN_INCLUDE_DIR) + # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() + # use the camelcase library name, not uppercase. + IF (Eigen_FIND_QUIETLY) + MESSAGE(STATUS "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + ELSEIF (Eigen_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + ELSE() + # Neither QUIETLY nor REQUIRED, use no priority which emits a message + # but continues configuration and allows generation. + MESSAGE("-- Failed to find Eigen - " ${REASON_MSG} ${ARGN}) + ENDIF () +ENDMACRO(EIGEN_REPORT_NOT_FOUND) + +# Search user-installed locations first, so that we prefer user installs +# to system installs where both exist. +# +# TODO: Add standard Windows search locations for Eigen. +LIST(APPEND EIGEN_CHECK_INCLUDE_DIRS + /usr/local/include/eigen3 + /usr/local/homebrew/include/eigen3 # Mac OS X + /opt/local/var/macports/software/eigen3 # Mac OS X. + /opt/local/include/eigen3 + /usr/include/eigen3) + +# Search supplied hint directories first if supplied. +FIND_PATH(EIGEN_INCLUDE_DIR + NAMES Eigen/Core + PATHS ${EIGEN_INCLUDE_DIR_HINTS} + ${EIGEN_CHECK_INCLUDE_DIRS}) +IF (NOT EIGEN_INCLUDE_DIR OR + NOT EXISTS ${EIGEN_INCLUDE_DIR}) + EIGEN_REPORT_NOT_FOUND( + "Could not find eigen3 include directory, set EIGEN_INCLUDE_DIR to " + "path to eigen3 include directory, e.g. /usr/local/include/eigen3.") +ENDIF (NOT EIGEN_INCLUDE_DIR OR + NOT EXISTS ${EIGEN_INCLUDE_DIR}) + +# Mark internally as found, then verify. EIGEN_REPORT_NOT_FOUND() unsets +# if called. +SET(EIGEN_FOUND TRUE) + +# Extract Eigen version from Eigen/src/Core/util/Macros.h +IF (EIGEN_INCLUDE_DIR) + SET(EIGEN_VERSION_FILE ${EIGEN_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h) + IF (NOT EXISTS ${EIGEN_VERSION_FILE}) + EIGEN_REPORT_NOT_FOUND( + "Could not find file: ${EIGEN_VERSION_FILE} " + "containing version information in Eigen install located at: " + "${EIGEN_INCLUDE_DIR}.") + ELSE (NOT EXISTS ${EIGEN_VERSION_FILE}) + FILE(READ ${EIGEN_VERSION_FILE} EIGEN_VERSION_FILE_CONTENTS) + + STRING(REGEX MATCH "#define EIGEN_WORLD_VERSION [0-9]+" + EIGEN_WORLD_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + STRING(REGEX REPLACE "#define EIGEN_WORLD_VERSION ([0-9]+)" "\\1" + EIGEN_WORLD_VERSION "${EIGEN_WORLD_VERSION}") + + STRING(REGEX MATCH "#define EIGEN_MAJOR_VERSION [0-9]+" + EIGEN_MAJOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + STRING(REGEX REPLACE "#define EIGEN_MAJOR_VERSION ([0-9]+)" "\\1" + EIGEN_MAJOR_VERSION "${EIGEN_MAJOR_VERSION}") + + STRING(REGEX MATCH "#define EIGEN_MINOR_VERSION [0-9]+" + EIGEN_MINOR_VERSION "${EIGEN_VERSION_FILE_CONTENTS}") + STRING(REGEX REPLACE "#define EIGEN_MINOR_VERSION ([0-9]+)" "\\1" + EIGEN_MINOR_VERSION "${EIGEN_MINOR_VERSION}") + + # This is on a single line s/t CMake does not interpret it as a list of + # elements and insert ';' separators which would result in 3.;2.;0 nonsense. + SET(EIGEN_VERSION "${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}") + ENDIF (NOT EXISTS ${EIGEN_VERSION_FILE}) +ENDIF (EIGEN_INCLUDE_DIR) + +# Set standard CMake FindPackage variables if found. +IF (EIGEN_FOUND) + SET(EIGEN_INCLUDE_DIRS ${EIGEN_INCLUDE_DIR}) +ENDIF (EIGEN_FOUND) + +# Handle REQUIRED / QUIET optional arguments and version. +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Eigen + REQUIRED_VARS EIGEN_INCLUDE_DIRS + VERSION_VAR EIGEN_VERSION) + +# Only mark internal variables as advanced if we found Eigen, otherwise +# leave it visible in the standard GUI for the user to set manually. +IF (EIGEN_FOUND) + MARK_AS_ADVANCED(FORCE EIGEN_INCLUDE_DIR) +ENDIF (EIGEN_FOUND) diff --git a/src/boost/libs/compute/cmake/FindTBB.cmake b/src/boost/libs/compute/cmake/FindTBB.cmake new file mode 100644 index 00000000..d299fd14 --- /dev/null +++ b/src/boost/libs/compute/cmake/FindTBB.cmake @@ -0,0 +1,286 @@ +# Locate Intel Threading Building Blocks include paths and libraries +# FindTBB.cmake can be found at https://code.google.com/p/findtbb/ +# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de> +# Improvements by Gino van den Bergen <gino _at_ dtecta.com>, +# Florian Uhlig <F.Uhlig _at_ gsi.de>, +# Jiri Marsik <jiri.marsik89 _at_ gmail.com> + +# The MIT License +# +# Copyright (c) 2011 Hannes Hofmann +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler. +# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21" +# TBB_ARCH_PLATFORM is set by the build script `tbbvars[.bat|.sh|.csh], which can be found +# in the TBB installation directory (TBB_INSTALL_DIR). +# +# GvdB: Mac OS X distribution places libraries directly in lib directory. +# +# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER. +# TBB_ARCHITECTURE [ ia32 | em64t | itanium ] +# which architecture to use +# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9 +# which compiler to use (detected automatically on Windows) + +# This module respects +# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR} + +# This module defines +# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc. +# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc +# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug +# TBB_INSTALL_DIR, the base TBB install directory +# TBB_LIBRARIES, the libraries to link against to use TBB. +# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols. +# TBB_FOUND, If false, don't try to use TBB. +# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h + + +if (WIN32) + # has em64t/vc8 em64t/vc9 + # has ia32/vc7.1 ia32/vc8 ia32/vc9 + set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB") + set(_TBB_LIB_NAME "tbb") + set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") + if (MSVC71) + set (_TBB_COMPILER "vc7.1") + endif(MSVC71) + if (MSVC80) + set(_TBB_COMPILER "vc8") + endif(MSVC80) + if (MSVC90) + set(_TBB_COMPILER "vc9") + endif(MSVC90) + if(MSVC10) + set(_TBB_COMPILER "vc10") + endif(MSVC10) + # Todo: add other Windows compilers such as ICL. + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) +endif (WIN32) + +if (UNIX) + if (APPLE) + # MAC + set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions") + # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug + set(_TBB_LIB_NAME "tbb") + set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") + # default flavor on apple: ia32/cc4.0.1_os10.4.9 + # Jiri: There is no reason to presume there is only one flavor and + # that user's setting of variables should be ignored. + if(NOT TBB_COMPILER) + set(_TBB_COMPILER "cc4.0.1_os10.4.9") + elseif (NOT TBB_COMPILER) + set(_TBB_COMPILER ${TBB_COMPILER}) + endif(NOT TBB_COMPILER) + if(NOT TBB_ARCHITECTURE) + set(_TBB_ARCHITECTURE "ia32") + elseif(NOT TBB_ARCHITECTURE) + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) + endif(NOT TBB_ARCHITECTURE) + else (APPLE) + # LINUX + set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include") + set(_TBB_LIB_NAME "tbb") + set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") + set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") + set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") + # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21 + # has ia32/* + # has itanium/* + set(_TBB_COMPILER ${TBB_COMPILER}) + set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) + endif (APPLE) +endif (UNIX) + +if (CMAKE_SYSTEM MATCHES "SunOS.*") +# SUN +# not yet supported +# has em64t/cc3.4.3_kernel5.10 +# has ia32/* +endif (CMAKE_SYSTEM MATCHES "SunOS.*") + + +#-- Clear the public variables +set (TBB_FOUND "NO") + + +#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR} +# first: use CMake variable TBB_INSTALL_DIR +if (TBB_INSTALL_DIR) + set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR}) +endif (TBB_INSTALL_DIR) +# second: use environment variable +if (NOT _TBB_INSTALL_DIR) + if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR}) + endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") + # Intel recommends setting TBB21_INSTALL_DIR + if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR}) + endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") + if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR}) + endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") + if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") + set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR}) + endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") +endif (NOT _TBB_INSTALL_DIR) +# third: try to find path automatically +if (NOT _TBB_INSTALL_DIR) + if (_TBB_DEFAULT_INSTALL_DIR) + set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR}) + endif (_TBB_DEFAULT_INSTALL_DIR) +endif (NOT _TBB_INSTALL_DIR) +# sanity check +if (NOT _TBB_INSTALL_DIR) + message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}") +else (NOT _TBB_INSTALL_DIR) +# finally: set the cached CMake variable TBB_INSTALL_DIR +if (NOT TBB_INSTALL_DIR) + set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory") + mark_as_advanced(TBB_INSTALL_DIR) +endif (NOT TBB_INSTALL_DIR) + + +#-- A macro to rewrite the paths of the library. This is necessary, because +# find_library() always found the em64t/vc9 version of the TBB libs +macro(TBB_CORRECT_LIB_DIR var_name) +# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") + string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) +# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") + string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) + string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) + string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) + string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) + string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) +endmacro(TBB_CORRECT_LIB_DIR var_content) + + +#-- Look for include directory and set ${TBB_INCLUDE_DIR} +set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include) +# Jiri: tbbvars now sets the CPATH environment variable to the directory +# containing the headers. +find_path(TBB_INCLUDE_DIR + tbb/task_scheduler_init.h + PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH +) +mark_as_advanced(TBB_INCLUDE_DIR) + + +#-- Look for libraries +# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh] +if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") + set (_TBB_LIBRARY_DIR + ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM} + ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib + ) +endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") +# Jiri: This block isn't mutually exclusive with the previous one +# (hence no else), instead I test if the user really specified +# the variables in question. +if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) + # HH: deprecated + message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).") + # Jiri: It doesn't hurt to look in more places, so I store the hints from + # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER + # variables and search them both. + set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR}) +endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) + +# GvdB: Mac OS X distribution places libraries directly in lib directory. +list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib) + +# Jiri: No reason not to check the default paths. From recent versions, +# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH +# variables, which now point to the directories of the lib files. +# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS +# argument instead of the implicit PATHS as it isn't hard-coded +# but computed by system introspection. Searching the LIBRARY_PATH +# and LD_LIBRARY_PATH environment variables is now even more important +# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates +# the use of TBB built from sources. +find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) +find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + +#Extract path from TBB_LIBRARY name +get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH) + +#TBB_CORRECT_LIB_DIR(TBB_LIBRARY) +#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY) +mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY) + +#-- Look for debug libraries +# Jiri: Changed the same way as for the release libraries. +find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) +find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} + PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) + +# Jiri: Self-built TBB stores the debug libraries in a separate directory. +# Extract path from TBB_LIBRARY_DEBUG name +get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH) + +#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG) +#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG) +mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG) + + +if (TBB_INCLUDE_DIR) + if (TBB_LIBRARY) + set (TBB_FOUND "YES") + set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES}) + set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES}) + set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE) + set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE) + # Jiri: Self-built TBB stores the debug libraries in a separate directory. + set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE) + mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES) + message(STATUS "Found Intel TBB") + endif (TBB_LIBRARY) +endif (TBB_INCLUDE_DIR) + +if (NOT TBB_FOUND) + message("ERROR: Intel TBB NOT found!") + message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}") + # do only throw fatal, if this pkg is REQUIRED + if (TBB_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find TBB library. + On ubuntu try + apt-get install libtbb-dev +") + endif (TBB_FIND_REQUIRED) +endif (NOT TBB_FOUND) + +endif (NOT _TBB_INSTALL_DIR) + +if (TBB_FOUND) + set(TBB_INTERFACE_VERSION 0) + FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS) + STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}") + set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}") +endif (TBB_FOUND) diff --git a/src/boost/libs/compute/cmake/opencl/FindOpenCL.cmake b/src/boost/libs/compute/cmake/opencl/FindOpenCL.cmake new file mode 100644 index 00000000..0a60e8d1 --- /dev/null +++ b/src/boost/libs/compute/cmake/opencl/FindOpenCL.cmake @@ -0,0 +1,84 @@ +# - Try to find OpenCL +# This module tries to find an OpenCL implementation on your system. It supports +# AMD / ATI, Apple and NVIDIA implementations. +# +# To set the paths manually, define these environment variables: +# OpenCL_INCPATH - Include path (e.g. OpenCL_INCPATH=/opt/cuda/4.0/cuda/include) +# OpenCL_LIBPATH - Library path (e.h. OpenCL_LIBPATH=/usr/lib64/nvidia) +# +# Once done this will define +# OpenCL_FOUND - system has OpenCL +# OpenCL_INCLUDE_DIRS - the OpenCL include directory +# OpenCL_LIBRARIES - link these to use OpenCL + +FIND_PACKAGE(PackageHandleStandardArgs) + +SET (OpenCL_VERSION_STRING "0.1.0") +SET (OpenCL_VERSION_MAJOR 0) +SET (OpenCL_VERSION_MINOR 1) +SET (OpenCL_VERSION_PATCH 0) + +IF (APPLE) + + FIND_LIBRARY(OpenCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") + FIND_PATH(OpenCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") + FIND_PATH(_OpenCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") + +ELSE (APPLE) + + IF (WIN32) + # The AMD SDK currently installs both x86 and x86_64 libraries + # This is only a hack to find out architecture + IF( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + SET(OpenCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86_64") + ELSE( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + SET(OpenCL_LIB_DIR "$ENV{AMDAPPSDKROOT}/lib/x86") + ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + + FIND_LIBRARY(OpenCL_LIBRARIES OpenCL.lib PATHS + ${OpenCL_LIB_DIR} $ENV{OpenCL_LIBPATH} $ENV{CUDA_LIB_PATH}) + + GET_FILENAME_COMPONENT(_OpenCL_INC_CAND ${OpenCL_LIB_DIR}/../../include ABSOLUTE) + + # On Win32 search relative to the library + FIND_PATH(OpenCL_INCLUDE_DIRS CL/cl.h PATHS + ${_OpenCL_INC_CAND} $ENV{OpenCL_INCPATH} $ENV{CUDA_INC_PATH}) + FIND_PATH(_OpenCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS + ${_OpenCL_INC_CAND} $ENV{OpenCL_INCPATH} $ENV{CUDA_INC_PATH}) + + ELSE (WIN32) + + # Unix style platforms + FIND_LIBRARY(OpenCL_LIBRARIES OpenCL + PATHS ENV LD_LIBRARY_PATH ENV OpenCL_LIBPATH + ) + + GET_FILENAME_COMPONENT(OpenCL_LIB_DIR ${OpenCL_LIBRARIES} PATH) + GET_FILENAME_COMPONENT(_OpenCL_INC_CAND ${OpenCL_LIB_DIR}/../../include ABSOLUTE) + + # The AMD SDK currently does not place its headers + # in /usr/include, therefore also search relative + # to the library + FIND_PATH(OpenCL_INCLUDE_DIRS CL/cl.h PATHS "$ENV{CUDADIR}/include" ${_OpenCL_INC_CAND} "/usr/local/cuda/include" "/opt/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) + FIND_PATH(_OpenCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "$ENV{CUDADIR}/include" ${_OpenCL_INC_CAND} "/usr/local/cuda/include" "/opt/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) + # for Mali GPUs, libmali must be linked + FIND_LIBRARY(OpenCL_LIBRARIES_MALI mali + PATHS ENV LD_LIBRARY_PATH ENV OpenCL_LIBPATH "/usr/lib64" "$ENV{CUDADIR}/lib64" + ) + IF (OpenCL_LIBRARIES_MALI) + SET(OpenCL_LIBRARIES ${OpenCL_LIBRARIES} ${OpenCL_LIBRARIES_MALI}) + ENDIF (OpenCL_LIBRARIES_MALI) + ENDIF (WIN32) + +ENDIF (APPLE) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenCL DEFAULT_MSG OpenCL_LIBRARIES OpenCL_INCLUDE_DIRS) + +IF(_OpenCL_CPP_INCLUDE_DIRS) + SET( OpenCL_HAS_CPP_BINDINGS TRUE ) + LIST( APPEND OpenCL_INCLUDE_DIRS ${_OpenCL_CPP_INCLUDE_DIRS} ) + # This is often the same, so clean up + LIST( REMOVE_DUPLICATES OpenCL_INCLUDE_DIRS ) +ENDIF(_OpenCL_CPP_INCLUDE_DIRS) + +MARK_AS_ADVANCED( OpenCL_INCLUDE_DIRS ) diff --git a/src/boost/libs/compute/example/CMakeLists.txt b/src/boost/libs/compute/example/CMakeLists.txt new file mode 100644 index 00000000..a5708cb0 --- /dev/null +++ b/src/boost/libs/compute/example/CMakeLists.txt @@ -0,0 +1,166 @@ +# --------------------------------------------------------------------------- +# 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 +# +# --------------------------------------------------------------------------- + +include_directories(../include) + +set(EXAMPLES + amd_cpp_kernel + black_scholes + copy_data + fizz_buzz + hello_world + host_sort + inline_ptx + longest_vector + list_devices + mapped_view + memory_limits + monte_carlo + point_centroid + price_cross + print_vector + sort_vector + simple_kernel + time_copy + transform_sqrt + vector_addition + simple_moving_average + matrix_transpose +) + +# boost library link dependencies +set(EXAMPLE_BOOST_COMPONENTS program_options) + +if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) + set(EXAMPLE_BOOST_COMPONENTS ${EXAMPLE_BOOST_COMPONENTS} system filesystem) +endif() + +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(EXAMPLE_BOOST_COMPONENTS ${EXAMPLE_BOOST_COMPONENTS} system thread) +endif() + +if(MSVC AND EXAMPLE_BOOST_COMPONENTS) + set(EXAMPLE_BOOST_COMPONENTS ${EXAMPLE_BOOST_COMPONENTS} chrono) +endif() + +if(EXAMPLE_BOOST_COMPONENTS) + list(REMOVE_DUPLICATES EXAMPLE_BOOST_COMPONENTS) +endif() +find_package(Boost 1.54 REQUIRED COMPONENTS ${EXAMPLE_BOOST_COMPONENTS}) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + +foreach(EXAMPLE ${EXAMPLES}) + add_executable(${EXAMPLE} ${EXAMPLE}.cpp) + target_link_libraries(${EXAMPLE} ${OpenCL_LIBRARIES} ${Boost_LIBRARIES}) + + # add example program to list of tests (if testing is enabled) + if(${BOOST_COMPUTE_BUILD_TESTS}) + add_test("example.${EXAMPLE}" ${EXAMPLE}) + endif() +endforeach() + +# opencl test example +add_executable(opencl_test opencl_test.cpp) +target_link_libraries(opencl_test ${OpenCL_LIBRARIES}) + +# eigen examples +if(${BOOST_COMPUTE_HAVE_EIGEN}) + find_package(Eigen REQUIRED) + include_directories(SYSTEM ${EIGEN_INCLUDE_DIRS}) + add_executable(batched_determinant batched_determinant.cpp) + target_link_libraries(batched_determinant ${OpenCL_LIBRARIES} ${Boost_LIBRARIES}) +endif() + +# opencv examples +if(${BOOST_COMPUTE_HAVE_OPENCV}) + find_package(OpenCV REQUIRED) + include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS}) + + set(OPENCV_EXAMPLES + k_means + opencv_flip + random_walk + opencv_optical_flow + opencv_convolution + opencv_sobel_filter + opencv_histogram + ) + + foreach(EXAMPLE ${OPENCV_EXAMPLES}) + add_executable(${EXAMPLE} ${EXAMPLE}.cpp) + target_link_libraries(${EXAMPLE} ${OpenCL_LIBRARIES} ${Boost_LIBRARIES} ${OpenCV_LIBS}) + endforeach() +endif() + +# opengl/vtk examples +if(${BOOST_COMPUTE_HAVE_VTK}) + find_package(VTK REQUIRED) + include(${VTK_USE_FILE}) + add_executable(opengl_sphere opengl_sphere.cpp) + target_link_libraries(opengl_sphere ${OpenCL_LIBRARIES} ${Boost_LIBRARIES} ${VTK_LIBRARIES}) + if(APPLE) + target_link_libraries(opengl_sphere "-framework OpenGL") + elseif(UNIX) + target_link_libraries(opengl_sphere GL) + endif() +endif() + +# qt examples +if(${BOOST_COMPUTE_HAVE_QT}) + + # look for Qt4 in the first place + find_package(Qt4 QUIET) + + if(${QT4_FOUND}) + # build with Qt4 + find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtOpenGL) + set(QT_USE_QTOPENGL TRUE) + include(${QT_USE_FILE}) + else() + + # look for Qt5 + find_package(Qt5Widgets QUIET) + + if(${Qt5Widgets_FOUND}) + # build with Qt5 + find_package(Qt5Core REQUIRED) + find_package(Qt5Widgets REQUIRED) + find_package(Qt5OpenGL REQUIRED) + include_directories(${Qt5OpenGL_INCLUDE_DIRS}) + 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() + + # required by both versions + set(CMAKE_AUTOMOC TRUE) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + # add examples + add_executable(qimage_blur qimage_blur.cpp) + target_link_libraries(qimage_blur ${OpenCL_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES}) + + set(QT_OPENGL_EXAMPLES + mandelbrot + nbody + resize_image + ) + foreach(EXAMPLE ${QT_OPENGL_EXAMPLES}) + add_executable(${EXAMPLE} ${EXAMPLE}.cpp) + target_link_libraries(${EXAMPLE} ${OpenCL_LIBRARIES} ${Boost_LIBRARIES} ${QT_LIBRARIES}) + if(APPLE) + target_link_libraries(${EXAMPLE} "-framework OpenGL") + elseif(UNIX) + target_link_libraries(${EXAMPLE} GL) + endif() + endforeach() +endif() diff --git a/src/boost/libs/compute/example/amd_cpp_kernel.cpp b/src/boost/libs/compute/example/amd_cpp_kernel.cpp new file mode 100644 index 00000000..0207312f --- /dev/null +++ b/src/boost/libs/compute/example/amd_cpp_kernel.cpp @@ -0,0 +1,116 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/kernel.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// this example shows how to use the static c++ kernel language +// extension (currently only supported by AMD) to compile and +// execute a templated c++ kernel. +// Using platform vendor info to decide if this is AMD platform +int main() +{ + // get default device and setup context + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + // check the platform vendor string + if(device.platform().vendor() != "Advanced Micro Devices, Inc."){ + std::cerr << "error: static C++ kernel language is only " + << "supported on AMD devices." + << std::endl; + return 0; + } + + // create input int values and copy them to the device + int int_data[] = { 1, 2, 3, 4}; + compute::vector<int> int_vector(int_data, int_data + 4, queue); + + // create input float values and copy them to the device + float float_data[] = { 2.0f, 4.0f, 6.0f, 8.0f }; + compute::vector<float> float_vector(float_data, float_data + 4, queue); + + // create kernel source with a templated function and templated kernel + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // define our templated function which returns the square of its input + template<typename T> + inline T square(const T x) + { + return x * x; + } + + // define our templated kernel which calls square on each value in data + template<typename T> + __kernel void square_kernel(__global T *data) + { + const uint i = get_global_id(0); + data[i] = square(data[i]); + } + + // explicitly instantiate the square kernel for int's. this allows + // for it to be called from the host with the given mangled name. + template __attribute__((mangled_name(square_kernel_int))) + __kernel void square_kernel(__global int *data); + + // also instantiate the square kernel for float's. + template __attribute__((mangled_name(square_kernel_float))) + __kernel void square_kernel(__global float *data); + ); + + // build the program. must enable the c++ static kernel language + // by passing the "-x clc++" compile option. + compute::program square_program = + compute::program::build_with_source(source, context, "-x clc++"); + + // create the square kernel for int's by using its mangled name declared + // in the explicit template instantiation. + compute::kernel square_int_kernel(square_program, "square_kernel_int"); + square_int_kernel.set_arg(0, int_vector); + + // execute the square int kernel + queue.enqueue_1d_range_kernel(square_int_kernel, 0, int_vector.size(), 4); + + // print out the squared int values + std::cout << "int's: "; + compute::copy( + int_vector.begin(), int_vector.end(), + std::ostream_iterator<int>(std::cout, " "), + queue + ); + std::cout << std::endl; + + // now create the square kernel for float's + compute::kernel square_float_kernel(square_program, "square_kernel_float"); + square_float_kernel.set_arg(0, float_vector); + + // execute the square int kernel + queue.enqueue_1d_range_kernel(square_float_kernel, 0, float_vector.size(), 4); + + // print out the squared float values + std::cout << "float's: "; + compute::copy( + float_vector.begin(), float_vector.end(), + std::ostream_iterator<float>(std::cout, " "), + queue + ); + std::cout << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/batched_determinant.cpp b/src/boost/libs/compute/example/batched_determinant.cpp new file mode 100644 index 00000000..0029151e --- /dev/null +++ b/src/boost/libs/compute/example/batched_determinant.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. +//---------------------------------------------------------------------------// + +#include <iostream> + +#include <Eigen/Core> +#include <Eigen/LU> + +#include <boost/compute/function.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +namespace compute = boost::compute; + +// this example shows how to compute the determinant of many 4x4 matrices +// using a determinant function and the transform() algorithm. in OpenCL the +// float16 type can be used to store a 4x4 matrix and the components are laid +// out in the following order: +// +// M = [ s0 s4 s8 sc ] +// [ s1 s5 s9 sd ] +// [ s2 s6 sa se ] +// [ s3 s7 sb sf ] +// +// the input matrices are created using eigen's random matrix and then +// used again at the end to verify the results of the determinant function. +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + size_t n = 1000; + + // create random 4x4 matrices on the host + std::vector<Eigen::Matrix4f> matrices(n); + for(size_t i = 0; i < n; i++){ + matrices[i] = Eigen::Matrix4f::Random(); + } + + // copy matrices to the device + using compute::float16_; + compute::vector<float16_> input(n, context); + compute::copy( + matrices.begin(), matrices.end(), input.begin(), queue + ); + + // function returning the determinant of a 4x4 matrix. + BOOST_COMPUTE_FUNCTION(float, determinant4x4, (const float16_ m), + { + return m.s0*m.s5*m.sa*m.sf + m.s0*m.s6*m.sb*m.sd + m.s0*m.s7*m.s9*m.se + + m.s1*m.s4*m.sb*m.se + m.s1*m.s6*m.s8*m.sf + m.s1*m.s7*m.sa*m.sc + + m.s2*m.s4*m.s9*m.sf + m.s2*m.s5*m.sb*m.sc + m.s2*m.s7*m.s8*m.sd + + m.s3*m.s4*m.sa*m.sd + m.s3*m.s5*m.s8*m.se + m.s3*m.s6*m.s9*m.sc - + m.s0*m.s5*m.sb*m.se - m.s0*m.s6*m.s9*m.sf - m.s0*m.s7*m.sa*m.sd - + m.s1*m.s4*m.sa*m.sf - m.s1*m.s6*m.sb*m.sc - m.s1*m.s7*m.s8*m.se - + m.s2*m.s4*m.sb*m.sd - m.s2*m.s5*m.s8*m.sf - m.s2*m.s7*m.s9*m.sc - + m.s3*m.s4*m.s9*m.se - m.s3*m.s5*m.sa*m.sc - m.s3*m.s6*m.s8*m.sd; + }); + + // calculate determinants on the gpu + compute::vector<float> determinants(n, context); + compute::transform( + input.begin(), input.end(), determinants.begin(), determinant4x4, queue + ); + + // check determinants + std::vector<float> host_determinants(n); + compute::copy( + determinants.begin(), determinants.end(), host_determinants.begin(), queue + ); + + for(size_t i = 0; i < n; i++){ + float det = matrices[i].determinant(); + + if(std::abs(det - host_determinants[i]) > 1e-6){ + std::cerr << "error: wrong determinant at " << i << " (" + << host_determinants[i] << " != " << det << ")" + << std::endl; + return -1; + } + } + + return 0; +} diff --git a/src/boost/libs/compute/example/black_scholes.cpp b/src/boost/libs/compute/example/black_scholes.cpp new file mode 100644 index 00000000..13a0e097 --- /dev/null +++ b/src/boost/libs/compute/example/black_scholes.cpp @@ -0,0 +1,168 @@ +//---------------------------------------------------------------------------// +// 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 <cstdlib> +#include <iostream> + +#include <boost/compute/command_queue.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// return a random float between lo and hi +float rand_float(float lo, float hi) +{ + float x = (float) std::rand() / (float) RAND_MAX; + + return (1.0f - x) * lo + x * hi; +} + +// this example demostrates a black-scholes option pricing kernel. +int main() +{ + // number of options + const int N = 4000000; + + // black-scholes parameters + const float risk_free_rate = 0.02f; + const float volatility = 0.30f; + + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // initialize option data on host + std::vector<float> stock_price_data(N); + std::vector<float> option_strike_data(N); + std::vector<float> option_years_data(N); + + std::srand(5347); + for(int i = 0; i < N; i++){ + stock_price_data[i] = rand_float(5.0f, 30.0f); + option_strike_data[i] = rand_float(1.0f, 100.0f); + option_years_data[i] = rand_float(0.25f, 10.0f); + } + + // create memory buffers on the device + compute::vector<float> call_result(N, context); + compute::vector<float> put_result(N, context); + compute::vector<float> stock_price(N, context); + compute::vector<float> option_strike(N, context); + compute::vector<float> option_years(N, context); + + // copy initial values to the device + compute::copy_n(stock_price_data.begin(), N, stock_price.begin(), queue); + compute::copy_n(option_strike_data.begin(), N, option_strike.begin(), queue); + compute::copy_n(option_years_data.begin(), N, option_years.begin(), queue); + + // source code for black-scholes program + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // approximation of the cumulative normal distribution function + static float cnd(float d) + { + const float A1 = 0.319381530f; + const float A2 = -0.356563782f; + const float A3 = 1.781477937f; + const float A4 = -1.821255978f; + const float A5 = 1.330274429f; + const float RSQRT2PI = 0.39894228040143267793994605993438f; + + float K = 1.0f / (1.0f + 0.2316419f * fabs(d)); + float cnd = + RSQRT2PI * exp(-0.5f * d * d) * + (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5))))); + + if(d > 0){ + cnd = 1.0f - cnd; + } + + return cnd; + } + + // black-scholes option pricing kernel + __kernel void black_scholes(__global float *call_result, + __global float *put_result, + __global const float *stock_price, + __global const float *option_strike, + __global const float *option_years, + float risk_free_rate, + float volatility) + { + const uint opt = get_global_id(0); + + float S = stock_price[opt]; + float X = option_strike[opt]; + float T = option_years[opt]; + float R = risk_free_rate; + float V = volatility; + + float sqrtT = sqrt(T); + float d1 = (log(S / X) + (R + 0.5f * V * V) * T) / (V * sqrtT); + float d2 = d1 - V * sqrtT; + float CNDD1 = cnd(d1); + float CNDD2 = cnd(d2); + + float expRT = exp(-R * T); + call_result[opt] = S * CNDD1 - X * expRT * CNDD2; + put_result[opt] = X * expRT * (1.0f - CNDD2) - S * (1.0f - CNDD1); + } + ); + + // build black-scholes program + compute::program program = compute::program::create_with_source(source, context); + program.build(); + + // setup black-scholes kernel + compute::kernel kernel(program, "black_scholes"); + kernel.set_arg(0, call_result); + kernel.set_arg(1, put_result); + kernel.set_arg(2, stock_price); + kernel.set_arg(3, option_strike); + kernel.set_arg(4, option_years); + kernel.set_arg(5, risk_free_rate); + kernel.set_arg(6, volatility); + + // execute black-scholes kernel + queue.enqueue_1d_range_kernel(kernel, 0, N, 0); + + // print out the first option's put and call prices + float call0, put0; + compute::copy_n(put_result.begin(), 1, &put0, queue); + compute::copy_n(call_result.begin(), 1, &call0, queue); + + std::cout << "option 0 call price: " << call0 << std::endl; + std::cout << "option 0 put price: " << put0 << std::endl; + + // due to the differences in the random-number generators between Operating Systems + // and/or compilers, we will get different "expected" results for this example +#ifdef __APPLE__ + double expected_call0 = 0.000249461; + double expected_put0 = 26.2798; +#elif _MSC_VER + double expected_call0 = 8.21412; + double expected_put0 = 2.25904; +#else + double expected_call0 = 0.0999f; + double expected_put0 = 43.0524f; +#endif + + // check option prices + if(std::abs(call0 - expected_call0) > 1e-4 || std::abs(put0 - expected_put0) > 1e-4){ + std::cerr << "error: option prices are wrong" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/example/copy_data.cpp b/src/boost/libs/compute/example/copy_data.cpp new file mode 100644 index 00000000..0550287f --- /dev/null +++ b/src/boost/libs/compute/example/copy_data.cpp @@ -0,0 +1,49 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +//[copy_data_example + +#include <vector> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get default device and setup context + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + // create data array on host + int host_data[] = { 1, 3, 5, 7, 9 }; + + // create vector on device + compute::vector<int> device_vector(5, context); + + // copy from host to device + compute::copy( + host_data, host_data + 5, device_vector.begin(), queue + ); + + // create vector on host + std::vector<int> host_vector(5); + + // copy data back to host + compute::copy( + device_vector.begin(), device_vector.end(), host_vector.begin(), queue + ); + + return 0; +} + +//] diff --git a/src/boost/libs/compute/example/fizz_buzz.cpp b/src/boost/libs/compute/example/fizz_buzz.cpp new file mode 100644 index 00000000..2c69995f --- /dev/null +++ b/src/boost/libs/compute/example/fizz_buzz.cpp @@ -0,0 +1,160 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/accumulate.hpp> +#include <boost/compute/algorithm/exclusive_scan.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +const char fizz_buzz_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // returns the length of the string for the number 'n'. This is used + // during the first pass when we calculate the amount of space needed + // for each string in the fizz-buzz sequence. + inline uint fizz_buzz_string_length(uint n) + { + if((n % 5 == 0) && (n % 3 == 0)){ + return sizeof("fizzbuzz"); + } + else if(n % 5 == 0){ + return sizeof("fizz"); + } + else if(n % 3 == 0){ + return sizeof("buzz"); + } + else { + uint digits = 0; + while(n){ + n /= 10; + digits++; + } + return digits + 1; + } + } + + // first-pass kernel which calculates the string length for each number + // and writes it to the string_lengths array. these will then be passed + // to exclusive_scan() to calculate the output offsets for each string. + __kernel void fizz_buzz_allocate_strings(__global uint *string_lengths) + { + const uint i = get_global_id(0); + const uint n = i + 1; + + string_lengths[i] = fizz_buzz_string_length(n); + } + + // copy the string 's' with length 'n' to 'result' (just like strncpy()) + inline void copy_string(__constant const char *s, uint n, __global char *result) + { + while(n--){ + result[n] = s[n]; + } + } + + // reverse the string [start, end). + inline void reverse_string(__global char *start, __global char *end) + { + while(start < end){ + char tmp = *end; + *end = *start; + *start = tmp; + start++; + end--; + } + } + + // second-pass kernel which copies the fizz-buzz string for each number to + // buffer using the previously calculated offsets. + __kernel void fizz_buzz_copy_strings(__global const uint *offsets, __global char *buffer) + { + const uint i = get_global_id(0); + const uint n = i + 1; + const uint offset = offsets[i]; + + if((n % 5 == 0) && (n % 3 == 0)){ + copy_string("fizzbuzz\n", 9, buffer + offset); + } + else if(n % 5 == 0){ + copy_string("fizz\n", 5, buffer + offset); + } + else if(n % 3 == 0){ + copy_string("buzz\n", 5, buffer + offset); + } + else { + // convert number to string and write it to the output + __global char *number = buffer + offset; + uint n_ = n; + while(n_){ + *number++ = (n_%10) + '0'; + n_ /= 10; + } + reverse_string(buffer + offset, number - 1); + *number = '\n'; + } + } +); + +int main() +{ + using compute::dim; + using compute::uint_; + + // fizz-buzz up to 100 + size_t n = 100; + + // get the default device + compute::device device = compute::system::default_device(); + compute::context ctx(device); + compute::command_queue queue(ctx, device); + + // compile the fizz-buzz program + compute::program fizz_buzz_program = + compute::program::create_with_source(fizz_buzz_source, ctx); + fizz_buzz_program.build(); + + // create a vector for the output string and computing offsets + compute::vector<char> output(ctx); + compute::vector<uint_> offsets(n, ctx); + + // run the allocate kernel to calculate string lengths + compute::kernel allocate_kernel(fizz_buzz_program, "fizz_buzz_allocate_strings"); + allocate_kernel.set_arg(0, offsets); + queue.enqueue_nd_range_kernel(allocate_kernel, dim(0), dim(n), dim(1)); + + // allocate space for the output string + output.resize( + compute::accumulate(offsets.begin(), offsets.end(), 0, queue) + ); + + // scan string lengths for each number to calculate the output offsets + compute::exclusive_scan( + offsets.begin(), offsets.end(), offsets.begin(), queue + ); + + // run the copy kernel to fill the output buffer + compute::kernel copy_kernel(fizz_buzz_program, "fizz_buzz_copy_strings"); + copy_kernel.set_arg(0, offsets); + copy_kernel.set_arg(1, output); + queue.enqueue_nd_range_kernel(copy_kernel, dim(0), dim(n), dim(1)); + + // copy the string to the host and print it to stdout + std::string str; + str.resize(output.size()); + compute::copy(output.begin(), output.end(), str.begin(), queue); + std::cout << str; + + return 0; +} diff --git a/src/boost/libs/compute/example/hello_world.cpp b/src/boost/libs/compute/example/hello_world.cpp new file mode 100644 index 00000000..ef45fdd6 --- /dev/null +++ b/src/boost/libs/compute/example/hello_world.cpp @@ -0,0 +1,30 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +//[hello_world_example + +#include <iostream> + +#include <boost/compute/core.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get the default device + compute::device device = compute::system::default_device(); + + // print the device's name and platform + std::cout << "hello from " << device.name(); + std::cout << " (platform: " << device.platform().name() << ")" << std::endl; + + return 0; +} +//] diff --git a/src/boost/libs/compute/example/host_sort.cpp b/src/boost/libs/compute/example/host_sort.cpp new file mode 100644 index 00000000..b5ff52cf --- /dev/null +++ b/src/boost/libs/compute/example/host_sort.cpp @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <vector> + +#include <boost/spirit/include/karma.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/sort.hpp> + +namespace compute = boost::compute; +namespace karma = boost::spirit::karma; + +int rand_int() +{ + return rand() % 100; +} + +// this example demonstrates how to sort a std::vector of ints on the GPU +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // create vector of random values on the host + std::vector<int> vector(8); + std::generate(vector.begin(), vector.end(), rand_int); + + // print input vector + std::cout << "input: [ " + << karma::format(karma::int_ % ", ", vector) + << " ]" + << std::endl; + + // sort vector + compute::sort(vector.begin(), vector.end(), queue); + + // print sorted vector + std::cout << "output: [ " + << karma::format(karma::int_ % ", ", vector) + << " ]" + << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/inline_ptx.cpp b/src/boost/libs/compute/example/inline_ptx.cpp new file mode 100644 index 00000000..fe4e32f0 --- /dev/null +++ b/src/boost/libs/compute/example/inline_ptx.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> + +namespace compute = boost::compute; + +// this example shows how to embed PTX assembly instructions +// directly into boost.compute functions and use them with the +// transform() algorithm. +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // check to ensure we have an nvidia device + if(gpu.vendor() != "NVIDIA Corporation"){ + std::cerr << "error: inline PTX assembly is only supported " + << "on NVIDIA devices." + << std::endl; + return 0; + } + + // create input values and copy them to the device + using compute::uint_; + uint_ data[] = { 0x00, 0x01, 0x11, 0xFF }; + compute::vector<uint_> input(data, data + 4, queue); + + // function returning the number of bits set (aka population count or + // popcount) using the "popc" inline ptx assembly instruction. + BOOST_COMPUTE_FUNCTION(uint_, nvidia_popc, (uint_ x), + { + uint count; + asm("popc.b32 %0, %1;" : "=r"(count) : "r"(x)); + return count; + }); + + // calculate the popcount for each input value + compute::vector<uint_> output(input.size(), context); + compute::transform( + input.begin(), input.end(), output.begin(), nvidia_popc, queue + ); + + // copy results back to the host and print them out + std::vector<uint_> counts(output.size()); + compute::copy(output.begin(), output.end(), counts.begin(), queue); + + for(size_t i = 0; i < counts.size(); i++){ + std::cout << "0x" << std::hex << data[i] + << " has " << counts[i] + << " bits set" << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/compute/example/k_means.cpp b/src/boost/libs/compute/example/k_means.cpp new file mode 100644 index 00000000..cd291a9b --- /dev/null +++ b/src/boost/libs/compute/example/k_means.cpp @@ -0,0 +1,229 @@ +//---------------------------------------------------------------------------// +// 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 <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/image/image2d.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/uniform_real_distribution.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +using compute::dim; +using compute::int_; +using compute::float_; +using compute::float2_; + +// the k-means example implements the k-means clustering algorithm +int main() +{ + // number of clusters + size_t k = 6; + + // number of points + size_t n_points = 4500; + + // height and width of image + size_t height = 800; + size_t width = 800; + + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + // generate random, uniformily-distributed points + compute::default_random_engine random_engine(queue); + compute::uniform_real_distribution<float_> uniform_distribution(0, 800); + + compute::vector<float2_> points(n_points, context); + uniform_distribution.generate( + compute::make_buffer_iterator<float_>(points.get_buffer(), 0), + compute::make_buffer_iterator<float_>(points.get_buffer(), n_points * 2), + random_engine, + queue + ); + + // initialize all points to cluster 0 + compute::vector<int_> clusters(n_points, context); + compute::fill(clusters.begin(), clusters.end(), 0, queue); + + // create initial means with the first k points + compute::vector<float2_> means(k, context); + compute::copy_n(points.begin(), k, means.begin(), queue); + + // k-means clustering program source + const char k_means_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void assign_clusters(__global const float2 *points, + __global const float2 *means, + const int k, + __global int *clusters) + { + const uint gid = get_global_id(0); + + const float2 point = points[gid]; + + // find the closest cluster + float current_distance = 0; + int closest_cluster = -1; + + // find closest cluster mean to the point + for(int i = 0; i < k; i++){ + const float2 mean = means[i]; + + int distance_to_mean = distance(point, mean); + if(closest_cluster == -1 || distance_to_mean < current_distance){ + current_distance = distance_to_mean; + closest_cluster = i; + } + } + + // write new cluster + clusters[gid] = closest_cluster; + } + + __kernel void update_means(__global const float2 *points, + const uint n_points, + __global float2 *means, + __global const int *clusters) + { + const uint k = get_global_id(0); + + float2 sum = { 0, 0 }; + float count = 0; + for(uint i = 0; i < n_points; i++){ + if(clusters[i] == k){ + sum += points[i]; + count += 1; + } + } + + means[k] = sum / count; + } + ); + + // build the k-means program + compute::program k_means_program = + compute::program::build_with_source(k_means_source, context); + + // setup the k-means kernels + compute::kernel assign_clusters_kernel(k_means_program, "assign_clusters"); + assign_clusters_kernel.set_arg(0, points); + assign_clusters_kernel.set_arg(1, means); + assign_clusters_kernel.set_arg(2, int_(k)); + assign_clusters_kernel.set_arg(3, clusters); + + compute::kernel update_means_kernel(k_means_program, "update_means"); + update_means_kernel.set_arg(0, points); + update_means_kernel.set_arg(1, int_(n_points)); + update_means_kernel.set_arg(2, means); + update_means_kernel.set_arg(3, clusters); + + // run the k-means algorithm + for(int iteration = 0; iteration < 25; iteration++){ + queue.enqueue_1d_range_kernel(assign_clusters_kernel, 0, n_points, 0); + queue.enqueue_1d_range_kernel(update_means_kernel, 0, k, 0); + } + + // create output image + compute::image2d image( + context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8) + ); + + // program with two kernels, one to fill the image with white, and then + // one the draw to points calculated in coordinates on the image + const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void draw_points(__global const float2 *points, + __global const int *clusters, + __write_only image2d_t image) + { + const uint i = get_global_id(0); + const float2 coord = points[i]; + + // map cluster number to color + uint4 color = { 0, 0, 0, 0 }; + switch(clusters[i]){ + case 0: + color = (uint4)(255, 0, 0, 255); + break; + case 1: + color = (uint4)(0, 255, 0, 255); + break; + case 2: + color = (uint4)(0, 0, 255, 255); + break; + case 3: + color = (uint4)(255, 255, 0, 255); + break; + case 4: + color = (uint4)(255, 0, 255, 255); + break; + case 5: + color = (uint4)(0, 255, 255, 255); + break; + } + + // draw a 3x3 pixel point + for(int x = -1; x <= 1; x++){ + for(int y = -1; y <= 1; y++){ + if(coord.x + x > 0 && coord.x + x < get_image_width(image) && + coord.y + y > 0 && coord.y + y < get_image_height(image)){ + write_imageui(image, (int2)(coord.x, coord.y) + (int2)(x, y), color); + } + } + } + } + + __kernel void fill_gray(__write_only image2d_t image) + { + const int2 coord = { get_global_id(0), get_global_id(1) }; + + if(coord.x < get_image_width(image) && coord.y < get_image_height(image)){ + uint4 gray = { 15, 15, 15, 15 }; + write_imageui(image, coord, gray); + } + } + ); + + // build the program + compute::program draw_program = + compute::program::build_with_source(draw_walk_source, context); + + // fill image with dark gray + compute::kernel fill_kernel(draw_program, "fill_gray"); + fill_kernel.set_arg(0, image); + + queue.enqueue_nd_range_kernel( + fill_kernel, dim(0, 0), dim(width, height), dim(1, 1) + ); + + // draw points colored according to cluster + compute::kernel draw_kernel(draw_program, "draw_points"); + draw_kernel.set_arg(0, points); + draw_kernel.set_arg(1, clusters); + draw_kernel.set_arg(2, image); + queue.enqueue_1d_range_kernel(draw_kernel, 0, n_points, 0); + + // show image + compute::opencv_imshow("k-means", image, queue); + + // wait and return + cv::waitKey(0); + + return 0; +} diff --git a/src/boost/libs/compute/example/list_devices.cpp b/src/boost/libs/compute/example/list_devices.cpp new file mode 100644 index 00000000..b7bdbc94 --- /dev/null +++ b/src/boost/libs/compute/example/list_devices.cpp @@ -0,0 +1,45 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <boost/compute/core.hpp> + +namespace compute = boost::compute; + +int main() +{ + std::vector<compute::platform> platforms = compute::system::platforms(); + + for(size_t i = 0; i < platforms.size(); i++){ + const compute::platform &platform = platforms[i]; + + std::cout << "Platform '" << platform.name() << "'" << std::endl; + + std::vector<compute::device> devices = platform.devices(); + for(size_t j = 0; j < devices.size(); j++){ + const compute::device &device = devices[j]; + + std::string type; + if(device.type() & compute::device::gpu) + type = "GPU Device"; + else if(device.type() & compute::device::cpu) + type = "CPU Device"; + else if(device.type() & compute::device::accelerator) + type = "Accelerator Device"; + else + type = "Unknown Device"; + + std::cout << " " << type << ": " << device.name() << std::endl; + } + } + + return 0; +} diff --git a/src/boost/libs/compute/example/longest_vector.cpp b/src/boost/libs/compute/example/longest_vector.cpp new file mode 100644 index 00000000..faada332 --- /dev/null +++ b/src/boost/libs/compute/example/longest_vector.cpp @@ -0,0 +1,58 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <iterator> + +#include <boost/compute/algorithm/max_element.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/geometry.hpp> +#include <boost/compute/iterator/transform_iterator.hpp> +#include <boost/compute/types/fundamental.hpp> + +namespace compute = boost::compute; + +// this example shows how to use the max_element() algorithm along with +// a transform_iterator and the length() function to find the longest +// 4-component vector in an array of vectors +int main() +{ + using compute::float4_; + + // vectors data + float data[] = { 1.0f, 2.0f, 3.0f, 0.0f, + 4.0f, 5.0f, 6.0f, 0.0f, + 7.0f, 8.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f }; + + // create device vector with the vector data + compute::vector<float4_> vector( + reinterpret_cast<float4_ *>(data), + reinterpret_cast<float4_ *>(data) + 4 + ); + + // find the longest vector + compute::vector<float4_>::const_iterator iter = + compute::max_element( + compute::make_transform_iterator( + vector.begin(), compute::length<float4_>() + ), + compute::make_transform_iterator( + vector.end(), compute::length<float4_>() + ) + ).base(); + + // print the index of the longest vector + std::cout << "longest vector index: " + << std::distance(vector.begin(), iter) + << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/mandelbrot.cpp b/src/boost/libs/compute/example/mandelbrot.cpp new file mode 100644 index 00000000..5ddb3687 --- /dev/null +++ b/src/boost/libs/compute/example/mandelbrot.cpp @@ -0,0 +1,224 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <algorithm> + +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtWidgets> +#else +#include <QtGui> +#endif +#include <QtOpenGL> + +#ifndef Q_MOC_RUN +#include <boost/compute/command_queue.hpp> +#include <boost/compute/kernel.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/interop/opengl.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> +#endif // Q_MOC_RUN + +namespace compute = boost::compute; + +// opencl source code +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + // map value to color + float4 color(uint i) + { + uchar c = i; + uchar x = 35; + uchar y = 25; + uchar z = 15; + uchar max = 255; + + if(i == 256) + return (float4)(0, 0, 0, 255); + else + return (float4)(max-x*i, max-y*i, max-z*i, max) / 255.f; + } + + __kernel void mandelbrot(__write_only image2d_t image) + { + const uint x_coord = get_global_id(0); + const uint y_coord = get_global_id(1); + const uint width = get_global_size(0); + const uint height = get_global_size(1); + + float x_origin = ((float) x_coord / width) * 3.25f - 2.0f; + float y_origin = ((float) y_coord / height) * 2.5f - 1.25f; + + float x = 0.0f; + float y = 0.0f; + + uint i = 0; + while(x*x + y*y <= 4.f && i < 256){ + float tmp = x*x - y*y + x_origin; + y = 2*x*y + y_origin; + x = tmp; + i++; + } + + int2 coord = { x_coord, y_coord }; + write_imagef(image, coord, color(i)); + }; +); + +class MandelbrotWidget : public QGLWidget +{ + Q_OBJECT + +public: + MandelbrotWidget(QWidget *parent = 0); + ~MandelbrotWidget(); + + void initializeGL(); + void resizeGL(int width, int height); + void paintGL(); + void keyPressEvent(QKeyEvent* event); + +private: + compute::context context_; + compute::command_queue queue_; + compute::program program_; + GLuint gl_texture_; + compute::opengl_texture cl_texture_; +}; + +MandelbrotWidget::MandelbrotWidget(QWidget *parent) + : QGLWidget(parent) +{ + gl_texture_ = 0; +} + +MandelbrotWidget::~MandelbrotWidget() +{ +} + +void MandelbrotWidget::initializeGL() +{ + // setup opengl + glDisable(GL_LIGHTING); + + // create the OpenGL/OpenCL shared context + context_ = compute::opengl_create_shared_context(); + + // get gpu device + compute::device gpu = context_.get_device(); + std::cout << "device: " << gpu.name() << std::endl; + + // setup command queue + queue_ = compute::command_queue(context_, gpu); + + // build mandelbrot program + program_ = compute::program::create_with_source(source, context_); + program_.build(); +} + +void MandelbrotWidget::resizeGL(int width, int height) +{ +#if QT_VERSION >= 0x050000 + // scale height/width based on device pixel ratio + width /= windowHandle()->devicePixelRatio(); + height /= windowHandle()->devicePixelRatio(); +#endif + + // resize viewport + glViewport(0, 0, width, height); + + // delete old texture + if(gl_texture_){ + glDeleteTextures(1, &gl_texture_); + gl_texture_ = 0; + } + + // generate new texture + glGenTextures(1, &gl_texture_); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 + ); + + // create opencl object for the texture + cl_texture_ = compute::opengl_texture( + context_, GL_TEXTURE_2D, 0, gl_texture_, CL_MEM_WRITE_ONLY + ); +} + +void MandelbrotWidget::paintGL() +{ + using compute::dim; + + float w = width(); + float h = height(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, w, 0.0, h, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // setup the mandelbrot kernel + compute::kernel kernel(program_, "mandelbrot"); + kernel.set_arg(0, cl_texture_); + + // acquire the opengl texture so it can be used in opencl + compute::opengl_enqueue_acquire_gl_objects(1, &cl_texture_.get(), queue_); + + // execute the mandelbrot kernel + queue_.enqueue_nd_range_kernel( + kernel, dim(0, 0), dim(width(), height()), dim(1, 1) + ); + + // release the opengl texture so it can be used by opengl + compute::opengl_enqueue_release_gl_objects(1, &cl_texture_.get(), queue_); + + // ensure opencl is finished before rendering in opengl + queue_.finish(); + + // draw a single quad with the mandelbrot image texture + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(0, 1); glVertex2f(0, h); + glTexCoord2f(1, 1); glVertex2f(w, h); + glTexCoord2f(1, 0); glVertex2f(w, 0); + glEnd(); +} + +void MandelbrotWidget::keyPressEvent(QKeyEvent* event) +{ + if(event->key() == Qt::Key_Escape) { + this->close(); + } +} + +// the mandelbrot example shows how to create a mandelbrot image in +// OpenCL and render the image as a texture in OpenGL +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + MandelbrotWidget widget; + widget.show(); + + return app.exec(); +} + +#include "mandelbrot.moc" diff --git a/src/boost/libs/compute/example/mapped_view.cpp b/src/boost/libs/compute/example/mapped_view.cpp new file mode 100644 index 00000000..1e05107a --- /dev/null +++ b/src/boost/libs/compute/example/mapped_view.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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/reduce.hpp> +#include <boost/compute/container/mapped_view.hpp> + +namespace compute = boost::compute; + +// this example demonstrates how to use the mapped_view class to map +// an array of numbers to device memory and use the reduce() algorithm +// to calculate the sum. +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // create data on host + int data[] = { 4, 2, 3, 7, 8, 9, 1, 6 }; + + // create mapped view on device + compute::mapped_view<int> view(data, 8, context); + + // use reduce() to calculate sum on the device + int sum = 0; + compute::reduce(view.begin(), view.end(), &sum, queue); + + // print the sum on the host + std::cout << "sum: " << sum << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/matrix_transpose.cpp b/src/boost/libs/compute/example/matrix_transpose.cpp new file mode 100644 index 00000000..ee9b1e9d --- /dev/null +++ b/src/boost/libs/compute/example/matrix_transpose.cpp @@ -0,0 +1,355 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Benoit Dequidt <benoit.dequidt@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 <iostream> +#include <cstdlib> + +#include <boost/program_options.hpp> + +#include <boost/compute/core.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/type_traits/type_name.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; +namespace po = boost::program_options; + +using compute::uint_; + +const uint_ TILE_DIM = 32; +const uint_ BLOCK_ROWS = 8; + +// generate a copy kernel program +compute::kernel make_copy_kernel(const compute::context& context) +{ + // source for the copy_kernel program + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void copy_kernel(__global const float *src, __global float *dst) + { + uint x = get_group_id(0) * TILE_DIM + get_local_id(0); + uint y = get_group_id(1) * TILE_DIM + get_local_id(1); + + uint width = get_num_groups(0) * TILE_DIM; + + for(uint i = 0 ; i < TILE_DIM ; i+= BLOCK_ROWS){ + dst[(y+i)*width +x] = src[(y+i)*width + x]; + } + } + ); + + // setup compilation flags for the copy program + std::stringstream options; + options << "-DTILE_DIM=" << TILE_DIM << " -DBLOCK_ROWS=" << BLOCK_ROWS; + + // create and build the copy program + compute::program program = + compute::program::build_with_source(source, context, options.str()); + + // create and return the copy kernel + return program.create_kernel("copy_kernel"); +} + +// generate a naive transpose kernel +compute::kernel make_naive_transpose_kernel(const compute::context& context) +{ + // source for the naive_transpose kernel + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void naive_transpose(__global const float *src, __global float *dst) + { + uint x = get_group_id(0) * TILE_DIM + get_local_id(0); + uint y = get_group_id(1) * TILE_DIM + get_local_id(1); + + uint width = get_num_groups(0) * TILE_DIM; + + for(uint i = 0 ; i < TILE_DIM; i+= BLOCK_ROWS){ + dst[x*width + y+i] = src[(y+i)*width + x]; + } + } + ); + + // setup compilation flags for the naive_transpose program + std::stringstream options; + options << "-DTILE_DIM=" << TILE_DIM << " -DBLOCK_ROWS=" << BLOCK_ROWS; + + // create and build the naive_transpose program + compute::program program = + compute::program::build_with_source(source, context, options.str()); + + // create and return the naive_transpose kernel + return program.create_kernel("naive_transpose"); +} + +// generates a coalesced transpose kernel +compute::kernel make_coalesced_transpose_kernel(const compute::context& context) +{ + // source for the coalesced_transpose kernel + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void coalesced_transpose(__global const float *src, __global float *dst) + { + __local float tile[TILE_DIM][TILE_DIM]; + + // compute indexes + uint x = get_group_id(0) * TILE_DIM + get_local_id(0); + uint y = get_group_id(1) * TILE_DIM + get_local_id(1); + + uint width = get_num_groups(0) * TILE_DIM; + + // load inside local memory + for(uint i = 0 ; i < TILE_DIM; i+= BLOCK_ROWS){ + tile[get_local_id(1)+i][get_local_id(0)] = src[(y+i)*width + x]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // transpose indexes + x = get_group_id(1) * TILE_DIM + get_local_id(0); + y = get_group_id(0) * TILE_DIM + get_local_id(1); + + // write output from local memory + for(uint i = 0 ; i < TILE_DIM ; i+=BLOCK_ROWS){ + dst[(y+i)*width + x] = tile[get_local_id(0)][get_local_id(1)+i]; + } + } + ); + + // setup compilation flags for the coalesced_transpose program + std::stringstream options; + options << "-DTILE_DIM=" << TILE_DIM << " -DBLOCK_ROWS=" << BLOCK_ROWS; + + // create and build the coalesced_transpose program + compute::program program = + compute::program::build_with_source(source, context, options.str()); + + // create and return coalesced_transpose kernel + return program.create_kernel("coalesced_transpose"); +} + +// generate a coalesced withtout bank conflicts kernel +compute::kernel make_coalesced_no_bank_conflicts_kernel(const compute::context& context) +{ + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void coalesced_no_bank_conflicts(__global const float *src, __global float *dst) + { + // TILE_DIM+1 is here to avoid bank conflicts in local memory + __local float tile[TILE_DIM][TILE_DIM+1]; + + // compute indexes + uint x = get_group_id(0) * TILE_DIM + get_local_id(0); + uint y = get_group_id(1) * TILE_DIM + get_local_id(1); + + uint width = get_num_groups(0) * TILE_DIM; + + // load inside local memory + for(uint i = 0 ; i < TILE_DIM; i+= BLOCK_ROWS){ + tile[get_local_id(1)+i][get_local_id(0)] = src[(y+i)*width + x]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + // transpose indexes + x = get_group_id(1) * TILE_DIM + get_local_id(0); + y = get_group_id(0) * TILE_DIM + get_local_id(1); + + // write output from local memory + for(uint i = 0 ; i < TILE_DIM ; i+=BLOCK_ROWS){ + dst[(y+i)*width + x] = tile[get_local_id(0)][get_local_id(1)+i]; + } + } + ); + + // setup compilation flags for the coalesced_no_bank_conflicts program + std::stringstream options; + options << "-DTILE_DIM=" << TILE_DIM << " -DBLOCK_ROWS=" << BLOCK_ROWS; + + // create and build the coalesced_no_bank_conflicts program + compute::program program = + compute::program::build_with_source(source, context, options.str()); + + // create and return the coalesced_no_bank_conflicts kernel + return program.create_kernel("coalesced_no_bank_conflicts"); +} + +// compare 'expectedResult' to 'transposedMatrix'. prints an error message if not equal. +bool check_transposition(const std::vector<float>& expectedResult, + uint_ size, + const std::vector<float>& transposedMatrix) +{ + for(uint_ i = 0 ; i < size ; ++i){ + if(expectedResult[i] != transposedMatrix[i]){ + std::cout << "idx = " << i << " , expected " << expectedResult[i] + << " , got " << transposedMatrix[i] << std::endl; + std::cout << "FAILED" << std::endl; + return false; + } + } + return true; +} + +// generate a matrix inside 'in' and do the tranposition inside 'out' +void generate_matrix(std::vector<float>& in, std::vector<float>& out, uint_ rows, uint_ cols) +{ + // generate a matrix + for(uint_ i = 0 ; i < rows ; ++i){ + for(uint_ j = 0 ; j < cols ; ++j){ + in[i*cols + j] = i*cols + j; + } + } + + // store transposed result + for(uint_ j = 0; j < cols ; ++j){ + for(uint_ i = 0 ; i < rows ; ++i){ + out[j*rows + i] = in[i*cols + j]; + } + } +} + +// neccessary for 64-bit integer on win32 +#ifdef _WIN32 +#define uint64_t unsigned __int64 +#endif + +int main(int argc, char *argv[]) +{ + // setup command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("rows", po::value<uint_>()->default_value(4096), "number of matrix rows") + ("cols", po::value<uint_>()->default_value(4096), "number of matrix columns") + ; + + // parse command line + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, options), vm); + po::notify(vm); + + // check command line arguments + if(vm.count("help")){ + std::cout << options << std::endl; + return 0; + } + + // get number rows and columns for the matrix + const uint_ rows = vm["rows"].as<uint_>(); + const uint_ cols = vm["cols"].as<uint_>(); + + // get the default device + compute::device device = compute::system::default_device(); + + // print out device name and matrix information + std::cout << "Device: " << device.name() << std::endl; + std::cout << "Matrix Size: " << rows << "x" << cols << std::endl; + std::cout << "Grid Size: " << rows/TILE_DIM << "x" << cols/TILE_DIM << " blocks" << std::endl; + std::cout << "Local Size: " << TILE_DIM << "x" << BLOCK_ROWS << " threads" << std::endl; + std::cout << std::endl; + + // On OSX this example does not work on CPU devices + #if defined(__APPLE__) + if(device.type() & compute::device::cpu) { + std::cout << "On OSX this example does not work on CPU devices" << std::endl; + return 0; + } + #endif + + const size_t global_work_size[2] = {rows, cols*BLOCK_ROWS/TILE_DIM}; + const size_t local_work_size[2] = {TILE_DIM, BLOCK_ROWS}; + + // setup input data on the host + const uint_ size = rows * cols; + std::vector<float> h_input(size); + std::vector<float> h_output(size); + std::vector<float> expectedResult(size); + generate_matrix(h_input, expectedResult, rows, cols); + + // create a context for the device + compute::context context(device); + + // device vectors + compute::vector<float> d_input(size, context); + compute::vector<float> d_output(size, context); + + // command_queue with profiling + compute::command_queue queue(context, device, compute::command_queue::enable_profiling); + + // copy input data + compute::copy(h_input.begin(), h_input.end(), d_input.begin(), queue); + + // simple copy kernel + std::cout << "Testing copy_kernel:" << std::endl; + compute::kernel kernel = make_copy_kernel(context); + kernel.set_arg(0, d_input); + kernel.set_arg(1, d_output); + + compute::event start; + start = queue.enqueue_nd_range_kernel(kernel, 2, 0, global_work_size, local_work_size); + queue.finish(); + uint64_t elapsed = start.duration<boost::chrono::nanoseconds>().count(); + + std::cout << " Elapsed: " << elapsed << " ns" << std::endl; + std::cout << " BandWidth: " << 2*rows*cols*sizeof(float) / elapsed << " GB/s" << std::endl; + compute::copy(d_output.begin(), d_output.end(), h_output.begin(), queue); + + check_transposition(h_input, rows*cols, h_output); + std::cout << std::endl; + + // naive_transpose kernel + std::cout << "Testing naive_transpose:" << std::endl; + kernel = make_naive_transpose_kernel(context); + kernel.set_arg(0, d_input); + kernel.set_arg(1, d_output); + + start = queue.enqueue_nd_range_kernel(kernel, 2, 0, global_work_size, local_work_size); + queue.finish(); + elapsed = start.duration<boost::chrono::nanoseconds>().count(); + std::cout << " Elapsed: " << elapsed << " ns" << std::endl; + std::cout << " BandWidth: " << 2*rows*cols*sizeof(float) / elapsed << " GB/s" << std::endl; + compute::copy(d_output.begin(), d_output.end(), h_output.begin(), queue); + + check_transposition(expectedResult, rows*cols, h_output); + std::cout << std::endl; + + // coalesced_transpose kernel + std::cout << "Testing coalesced_transpose:" << std::endl; + kernel = make_coalesced_transpose_kernel(context); + kernel.set_arg(0, d_input); + kernel.set_arg(1, d_output); + + start = queue.enqueue_nd_range_kernel(kernel, 2, 0, global_work_size, local_work_size); + queue.finish(); + elapsed = start.duration<boost::chrono::nanoseconds>().count(); + std::cout << " Elapsed: " << elapsed << " ns" << std::endl; + std::cout << " BandWidth: " << 2*rows*cols*sizeof(float) / elapsed << " GB/s" << std::endl; + + compute::copy(d_output.begin(), d_output.end(), h_output.begin(), queue); + + check_transposition(expectedResult, rows*cols, h_output); + std::cout << std::endl; + + // coalesced_no_bank_conflicts kernel + std::cout << "Testing coalesced_no_bank_conflicts:" << std::endl; + + kernel = make_coalesced_no_bank_conflicts_kernel(context); + kernel.set_arg(0, d_input); + kernel.set_arg(1, d_output); + + start = queue.enqueue_nd_range_kernel(kernel, 2, 0, global_work_size, local_work_size); + queue.finish(); + elapsed = start.duration<boost::chrono::nanoseconds>().count(); + std::cout << " Elapsed: " << elapsed << " ns" << std::endl; + std::cout << " BandWidth: " << 2*rows*cols*sizeof(float) / elapsed << " GB/s" << std::endl; + + compute::copy(d_output.begin(), d_output.end(), h_output.begin(), queue); + + check_transposition(expectedResult, rows*cols, h_output); + std::cout << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/memory_limits.cpp b/src/boost/libs/compute/example/memory_limits.cpp new file mode 100644 index 00000000..8d0e4a7a --- /dev/null +++ b/src/boost/libs/compute/example/memory_limits.cpp @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <boost/compute/core.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get the default device + compute::device device = compute::system::default_device(); + + std::cout << "device: " << device.name() << std::endl; + std::cout << " global memory size: " + << device.get_info<cl_ulong>(CL_DEVICE_GLOBAL_MEM_SIZE) / 1024 / 1024 + << " MB" + << std::endl; + std::cout << " local memory size: " + << device.get_info<cl_ulong>(CL_DEVICE_LOCAL_MEM_SIZE) / 1024 + << " KB" + << std::endl; + std::cout << " constant memory size: " + << device.get_info<cl_ulong>(CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE) / 1024 + << " KB" + << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/monte_carlo.cpp b/src/boost/libs/compute/example/monte_carlo.cpp new file mode 100644 index 00000000..8ae26209 --- /dev/null +++ b/src/boost/libs/compute/example/monte_carlo.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. +//---------------------------------------------------------------------------// + +#include <iostream> + +#include <boost/compute/function.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/count_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/buffer_iterator.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/types/fundamental.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + std::cout << "device: " << gpu.name() << std::endl; + + using compute::uint_; + using compute::uint2_; + + +#ifdef CI_BUILD // lower number of points for CI builds + size_t n = 2000; +#else + // ten million random points + size_t n = 10000000; +#endif + + // generate random numbers + compute::default_random_engine rng(queue); + compute::vector<uint_> vector(n * 2, context); + rng.generate(vector.begin(), vector.end(), queue); + + // function returing true if the point is within the unit circle + BOOST_COMPUTE_FUNCTION(bool, is_in_unit_circle, (const uint2_ point), + { + const float x = point.x / (float) UINT_MAX - 1; + const float y = point.y / (float) UINT_MAX - 1; + + return (x*x + y*y) < 1.0f; + }); + + // iterate over vector<uint> as vector<uint2> + compute::buffer_iterator<uint2_> start = + compute::make_buffer_iterator<uint2_>(vector.get_buffer(), 0); + compute::buffer_iterator<uint2_> end = + compute::make_buffer_iterator<uint2_>(vector.get_buffer(), vector.size() / 2); + + // count number of random points within the unit circle + size_t count = compute::count_if(start, end, is_in_unit_circle, queue); + + // print out values + float count_f = static_cast<float>(count); + std::cout << "count: " << count << " / " << n << std::endl; + std::cout << "ratio: " << count_f / float(n) << std::endl; + std::cout << "pi = " << (count_f / float(n)) * 4.0f << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/nbody.cpp b/src/boost/libs/compute/example/nbody.cpp new file mode 100644 index 00000000..9379c63b --- /dev/null +++ b/src/boost/libs/compute/example/nbody.cpp @@ -0,0 +1,236 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> + +#define GL_GLEXT_PROTOTYPES +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> +#else +#include <GL/gl.h> +#include <GL/glext.h> +#endif + +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtWidgets> +#else +#include <QtGui> +#endif +#include <QtOpenGL> +#include <QTimer> + +#include <boost/program_options.hpp> +#include <boost/random/uniform_real_distribution.hpp> +#include <boost/random/mersenne_twister.hpp> + +#ifndef Q_MOC_RUN +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/interop/opengl.hpp> +#include <boost/compute/utility/source.hpp> +#endif // Q_MOC_RUN + +namespace compute = boost::compute; +namespace po = boost::program_options; + +using compute::uint_; +using compute::float4_; + +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void updateVelocity(__global const float4* position, __global float4* velocity, float dt, uint N) + { + uint gid = get_global_id(0); + + float4 r = { 0.0f, 0.0f, 0.0f, 0.0f }; + float f = 0.0f; + for(uint i = 0; i != gid; i++) { + if(i != gid) { + r = position[i]-position[gid]; + f = length(r)+0.001f; + f *= f*f; + f = dt/f; + velocity[gid] += f*r; + } + } + } + __kernel void updatePosition(__global float4* position, __global const float4* velocity, float dt) + { + uint gid = get_global_id(0); + + position[gid].xyz += dt*velocity[gid].xyz; + } +); + +class NBodyWidget : public QGLWidget +{ + Q_OBJECT + +public: + NBodyWidget(std::size_t particles, float dt, QWidget* parent = 0); + ~NBodyWidget(); + + void initializeGL(); + void resizeGL(int width, int height); + void paintGL(); + void updateParticles(); + void keyPressEvent(QKeyEvent* event); + +private: + QTimer* timer; + + compute::context m_context; + compute::command_queue m_queue; + compute::program m_program; + compute::opengl_buffer m_position; + compute::vector<float4_>* m_velocity; + compute::kernel m_velocity_kernel; + compute::kernel m_position_kernel; + + bool m_initial_draw; + + const uint_ m_particles; + const float m_dt; +}; + +NBodyWidget::NBodyWidget(std::size_t particles, float dt, QWidget* parent) + : QGLWidget(parent), m_initial_draw(true), m_particles(particles), m_dt(dt) +{ + // create a timer to redraw as fast as possible + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateGL())); + timer->start(1); +} + +NBodyWidget::~NBodyWidget() +{ + delete m_velocity; + + // delete the opengl buffer + GLuint vbo = m_position.get_opengl_object(); + glDeleteBuffers(1, &vbo); +} + +void NBodyWidget::initializeGL() +{ + // create context, command queue and program + m_context = compute::opengl_create_shared_context(); + m_queue = compute::command_queue(m_context, m_context.get_device()); + m_program = compute::program::create_with_source(source, m_context); + m_program.build(); + + // prepare random particle positions that will be transferred to the vbo + float4_* temp = new float4_[m_particles]; + boost::random::uniform_real_distribution<float> dist(-0.5f, 0.5f); + boost::random::mt19937_64 gen; + for(size_t i = 0; i < m_particles; i++) { + temp[i][0] = dist(gen); + temp[i][1] = dist(gen); + temp[i][2] = dist(gen); + temp[i][3] = 1.0f; + } + + // create an OpenGL vbo + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, m_particles*sizeof(float4_), temp, GL_DYNAMIC_DRAW); + + // create a OpenCL buffer from the vbo + m_position = compute::opengl_buffer(m_context, vbo); + delete[] temp; + + // create buffer for velocities + m_velocity = new compute::vector<float4_>(m_particles, m_context); + compute::fill(m_velocity->begin(), m_velocity->end(), float4_(0.0f, 0.0f, 0.0f, 0.0f), m_queue); + + // create compute kernels + m_velocity_kernel = m_program.create_kernel("updateVelocity"); + m_velocity_kernel.set_arg(0, m_position); + m_velocity_kernel.set_arg(1, m_velocity->get_buffer()); + m_velocity_kernel.set_arg(2, m_dt); + m_velocity_kernel.set_arg(3, m_particles); + m_position_kernel = m_program.create_kernel("updatePosition"); + m_position_kernel.set_arg(0, m_position); + m_position_kernel.set_arg(1, m_velocity->get_buffer()); + m_position_kernel.set_arg(2, m_dt); +} +void NBodyWidget::resizeGL(int width, int height) +{ + // update viewport + glViewport(0, 0, width, height); +} +void NBodyWidget::paintGL() +{ + // clear buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // check if this is the first draw + if(m_initial_draw) { + // do not update particles + m_initial_draw = false; + } else { + // update particles + updateParticles(); + } + + // draw + glVertexPointer(4, GL_FLOAT, 0, 0); + glEnableClientState(GL_VERTEX_ARRAY); + glDrawArrays(GL_POINTS, 0, m_particles); + glFinish(); +} +void NBodyWidget::updateParticles() +{ + // enqueue kernels to update particles and make sure that the command queue is finished + compute::opengl_enqueue_acquire_buffer(m_position, m_queue); + m_queue.enqueue_1d_range_kernel(m_velocity_kernel, 0, m_particles, 0).wait(); + m_queue.enqueue_1d_range_kernel(m_position_kernel, 0, m_particles, 0).wait(); + m_queue.finish(); + compute::opengl_enqueue_release_buffer(m_position, m_queue); +} +void NBodyWidget::keyPressEvent(QKeyEvent* event) +{ + if(event->key() == Qt::Key_Escape) { + this->close(); + } +} + +int main(int argc, char** argv) +{ + // parse command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage") + ("particles", po::value<uint_>()->default_value(1000), "number of particles") + ("dt", po::value<float>()->default_value(0.00001f), "width of each integration step"); + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, options), vm); + po::notify(vm); + + if(vm.count("help") > 0) { + std::cout << options << std::endl; + return 0; + } + + const uint_ particles = vm["particles"].as<uint_>(); + const float dt = vm["dt"].as<float>(); + + QApplication app(argc, argv); + NBodyWidget nbody(particles, dt); + + nbody.show(); + + return app.exec(); +} + +#include "nbody.moc" diff --git a/src/boost/libs/compute/example/opencl_test.cpp b/src/boost/libs/compute/example/opencl_test.cpp new file mode 100644 index 00000000..15b85202 --- /dev/null +++ b/src/boost/libs/compute/example/opencl_test.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. +//---------------------------------------------------------------------------// + +// See boost/compute/detail/diagnostic.hpp +// GCC +#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 +#define BOOST_COMPUTE_GCC_DIAG_STR(s) #s +#define BOOST_COMPUTE_GCC_DIAG_JOINSTR(x,y) BOOST_COMPUTE_GCC_DIAG_STR(x ## y) +# define BOOST_COMPUTE_GCC_DIAG_DO_PRAGMA(x) _Pragma (#x) +# define BOOST_COMPUTE_GCC_DIAG_PRAGMA(x) BOOST_COMPUTE_GCC_DIAG_DO_PRAGMA(GCC diagnostic x) +# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 +# define BOOST_COMPUTE_GCC_DIAG_OFF(x) BOOST_COMPUTE_GCC_DIAG_PRAGMA(push) \ + BOOST_COMPUTE_GCC_DIAG_PRAGMA(ignored BOOST_COMPUTE_GCC_DIAG_JOINSTR(-W,x)) +# define BOOST_COMPUTE_GCC_DIAG_ON(x) BOOST_COMPUTE_GCC_DIAG_PRAGMA(pop) +# else +# define BOOST_COMPUTE_GCC_DIAG_OFF(x) \ + BOOST_COMPUTE_GCC_DIAG_PRAGMA(ignored BOOST_COMPUTE_GCC_DIAG_JOINSTR(-W,x)) +# define BOOST_COMPUTE_GCC_DIAG_ON(x) \ + BOOST_COMPUTE_GCC_DIAG_PRAGMA(warning BOOST_COMPUTE_GCC_DIAG_JOINSTR(-W,x)) +# endif +#else // Ensure these macros do nothing for other compilers. +# define BOOST_COMPUTE_GCC_DIAG_OFF(x) +# define BOOST_COMPUTE_GCC_DIAG_ON(x) +#endif + +// Clang +#ifdef __clang__ +# define BOOST_COMPUTE_CLANG_DIAG_STR(s) # s +// stringize s to "no-sign-compare" +# define BOOST_COMPUTE_CLANG_DIAG_JOINSTR(x,y) BOOST_COMPUTE_CLANG_DIAG_STR(x ## y) +// join -W with no-unused-variable to "-Wno-sign-compare" +# define BOOST_COMPUTE_CLANG_DIAG_DO_PRAGMA(x) _Pragma (#x) +// _Pragma is unary operator #pragma ("") +# define BOOST_COMPUTE_CLANG_DIAG_PRAGMA(x) \ + BOOST_COMPUTE_CLANG_DIAG_DO_PRAGMA(clang diagnostic x) +# define BOOST_COMPUTE_CLANG_DIAG_OFF(x) BOOST_COMPUTE_CLANG_DIAG_PRAGMA(push) \ + BOOST_COMPUTE_CLANG_DIAG_PRAGMA(ignored BOOST_COMPUTE_CLANG_DIAG_JOINSTR(-W,x)) +// For example: #pragma clang diagnostic ignored "-Wno-sign-compare" +# define BOOST_COMPUTE_CLANG_DIAG_ON(x) BOOST_COMPUTE_CLANG_DIAG_PRAGMA(pop) +// For example: #pragma clang diagnostic warning "-Wno-sign-compare" +#else // Ensure these macros do nothing for other compilers. +# define BOOST_COMPUTE_CLANG_DIAG_OFF(x) +# define BOOST_COMPUTE_CLANG_DIAG_ON(x) +# define BOOST_COMPUTE_CLANG_DIAG_PRAGMA(x) +#endif + +// MSVC +#if defined(_MSC_VER) +# define BOOST_COMPUTE_MSVC_DIAG_DO_PRAGMA(x) __pragma(x) +# define BOOST_COMPUTE_MSVC_DIAG_PRAGMA(x) \ + BOOST_COMPUTE_MSVC_DIAG_DO_PRAGMA(warning(x)) +# define BOOST_COMPUTE_MSVC_DIAG_OFF(x) BOOST_COMPUTE_MSVC_DIAG_PRAGMA(push) \ + BOOST_COMPUTE_MSVC_DIAG_PRAGMA(disable: x) +# define BOOST_COMPUTE_MSVC_DIAG_ON(x) BOOST_COMPUTE_MSVC_DIAG_PRAGMA(pop) +#else // Ensure these macros do nothing for other compilers. +# define BOOST_COMPUTE_MSVC_DIAG_OFF(x) +# define BOOST_COMPUTE_MSVC_DIAG_ON(x) +#endif + +#include <iostream> + +// include the proper opencl header for the system +#if defined(__APPLE__) +#include <OpenCL/cl.h> +#else +#include <CL/cl.h> +#endif + +// the opencl_test example displays the opencl platforms and devices found +// on the system using the opencl api directly. if this test fails to compile +// and/or run, there is a problem with the opencl implementation found on the +// system. users should ensure this test runs successfuly before using any of +// the boost.compute apis (which depend on a working opencl implementation). +int main() +{ + // Suppress deprecated declarations warning + BOOST_COMPUTE_MSVC_DIAG_OFF(4996); // MSVC + BOOST_COMPUTE_GCC_DIAG_OFF(deprecated-declarations); // GCC + BOOST_COMPUTE_CLANG_DIAG_OFF(deprecated-declarations); // Clang + + // query number of opencl platforms + cl_uint num_platforms = 0; + cl_int ret = clGetPlatformIDs(0, NULL, &num_platforms); + if(ret != CL_SUCCESS){ + std::cerr << "failed to query platforms: " << ret << std::endl; + return -1; + } + + // check that at least one platform was found + if(num_platforms == 0){ + std::cerr << "found 0 platforms" << std::endl; + return 0; + } + + // get platform ids + cl_platform_id *platforms = new cl_platform_id[num_platforms]; + clGetPlatformIDs(num_platforms, platforms, NULL); + + // iterate through each platform and query its devices + for(cl_uint i = 0; i < num_platforms; i++){ + cl_platform_id platform = platforms[i]; + + // query number of opencl devices + cl_uint num_devices = 0; + ret = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &num_devices); + if(ret != CL_SUCCESS){ + std::cerr << "failed to lookup devices for platform " << i << std::endl; + continue; + } + + // print number of devices found + std::cout << "platform " << i << " has " << num_devices << " devices:" << std::endl; + + // get device ids for the platform + cl_device_id *devices = new cl_device_id[num_devices]; + ret = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, num_devices, devices, NULL); + if(ret != CL_SUCCESS){ + std::cerr << "failed to query platform devices" << std::endl; + delete[] devices; + continue; + } + + // iterate through each device on the platform and print its name + for(cl_uint j = 0; j < num_devices; j++){ + cl_device_id device = devices[j]; + + // get length of the device name string + size_t name_length = 0; + ret = clGetDeviceInfo(device, CL_DEVICE_NAME, 0, NULL, &name_length); + if(ret != CL_SUCCESS){ + std::cerr << "failed to query device name length for device " << j << std::endl; + continue; + } + + // get the device name string + char *name = new char[name_length]; + ret = clGetDeviceInfo(device, CL_DEVICE_NAME, name_length, name, NULL); + if(ret != CL_SUCCESS){ + std::cerr << "failed to query device name string for device " << j << std::endl; + delete[] name; + continue; + } + + // print out the device name + std::cout << " device: " << name << std::endl; + + delete[] name; + } + delete[] devices; + } + delete[] platforms; + + BOOST_COMPUTE_CLANG_DIAG_ON(deprecated-declarations); // Clang + BOOST_COMPUTE_GCC_DIAG_ON(deprecated-declarations); // GCC + BOOST_COMPUTE_MSVC_DIAG_OFF(4996); // MSVC + + return 0; +} diff --git a/src/boost/libs/compute/example/opencv_convolution.cpp b/src/boost/libs/compute/example/opencv_convolution.cpp new file mode 100644 index 00000000..7ba53436 --- /dev/null +++ b/src/boost/libs/compute/example/opencv_convolution.cpp @@ -0,0 +1,265 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <string> + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/utility/source.hpp> + +#include <boost/program_options.hpp> + +namespace compute = boost::compute; +namespace po = boost::program_options; + +// Create convolution program +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE ( + __kernel void convolution(__read_only image2d_t sourceImage, + __write_only image2d_t outputImage, + __constant float* filter, + int filterWidth) + { + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST; + + // Store each work-item's unique row and column + int x = get_global_id(0); + int y = get_global_id(1); + + // Half the width of the filter is needed for indexing + // memory later + int halfWidth = (int)(filterWidth/2); + + // All accesses to images return data as four-element vector + // (i.e., float4). + float4 sum = {0.0f, 0.0f, 0.0f, 0.0f}; + + // Iterator for the filter + int filterIdx = 0; + + // Each work-item iterates around its local area based on the + // size of the filter + int2 coords; // Coordinates for accessing the image + + // Iterate the filter rows + for(int i = -halfWidth; i <= halfWidth; i++) + { + coords.y = y + i; + + // Iterate over the filter columns + for(int j = -halfWidth; j <= halfWidth; j++) + { + coords.x = x + j; + + float4 pixel; + + // Read a pixel from the image. + // Work on a channel + pixel = read_imagef(sourceImage, sampler, coords); + sum.x += pixel.x * filter[filterIdx++]; + //sum.y += pixel.y * filter[filterIdx++]; + //sum.z += pixel.z * filter[filterIdx++]; + } + } + + barrier(CLK_GLOBAL_MEM_FENCE); + // Copy the data to the output image if the + // work-item is in bounds + if(y < get_image_height(sourceImage) && + x < get_image_width(sourceImage)) + { + coords.x = x; + coords.y = y; + + //Same channel is copied in all three channels + //write_imagef(outputImage, coords, + // (float4)(sum.x,sum.x,sum.x,1.0f)); + + write_imagef(outputImage, coords, sum); + } + } +); + +// This example shows how to read two images or use camera +// with OpenCV, transfer the frames to the GPU, +// and apply a convolution written in OpenCL +int main(int argc, char *argv[]) +{ + /////////////////////////////////////////////////////////////////////////// + + // setup the command line arguments + po::options_description desc; + desc.add_options() + ("help", "show available options") + ("camera", po::value<int>()->default_value(-1), + "if not default camera, specify a camera id") + ("image", po::value<std::string>(), "path to image file"); + + // Parse the command lines + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //check the command line arguments + if(vm.count("help")) + { + std::cout << desc << std::endl; + return 0; + } + + /////////////////////////////////////////////////////////////////////////// + + //OpenCV variables + cv::Mat cv_mat; + cv::VideoCapture cap; //OpenCV camera handle. + + //Filter Variables + float filter[9] = { + -1.0, 0.0, 1.0, + -2.0, 0.0, 2.0, + -1.0, 0.0, 1.0, + }; + + // The convolution filter is 3x3 + int filterWidth = 3; + + //OpenCL variables + // Get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + compute::buffer dev_filter(context, sizeof(filter), + compute::memory_object::read_only | + compute::memory_object::copy_host_ptr, + filter); + + compute::program filter_program = + compute::program::create_with_source(source, context); + + try + { + filter_program.build(); + } + catch(compute::opencl_error e) + { + std::cout<<"Build Error: "<<std::endl + <<filter_program.build_log(); + return -1; + } + + // create fliter kernel and set arguments + compute::kernel filter_kernel(filter_program, "convolution"); + + /////////////////////////////////////////////////////////////////////////// + + //check for image paths + if(vm.count("image")) + { + // Read image with OpenCV + cv_mat = cv::imread(vm["image"].as<std::string>(), + CV_LOAD_IMAGE_COLOR); + if(!cv_mat.data){ + std::cerr << "Failed to load image" << std::endl; + return -1; + } + } + else //by default use camera + { + //open camera + cap.open(vm["camera"].as<int>()); + // read first frame + cap >> cv_mat; + if(!cv_mat.data){ + std::cerr << "failed to capture frame" << std::endl; + return -1; + } + } + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA); + + // Transfer image/frame data to gpu + compute::image2d dev_input_image = + compute::opencv_create_image2d_with_mat( + cv_mat, compute::image2d::read_write, queue + ); + + // Create output image + // Be sure what will be your ouput image/frame size + compute::image2d dev_output_image( + context, + dev_input_image.width(), + dev_input_image.height(), + dev_input_image.format(), + compute::image2d::write_only + ); + + filter_kernel.set_arg(0, dev_input_image); + filter_kernel.set_arg(1, dev_output_image); + filter_kernel.set_arg(2, dev_filter); + filter_kernel.set_arg(3, filterWidth); + + // run flip kernel + size_t origin[2] = { 0, 0 }; + size_t region[2] = { dev_input_image.width(), + dev_input_image.height() }; + + /////////////////////////////////////////////////////////////////////////// + + queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0); + + //check for image paths + if(vm.count("image")) + { + // show host image + cv::imshow("Original Image", cv_mat); + + // show gpu image + compute::opencv_imshow("Convoluted Image", dev_output_image, queue); + + // wait and return + cv::waitKey(0); + } + else + { + char key = '\0'; + while(key != 27) //check for escape key + { + cap >> cv_mat; + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA); + + // Update the device image memory with current frame data + compute::opencv_copy_mat_to_image(cv_mat, + dev_input_image,queue); + + // Run the kernel on the device + queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0); + + // Show host image + cv::imshow("Camera Frame", cv_mat); + + // Show GPU image + compute::opencv_imshow("Convoluted Frame", dev_output_image, queue); + + // wait + key = cv::waitKey(10); + } + } + return 0; +} diff --git a/src/boost/libs/compute/example/opencv_flip.cpp b/src/boost/libs/compute/example/opencv_flip.cpp new file mode 100644 index 00000000..8cc26ef2 --- /dev/null +++ b/src/boost/libs/compute/example/opencv_flip.cpp @@ -0,0 +1,101 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// this example shows how to read an image with OpenCV, transfer the +// image to the GPU, and apply a simple flip filter written in OpenCL +int main(int argc, char *argv[]) +{ + // check command line + if(argc < 2){ + std::cerr << "usage: " << argv[0] << " FILENAME" << std::endl; + return -1; + } + + // read image with opencv + cv::Mat cv_image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR); + if(!cv_image.data){ + std::cerr << "failed to load image" << std::endl; + return -1; + } + + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + // convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(cv_image, cv_image, CV_BGR2BGRA); + + // transfer image to gpu + compute::image2d input_image = + compute::opencv_create_image2d_with_mat( + cv_image, compute::image2d::read_write, queue + ); + + // create output image + compute::image2d output_image( + context, + input_image.width(), + input_image.height(), + input_image.format(), + compute::image2d::write_only + ); + + // create flip program + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void flip_kernel(__read_only image2d_t input, + __write_only image2d_t output) + { + const sampler_t sampler = CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + int height = get_image_height(input); + int2 input_coord = { get_global_id(0), get_global_id(1) }; + int2 output_coord = { input_coord.x, height - input_coord.y - 1 }; + float4 value = read_imagef(input, sampler, input_coord); + write_imagef(output, output_coord, value); + } + ); + + compute::program flip_program = + compute::program::create_with_source(source, context); + flip_program.build(); + + // create flip kernel and set arguments + compute::kernel flip_kernel(flip_program, "flip_kernel"); + flip_kernel.set_arg(0, input_image); + flip_kernel.set_arg(1, output_image); + + // run flip kernel + size_t origin[2] = { 0, 0 }; + size_t region[2] = { input_image.width(), input_image.height() }; + queue.enqueue_nd_range_kernel(flip_kernel, 2, origin, region, 0); + + // show host image + cv::imshow("opencv image", cv_image); + + // show gpu image + compute::opencv_imshow("filtered image", output_image, queue); + + // wait and return + cv::waitKey(0); + return 0; +} diff --git a/src/boost/libs/compute/example/opencv_histogram.cpp b/src/boost/libs/compute/example/opencv_histogram.cpp new file mode 100644 index 00000000..e339030b --- /dev/null +++ b/src/boost/libs/compute/example/opencv_histogram.cpp @@ -0,0 +1,228 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-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. +//---------------------------------------------------------------------------// + +//Code sample for calculating histogram using OpenCL and +//displaying image histogram in OpenCV. + +#include <iostream> +#include <string> + +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> + +#include <boost/compute/source.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/program_options.hpp> + +namespace compute = boost::compute; +namespace po = boost::program_options; + +// number of bins +int histSize = 256; + +// Set the ranges ( for B,G,R) ) +// TryOut: consider the range in kernel calculation +float range[] = { 0, 256 } ; +const float* histRange = { range }; + +// Create naive histogram program +// Needs "cl_khr_local_int32_base_atomics" extension +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE ( + __kernel void histogram(read_only image2d_t src_image, + __global int* b_hist, + __global int* g_hist, + __global int* r_hist) + { + sampler_t sampler =( CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST | + CLK_ADDRESS_CLAMP_TO_EDGE); + + int image_width = get_image_width(src_image); + int image_height = get_image_height(src_image); + + int2 coords = (int2)(get_global_id(0), get_global_id(1)); + float4 pixel = read_imagef(src_image,sampler, coords); + + //boundary condition + if ((coords.x < image_width) && (coords.y < image_height)) + { + uchar indx_x, indx_y, indx_z; + indx_x = convert_uchar_sat(pixel.x * 255.0f); + indx_y = convert_uchar_sat(pixel.y * 255.0f); + indx_z = convert_uchar_sat(pixel.z * 255.0f); + + atomic_inc(&b_hist[(uint)indx_z]); + atomic_inc(&g_hist[(uint)indx_y]); + atomic_inc(&r_hist[(uint)indx_x]); + } + } +); + +inline void showHistogramWindow(cv::Mat &b_hist, cv::Mat &g_hist, cv::Mat &r_hist, + std::string window_name) +{ + // Draw the histograms for B, G and R + int hist_w = 1024; + int hist_h = 768; + int bin_w = cvRound((double)hist_w/histSize); + + cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(0,0,0)); + + // Normalize the result to [ 0, histImage.rows ] + cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); + cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); + cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); + + // Draw for each channel + for (int i = 1; i < histSize; i++ ) + { + cv::line(histImage, + cv::Point(bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1))), + cv::Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), + cv::Scalar(255, 0, 0), + 2, + 8, + 0); + + cv::line(histImage, + cv::Point(bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1))), + cv::Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), + cv::Scalar(0, 255, 0), + 2, + 8, + 0); + + cv::line(histImage, + cv::Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1))), + cv::Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ), + cv::Scalar( 0, 0, 255), + 2, + 8, + 0); + } + + // Display + cv::namedWindow(window_name, CV_WINDOW_AUTOSIZE ); + cv::imshow(window_name, histImage ); +} + +//Get the device context +//Create GPU array/vector +//Copy the image & set up the kernel +//Execute the kernel +//Copy GPU data back to CPU cv::Mat data pointer +//OpenCV conversion for convienient display +void calculateHistogramUsingCL(cv::Mat src, compute::command_queue &queue) +{ + compute::context context = queue.get_context(); + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(src, src, CV_BGR2BGRA); + + //3 channels & 256 bins : alpha channel is ignored + compute::vector<int> gpu_b_hist(histSize, context); + compute::vector<int> gpu_g_hist(histSize, context); + compute::vector<int> gpu_r_hist(histSize, context); + + // Transfer image to gpu + compute::image2d gpu_src = + compute::opencv_create_image2d_with_mat( + src, compute::image2d::read_only, + queue + ); + + compute::program histogram_program = + compute::program::create_with_source(source, context); + histogram_program.build(); + + // create histogram kernel and set arguments + compute::kernel histogram_kernel(histogram_program, "histogram"); + histogram_kernel.set_arg(0, gpu_src); + histogram_kernel.set_arg(1, gpu_b_hist.get_buffer()); + histogram_kernel.set_arg(2, gpu_g_hist.get_buffer()); + histogram_kernel.set_arg(3, gpu_r_hist.get_buffer()); + + // run histogram kernel + // each kernel thread updating red, green & blue bins + size_t origin[2] = { 0, 0 }; + size_t region[2] = { gpu_src.width(), + gpu_src.height() }; + + queue.enqueue_nd_range_kernel(histogram_kernel, 2, origin, region, 0); + + //Make sure kernel get executed and data copied back + queue.finish(); + + //create Mat and copy GPU bins to CPU memory + cv::Mat b_hist(256, 1, CV_32SC1); + compute::copy(gpu_b_hist.begin(), gpu_b_hist.end(), b_hist.data, queue); + cv::Mat g_hist(256, 1, CV_32SC1); + compute::copy(gpu_g_hist.begin(), gpu_g_hist.end(), g_hist.data, queue); + cv::Mat r_hist(256, 1, CV_32SC1); + compute::copy(gpu_r_hist.begin(), gpu_r_hist.end(), r_hist.data, queue); + + b_hist.convertTo(b_hist, CV_32FC1); //converted for displaying + g_hist.convertTo(g_hist, CV_32FC1); + r_hist.convertTo(r_hist, CV_32FC1); + + showHistogramWindow(b_hist, g_hist, r_hist, "Histogram"); +} + +int main( int argc, char** argv ) +{ + // Get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + cv::Mat src; + + // setup the command line arguments + po::options_description desc; + desc.add_options() + ("help", "show available options") + ("image", po::value<std::string>(), "path to image file"); + + // Parse the command lines + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //check the command line arguments + if(vm.count("help")) + { + std::cout << desc << std::endl; + return 0; + } + + //check for image paths + if(vm.count("image")) + { + // Read image with OpenCV + src = cv::imread(vm["image"].as<std::string>(), + CV_LOAD_IMAGE_COLOR); + if(!src.data){ + std::cerr << "Failed to load image" << std::endl; + return -1; + } + calculateHistogramUsingCL(src, queue); + cv::imshow("Image", src); + cv::waitKey(0); + } + else + { + std::cout << desc << std::endl; + return 0; + } + return 0; +} diff --git a/src/boost/libs/compute/example/opencv_optical_flow.cpp b/src/boost/libs/compute/example/opencv_optical_flow.cpp new file mode 100644 index 00000000..87f330ae --- /dev/null +++ b/src/boost/libs/compute/example/opencv_optical_flow.cpp @@ -0,0 +1,289 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <string> + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/utility/source.hpp> + +#include <boost/program_options.hpp> + +namespace compute = boost::compute; +namespace po = boost::program_options; + +// Create naive optical flow program +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE ( + const sampler_t sampler = CLK_ADDRESS_CLAMP_TO_EDGE; + + __kernel void optical_flow ( + read_only + image2d_t current_image, + read_only image2d_t previous_image, + write_only image2d_t optical_flow, + const float scale, + const float offset, + const float lambda, + const float threshold ) + { + int2 coords = (int2)(get_global_id(0), get_global_id(1)); + float4 current_pixel = read_imagef(current_image, + sampler, + coords); + float4 previous_pixel = read_imagef(previous_image, + sampler, + coords); + int2 x1 = (int2)(offset, 0.f); + int2 y1 = (int2)(0.f, offset); + + //get the difference + float4 curdif = previous_pixel - current_pixel; + + //calculate the gradient + //Image 2 first + float4 gradx = read_imagef(previous_image, + sampler, + coords+x1) - + read_imagef(previous_image, + sampler, + coords-x1); + //Image 1 + gradx += read_imagef(current_image, + sampler, + coords+x1) - + read_imagef(current_image, + sampler, + coords-x1); + //Image 2 first + float4 grady = read_imagef(previous_image, + sampler, + coords+y1) - + read_imagef(previous_image, + sampler, + coords-y1); + //Image 1 + grady += read_imagef(current_image, + sampler, + coords+y1) - + read_imagef(current_image, + sampler, + coords-y1); + + float4 sqr = (gradx*gradx) + (grady*grady) + + (float4)(lambda,lambda, lambda, lambda); + float4 gradmag = sqrt(sqr); + + /////////////////////////////////////////////////// + float4 vx = curdif * (gradx / gradmag); + float vxd = vx.x;//assumes greyscale + + //format output for flowrepos, out(-x,+x,-y,+y) + float2 xout = (float2)(fmax(vxd,0.f),fabs(fmin(vxd,0.f))); + xout *= scale; + /////////////////////////////////////////////////// + float4 vy = curdif*(grady/gradmag); + float vyd = vy.x;//assumes greyscale + + //format output for flowrepos, out(-x,+x,-y,+y) + float2 yout = (float2)(fmax(vyd,0.f),fabs(fmin(vyd,0.f))); + yout *= scale; + /////////////////////////////////////////////////// + + float4 out = (float4)(xout, yout); + float cond = (float)isgreaterequal(length(out), threshold); + out *= cond; + + write_imagef(optical_flow, coords, out); + } +); + +// This example shows how to read two images or use camera +// with OpenCV, transfer the frames to the GPU, +// and apply a naive optical flow algorithm +// written in OpenCL +int main(int argc, char *argv[]) +{ + // setup the command line arguments + po::options_description desc; + desc.add_options() + ("help", "show available options") + ("camera", po::value<int>()->default_value(-1), + "if not default camera, specify a camera id") + ("image1", po::value<std::string>(), "path to image file 1") + ("image2", po::value<std::string>(), "path to image file 2"); + + // Parse the command lines + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //check the command line arguments + if(vm.count("help")) + { + std::cout << desc << std::endl; + return 0; + } + + //OpenCV variables + cv::Mat previous_cv_image; + cv::Mat current_cv_image; + cv::VideoCapture cap; //OpenCV camera handle + + //check for image paths + if(vm.count("image1") && vm.count("image2")) + { + // Read image 1 with OpenCV + previous_cv_image = cv::imread(vm["image1"].as<std::string>(), + CV_LOAD_IMAGE_COLOR); + if(!previous_cv_image.data){ + std::cerr << "Failed to load image" << std::endl; + return -1; + } + + // Read image 2 with opencv + current_cv_image = cv::imread(vm["image2"].as<std::string>(), + CV_LOAD_IMAGE_COLOR); + if(!current_cv_image.data){ + std::cerr << "Failed to load image" << std::endl; + return -1; + } + } + else //by default use camera + { + //open camera + cap.open(vm["camera"].as<int>()); + // read first frame + cap >> previous_cv_image; + if(!previous_cv_image.data){ + std::cerr << "failed to capture frame" << std::endl; + return -1; + } + + // read second frame + cap >> current_cv_image; + if(!current_cv_image.data){ + std::cerr << "failed to capture frame" << std::endl; + return -1; + } + + } + + // Get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(previous_cv_image, previous_cv_image, CV_BGR2BGRA); + cv::cvtColor(current_cv_image, current_cv_image, CV_BGR2BGRA); + + // Transfer image to gpu + compute::image2d dev_previous_image = + compute::opencv_create_image2d_with_mat( + previous_cv_image, compute::image2d::read_write, queue + ); + // Transfer image to gpu + compute::image2d dev_current_image = + compute::opencv_create_image2d_with_mat( + current_cv_image, compute::image2d::read_write, queue + ); + + // Create output image + compute::image2d dev_output_image( + context, + dev_previous_image.width(), + dev_previous_image.height(), + dev_previous_image.format(), + compute::image2d::write_only + ); + + compute::program optical_program = + compute::program::create_with_source(source, context); + optical_program.build(); + + // create flip kernel and set arguments + compute::kernel optical_kernel(optical_program, "optical_flow"); + float scale = 10; + float offset = 1; + float lambda = 0.0025; + float threshold = 1.0; + + optical_kernel.set_arg(0, dev_previous_image); + optical_kernel.set_arg(1, dev_current_image); + optical_kernel.set_arg(2, dev_output_image); + optical_kernel.set_arg(3, scale); + optical_kernel.set_arg(4, offset); + optical_kernel.set_arg(5, lambda); + optical_kernel.set_arg(6, threshold); + + // run flip kernel + size_t origin[2] = { 0, 0 }; + size_t region[2] = { dev_previous_image.width(), + dev_previous_image.height() }; + queue.enqueue_nd_range_kernel(optical_kernel, 2, origin, region, 0); + + //check for image paths + if(vm.count("image1") && vm.count("image2")) + { + // show host image + cv::imshow("Previous Frame", previous_cv_image); + cv::imshow("Current Frame", current_cv_image); + + // show gpu image + compute::opencv_imshow("filtered image", dev_output_image, queue); + + // wait and return + cv::waitKey(0); + } + else + { + char key = '\0'; + while(key != 27) //check for escape key + { + cap >> current_cv_image; + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(current_cv_image, current_cv_image, CV_BGR2BGRA); + + // Update the device image memory with current frame data + compute::opencv_copy_mat_to_image(previous_cv_image, + dev_previous_image, + queue); + compute::opencv_copy_mat_to_image(current_cv_image, + dev_current_image, + queue); + + // Run the kernel on the device + queue.enqueue_nd_range_kernel(optical_kernel, 2, origin, region, 0); + + // Show host image + cv::imshow("Previous Frame", previous_cv_image); + cv::imshow("Current Frame", current_cv_image); + + // Show GPU image + compute::opencv_imshow("filtered image", dev_output_image, queue); + + // Copy current frame container to previous frame container + current_cv_image.copyTo(previous_cv_image); + + // wait + key = cv::waitKey(10); + } + + } + return 0; +} + diff --git a/src/boost/libs/compute/example/opencv_sobel_filter.cpp b/src/boost/libs/compute/example/opencv_sobel_filter.cpp new file mode 100644 index 00000000..4fcfa206 --- /dev/null +++ b/src/boost/libs/compute/example/opencv_sobel_filter.cpp @@ -0,0 +1,254 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Mageswaran.D <mageswaran1989@gmail.com> +// +// Book Refered: OpenCL Programming Guide +// 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. +//---------------------------------------------------------------------------// + +//---------------------------------------------------------------------------// +// About Sobel Filter: +// * Edge Filter - distinguishes the differrent color region +// * Finds the gradient in x and y-axes +// * Three step process +// -> Find x-axis gradient with kernel/matrix +// Gx = [-1 0 +1] +// [-2 0 +2] +// [-1 0 +1] +// -> Find y-axis gradient with kernel/matrix +// Gy = [-1 -2 -1] +// [ 0 0 0] +// [+1 +2 +1] +// * Gradient magnitude G = sqrt(Gx^2 + Gy^2) +//---------------------------------------------------------------------------// + +#include <iostream> +#include <string> + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/utility/source.hpp> + +#include <boost/program_options.hpp> + +namespace compute = boost::compute; +namespace po = boost::program_options; + +// Create sobel filter program +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE ( + //For out of boundary pixels, edge pixel + // value is returned + const sampler_t sampler = CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST; + kernel void sobel_rgb(read_only image2d_t src, write_only image2d_t dst) + { + int x = (int)get_global_id(0); + int y = (int)get_global_id(1); + + if (x >= get_image_width(src) || y >= get_image_height(src)) + return; + + // [(x-1, y+1), (x, y+1), (x+1, y+1)] + // [(x-1, y ), (x, y ), (x+1, y )] + // [(x-1, y-1), (x, y-1), (x+1, y-1)] + + // [p02, p12, p22] + // [p01, pixel, p21] + // [p00, p10, p20] + + //Basically finding influence of neighbour pixels on current pixel + float4 p00 = read_imagef(src, sampler, (int2)(x - 1, y - 1)); + float4 p10 = read_imagef(src, sampler, (int2)(x, y - 1)); + float4 p20 = read_imagef(src, sampler, (int2)(x + 1, y - 1)); + + float4 p01 = read_imagef(src, sampler, (int2)(x - 1, y)); + //pixel that we are working on + float4 p21 = read_imagef(src, sampler, (int2)(x + 1, y)); + + float4 p02 = read_imagef(src, sampler, (int2)(x - 1, y + 1)); + float4 p12 = read_imagef(src, sampler, (int2)(x, y + 1)); + float4 p22 = read_imagef(src, sampler, (int2)(x + 1, y + 1)); + + //Find Gx = kernel + 3x3 around current pixel + // Gx = [-1 0 +1] [p02, p12, p22] + // [-2 0 +2] + [p01, pixel, p21] + // [-1 0 +1] [p00, p10, p20] + float3 gx = -p00.xyz + p20.xyz + + 2.0f * (p21.xyz - p01.xyz) + -p02.xyz + p22.xyz; + + //Find Gy = kernel + 3x3 around current pixel + // Gy = [-1 -2 -1] [p02, p12, p22] + // [ 0 0 0] + [p01, pixel, p21] + // [+1 +2 +1] [p00, p10, p20] + float3 gy = p00.xyz + p20.xyz + + 2.0f * (- p12.xyz + p10.xyz) - + p02.xyz - p22.xyz; + //Find G + float3 g = native_sqrt(gx * gx + gy * gy); + + // we could also approximate this as g = fabs(gx) + fabs(gy) + write_imagef(dst, (int2)(x, y), (float4)(g.x, g.y, g.z, 1.0f)); + } +); + +// This example shows how to apply sobel filter on images or on camera frames +// with OpenCV, transfer the frames to the GPU, and apply a sobel filter +// written in OpenCL +int main(int argc, char *argv[]) +{ + /////////////////////////////////////////////////////////////////////////// + + // setup the command line arguments + po::options_description desc; + desc.add_options() + ("help", "show available options") + ("camera", po::value<int>()->default_value(-1), + "if not default camera, specify a camera id") + ("image", po::value<std::string>(), "path to image file"); + + // Parse the command lines + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //check the command line arguments + if(vm.count("help")) + { + std::cout << desc << std::endl; + return 0; + } + + /////////////////////////////////////////////////////////////////////////// + + //OpenCV variables + cv::Mat cv_mat; + cv::VideoCapture cap; //OpenCV camera handle. + + //OpenCL variables + // Get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + compute::program filter_program = + compute::program::create_with_source(source, context); + + try + { + filter_program.build(); + } + catch(compute::opencl_error e) + { + std::cout<<"Build Error: "<<std::endl + <<filter_program.build_log(); + } + + // create fliter kernel and set arguments + compute::kernel filter_kernel(filter_program, "sobel_rgb"); + + /////////////////////////////////////////////////////////////////////////// + + //check for image paths + if(vm.count("image")) + { + // Read image with OpenCV + cv_mat = cv::imread(vm["image"].as<std::string>(), + CV_LOAD_IMAGE_COLOR); + if(!cv_mat.data){ + std::cerr << "Failed to load image" << std::endl; + return -1; + } + } + else //by default use camera + { + //open camera + cap.open(vm["camera"].as<int>()); + // read first frame + cap >> cv_mat; + if(!cv_mat.data){ + std::cerr << "failed to capture frame" << std::endl; + return -1; + } + } + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA); + + // Transfer image/frame data to gpu + compute::image2d dev_input_image = + compute::opencv_create_image2d_with_mat( + cv_mat, compute::image2d::read_write, queue + ); + + // Create output image + // Be sure what will be your ouput image/frame size + compute::image2d dev_output_image( + context, + dev_input_image.width(), + dev_input_image.height(), + dev_input_image.format(), + compute::image2d::write_only + ); + + filter_kernel.set_arg(0, dev_input_image); + filter_kernel.set_arg(1, dev_output_image); + + + // run flip kernel + size_t origin[2] = { 0, 0 }; + size_t region[2] = { dev_input_image.width(), + dev_input_image.height() }; + + /////////////////////////////////////////////////////////////////////////// + + queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0); + + //check for image paths + if(vm.count("image")) + { + // show host image + cv::imshow("Original Image", cv_mat); + + // show gpu image + compute::opencv_imshow("Filtered Image", dev_output_image, queue); + + // wait and return + cv::waitKey(0); + } + else + { + char key = '\0'; + while(key != 27) //check for escape key + { + cap >> cv_mat; + + // Convert image to BGRA (OpenCL requires 16-byte aligned data) + cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA); + + // Update the device image memory with current frame data + compute::opencv_copy_mat_to_image(cv_mat, + dev_input_image,queue); + + // Run the kernel on the device + queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0); + + // Show host image + cv::imshow("Camera Frame", cv_mat); + + // Show GPU image + compute::opencv_imshow("Filtered RGB Frame", dev_output_image, queue); + + // wait + key = cv::waitKey(10); + } + } + return 0; +} diff --git a/src/boost/libs/compute/example/opengl_sphere.cpp b/src/boost/libs/compute/example/opengl_sphere.cpp new file mode 100644 index 00000000..38999f34 --- /dev/null +++ b/src/boost/libs/compute/example/opengl_sphere.cpp @@ -0,0 +1,242 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <algorithm> + +#include <GL/gl.h> + +#include <vtkActor.h> +#include <vtkCamera.h> +#include <vtkgl.h> +#include <vtkInteractorStyleSwitch.h> +#include <vtkMapper.h> +#include <vtkObjectFactory.h> +#include <vtkOpenGLExtensionManager.h> +#include <vtkOpenGLRenderWindow.h> +#include <vtkProperty.h> +#include <vtkRenderer.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkSmartPointer.h> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/interop/opengl.hpp> +#include <boost/compute/interop/vtk.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// tesselates a sphere with radius, phi_slices, and theta_slices. returns +// a shared opencl/opengl buffer containing the vertex data. +compute::opengl_buffer tesselate_sphere(float radius, + size_t phi_slices, + size_t theta_slices, + compute::command_queue &queue) +{ + using compute::dim; + + const compute::context &context = queue.get_context(); + + const size_t vertex_count = phi_slices * theta_slices; + + // create opengl buffer + GLuint vbo; + vtkgl::GenBuffersARB(1, &vbo); + vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, vbo); + vtkgl::BufferDataARB(vtkgl::ARRAY_BUFFER, + sizeof(float) * 4 * vertex_count, + NULL, + vtkgl::STREAM_DRAW); + vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, 0); + + // create shared opengl/opencl buffer + compute::opengl_buffer vertex_buffer(context, vbo); + + // tesselate_sphere kernel source + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void tesselate_sphere(float radius, + uint phi_slices, + uint theta_slices, + __global float4 *vertex_buffer) + { + const uint phi_i = get_global_id(0); + const uint theta_i = get_global_id(1); + + const float phi = phi_i * 2.f * M_PI_F / phi_slices; + const float theta = theta_i * 2.f * M_PI_F / theta_slices; + + float4 v; + v.x = radius * cos(theta) * cos(phi); + v.y = radius * cos(theta) * sin(phi); + v.z = radius * sin(theta); + v.w = 1.f; + + vertex_buffer[phi_i*phi_slices+theta_i] = v; + } + ); + + // build tesselate_sphere program + compute::program program = + compute::program::create_with_source(source, context); + program.build(); + + // setup tesselate_sphere kernel + compute::kernel kernel(program, "tesselate_sphere"); + kernel.set_arg<compute::float_>(0, radius); + kernel.set_arg<compute::uint_>(1, phi_slices); + kernel.set_arg<compute::uint_>(2, theta_slices); + kernel.set_arg(3, vertex_buffer); + + // acqurire buffer so that it is accessible to OpenCL + compute::opengl_enqueue_acquire_buffer(vertex_buffer, queue); + + // execute tesselate_sphere kernel + queue.enqueue_nd_range_kernel( + kernel, dim(0, 0), dim(phi_slices, theta_slices), dim(1, 1) + ); + + // release buffer so that it is accessible to OpenGL + compute::opengl_enqueue_release_buffer(vertex_buffer, queue); + + return vertex_buffer; +} + +// simple vtkMapper subclass to render the tesselated sphere on the gpu. +class gpu_sphere_mapper : public vtkMapper +{ +public: + vtkTypeMacro(gpu_sphere_mapper, vtkMapper) + + static gpu_sphere_mapper* New() + { + return new gpu_sphere_mapper; + } + + void Render(vtkRenderer *renderer, vtkActor *actor) + { + if(!m_initialized){ + Initialize(renderer, actor); + m_initialized = true; + } + + if(!m_tesselated){ + m_vertex_count = m_phi_slices * m_theta_slices; + + // tesselate sphere + m_vertex_buffer = tesselate_sphere( + m_radius, m_phi_slices, m_theta_slices, m_command_queue + ); + + // ensure tesselation is finished (seems to be required on AMD) + m_command_queue.finish(); + + // set tesselated flag to true + m_tesselated = true; + } + + // draw sphere + glEnableClientState(GL_VERTEX_ARRAY); + vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, m_vertex_buffer.get_opengl_object()); + glVertexPointer(4, GL_FLOAT, sizeof(float)*4, 0); + glDrawArrays(GL_POINTS, 0, m_vertex_count); + } + + void Initialize(vtkRenderer *renderer, vtkActor *actor) + { + // initialize opengl extensions + vtkOpenGLExtensionManager *extensions = + static_cast<vtkOpenGLRenderWindow *>(renderer->GetRenderWindow()) + ->GetExtensionManager(); + extensions->LoadExtension("GL_ARB_vertex_buffer_object"); + + // initialize opencl/opengl shared context + m_context = compute::opengl_create_shared_context(); + compute::device device = m_context.get_device(); + std::cout << "device: " << device.name() << std::endl; + + // create command queue for the gpu device + m_command_queue = compute::command_queue(m_context, device); + } + + double* GetBounds() + { + static double bounds[6]; + bounds[0] = -m_radius; bounds[1] = m_radius; + bounds[2] = -m_radius; bounds[3] = m_radius; + bounds[4] = -m_radius; bounds[5] = m_radius; + return bounds; + } + +protected: + gpu_sphere_mapper() + { + m_radius = 5.0f; + m_phi_slices = 100; + m_theta_slices = 100; + m_initialized = false; + m_tesselated = false; + } + +private: + float m_radius; + int m_phi_slices; + int m_theta_slices; + int m_vertex_count; + bool m_initialized; + bool m_tesselated; + compute::context m_context; + compute::command_queue m_command_queue; + compute::opengl_buffer m_vertex_buffer; +}; + +int main(int argc, char *argv[]) +{ + // create gpu sphere mapper + vtkSmartPointer<gpu_sphere_mapper> mapper = + vtkSmartPointer<gpu_sphere_mapper>::New(); + + // create actor for gpu sphere mapper + vtkSmartPointer<vtkActor> actor = + vtkSmartPointer<vtkActor>::New(); + actor->GetProperty()->LightingOff(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->SetMapper(mapper); + + // create render window + vtkSmartPointer<vtkRenderer> renderer = + vtkSmartPointer<vtkRenderer>::New(); + renderer->SetBackground(.1, .2, .31); + vtkSmartPointer<vtkRenderWindow> renderWindow = + vtkSmartPointer<vtkRenderWindow>::New(); + renderWindow->SetSize(800, 600); + renderWindow->AddRenderer(renderer); + vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = + vtkSmartPointer<vtkRenderWindowInteractor>::New(); + vtkInteractorStyleSwitch *interactorStyle = + vtkInteractorStyleSwitch::SafeDownCast( + renderWindowInteractor->GetInteractorStyle() + ); + interactorStyle->SetCurrentStyleToTrackballCamera(); + renderWindowInteractor->SetRenderWindow(renderWindow); + renderer->AddActor(actor); + + // render + renderer->ResetCamera(); + vtkCamera *camera = renderer->GetActiveCamera(); + camera->Elevation(-90.0); + renderWindowInteractor->Initialize(); + renderWindow->Render(); + renderWindowInteractor->Start(); + + return 0; +} diff --git a/src/boost/libs/compute/example/point_centroid.cpp b/src/boost/libs/compute/example/point_centroid.cpp new file mode 100644 index 00000000..e5691f7c --- /dev/null +++ b/src/boost/libs/compute/example/point_centroid.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. +//---------------------------------------------------------------------------// + +//[point_centroid_example + +#include <iostream> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/accumulate.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/types/fundamental.hpp> + +namespace compute = boost::compute; + +// the point centroid example calculates and displays the +// centroid of a set of 3D points stored as float4's +int main() +{ + using compute::float4_; + + // get default device and setup context + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + // point coordinates + float points[] = { 1.0f, 2.0f, 3.0f, 0.0f, + -2.0f, -3.0f, 4.0f, 0.0f, + 1.0f, -2.0f, 2.5f, 0.0f, + -7.0f, -3.0f, -2.0f, 0.0f, + 3.0f, 4.0f, -5.0f, 0.0f }; + + // create vector for five points + compute::vector<float4_> vector(5, context); + + // copy point data to the device + compute::copy( + reinterpret_cast<float4_ *>(points), + reinterpret_cast<float4_ *>(points) + 5, + vector.begin(), + queue + ); + + // calculate sum + float4_ sum = compute::accumulate( + vector.begin(), vector.end(), float4_(0, 0, 0, 0), queue + ); + + // calculate centroid + float4_ centroid; + for(size_t i = 0; i < 3; i++){ + centroid[i] = sum[i] / 5.0f; + } + + // print centroid + std::cout << "centroid: " << centroid << std::endl; + + return 0; +} + +//] diff --git a/src/boost/libs/compute/example/price_cross.cpp b/src/boost/libs/compute/example/price_cross.cpp new file mode 100644 index 00000000..95196494 --- /dev/null +++ b/src/boost/libs/compute/example/price_cross.cpp @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 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 <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/find_if.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/iterator/zip_iterator.hpp> + +namespace compute = boost::compute; + +// this example shows how to use the find_if() algorithm to detect the +// point at which two vectors of prices (such as stock prices) cross. +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + // prices #1 (from 10.0 to 11.0) + std::vector<float> prices1; + for(float i = 10.0; i <= 11.0; i += 0.1){ + prices1.push_back(i); + } + + // prices #2 (from 11.0 to 10.0) + std::vector<float> prices2; + for(float i = 11.0; i >= 10.0; i -= 0.1){ + prices2.push_back(i); + } + + // create gpu vectors + compute::vector<float> gpu_prices1(prices1.size(), context); + compute::vector<float> gpu_prices2(prices2.size(), context); + + // copy prices to gpu + compute::copy(prices1.begin(), prices1.end(), gpu_prices1.begin(), queue); + compute::copy(prices2.begin(), prices2.end(), gpu_prices2.begin(), queue); + + // function returning true if the second price is less than the first price + BOOST_COMPUTE_FUNCTION(bool, check_price_cross, (boost::tuple<float, float> prices), + { + // first price + const float first = boost_tuple_get(prices, 0); + + // second price + const float second = boost_tuple_get(prices, 1); + + // return true if second price is less than first + return second < first; + }); + + // find cross point (should be 10.5) + compute::vector<float>::iterator iter = boost::get<0>( + compute::find_if( + compute::make_zip_iterator( + boost::make_tuple(gpu_prices1.begin(), gpu_prices2.begin()) + ), + compute::make_zip_iterator( + boost::make_tuple(gpu_prices1.end(), gpu_prices2.end()) + ), + check_price_cross, + queue + ).get_iterator_tuple() + ); + + // print out result + int index = std::distance(gpu_prices1.begin(), iter); + std::cout << "price cross at index: " << index << std::endl; + + float value; + compute::copy_n(iter, 1, &value, queue); + std::cout << "value: " << value << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/print_vector.cpp b/src/boost/libs/compute/example/print_vector.cpp new file mode 100644 index 00000000..9ec5c6c7 --- /dev/null +++ b/src/boost/libs/compute/example/print_vector.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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/iota.hpp> +#include <boost/compute/container/vector.hpp> + +namespace compute = boost::compute; + +// this example demonstrates how to print the values in a vector +int main() +{ + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // create vector on the device and fill with the sequence 1..10 + compute::vector<int> vector(10, context); + compute::iota(vector.begin(), vector.end(), 1, queue); + +//[print_vector_example + std::cout << "vector: [ "; + boost::compute::copy( + vector.begin(), vector.end(), + std::ostream_iterator<int>(std::cout, ", "), + queue + ); + std::cout << "]" << std::endl; +//] + + return 0; +} diff --git a/src/boost/libs/compute/example/qimage_blur.cpp b/src/boost/libs/compute/example/qimage_blur.cpp new file mode 100644 index 00000000..cbfa3145 --- /dev/null +++ b/src/boost/libs/compute/example/qimage_blur.cpp @@ -0,0 +1,145 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 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 <iostream> +#include <algorithm> + +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtWidgets> +#else +#include <QtGui> +#endif + +#ifndef Q_MOC_RUN +#include <boost/compute/system.hpp> +#include <boost/compute/image/image2d.hpp> +#include <boost/compute/interop/qt.hpp> +#include <boost/compute/utility/dim.hpp> +#include <boost/compute/utility/source.hpp> +#endif // Q_MOC_RUN + +namespace compute = boost::compute; + +inline void box_filter_image(const compute::image2d &input, + compute::image2d &output, + compute::uint_ box_height, + compute::uint_ box_width, + compute::command_queue &queue) +{ + using compute::dim; + + const compute::context &context = queue.get_context(); + + // simple box filter kernel source + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void box_filter(__read_only image2d_t input, + __write_only image2d_t output, + uint box_height, + uint box_width) + { + int x = get_global_id(0); + int y = get_global_id(1); + int h = get_image_height(input); + int w = get_image_width(input); + int k = box_width; + int l = box_height; + + if(x < k/2 || y < l/2 || x >= w-(k/2) || y >= h-(l/2)){ + write_imagef(output, (int2)(x, y), (float4)(0, 0, 0, 1)); + } + else { + const sampler_t sampler = CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + + float4 sum = { 0, 0, 0, 0 }; + for(int i = 0; i < k; i++){ + for(int j = 0; j < l; j++){ + sum += read_imagef(input, sampler, (int2)(x+i-k, y+j-l)); + } + } + sum /= (float) k * l; + float4 value = (float4)( sum.x, sum.y, sum.z, 1.f ); + write_imagef(output, (int2)(x, y), value); + } + } + ); + + // build box filter program + compute::program program = + compute::program::create_with_source(source, context); + program.build(); + + // setup box filter kernel + compute::kernel kernel(program, "box_filter"); + kernel.set_arg(0, input); + kernel.set_arg(1, output); + kernel.set_arg(2, box_height); + kernel.set_arg(3, box_width); + + // execute the box filter kernel + queue.enqueue_nd_range_kernel(kernel, dim(0, 0), input.size(), dim(1, 1)); +} + +// this example shows how to load an image using Qt, apply a simple +// box blur filter, and then display it in a Qt window. +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + // check command line + if(argc < 2){ + std::cout << "usage: qimage_blur [FILENAME]" << std::endl; + return -1; + } + + // load image using Qt + QString fileName = argv[1]; + QImage qimage(fileName); + + size_t height = qimage.height(); + size_t width = qimage.width(); + size_t bytes_per_line = qimage.bytesPerLine(); + + qDebug() << "height:" << height + << "width:" << width + << "bytes per line:" << bytes_per_line + << "depth:" << qimage.depth() + << "format:" << qimage.format(); + + // create compute context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + std::cout << "device: " << gpu.name() << std::endl; + + // get the opencl image format for the qimage + compute::image_format format = + compute::qt_qimage_format_to_image_format(qimage.format()); + + // create input and output images on the gpu + compute::image2d input_image(context, width, height, format); + compute::image2d output_image(context, width, height, format); + + // copy host qimage to gpu image + compute::qt_copy_qimage_to_image2d(qimage, input_image, queue); + + // apply box filter + box_filter_image(input_image, output_image, 7, 7, queue); + + // copy gpu blurred image from to host qimage + compute::qt_copy_image2d_to_qimage(output_image, qimage, queue); + + // show image as a pixmap + QLabel label; + label.setPixmap(QPixmap::fromImage(qimage)); + label.show(); + + return app.exec(); +} diff --git a/src/boost/libs/compute/example/random_walk.cpp b/src/boost/libs/compute/example/random_walk.cpp new file mode 100644 index 00000000..13106d96 --- /dev/null +++ b/src/boost/libs/compute/example/random_walk.cpp @@ -0,0 +1,153 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <opencv2/core/core.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/imgproc/imgproc.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/inclusive_scan.hpp> +#include <boost/compute/algorithm/inclusive_scan.hpp> +#include <boost/compute/interop/opencv/core.hpp> +#include <boost/compute/interop/opencv/highgui.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/uniform_real_distribution.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +// this example uses the random-number generation functions in Boost.Compute +// to calculate a large number of random "steps" and then plots the final +// random "walk" in a 2D image on the GPU and displays it with OpenCV +int main() +{ + // number of random steps to take + size_t steps = 250000; + + // height and width of image + size_t height = 800; + size_t width = 800; + + // get default device and setup context + compute::device gpu = compute::system::default_device(); + compute::context context(gpu); + compute::command_queue queue(context, gpu); + + using compute::int2_; + + // calaculate random values for each step + compute::vector<float> random_values(steps, context); + compute::default_random_engine random_engine(queue); + compute::uniform_real_distribution<float> random_distribution(0.f, 4.f); + + random_distribution.generate( + random_values.begin(), random_values.end(), random_engine, queue + ); + + // calaculate coordinates for each step + compute::vector<int2_> coordinates(steps, context); + + // function to convert random values to random directions (in 2D) + BOOST_COMPUTE_FUNCTION(int2_, take_step, (const float x), + { + if(x < 1.f){ + // move right + return (int2)(1, 0); + } + if(x < 2.f){ + // move up + return (int2)(0, 1); + } + if(x < 3.f){ + // move left + return (int2)(-1, 0); + } + else { + // move down + return (int2)(0, -1); + } + }); + + // transform the random values into random steps + compute::transform( + random_values.begin(), random_values.end(), coordinates.begin(), take_step, queue + ); + + // set staring position + int2_ starting_position(width / 2, height / 2); + compute::copy_n(&starting_position, 1, coordinates.begin(), queue); + + // scan steps to calculate position after each step + compute::inclusive_scan( + coordinates.begin(), coordinates.end(), coordinates.begin(), queue + ); + + // create output image + compute::image2d image( + context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8) + ); + + // program with two kernels, one to fill the image with white, and then + // one the draw to points calculated in coordinates on the image + const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void draw_walk(__global const int2 *coordinates, + __write_only image2d_t image) + { + const uint i = get_global_id(0); + const int2 coord = coordinates[i]; + + if(coord.x > 0 && coord.x < get_image_width(image) && + coord.y > 0 && coord.y < get_image_height(image)){ + uint4 black = { 0, 0, 0, 0 }; + write_imageui(image, coord, black); + } + } + + __kernel void fill_white(__write_only image2d_t image) + { + const int2 coord = { get_global_id(0), get_global_id(1) }; + + if(coord.x < get_image_width(image) && + coord.y < get_image_height(image)){ + uint4 white = { 255, 255, 255, 255 }; + write_imageui(image, coord, white); + } + } + ); + + // build the program + compute::program draw_program = + compute::program::build_with_source(draw_walk_source, context); + + // fill image with white + compute::kernel fill_kernel(draw_program, "fill_white"); + fill_kernel.set_arg(0, image); + + const size_t offset[] = { 0, 0 }; + const size_t bounds[] = { width, height }; + + queue.enqueue_nd_range_kernel(fill_kernel, 2, offset, bounds, 0); + + // draw random walk + compute::kernel draw_kernel(draw_program, "draw_walk"); + draw_kernel.set_arg(0, coordinates); + draw_kernel.set_arg(1, image); + queue.enqueue_1d_range_kernel(draw_kernel, 0, coordinates.size(), 0); + + // show image + compute::opencv_imshow("random walk", image, queue); + + // wait and return + cv::waitKey(0); + + return 0; +} diff --git a/src/boost/libs/compute/example/resize_image.cpp b/src/boost/libs/compute/example/resize_image.cpp new file mode 100644 index 00000000..d9e29edd --- /dev/null +++ b/src/boost/libs/compute/example/resize_image.cpp @@ -0,0 +1,253 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <algorithm> + +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtWidgets> +#else +#include <QtGui> +#endif +#include <QtOpenGL> + +#include <boost/program_options.hpp> + +#ifndef Q_MOC_RUN +#include <boost/compute/command_queue.hpp> +#include <boost/compute/kernel.hpp> +#include <boost/compute/program.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/image/image2d.hpp> +#include <boost/compute/image/image_sampler.hpp> +#include <boost/compute/interop/qt.hpp> +#include <boost/compute/interop/opengl.hpp> +#include <boost/compute/utility/source.hpp> +#endif // Q_MOC_RUN + +namespace compute = boost::compute; +namespace po = boost::program_options; + +// opencl source code +const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void resize_image(__read_only image2d_t input, + const sampler_t sampler, + __write_only image2d_t output) + { + const uint x = get_global_id(0); + const uint y = get_global_id(1); + + const float w = get_image_width(output); + const float h = get_image_height(output); + + float2 coord = { ((float) x / w) * get_image_width(input), + ((float) y / h) * get_image_height(input) }; + + float4 pixel = read_imagef(input, sampler, coord); + write_imagef(output, (int2)(x, h - y - 1), pixel); + }; +); + +class ImageWidget : public QGLWidget +{ + Q_OBJECT + +public: + ImageWidget(QString fileName, QWidget *parent = 0); + ~ImageWidget(); + + void initializeGL(); + void resizeGL(int width, int height); + void paintGL(); + +private: + QImage qt_image_; + compute::context context_; + compute::command_queue queue_; + compute::program program_; + compute::image2d image_; + compute::image_sampler sampler_; + GLuint gl_texture_; + compute::opengl_texture cl_texture_; +}; + +ImageWidget::ImageWidget(QString fileName, QWidget *parent) + : QGLWidget(parent), + qt_image_(fileName) +{ + gl_texture_ = 0; +} + +ImageWidget::~ImageWidget() +{ +} + +void ImageWidget::initializeGL() +{ + // setup opengl + glDisable(GL_LIGHTING); + + // create the OpenGL/OpenCL shared context + context_ = compute::opengl_create_shared_context(); + + // get gpu device + compute::device gpu = context_.get_device(); + std::cout << "device: " << gpu.name() << std::endl; + + // setup command queue + queue_ = compute::command_queue(context_, gpu); + + // allocate image on the device + compute::image_format format = + compute::qt_qimage_format_to_image_format(qt_image_.format()); + + image_ = compute::image2d( + context_, qt_image_.width(), qt_image_.height(), format, CL_MEM_READ_ONLY + ); + + // transfer image to the device + compute::qt_copy_qimage_to_image2d(qt_image_, image_, queue_); + + // setup image sampler (use CL_FILTER_NEAREST to disable linear interpolation) + sampler_ = compute::image_sampler( + context_, false, CL_ADDRESS_NONE, CL_FILTER_LINEAR + ); + + // build resize program + program_ = compute::program::build_with_source(source, context_); +} + +void ImageWidget::resizeGL(int width, int height) +{ +#if QT_VERSION >= 0x050000 + // scale height/width based on device pixel ratio + width /= windowHandle()->devicePixelRatio(); + height /= windowHandle()->devicePixelRatio(); +#endif + + // resize viewport + glViewport(0, 0, width, height); + + // delete old texture + if(gl_texture_){ + glDeleteTextures(1, &gl_texture_); + gl_texture_ = 0; + } + + // generate new texture + glGenTextures(1, &gl_texture_); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 + ); + + // create opencl object for the texture + cl_texture_ = compute::opengl_texture( + context_, GL_TEXTURE_2D, 0, gl_texture_, CL_MEM_WRITE_ONLY + ); +} + +void ImageWidget::paintGL() +{ + float w = width(); + float h = height(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, w, 0.0, h, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // setup the resize kernel + compute::kernel kernel(program_, "resize_image"); + kernel.set_arg(0, image_); + kernel.set_arg(1, sampler_); + kernel.set_arg(2, cl_texture_); + + // acquire the opengl texture so it can be used in opencl + compute::opengl_enqueue_acquire_gl_objects(1, &cl_texture_.get(), queue_); + + // execute the resize kernel + const size_t global_work_offset[] = { 0, 0 }; + const size_t global_work_size[] = { size_t(width()), size_t(height()) }; + + queue_.enqueue_nd_range_kernel( + kernel, 2, global_work_offset, global_work_size, 0 + ); + + // release the opengl texture so it can be used by opengl + compute::opengl_enqueue_release_gl_objects(1, &cl_texture_.get(), queue_); + + // ensure opencl is finished before rendering in opengl + queue_.finish(); + + // draw a single quad with the resized image texture + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(0, 1); glVertex2f(0, h); + glTexCoord2f(1, 1); glVertex2f(w, h); + glTexCoord2f(1, 0); glVertex2f(w, 0); + glEnd(); +} + +// the resize image example demonstrates how to interactively resize a +// 2D image and display it using OpenGL. a image sampler is used to perform +// hardware-accelerated linear interpolation for the resized image. +int main(int argc, char *argv[]) +{ + // setup command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("file", po::value<std::string>(), "image file name (e.g. /path/to/image.png)") + ; + po::positional_options_description positional_options; + positional_options.add("file", 1); + + // parse command line + po::variables_map vm; + po::store( + po::command_line_parser(argc, argv) + .options(options) + .positional(positional_options) + .run(), + vm + ); + po::notify(vm); + + // check for file argument + if(vm.count("help") || !vm.count("file")){ + std::cout << options << std::endl; + return -1; + } + + // get file name + std::string file_name = vm["file"].as<std::string>(); + + // setup qt application + QApplication app(argc, argv); + + // setup image widget + ImageWidget widget(QString::fromStdString(file_name)); + widget.show(); + + // run qt application + return app.exec(); +} + +#include "resize_image.moc" diff --git a/src/boost/libs/compute/example/simple_kernel.cpp b/src/boost/libs/compute/example/simple_kernel.cpp new file mode 100644 index 00000000..4aa1872f --- /dev/null +++ b/src/boost/libs/compute/example/simple_kernel.cpp @@ -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. +//---------------------------------------------------------------------------// + +#include <iostream> + +#include <boost/compute/core.hpp> + +namespace compute = boost::compute; + +// this example demonstrates how to use the Boost.Compute classes to +// setup and run a simple vector addition kernel on the GPU +int main() +{ + // get the default device + compute::device device = compute::system::default_device(); + + // create a context for the device + compute::context context(device); + + // setup input arrays + float a[] = { 1, 2, 3, 4 }; + float b[] = { 5, 6, 7, 8 }; + + // make space for the output + float c[] = { 0, 0, 0, 0 }; + + // create memory buffers for the input and output + compute::buffer buffer_a(context, 4 * sizeof(float)); + compute::buffer buffer_b(context, 4 * sizeof(float)); + compute::buffer buffer_c(context, 4 * sizeof(float)); + + // source code for the add kernel + const char source[] = + "__kernel void add(__global const float *a," + " __global const float *b," + " __global float *c)" + "{" + " const uint i = get_global_id(0);" + " c[i] = a[i] + b[i];" + "}"; + + // create the program with the source + compute::program program = + compute::program::create_with_source(source, context); + + // compile the program + program.build(); + + // create the kernel + compute::kernel kernel(program, "add"); + + // set the kernel arguments + kernel.set_arg(0, buffer_a); + kernel.set_arg(1, buffer_b); + kernel.set_arg(2, buffer_c); + + // create a command queue + compute::command_queue queue(context, device); + + // write the data from 'a' and 'b' to the device + queue.enqueue_write_buffer(buffer_a, 0, 4 * sizeof(float), a); + queue.enqueue_write_buffer(buffer_b, 0, 4 * sizeof(float), b); + + // run the add kernel + queue.enqueue_1d_range_kernel(kernel, 0, 4, 0); + + // transfer results back to the host array 'c' + queue.enqueue_read_buffer(buffer_c, 0, 4 * sizeof(float), c); + + // print out results in 'c' + std::cout << "c: [" << c[0] << ", " + << c[1] << ", " + << c[2] << ", " + << c[3] << "]" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/simple_moving_average.cpp b/src/boost/libs/compute/example/simple_moving_average.cpp new file mode 100644 index 00000000..968db393 --- /dev/null +++ b/src/boost/libs/compute/example/simple_moving_average.cpp @@ -0,0 +1,139 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Benoit Dequidt <benoit.dequidt@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 <iostream> +#include <cstdlib> + +#include <boost/compute/core.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/inclusive_scan.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/type_traits/type_name.hpp> +#include <boost/compute/utility/source.hpp> + +namespace compute = boost::compute; + +/// warning precision is not precise due +/// to the float error accumulation when size is large enough +/// for more precision use double +/// or a kahan sum else results can diverge +/// from the CPU implementation +compute::program make_sma_program(const compute::context& context) +{ + const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE( + __kernel void SMA(__global const float *scannedValues, int size, __global float *output, int wSize) + { + const int gid = get_global_id(0); + + float cumValues = 0.f; + int endIdx = gid + wSize/2; + int startIdx = gid -1 - wSize/2; + + if(endIdx > size -1) + endIdx = size -1; + + cumValues += scannedValues[endIdx]; + if(startIdx < 0) + startIdx = -1; + else + cumValues -= scannedValues[startIdx]; + + output[gid] =(float)( cumValues / ( float )(endIdx - startIdx)); + } + ); + + // create sma program + return compute::program::build_with_source(source,context); +} + +bool check_results(const std::vector<float>& values, const std::vector<float>& smoothValues, unsigned int wSize) +{ + int size = values.size(); + if(size != (int)smoothValues.size()) return false; + + int semiWidth = wSize/2; + + bool ret = true; + for(int idx = 0 ; idx < size ; ++idx) + { + int start = (std::max)(idx - semiWidth,0); + int end = (std::min)(idx + semiWidth,size-1); + float res = 0; + for(int j = start ; j <= end ; ++j) + { + res+= values[j]; + } + + res /= float(end - start +1); + + if(std::abs(res-smoothValues[idx]) > 1e-3) + { + std::cout << "idx = " << idx << " -- expected = " << res << " -- result = " << smoothValues[idx] << std::endl; + ret = false; + } + } + + return ret; +} + +// generate a uniform law over [0,10] +float myRand() +{ + static const double divisor = double(RAND_MAX)+1.; + return double(rand())/divisor * 10.; +} + +int main() +{ + unsigned int size = 1024; + // wSize must be odd + unsigned int wSize = 21; + // get the default device + compute::device device = compute::system::default_device(); + // create a context for the device + compute::context context(device); + // get the program + compute::program program = make_sma_program(context); + + // create vector of random numbers on the host + std::vector<float> host_vector(size); + std::vector<float> host_result(size); + std::generate(host_vector.begin(), host_vector.end(), myRand); + + compute::vector<float> a(size,context); + compute::vector<float> b(size,context); + compute::vector<float> c(size,context); + compute::command_queue queue(context, device); + + compute::copy(host_vector.begin(),host_vector.end(),a.begin(),queue); + + // scan values + compute::inclusive_scan(a.begin(),a.end(),b.begin(),queue); + // sma kernel + compute::kernel kernel(program, "SMA"); + kernel.set_arg(0,b.get_buffer()); + kernel.set_arg(1,(int)b.size()); + kernel.set_arg(2,c.get_buffer()); + kernel.set_arg(3,(int)wSize); + + using compute::uint_; + uint_ tpb = 128; + uint_ workSize = size; + queue.enqueue_1d_range_kernel(kernel,0,workSize,tpb); + + compute::copy(c.begin(),c.end(),host_result.begin(),queue); + + bool res = check_results(host_vector,host_result,wSize); + std::string status = res ? "results are equivalent" : "GPU results differs from CPU one's"; + std::cout << status << std::endl; + + return 0; +} + diff --git a/src/boost/libs/compute/example/sort_vector.cpp b/src/boost/libs/compute/example/sort_vector.cpp new file mode 100644 index 00000000..39ec8ea7 --- /dev/null +++ b/src/boost/libs/compute/example/sort_vector.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> + +namespace compute = boost::compute; + +int rand_int() +{ + return rand() % 100; +} + +// this example demonstrates how to sort a vector of ints on the GPU +int main() +{ + // create vector of random values on the host + std::vector<int> host_vector(10); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // print out input vector + std::cout << "input: [ "; + for(size_t i = 0; i < host_vector.size(); i++){ + std::cout << host_vector[i]; + + if(i != host_vector.size() - 1){ + std::cout << ", "; + } + } + std::cout << " ]" << std::endl; + + // transfer the values to the device + compute::vector<int> device_vector = host_vector; + + // sort the values on the device + compute::sort(device_vector.begin(), device_vector.end()); + + // transfer the values back to the host + compute::copy(device_vector.begin(), + device_vector.end(), + host_vector.begin()); + + // print out the sorted vector + std::cout << "output: [ "; + for(size_t i = 0; i < host_vector.size(); i++){ + std::cout << host_vector[i]; + + if(i != host_vector.size() - 1){ + std::cout << ", "; + } + } + std::cout << " ]" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/example/threefry_engine.cpp b/src/boost/libs/compute/example/threefry_engine.cpp new file mode 100644 index 00000000..5cbf6c8e --- /dev/null +++ b/src/boost/libs/compute/example/threefry_engine.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + + +#include <boost/compute/random/threefry_engine.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/context.hpp> +#include <boost/compute/device.hpp> +#include <boost/compute/system.hpp> +#include <iostream> + +int main() +{ + using boost::compute::uint_; + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + boost::compute::threefry_engine<> rng(queue); + boost::compute::vector<uint_> vector_ctr(20, context); + + uint32_t ctr[20]; + for(int i = 0; i < 10; i++) { + ctr[i*2] = i; + ctr[i*2+1] = 0; + } + boost::compute::copy(ctr, ctr+20, vector_ctr.begin(), queue); + rng.generate(vector_ctr.begin(), vector_ctr.end(), queue); + boost::compute::copy(vector_ctr.begin(), vector_ctr.end(), ctr, queue); + + for(int i = 0; i < 10; i++) { + std::cout << std::hex << ctr[i*2] << " " << ctr[i*2+1] << std::endl; + } + return 0; +} + diff --git a/src/boost/libs/compute/example/time_copy.cpp b/src/boost/libs/compute/example/time_copy.cpp new file mode 100644 index 00000000..35168770 --- /dev/null +++ b/src/boost/libs/compute/example/time_copy.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +//[time_copy_example + +#include <vector> +#include <cstdlib> +#include <iostream> + +#include <boost/compute/event.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/async/future.hpp> +#include <boost/compute/container/vector.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get the default device + compute::device gpu = compute::system::default_device(); + + // create context for default device + compute::context context(gpu); + + // create command queue with profiling enabled + compute::command_queue queue( + context, gpu, compute::command_queue::enable_profiling + ); + + // generate random data on the host + std::vector<int> host_vector(16000000); + std::generate(host_vector.begin(), host_vector.end(), rand); + + // create a vector on the device + compute::vector<int> device_vector(host_vector.size(), context); + + // copy data from the host to the device + compute::future<void> future = compute::copy_async( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // wait for copy to finish + future.wait(); + + // get elapsed time from event profiling information + boost::chrono::milliseconds duration = + future.get_event().duration<boost::chrono::milliseconds>(); + + // print elapsed time in milliseconds + std::cout << "time: " << duration.count() << " ms" << std::endl; + + return 0; +} + +//] diff --git a/src/boost/libs/compute/example/transform_sqrt.cpp b/src/boost/libs/compute/example/transform_sqrt.cpp new file mode 100644 index 00000000..860063fc --- /dev/null +++ b/src/boost/libs/compute/example/transform_sqrt.cpp @@ -0,0 +1,58 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +//[transform_sqrt_example + +#include <vector> +#include <algorithm> + +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/math.hpp> + +namespace compute = boost::compute; + +int main() +{ + // get default device and setup context + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + // generate random data on the host + std::vector<float> host_vector(10000); + std::generate(host_vector.begin(), host_vector.end(), rand); + + // create a vector on the device + compute::vector<float> device_vector(host_vector.size(), context); + + // transfer data from the host to the device + compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // calculate the square-root of each element in-place + compute::transform( + device_vector.begin(), + device_vector.end(), + device_vector.begin(), + compute::sqrt<float>(), + queue + ); + + // copy values back to the host + compute::copy( + device_vector.begin(), device_vector.end(), host_vector.begin(), queue + ); + + return 0; +} + +//] diff --git a/src/boost/libs/compute/example/vector_addition.cpp b/src/boost/libs/compute/example/vector_addition.cpp new file mode 100644 index 00000000..1f3aa92d --- /dev/null +++ b/src/boost/libs/compute/example/vector_addition.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. +//---------------------------------------------------------------------------// + +#include <iostream> + +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/functional/operator.hpp> + +namespace compute = boost::compute; + +// this example demonstrates how to use Boost.Compute's STL +// implementation to add two vectors on the GPU +int main() +{ + // setup input arrays + float a[] = { 1, 2, 3, 4 }; + float b[] = { 5, 6, 7, 8 }; + + // make space for the output + float c[] = { 0, 0, 0, 0 }; + + // create vectors and transfer data for the input arrays 'a' and 'b' + compute::vector<float> vector_a(a, a + 4); + compute::vector<float> vector_b(b, b + 4); + + // create vector for the output array + compute::vector<float> vector_c(4); + + // add the vectors together + compute::transform( + vector_a.begin(), + vector_a.end(), + vector_b.begin(), + vector_c.begin(), + compute::plus<float>() + ); + + // transfer results back to the host array 'c' + compute::copy(vector_c.begin(), vector_c.end(), c); + + // print out results in 'c' + std::cout << "c: [" << c[0] << ", " + << c[1] << ", " + << c[2] << ", " + << c[3] << "]" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/index.html b/src/boost/libs/compute/index.html new file mode 100644 index 00000000..a5accd49 --- /dev/null +++ b/src/boost/libs/compute/index.html @@ -0,0 +1,20 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=doc/html/index.html"> +</head> +<body> +Automatic redirection failed, please go to +<a href="doc/html/index.html">doc/html/index.html</a> +<hr> +<tt> +Boost.Compute<br> +<br> +Copyright (C) 2013-2015 Kyle Lutz<br> +<br> +Distributed under the Boost Software License, Version 1.0. (See +accompanying file LICENSE_1_0.txt or copy at +<a href=http://www.boost.org/LICENSE_1_0.txt>http://www.boost.org/LICENSE_1_0.txt</a>) <br> +<br> +</tt> +</body> +</html> diff --git a/src/boost/libs/compute/meta/libraries.json b/src/boost/libs/compute/meta/libraries.json new file mode 100644 index 00000000..9e70fdd4 --- /dev/null +++ b/src/boost/libs/compute/meta/libraries.json @@ -0,0 +1,14 @@ +{ + "key": "compute", + "name": "Compute", + "authors": [ + "Kyle Lutz" + ], + "description": "Parallel/GPU-computing library", + "category": [ + "Concurrent" + ], + "maintainers": [ + "Kyle Lutz <kyle.r.lutz -at- gmail.com>" + ] +} diff --git a/src/boost/libs/compute/perf/CMakeLists.txt b/src/boost/libs/compute/perf/CMakeLists.txt new file mode 100644 index 00000000..b04429e9 --- /dev/null +++ b/src/boost/libs/compute/perf/CMakeLists.txt @@ -0,0 +1,210 @@ +# --------------------------------------------------------------------------- +# 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(PERF_BOOST_COMPONENTS system timer chrono program_options) + +if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) + set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} filesystem) +endif() + +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} thread) +elseif(${BOOST_COMPUTE_HAVE_BOLT} AND ${BOOST_COMPUTE_USE_CPP11}) + set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} thread) +endif() + +if(${BOOST_COMPUTE_HAVE_BOLT} AND ${BOOST_COMPUTE_USE_CPP11}) + set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} date_time) +endif() + +if(PERF_BOOST_COMPONENTS) + list(REMOVE_DUPLICATES PERF_BOOST_COMPONENTS) +endif() +find_package(Boost 1.54 REQUIRED COMPONENTS ${PERF_BOOST_COMPONENTS}) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + +set(BENCHMARKS + accumulate + bernoulli_distribution + binary_find + cart_to_polar + comparison_sort + copy_if + copy_to_device + count + discrete_distribution + erase_remove + exclusive_scan + fill + find + find_end + includes + inner_product + is_permutation + is_sorted + max_element + merge + next_permutation + nth_element + partial_sum + partition + partition_point + prev_permutation + reverse + reverse_copy + rotate + rotate_copy + host_sort + random_number_engine + reduce_by_key + saxpy + search + search_n + set_difference + set_intersection + set_symmetric_difference + set_union + sort + sort_by_key + sort_float + stable_partition + uniform_int_distribution + unique + unique_copy +) + +foreach(BENCHMARK ${BENCHMARKS}) + set(PERF_TARGET perf_${BENCHMARK}) + add_executable(${PERF_TARGET} perf_${BENCHMARK}.cpp) + target_link_libraries(${PERF_TARGET} ${OpenCL_LIBRARIES} ${Boost_LIBRARIES}) +endforeach() + +# stl benchmarks (for comparison) +set(STL_BENCHMARKS + stl_accumulate + stl_count + stl_find + stl_find_end + stl_includes + stl_inner_product + stl_max_element + stl_merge + stl_next_permutation + stl_partial_sum + stl_partition + stl_prev_permutation + stl_reverse + stl_reverse_copy + stl_rotate + stl_rotate_copy + stl_saxpy + stl_search + stl_search_n + stl_set_difference + stl_set_intersection + stl_set_symmetric_difference + stl_set_union + stl_sort + stl_stable_partition + stl_unique + stl_unique_copy +) + +# stl benchmarks which require c++11 +if(${BOOST_COMPUTE_USE_CPP11}) + list(APPEND + STL_BENCHMARKS + stl_is_permutation + stl_partition_point + ) +endif() + +foreach(BENCHMARK ${STL_BENCHMARKS}) + set(PERF_TARGET perf_${BENCHMARK}) + add_executable(${PERF_TARGET} perf_${BENCHMARK}.cpp) + target_link_libraries(${PERF_TARGET} ${Boost_LIBRARIES}) +endforeach() + +# cuda/thrust benchmarks (for comparison) +if(${BOOST_COMPUTE_HAVE_CUDA}) + find_package(CUDA 5.0 REQUIRED) + + set(CUDA_BENCHMARKS + thrust_accumulate + thrust_count + thrust_exclusive_scan + thrust_find + thrust_inner_product + thrust_merge + thrust_partial_sum + thrust_partition + thrust_reduce_by_key + thrust_reverse + thrust_reverse_copy + thrust_rotate + thrust_saxpy + thrust_set_difference + thrust_sort + thrust_unique + ) + + foreach(BENCHMARK ${CUDA_BENCHMARKS}) + set(PERF_TARGET perf_${BENCHMARK}) + cuda_add_executable(${PERF_TARGET} perf_${BENCHMARK}.cu) + target_link_libraries(${PERF_TARGET} ${CUDA_LIBRARIES} ${Boost_LIBRARIES}) + endforeach() +endif() + +# intel tbb benchmarks (for comparison) +if(${BOOST_COMPUTE_HAVE_TBB}) + find_package(TBB REQUIRED) + include_directories(SYSTEM ${TBB_INCLUDE_DIRS}) + + set(TBB_BENCHMARKS + tbb_accumulate + tbb_merge + tbb_sort + ) + + foreach(BENCHMARK ${TBB_BENCHMARKS}) + set(PERF_TARGET perf_${BENCHMARK}) + add_executable(${PERF_TARGET} perf_${BENCHMARK}.cpp) + target_link_libraries(${PERF_TARGET} ${TBB_LIBRARIES} ${Boost_LIBRARIES}) + endforeach() +endif() + +# bolt c++ template lib benchmarks (for comparison) +if(${BOOST_COMPUTE_HAVE_BOLT} AND ${BOOST_COMPUTE_USE_CPP11}) + find_package(Bolt REQUIRED) + include_directories(SYSTEM ${BOLT_INCLUDE_DIRS}) + + set(BOLT_BENCHMARKS + bolt_accumulate + bolt_count + bolt_exclusive_scan + bolt_fill + bolt_inner_product + bolt_max_element + bolt_merge + bolt_partial_sum + bolt_reduce_by_key + bolt_saxpy + bolt_sort + ) + + foreach(BENCHMARK ${BOLT_BENCHMARKS}) + set(PERF_TARGET perf_${BENCHMARK}) + add_executable(${PERF_TARGET} perf_${BENCHMARK}.cpp) + target_link_libraries(${PERF_TARGET} ${OpenCL_LIBRARIES} ${BOLT_LIBRARIES} ${Boost_LIBRARIES}) + endforeach() +elseif(${BOOST_COMPUTE_HAVE_BOLT} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + message(WARNING "BOOST_COMPUTE_USE_CPP11 must be ON for building Bolt C++ Template Library performance tests.") +endif() diff --git a/src/boost/libs/compute/perf/perf.hpp b/src/boost/libs/compute/perf/perf.hpp new file mode 100644 index 00000000..cce0328c --- /dev/null +++ b/src/boost/libs/compute/perf/perf.hpp @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#ifndef PERF_HPP +#define PERF_HPP + +// this header contains general purpose functions and variables used by +// the boost.compute performance benchmarks. + +#include <vector> +#include <cstdlib> +#include <algorithm> + +#include <boost/lexical_cast.hpp> +#include <boost/timer/timer.hpp> + +static size_t PERF_N = 1024; +static size_t PERF_TRIALS = 3; + +// parses command line arguments and sets the corresponding perf variables +inline void perf_parse_args(int argc, char *argv[]) +{ + if(argc >= 2){ + PERF_N = boost::lexical_cast<size_t>(argv[1]); + } + + if(argc >= 3){ + PERF_TRIALS = boost::lexical_cast<size_t>(argv[2]); + } +} + +// generates a vector of random numbers +template<class T> +std::vector<T> generate_random_vector(const size_t size) +{ + std::vector<T> vector(size); + std::generate(vector.begin(), vector.end(), rand); + return vector; +} + +// a simple timer wrapper which records multiple time entries +class perf_timer +{ +public: + typedef boost::timer::nanosecond_type nanosecond_type; + + perf_timer() + { + timer.stop(); + } + + void start() + { + timer.start(); + } + + void stop() + { + timer.stop(); + times.push_back(timer.elapsed().wall); + } + + size_t trials() const + { + return times.size(); + } + + void clear() + { + times.clear(); + } + + nanosecond_type last_time() const + { + return times.back(); + } + + nanosecond_type min_time() const + { + return *std::min_element(times.begin(), times.end()); + } + + nanosecond_type max_time() const + { + return *std::max_element(times.begin(), times.end()); + } + + boost::timer::cpu_timer timer; + std::vector<boost::timer::nanosecond_type> times; +}; + +// returns the rate (in MB/s) for processing 'count' items of type 'T' +// in 'time' nanoseconds +template<class T> +double perf_rate(const size_t count, perf_timer::nanosecond_type time) +{ + const size_t byte_count = count * sizeof(T); + + return (double(byte_count) / 1024 / 1024) / (time / 1e9); +} + +#endif // PERF_HPP diff --git a/src/boost/libs/compute/perf/perf.py b/src/boost/libs/compute/perf/perf.py new file mode 100755 index 00000000..c7b33f63 --- /dev/null +++ b/src/boost/libs/compute/perf/perf.py @@ -0,0 +1,238 @@ +#!/usr/bin/python + +# Copyright (c) 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. + +# driver script for boost.compute benchmarking. will run a +# benchmark for a given function (e.g. accumulate, sort). + +import os +import sys +import subprocess + +try: + import pylab +except: + print('pylab not found, no ploting...') + pass + +def run_perf_process(name, size, backend = ""): + if not backend: + proc = "perf_%s" % name + else: + proc = "perf_%s_%s" % (backend, name) + + filename = "./perf/" + proc + + if not os.path.isfile(filename): + print("Error: failed to find ", filename, " for running") + return 0 + try: + output = subprocess.check_output([filename, str(int(size))]) + except: + return 0 + + t = 0 + for line in output.decode('utf8').split("\n"): + if line.startswith("time:"): + t = float(line.split(":")[1].split()[0]) + + return t + +class Report: + def __init__(self, name): + self.name = name + self.samples = {} + + def add_sample(self, name, size, time): + if not name in self.samples: + self.samples[name] = [] + + self.samples[name].append((size, time)) + + def display(self): + for name in self.samples.keys(): + print('=== %s with %s ===' % (self.name, name)) + print('size,time (ms)') + + for sample in self.samples[name]: + print('%d,%f' % sample) + + def plot_time(self, name): + if not name in self.samples: + return + + x = [] + y = [] + + any_valid_samples = False + + for sample in self.samples[name]: + if sample[1] == 0: + continue + + x.append(sample[0]) + y.append(sample[1]) + any_valid_samples = True + + if not any_valid_samples: + return + + pylab.loglog(x, y, marker='o', label=name) + pylab.xlabel("Size") + pylab.ylabel("Time (ms)") + pylab.title(self.name) + + def plot_rate(self, name): + if not name in self.samples: + return + + x = [] + y = [] + + any_valid_samples = False + + for sample in self.samples[name]: + if sample[1] == 0: + continue + + x.append(sample[0]) + y.append(float(sample[0]) / (float(sample[1]) * 1e-3)) + any_valid_samples = True + + if not any_valid_samples: + return + + pylab.loglog(x, y, marker='o', label=name) + pylab.xlabel("Size") + pylab.ylabel("Rate (values/s)") + pylab.title(self.name) + +def run_benchmark(name, sizes, vs=[]): + report = Report(name) + + for size in sizes: + time = run_perf_process(name, size) + + report.add_sample("compute", size, time) + + competitors = { + "thrust" : [ + "accumulate", + "count", + "exclusive_scan", + "find", + "inner_product", + "merge", + "partial_sum", + "partition", + "reduce_by_key", + "reverse", + "reverse_copy", + "rotate", + "saxpy", + "sort", + "unique" + ], + "bolt" : [ + "accumulate", + "count", + "exclusive_scan", + "fill", + "inner_product", + "max_element", + "merge", + "partial_sum", + "reduce_by_key", + "saxpy", + "sort" + ], + "tbb": [ + "accumulate", + "merge", + "sort" + ], + "stl": [ + "accumulate", + "count", + "find", + "find_end", + "includes", + "inner_product", + "is_permutation", + "max_element", + "merge", + "next_permutation", + "nth_element", + "partial_sum", + "partition", + "partition_point", + "prev_permutation", + "reverse", + "reverse_copy", + "rotate", + "rotate_copy", + "saxpy", + "search", + "search_n", + "set_difference", + "set_intersection", + "set_symmetric_difference", + "set_union", + "sort", + "stable_partition", + "unique", + "unique_copy" + ] + } + + for other in vs: + if not other in competitors: + continue + if not name in competitors[other]: + continue + + for size in sizes: + time = run_perf_process(name, size, other) + report.add_sample(other, size, time) + + return report + +if __name__ == '__main__': + test = "sort" + if len(sys.argv) >= 2: + test = sys.argv[1] + print('running %s perf test' % test) + + sizes = [ pow(2, x) for x in range(1, 26) ] + + sizes = sorted(sizes) + + competitors = ["bolt", "tbb", "thrust", "stl"] + + report = run_benchmark(test, sizes, competitors) + + plot = None + if "--plot-time" in sys.argv: + plot = "time" + elif "--plot-rate" in sys.argv: + plot = "rate" + + if plot == "time": + report.plot_time("compute") + for competitor in competitors: + report.plot_time(competitor) + elif plot == "rate": + report.plot_rate("compute") + for competitor in competitors: + report.plot_rate(competitor) + + if plot: + pylab.legend(loc='upper left') + pylab.show() + else: + report.display() diff --git a/src/boost/libs/compute/perf/perf_accumulate.cpp b/src/boost/libs/compute/perf/perf_accumulate.cpp new file mode 100644 index 00000000..bd4276e6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_accumulate.cpp @@ -0,0 +1,140 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/program_options.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/accumulate.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +namespace po = boost::program_options; +namespace compute = boost::compute; + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +template<class T> +double perf_accumulate(const compute::vector<T>& data, + const size_t trials, + compute::command_queue& queue) +{ + perf_timer t; + for(size_t trial = 0; trial < trials; trial++){ + t.start(); + compute::accumulate(data.begin(), data.end(), T(0), queue); + queue.finish(); + t.stop(); + } + return t.min_time(); +} + +template<class T> +void tune_accumulate(const compute::vector<T>& data, + const size_t trials, + compute::command_queue& queue) +{ + boost::shared_ptr<compute::detail::parameter_cache> + params = compute::detail::parameter_cache::get_global_cache(queue.get_device()); + + const std::string cache_key = + std::string("__boost_reduce_on_gpu_") + compute::type_name<T>(); + + const compute::uint_ tpbs[] = { 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; + const compute::uint_ vpts[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + double min_time = (std::numeric_limits<double>::max)(); + compute::uint_ best_tpb = 0; + compute::uint_ best_vpt = 0; + + for(size_t i = 0; i < sizeof(tpbs) / sizeof(*tpbs); i++){ + params->set(cache_key, "tpb", tpbs[i]); + for(size_t j = 0; j < sizeof(vpts) / sizeof(*vpts); j++){ + params->set(cache_key, "vpt", vpts[j]); + + try { + const double t = perf_accumulate(data, trials, queue); + if(t < min_time){ + best_tpb = tpbs[i]; + best_vpt = vpts[j]; + min_time = t; + } + } + catch(compute::opencl_error&){ + // invalid parameters for this device, skip + } + } + } + + // store optimal parameters + params->set(cache_key, "tpb", best_tpb); + params->set(cache_key, "vpt", best_vpt); +} + +int main(int argc, char *argv[]) +{ + // setup command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("size", po::value<size_t>()->default_value(8192), "input size") + ("trials", po::value<size_t>()->default_value(3), "number of trials to run") + ("tune", "run tuning procedure") + ; + po::positional_options_description positional_options; + positional_options.add("size", 1); + + // parse command line + po::variables_map vm; + po::store( + po::command_line_parser(argc, argv) + .options(options).positional(positional_options).run(), + vm + ); + po::notify(vm); + + const size_t size = vm["size"].as<size_t>(); + const size_t trials = vm["trials"].as<size_t>(); + std::cout << "size: " << size << std::endl; + + // setup context and queue for the default device + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_data(size); + std::generate(host_data.begin(), host_data.end(), rand_int); + + // create vector on the device and copy the data + compute::vector<int> device_data( + host_data.begin(), host_data.end(), queue + ); + + // run tuning proceure (if requested) + if(vm.count("tune")){ + tune_accumulate(device_data, trials, queue); + } + + // run benchmark + double t = perf_accumulate(device_data, trials, queue); + std::cout << "time: " << t / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bernoulli_distribution.cpp b/src/boost/libs/compute/perf/perf_bernoulli_distribution.cpp new file mode 100644 index 00000000..bffbe58f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bernoulli_distribution.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/bernoulli_distribution.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + compute::vector<bool> vector(PERF_N, context); + + compute::default_random_engine rng(queue); + compute::bernoulli_distribution<float> dist(0.5); + + perf_timer t; + t.start(); + dist.generate(vector.begin(), vector.end(), rng, queue); + queue.finish(); + t.stop(); + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_binary_find.cpp b/src/boost/libs/compute/perf/perf_binary_find.cpp new file mode 100644 index 00000000..ee7c4631 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_binary_find.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/detail/binary_find.hpp> +#include <boost/compute/algorithm/partition.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + using boost::compute::_1; + boost::compute::partition( + device_vector.begin(), device_vector.end(), _1 < 20, queue + ); + + // just to be sure everything is finished before measuring execution time + // of binary_find algorithm + queue.finish(); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::detail::binary_find( + device_vector.begin(), device_vector.end(), _1 >= 20, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_accumulate.cpp b/src/boost/libs/compute/perf/perf_bolt_accumulate.cpp new file mode 100644 index 00000000..5a6b9b9c --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_accumulate.cpp @@ -0,0 +1,51 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> +#include <bolt/cl/reduce.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create host vector + std::vector<int> host_vec = generate_random_vector<int>(PERF_N); + + // create device vectors + bolt::cl::device_vector<int> device_vec(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_vec.begin(), host_vec.end(), device_vec.begin()); + + int sum = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + sum = bolt::cl::reduce(device_vec.begin(), device_vec.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "sum: " << sum << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_count.cpp b/src/boost/libs/compute/perf/perf_bolt_count.cpp new file mode 100644 index 00000000..a23c5ac3 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_count.cpp @@ -0,0 +1,57 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/count.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create vector of random numbers on the host + std::vector<int> h_vec(PERF_N); + std::generate(h_vec.begin(), h_vec.end(), rand_int); + + // create device vector + bolt::cl::device_vector<int> d_vec(PERF_N); + + // transfer data to the device + bolt::cl::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); + + size_t count = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + count = bolt::cl::count(ctrl, d_vec.begin(), d_vec.end(), 4); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "count: " << count << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_exclusive_scan.cpp b/src/boost/libs/compute/perf/perf_bolt_exclusive_scan.cpp new file mode 100644 index 00000000..a60e4655 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_exclusive_scan.cpp @@ -0,0 +1,52 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/scan.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create vector of random numbers on the host + std::vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // create device vector + bolt::cl::device_vector<int> d_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + // transfer data to the device + bolt::cl::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); + + t.start(); + bolt::cl::exclusive_scan(d_vec.begin(), d_vec.end(), d_vec.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + bolt::cl::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_fill.cpp b/src/boost/libs/compute/perf/perf_bolt_fill.cpp new file mode 100644 index 00000000..50b6e85e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_fill.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/fill.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create device vector (filled with zeros) + bolt::cl::device_vector<int> d_vec(PERF_N, 0); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + bolt::cl::fill(d_vec.begin(), d_vec.end(), int(trial)); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_inner_product.cpp b/src/boost/libs/compute/perf/perf_bolt_inner_product.cpp new file mode 100644 index 00000000..4c9652e6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_inner_product.cpp @@ -0,0 +1,56 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/inner_product.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create host vectors + std::vector<int> host_x = generate_random_vector<int>(PERF_N); + std::vector<int> host_y = generate_random_vector<int>(PERF_N); + + // create device vectors + bolt::cl::device_vector<int> device_x(PERF_N); + bolt::cl::device_vector<int> device_y(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_x.begin(), host_x.end(), device_x.begin()); + bolt::cl::copy(host_y.begin(), host_y.end(), device_y.begin()); + + int product = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + product = bolt::cl::inner_product( + device_x.begin(), device_x.end(), device_y.begin(), 0 + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "product: " << product << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_max_element.cpp b/src/boost/libs/compute/perf/perf_bolt_max_element.cpp new file mode 100644 index 00000000..238b1ba2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_max_element.cpp @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> +#include <bolt/cl/max_element.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>(rand() % 10000000); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create host vector + std::vector<int> host_vec = generate_random_vector<int>(PERF_N); + + // create device vectors + bolt::cl::device_vector<int> device_vec(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_vec.begin(), host_vec.end(), device_vec.begin()); + + bolt::cl::device_vector<int>::iterator max_iter = device_vec.begin(); + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + max_iter = bolt::cl::max_element(device_vec.begin(), device_vec.end()); + t.stop(); + } + + int device_max = *max_iter; + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "max: " << device_max << std::endl; + + // verify max is correct + int host_max = *std::max_element(host_vec.begin(), host_vec.end()); + if(device_max != host_max){ + std::cout << "ERROR: " + << "device_max (" << device_max << ") " + << "!= " + << "host_max (" << host_max << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_merge.cpp b/src/boost/libs/compute/perf/perf_bolt_merge.cpp new file mode 100644 index 00000000..c5ee12ac --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_merge.cpp @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/merge.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vec1 = generate_random_vector<int>(std::floor(PERF_N / 2.0)); + std::vector<int> host_vec2 = generate_random_vector<int>(std::ceil(PERF_N / 2.0)); + // sort them + std::sort(host_vec1.begin(), host_vec1.end()); + std::sort(host_vec2.begin(), host_vec2.end()); + + // create device vectors + bolt::cl::device_vector<int> device_vec1(PERF_N); + bolt::cl::device_vector<int> device_vec2(PERF_N); + bolt::cl::device_vector<int> device_vec3(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_vec1.begin(), host_vec1.end(), device_vec1.begin()); + bolt::cl::copy(host_vec2.begin(), host_vec2.end(), device_vec2.begin()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + bolt::cl::merge( + device_vec1.begin(), device_vec1.end(), + device_vec2.begin(), device_vec2.end(), + device_vec3.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_partial_sum.cpp b/src/boost/libs/compute/perf/perf_bolt_partial_sum.cpp new file mode 100644 index 00000000..2f9c830e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_partial_sum.cpp @@ -0,0 +1,53 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/scan.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create vector of random numbers on the host + std::vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // create device vector + bolt::cl::device_vector<int> d_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + // transfer data to the device + bolt::cl::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); + + t.start(); + bolt::cl::inclusive_scan(d_vec.begin(), d_vec.end(), d_vec.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + bolt::cl::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} + diff --git a/src/boost/libs/compute/perf/perf_bolt_reduce_by_key.cpp b/src/boost/libs/compute/perf/perf_bolt_reduce_by_key.cpp new file mode 100644 index 00000000..e7668498 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_reduce_by_key.cpp @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> +#include <bolt/cl/reduce_by_key.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +struct unique_key { + int current; + int avgValuesNoPerKey; + + unique_key() + { + current = 0; + avgValuesNoPerKey = 512; + } + + int operator()() + { + double p = double(1.0) / static_cast<double>(avgValuesNoPerKey); + if((rand() / double(RAND_MAX)) <= p) + return ++current; + return current; + } +} UniqueKey; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create vector of keys and random values + std::vector<int> host_keys(PERF_N); + std::vector<int> host_values(PERF_N); + std::generate(host_keys.begin(), host_keys.end(), UniqueKey); + std::generate(host_values.begin(), host_values.end(), rand_int); + + // create device vectors for data + bolt::cl::device_vector<int> device_keys(PERF_N); + bolt::cl::device_vector<int> device_values(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_keys.begin(), host_keys.end(), device_keys.begin()); + bolt::cl::copy(host_values.begin(), host_values.end(), device_values.begin()); + + // create device vectors for the results + bolt::cl::device_vector<int> device_keys_results(PERF_N); + bolt::cl::device_vector<int> device_values_results(PERF_N); + + typedef bolt::cl::device_vector<int>::iterator iterType; + bolt::cl::pair<iterType, iterType> result = { + device_keys_results.begin(), + device_values_results.begin() + }; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + result = bolt::cl::reduce_by_key(device_keys.begin(), + device_keys.end(), + device_values.begin(), + device_keys_results.begin(), + device_values_results.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + size_t result_size = bolt::cl::distance(device_keys_results.begin(), result.first); + if(result_size != static_cast<size_t>(host_keys[PERF_N-1] + 1)){ + std::cout << "ERROR: " + << "wrong number of keys" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_saxpy.cpp b/src/boost/libs/compute/perf/perf_bolt_saxpy.cpp new file mode 100644 index 00000000..201f683a --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_saxpy.cpp @@ -0,0 +1,76 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> +#include <bolt/cl/transform.h> + +#include "perf.hpp" + +BOLT_FUNCTOR(saxpy_functor, + struct saxpy_functor + { + float _a; + saxpy_functor(float a) : _a(a) {}; + + float operator() (const float &x, const float &y) const + { + return _a * x + y; + }; + }; +) + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + bolt::cl::control ctrl = bolt::cl::control::getDefault(); + ::cl::Device device = ctrl.getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create host vectors + std::vector<float> host_x(PERF_N); + std::vector<float> host_y(PERF_N); + std::generate(host_x.begin(), host_x.end(), rand); + std::generate(host_y.begin(), host_y.end(), rand); + + // create device vectors + bolt::cl::device_vector<float> device_x(PERF_N); + bolt::cl::device_vector<float> device_y(PERF_N); + + // transfer data to the device + bolt::cl::copy(host_x.begin(), host_x.end(), device_x.begin()); + bolt::cl::copy(host_y.begin(), host_y.end(), device_y.begin()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + bolt::cl::transform( + device_x.begin(), device_x.end(), + device_y.begin(), + device_y.begin(), + saxpy_functor(2.5f) + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + bolt::cl::copy(device_x.begin(), device_x.end(), host_x.begin()); + bolt::cl::copy(device_y.begin(), device_y.end(), host_y.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_bolt_sort.cpp b/src/boost/libs/compute/perf/perf_bolt_sort.cpp new file mode 100644 index 00000000..2508ec06 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_bolt_sort.cpp @@ -0,0 +1,50 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <cstdlib> +#include <vector> + +#include <bolt/cl/sort.h> +#include <bolt/cl/copy.h> +#include <bolt/cl/device_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + ::cl::Device device = bolt::cl::control::getDefault().getDevice(); + std::cout << "device: " << device.getInfo<CL_DEVICE_NAME>() << std::endl; + + // create host vector + std::vector<int> h_vec = generate_random_vector<int>(PERF_N); + // create device vector + bolt::cl::device_vector<int> d_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + // transfer data to the device + bolt::cl::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); + + t.start(); + bolt::cl::sort(d_vec.begin(), d_vec.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + bolt::cl::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_cart_to_polar.cpp b/src/boost/libs/compute/perf/perf_cart_to_polar.cpp new file mode 100644 index 00000000..e0d333eb --- /dev/null +++ b/src/boost/libs/compute/perf/perf_cart_to_polar.cpp @@ -0,0 +1,158 @@ +//---------------------------------------------------------------------------// +// 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 _USE_MATH_DEFINES +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/copy_n.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; + +using compute::float2_; + +float rand_float() +{ + return (float(rand()) / float(RAND_MAX)) * 1000.f; +} + +void serial_cartesian_to_polar(const float *input, size_t n, float *output) +{ + for(size_t i = 0; i < n; i++){ + float x = input[i*2+0]; + float y = input[i*2+1]; + + float magnitude = std::sqrt(x*x + y*y); + float angle = std::atan2(y, x) * 180.f / M_PI; + + output[i*2+0] = magnitude; + output[i*2+1] = angle; + } +} + +void serial_polar_to_cartesian(const float *input, size_t n, float *output) +{ + for(size_t i = 0; i < n; i++){ + float magnitude = input[i*2+0]; + float angle = input[i*2+1]; + + float x = magnitude * cos(angle); + float y = magnitude * sin(angle); + + output[i*2+0] = x; + output[i*2+1] = y; + } +} + +// converts from cartesian coordinates (x, y) to polar coordinates (magnitude, angle) +BOOST_COMPUTE_FUNCTION(float2_, cartesian_to_polar, (float2_ p), +{ + float x = p.x; + float y = p.y; + + float magnitude = sqrt(x*x + y*y); + float angle = atan2(y, x) * 180.f / M_PI; + + return (float2)(magnitude, angle); +}); + +// converts from polar coordinates (magnitude, angle) to cartesian coordinates (x, y) +BOOST_COMPUTE_FUNCTION(float2_, polar_to_cartesian, (float2_ p), +{ + float magnitude = p.x; + float angle = p.y; + + float x = magnitude * cos(angle); + float y = magnitude * sin(angle); + + return (float2)(x, y) +}); + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<float> host_vector(PERF_N*2); + std::generate(host_vector.begin(), host_vector.end(), rand_float); + + // create vector on the device and copy the data + compute::vector<float2_> device_vector(PERF_N, context); + compute::copy_n( + reinterpret_cast<float2_ *>(&host_vector[0]), + PERF_N, + device_vector.begin(), + queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + compute::transform( + device_vector.begin(), + device_vector.end(), + device_vector.begin(), + cartesian_to_polar, + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // perform saxpy on host + t.clear(); + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + serial_cartesian_to_polar(&host_vector[0], PERF_N, &host_vector[0]); + t.stop(); + } + std::cout << "host time: " << t.min_time() / 1e6 << " ms" << std::endl; + + std::vector<float> device_data(PERF_N*2); + compute::copy( + device_vector.begin(), + device_vector.end(), + reinterpret_cast<float2_ *>(&device_data[0]), + queue + ); + + for(size_t i = 0; i < PERF_N; i++){ + float host_value = host_vector[i]; + float device_value = device_data[i]; + + if(std::abs(device_value - host_value) > 1e-3){ + std::cout << "ERROR: " + << "value at " << i << " " + << "device_value (" << device_value << ") " + << "!= " + << "host_value (" << host_value << ")" + << std::endl; + return -1; + } + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_comparison_sort.cpp b/src/boost/libs/compute/perf/perf_comparison_sort.cpp new file mode 100644 index 00000000..fa63303f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_comparison_sort.cpp @@ -0,0 +1,86 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/program_options.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 "perf.hpp" + +namespace po = boost::program_options; +namespace compute = boost::compute; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + using boost::compute::int_; + + // create vector of random numbers on the host + std::vector<int_> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand); + + // create vector on the device and copy the data + boost::compute::vector<int_> device_vector(PERF_N, context); + + // less function for float + BOOST_COMPUTE_FUNCTION(bool, comp, (int_ a, int_ b), + { + return a < b; + }); + + // sort vector + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + queue.finish(); + + t.start(); + boost::compute::sort( + device_vector.begin(), + device_vector.end(), + comp, + queue + ); + queue.finish(); + t.stop(); + }; + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify vector is sorted + if(!boost::compute::is_sorted(device_vector.begin(), + device_vector.end(), + comp, + queue)){ + std::cout << "ERROR: is_sorted() returned false" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_copy_if.cpp b/src/boost/libs/compute/perf/perf_copy_if.cpp new file mode 100644 index 00000000..b2c162f6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_copy_if.cpp @@ -0,0 +1,122 @@ +//---------------------------------------------------------------------------// +// 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/core.hpp> +#include <boost/compute/closure.hpp> +#include <boost/compute/algorithm/copy_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/random/uniform_real_distribution.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; + +void test_copy_if_odd(compute::command_queue &queue) +{ + // create input and output vectors on the device + const compute::context &context = queue.get_context(); + compute::vector<int> input(PERF_N, context); + compute::vector<int> output(PERF_N, 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_COMPUTE_FUNCTION(bool, is_odd, (int x), + { + return x & 1; + }); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + compute::vector<int>::iterator i = compute::copy_if( + input.begin(), input.end(), output.begin(), is_odd, queue + ); + queue.finish(); + t.stop(); + + float ratio = float(std::distance(output.begin(), i)) / PERF_N; + if(PERF_N > 1000 && (ratio < 0.45f || ratio > 0.55f)){ + std::cerr << "error: ratio is " << ratio << std::endl; + std::cerr << "error: ratio should be around 45-55%" << std::endl; + } + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; +} + +void test_copy_if_in_sphere(compute::command_queue &queue) +{ + using boost::compute::float4_; + + // create input and output vectors on the device + const compute::context &context = queue.get_context(); + compute::vector<float4_> input_points(PERF_N, context); + compute::vector<float4_> output_points(PERF_N, context); + + // generate random numbers in a cube + float radius = 5.0f; + compute::default_random_engine rng(queue); + compute::uniform_real_distribution<float> d(-radius, +radius); + d.generate( + compute::make_buffer_iterator<float>(input_points.get_buffer(), 0), + compute::make_buffer_iterator<float>(input_points.get_buffer(), PERF_N * 4), + rng, + queue + ); + + // predicate which returns true if the point lies within the sphere + BOOST_COMPUTE_CLOSURE(bool, is_in_sphere, (float4_ point), (radius), + { + // ignore fourth component + point.w = 0; + + return length(point) < radius; + }); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + compute::vector<float4_>::iterator i = compute::copy_if( + input_points.begin(), + input_points.end(), + output_points.begin(), + is_in_sphere, + queue + ); + queue.finish(); + t.stop(); + + float ratio = float(std::distance(output_points.begin(), i)) / PERF_N; + if(PERF_N > 1000 && (ratio < 0.5f || ratio > 0.6f)){ + std::cerr << "error: ratio is " << ratio << std::endl; + std::cerr << "error: ratio should be around 50-60%" << std::endl; + } + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + test_copy_if_odd(queue); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_copy_to_device.cpp b/src/boost/libs/compute/perf/perf_copy_to_device.cpp new file mode 100644 index 00000000..0cda3d0f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_copy_to_device.cpp @@ -0,0 +1,55 @@ +//---------------------------------------------------------------------------// +// 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 <vector> +#include <cstdlib> +#include <iostream> + +#include <boost/compute.hpp> + +int main(int argc, char *argv[]) +{ + size_t size = 1000; + if(argc >= 2){ + size = boost::lexical_cast<size_t>(argv[1]); + } + + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + + boost::compute::command_queue::properties + properties = boost::compute::command_queue::enable_profiling; + boost::compute::command_queue queue(context, device, properties); + + std::vector<int> host_vector(size); + std::generate(host_vector.begin(), host_vector.end(), rand); + + boost::compute::vector<int> device_vector(host_vector.size(), context); + + boost::compute::future<void> future = + boost::compute::copy_async(host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue); + + // wait for copy to finish + future.wait(); + + // get elapsed time in nanoseconds + size_t elapsed = + future.get_event().duration<boost::chrono::nanoseconds>().count(); + + std::cout << "time: " << elapsed / 1e6 << " ms" << std::endl; + + float rate = (float(size * sizeof(int)) / elapsed) * 1000.f; + std::cout << "rate: " << rate << " MB/s" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_count.cpp b/src/boost/libs/compute/perf/perf_count.cpp new file mode 100644 index 00000000..a47eb615 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_count.cpp @@ -0,0 +1,77 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/count.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + size_t count = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + count = boost::compute::count( + device_vector.begin(), device_vector.end(), 4, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "count: " << count << std::endl; + + // verify count is correct + size_t host_count = std::count(host_vector.begin(), + host_vector.end(), + 4); + if(count != host_count){ + std::cout << "ERROR: " + << "device_count (" << count << ") " + << "!= " + << "host_count (" << host_count << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_discrete_distribution.cpp b/src/boost/libs/compute/perf/perf_discrete_distribution.cpp new file mode 100644 index 00000000..f6679eb1 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_discrete_distribution.cpp @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/discrete_distribution.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + compute::vector<compute::uint_> vector(PERF_N, context); + + int weights[] = {1, 1}; + + compute::default_random_engine rng(queue); + compute::discrete_distribution<compute::uint_> dist(weights, weights+2); + + perf_timer t; + t.start(); + dist.generate(vector.begin(), vector.end(), rng, queue); + queue.finish(); + t.stop(); + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_erase_remove.cpp b/src/boost/libs/compute/perf/perf_erase_remove.cpp new file mode 100644 index 00000000..f567247f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_erase_remove.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/remove.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 10.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::vector<int> device_vector( + host_vector.begin(), host_vector.end(), queue + ); + + t.start(); + device_vector.erase( + boost::compute::remove( + device_vector.begin(), device_vector.end(), 4, queue + ), + device_vector.end(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_exclusive_scan.cpp b/src/boost/libs/compute/perf/perf_exclusive_scan.cpp new file mode 100644 index 00000000..e6c65135 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_exclusive_scan.cpp @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Benoit +// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/exclusive_scan.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::vector<int> device_res(PERF_N,context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + // sum vector + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + t.start(); + boost::compute::exclusive_scan( + device_vector.begin(), + device_vector.end(), + device_res.begin(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify sum is correct + std::partial_sum( + host_vector.begin(), + host_vector.end(), + host_vector.begin() + ); + + int device_sum = device_res.back(); + // when scan is exclusive values are shifted by one on the left + // compared to a inclusive scan + int host_sum = host_vector[host_vector.size()-2]; + + if(device_sum != host_sum){ + std::cout << "ERROR: " + << "device_sum (" << device_sum << ") " + << "!= " + << "host_sum (" << host_sum << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_fill.cpp b/src/boost/libs/compute/perf/perf_fill.cpp new file mode 100644 index 00000000..9f35b6b0 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_fill.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector on the device (filled with zeros) + boost::compute::vector<int> vec(PERF_N, 0, queue); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::fill(vec.begin(), vec.end(), int(trial), queue); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_find.cpp b/src/boost/libs/compute/perf/perf_find.cpp new file mode 100644 index 00000000..3cfb75ad --- /dev/null +++ b/src/boost/libs/compute/perf/perf_find.cpp @@ -0,0 +1,88 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/find.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +// Max integer that can be generated by rand_int() function. +int rand_int_max = 25; + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * rand_int_max); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + // trying to find element that isn't in vector (worst-case scenario) + int wanted = rand_int_max + 1; + + // device iterator + boost::compute::vector<int>::iterator device_result_it; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + device_result_it = boost::compute::find(device_vector.begin(), + device_vector.end(), + wanted, + queue); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify if found index is correct by comparing it with std::find() result + size_t host_result_index = std::distance(host_vector.begin(), + std::find(host_vector.begin(), + host_vector.end(), + wanted)); + size_t device_result_index = device_result_it.get_index(); + + if(device_result_index != host_result_index){ + std::cout << "ERROR: " + << "device_result_index (" << device_result_index << ") " + << "!= " + << "host_result_index (" << host_result_index << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_find_end.cpp b/src/boost/libs/compute/perf/perf_find_end.cpp new file mode 100644 index 00000000..e20a7e8d --- /dev/null +++ b/src/boost/libs/compute/perf/perf_find_end.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/find_end.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int pattern[] = {2, 6, 6, 7, 8, 4}; + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + boost::compute::vector<int> pattern_vector(pattern, pattern + 6, queue); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::find_end( + device_vector.begin(), device_vector.end(), + pattern_vector.begin(), pattern_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_host_sort.cpp b/src/boost/libs/compute/perf/perf_host_sort.cpp new file mode 100644 index 00000000..d34b1c52 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_host_sort.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/timer/timer.hpp> + +#include <boost/compute/system.hpp> +#include <boost/compute/command_queue.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> random_vector(PERF_N); + std::generate(random_vector.begin(), random_vector.end(), rand); + + // create input vector for gpu + std::vector<int> gpu_vector = random_vector; + + // sort vector on gpu + boost::timer::cpu_timer t; + boost::compute::sort( + gpu_vector.begin(), gpu_vector.end(), queue + ); + queue.finish(); + std::cout << "time: " << t.elapsed().wall / 1e6 << " ms" << std::endl; + + // create input vector for host + std::vector<int> host_vector = random_vector; + + // sort vector on host + t.start(); + std::sort(host_vector.begin(), host_vector.end()); + std::cout << "host time: " << t.elapsed().wall / 1e6 << " ms" << std::endl; + + // ensure that both sorted vectors are equal + if(!std::equal(gpu_vector.begin(), gpu_vector.end(), host_vector.begin())){ + std::cerr << "ERROR: sorted vectors not the same" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_includes.cpp b/src/boost/libs/compute/perf/perf_includes.cpp new file mode 100644 index 00000000..0418a5d7 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_includes.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/includes.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vectors of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::sort(host_vector.begin(), host_vector.end()); + + // create vectors on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + boost::compute::vector<int> device_vector2(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector2.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::includes( + device_vector.begin(), device_vector.end(), + device_vector2.begin(), device_vector2.end(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_inner_product.cpp b/src/boost/libs/compute/perf/perf_inner_product.cpp new file mode 100644 index 00000000..112a4bc6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_inner_product.cpp @@ -0,0 +1,74 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/inner_product.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + std::vector<int> h1(PERF_N); + std::vector<int> h2(PERF_N); + std::generate(h1.begin(), h1.end(), rand_int); + std::generate(h2.begin(), h2.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> d1(PERF_N, context); + boost::compute::vector<int> d2(PERF_N, context); + boost::compute::copy(h1.begin(), h1.end(), d1.begin(), queue); + boost::compute::copy(h2.begin(), h2.end(), d2.begin(), queue); + + int product = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + product = boost::compute::inner_product( + d1.begin(), d1.end(), d2.begin(), int(0), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify product is correct + int host_product = std::inner_product( + h1.begin(), h1.end(), h2.begin(), int(0) + ); + if(product != host_product){ + std::cout << "ERROR: " + << "device_product (" << product << ") " + << "!= " + << "host_product (" << host_product << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_is_permutation.cpp b/src/boost/libs/compute/perf/perf_is_permutation.cpp new file mode 100644 index 00000000..39c72bf1 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_is_permutation.cpp @@ -0,0 +1,66 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + boost::compute::vector<int> device_vector2(PERF_N, context); + boost::compute::copy( + host_vector.rbegin(), host_vector.rend(), device_vector2.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::is_permutation( + device_vector.begin(), device_vector.end(), + device_vector2.begin(), device_vector2.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_is_sorted.cpp b/src/boost/libs/compute/perf/perf_is_sorted.cpp new file mode 100644 index 00000000..f16a3172 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_is_sorted.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // sort and then reverse the random vector + boost::compute::sort(device_vector.begin(), device_vector.end(), queue); + boost::compute::reverse(device_vector.begin(), device_vector.end(), queue); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + bool sorted = boost::compute::is_sorted( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + if(sorted){ + std::cerr << "ERROR: is_sorted() returned true" << std::endl; + } + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_max_element.cpp b/src/boost/libs/compute/perf/perf_max_element.cpp new file mode 100644 index 00000000..0e47c67e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_max_element.cpp @@ -0,0 +1,93 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Rastko Anicic <anicic.rastko@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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/max_element.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>(rand() % 10000000); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + boost::compute::vector<int>::iterator device_max_iter + = device_vector.begin(); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + device_max_iter = boost::compute::max_element( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + + int device_max = device_max_iter.read(queue); + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "max: " << device_max << std::endl; + + // verify max is correct + std::vector<int>::iterator host_max_iter + = std::max_element(host_vector.begin(), host_vector.end()); + + int host_max = *host_max_iter; + if(device_max != host_max){ + std::cout << "ERROR: " + << "device_max (" << device_max << ") " + << "!= " + << "host_max (" << host_max << ")" + << std::endl; + return -1; + } + + size_t host_max_idx = std::distance(host_vector.begin(), host_max_iter); + size_t device_max_idx = std::distance(device_vector.begin(), device_max_iter); + if(device_max_idx != host_max_idx){ + std::cout << "ERROR: " + << "device_max index (" << device_max_idx << ") " + << "!= " + << "host_max index (" << host_max_idx << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_merge.cpp b/src/boost/libs/compute/perf/perf_merge.cpp new file mode 100644 index 00000000..58ea836f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_merge.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. +//---------------------------------------------------------------------------// + +#include <cmath> +#include <vector> +#include <algorithm> +#include <iostream> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/merge.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + std::vector<int> v1 = generate_random_vector<int>(std::floor(PERF_N / 2.0)); + std::vector<int> v2 = generate_random_vector<int>(std::ceil(PERF_N / 2.0)); + std::vector<int> v3(PERF_N); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + boost::compute::vector<int> gpu_v1(v1.begin(), v1.end(), queue); + boost::compute::vector<int> gpu_v2(v2.begin(), v2.end(), queue); + boost::compute::vector<int> gpu_v3(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::merge(gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + std::vector<int> check_v3(PERF_N); + boost::compute::copy(gpu_v3.begin(), gpu_v3.end(), check_v3.begin(), queue); + queue.finish(); + + std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin()); + bool ok = std::equal(check_v3.begin(), check_v3.end(), v3.begin()); + if(!ok){ + std::cerr << "ERROR: merged ranges different" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_next_permutation.cpp b/src/boost/libs/compute/perf/perf_next_permutation.cpp new file mode 100644 index 00000000..62f0bbb0 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_next_permutation.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/next_permutation.hpp> +#include <boost/compute/algorithm/prev_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::sort(host_vector.begin(), host_vector.end(), std::greater<int>()); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::next_permutation( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + boost::compute::prev_permutation( + device_vector.begin(), device_vector.end(), queue + ); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_nth_element.cpp b/src/boost/libs/compute/perf/perf_nth_element.cpp new file mode 100644 index 00000000..07627cb4 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_nth_element.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/nth_element.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::nth_element( + device_vector.begin(), device_vector.begin()+(PERF_N/2), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_partial_sum.cpp b/src/boost/libs/compute/perf/perf_partial_sum.cpp new file mode 100644 index 00000000..1c02b4c4 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_partial_sum.cpp @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/partial_sum.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + using boost::compute::int_; + + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int_> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int_> device_vector(PERF_N, context); + boost::compute::vector<int_> device_res(PERF_N,context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + // sum vector + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + t.start(); + boost::compute::partial_sum( + device_vector.begin(), + device_vector.end(), + device_res.begin(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify sum is correct + std::partial_sum( + host_vector.begin(), + host_vector.end(), + host_vector.begin() + ); + + int device_sum = device_res.back(); + int host_sum = host_vector.back(); + + if(device_sum != host_sum){ + std::cout << "ERROR: " + << "device_sum (" << device_sum << ") " + << "!= " + << "host_sum (" << host_sum << ")" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_partition.cpp b/src/boost/libs/compute/perf/perf_partition.cpp new file mode 100644 index 00000000..b765d736 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_partition.cpp @@ -0,0 +1,66 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/partition.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + using boost::compute::_1; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + t.start(); + boost::compute::partition( + device_vector.begin(), device_vector.end(), _1 < 10, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_partition_point.cpp b/src/boost/libs/compute/perf/perf_partition_point.cpp new file mode 100644 index 00000000..91261aa1 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_partition_point.cpp @@ -0,0 +1,68 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/lambda.hpp> +#include <boost/compute/algorithm/partition.hpp> +#include <boost/compute/algorithm/partition_point.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + using boost::compute::_1; + boost::compute::partition( + device_vector.begin(), device_vector.end(), _1 < 20, queue + ); + + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::partition_point( + device_vector.begin(), device_vector.end(), _1 < 20, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_prev_permutation.cpp b/src/boost/libs/compute/perf/perf_prev_permutation.cpp new file mode 100644 index 00000000..bb7d76d2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_prev_permutation.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/next_permutation.hpp> +#include <boost/compute/algorithm/prev_permutation.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::sort(host_vector.begin(), host_vector.end()); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::prev_permutation( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + boost::compute::next_permutation( + device_vector.begin(), device_vector.end(), queue + ); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_random_number_engine.cpp b/src/boost/libs/compute/perf/perf_random_number_engine.cpp new file mode 100644 index 00000000..db25d437 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_random_number_engine.cpp @@ -0,0 +1,101 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <vector> + +#include <boost/program_options.hpp> + +#include <boost/compute/container/vector.hpp> +#include <boost/compute/core.hpp> +#include <boost/compute/random.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; +namespace po = boost::program_options; + +template<class Engine> +void perf_random_number_engine(const size_t size, + const size_t trials, + compute::command_queue& queue) +{ + typedef typename Engine::result_type T; + + // create random number engine + Engine engine(queue); + + // create vector on the device + std::cout << "size = " << size << std::endl; + compute::vector<T> vector(size, queue.get_context()); + + // generate random numbers + perf_timer t; + for(size_t i = 0; i < trials; i++){ + t.start(); + engine.generate(vector.begin(), vector.end(), queue); + queue.finish(); + t.stop(); + } + + // print result + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "rate: " << perf_rate<T>(size, t.min_time()) << " MB/s" << std::endl; +} + +int main(int argc, char *argv[]) +{ + // setup and parse command line options + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("size", po::value<size_t>()->default_value(8192), "number of values") + ("trials", po::value<size_t>()->default_value(3), "number of trials") + ("engine", po::value<std::string>()->default_value("default_random_engine"), "random number engine") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, options), vm); + po::notify(vm); + + if(vm.count("help")) { + std::cout << options << std::endl; + return 0; + } + + // setup context and queue for the default device + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + // get command line options + const size_t size = vm["size"].as<size_t>(); + const size_t trials = vm["trials"].as<size_t>(); + const std::string& engine = vm["engine"].as<std::string>(); + + // run benchmark + if(engine == "default_random_engine"){ + perf_random_number_engine<compute::default_random_engine>(size, trials, queue); + } + else if(engine == "mersenne_twister_engine"){ + perf_random_number_engine<compute::mt19937>(size, trials, queue); + } + else if(engine == "linear_congruential_engine"){ + perf_random_number_engine<compute::linear_congruential_engine<> >(size, trials, queue); + } + else if(engine == "threefry_engine"){ + perf_random_number_engine<compute::threefry_engine<> >(size, trials, queue); + } + else { + std::cerr << "error: unknown random number engine '" << engine << "'" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_reduce_by_key.cpp b/src/boost/libs/compute/perf/perf_reduce_by_key.cpp new file mode 100644 index 00000000..c88d450e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_reduce_by_key.cpp @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/fill.hpp> +#include <boost/compute/algorithm/reduce_by_key.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +struct unique_key { + int current; + int avgValuesNoPerKey; + + unique_key() + { + current = 0; + avgValuesNoPerKey = 512; + } + + int operator()() + { + double p = double(1.0) / static_cast<double>(avgValuesNoPerKey); + if((rand() / double(RAND_MAX)) <= p) + return ++current; + return current; + } +} UniqueKey; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of keys and random values + std::vector<int> host_keys(PERF_N); + std::vector<int> host_values(PERF_N); + std::generate(host_keys.begin(), host_keys.end(), UniqueKey); + std::generate(host_values.begin(), host_values.end(), rand_int); + + // create vectors for keys and values on the device and copy the data + boost::compute::vector<int> device_keys(PERF_N, context); + boost::compute::vector<int> device_values(PERF_N,context); + boost::compute::copy( + host_keys.begin(), + host_keys.end(), + device_keys.begin(), + queue + ); + boost::compute::copy( + host_values.begin(), + host_values.end(), + device_values.begin(), + queue + ); + + // vectors for the results + boost::compute::vector<int> device_keys_results(PERF_N, context); + boost::compute::vector<int> device_values_results(PERF_N,context); + + typedef boost::compute::vector<int>::iterator iterType; + std::pair<iterType, iterType> result( + device_keys_results.begin(), + device_values_results.begin() + ); + + // reduce by key + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + result = boost::compute::reduce_by_key(device_keys.begin(), + device_keys.end(), + device_values.begin(), + device_keys_results.begin(), + device_values_results.begin(), + queue); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + size_t result_size = std::distance(device_keys_results.begin(), result.first); + if(result_size != static_cast<size_t>(host_keys[PERF_N-1] + 1)){ + std::cout << "ERROR: " + << "wrong number of keys" << result_size << "\n" << (host_keys[PERF_N-1] + 1) + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_reverse.cpp b/src/boost/libs/compute/perf/perf_reverse.cpp new file mode 100644 index 00000000..64369a78 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_reverse.cpp @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/reverse.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::reverse( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_reverse_copy.cpp b/src/boost/libs/compute/perf/perf_reverse_copy.cpp new file mode 100644 index 00000000..5ce01c9b --- /dev/null +++ b/src/boost/libs/compute/perf/perf_reverse_copy.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/reverse_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + // create vector on the device for reversed data + boost::compute::vector<int> device_reversed_vector(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::reverse_copy( + device_vector.begin(), device_vector.end(), + device_reversed_vector.begin(), + queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_rotate.cpp b/src/boost/libs/compute/perf/perf_rotate.cpp new file mode 100644 index 00000000..49f85d57 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_rotate.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/rotate.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::rotate( + device_vector.begin(), device_vector.begin()+(PERF_N/2), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_rotate_copy.cpp b/src/boost/libs/compute/perf/perf_rotate_copy.cpp new file mode 100644 index 00000000..97111ef5 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_rotate_copy.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/rotate_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + boost::compute::vector<int> device_vector2(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::rotate_copy( + device_vector.begin(), device_vector.begin()+(PERF_N/2), device_vector.end(), device_vector2.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_saxpy.cpp b/src/boost/libs/compute/perf/perf_saxpy.cpp new file mode 100644 index 00000000..99ffc55d --- /dev/null +++ b/src/boost/libs/compute/perf/perf_saxpy.cpp @@ -0,0 +1,162 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/program_options.hpp> + +#include <boost/compute/lambda.hpp> +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/copy.hpp> +#include <boost/compute/algorithm/transform.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +namespace po = boost::program_options; +namespace compute = boost::compute; + +float rand_float() +{ + return (float(rand()) / float(RAND_MAX)) * 1000.f; +} + +template<class T> +double perf_saxpy(const compute::vector<T>& x, + const compute::vector<T>& y, + const T alpha, + const size_t trials, + compute::command_queue& queue) +{ + // create vector on the device to store the result + compute::vector<T> result(x.size(), queue.get_context()); + + perf_timer t; + for(size_t trial = 0; trial < trials; trial++){ + compute::fill(result.begin(), result.end(), T(0), queue); + queue.finish(); + + t.start(); + + using compute::lambda::_1; + using compute::lambda::_2; + + compute::transform( + x.begin(), x.end(), y.begin(), result.begin(), alpha * _1 + _2, queue + ); + + queue.finish(); + t.stop(); + } + + return t.min_time(); +} + +template<class T> +void tune_saxpy(const compute::vector<T>& x, + const compute::vector<T>& y, + const T alpha, + const size_t trials, + compute::command_queue& queue) +{ + boost::shared_ptr<compute::detail::parameter_cache> + params = compute::detail::parameter_cache::get_global_cache(queue.get_device()); + + const std::string cache_key = + std::string("__boost_copy_kernel_") + boost::lexical_cast<std::string>(sizeof(T)); + + const compute::uint_ tpbs[] = { 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; + const compute::uint_ vpts[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + double min_time = (std::numeric_limits<double>::max)(); + compute::uint_ best_tpb = 0; + compute::uint_ best_vpt = 0; + + for(size_t i = 0; i < sizeof(tpbs) / sizeof(*tpbs); i++){ + params->set(cache_key, "tpb", tpbs[i]); + for(size_t j = 0; j < sizeof(vpts) / sizeof(*vpts); j++){ + params->set(cache_key, "vpt", vpts[j]); + + try { + const double t = perf_saxpy(x, y, alpha, trials, queue); + if(t < min_time){ + best_tpb = tpbs[i]; + best_vpt = vpts[j]; + min_time = t; + } + } + catch(compute::opencl_error&){ + // invalid parameters for this device, skip + } + } + } + + // store optimal parameters + params->set(cache_key, "tpb", best_tpb); + params->set(cache_key, "vpt", best_vpt); +} + +int main(int argc, char *argv[]) +{ + // setup command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("size", po::value<size_t>()->default_value(8192), "input size") + ("trials", po::value<size_t>()->default_value(3), "number of trials to run") + ("tune", "run tuning procedure") + ("alpha", po::value<double>()->default_value(2.5), "saxpy alpha value") + ; + po::positional_options_description positional_options; + positional_options.add("size", 1); + + // parse command line + po::variables_map vm; + po::store( + po::command_line_parser(argc, argv) + .options(options).positional(positional_options).run(), + vm + ); + po::notify(vm); + + const size_t size = vm["size"].as<size_t>(); + const size_t trials = vm["trials"].as<size_t>(); + const float alpha = vm["alpha"].as<double>(); + std::cout << "size: " << size << std::endl; + + // setup context and queue for the default device + compute::device device = boost::compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<float> host_x(size); + std::vector<float> host_y(size); + std::generate(host_x.begin(), host_x.end(), rand_float); + std::generate(host_y.begin(), host_y.end(), rand_float); + + // create vector on the device and copy the data + compute::vector<float> x(host_x.begin(), host_x.end(), queue); + compute::vector<float> y(host_y.begin(), host_y.end(), queue); + + // run tuning proceure (if requested) + if(vm.count("tune")){ + tune_saxpy(x, y, alpha, trials, queue); + } + + // run benchmark + double t = perf_saxpy(x, y, alpha, trials, queue); + std::cout << "time: " << t / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_search.cpp b/src/boost/libs/compute/perf/perf_search.cpp new file mode 100644 index 00000000..b76e9755 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_search.cpp @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/search.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int pattern[] = {2, 6, 6, 7, 8, 4}; + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + boost::compute::vector<int> pattern_vector(pattern, pattern + 6, queue); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::search( + device_vector.begin(), device_vector.end(), + pattern_vector.begin(), pattern_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_search_n.cpp b/src/boost/libs/compute/perf/perf_search_n.cpp new file mode 100644 index 00000000..31fa0adb --- /dev/null +++ b/src/boost/libs/compute/perf/perf_search_n.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/search_n.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::search_n( + device_vector.begin(), device_vector.end(), + 5, 2, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_set_difference.cpp b/src/boost/libs/compute/perf/perf_set_difference.cpp new file mode 100644 index 00000000..b1b28573 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_set_difference.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/set_difference.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vectors of random numbers on the host + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // create vectors on the device and copy the data + boost::compute::vector<int> gpu_v1(std::floor(PERF_N / 2.0), context); + boost::compute::vector<int> gpu_v2(std::ceil(PERF_N / 2.0), context); + + boost::compute::copy( + v1.begin(), v1.end(), gpu_v1.begin(), queue + ); + boost::compute::copy( + v2.begin(), v2.end(), gpu_v2.begin(), queue + ); + + boost::compute::vector<int> gpu_v3(PERF_N, context); + boost::compute::vector<int>::iterator gpu_v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + gpu_v3_end = boost::compute::set_difference( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(gpu_v3.begin(), gpu_v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_set_intersection.cpp b/src/boost/libs/compute/perf/perf_set_intersection.cpp new file mode 100644 index 00000000..dbfeb42f --- /dev/null +++ b/src/boost/libs/compute/perf/perf_set_intersection.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/set_intersection.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vectors of random numbers on the host + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // create vectors on the device and copy the data + boost::compute::vector<int> gpu_v1(std::floor(PERF_N / 2.0), context); + boost::compute::vector<int> gpu_v2(std::ceil(PERF_N / 2.0), context); + + boost::compute::copy( + v1.begin(), v1.end(), gpu_v1.begin(), queue + ); + boost::compute::copy( + v2.begin(), v2.end(), gpu_v2.begin(), queue + ); + + boost::compute::vector<int> gpu_v3(PERF_N, context); + boost::compute::vector<int>::iterator gpu_v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + gpu_v3_end = boost::compute::set_intersection( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(gpu_v3.begin(), gpu_v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_set_symmetric_difference.cpp b/src/boost/libs/compute/perf/perf_set_symmetric_difference.cpp new file mode 100644 index 00000000..9449c585 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_set_symmetric_difference.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/set_symmetric_difference.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vectors of random numbers on the host + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // create vectors on the device and copy the data + boost::compute::vector<int> gpu_v1(std::floor(PERF_N / 2.0), context); + boost::compute::vector<int> gpu_v2(std::ceil(PERF_N / 2.0), context); + + boost::compute::copy( + v1.begin(), v1.end(), gpu_v1.begin(), queue + ); + boost::compute::copy( + v2.begin(), v2.end(), gpu_v2.begin(), queue + ); + + boost::compute::vector<int> gpu_v3(PERF_N, context); + boost::compute::vector<int>::iterator gpu_v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + gpu_v3_end = boost::compute::set_symmetric_difference( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(gpu_v3.begin(), gpu_v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_set_union.cpp b/src/boost/libs/compute/perf/perf_set_union.cpp new file mode 100644 index 00000000..3a336cb6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_set_union.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/set_union.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vectors of random numbers on the host + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // create vectors on the device and copy the data + boost::compute::vector<int> gpu_v1(std::floor(PERF_N / 2.0), context); + boost::compute::vector<int> gpu_v2(std::ceil(PERF_N / 2.0), context); + + boost::compute::copy( + v1.begin(), v1.end(), gpu_v1.begin(), queue + ); + boost::compute::copy( + v2.begin(), v2.end(), gpu_v2.begin(), queue + ); + + boost::compute::vector<int> gpu_v3(PERF_N, context); + boost::compute::vector<int>::iterator gpu_v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + gpu_v3_end = boost::compute::set_union( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(gpu_v3.begin(), gpu_v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_sort.cpp b/src/boost/libs/compute/perf/perf_sort.cpp new file mode 100644 index 00000000..458203ed --- /dev/null +++ b/src/boost/libs/compute/perf/perf_sort.cpp @@ -0,0 +1,130 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <boost/program_options.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 "perf.hpp" + +namespace po = boost::program_options; +namespace compute = boost::compute; + +template<class T> +double perf_sort(const std::vector<T>& data, + const size_t trials, + compute::command_queue& queue) +{ + compute::vector<T> vec(data.size(), queue.get_context()); + + perf_timer t; + for(size_t trial = 0; trial < trials; trial++){ + compute::copy(data.begin(), data.end(), vec.begin(), queue); + t.start(); + compute::sort(vec.begin(), vec.end(), queue); + queue.finish(); + t.stop(); + + if(!compute::is_sorted(vec.begin(), vec.end(), queue)){ + std::cerr << "ERROR: is_sorted() returned false" << std::endl; + } + } + return t.min_time(); +} + +template<class T> +void tune_sort(const std::vector<T>& data, + const size_t trials, + compute::command_queue& queue) +{ + boost::shared_ptr<compute::detail::parameter_cache> + params = compute::detail::parameter_cache::get_global_cache(queue.get_device()); + + const std::string cache_key = + std::string("__boost_radix_sort_") + compute::type_name<T>(); + + const compute::uint_ tpbs[] = { 32, 64, 128, 256, 512, 1024 }; + + double min_time = (std::numeric_limits<double>::max)(); + compute::uint_ best_tpb = 0; + + for(size_t i = 0; i < sizeof(tpbs) / sizeof(*tpbs); i++){ + params->set(cache_key, "tpb", tpbs[i]); + + try { + const double t = perf_sort(data, trials, queue); + if(t < min_time){ + best_tpb = tpbs[i]; + min_time = t; + } + } + catch(compute::opencl_error&){ + // invalid work group size for this device, skip + } + } + + // store optimal parameters + params->set(cache_key, "tpb", best_tpb); +} + +int main(int argc, char *argv[]) +{ + // setup command line arguments + po::options_description options("options"); + options.add_options() + ("help", "show usage instructions") + ("size", po::value<size_t>()->default_value(8192), "input size") + ("trials", po::value<size_t>()->default_value(3), "number of trials to run") + ("tune", "run tuning procedure") + ; + po::positional_options_description positional_options; + positional_options.add("size", 1); + + // parse command line + po::variables_map vm; + po::store( + po::command_line_parser(argc, argv) + .options(options).positional(positional_options).run(), + vm + ); + po::notify(vm); + + const size_t size = vm["size"].as<size_t>(); + const size_t trials = vm["trials"].as<size_t>(); + std::cout << "size: " << size << std::endl; + + // setup context and queue for the default device + compute::device device = boost::compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<unsigned int> data(size); + std::generate(data.begin(), data.end(), rand); + + // run tuning proceure (if requested) + if(vm.count("tune")){ + tune_sort(data, trials, queue); + } + + // run sort benchmark + double t = perf_sort(data, trials, queue); + std::cout << "time: " << t / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_sort_by_key.cpp b/src/boost/libs/compute/perf/perf_sort_by_key.cpp new file mode 100644 index 00000000..57c3fc83 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_sort_by_key.cpp @@ -0,0 +1,79 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#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/fundamental.hpp> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + using boost::compute::int_; + using boost::compute::long_; + + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int_> host_keys(PERF_N); + std::generate(host_keys.begin(), host_keys.end(), rand); + std::vector<long_> host_values(PERF_N); + std::copy(host_keys.begin(), host_keys.end(), host_values.begin()); + + // create vector on the device and copy the data + boost::compute::vector<int_> device_keys(PERF_N, context); + boost::compute::vector<long_> device_values(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_keys.begin(), host_keys.end(), device_keys.begin(), queue + ); + boost::compute::copy( + host_values.begin(), host_values.end(), device_values.begin(), queue + ); + + t.start(); + // sort vector + boost::compute::sort_by_key( + device_keys.begin(), device_keys.end(), device_values.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify keys are sorted + if(!boost::compute::is_sorted(device_keys.begin(), device_keys.end(), queue)){ + std::cout << "ERROR: is_sorted() returned false for the keys" << std::endl; + return -1; + } + // verify values are sorted + if(!boost::compute::is_sorted(device_values.begin(), device_values.end(), queue)){ + std::cout << "ERROR: is_sorted() returned false for the values" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_sort_float.cpp b/src/boost/libs/compute/perf/perf_sort_float.cpp new file mode 100644 index 00000000..1b2d5f5e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_sort_float.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/is_sorted.hpp> +#include <boost/compute/algorithm/sort.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +float rand_float() +{ + return ((rand() / float(RAND_MAX)) - 0.5f) * 100000.0f; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<float> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_float); + + // create vector on the device and copy the data + boost::compute::vector<float> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), + host_vector.end(), + device_vector.begin(), + queue + ); + + // sort vector + perf_timer t; + t.start(); + boost::compute::sort( + device_vector.begin(), + device_vector.end(), + queue + ); + queue.finish(); + t.stop(); + std::cout << "time: " << t.last_time() / 1e6 << " ms" << std::endl; + + // verify vector is sorted + if(!boost::compute::is_sorted(device_vector.begin(), + device_vector.end(), + queue)){ + std::cout << "ERROR: is_sorted() returned false" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stable_partition.cpp b/src/boost/libs/compute/perf/perf_stable_partition.cpp new file mode 100644 index 00000000..f7ef1063 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stable_partition.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/stable_partition.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + + using boost::compute::_1; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + boost::compute::stable_partition( + device_vector.begin(), device_vector.end(), _1 < 10, queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_accumulate.cpp b/src/boost/libs/compute/perf/perf_stl_accumulate.cpp new file mode 100644 index 00000000..c28d2d03 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_accumulate.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int sum = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + sum = std::accumulate(host_vector.begin(), host_vector.end(), int(0)); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "sum: " << sum << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_count.cpp b/src/boost/libs/compute/perf/perf_stl_count.cpp new file mode 100644 index 00000000..9df13f86 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_count.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // count values equal to four in the vector + size_t count = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + count = std::count( + host_vector.begin(), host_vector.end(), 4 + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "count: " << count << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_find.cpp b/src/boost/libs/compute/perf/perf_stl_find.cpp new file mode 100644 index 00000000..b5d3eed2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_find.cpp @@ -0,0 +1,58 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include "perf.hpp" + +// Max integer that can be generated by rand_int() function. +int rand_int_max = 25; + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * rand_int_max); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // trying to find element that isn't in vector (worst-case scenario) + int wanted = rand_int_max + 1; + + // result + std::vector<int>::iterator host_result_it; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + host_result_it = std::find(host_vector.begin(), host_vector.end(), wanted); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify + if(host_result_it != host_vector.end()){ + std::cout << "ERROR: " + << "host_result_iterator != " + << "host_vector.end()" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_find_end.cpp b/src/boost/libs/compute/perf/perf_stl_find_end.cpp new file mode 100644 index 00000000..cb1233b1 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_find_end.cpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int pattern[] = {2, 6, 6, 7, 8, 4}; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::find_end(host_vector.begin(), host_vector.end(), + pattern, pattern + 6); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_includes.cpp b/src/boost/libs/compute/perf/perf_stl_includes.cpp new file mode 100644 index 00000000..b71dbf3c --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_includes.cpp @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v1(PERF_N); + std::generate(v1.begin(), v1.end(), rand_int); + + std::vector<int> v2(v1); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::includes( + v1.begin(), v1.end(), + v2.begin(), v2.end() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_inner_product.cpp b/src/boost/libs/compute/perf/perf_stl_inner_product.cpp new file mode 100644 index 00000000..884f06c9 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_inner_product.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> h1(PERF_N); + std::vector<int> h2(PERF_N); + std::generate(h1.begin(), h1.end(), rand_int); + std::generate(h2.begin(), h2.end(), rand_int); + + int product = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + product = std::inner_product( + h1.begin(), h1.end(), h2.begin(), int(0) + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "product: " << product << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_is_permutation.cpp b/src/boost/libs/compute/perf/perf_stl_is_permutation.cpp new file mode 100644 index 00000000..1384e8e9 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_is_permutation.cpp @@ -0,0 +1,45 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + std::vector<int> host_vector2(PERF_N); + std::copy(host_vector.rbegin(), host_vector.rend(), host_vector2.begin()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::is_permutation(host_vector.begin(), host_vector.end(), + host_vector2.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_max_element.cpp b/src/boost/libs/compute/perf/perf_stl_max_element.cpp new file mode 100644 index 00000000..3fa61267 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_max_element.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Rastko Anicic <anicic.rastko@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 <algorithm> +#include <iostream> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>(rand() % 10000000); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int max = 0; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + max = *(std::max_element(host_vector.begin(), host_vector.end())); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "max: " << max << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_merge.cpp b/src/boost/libs/compute/perf/perf_stl_merge.cpp new file mode 100644 index 00000000..0a842a04 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_merge.cpp @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------------// +// 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 <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + std::vector<int> v1 = generate_random_vector<int>(std::floor(PERF_N / 2.0)); + std::vector<int> v2 = generate_random_vector<int>(std::ceil(PERF_N / 2.0)); + std::vector<int> v3(PERF_N); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_next_permutation.cpp b/src/boost/libs/compute/perf/perf_stl_next_permutation.cpp new file mode 100644 index 00000000..22148975 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_next_permutation.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::sort(host_vector.begin(), host_vector.end(), std::greater<int>()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::next_permutation(host_vector.begin(), host_vector.end()); + t.stop(); + std::prev_permutation(host_vector.begin(), host_vector.end()); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_partial_sum.cpp b/src/boost/libs/compute/perf/perf_stl_partial_sum.cpp new file mode 100644 index 00000000..533defb2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_partial_sum.cpp @@ -0,0 +1,51 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + using boost::compute::int_; + + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int_> v(PERF_N); + std::vector<int_> r(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + std::generate(v.begin(), v.end(), rand_int); + t.start(); + std::partial_sum( + v.begin(), + v.end(), + r.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_partition.cpp b/src/boost/libs/compute/perf/perf_stl_partition.cpp new file mode 100644 index 00000000..56aadd0d --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_partition.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +bool less_than_10(int value) +{ + return value < 10; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::partition(host_vector.begin(), host_vector.end(), less_than_10); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_partition_point.cpp b/src/boost/libs/compute/perf/perf_stl_partition_point.cpp new file mode 100644 index 00000000..94b1c263 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_partition_point.cpp @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +bool less_than_20(int value) +{ + return value < 20; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::partition(host_vector.begin(), host_vector.end(), + less_than_20); + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::partition_point(host_vector.begin(), host_vector.end(), + less_than_20); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_prev_permutation.cpp b/src/boost/libs/compute/perf/perf_stl_prev_permutation.cpp new file mode 100644 index 00000000..f246ba2a --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_prev_permutation.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + std::sort(host_vector.begin(), host_vector.end()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::prev_permutation(host_vector.begin(), host_vector.end()); + t.stop(); + std::next_permutation(host_vector.begin(), host_vector.end()); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_reverse.cpp b/src/boost/libs/compute/perf/perf_stl_reverse.cpp new file mode 100644 index 00000000..b2ee2ef6 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_reverse.cpp @@ -0,0 +1,41 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::reverse(host_vector.begin(), host_vector.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_reverse_copy.cpp b/src/boost/libs/compute/perf/perf_stl_reverse_copy.cpp new file mode 100644 index 00000000..1397e9a7 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_reverse_copy.cpp @@ -0,0 +1,45 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector for reversed data + std::vector<int> host_reversed_vector(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::reverse_copy(host_vector.begin(), host_vector.end(), + host_reversed_vector.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_rotate.cpp b/src/boost/libs/compute/perf/perf_stl_rotate.cpp new file mode 100644 index 00000000..f90acef2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_rotate.cpp @@ -0,0 +1,41 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::rotate(host_vector.begin(), host_vector.begin()+(PERF_N/2), host_vector.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_rotate_copy.cpp b/src/boost/libs/compute/perf/perf_stl_rotate_copy.cpp new file mode 100644 index 00000000..516d11c2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_rotate_copy.cpp @@ -0,0 +1,43 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + std::vector<int> host_vector2(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::rotate_copy(host_vector.begin(), host_vector.begin()+(PERF_N/2), host_vector.end(), host_vector2.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_saxpy.cpp b/src/boost/libs/compute/perf/perf_stl_saxpy.cpp new file mode 100644 index 00000000..8ab33535 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_saxpy.cpp @@ -0,0 +1,52 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include "perf.hpp" + +float rand_float() +{ + return (float(rand()) / float(RAND_MAX)) * 1000.f; +} + +// y <- alpha * x + y +void serial_saxpy(size_t n, float alpha, const float *x, float *y) +{ + for(size_t i = 0; i < n; i++){ + y[i] = alpha * x[i] + y[i]; + } +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + float alpha = 2.5f; + + std::vector<float> host_x(PERF_N); + std::vector<float> host_y(PERF_N); + std::generate(host_x.begin(), host_x.end(), rand_float); + std::generate(host_y.begin(), host_y.end(), rand_float); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + serial_saxpy(PERF_N, alpha, &host_x[0], &host_y[0]); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_search.cpp b/src/boost/libs/compute/perf/perf_stl_search.cpp new file mode 100644 index 00000000..8166d35e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_search.cpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int pattern[] = {2, 6, 6, 7, 8, 4}; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::search(host_vector.begin(), host_vector.end(), + pattern, pattern + 6); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_search_n.cpp b/src/boost/libs/compute/perf/perf_stl_search_n.cpp new file mode 100644 index 00000000..76a6bb07 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_search_n.cpp @@ -0,0 +1,41 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::search_n(host_vector.begin(), host_vector.end(), 5, 2); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_set_difference.cpp b/src/boost/libs/compute/perf/perf_stl_set_difference.cpp new file mode 100644 index 00000000..c5d0802d --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_set_difference.cpp @@ -0,0 +1,54 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + std::vector<int> v3(PERF_N); + std::vector<int>::iterator v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + v3_end = std::set_difference( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(v3.begin(), v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_set_intersection.cpp b/src/boost/libs/compute/perf/perf_stl_set_intersection.cpp new file mode 100644 index 00000000..6aa3493b --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_set_intersection.cpp @@ -0,0 +1,54 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + std::vector<int> v3(PERF_N); + std::vector<int>::iterator v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + v3_end = std::set_intersection( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(v3.begin(), v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_set_symmetric_difference.cpp b/src/boost/libs/compute/perf/perf_stl_set_symmetric_difference.cpp new file mode 100644 index 00000000..c22c70a7 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_set_symmetric_difference.cpp @@ -0,0 +1,54 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + std::vector<int> v3(PERF_N); + std::vector<int>::iterator v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + v3_end = std::set_symmetric_difference( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(v3.begin(), v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_set_union.cpp b/src/boost/libs/compute/perf/perf_stl_set_union.cpp new file mode 100644 index 00000000..9d4fe3a8 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_set_union.cpp @@ -0,0 +1,54 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <vector> +#include <algorithm> +#include <iostream> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v1(std::floor(PERF_N / 2.0)); + std::vector<int> v2(std::ceil(PERF_N / 2.0)); + + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + std::vector<int> v3(PERF_N); + std::vector<int>::iterator v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + v3_end = std::set_union( + v1.begin(), v1.end(), + v2.begin(), v2.end(), + v3.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << std::distance(v3.begin(), v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_sort.cpp b/src/boost/libs/compute/perf/perf_stl_sort.cpp new file mode 100644 index 00000000..c9d4294b --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_sort.cpp @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + std::vector<int> v; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + v = generate_random_vector<int>(PERF_N); + t.start(); + std::sort(v.begin(), v.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_stable_partition.cpp b/src/boost/libs/compute/perf/perf_stl_stable_partition.cpp new file mode 100644 index 00000000..ee4993cc --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_stable_partition.cpp @@ -0,0 +1,47 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +bool less_than_10(int value) +{ + return value < 10; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + std::stable_partition(host_vector.begin(), host_vector.end(), + less_than_10); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_unique.cpp b/src/boost/libs/compute/perf/perf_stl_unique.cpp new file mode 100644 index 00000000..f4f97b4b --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_unique.cpp @@ -0,0 +1,41 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + std::generate(host_vector.begin(), host_vector.end(), rand_int); + t.start(); + std::unique(host_vector.begin(), host_vector.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_stl_unique_copy.cpp b/src/boost/libs/compute/perf/perf_stl_unique_copy.cpp new file mode 100644 index 00000000..77705fa2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_stl_unique_copy.cpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::vector<int> host_vector2(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + std::generate(host_vector.begin(), host_vector.end(), rand_int); + t.start(); + std::unique_copy( + host_vector.begin(), host_vector.end(), host_vector2.begin() + ); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_tbb_accumulate.cpp b/src/boost/libs/compute/perf/perf_tbb_accumulate.cpp new file mode 100644 index 00000000..319ad8af --- /dev/null +++ b/src/boost/libs/compute/perf/perf_tbb_accumulate.cpp @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <tbb/blocked_range.h> +#include <tbb/parallel_reduce.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +template<class T> +struct Sum { + T value; + Sum() : value(0) {} + Sum( Sum& s, tbb::split ) {value = 0;} + void operator()( const tbb::blocked_range<T*>& r ) { + T temp = value; + for( T* a=r.begin(); a!=r.end(); ++a ) { + temp += *a; + } + value = temp; + } + void join( Sum& rhs ) {value += rhs.value;} +}; + +template<class T> +T ParallelSum( T array[], size_t n ) { + Sum<T> total; + tbb::parallel_reduce( tbb::blocked_range<T*>( array, array+n ), + total ); + return total.value; +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + int sum = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + sum = ParallelSum<int>(&host_vector[0], host_vector.size()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "sum: " << sum << std::endl; + + int host_sum = std::accumulate(host_vector.begin(), host_vector.end(), int(0)); + if(sum != host_sum){ + std::cerr << "ERROR: sum (" << sum << ") != (" << host_sum << ")" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_tbb_merge.cpp b/src/boost/libs/compute/perf/perf_tbb_merge.cpp new file mode 100644 index 00000000..a7aa814e --- /dev/null +++ b/src/boost/libs/compute/perf/perf_tbb_merge.cpp @@ -0,0 +1,95 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 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 <algorithm> +#include <iostream> +#include <vector> + +#include <tbb/parallel_for.h> + +#include "perf.hpp" + +// example from: http://www.threadingbuildingblocks.org/docs/help/reference/algorithms/parallel_for_func.htm +using namespace tbb; + +template<typename Iterator> +struct ParallelMergeRange { + static size_t grainsize; + Iterator begin1, end1; // [begin1,end1) is 1st sequence to be merged + Iterator begin2, end2; // [begin2,end2) is 2nd sequence to be merged + Iterator out; // where to put merged sequence + bool empty() const {return (end1-begin1)+(end2-begin2)==0;} + bool is_divisible() const { + return (std::min)( end1-begin1, end2-begin2 ) > grainsize; + } + ParallelMergeRange( ParallelMergeRange& r, split ) { + if( r.end1-r.begin1 < r.end2-r.begin2 ) { + std::swap(r.begin1,r.begin2); + std::swap(r.end1,r.end2); + } + Iterator m1 = r.begin1 + (r.end1-r.begin1)/2; + Iterator m2 = std::lower_bound( r.begin2, r.end2, *m1 ); + begin1 = m1; + begin2 = m2; + end1 = r.end1; + end2 = r.end2; + out = r.out + (m1-r.begin1) + (m2-r.begin2); + r.end1 = m1; + r.end2 = m2; + } + ParallelMergeRange( Iterator begin1_, Iterator end1_, + Iterator begin2_, Iterator end2_, + Iterator out_ ) : + begin1(begin1_), end1(end1_), + begin2(begin2_), end2(end2_), out(out_) + {} +}; + +template<typename Iterator> +size_t ParallelMergeRange<Iterator>::grainsize = 1000; + +template<typename Iterator> +struct ParallelMergeBody { + void operator()( ParallelMergeRange<Iterator>& r ) const { + std::merge( r.begin1, r.end1, r.begin2, r.end2, r.out ); + } +}; + +template<typename Iterator> +void ParallelMerge( Iterator begin1, Iterator end1, Iterator begin2, Iterator end2, Iterator out ) { + parallel_for( + ParallelMergeRange<Iterator>(begin1,end1,begin2,end2,out), + ParallelMergeBody<Iterator>(), + simple_partitioner() + ); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + std::vector<int> v1 = generate_random_vector<int>(PERF_N / 2); + std::vector<int> v2 = generate_random_vector<int>(PERF_N / 2); + std::vector<int> v3(PERF_N); + + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + ParallelMerge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_tbb_sort.cpp b/src/boost/libs/compute/perf/perf_tbb_sort.cpp new file mode 100644 index 00000000..2f79b5b2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_tbb_sort.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. +//---------------------------------------------------------------------------// + +#include <iostream> +#include <vector> + +#include <tbb/parallel_sort.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + std::vector<int> v(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + v = generate_random_vector<int>(PERF_N); + t.start(); + tbb::parallel_sort(v.begin(), v.end()); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_accumulate.cu b/src/boost/libs/compute/perf/perf_thrust_accumulate.cu new file mode 100644 index 00000000..76b72321 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_accumulate.cu @@ -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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/reduce.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec = h_vec; + + int sum = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + sum = thrust::reduce(d_vec.begin(), d_vec.end()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "sum: " << sum << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_count.cu b/src/boost/libs/compute/perf/perf_thrust_count.cu new file mode 100644 index 00000000..d69df901 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_count.cu @@ -0,0 +1,49 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <iostream> +#include <vector> + +#include <thrust/count.h> +#include <thrust/host_vector.h> +#include <thrust/device_vector.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + thrust::host_vector<int> host_vector(PERF_N); + thrust::generate(host_vector.begin(), host_vector.end(), rand_int); + + thrust::device_vector<int> v = host_vector; + + size_t count = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + count = thrust::count(v.begin(), v.end(), 4); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "count: " << count << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_exclusive_scan.cu b/src/boost/libs/compute/perf/perf_thrust_exclusive_scan.cu new file mode 100644 index 00000000..df1367a2 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_exclusive_scan.cu @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2014 Benoit +// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/scan.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec = h_vec; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::exclusive_scan(d_vec.begin(), d_vec.end(), d_vec.begin()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_find.cu b/src/boost/libs/compute/perf/perf_thrust_find.cu new file mode 100644 index 00000000..e1482604 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_find.cu @@ -0,0 +1,65 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <thrust/find.h> +#include <thrust/host_vector.h> +#include <thrust/device_vector.h> + +#include "perf.hpp" + +// Max integer that can be generated by rand_int() function. +int rand_int_max = 25; + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * rand_int_max); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // create vector of random numbers on the host + thrust::host_vector<int> host_vector(PERF_N); + thrust::generate(host_vector.begin(), host_vector.end(), rand_int); + + thrust::device_vector<int> v = host_vector; + + // trying to find element that isn't in vector (worst-case scenario) + int wanted = rand_int_max + 1; + + // result + thrust::device_vector<int>::iterator device_result_it; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + device_result_it = thrust::find(v.begin(), v.end(), wanted); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // verify + if(device_result_it != v.end()){ + std::cout << "ERROR: " + << "device_result_iterator != " + << "v.end()" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_inner_product.cu b/src/boost/libs/compute/perf/perf_thrust_inner_product.cu new file mode 100644 index 00000000..6d01fc53 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_inner_product.cu @@ -0,0 +1,49 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <iterator> +#include <algorithm> + +#include <thrust/device_vector.h> +#include <thrust/host_vector.h> +#include <thrust/inner_product.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> host_x(PERF_N); + thrust::host_vector<int> host_y(PERF_N); + std::generate(host_x.begin(), host_x.end(), rand); + std::generate(host_y.begin(), host_y.end(), rand); + + // transfer data to the device + thrust::device_vector<int> device_x = host_x; + thrust::device_vector<int> device_y = host_y; + + int product = 0; + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + product = thrust::inner_product( + device_x.begin(), device_x.end(), device_y.begin(), 0 + ); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "product: " << product << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_merge.cu b/src/boost/libs/compute/perf/perf_thrust_merge.cu new file mode 100644 index 00000000..f269c939 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_merge.cu @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <iterator> +#include <algorithm> + +#include <thrust/device_vector.h> +#include <thrust/host_vector.h> +#include <thrust/merge.h> +#include <thrust/sort.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> v1(std::floor(PERF_N / 2.0)); + thrust::host_vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand); + std::generate(v2.begin(), v2.end(), rand); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // transfer data to the device + thrust::device_vector<int> gpu_v1 = v1; + thrust::device_vector<int> gpu_v2 = v2; + thrust::device_vector<int> gpu_v3(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + thrust::merge( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin() + ); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + thrust::host_vector<int> check_v3 = gpu_v3; + + thrust::host_vector<int> v3(PERF_N); + std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin()); + bool ok = std::equal(check_v3.begin(), check_v3.end(), v3.begin()); + if(!ok){ + std::cerr << "ERROR: merged ranges different" << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_partial_sum.cu b/src/boost/libs/compute/perf/perf_thrust_partial_sum.cu new file mode 100644 index 00000000..e30e80b5 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_partial_sum.cu @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/scan.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec = h_vec; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::inclusive_scan(d_vec.begin(), d_vec.end(), d_vec.begin()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_partition.cu b/src/boost/libs/compute/perf/perf_thrust_partition.cu new file mode 100644 index 00000000..5c89014c --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_partition.cu @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/partition.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +struct less_than_ten : public thrust::unary_function<bool, int> +{ + __device__ bool operator()(int x) const + { + return x < 10; + } +}; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec(PERF_N); + std::generate(h_vec.begin(), h_vec.end(), rand_int); + + thrust::device_vector<int> d_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::partition( + d_vec.begin(), d_vec.end(), less_than_ten() + ); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_reduce_by_key.cu b/src/boost/libs/compute/perf/perf_thrust_reduce_by_key.cu new file mode 100644 index 00000000..a445c137 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_reduce_by_key.cu @@ -0,0 +1,92 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/reduce.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +struct unique_key { + int current; + int avgValuesNoPerKey; + + unique_key() + { + current = 0; + avgValuesNoPerKey = 512; + } + + int operator()() + { + double p = double(1.0) / static_cast<double>(avgValuesNoPerKey); + if((rand() / double(RAND_MAX)) <= p) + return ++current; + return current; + } +} UniqueKey; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + + // create vector of keys and random values + thrust::host_vector<int> host_keys(PERF_N); + thrust::host_vector<int> host_values(PERF_N); + std::generate(host_keys.begin(), host_keys.end(), UniqueKey); + std::generate(host_values.begin(), host_values.end(), rand_int); + + // transfer data to the device + thrust::device_vector<int> device_keys = host_keys; + thrust::device_vector<int> device_values = host_values; + + // create device vectors for the results + thrust::device_vector<int> device_keys_results(PERF_N); + thrust::device_vector<int> device_values_results(PERF_N); + + typedef typename thrust::device_vector<int>::iterator iterType; + thrust::pair<iterType, iterType> result; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + result = thrust::reduce_by_key(device_keys.begin(), + device_keys.end(), + device_values.begin(), + device_keys_results.begin(), + device_values_results.begin()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + size_t result_size = thrust::distance(device_keys_results.begin(), result.first); + if(result_size != static_cast<size_t>(host_keys[PERF_N-1] + 1)){ + std::cout << "ERROR: " + << "wrong number of keys" + << std::endl; + return -1; + } + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_reverse.cu b/src/boost/libs/compute/perf/perf_thrust_reverse.cu new file mode 100644 index 00000000..1927ca6a --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_reverse.cu @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/reverse.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::reverse(d_vec.begin(), d_vec.end()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_reverse_copy.cu b/src/boost/libs/compute/perf/perf_thrust_reverse_copy.cu new file mode 100644 index 00000000..af1a044d --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_reverse_copy.cu @@ -0,0 +1,47 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/reverse.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec; + d_vec = h_vec; + + // device vector for reversed data + thrust::device_vector<int> d_reversed_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + thrust::reverse_copy(d_vec.begin(), d_vec.end(), d_reversed_vec.begin()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_rotate.cu b/src/boost/libs/compute/perf/perf_thrust_rotate.cu new file mode 100644 index 00000000..108bb99b --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_rotate.cu @@ -0,0 +1,51 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/host_vector.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec; + + size_t rotate_distance = PERF_N / 2; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + // there is no thrust::rotate() so we implement it manually with copy() + thrust::device_vector<int> tmp(d_vec.begin(), d_vec.begin() + rotate_distance); + thrust::copy(d_vec.begin() + rotate_distance, d_vec.end(), d_vec.begin()); + thrust::copy(tmp.begin(), tmp.end(), d_vec.begin() + rotate_distance); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_saxpy.cu b/src/boost/libs/compute/perf/perf_thrust_saxpy.cu new file mode 100644 index 00000000..aa35a191 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_saxpy.cu @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <iterator> +#include <algorithm> + +#include <thrust/device_vector.h> +#include <thrust/functional.h> +#include <thrust/host_vector.h> +#include <thrust/transform.h> + +#include "perf.hpp" + +struct saxpy_functor : public thrust::binary_function<float,float,float> +{ + const float a; + + saxpy_functor(float _a) : a(_a) {} + + __host__ __device__ + float operator()(const float& x, const float& y) const + { + return a * x + y; + } +}; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> host_x(PERF_N); + thrust::host_vector<int> host_y(PERF_N); + std::generate(host_x.begin(), host_x.end(), rand); + std::generate(host_y.begin(), host_y.end(), rand); + + // transfer data to the device + thrust::device_vector<int> device_x = host_x; + thrust::device_vector<int> device_y = host_y; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + thrust::transform(device_x.begin(), device_x.end(), device_y.begin(), device_y.begin(), saxpy_functor(2.5f)); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(device_x.begin(), device_x.end(), host_x.begin()); + thrust::copy(device_y.begin(), device_y.end(), host_y.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_set_difference.cu b/src/boost/libs/compute/perf/perf_thrust_set_difference.cu new file mode 100644 index 00000000..3465f214 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_set_difference.cu @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// 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 <iostream> +#include <iterator> +#include <algorithm> + +#include <thrust/device_vector.h> +#include <thrust/host_vector.h> +#include <thrust/set_operations.h> +#include <thrust/sort.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> v1(std::floor(PERF_N / 2.0)); + thrust::host_vector<int> v2(std::ceil(PERF_N / 2.0)); + std::generate(v1.begin(), v1.end(), rand_int); + std::generate(v2.begin(), v2.end(), rand_int); + std::sort(v1.begin(), v1.end()); + std::sort(v2.begin(), v2.end()); + + // transfer data to the device + thrust::device_vector<int> gpu_v1 = v1; + thrust::device_vector<int> gpu_v2 = v2; + thrust::device_vector<int> gpu_v3(PERF_N); + + thrust::device_vector<int>::iterator gpu_v3_end; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + t.start(); + gpu_v3_end = thrust::set_difference( + gpu_v1.begin(), gpu_v1.end(), + gpu_v2.begin(), gpu_v2.end(), + gpu_v3.begin() + ); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + std::cout << "size: " << thrust::distance(gpu_v3.begin(), gpu_v3_end) << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_sort.cu b/src/boost/libs/compute/perf/perf_thrust_sort.cu new file mode 100644 index 00000000..b2d90939 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_sort.cu @@ -0,0 +1,48 @@ +//---------------------------------------------------------------------------// +// 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 <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/sort.h> + +#include "perf.hpp" + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec = generate_random_vector<int>(PERF_N); + + // transfer data to the device + thrust::device_vector<int> d_vec; + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::sort(d_vec.begin(), d_vec.end()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + // transfer data back to host + thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_thrust_unique.cu b/src/boost/libs/compute/perf/perf_thrust_unique.cu new file mode 100644 index 00000000..6030f291 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_thrust_unique.cu @@ -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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <cstdlib> +#include <iostream> + +#include <thrust/copy.h> +#include <thrust/device_vector.h> +#include <thrust/generate.h> +#include <thrust/host_vector.h> +#include <thrust/unique.h> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + + std::cout << "size: " << PERF_N << std::endl; + thrust::host_vector<int> h_vec(PERF_N); + std::generate(h_vec.begin(), h_vec.end(), rand_int); + + thrust::device_vector<int> d_vec(PERF_N); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + d_vec = h_vec; + + t.start(); + thrust::unique(d_vec.begin(), d_vec.end()); + cudaDeviceSynchronize(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_uniform_int_distribution.cpp b/src/boost/libs/compute/perf/perf_uniform_int_distribution.cpp new file mode 100644 index 00000000..57973a81 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_uniform_int_distribution.cpp @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/container/vector.hpp> +#include <boost/compute/random/default_random_engine.hpp> +#include <boost/compute/random/uniform_int_distribution.hpp> + +#include "perf.hpp" + +namespace compute = boost::compute; + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + compute::device device = compute::system::default_device(); + compute::context context(device); + compute::command_queue queue(context, device); + + compute::vector<compute::uint_> vector(PERF_N, context); + + compute::default_random_engine rng(queue); + compute::uniform_int_distribution<compute::uint_> dist(0, 1); + + perf_timer t; + t.start(); + dist.generate(vector.begin(), vector.end(), rng, queue); + queue.finish(); + t.stop(); + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_unique.cpp b/src/boost/libs/compute/perf/perf_unique.cpp new file mode 100644 index 00000000..b25801f1 --- /dev/null +++ b/src/boost/libs/compute/perf/perf_unique.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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/unique.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + t.start(); + boost::compute::unique( + device_vector.begin(), device_vector.end(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perf_unique_copy.cpp b/src/boost/libs/compute/perf/perf_unique_copy.cpp new file mode 100644 index 00000000..d7ff98af --- /dev/null +++ b/src/boost/libs/compute/perf/perf_unique_copy.cpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#include <algorithm> +#include <iostream> +#include <numeric> +#include <vector> + +#include <boost/compute/system.hpp> +#include <boost/compute/algorithm/unique_copy.hpp> +#include <boost/compute/container/vector.hpp> + +#include "perf.hpp" + +int rand_int() +{ + return static_cast<int>((rand() / double(RAND_MAX)) * 25.0); +} + +int main(int argc, char *argv[]) +{ + perf_parse_args(argc, argv); + std::cout << "size: " << PERF_N << std::endl; + + // setup context and queue for the default device + boost::compute::device device = boost::compute::system::default_device(); + boost::compute::context context(device); + boost::compute::command_queue queue(context, device); + std::cout << "device: " << device.name() << std::endl; + + // create vector of random numbers on the host + std::vector<int> host_vector(PERF_N); + std::generate(host_vector.begin(), host_vector.end(), rand_int); + + // create vector on the device and copy the data + boost::compute::vector<int> device_vector(PERF_N, context); + boost::compute::vector<int> device_vector2(PERF_N, context); + + perf_timer t; + for(size_t trial = 0; trial < PERF_TRIALS; trial++){ + boost::compute::copy( + host_vector.begin(), host_vector.end(), device_vector.begin(), queue + ); + t.start(); + boost::compute::unique_copy( + device_vector.begin(), device_vector.end(), device_vector2.begin(), queue + ); + queue.finish(); + t.stop(); + } + std::cout << "time: " << t.min_time() / 1e6 << " ms" << std::endl; + + return 0; +} diff --git a/src/boost/libs/compute/perf/perfdoc.py b/src/boost/libs/compute/perf/perfdoc.py new file mode 100755 index 00000000..e9c60362 --- /dev/null +++ b/src/boost/libs/compute/perf/perfdoc.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +# Copyright (c) 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. + +import os +import sys +import pylab + +from perf import run_benchmark + +fignum = 0 + +def plot_to_file(report, filename): + global fignum + fignum += 1 + pylab.figure(fignum) + + run_to_label = { + "stl" : "C++ STL", + "thrust" : "Thrust", + "compute" : "Boost.Compute", + "bolt" : "Bolt" + } + + for run in sorted(report.samples.keys()): + x = [] + y = [] + + for sample in report.samples[run]: + x.append(sample[0]) + y.append(sample[1]) + + pylab.loglog(x, y, marker='o', label=run_to_label[run]) + + pylab.xlabel("Size") + pylab.ylabel("Time (ms)") + pylab.legend(loc='upper left') + pylab.savefig(filename) + +if __name__ == '__main__': + sizes = [pow(2, x) for x in range(10, 26)] + algorithms = [ + "accumulate", + "count", + "inner_product", + "merge", + "partial_sum", + "partition", + "reverse", + "rotate", + "saxpy", + "sort", + "unique", + ] + + try: + os.mkdir("perf_plots") + except OSError: + pass + + for algorithm in algorithms: + print("running '%s'" % (algorithm)) + report = run_benchmark(algorithm, sizes, ["stl", "thrust", "bolt"]) + plot_to_file(report, "perf_plots/%s_time_plot.png" % algorithm) + 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() |