Release v13.3 of the CUDA samples with CUDA 13.3 Toolkit (#435)

This is the release of the CUDA 13.3 samples, which include additions for CUDA Tile C++, and updated CCCL and Python samples.
This commit is contained in:
Dheemanth
2026-05-27 14:50:59 -07:00
committed by GitHub
parent aeab82ff30
commit b7c5481c55
150 changed files with 7977 additions and 246 deletions

View File

@@ -0,0 +1,92 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(libcuxxMdspan LANGUAGES C CXX CUDA)
# Disable response file for libraries on QNX as qcc does not support lib paths with double quotes
if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF)
endif()
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 89 90 100 110 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(ENABLE_CUDA_DEBUG)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif()
# Fetch CCCL (CUB + libcu++ + Thrust) via CPM. The toolkit that ships
# with CUDA 13.2 bundles CCCL 3.2, but this sample uses APIs added in
# CCCL 3.3. Pinning the tag here lets the sample build on any toolkit
# with a usable nvcc. Override with -DCCCL_SOURCE_DIR=/path/to/cccl
# to use a local checkout instead of fetching from GitHub.
set(CCCL_SAMPLES_CCCL_TAG "v3.3.3" CACHE STRING
"Tag/branch of NVIDIA/cccl to fetch for the CCCL samples")
if(NOT TARGET CCCL::CCCL)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CPM.cmake")
if(DEFINED CCCL_SOURCE_DIR AND NOT CCCL_SOURCE_DIR STREQUAL "")
CPMAddPackage(NAME CCCL SOURCE_DIR "${CCCL_SOURCE_DIR}")
else()
CPMAddPackage(
NAME CCCL
GIT_REPOSITORY "https://github.com/NVIDIA/cccl"
GIT_TAG "${CCCL_SAMPLES_CCCL_TAG}"
)
endif()
endif()
# DLPack headers are required for cuda::to_device_mdspan and
# cuda::to_dlpack_tensor. Fetch via CPM (override with DLPACK_SOURCE_DIR).
set(CCCL_SAMPLES_DLPACK_TAG "v1.3" CACHE STRING
"Tag of dmlc/dlpack to fetch for libcuxxMdspan")
if(NOT TARGET dlpack::dlpack)
if(NOT COMMAND CPMAddPackage)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CPM.cmake")
endif()
if(DEFINED DLPACK_SOURCE_DIR AND NOT DLPACK_SOURCE_DIR STREQUAL "")
CPMAddPackage(NAME dlpack SOURCE_DIR "${DLPACK_SOURCE_DIR}" DOWNLOAD_ONLY YES)
else()
CPMAddPackage(
NAME dlpack
GIT_REPOSITORY "https://github.com/dmlc/dlpack"
GIT_TAG "${CCCL_SAMPLES_DLPACK_TAG}"
DOWNLOAD_ONLY YES
)
endif()
if(dlpack_ADDED)
add_library(dlpack_headers INTERFACE)
target_include_directories(dlpack_headers INTERFACE "${dlpack_SOURCE_DIR}/include")
add_library(dlpack::dlpack ALIAS dlpack_headers)
endif()
endif()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for libcuxxMdspan
add_executable(libcuxxMdspan libcuxxMdspan.cu)
target_compile_options(libcuxxMdspan PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(libcuxxMdspan PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(libcuxxMdspan PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_link_libraries(libcuxxMdspan PRIVATE
CUDA::cudart
CCCL::CCCL
dlpack::dlpack
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@@ -0,0 +1,44 @@
# libcuxxMdspan - libcu++ mdspan Interop (DLPack + shared_memory_mdspan)
## Description
This sample demonstrates two mdspan-centric features CCCL: DLPack <-> `cuda::std::mdspan` bridging via `cuda::to_device_mdspan` / `cuda::to_dlpack_tensor` (the tensor-interchange protocol used by PyTorch, JAX, CuPy, and others), and `cuda::shared_memory_mdspan` for multi-dimensional views of shared-memory tiles with address-space-safe accessors. A small matrix is built, wrapped in a DLTensor, converted to a `device_mdspan`, scaled row-wise, and transposed through a `shared_memory_mdspan` tile. The output mdspan is converted back to DLPack and its metadata is printed.
## Key Concepts
CCCL 3.3, libcu++ mdspan, DLPack Interoperability, Shared Memory Views
## Supported SM Architectures
[SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus) [SM 10.0 ](https://developer.nvidia.com/cuda-gpus) [SM 11.0 ](https://developer.nvidia.com/cuda-gpus) [SM 12.0 ](https://developer.nvidia.com/cuda-gpus)
## Supported OSes
Linux, Windows
## Supported CPU Architecture
x86_64, aarch64
## CUDA APIs involved
### [CCCL libcu++](https://nvidia.github.io/cccl/libcudacxx/)
cuda::to_device_mdspan, cuda::to_dlpack_tensor, cuda::device_mdspan, cuda::shared_memory_mdspan, cuda::std::mdspan
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
cudaMalloc, cudaFree, cudaMemcpy, cudaMemset, cudaDeviceSynchronize, cudaGetDeviceProperties
## Dependencies needed to build/run
[CCCL 3.3+](https://github.com/NVIDIA/cccl), [DLPack 1.2+](https://github.com/dmlc/dlpack). Both fetched automatically via CPM at configure time (pinned to `v3.3.3` and `v1.3` respectively). Override with `-DCCCL_SOURCE_DIR=/path/to/cccl` and `-DDLPACK_SOURCE_DIR=/path/to/dlpack` to use local checkouts.
## Prerequisites
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)
[CCCL 3.3 release notes](https://github.com/NVIDIA/cccl/releases), [cuda::to_device_mdspan header](https://github.com/NVIDIA/cccl/blob/main/libcudacxx/include/cuda/__mdspan/dlpack_to_mdspan.h), [cuda::shared_memory_mdspan docs](https://nvidia.github.io/cccl/libcudacxx/extended_api/mdspan/shared_memory_accessor.html), [DLPack specification](https://dmlc.github.io/dlpack/latest/)

View File

@@ -0,0 +1,246 @@
/* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*
* 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 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 ``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.
*/
/* This sample demonstrates two mdspan-centric features from CCCL 3.3:
*
* 1. DLPack <-> cuda::std::mdspan bridging through
* cuda::to_device_mdspan<T, Rank>(DLTensor) -> cuda::device_mdspan
* cuda::to_dlpack_tensor(device_mdspan) -> DLManagedTensor
* The DLPack format is the interchange protocol used by PyTorch,
* JAX, CuPy, and other frameworks; cuda::device_mdspan is the
* device-side view with rich shape/stride metadata for kernels.
*
* 2. cuda::shared_memory_mdspan: a multi-dimensional view over a
* shared-memory tile. The accessor guarantees shared-memory
* load/store instructions and adds address-space safety checks.
*
* A sample matrix is built on the device, wrapped in a DLTensor,
* converted to a cuda::device_mdspan, and two kernels run against it:
* scale_rows_kernel multiplies row i by (i + 1), and
* shared_tile_transpose_kernel uses a cuda::shared_memory_mdspan to
* transpose a block-sized tile through shared memory. The output
* mdspan is then converted back to DLPack metadata and printed.
*/
/* Includes, system */
#include <stdio.h>
#include <stdlib.h>
#include <vector>
/* Includes, cuda */
#include <cuda_runtime.h>
#include <helper_cuda.h>
/* Includes, cccl */
#include <cuda/mdspan>
#include <cuda/std/array>
#include <cuda/std/cstdint>
#include <cuda/std/mdspan>
#define ROWS 8
#define COLS 8
#define TILE 8 /* matches ROWS / COLS for simplicity */
using extents2d = cuda::std::dextents<cuda::std::size_t, 2>;
/* Kernel A: multiply row i of a 2-D device_mdspan by (i + 1). Templated
* on the mdspan type so it accepts the exact type produced by
* cuda::to_device_mdspan (which uses layout_stride_relaxed and int64_t
* extents). */
template <typename Tensor>
__global__ void scale_rows_kernel(Tensor tensor)
{
const int r = blockIdx.y * blockDim.y + threadIdx.y;
const int c = blockIdx.x * blockDim.x + threadIdx.x;
if (r < static_cast<int>(tensor.extent(0)) && c < static_cast<int>(tensor.extent(1))) {
tensor(r, c) *= static_cast<float>(r + 1);
}
}
/* Kernel B: block-tile transpose driven by a shared_memory_mdspan.
* Each block loads a TILE x TILE tile from the input into shared memory
* through a cuda::shared_memory_mdspan, transposes in shared, and writes
* to the output. */
template <typename InTensor, typename OutTensor>
__global__ void shared_tile_transpose_kernel(InTensor in, OutTensor out)
{
__shared__ float smem_storage[TILE * TILE];
cuda::shared_memory_mdspan smem(smem_storage, cuda::std::dextents<cuda::std::size_t, 2>{TILE, TILE});
const int tr = threadIdx.y;
const int tc = threadIdx.x;
const int r = blockIdx.y * TILE + tr;
const int c = blockIdx.x * TILE + tc;
if (r < static_cast<int>(in.extent(0)) && c < static_cast<int>(in.extent(1))) {
smem(tr, tc) = in(r, c);
}
__syncthreads();
const int r_out = blockIdx.x * TILE + tr;
const int c_out = blockIdx.y * TILE + tc;
if (r_out < static_cast<int>(out.extent(0)) && c_out < static_cast<int>(out.extent(1))) {
out(r_out, c_out) = smem(tc, tr);
}
}
struct DLTensorStorage
{
::DLTensor tensor{};
cuda::std::array<cuda::std::int64_t, 2> shape{};
cuda::std::array<cuda::std::int64_t, 2> strides{};
};
static DLTensorStorage make_row_major_dltensor(float *device_ptr, int rows, int cols, int device_ordinal)
{
DLTensorStorage s;
s.shape = {rows, cols};
s.strides = {cols, 1};
s.tensor.data = device_ptr;
s.tensor.device = ::DLDevice{::kDLCUDA, device_ordinal};
s.tensor.ndim = 2;
s.tensor.dtype = ::DLDataType{::DLDataTypeCode::kDLFloat, 32, 1};
s.tensor.shape = s.shape.data();
s.tensor.strides = s.strides.data();
s.tensor.byte_offset = 0;
return s;
}
int main(int argc, char **argv)
{
int devID = findCudaDevice(argc, (const char **)argv);
cudaDeviceProp props;
checkCudaErrors(cudaGetDeviceProperties(&props, devID));
printf("Device: %s (Compute Capability %d.%d)\n\n", props.name, props.major, props.minor);
float *d_in = nullptr;
float *d_out = nullptr;
const size_t nelem = static_cast<size_t>(ROWS) * COLS;
checkCudaErrors(cudaMalloc(&d_in, nelem * sizeof(float)));
checkCudaErrors(cudaMalloc(&d_out, nelem * sizeof(float)));
std::vector<float> host(nelem);
for (int r = 0; r < ROWS; ++r) {
for (int c = 0; c < COLS; ++c) {
host[r * COLS + c] = static_cast<float>(r * COLS + c);
}
}
checkCudaErrors(cudaMemcpy(d_in, host.data(), nelem * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemset(d_out, 0, nelem * sizeof(float)));
DLTensorStorage in_dl = make_row_major_dltensor(d_in, ROWS, COLS, devID);
DLTensorStorage out_dl = make_row_major_dltensor(d_out, ROWS, COLS, devID);
auto in_md = cuda::to_device_mdspan<float, 2>(in_dl.tensor);
auto out_md = cuda::to_device_mdspan<float, 2>(out_dl.tensor);
printf("cuda::to_device_mdspan produced a 2-D device_mdspan of shape (%zu, %zu)\n\n",
in_md.extent(0),
in_md.extent(1));
dim3 block(8, 8);
dim3 grid((COLS + block.x - 1) / block.x, (ROWS + block.y - 1) / block.y);
scale_rows_kernel<<<grid, block>>>(in_md);
checkCudaErrors(cudaGetLastError());
checkCudaErrors(cudaDeviceSynchronize());
std::vector<float> scaled(nelem);
checkCudaErrors(cudaMemcpy(scaled.data(), d_in, nelem * sizeof(float), cudaMemcpyDeviceToHost));
bool scale_ok = true;
for (int r = 0; r < ROWS && scale_ok; ++r) {
for (int c = 0; c < COLS && scale_ok; ++c) {
const float expect = static_cast<float>((r * COLS + c) * (r + 1));
if (scaled[r * COLS + c] != expect) {
printf("scale_rows mismatch at (%d,%d): got %g expected %g\n",
r,
c,
scaled[r * COLS + c],
expect);
scale_ok = false;
}
}
}
if (scale_ok) {
printf("scale_rows kernel: OK (row i scaled by i+1 via cuda::device_mdspan)\n");
}
cuda::device_mdspan<const float, extents2d> in_md_const(d_in, extents2d{ROWS, COLS});
cuda::device_mdspan<float, extents2d> out_md_rw(d_out, extents2d{ROWS, COLS});
dim3 tile_block(TILE, TILE);
dim3 tile_grid((COLS + TILE - 1) / TILE, (ROWS + TILE - 1) / TILE);
shared_tile_transpose_kernel<<<tile_grid, tile_block>>>(in_md_const, out_md_rw);
checkCudaErrors(cudaGetLastError());
checkCudaErrors(cudaDeviceSynchronize());
std::vector<float> transposed(nelem);
checkCudaErrors(cudaMemcpy(transposed.data(), d_out, nelem * sizeof(float), cudaMemcpyDeviceToHost));
bool tp_ok = true;
for (int r = 0; r < ROWS && tp_ok; ++r) {
for (int c = 0; c < COLS && tp_ok; ++c) {
const float expect = scaled[c * COLS + r];
if (transposed[r * COLS + c] != expect) {
printf("transpose mismatch at (%d,%d): got %g expected %g\n",
r,
c,
transposed[r * COLS + c],
expect);
tp_ok = false;
}
}
}
if (tp_ok) {
printf("shared_tile_transpose kernel: OK (tile transpose via cuda::shared_memory_mdspan)\n");
}
auto dl_wrapper = cuda::to_dlpack_tensor(out_md);
const auto &dltensor = dl_wrapper.get();
printf("\ncuda::to_dlpack_tensor metadata:\n");
printf(" device : kDLCUDA (ordinal %d)\n", dltensor.device.device_id);
printf(" ndim : %d\n", dltensor.ndim);
printf(" dtype : code=%u bits=%u lanes=%u\n",
static_cast<unsigned>(dltensor.dtype.code),
static_cast<unsigned>(dltensor.dtype.bits),
static_cast<unsigned>(dltensor.dtype.lanes));
printf(" shape : [%lld, %lld]\n",
static_cast<long long>(dltensor.shape[0]),
static_cast<long long>(dltensor.shape[1]));
if (dltensor.strides != nullptr) {
printf(" strides : [%lld, %lld]\n",
static_cast<long long>(dltensor.strides[0]),
static_cast<long long>(dltensor.strides[1]));
}
checkCudaErrors(cudaFree(d_in));
checkCudaErrors(cudaFree(d_out));
if (!scale_ok || !tp_ok) {
return EXIT_FAILURE;
}
printf("\nDone\n");
return EXIT_SUCCESS;
}