CCCL (CUDA C++ Core Libraries) provides: - CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk) - Thrust: high-level parallel algorithms (transform_reduce, sort, scan) - libcudacxx: CUDA C++ standard library (atomics, barriers, memory) - cudax: experimental features (memory resources, allocators) - Tuning policies: per-SM hardware-specific algorithm parameters Competition optimization vectors mapped to CCCL: - Output TPS (83% weight): warp_reduce, block_reduce, device_topk - Input TPS (14% weight): device_scan, block_load, prefetch - Cache TPS (3% weight): prefix caching strategy patterns - Memory (0.9 util): pooled/cached/buddy allocators Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only) License: Apache-2.0
294 lines
12 KiB
Plaintext
294 lines
12 KiB
Plaintext
// SPDX-FileCopyrightText: Copyright (c) 2011-2022, NVIDIA CORPORATION. All rights reserved.
|
|
// SPDX-License-Identifier: BSD-3
|
|
|
|
//! @file
|
|
//! cub::DeviceMemcpy provides device-wide, parallel operations for copying data.
|
|
|
|
#pragma once
|
|
|
|
#include <cub/config.cuh>
|
|
|
|
#ifndef CCCL_DISABLE_NVRTC_COMPATIBILITY_CHECK
|
|
# if _CCCL_COMPILER(NVRTC)
|
|
# error \
|
|
"Including <cub/device/device_memcpy.cuh> is not supported when compiling with NVRTC. Include block-, warp-, or thread-level primitives instead (e.g. <cub/block/block_reduce.cuh>). You can define CCCL_DISABLE_NVRTC_COMPATIBILITY_CHECK to disable this warning."
|
|
# endif // _CCCL_COMPILER(NVRTC)
|
|
#endif // CCCL_DISABLE_NVRTC_COMPATIBILITY_CHECK
|
|
|
|
#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 <cub/detail/env_dispatch.cuh>
|
|
#include <cub/device/dispatch/dispatch_batch_memcpy.cuh>
|
|
|
|
#include <cuda/std/__execution/env.h>
|
|
#include <cuda/std/__type_traits/is_pointer.h>
|
|
#include <cuda/std/cstdint>
|
|
|
|
CUB_NAMESPACE_BEGIN
|
|
|
|
//! @brief cub::DeviceMemcpy provides device-wide, parallel operations for copying data.
|
|
//!
|
|
//! @rst
|
|
//!
|
|
//! Tuning
|
|
//! +++++++++++++++++++++++++++++++++++++++++++++
|
|
//!
|
|
//! All algorithms in DeviceMemcpy that accept an environment can be tuned by passing a custom :ref:`policy selector
|
|
//! <cub-policy-selectors>` that returns a :cpp:struct:`cub::BatchedCopyPolicy`, as shown in the example below:
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/test/catch2_test_device_memcpy_env_api.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin memcpy-batched-policy-selector
|
|
//! :end-before: example-end memcpy-batched-policy-selector
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/test/catch2_test_device_memcpy_env_api.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin memcpy-batched-tuning
|
|
//! :end-before: example-end memcpy-batched-tuning
|
|
//! @endrst
|
|
struct DeviceMemcpy
|
|
{
|
|
//! @rst
|
|
//! Copies data from a batch of given source buffers to their corresponding destination buffer.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! .. note::
|
|
//!
|
|
//! If any input buffer aliases memory from any output buffer the behavior is undefined.
|
|
//! If any output buffer aliases memory of another output buffer the behavior is undefined.
|
|
//! Input buffers can alias one another.
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates usage of DeviceMemcpy::Batched for mutating strings withing
|
|
//! a single string buffer.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! struct GetPtrToStringItem
|
|
//! {
|
|
//! __host__ __device__ __forceinline__ void *operator()(uint32_t index)
|
|
//! {
|
|
//! return &d_string_data_in[d_string_offsets[index]];
|
|
//! }
|
|
//! char *d_string_data_in;
|
|
//! uint32_t *d_string_offsets;
|
|
//! };
|
|
//!
|
|
//! struct GetStringItemSize
|
|
//! {
|
|
//! __host__ __device__ __forceinline__ uint32_t operator()(uint32_t index)
|
|
//! {
|
|
//! return d_string_offsets[index + 1] - d_string_offsets[index];
|
|
//! }
|
|
//! uint32_t *d_string_offsets;
|
|
//! };
|
|
//!
|
|
//! uint32_t num_strings = 5;
|
|
//! char *d_string_data_in; // e.g., "TomatoesBananasApplesOrangesGrapes"
|
|
//! char *d_string_data_out; // e.g., " ... "
|
|
//! uint32_t *d_string_offsets_old; // e.g., [0, 8, 15, 21, 28, 34]
|
|
//! uint32_t *d_string_offsets_new; // e.g., [0, 6, 13, 19, 26, 34]
|
|
//! uint32_t *d_gather_index; // e.g., [2, 1, 4, 3, 0]
|
|
//!
|
|
//! // Initialize an iterator that returns d_gather_index[i] when the i-th item is dereferenced
|
|
//! auto gather_iterator = thrust::make_permutation_iterator(thrust::make_counting_iterator(0),
|
|
//! d_gather_index);
|
|
//!
|
|
//! // Returns pointers to the input buffer for each string
|
|
//! auto str_ptrs_in = thrust::make_transform_iterator(gather_iterator,
|
|
//! GetPtrToStringItem{d_string_data_in,
|
|
//! d_string_offsets_old});
|
|
//!
|
|
//! // Returns the string size of the i-th string
|
|
//! auto str_sizes = thrust::make_transform_iterator(gather_iterator,
|
|
//! GetStringItemSize{d_string_offsets_old});
|
|
//!
|
|
//! // Returns pointers to the output buffer for each string
|
|
//! auto str_ptrs_out = thrust::make_transform_iterator(thrust::make_counting_iterator(0),
|
|
//! GetPtrToStringItem{d_string_data_out,
|
|
//! d_string_offsets_new});
|
|
//!
|
|
//! // Determine temporary device storage requirements
|
|
//! void *d_temp_storage = nullptr;
|
|
//! size_t temp_storage_bytes = 0;
|
|
//! cub::DeviceMemcpy::Batched(d_temp_storage, temp_storage_bytes, str_ptrs_in, str_ptrs_out,
|
|
//! str_sizes, num_strings);
|
|
//!
|
|
//! // Allocate temporary storage
|
|
//! cudaMalloc(&d_temp_storage, temp_storage_bytes);
|
|
//!
|
|
//! // Run batched copy algorithm (used to permute strings)
|
|
//! cub::DeviceMemcpy::Batched(d_temp_storage, temp_storage_bytes, str_ptrs_in, str_ptrs_out,
|
|
//! str_sizes, num_strings);
|
|
//!
|
|
//! // d_string_data_out <-- "ApplesBananasGrapesOrangesTomatoe"
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam InputBufferIt
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the pointers to
|
|
//! the source memory buffers
|
|
//!
|
|
//! @tparam OutputBufferIt
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the pointers to
|
|
//! the destination memory buffers
|
|
//!
|
|
//! @tparam BufferSizeIteratorT
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the number of bytes
|
|
//! to be copied for each pair of buffers
|
|
//!
|
|
//! @param[in] d_temp_storage
|
|
//! @devicestorage
|
|
//!
|
|
//! @param[in,out] temp_storage_bytes
|
|
//! Reference to size in bytes of `d_temp_storage` allocation
|
|
//!
|
|
//! @param[in] input_buffer_it
|
|
//! Device-accessible iterator providing the pointers to the source memory buffers
|
|
//!
|
|
//! @param[in] output_buffer_it
|
|
//! Device-accessible iterator providing the pointers to the destination memory buffers
|
|
//!
|
|
//! @param[in] buffer_sizes
|
|
//! Device-accessible iterator providing the number of bytes to be copied for each pair of buffers
|
|
//!
|
|
//! @param[in] num_buffers
|
|
//! The total number of buffer pairs
|
|
//!
|
|
//! @param[in] stream
|
|
//! @rst
|
|
//! **[optional]** CUDA stream to launch kernels within. Default is stream\ :sub:`0`.
|
|
//! @endrst
|
|
template <typename InputBufferIt, typename OutputBufferIt, typename BufferSizeIteratorT>
|
|
CUB_RUNTIME_FUNCTION static cudaError_t Batched(
|
|
void* d_temp_storage,
|
|
size_t& temp_storage_bytes,
|
|
InputBufferIt input_buffer_it,
|
|
OutputBufferIt output_buffer_it,
|
|
BufferSizeIteratorT buffer_sizes,
|
|
::cuda::std::int64_t num_buffers,
|
|
cudaStream_t stream = nullptr)
|
|
{
|
|
_CCCL_NVTX_RANGE_SCOPE_IF(d_temp_storage, "cub::DeviceMemcpy::Batched");
|
|
static_assert(::cuda::std::is_pointer_v<cub::detail::it_value_t<InputBufferIt>>,
|
|
"DeviceMemcpy::Batched only supports copying of memory buffers."
|
|
"Please consider using DeviceCopy::Batched instead.");
|
|
static_assert(::cuda::std::is_pointer_v<cub::detail::it_value_t<OutputBufferIt>>,
|
|
"DeviceMemcpy::Batched only supports copying of memory buffers."
|
|
"Please consider using DeviceCopy::Batched instead.");
|
|
|
|
// Integer type large enough to hold any offset in [0, num_thread_blocks_launched), where a safe
|
|
// upper bound on num_thread_blocks_launched can be assumed to be given by
|
|
// IDIV_CEIL(num_buffers, 64)
|
|
using BlockOffsetT = uint32_t;
|
|
|
|
return detail::batch_memcpy::dispatch<CopyAlg::Memcpy, BlockOffsetT>(
|
|
d_temp_storage, temp_storage_bytes, input_buffer_it, output_buffer_it, buffer_sizes, num_buffers, stream);
|
|
}
|
|
|
|
//! @rst
|
|
//! Copies data from a batch of given source buffers to their corresponding destination buffer.
|
|
//!
|
|
//! .. versionadded:: 3.4.0
|
|
//! First appears in CUDA Toolkit 13.4.
|
|
//!
|
|
//! This is an environment-based API that allows customization of:
|
|
//!
|
|
//! - Stream: Query via ``cuda::get_stream``
|
|
//! - Memory resource: Query via ``cuda::mr::get_memory_resource``
|
|
//!
|
|
//! .. note::
|
|
//!
|
|
//! If any input buffer aliases memory from any output buffer the behavior is undefined.
|
|
//! If any output buffer aliases memory of another output buffer the behavior is undefined.
|
|
//! Input buffers can alias one another.
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates usage of DeviceMemcpy::Batched with an environment:
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/test/catch2_test_device_memcpy_env_api.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin memcpy-batched-env
|
|
//! :end-before: example-end memcpy-batched-env
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam InputBufferIt
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the pointers to
|
|
//! the source memory buffers
|
|
//!
|
|
//! @tparam OutputBufferIt
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the pointers to
|
|
//! the destination memory buffers
|
|
//!
|
|
//! @tparam BufferSizeIteratorT
|
|
//! **[inferred]** Device-accessible random-access input iterator type providing the number of bytes
|
|
//! to be copied for each pair of buffers
|
|
//!
|
|
//! @tparam EnvT
|
|
//! **[inferred]** Environment type (e.g., `cuda::std::execution::env<...>`)
|
|
//!
|
|
//! @param[in] input_buffer_it
|
|
//! Device-accessible iterator providing the pointers to the source memory buffers
|
|
//!
|
|
//! @param[in] output_buffer_it
|
|
//! Device-accessible iterator providing the pointers to the destination memory buffers
|
|
//!
|
|
//! @param[in] buffer_sizes
|
|
//! Device-accessible iterator providing the number of bytes to be copied for each pair of buffers
|
|
//!
|
|
//! @param[in] num_buffers
|
|
//! The total number of buffer pairs
|
|
//!
|
|
//! @param[in] env
|
|
//! @rst
|
|
//! **[optional]** Execution environment. Default is ``cuda::std::execution::env{}``.
|
|
//! @endrst
|
|
template <typename InputBufferIt,
|
|
typename OutputBufferIt,
|
|
typename BufferSizeIteratorT,
|
|
typename EnvT = ::cuda::std::execution::env<>,
|
|
::cuda::std::enable_if_t<!::cuda::std::is_same_v<InputBufferIt, void*>, int> = 0>
|
|
[[nodiscard]] CUB_RUNTIME_FUNCTION _CCCL_FORCEINLINE static cudaError_t
|
|
Batched(InputBufferIt input_buffer_it,
|
|
OutputBufferIt output_buffer_it,
|
|
BufferSizeIteratorT buffer_sizes,
|
|
::cuda::std::int64_t num_buffers,
|
|
const EnvT& env = {})
|
|
{
|
|
_CCCL_NVTX_RANGE_SCOPE("cub::DeviceMemcpy::Batched");
|
|
static_assert(::cuda::std::is_pointer_v<cub::detail::it_value_t<InputBufferIt>>,
|
|
"DeviceMemcpy::Batched only supports copying of memory buffers."
|
|
"Please consider using DeviceCopy::Batched instead.");
|
|
static_assert(::cuda::std::is_pointer_v<cub::detail::it_value_t<OutputBufferIt>>,
|
|
"DeviceMemcpy::Batched only supports copying of memory buffers."
|
|
"Please consider using DeviceCopy::Batched instead.");
|
|
|
|
using BlockOffsetT = uint32_t;
|
|
using default_policy_selector = detail::batch_memcpy::policy_selector;
|
|
|
|
return detail::dispatch_with_env_and_tuning<default_policy_selector>(
|
|
env, [&](auto policy_selector, void* storage, size_t& bytes, auto stream) {
|
|
return detail::batch_memcpy::dispatch<CopyAlg::Memcpy, BlockOffsetT>(
|
|
storage, bytes, input_buffer_it, output_buffer_it, buffer_sizes, num_buffers, stream, policy_selector);
|
|
});
|
|
}
|
|
};
|
|
|
|
CUB_NAMESPACE_END
|