/****************************************************************************** * Copyright (c) 2016, NVIDIA CORPORATION. All rights meserved. * * 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 the NVIDIA CORPORATION 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 NVIDIA CORPORATION 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. * ******************************************************************************/ #pragma once #include #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) # pragma clang system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) # pragma system_header #endif // no system header #include #include #include #include #include #include #include #include #include #include THRUST_NAMESPACE_BEGIN namespace cuda_cub { inline _CCCL_HOST_DEVICE cudaStream_t default_stream() { #ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM return cudaStreamPerThread; #else return cudaStreamLegacy; #endif } // Fallback implementation of the customization point. template _CCCL_HOST_DEVICE cudaStream_t get_stream(execution_policy&) { return default_stream(); } // Entry point/interface. template _CCCL_HOST_DEVICE cudaStream_t stream(execution_policy& policy) { return get_stream(derived_cast(policy)); } // Fallback implementation of the customization point. template _CCCL_HOST_DEVICE bool must_perform_optional_stream_synchronization(execution_policy&) { return true; } // Entry point/interface. template _CCCL_HOST_DEVICE bool must_perform_optional_synchronization(execution_policy& policy) { return must_perform_optional_stream_synchronization(derived_cast(policy)); } // Fallback implementation of the customization point. _CCCL_EXEC_CHECK_DISABLE template _CCCL_HOST_DEVICE cudaError_t synchronize_stream(execution_policy& policy) { return cub::SyncStream(stream(policy)); } // Entry point/interface. template _CCCL_HOST_DEVICE cudaError_t synchronize(Policy& policy) { return synchronize_stream(derived_cast(policy)); } // Fallback implementation of the customization point. _CCCL_EXEC_CHECK_DISABLE template _CCCL_HOST_DEVICE cudaError_t synchronize_stream_optional(execution_policy& policy) { cudaError_t result; if (must_perform_optional_synchronization(policy)) { result = synchronize_stream(policy); } else { result = cudaSuccess; } return result; } // Entry point/interface. template _CCCL_HOST_DEVICE cudaError_t synchronize_optional(Policy& policy) { return synchronize_stream_optional(derived_cast(policy)); } template THRUST_HOST_FUNCTION cudaError_t trivial_copy_from_device(Type* dst, Type const* src, size_t count, cudaStream_t stream) { cudaError status = cudaSuccess; if (count == 0) { return status; } status = ::cudaMemcpyAsync(dst, src, sizeof(Type) * count, cudaMemcpyDeviceToHost, stream); cudaStreamSynchronize(stream); return status; } template THRUST_HOST_FUNCTION cudaError_t trivial_copy_to_device(Type* dst, Type const* src, size_t count, cudaStream_t stream) { cudaError status = cudaSuccess; if (count == 0) { return status; } status = ::cudaMemcpyAsync(dst, src, sizeof(Type) * count, cudaMemcpyHostToDevice, stream); cudaStreamSynchronize(stream); return status; } template _CCCL_HOST_DEVICE cudaError_t trivial_copy_device_to_device(Policy& policy, Type* dst, Type const* src, size_t count) { cudaError_t status = cudaSuccess; if (count == 0) { return status; } cudaStream_t stream = cuda_cub::stream(policy); // status = ::cudaMemcpyAsync(dst, src, sizeof(Type) * count, cudaMemcpyDeviceToDevice, stream); cuda_cub::synchronize(policy); return status; } inline void _CCCL_HOST_DEVICE terminate() { NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (asm("trap;");)); } _CCCL_HOST_DEVICE inline void throw_on_error(cudaError_t status) { // Clear the global CUDA error state which may have been set by the last // call. Otherwise, errors may "leak" to unrelated kernel launches. #ifdef THRUST_RDC_ENABLED cudaGetLastError(); #else NV_IF_TARGET(NV_IS_HOST, (cudaGetLastError();)); #endif if (cudaSuccess != status) { // Can't use #if inside NV_IF_TARGET, use a temp macro to hoist the device // instructions out of the target logic. #ifdef THRUST_RDC_ENABLED # define THRUST_TEMP_DEVICE_CODE \ printf("Thrust CUDA backend error: %s: %s\n", cudaGetErrorName(status), cudaGetErrorString(status)) #else # define THRUST_TEMP_DEVICE_CODE printf("Thrust CUDA backend error: %d\n", static_cast(status)) #endif NV_IF_TARGET(NV_IS_HOST, (throw thrust::system_error(status, thrust::cuda_category());), (THRUST_TEMP_DEVICE_CODE; cuda_cub::terminate();)); #undef THRUST_TEMP_DEVICE_CODE } } _CCCL_HOST_DEVICE inline void throw_on_error(cudaError_t status, char const* msg) { // Clear the global CUDA error state which may have been set by the last // call. Otherwise, errors may "leak" to unrelated kernel launches. #ifdef THRUST_RDC_ENABLED cudaGetLastError(); #else NV_IF_TARGET(NV_IS_HOST, (cudaGetLastError();)); #endif if (cudaSuccess != status) { // Can't use #if inside NV_IF_TARGET, use a temp macro to hoist the device // instructions out of the target logic. #ifdef THRUST_RDC_ENABLED # define THRUST_TEMP_DEVICE_CODE \ printf("Thrust CUDA backend error: %s: %s: %s\n", cudaGetErrorName(status), cudaGetErrorString(status), msg) #else # define THRUST_TEMP_DEVICE_CODE printf("Thrust CUDA backend error: %d: %s\n", static_cast(status), msg) #endif NV_IF_TARGET(NV_IS_HOST, (throw thrust::system_error(status, thrust::cuda_category(), msg);), (THRUST_TEMP_DEVICE_CODE; cuda_cub::terminate();)); #undef THRUST_TEMP_DEVICE_CODE } } // FIXME: Move the iterators elsewhere. template struct transform_input_iterator_t { typedef transform_input_iterator_t self_t; typedef typename iterator_traits::difference_type difference_type; typedef ValueType value_type; typedef void pointer; typedef value_type reference; typedef std::random_access_iterator_tag iterator_category; InputIt input; mutable UnaryOp op; _CCCL_HOST_DEVICE _CCCL_FORCEINLINE transform_input_iterator_t(InputIt input, UnaryOp op) : input(input) , op(op) {} transform_input_iterator_t(const self_t&) = default; // UnaryOp might not be copy assignable, such as when it is a lambda. Define // an explicit copy assignment operator that doesn't try to assign it. _CCCL_HOST_DEVICE self_t& operator=(const self_t& o) { input = o.input; return *this; } /// Postfix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++(int) { self_t retval = *this; ++input; return retval; } /// Prefix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++() { ++input; return *this; } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() const { typename thrust::iterator_value::type x = *input; return op(x); } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() { typename thrust::iterator_value::type x = *input; return op(x); } /// Addition _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator+(difference_type n) const { return self_t(input + n, op); } /// Addition assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator+=(difference_type n) { input += n; return *this; } /// Subtraction _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator-(difference_type n) const { return self_t(input - n, op); } /// Subtraction assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator-=(difference_type n) { input -= n; return *this; } /// Distance _CCCL_HOST_DEVICE _CCCL_FORCEINLINE difference_type operator-(self_t other) const { return input - other.input; } /// Array subscript _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator[](difference_type n) const { return op(input[n]); } /// Equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator==(const self_t& rhs) const { return (input == rhs.input); } /// Not equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator!=(const self_t& rhs) const { return (input != rhs.input); } }; // struct transform_input_iterarot_t template struct transform_pair_of_input_iterators_t { typedef transform_pair_of_input_iterators_t self_t; typedef typename iterator_traits::difference_type difference_type; typedef ValueType value_type; typedef void pointer; typedef value_type reference; typedef std::random_access_iterator_tag iterator_category; InputIt1 input1; InputIt2 input2; mutable BinaryOp op; _CCCL_HOST_DEVICE _CCCL_FORCEINLINE transform_pair_of_input_iterators_t(InputIt1 input1_, InputIt2 input2_, BinaryOp op_) : input1(input1_) , input2(input2_) , op(op_) {} transform_pair_of_input_iterators_t(const self_t&) = default; // BinaryOp might not be copy assignable, such as when it is a lambda. // Define an explicit copy assignment operator that doesn't try to assign it. _CCCL_HOST_DEVICE self_t& operator=(const self_t& o) { input1 = o.input1; input2 = o.input2; return *this; } /// Postfix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++(int) { self_t retval = *this; ++input1; ++input2; return retval; } /// Prefix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++() { ++input1; ++input2; return *this; } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() const { return op(*input1, *input2); } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() { return op(*input1, *input2); } /// Addition _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator+(difference_type n) const { return self_t(input1 + n, input2 + n, op); } /// Addition assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator+=(difference_type n) { input1 += n; input2 += n; return *this; } /// Subtraction _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator-(difference_type n) const { return self_t(input1 - n, input2 - n, op); } /// Subtraction assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator-=(difference_type n) { input1 -= n; input2 -= n; return *this; } /// Distance _CCCL_HOST_DEVICE _CCCL_FORCEINLINE difference_type operator-(self_t other) const { return input1 - other.input1; } /// Array subscript _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator[](difference_type n) const { return op(input1[n], input2[n]); } /// Equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator==(const self_t& rhs) const { return (input1 == rhs.input1) && (input2 == rhs.input2); } /// Not equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator!=(const self_t& rhs) const { return (input1 != rhs.input1) || (input2 != rhs.input2); } }; // struct transform_pair_of_input_iterators_t struct identity { template _CCCL_HOST_DEVICE T const& operator()(T const& t) const { return t; } template _CCCL_HOST_DEVICE T& operator()(T& t) const { return t; } }; template struct counting_iterator_t { typedef counting_iterator_t self_t; typedef T difference_type; typedef T value_type; typedef void pointer; typedef T reference; typedef std::random_access_iterator_tag iterator_category; T count; _CCCL_HOST_DEVICE _CCCL_FORCEINLINE counting_iterator_t(T count_) : count(count_) {} /// Postfix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++(int) { self_t retval = *this; ++count; return retval; } /// Prefix increment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator++() { ++count; return *this; } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() const { return count; } /// Indirection _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator*() { return count; } /// Addition _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator+(difference_type n) const { return self_t(count + n); } /// Addition assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator+=(difference_type n) { count += n; return *this; } /// Subtraction _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t operator-(difference_type n) const { return self_t(count - n); } /// Subtraction assignment _CCCL_HOST_DEVICE _CCCL_FORCEINLINE self_t& operator-=(difference_type n) { count -= n; return *this; } /// Distance _CCCL_HOST_DEVICE _CCCL_FORCEINLINE difference_type operator-(self_t other) const { return count - other.count; } /// Array subscript _CCCL_HOST_DEVICE _CCCL_FORCEINLINE reference operator[](difference_type n) const { return count + n; } /// Equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator==(const self_t& rhs) const { return (count == rhs.count); } /// Not equal to _CCCL_HOST_DEVICE _CCCL_FORCEINLINE bool operator!=(const self_t& rhs) const { return (count != rhs.count); } }; // struct count_iterator_t } // namespace cuda_cub THRUST_NAMESPACE_END