CUDA 13.4 samples update - v13.4-public

Release 13.4 of the CUDA Samples supported by CUDA Toolkit 13.4.
See Changelog for more information.
This commit is contained in:
Dheemanth
2026-09-09 15:07:08 -07:00
committed by GitHub
parent b7c5481c55
commit 5443602d89
871 changed files with 6843 additions and 321849 deletions

View File

@@ -9,6 +9,7 @@ add_subdirectory(cdpSimplePrint)
add_subdirectory(cdpSimpleQuicksort)
add_subdirectory(cudaCompressibleMemory)
add_subdirectory(cudaTensorCoreGemm)
add_subdirectory(dmabufInterop)
add_subdirectory(dmmaTensorCoreGemm)
add_subdirectory(globalToShmemAsyncCopy)
add_subdirectory(graphConditionalNodes)
@@ -16,6 +17,8 @@ add_subdirectory(graphMemoryFootprint)
add_subdirectory(graphMemoryNodes)
add_subdirectory(immaTensorCoreGemm)
add_subdirectory(jacobiCudaGraphs)
add_subdirectory(localityDomains)
add_subdirectory(localityDomainsDrv)
add_subdirectory(memMapIPCDrv)
add_subdirectory(newdelete)
add_subdirectory(ptxjit)

View File

@@ -53,6 +53,12 @@ CUDA sample demonstrating a integer GEMM computation using the Warp Matrix Multi
### [jacobiCudaGraphs](./jacobiCudaGraphs)
Demonstrates Instantiated CUDA Graph Update with Jacobi Iterative Method using cudaGraphExecKernelNodeSetParams() and cudaGraphExecUpdate() approach.
### [localityDomains](./localityDomains)
This CUDA Runtime API sample demonstrates APIs for creating localized green contexts and localized memory pool allocations.
### [localityDomainsDrv](./localityDomainsDrv)
This CUDA Driver API sample demonstrates APIs for creating localized green contexts and creating localized memory allocations.
### [memMapIPCDrv](./memMapIPCDrv)
This CUDA Driver API sample is a very basic sample that demonstrates Inter Process Communication using cuMemMap APIs with one process per GPU for computation. Requires Compute Capability 3.0 or higher and a Linux Operating System, or a Windows Operating System

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,42 +1,30 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(StreamPriorities LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Source file
# Add target for StreamPriorities
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
message(STATUS "Will not build sample streamPriorities - not supported on aarch64")
else()
add_executable(StreamPriorities StreamPriorities.cu)
target_compile_options(StreamPriorities PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(StreamPriorities PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(StreamPriorities PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
include(InstallSamples)
setup_samples_install()
endif()
else()
message(STATUS "Will not build sample StreamPriorities - requires Linux OS")
endif()
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,21 +1,24 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(bf16TensorCoreGemm LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 89 90 100 110 120)
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()
# Include directories and libraries
include_directories(../../../Common)
# This sample is not supported on QNX
@@ -24,16 +27,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
return()
endif()
# Source file
# Add target for bf16TensorCoreGemm
add_executable(bf16TensorCoreGemm bf16TensorCoreGemm.cu)
target_compile_options(bf16TensorCoreGemm PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(bf16TensorCoreGemm PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(bf16TensorCoreGemm PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(binaryPartitionCG LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for binaryPartitionCG
add_executable(binaryPartitionCG binaryPartitionCG.cu)
target_compile_options(binaryPartitionCG PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(binaryPartitionCG PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(binaryPartitionCG PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,22 +1,18 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(bindlessTexture LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
if(WIN32)
@@ -33,49 +29,37 @@ endif()
find_package(OpenGL)
find_package(GLUT)
# Source file
if(${OpenGL_FOUND})
if (${GLUT_FOUND})
# Add target for bindlessTexture
add_executable(bindlessTexture bindlessTexture.cpp bindlessTexture_kernel.cu)
target_compile_options(bindlessTexture PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(bindlessTexture PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(bindlessTexture PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_compile_options(bindlessTexture PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(bindlessTexture PRIVATE cxx_std_17 cuda_std_17)
target_include_directories(bindlessTexture PUBLIC
${OPENGL_INCLUDE_DIR}
${CUDAToolkit_INCLUDE_DIRS}
${GLUT_INCLUDE_DIRS}
)
target_link_libraries(bindlessTexture
${OPENGL_LIBRARIES}
${GLUT_LIBRARIES}
)
# Copy clock_kernel.cu to the output directory
add_custom_command(TARGET bindlessTexture POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/data
${CMAKE_CURRENT_BINARY_DIR}/data
)
if(WIN32)
target_link_libraries(bindlessTexture
${PC_GLUT_LIBRARY_DIRS}/freeglut.lib
${PC_GLUT_LIBRARY_DIRS}/${GLEW_LIB_NAME}.lib
)
add_custom_command(TARGET bindlessTexture
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/win64/$<CONFIGURATION>/freeglut.dll
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>
)
add_custom_command(TARGET bindlessTexture
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
@@ -83,14 +67,11 @@ target_compile_features(bindlessTexture PRIVATE cxx_std_17 cuda_std_17)
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>
)
endif()
include(InstallSamples)
setup_samples_install()
else()
message(STATUS "GLUT not found - will not build sample 'bindlessTexture'")
endif()
else()
message(STATUS "OpenGL not found - will not build sample 'bindlessTexture'")
endif()
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,36 +1,28 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
# CDP device-links the CUDA device runtime (cudadevrt), which the DriveOS Tegra
# toolkit ships only for the native Tegra archs; drop the desktop archs there.
get_filename_component(_ctk_root "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(_ctk_root "${_ctk_root}" DIRECTORY)
if(EXISTS "${_ctk_root}/targets/aarch64-linux" OR EXISTS "${_ctk_root}/targets/aarch64-qnx")
set(SAMPLE_DISALLOW_ARCHS 75 80 86 89 90 100 103 107 120)
endif()
unset(_ctk_root)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cdpAdvancedQuicksort LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# The aarch64/sbsa_aarch64 CUDA toolkit are support on Tegra since 13.0, so need to check which version of the toolkit is installed
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-linux" _aarch64_linux_ctk)
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-qnx" _aarch64_qnx_ctk)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND (NOT _aarch64_linux_ctk EQUAL -1 OR NOT _aarch64_qnx_ctk EQUAL -1))
set(CMAKE_CUDA_ARCHITECTURES 87 110)
else()
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 110 120)
endif()
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)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -maxrregcount=64") # Limit register usage to 64 for the 'big_bitonicsort kernel
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cdpAdvancedQuicksort
add_executable(cdpAdvancedQuicksort cdpAdvancedQuicksort.cu cdpBitonicSort.cu)
target_compile_options(cdpAdvancedQuicksort PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@@ -39,6 +31,5 @@ target_compile_features(cdpAdvancedQuicksort PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cdpAdvancedQuicksort PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -137,7 +137,9 @@ template <typename T> static __device__ void ringbufFree(qsortRingbuf *ringbuf,
// and cover the instruction overhead.
//
////////////////////////////////////////////////////////////////////////////////
__global__ void qsort_warp(unsigned *indata,
// __launch_bounds__ caps registers to the launch block size so -G (device-debug) builds stay
// within the per-block register limit (big register usage under -G overflows it on Blackwell sm_110+).
__launch_bounds__(QSORT_BLOCKSIZE) __global__ void qsort_warp(unsigned *indata,
unsigned *outdata,
unsigned int offset,
unsigned int len,

View File

@@ -272,14 +272,16 @@ static __device__ __forceinline__ void big_bitonicsort_kernel(unsigned *i
// KERNELS
////////////////////////////////////////////////////////////////////////////////
__global__ void bitonicsort(unsigned *indata, unsigned *outdata, unsigned int offset, unsigned int len)
// __launch_bounds__ caps registers to the launch block size so -G builds stay within the per-block register limit (Blackwell sm_110+).
__launch_bounds__(BITONICSORT_LEN) __global__ void bitonicsort(unsigned *indata, unsigned *outdata, unsigned int offset, unsigned int len)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
bitonicsort_kernel(indata, outdata, offset, len, cta);
}
__global__ void
// __launch_bounds__ caps registers to the launch block size so -G builds stay within the per-block register limit (Blackwell sm_110+).
__launch_bounds__(BITONICSORT_LEN) __global__ void
big_bitonicsort(unsigned *indata, unsigned *outdata, unsigned *backbuf, unsigned int offset, unsigned int len)
{
// Handle to thread block group

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,28 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
# CDP device-links the CUDA device runtime (cudadevrt), which the DriveOS Tegra
# toolkit ships only for the native Tegra archs; drop the desktop archs there.
get_filename_component(_ctk_root "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(_ctk_root "${_ctk_root}" DIRECTORY)
if(EXISTS "${_ctk_root}/targets/aarch64-linux" OR EXISTS "${_ctk_root}/targets/aarch64-qnx")
set(SAMPLE_DISALLOW_ARCHS 75 80 86 89 90 100 103 107 120)
endif()
unset(_ctk_root)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cdpBezierTessellation LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# The aarch64/sbsa_aarch64 CUDA toolkit are support on Tegra since 13.0, so need to check which version of the toolkit is installed
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-linux" _aarch64_linux_ctk)
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-qnx" _aarch64_qnx_ctk)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND (NOT _aarch64_linux_ctk EQUAL -1 OR NOT _aarch64_qnx_ctk EQUAL -1))
set(CMAKE_CUDA_ARCHITECTURES 87 110)
else()
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 110 120)
endif()
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cdpBezierTessellation
add_executable(cdpBezierTessellation BezierLineCDP.cu)
target_compile_options(cdpBezierTessellation PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@@ -38,6 +31,5 @@ target_compile_features(cdpBezierTessellation PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cdpBezierTessellation PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,28 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
# CDP device-links the CUDA device runtime (cudadevrt), which the DriveOS Tegra
# toolkit ships only for the native Tegra archs; drop the desktop archs there.
get_filename_component(_ctk_root "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(_ctk_root "${_ctk_root}" DIRECTORY)
if(EXISTS "${_ctk_root}/targets/aarch64-linux" OR EXISTS "${_ctk_root}/targets/aarch64-qnx")
set(SAMPLE_DISALLOW_ARCHS 75 80 86 89 90 100 103 107 120)
endif()
unset(_ctk_root)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cdpQuadtree LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# The aarch64/sbsa_aarch64 CUDA toolkit are support on Tegra since 13.0, so need to check which version of the toolkit is installed
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-linux" _aarch64_linux_ctk)
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-qnx" _aarch64_qnx_ctk)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND (NOT _aarch64_linux_ctk EQUAL -1 OR NOT _aarch64_qnx_ctk EQUAL -1))
set(CMAKE_CUDA_ARCHITECTURES 87 110)
else()
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 110 120)
endif()
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cdpQuadtree
add_executable(cdpQuadtree cdpQuadtree.cu)
target_compile_options(cdpQuadtree PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@@ -38,6 +31,5 @@ target_compile_features(cdpQuadtree PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cdpQuadtree PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -25,6 +25,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include <cooperative_groups.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,28 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
# CDP device-links the CUDA device runtime (cudadevrt), which the DriveOS Tegra
# toolkit ships only for the native Tegra archs; drop the desktop archs there.
get_filename_component(_ctk_root "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(_ctk_root "${_ctk_root}" DIRECTORY)
if(EXISTS "${_ctk_root}/targets/aarch64-linux" OR EXISTS "${_ctk_root}/targets/aarch64-qnx")
set(SAMPLE_DISALLOW_ARCHS 75 80 86 89 90 100 103 107 120)
endif()
unset(_ctk_root)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cdpSimplePrint LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# The aarch64/sbsa_aarch64 CUDA toolkit are support on Tegra since 13.0, so need to check which version of the toolkit is installed
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-linux" _aarch64_linux_ctk)
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-qnx" _aarch64_qnx_ctk)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND (NOT _aarch64_linux_ctk EQUAL -1 OR NOT _aarch64_qnx_ctk EQUAL -1))
set(CMAKE_CUDA_ARCHITECTURES 87 110)
else()
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 110 120)
endif()
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cdpSimplePrint
add_executable(cdpSimplePrint cdpSimplePrint.cu)
target_compile_options(cdpSimplePrint PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@@ -38,6 +31,5 @@ target_compile_features(cdpSimplePrint PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cdpSimplePrint PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,28 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
# CDP device-links the CUDA device runtime (cudadevrt), which the DriveOS Tegra
# toolkit ships only for the native Tegra archs; drop the desktop archs there.
get_filename_component(_ctk_root "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(_ctk_root "${_ctk_root}" DIRECTORY)
if(EXISTS "${_ctk_root}/targets/aarch64-linux" OR EXISTS "${_ctk_root}/targets/aarch64-qnx")
set(SAMPLE_DISALLOW_ARCHS 75 80 86 89 90 100 103 107 120)
endif()
unset(_ctk_root)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cdpSimpleQuicksort LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# The aarch64/sbsa_aarch64 CUDA toolkit are support on Tegra since 13.0, so need to check which version of the toolkit is installed
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-linux" _aarch64_linux_ctk)
string(FIND "${CUDAToolkit_INCLUDE_DIRS}" "aarch64-qnx" _aarch64_qnx_ctk)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND (NOT _aarch64_linux_ctk EQUAL -1 OR NOT _aarch64_qnx_ctk EQUAL -1))
set(CMAKE_CUDA_ARCHITECTURES 87 110)
else()
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 110 120)
endif()
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cdpSimpleQuicksort
add_executable(cdpSimpleQuicksort cdpSimpleQuicksort.cu)
target_compile_options(cdpSimpleQuicksort PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@@ -38,6 +31,5 @@ target_compile_features(cdpSimpleQuicksort PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cdpSimpleQuicksort PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,26 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cudaCompressibleMemory LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cudaCompressibleMemory
add_executable(cudaCompressibleMemory compMalloc.cpp saxpy.cu)
target_compile_options(cudaCompressibleMemory PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(cudaCompressibleMemory PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cudaCompressibleMemory PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(cudaCompressibleMemory PRIVATE
${CUDAToolkit_INCLUDE_DIRS}
)
@@ -37,6 +29,5 @@ target_link_libraries(cudaCompressibleMemory PRIVATE
CUDA::cuda_driver
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(cudaTensorCoreGemm LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for cudaTensorCoreGemm
add_executable(cudaTensorCoreGemm cudaTensorCoreGemm.cu)
target_compile_options(cudaTensorCoreGemm PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(cudaTensorCoreGemm PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cudaTensorCoreGemm PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.20)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(dmabufInterop LANGUAGES C CXX CUDA)
# dma-buf is a Linux-only kernel facility. Skip the sample on all other platforms.
if(NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
message(STATUS "Skipping dmabufInterop: requires Linux (dma-buf is Linux-only). "
"Found ${CMAKE_SYSTEM_NAME}.")
return()
endif()
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
include_directories(../../../Common)
add_executable(dmabufInterop dmabufInterop.cu)
target_compile_options(dmabufInterop PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(dmabufInterop PRIVATE cxx_std_17 cuda_std_17)
target_link_libraries(dmabufInterop PRIVATE
CUDA::cuda_driver
CUDA::cudart
)
include(InstallSamples)
setup_samples_install()

View File

@@ -0,0 +1,124 @@
# Sample: CUDA dma-buf Interoperability
## Description
Linux **dma-buf** is the kernel's standard mechanism for sharing a buffer between subsystems by representing it as a file descriptor. This sample shows CUDA acting as both a dma-buf **producer** (taking one of its own allocations and obtaining a dma-buf fd for it with `cuMemGetHandleForAddressRange`) and a dma-buf **consumer** (taking an existing dma-buf fd and turning it into a CUDA-mappable buffer with `cuImportExternalMemory` + `cuExternalMemoryGetMappedBuffer`). A single binary runs three demos in sequence:
1. **Same-process round-trip** — one CUDA context exports a host allocation and imports it back as external memory.
2. **Cross-process IPC** — a `fork()`-ed child exports an allocation and passes the fd to the parent over a Unix domain socket using `SCM_RIGHTS`.
3. **Cross-GPU sharing across processes** — the same `fork()` + `SCM_RIGHTS` path as demo 2, but the producer child runs on one GPU and the consumer parent imports the fd into a different GPU's context. The sample auto-detects any pair of GPUs whose driver reports support for the dma-buf capability attributes. This demo self-skips when no qualifying pair is present.
Producer-side allocations always use `cuMemAllocHost`; using a single allocator keeps the producer code identical across all three demos.
## What You'll Learn
- Exporting a CUDA host allocation as a Linux dma-buf file descriptor
- Importing a dma-buf fd into CUDA as external memory and mapping it to a device pointer
- Passing a dma-buf fd between processes via a Unix-domain socket using `SCM_RIGHTS`
- Sharing a single buffer between two GPUs in two different processes, with the producer-completes-before-consumer-reads ordering enforced by the existing fork + socket handshake
- Detecting dma-buf platform support at runtime with CUDA device attributes
- Coordinating fork()ed children so output and CUDA work appear in source order rather than the order processes happen to be scheduled
## Key Concepts
- **dma-buf** — kernel-side shareable buffer represented as a file descriptor; usable across CUDA, V4L2, DRM/KMS, Vulkan, and any other subsystem that speaks dma-buf
- **Page-aligned export** — `cuMemGetHandleForAddressRange` requires a page-aligned base, so the producer over-allocates by one page and rounds up
- **fd as IPC primitive** — once CUDA has produced a dma-buf fd, the fd is just a POSIX file descriptor and can be sent across `fork()` boundaries via `SCM_RIGHTS`
- **Capability-gated execution** — `CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED` (producer side) and `CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED` (consumer side) determine which paths run on the current hardware
- **Parent-arbitrated synchronisation** — both fork()ed children block on a one-byte "go" from the parent before doing any CUDA work, so output across the three demos appears in source order even when stdout is fully buffered (e.g., over ssh)
## Key APIs
### CUDA Driver API
- `cuMemAllocHost` — allocate page-locked host memory that is also a valid CUDA device pointer
- `cuMemGetHandleForAddressRange` (with `CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD`) — export a CUDA allocation as a Linux dma-buf fd
- `cuImportExternalMemory` (with `CU_EXTERNAL_MEMORY_HANDLE_TYPE_DMABUF_FD`) — bring a dma-buf fd into CUDA as external memory
- `cuExternalMemoryGetMappedBuffer` — obtain a `CUdeviceptr` from an imported external memory object
- `cuDeviceGetAttribute` — runtime capability query for `CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED` and `CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED`
### CUDA Runtime API
- `cudaSetDevice` — pin the runtime to the producer GPU (child process) or the consumer GPU (parent process); both demos that use multiple GPUs do this on each side after the fork
- `cudaGetDeviceCount` — used inside the cross-GPU pair detection to enumerate the available GPUs
- `cudaDeviceSynchronize` — used on the producer side to make sure the kernel that wrote the buffer has retired before the fd is sent to the consumer
### Linux / POSIX
- `socketpair` + `fork` + `sendmsg`/`recvmsg` with `SCM_RIGHTS` — pass a file descriptor between processes
## Requirements
### Hardware
- An NVIDIA GPU whose `CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED` is `1`. The sample queries this at startup and skips entirely on unsupported devices.
- The cross-GPU section additionally needs at least two GPUs in the system, with one reporting `CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED = 1` (producer) and the other reporting `CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED = 1` (consumer). On systems without a qualifying pair the cross-GPU section prints a skip message and the sample continues.
### Software
- CUDA Toolkit 13.4 or newer
- CMake 3.20 or newer
- Linux. dma-buf is a Linux kernel facility; this sample does not build on Windows or QNX.
## How to Build
See the [top-level README](../../../README.md#building-cuda-samples) for full build instructions, including how to build all samples or a single sample standalone.
## How to Run
The sample takes no arguments:
```bash
./dmabufInterop
```
All three sections run in sequence. The cross-GPU section self-skips when the running system has no qualifying GPU pair, so the same binary is appropriate for a single-GPU workstation, a multi-GPU server, or a heterogeneous-GPU platform.
## Expected Output
On a system with a single discrete GPU (the cross-GPU section self-skips):
```text
Device 0: <GPU name> (Compute Capability X.Y)
Same-process round-trip
producer: allocated 16384 bytes, exported as dma-buf fd 45
producer: wrote pattern
consumer: imported dma-buf as device pointer
consumer: verified (0 mismatches)
Cross-process IPC (fork + SCM_RIGHTS)
child: allocated 16384 bytes, exported as dma-buf fd 45
child: wrote pattern
child: sent fd to parent
parent: received dma-buf fd 45 from child
parent: imported dma-buf as device pointer
parent: verified (0 mismatches)
Cross-GPU sharing across processes
no GPU pair satisfies the dma-buf capability attributes. Skipping.
Done
```
On a system with two or more dma-buf-capable GPUs, the cross-GPU section runs to completion:
```text
Cross-GPU sharing across processes
child: on device 1, allocated 16384 bytes, exported as dma-buf fd 53
child: wrote pattern
child: sent fd to parent
parent: on device 0, received dma-buf fd 4 from child
parent: imported dma-buf as device pointer
parent: verified (0 mismatches)
```
If a verification kernel reports any mismatches, the corresponding line ends with `Error (N mismatches)` and the sample exits with a non-zero status.
## Files
- `dmabufInterop.cu` — kernels, CUDA export/import helpers, and the three demo functions. Reading this file end-to-end gives the full CUDA dma-buf flow without needing to open anything else.
- `dmabufInterop_helpers.h` — POSIX-only helpers used by the cross-process demos: `sendFd` / `recvFd` for `SCM_RIGHTS`-based file-descriptor passing, and `reapCrossProcessChild` (a `waitpid` wrapper). Split out so the main `.cu` stays focused on CUDA; open this file only if you want to see the SCM_RIGHTS mechanics.
- `README.md` — this file
- `CMakeLists.txt` — build configuration (Linux-only guard, CUDA driver + runtime link)
## See Also
- [Linux kernel dma-buf documentation](https://docs.kernel.org/driver-api/dma-buf.html)
- [CUDA External Resource Interoperability](https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXTRES__INTEROP.html)
- [`cuMemGetHandleForAddressRange`](https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html)

View File

@@ -0,0 +1,507 @@
/* Copyright (c) 2026, 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.
*/
/**
* CUDA dma-buf interoperability.
*
* Three demos exercise CUDA's ability to export a host allocation as a Linux
* dma-buf file descriptor and to import a dma-buf fd back as a CUDA-mappable
* buffer: (1) same-process round-trip, (2) cross-process IPC via fork() and
* SCM_RIGHTS with both sides on one GPU, and (3) cross-GPU sharing across
* processes -- the same fork+SCM_RIGHTS path as demo 2, but the producer
* child runs on one GPU and the consumer parent imports the fd into a
* different GPU's context. Demo 3 self-skips when the system does not have
* two GPUs that satisfy the dma-buf capability attributes.
*
* Producer allocations are always pinned host memory; using a single
* allocator keeps the producer path identical across all three demos.
*
* See README.md for build instructions, expected output, and the full list
* of APIs the sample exercises.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include "dmabufInterop_helpers.h"
#define NUM_ELEMENTS 4096
#define BLOCK_SIZE 256
#define PATTERN_BASE 0x1000
/* Kernel: writes ptr[i] = base + i. */
__global__ void writePatternKernel(int *ptr, int base, int count)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < count) {
ptr[idx] = base + idx;
}
}
/* Kernel: counts elements that do not match base + i. */
__global__ void verifyPatternKernel(int *ptr, int base, int count, int *errors)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < count) {
if (ptr[idx] != base + idx) {
atomicAdd(errors, 1);
}
}
}
/* Align v up to the next multiple of a. */
static size_t alignUp(size_t v, size_t a)
{
size_t r = v % a;
return (r == 0) ? v : v + (a - r);
}
/* Result of a producer-side export: the allocation base (for cuMemFreeHost),
* the page-aligned pointer usable as both host and device pointer, the
* dma-buf fd, and the aligned size. */
struct DmabufExport
{
void *allocBase;
void *alignedPtr;
int fd;
size_t size;
};
/* Allocate page-aligned pinned host memory and export it as a dma-buf fd.
* cuMemGetHandleForAddressRange requires a page-aligned base, so we allocate
* an extra page of headroom and round up. */
static DmabufExport exportHostAllocAsDmabuf(size_t size)
{
long pageSize = sysconf(_SC_PAGESIZE);
DmabufExport e = {};
e.size = alignUp(size, (size_t)pageSize);
cuMemAllocHost(&e.allocBase, e.size + (size_t)pageSize);
e.alignedPtr = (void *)alignUp((size_t)e.allocBase, (size_t)pageSize);
cuMemGetHandleForAddressRange(&e.fd,
(CUdeviceptr)e.alignedPtr,
e.size,
CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD,
0ULL);
return e;
}
/* Import a dma-buf fd into the current CUDA context and obtain a CUdeviceptr
* that kernels can read and write. */
static void importDmabuf(int fd, size_t size, CUexternalMemory *outExtMem, CUdeviceptr *outDevPtr)
{
CUDA_EXTERNAL_MEMORY_HANDLE_DESC memDesc = {};
memDesc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_DMABUF_FD;
memDesc.handle.fd = fd;
memDesc.size = size;
cuImportExternalMemory(outExtMem, &memDesc);
CUDA_EXTERNAL_MEMORY_BUFFER_DESC bufDesc = {};
bufDesc.size = size;
cuExternalMemoryGetMappedBuffer(outDevPtr, *outExtMem, &bufDesc);
}
/* Same-process round-trip: one context exports a host allocation as a
* dma-buf fd and imports it back. Producer writes the pattern; consumer
* reads via the imported mapping and verifies. */
static int runSameProcess(int device)
{
cudaSetDevice(device);
DmabufExport e = exportHostAllocAsDmabuf(NUM_ELEMENTS * sizeof(int));
printf(" producer: allocated %zu bytes, exported as dma-buf fd %d\n", e.size, e.fd);
int blocks = (NUM_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
writePatternKernel<<<blocks, BLOCK_SIZE>>>((int *)e.alignedPtr, PATTERN_BASE, NUM_ELEMENTS);
cudaDeviceSynchronize();
printf(" producer: wrote pattern\n");
CUexternalMemory extMem = NULL;
CUdeviceptr importedPtr = 0;
importDmabuf(e.fd, e.size, &extMem, &importedPtr);
printf(" consumer: imported dma-buf as device pointer\n");
int *errors = NULL;
cudaMallocHost(&errors, sizeof(int));
*errors = 0;
verifyPatternKernel<<<blocks, BLOCK_SIZE>>>(
(int *)importedPtr, PATTERN_BASE, NUM_ELEMENTS, errors);
cudaDeviceSynchronize();
int rc = (*errors == 0) ? 0 : -1;
printf(" consumer: %s (%d mismatches)\n", rc == 0 ? "verified" : "Error", *errors);
/* Free up resources. */
cudaFreeHost(errors);
cuDestroyExternalMemory(extMem);
close(e.fd);
cuMemFreeHost(e.allocBase);
return rc;
}
/* Cross-process child: producer. Allocates, exports, writes the pattern,
* sends the fd to the parent, waits for a one-byte ack so it does not free
* the underlying memory before the parent finishes reading.
*
* The child waits for a one-byte "go" from the parent before doing any
* CUDA work, so that the parent can serialise output across the same-process
* demo and the two cross-process demos. If the parent closes the socket
* without writing (because some upstream gate failed), the child exits
* cleanly. */
static int runCrossProcessChild(int device, int sock)
{
cuInit(0);
cudaSetDevice(device);
char go = 0;
if (read(sock, &go, 1) <= 0) return 0;
DmabufExport e = exportHostAllocAsDmabuf(NUM_ELEMENTS * sizeof(int));
printf(" child: allocated %zu bytes, exported as dma-buf fd %d\n", e.size, e.fd);
int blocks = (NUM_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
writePatternKernel<<<blocks, BLOCK_SIZE>>>((int *)e.alignedPtr, PATTERN_BASE, NUM_ELEMENTS);
cudaDeviceSynchronize();
printf(" child: wrote pattern\n");
sendFd(sock, e.fd);
printf(" child: sent fd to parent\n");
char ack = 0;
[[maybe_unused]] ssize_t r = read(sock, &ack, 1);
/* Free up resources. */
close(e.fd);
cuMemFreeHost(e.allocBase);
return 0;
}
/* Cross-process parent: consumer. Signals the child to start producing,
* receives the fd, imports it, verifies the pattern, and acks the child so
* it can clean up. */
static int runCrossProcessParent(int device, int sock)
{
cudaSetDevice(device);
char go = 'G';
[[maybe_unused]] ssize_t r_go = write(sock, &go, 1);
/* fd is the dma-buf that the producer child just wrote to; it refers to
* the same underlying memory the child exported, just a different fd
* number in this process. */
int fd = recvFd(sock);
printf(" parent: received dma-buf fd %d from child\n", fd);
const size_t size = alignUp(NUM_ELEMENTS * sizeof(int), (size_t)sysconf(_SC_PAGESIZE));
CUexternalMemory extMem = NULL;
CUdeviceptr importedPtr = 0;
importDmabuf(fd, size, &extMem, &importedPtr);
printf(" parent: imported dma-buf as device pointer\n");
int *errors = NULL;
cudaMallocHost(&errors, sizeof(int));
*errors = 0;
int blocks = (NUM_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
verifyPatternKernel<<<blocks, BLOCK_SIZE>>>(
(int *)importedPtr, PATTERN_BASE, NUM_ELEMENTS, errors);
cudaDeviceSynchronize();
int rc = (*errors == 0) ? 0 : -1;
printf(" parent: %s (%d mismatches)\n", rc == 0 ? "verified" : "Error", *errors);
char ack = 'A';
[[maybe_unused]] ssize_t r_ack = write(sock, &ack, 1);
/* Free up resources. */
cudaFreeHost(errors);
cuDestroyExternalMemory(extMem);
close(fd);
return rc;
}
/* Cross-process orchestration. The fork() must happen BEFORE either side
* calls cuInit: the CUDA driver does not survive fork-after-init, so child
* and parent each initialise CUDA independently after the fork. main()
* spawns the child here and drives the parent side later. */
static pid_t spawnCrossProcessChild(int device, int *outParentSocket)
{
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
perror("socketpair");
return -1;
}
/* Flush stdio before fork() so the child does not inherit a buffer that
* would then be flushed twice. */
fflush(stdout);
fflush(stderr);
pid_t pid = fork();
if (pid < 0) {
perror("fork");
close(sockets[0]);
close(sockets[1]);
return -1;
}
if (pid == 0) {
close(sockets[1]);
int rc = runCrossProcessChild(device, sockets[0]);
close(sockets[0]);
fflush(stdout);
fflush(stderr);
_exit(rc == 0 ? 0 : 1);
}
close(sockets[0]);
*outParentSocket = sockets[1];
return pid;
}
/* Find any pair of GPUs where one supports producing a dma-buf fd from a
* host allocation and the other supports importing a dma-buf fd. Iteration
* is device-order so the result is deterministic -- child and parent each
* call this independently after the fork and arrive at the same (producer,
* consumer) pair. Both outputs are -1 if no qualifying pair is present. */
static void findCrossGpuPair(int *outProducer, int *outConsumer)
{
*outProducer = -1;
*outConsumer = -1;
int deviceCount = 0;
cudaGetDeviceCount(&deviceCount);
if (deviceCount < 2) return;
for (int p = 0; p < deviceCount; ++p) {
int hostAllocOk = 0;
cuDeviceGetAttribute(&hostAllocOk,
CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED, p);
if (!hostAllocOk) continue;
for (int c = 0; c < deviceCount; ++c) {
if (c == p) continue;
int importOk = 0;
cuDeviceGetAttribute(&importOk,
CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED, c);
if (importOk) { *outProducer = p; *outConsumer = c; return; }
}
}
}
/* Cross-GPU cross-process child: producer on the discovered producer GPU.
* Mirrors runCrossProcessChild but runs on a specific device chosen by
* findCrossGpuPair. The parent is the arbiter for skip decisions: child
* waits for a "go" byte from the parent (or an EOF if the parent decided
* to skip the demo) before allocating anything. */
static int runCrossProcCrossGpuChild(int sock)
{
cuInit(0);
char go = 0;
if (read(sock, &go, 1) <= 0) return 0;
int producer = -1, consumer = -1;
findCrossGpuPair(&producer, &consumer);
if (producer < 0) return 0;
cudaSetDevice(producer);
DmabufExport e = exportHostAllocAsDmabuf(NUM_ELEMENTS * sizeof(int));
printf(" child: on device %d, allocated %zu bytes, exported as dma-buf fd %d\n",
producer, e.size, e.fd);
int blocks = (NUM_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
writePatternKernel<<<blocks, BLOCK_SIZE>>>((int *)e.alignedPtr, PATTERN_BASE, NUM_ELEMENTS);
cudaDeviceSynchronize();
printf(" child: wrote pattern\n");
sendFd(sock, e.fd);
printf(" child: sent fd to parent\n");
char ack = 0;
[[maybe_unused]] ssize_t r = read(sock, &ack, 1);
/* Free up resources. */
close(e.fd);
cuMemFreeHost(e.allocBase);
return 0;
}
/* Cross-GPU cross-process parent: consumer on the discovered consumer GPU.
* Decides whether the demo proceeds: signals "go" to the child if a
* qualifying pair exists, otherwise prints a skip message and returns
* (closing the socket without writing, which the child sees as EOF). */
static int runCrossProcCrossGpuParent(int sock)
{
int producer = -1, consumer = -1;
findCrossGpuPair(&producer, &consumer);
if (producer < 0) {
printf(" no GPU pair satisfies the dma-buf capability attributes. Skipping.\n");
return 0;
}
cudaSetDevice(consumer);
char go = 'G';
[[maybe_unused]] ssize_t r_go = write(sock, &go, 1);
/* fd is the dma-buf that the producer child just wrote to on its own GPU;
* import it into this parent's context on the consumer GPU below to
* access the same underlying memory. */
int fd = recvFd(sock);
printf(" parent: on device %d, received dma-buf fd %d from child\n", consumer, fd);
const size_t size = alignUp(NUM_ELEMENTS * sizeof(int), (size_t)sysconf(_SC_PAGESIZE));
CUexternalMemory extMem = NULL;
CUdeviceptr importedPtr = 0;
importDmabuf(fd, size, &extMem, &importedPtr);
printf(" parent: imported dma-buf as device pointer\n");
int *errors = NULL;
cudaMallocHost(&errors, sizeof(int));
*errors = 0;
int blocks = (NUM_ELEMENTS + BLOCK_SIZE - 1) / BLOCK_SIZE;
verifyPatternKernel<<<blocks, BLOCK_SIZE>>>(
(int *)importedPtr, PATTERN_BASE, NUM_ELEMENTS, errors);
cudaDeviceSynchronize();
int rc = (*errors == 0) ? 0 : -1;
printf(" parent: %s (%d mismatches)\n", rc == 0 ? "verified" : "Error", *errors);
char ack = 'A';
[[maybe_unused]] ssize_t r_ack = write(sock, &ack, 1);
/* Free up resources. */
cudaFreeHost(errors);
cuDestroyExternalMemory(extMem);
close(fd);
return rc;
}
/* Cross-GPU cross-process orchestration: spawn the producer child the same
* way as spawnCrossProcessChild. Like the single-GPU IPC demo, this fork
* must happen before any cuInit in the parent process. */
static pid_t spawnCrossProcCrossGpuChild(int *outParentSocket)
{
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
perror("socketpair");
return -1;
}
fflush(stdout);
fflush(stderr);
pid_t pid = fork();
if (pid < 0) {
perror("fork");
close(sockets[0]);
close(sockets[1]);
return -1;
}
if (pid == 0) {
close(sockets[1]);
int rc = runCrossProcCrossGpuChild(sockets[0]);
close(sockets[0]);
fflush(stdout);
fflush(stderr);
_exit(rc == 0 ? 0 : 1);
}
close(sockets[0]);
*outParentSocket = sockets[1];
return pid;
}
int main()
{
/* Make stdout line-buffered so printf output from the parent and the
* fork()ed children appears in temporal order even when stdout is
* redirected to a pipe (e.g. via ssh) rather than a terminal. */
setvbuf(stdout, NULL, _IOLBF, 0);
const int device = 0;
/* Spawn both children before any cuInit in this process. Each child runs
* a producer-side role and blocks waiting for its parent to drive the
* import. fork() must precede cuInit -- the CUDA driver does not survive
* fork-after-init, so each child does its own cuInit independently. */
int sockIpc = -1, sockCrossGpu = -1;
pid_t childIpcPid = spawnCrossProcessChild(device, &sockIpc);
if (childIpcPid < 0) return 1;
pid_t childCrossGpuPid = spawnCrossProcCrossGpuChild(&sockCrossGpu);
if (childCrossGpuPid < 0) {
close(sockIpc);
reapCrossProcessChild(childIpcPid);
return 1;
}
cuInit(0);
int dmabufExportSupported = 0;
cuDeviceGetAttribute(&dmabufExportSupported,
CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED, device);
if (!dmabufExportSupported) {
printf("Device %d does not report CU_DEVICE_ATTRIBUTE_HOST_ALLOC_DMA_BUF_SUPPORTED. "
"Skipping sample.\n", device);
close(sockIpc);
close(sockCrossGpu);
reapCrossProcessChild(childIpcPid);
reapCrossProcessChild(childCrossGpuPid);
return 0;
}
cudaDeviceProp props;
cudaGetDeviceProperties(&props, device);
printf("Device %d: %s (Compute Capability %d.%d)\n\n",
device, props.name, props.major, props.minor);
printf("Same-process round-trip\n");
int rc = runSameProcess(device);
printf("\nCross-process IPC (fork + SCM_RIGHTS)\n");
int ipcParentRc = (rc == 0) ? runCrossProcessParent(device, sockIpc) : -1;
close(sockIpc);
int ipcChildRc = reapCrossProcessChild(childIpcPid);
if (rc == 0 && (ipcParentRc != 0 || ipcChildRc != 0)) rc = -1;
printf("\nCross-GPU sharing across processes\n");
int crossGpuParentRc = (rc == 0) ? runCrossProcCrossGpuParent(sockCrossGpu) : -1;
close(sockCrossGpu);
int crossGpuChildRc = reapCrossProcessChild(childCrossGpuPid);
if (rc == 0 && (crossGpuParentRc != 0 || crossGpuChildRc != 0)) rc = -1;
if (rc == 0) printf("\nDone\n");
return rc == 0 ? 0 : 1;
}

View File

@@ -0,0 +1,110 @@
/* Copyright (c) 2026, 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.
*/
/*
* POSIX helpers used by the cross-process demos in dmabufInterop.cu:
* - sendFd / recvFd: transport a file descriptor between two processes
* over a UNIX domain socket via the SCM_RIGHTS control message.
* - reapCrossProcessChild: waitpid() wrapper that returns 0 iff the child
* exited cleanly with status 0.
*
* These are POSIX-only (no CUDA code) and are separated out so that
* dmabufInterop.cu stays focused on the CUDA dma-buf export/import flow.
*/
#ifndef DMABUF_INTEROP_HELPERS_H
#define DMABUF_INTEROP_HELPERS_H
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
/* Send a file descriptor over a UNIX domain socket using SCM_RIGHTS. */
static inline void sendFd(int sock, int fd)
{
struct msghdr msg = {};
char dummy = 'F';
struct iovec iov = { &dummy, 1 };
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
char cbuf[CMSG_SPACE(sizeof(int))] = {};
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
(void)sendmsg(sock, &msg, 0);
}
/* Receive a file descriptor from a UNIX domain socket. Returns -1 if no
* valid single-fd SCM_RIGHTS control message was received. */
static inline int recvFd(int sock)
{
struct msghdr msg = {};
char dummy = 0;
struct iovec iov = { &dummy, 1 };
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
char cbuf[CMSG_SPACE(sizeof(int))] = {};
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
(void)recvmsg(sock, &msg, 0);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
/* Validate that recvmsg actually delivered a single-fd SCM_RIGHTS control
* message before dereferencing -- a truncated or absent ancillary buffer
* would otherwise crash on the memcpy below. */
if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int))) return -1;
int fd = -1;
memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
/* Wait for a child process to exit and return 0 iff it exited cleanly with
* status 0. */
static inline int reapCrossProcessChild(pid_t pid)
{
int status = 0;
if (waitpid(pid, &status, 0) < 0) {
perror("waitpid");
return -1;
}
return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : -1;
}
#endif /* DMABUF_INTEROP_HELPERS_H */

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,41 +1,31 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(dmmaTensorCoreGemm LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# This sample is not supported on QNX
if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
message(STATUS "Will not build sample ${PROJECT_NAME} - not supported on QNX")
return()
endif()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for dmmaTensorCoreGemm
add_executable(dmmaTensorCoreGemm dmmaTensorCoreGemm.cu)
target_compile_options(dmmaTensorCoreGemm PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(dmmaTensorCoreGemm PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(dmmaTensorCoreGemm PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,23 +1,18 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(globalToShmemAsyncCopy LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# This sample is not supported on QNX
@@ -26,16 +21,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
return()
endif()
# Source file
# Add target for globalToShmemAsyncCopy
add_executable(globalToShmemAsyncCopy globalToShmemAsyncCopy.cu)
target_compile_options(globalToShmemAsyncCopy PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(globalToShmemAsyncCopy PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(globalToShmemAsyncCopy PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(graphConditionalNodes LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for graphConditionalNodes
add_executable(graphConditionalNodes graphConditionalNodes.cu)
target_compile_options(graphConditionalNodes PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(graphConditionalNodes PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(graphConditionalNodes PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(graphMemoryFootprint LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for graphMemoryFootprint
add_executable(graphMemoryFootprint graphMemoryFootprint.cu)
target_compile_options(graphMemoryFootprint PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(graphMemoryFootprint PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(graphMemoryFootprint PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(graphMemoryNodes LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for graphMemoryNodes
add_executable(graphMemoryNodes graphMemoryNodes.cu)
target_compile_options(graphMemoryNodes PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(graphMemoryNodes PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(graphMemoryNodes PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,35 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(immaTensorCoreGemm LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for immaTensorCoreGemm
add_executable(immaTensorCoreGemm immaTensorCoreGemm.cu)
target_compile_options(immaTensorCoreGemm PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(immaTensorCoreGemm PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(immaTensorCoreGemm PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,38 +1,29 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(jacobiCudaGraphs LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for jacobiCudaGraphs
add_executable(jacobiCudaGraphs jacobi.cu main.cpp)
target_compile_options(jacobiCudaGraphs PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(jacobiCudaGraphs PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(jacobiCudaGraphs PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(jacobiCudaGraphs PRIVATE
${CUDAToolkit_INCLUDE_DIRS}
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(localityDomains LANGUAGES C CXX CUDA)
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()
# Source file
# Add target for localityDomains
add_executable(localityDomains localityDomains.cu)
target_compile_options(localityDomains PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(localityDomains PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(localityDomains PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@@ -0,0 +1,86 @@
# localityDomains - CUDA Runtime API Locality Domains
## Description
This CUDA Runtime API sample demonstrates localized compute and memory resources.
Compute is localized by splitting a device's SM resources into locality domain partitions and constructing a green context and stream per locality domain. Memory is localized by allocating from localized memory pools.
## What You'll Learn
How to:
- query a device's locality domain count and SM count per domain
- partition SM resources by locality domain ID
- create green contexts and streams from localized SM partitions
- create localized memory pools and allocate from them asynchronously
- query the locality domain associated with a stream and device pointer
## Key Concepts
- **Locality domain** — a portion of a GPU that contains streaming multiprocessors (SMs) and device memory.
**Green context** — an execution context created from a selected subset of device resources.
- **Localized memory pool** — a stream-ordered allocator whose physical memory is placed in a selected locality domain.
## Key APIs
### CUDA Runtime
- `cudaDeviceGetAttribute` — query the number of locality domains and SMs per domain
- `cudaDevSmResourceSplit` — partition the device's SM resources
- `cudaMemPoolCreate` — create a localized memory pool and allocate from it
- `cudaStreamGetDevResource` — inspect stream locality
- `cudaPointerGetAttributes` — inspect allocation locality
## Requirements
### Hardware
- NVIDIA GPU that supports locality domains and stream-ordered memory pools
### Software
- CUDA Toolkit and NVIDIA driver with locality domain support
- Linux or QNX on x86_64 or aarch64
- CMake 3.20 or newer
- A C++17-capable host compiler
## How to Build
See the [top-level README](../../../README.md#building-cuda-samples) for full build instructions, including how to build all samples or a single sample standalone.
## How to Run
```bash
./localityDomains
```
No command-line arguments are required. The sample always runs on device 0.
## Expected Output
The number of locality domains and SMs depends on the GPU. A run has the following form:
```text
CUDA Runtime API locality domains sample
Locality domain count: <domain count>
SMs per locality domain: <SM count>
Device SMs split into <domain count> partitions
- result[0]: .localityDomainId = 0, .smCount = <SM count>
...
Green context stream 0 is localized to locality domain 0
...
allocation 0x<address> is localized to locality domain 0
...
```
If device 0 does not support memory pools, the sample reports that it is waiving execution and exits with status EXIT_WAIVED.
## Files
- `localityDomains.cu` — Runtime API example
- `README.md` — this file
- `CMakeLists.txt` — build configuration
## See Also
- [CUDA Runtime API](https://docs.nvidia.com/cuda/cuda-runtime-api/)
- [CUDA Programming Guide](https://docs.nvidia.com/cuda/cuda-programming-guide/)

View File

@@ -0,0 +1,171 @@
/* Copyright (c) 2026, 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 CUDA locality domains using the Runtime API.
* It creates one green context and stream per reported locality domain and
* allocates one localized memory-pool chunk per locality domain, then queries the
* placement back from both the stream resource and the device pointer.
*/
#include <cstdint>
#include <cstring>
#include <cuda_runtime.h>
#include <iomanip>
#include <iostream>
#include <vector>
int main()
{
std::cout << "CUDA Runtime API locality domains sample" << std::endl;
int dev = 0;
cudaSetDevice(dev);
int memoryPoolsSupported = 0;
cudaDeviceGetAttribute(&memoryPoolsSupported, cudaDevAttrMemoryPoolsSupported, dev);
if (!memoryPoolsSupported) {
std::cout << "Waiving execution as the device does not support memory pools." << std::endl;
return 0;
}
// Device information
int localityDomainCount = 0;
{
int localityDomainSmCount = 0;
cudaDeviceGetAttribute(&localityDomainCount, cudaDevAttrLocalityDomainCount, dev);
cudaDeviceGetAttribute(&localityDomainSmCount, cudaDevAttrLocalityDomainMultiprocessorCount, dev);
std::cout << "Locality domain count: " << localityDomainCount << std::endl;
std::cout << "SMs per locality domain: " << localityDomainSmCount << std::endl;
}
// Construct localized green contexts and streams
std::vector<cudaExecutionContext_t> greenContexts(localityDomainCount);
std::vector<cudaStream_t> streams(localityDomainCount);
{
cudaDevResource smResource = {};
cudaDeviceGetDevResource(dev, &smResource, cudaDevResourceTypeSm);
std::vector<cudaDevSmResourceGroupParams> params(localityDomainCount);
for (size_t i = 0; i < localityDomainCount; i++) {
std::memset(&params[i], 0, sizeof(params[i]));
params[i].flags = cudaDevSmResourceGroupLocalityDomainId;
params[i].localityDomainId = static_cast<unsigned int>(i);
}
std::vector<cudaDevResource> result(localityDomainCount);
cudaDevResource remainder = {};
cudaDevSmResourceSplit(result.data(), localityDomainCount, &smResource, &remainder, 0, params.data());
std::cout << "Device SMs split into " << localityDomainCount << " partitions" << std::endl;
for (size_t i = 0; i < localityDomainCount; i++) {
std::cout << " - result[" << i << "]: .localityDomainId = " << result[i].sm.localityDomainId
<< ", .smCount = " << result[i].sm.smCount << std::endl;
}
if (remainder.sm.smCount > 0) {
std::cout << " - remainder: .localityDomainId = none, .smCount = " << remainder.sm.smCount << std::endl;
}
for (size_t i = 0; i < localityDomainCount; i++) {
cudaDevResourceDesc_t desc = nullptr;
cudaDevResourceGenerateDesc(&desc, &result[i], 1);
cudaGreenCtxCreate(&greenContexts[i], desc, dev, 0);
cudaExecutionCtxStreamCreate(&streams[i], greenContexts[i], cudaStreamNonBlocking, 0);
}
}
// Inspect locality of streams
{
for (size_t i = 0; i < localityDomainCount; i++) {
cudaDevResource streamSmResource = {};
cudaStreamGetDevResource(streams[i], &streamSmResource, cudaDevResourceTypeSm);
bool isStreamLocalized = (streamSmResource.sm.flags & cudaDevSmResourceGroupLocalityDomainId) != 0;
std::cout << "Green context stream " << i << " ";
if (isStreamLocalized) {
unsigned int streamLocalityDomain = streamSmResource.sm.localityDomainId;
std::cout << "is localized to locality domain " << streamLocalityDomain << std::endl;
}
else {
std::cout << "is not localized" << std::endl;
}
}
}
// Allocate localized memory
size_t allocationSize = 1 << 20;
std::vector<void *> localizedPtrs(localityDomainCount);
std::vector<cudaMemPool_t> pools(localityDomainCount);
{
for (size_t i = 0; i < localityDomainCount; i++) {
cudaMemPoolProps poolProps = {};
poolProps.allocType = cudaMemAllocationTypePinned;
poolProps.location.type = cudaMemLocationTypeDeviceLocalityDomain;
poolProps.location.localized.deviceId = static_cast<unsigned char>(dev);
poolProps.location.localized.localityDomainId = static_cast<unsigned char>(i);
cudaMemPoolCreate(&pools[i], &poolProps);
cudaMallocFromPoolAsync(&localizedPtrs[i], allocationSize, pools[i], streams[i]);
cudaStreamSynchronize(streams[i]);
}
}
// Inspect locality of allocations
{
for (void *ptr : localizedPtrs) {
cudaPointerAttributes pointerAttributes = {};
cudaPointerGetAttributes(&pointerAttributes, ptr);
std::cout << "allocation 0x" << std::hex << reinterpret_cast<std::uintptr_t>(ptr) << std::dec;
if (pointerAttributes.localityDomainOrdinal == -1) {
std::cout << " is not localized." << std::endl;
}
else {
std::cout << " is localized to locality domain " << pointerAttributes.localityDomainOrdinal
<< std::endl;
}
}
}
// Clean up
for (size_t i = 0; i < localizedPtrs.size(); i++) {
cudaFreeAsync(localizedPtrs[i], streams[i]);
}
for (cudaStream_t stream : streams) {
cudaStreamSynchronize(stream);
cudaStreamDestroy(stream);
}
for (cudaExecutionContext_t greenContext : greenContexts) {
cudaExecutionCtxDestroy(greenContext);
}
for (cudaMemPool_t pool : pools) {
cudaMemPoolDestroy(pool);
}
return 0;
}

View File

@@ -0,0 +1,39 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(localityDomainsDrv LANGUAGES C CXX CUDA)
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()
# Source file
# Add target for localityDomainsDrv
add_executable(localityDomainsDrv localityDomainsDrv.cpp)
target_compile_options(localityDomainsDrv PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(localityDomainsDrv PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(localityDomainsDrv PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(localityDomainsDrv PRIVATE
${CUDAToolkit_INCLUDE_DIRS}
)
target_link_libraries(localityDomainsDrv PUBLIC
CUDA::cuda_driver
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@@ -0,0 +1,86 @@
# localityDomainsDrv - CUDA Driver API Locality Domains
## Description
This CUDA Driver API sample demonstrates localized compute and memory resources.
Compute is localized by splitting a device's SM resources into locality domain partitions and constructing a green context and stream per locality domain. Memory is localized by creating a localized memory region and mapping it.
## What You'll Learn
How to:
- query a device's locality domain count and SM count per locality domain
- partition SM resources by locality domain ID
- create green contexts and streams from localized SM partitions
- create and map physical allocations in locality domains
- query the locality domain associated with a stream and device pointer
## Key Concepts
- **Locality domain** — a portion of a GPU that contains streaming multiprocessors (SMs) and device memory.
**Green context** — an execution context created from a selected subset of device resources.
- **Virtual memory management** — separate control over virtual addresses, physical allocations, mappings, and access permissions.
## Key APIs
### CUDA Driver
- `cuDeviceGetAttribute` — query the number of locality domains and SMs per domain
- `cuDevSmResourceSplit` — partition the device's SM resources
- `cuMemCreate` — create localized physical memory
- `cuStreamGetDevResource` — inspect stream locality
- `cuPointerGetAttribute` — inspect allocation locality
## Requirements
### Hardware
- NVIDIA GPU that supports locality domains
### Software
- CUDA Toolkit and NVIDIA driver with locality domain support
- Linux or QNX on x86_64 or aarch64
- CMake 3.20 or newer
- A C++17-capable host compiler
## How to Build
See the [top-level README](../../../README.md#building-cuda-samples) for full build instructions, including how to build all samples or a single sample standalone.
## How to Run
```bash
./localityDomainsDrv
```
No command-line arguments are required. The sample always runs on device 0.
## Expected Output
The number of locality domains and SMs depends on the GPU. A run has the following form:
```text
CUDA Driver API locality domains sample
Locality domain count: <domain count>
SMs per locality domain: <SM count>
Device SMs split into <domain count> partitions
- result[0]: .localityDomainId = 0, .smCount = <SM count>
...
Green context stream 0 is localized to locality domain 0
...
Allocation granularity per chunk: <bytes> bytes
Reserved VA range size: <bytes> bytes
allocation 0x<address> is localized to locality domain 0
...
```
## Files
- `localityDomainsDrv.cpp` — Driver API example
- `README.md` — this file
- `CMakeLists.txt` — build configuration
## See Also
- [CUDA Driver API](https://docs.nvidia.com/cuda/cuda-driver-api/)
- [CUDA Programming Guide](https://docs.nvidia.com/cuda/cuda-programming-guide/)

View File

@@ -0,0 +1,188 @@
/* Copyright (c) 2026, 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 CUDA locality domains using the Driver API.
* It creates one green context and stream per reported locality domain and
* maps one virtual-address chunk to each locality domain, then queries the
* placement back from both the stream resource and the device pointer.
*/
#include <cstring>
#include <cuda.h>
#include <iomanip>
#include <iostream>
#include <vector>
int main()
{
std::cout << "CUDA Driver API locality domains sample" << std::endl;
cuInit(0);
CUdevice dev;
cuDeviceGet(&dev, 0);
CUctxCreateParams ctxCreateParams = {};
CUcontext context;
cuCtxCreate(&context, &ctxCreateParams, 0, dev);
// Device information
int localityDomainCount = 0;
{
cuDeviceGetAttribute(&localityDomainCount, CU_DEVICE_ATTRIBUTE_LOCALITY_DOMAIN_COUNT, dev);
int localityDomainSmCount = 0;
cuDeviceGetAttribute(&localityDomainSmCount, CU_DEVICE_ATTRIBUTE_LOCALITY_DOMAIN_MULTIPROCESSOR_COUNT, dev);
std::cout << "Locality domain count: " << localityDomainCount << std::endl;
std::cout << "SMs per locality domain: " << localityDomainSmCount << std::endl;
}
// Construct localized green contexts and streams
std::vector<CUgreenCtx> greenContexts(localityDomainCount);
std::vector<CUstream> streams(localityDomainCount);
{
CUdevResource smResource;
cuDeviceGetDevResource(dev, &smResource, CU_DEV_RESOURCE_TYPE_SM);
std::vector<CU_DEV_SM_RESOURCE_GROUP_PARAMS> params(localityDomainCount);
for (size_t i = 0; i < localityDomainCount; i++) {
std::memset(&params[i], 0, sizeof(params[i]));
params[i].flags = CU_DEV_SM_RESOURCE_GROUP_LOCALITY_DOMAIN_ID;
params[i].localityDomainId = static_cast<unsigned int>(i);
}
std::vector<CUdevResource> result(localityDomainCount);
CUdevResource remainder = {};
cuDevSmResourceSplit(result.data(), localityDomainCount, &smResource, &remainder, 0, params.data());
std::cout << "Device SMs split into " << localityDomainCount << " partitions" << std::endl;
for (size_t i = 0; i < localityDomainCount; i++) {
std::cout << " - result[" << i << "]: .localityDomainId = " << result[i].sm.localityDomainId
<< ", .smCount = " << result[i].sm.smCount << std::endl;
}
if (remainder.sm.smCount > 0) {
std::cout << " - remainder: .localityDomainId = none, .smCount = " << remainder.sm.smCount << std::endl;
}
for (size_t i = 0; i < localityDomainCount; i++) {
CUdevResourceDesc desc;
cuDevResourceGenerateDesc(&desc, &result[i], 1);
cuGreenCtxCreate(&greenContexts[i], desc, dev, CU_GREEN_CTX_DEFAULT_STREAM);
cuGreenCtxStreamCreate(&streams[i], greenContexts[i], CU_STREAM_NON_BLOCKING, 0);
}
}
// Inspect locality of streams
{
for (size_t i = 0; i < localityDomainCount; i++) {
CUdevResource streamSmResource;
cuStreamGetDevResource(streams[i], &streamSmResource, CU_DEV_RESOURCE_TYPE_SM);
bool isStreamLocalized = (streamSmResource.sm.flags & CU_DEV_SM_RESOURCE_GROUP_LOCALITY_DOMAIN_ID) != 0;
std::cout << "Green context stream " << i << " ";
if (isStreamLocalized) {
unsigned int streamLocalityDomain = streamSmResource.sm.localityDomainId;
std::cout << "is localized to locality domain " << streamLocalityDomain << std::endl;
}
else {
std::cout << "is not localized" << std::endl;
}
}
}
// Allocate localized memory
CUdeviceptr allocationBase = 0;
size_t allocationGranularity = 0;
size_t allocationSize = 0;
std::vector<CUdeviceptr> localizedPtrs(localityDomainCount);
{
{
CUmemAllocationProp prop = {};
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE_LOCALITY_DOMAIN;
prop.location.localized.deviceId = static_cast<unsigned char>(dev);
prop.location.localized.localityDomainId = 0;
cuMemGetAllocationGranularity(&allocationGranularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM);
}
std::cout << "Allocation granularity per chunk: " << allocationGranularity << " bytes" << std::endl;
allocationSize = allocationGranularity * localityDomainCount;
cuMemAddressReserve(&allocationBase, allocationSize, 0, 0, 0);
std::cout << "Reserved VA range size: " << allocationSize << " bytes" << std::endl;
for (size_t i = 0; i < localityDomainCount; i++) {
localizedPtrs[i] = allocationBase + i * allocationGranularity;
CUmemGenericAllocationHandle handle;
CUmemAllocationProp prop = {};
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE_LOCALITY_DOMAIN;
prop.location.localized.deviceId = static_cast<unsigned char>(dev);
prop.location.localized.localityDomainId = static_cast<unsigned char>(i);
cuMemCreate(&handle, allocationGranularity, &prop, 0);
cuMemMap(localizedPtrs[i], allocationGranularity, 0, handle, 0);
CUmemAccessDesc desc = {};
desc.location.type = CU_MEM_LOCATION_TYPE_DEVICE_LOCALITY_DOMAIN;
desc.location.localized.deviceId = static_cast<unsigned char>(dev);
desc.location.localized.localityDomainId = static_cast<unsigned char>(i);
desc.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
cuMemSetAccess(localizedPtrs[i], allocationGranularity, &desc, 1);
cuMemRelease(handle);
}
}
// Inspect locality of allocations
{
for (CUdeviceptr ptr : localizedPtrs) {
unsigned int localityDomainId = 0;
cuPointerGetAttribute(&localityDomainId, CU_POINTER_ATTRIBUTE_LOCALITY_DOMAIN_ORDINAL, ptr);
std::cout << "allocation 0x" << std::hex << ptr << std::dec;
if (localityDomainId == -1) {
std::cout << " is not localized." << std::endl;
}
else {
std::cout << " is localized to locality domain " << localityDomainId << std::endl;
}
}
}
// Clean up
for (CUstream stream : streams) {
cuStreamDestroy(stream);
}
for (CUgreenCtx greenContext : greenContexts) {
cuGreenCtxDestroy(greenContext);
}
for (CUdeviceptr localizedPtr : localizedPtrs) {
cuMemUnmap(localizedPtr, allocationGranularity);
}
cuMemAddressFree(allocationBase, allocationSize);
cuCtxDestroy(context);
return 0;
}

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,26 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(memMapIPCDrv LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for memMapIPCDrv
add_executable(memMapIPCDrv memMapIpc.cpp ../../../Common/helper_multiprocess.cpp)
target_compile_options(memMapIPCDrv PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(memMapIPCDrv PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(memMapIPCDrv PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(memMapIPCDrv PRIVATE
${CUDAToolkit_INCLUDE_DIRS}
)
@@ -58,18 +50,16 @@ endif()
add_custom_command(
OUTPUT ${CUDA_PTX_FILE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets -o ${CUDA_PTX_FILE} -ptx ${CUDA_KERNEL_SOURCE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} -Wno-deprecated-gpu-targets -o ${CUDA_PTX_FILE} -ptx ${CUDA_KERNEL_SOURCE}
DEPENDS ${CUDA_KERNEL_SOURCE}
COMMENT "Building CUDA PTX: ${CUDA_PTX_FILE}"
)
# Create a dummy target for fatbin generation
add_custom_target(generate_memMapIpc_ptx ALL DEPENDS ${CUDA_PTX_FILE})
# Ensure memMapIPCDrv depends on the fatbin
add_dependencies(memMapIPCDrv generate_memMapIpc_ptx)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(newdelete LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for newdelete
add_executable(newdelete newdelete.cu)
target_compile_options(newdelete PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(newdelete PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(newdelete PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,26 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(ptxjit LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for ptxjit
add_executable(ptxjit ptxjit.cpp)
target_compile_options(ptxjit PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(ptxjit PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(ptxjit PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(ptxjit PRIVATE
${CUDAToolkit_INCLUDE_DIRS}
)
@@ -51,18 +43,16 @@ endif()
add_custom_command(
OUTPUT ${CUDA_PTX_FILE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets -o ${CUDA_PTX_FILE} -ptx ${CUDA_KERNEL_SOURCE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} -Wno-deprecated-gpu-targets -o ${CUDA_PTX_FILE} -ptx ${CUDA_KERNEL_SOURCE}
DEPENDS ${CUDA_KERNEL_SOURCE}
COMMENT "Building CUDA PTX: ${CUDA_PTX_FILE}"
)
# Create a dummy target for fatbin generation
add_custom_target(generate_ptxjit_ptx ALL DEPENDS ${CUDA_PTX_FILE})
# Ensure ptxjit depends on the fatbin
add_dependencies(ptxjit generate_ptxjit_ptx)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,26 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(simpleCudaGraphs LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_executable(simpleCudaGraphs_explicit simpleCudaGraphs_explicit.cu)
add_executable(simpleCudaGraphs_capture simpleCudaGraphs_capture.cu)
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()
foreach(target simpleCudaGraphs_explicit simpleCudaGraphs_capture)
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(${target} PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(${target} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(${target} PRIVATE ${CUDAToolkit_INCLUDE_DIRS}/cccl)
endforeach()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for simpleCudaGraphs
add_executable(simpleCudaGraphs simpleCudaGraphs.cu)
target_compile_options(simpleCudaGraphs PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(simpleCudaGraphs PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(simpleCudaGraphs PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,30 +1,126 @@
# simpleCudaGraphs - Simple CUDA Graphs
# Sample: CUDA Graphs (simpleCudaGraphs)
## Description
A demonstration of CUDA Graphs creation, instantiation and launch using Graphs APIs and Stream Capture APIs.
Demonstrates how to create, instantiate, and launch CUDA Graphs using two different approaches: building the graph explicitly, node by node, with `cudaGraphAddNode`, and building it automatically by recording an existing stream sequence with `cudaStreamBeginCapture` / `cudaStreamEndCapture`. A CUDA Graph records a sequence of GPU operations — memory copies, kernel launches, and host callbacks — as a reusable DAG (Directed Acyclic Graph). Once instantiated, the graph can be submitted to the GPU with a single API call per launch, reducing per-launch CPU overhead compared to issuing each operation individually.
The workload is a two-pass parallel reduction: 16M `float` values are reduced to per-block partial sums (`reduce` kernel), then to a single `double` result (`reduceFinal` kernel). Both samples use `cub::BlockReduce` for the in-kernel reduction. Each graph is launched several times, and the host input is refilled with new random values before every launch, to show that one instantiated graph can reprocess different data each iteration.
This sample is split into two standalone executables plus a shared header:
| File | Role |
|---|---|
| `simpleCudaGraphs_explicit.cu` | Explicit construction via the unified `cudaGraphAddNode` API |
| `simpleCudaGraphs_capture.cu` | Automatic construction via stream capture |
| `simpleCudaGraphs.cuh` | Shared reduction kernels, host callback (and its data type), and input-fill helper used by both |
## What You'll Learn
- Building a CUDA Graph node by node using the unified `cudaGraphAddNode` API with a typed `cudaGraphNodeParams`
- Expressing dependencies between nodes so the runtime enforces the correct execution order
- Building the same graph automatically by recording stream operations between `cudaStreamBeginCapture` and `cudaStreamEndCapture`
- Instantiating a graph with `cudaGraphInstantiate` (one-time compilation cost) and launching it repeatedly with `cudaGraphLaunch`
- Cloning a graph with `cudaGraphClone` to produce independent executable instances
- Adding memcpy, kernel, and host-callback nodes through the single polymorphic `cudaGraphAddNode` entry point
- Reusing one instantiated graph across many launches by refilling its input buffer between launches (and synchronizing so the graph's H2D copy consumes the data before the host overwrites it)
- Using `cub::BlockReduce` for efficient block-level reductions
## Key Concepts
CUDA Graphs, Stream Capture
- **CUDA Graph** — a DAG of GPU operations captured once and replayed many times; each replay is a single `cudaGraphLaunch` call regardless of graph size
- **Graph Node** — an individual operation in the graph: memcpy, kernel launch, or host callback
- **Node dependency** — an edge from node A to node B means B cannot start until A completes; expressed as a dependency list passed to `cudaGraphAddNode`
- **Instantiation** — `cudaGraphInstantiate` compiles the graph into an optimized executable form (`cudaGraphExec_t`); this is the one-time setup cost; subsequent launches reuse it
- **Stream Capture** — `cudaStreamBeginCapture` / `cudaStreamEndCapture` records stream operations into a graph automatically; the runtime infers the same node structure as the manually built graph
- **Graph Clone** — `cudaGraphClone` deep-copies the graph structure; each clone can be independently instantiated and launched, useful when multiple CPU threads need to launch the same graph concurrently
- **Graph reuse** — an instantiated graph is a template you launch repeatedly; because this graph begins with an H2D copy from a host buffer, refilling that buffer before each launch feeds new data through the same graph (with a `cudaStreamSynchronize` between launches so the copy reads the data before the host overwrites it)
- **`cub::BlockReduce`** — CUB's block-scoped reduction primitive; all threads in a block contribute their partial sum and thread 0 receives the block total
## Supported SM Architectures
## Key APIs
## Supported OSes
### CUDA Runtime — Explicit Graph Construction
- `cudaGraphCreate` — create an empty graph
- `cudaGraphAddNode` — add a node of any type (memcpy, kernel, host, …) via a `cudaGraphNodeParams` struct
- `cudaGraphNodeParams` — unified node descriptor: a `.type` tag plus a union of per-type parameters
- `cudaGraphGetNodes` — query the number of nodes in a graph
Linux, Windows
### CUDA Runtime — Stream Capture
- `cudaStreamBeginCapture` — put a stream into capture mode; subsequent operations are recorded, not executed
- `cudaStreamEndCapture` — stop recording and return the captured graph
- `cudaLaunchHostFunc` — schedule a CPU callback on a stream (captured as a host node)
## Supported CPU Architecture
### CUDA Runtime — Instantiation and Launch
- `cudaGraphInstantiate` — compile a graph into an executable `cudaGraphExec_t`
- `cudaGraphLaunch` — submit the entire graph to a stream in a single call
- `cudaGraphClone` — deep-copy a graph structure
- `cudaStreamSynchronize` — block until the stream's queued work (including the graph's H2D copy) completes, so the host input buffer can be safely refilled for the next launch
- `cudaGraphExecDestroy` — release an executable graph
- `cudaGraphDestroy` — release a graph
x86_64, armv7l
### CUB
- `cub::BlockReduce<T, BLOCK_THREADS>::Sum` — reduce all per-thread values to a single block sum; result lands on thread 0
## CUDA APIs involved
## Requirements
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
cudaGraphClone, cudaExtent, cudaGraphLaunch, cudaStreamCreate, cudaLaunchHostFunc, cudaGraphAddMemcpyNode, cudaMallocHost, cudaPitchedPtr, cudaStreamEndCapture, cudaGraphCreate, cudaFreeHost, cudaGraphGetNodes, cudaMemsetAsync, cudaMemcpyAsync, cudaGraphAddHostNode, cudaGraphInstantiate, cudaStreamDestroy, cudaStreamBeginCapture, cudaStreamWaitEvent, cudaEventCreate, cudaMalloc, cudaFree, cudaPos, cudaGraphAddKernelNode, cudaGraphDestroy, cudaEventRecord, cudaGraphsManual, cudaStreamSynchronize, cudaGraphAddMemsetNode, cudaGraphsUsingStreamCapture, cudaGraphExecDestroy
### Hardware
- NVIDIA GPU with Compute Capability 7.5 or higher
## Prerequisites
### Software
- CMake 3.20 or newer
- A C++17-capable host compiler
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## How to Build
## References (for more details)
See the [top-level README](../../../README.md#building-cuda-samples) for full build instructions, including how to build all samples or a single sample standalone.
## How to Run
**Explicit graph construction:**
```bash
./simpleCudaGraphs_explicit
```
**Stream capture:**
```bash
./simpleCudaGraphs_capture
```
## Expected Output
Both executables build the same 5-node graph (`Graph node count: 5`), confirming that stream capture produces the same structure as the explicit construction. Because the host input is refilled with new random values before every launch, **each of the six launches prints a different reduced sum** — showing that one instantiated graph reprocesses fresh data each iteration. The exact values depend on the platform's `rand()` implementation, but they are reproducible run-to-run and both executables print the same sequence.
**`simpleCudaGraphs_explicit`**
```text
GPU Device 0: compute capability X.Y, <smCount> SMs
Reducing 16777216 elements
Threads per block : 512
Graph launch iterations: 3
=== Explicit Graph Construction ===
Graph node count: 5
[cudaGraphsManual] Host callback final reduced sum = 0.996214
[cudaGraphsManual] Host callback final reduced sum = 0.996187
[cudaGraphsManual] Host callback final reduced sum = 0.996120
Cloned graph:
[cudaGraphsManual] Host callback final reduced sum = 0.996150
[cudaGraphsManual] Host callback final reduced sum = 0.996184
[cudaGraphsManual] Host callback final reduced sum = 0.996056
```
**`simpleCudaGraphs_capture`** prints the same six values, each line labeled `[cudaGraphsUsingStreamCapture]` and under a `=== Stream Capture ===` header.
## Files
- `simpleCudaGraphs.cuh` — shared code: `THREADS_PER_BLOCK`, the `callBackData_t` type, the `myHostNodeCallback` host callback, the `init_input` host helper, and the two reduction kernels (`reduce`, `reduceFinal`)
- `simpleCudaGraphs_explicit.cu` — explicit graph construction via the unified `cudaGraphAddNode` API
- `simpleCudaGraphs_capture.cu` — graph construction via stream capture
- `CMakeLists.txt` — build configuration
- `README.md` — this file
## See Also
- [CUDA Programming Guide — CUDA Graphs](https://docs.nvidia.com/cuda/cuda-programming-guide/04-special-topics/cuda-graphs.html#cuda-graphs)
- [Technical Blog — Getting Started with CUDA Graphs](https://developer.nvidia.com/blog/cuda-graphs/)
- [CUDA Core Compute Libraries — What is CUB?](https://nvidia.github.io/cccl/unstable/cub/index.html#what-is-cub)

View File

@@ -1,407 +0,0 @@
/* Copyright (c) 2022, 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.
*/
#include <cooperative_groups.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <vector>
namespace cg = cooperative_groups;
#define THREADS_PER_BLOCK 512
#define GRAPH_LAUNCH_ITERATIONS 3
typedef struct callBackData
{
const char *fn_name;
double *data;
} callBackData_t;
__global__ void reduce(float *inputVec, double *outputVec, size_t inputSize, size_t outputSize)
{
__shared__ double tmp[THREADS_PER_BLOCK];
cg::thread_block cta = cg::this_thread_block();
size_t globaltid = blockIdx.x * blockDim.x + threadIdx.x;
double temp_sum = 0.0;
for (int i = globaltid; i < inputSize; i += gridDim.x * blockDim.x) {
temp_sum += (double)inputVec[i];
}
tmp[cta.thread_rank()] = temp_sum;
cg::sync(cta);
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
double beta = temp_sum;
double temp;
for (int i = tile32.size() / 2; i > 0; i >>= 1) {
if (tile32.thread_rank() < i) {
temp = tmp[cta.thread_rank() + i];
beta += temp;
tmp[cta.thread_rank()] = beta;
}
cg::sync(tile32);
}
cg::sync(cta);
if (cta.thread_rank() == 0 && blockIdx.x < outputSize) {
beta = 0.0;
for (int i = 0; i < cta.size(); i += tile32.size()) {
beta += tmp[i];
}
outputVec[blockIdx.x] = beta;
}
}
__global__ void reduceFinal(double *inputVec, double *result, size_t inputSize)
{
__shared__ double tmp[THREADS_PER_BLOCK];
cg::thread_block cta = cg::this_thread_block();
size_t globaltid = blockIdx.x * blockDim.x + threadIdx.x;
double temp_sum = 0.0;
for (int i = globaltid; i < inputSize; i += gridDim.x * blockDim.x) {
temp_sum += (double)inputVec[i];
}
tmp[cta.thread_rank()] = temp_sum;
cg::sync(cta);
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
// do reduction in shared mem
if ((blockDim.x >= 512) && (cta.thread_rank() < 256)) {
tmp[cta.thread_rank()] = temp_sum = temp_sum + tmp[cta.thread_rank() + 256];
}
cg::sync(cta);
if ((blockDim.x >= 256) && (cta.thread_rank() < 128)) {
tmp[cta.thread_rank()] = temp_sum = temp_sum + tmp[cta.thread_rank() + 128];
}
cg::sync(cta);
if ((blockDim.x >= 128) && (cta.thread_rank() < 64)) {
tmp[cta.thread_rank()] = temp_sum = temp_sum + tmp[cta.thread_rank() + 64];
}
cg::sync(cta);
if (cta.thread_rank() < 32) {
// Fetch final intermediate sum from 2nd warp
if (blockDim.x >= 64)
temp_sum += tmp[cta.thread_rank() + 32];
// Reduce final warp using shuffle
for (int offset = tile32.size() / 2; offset > 0; offset /= 2) {
temp_sum += tile32.shfl_down(temp_sum, offset);
}
}
// write result for this block to global mem
if (cta.thread_rank() == 0)
result[0] = temp_sum;
}
void init_input(float *a, size_t size)
{
for (size_t i = 0; i < size; i++)
a[i] = (rand() & 0xFF) / (float)RAND_MAX;
}
void CUDART_CB myHostNodeCallback(void *data)
{
// Check status of GPU after stream operations are done
callBackData_t *tmp = (callBackData_t *)(data);
// checkCudaErrors(tmp->status);
double *result = (double *)(tmp->data);
char *function = (char *)(tmp->fn_name);
printf("[%s] Host callback final reduced sum = %lf\n", function, *result);
*result = 0.0; // reset the result
}
void cudaGraphsManual(float *inputVec_h,
float *inputVec_d,
double *outputVec_d,
double *result_d,
size_t inputSize,
size_t numOfBlocks)
{
cudaStream_t streamForGraph;
cudaGraph_t graph;
std::vector<cudaGraphNode_t> nodeDependencies;
cudaGraphNode_t memcpyNode, kernelNode, memsetNode;
double result_h = 0.0;
checkCudaErrors(cudaStreamCreate(&streamForGraph));
cudaKernelNodeParams kernelNodeParams = {0};
cudaMemcpy3DParms memcpyParams = {0};
cudaMemsetParams memsetParams = {0};
memcpyParams.srcArray = NULL;
memcpyParams.srcPos = make_cudaPos(0, 0, 0);
memcpyParams.srcPtr = make_cudaPitchedPtr(inputVec_h, sizeof(float) * inputSize, inputSize, 1);
memcpyParams.dstArray = NULL;
memcpyParams.dstPos = make_cudaPos(0, 0, 0);
memcpyParams.dstPtr = make_cudaPitchedPtr(inputVec_d, sizeof(float) * inputSize, inputSize, 1);
memcpyParams.extent = make_cudaExtent(sizeof(float) * inputSize, 1, 1);
memcpyParams.kind = cudaMemcpyHostToDevice;
memsetParams.dst = (void *)outputVec_d;
memsetParams.value = 0;
memsetParams.pitch = 0;
memsetParams.elementSize = sizeof(float); // elementSize can be max 4 bytes
memsetParams.width = numOfBlocks * 2;
memsetParams.height = 1;
checkCudaErrors(cudaGraphCreate(&graph, 0));
checkCudaErrors(cudaGraphAddMemcpyNode(&memcpyNode, graph, NULL, 0, &memcpyParams));
checkCudaErrors(cudaGraphAddMemsetNode(&memsetNode, graph, NULL, 0, &memsetParams));
nodeDependencies.push_back(memsetNode);
nodeDependencies.push_back(memcpyNode);
void *kernelArgs[4] = {(void *)&inputVec_d, (void *)&outputVec_d, &inputSize, &numOfBlocks};
kernelNodeParams.func = (void *)reduce;
kernelNodeParams.gridDim = dim3(numOfBlocks, 1, 1);
kernelNodeParams.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
kernelNodeParams.sharedMemBytes = 0;
kernelNodeParams.kernelParams = (void **)kernelArgs;
kernelNodeParams.extra = NULL;
checkCudaErrors(cudaGraphAddKernelNode(
&kernelNode, graph, nodeDependencies.data(), nodeDependencies.size(), &kernelNodeParams));
nodeDependencies.clear();
nodeDependencies.push_back(kernelNode);
memset(&memsetParams, 0, sizeof(memsetParams));
memsetParams.dst = result_d;
memsetParams.value = 0;
memsetParams.elementSize = sizeof(float);
memsetParams.width = 2;
memsetParams.height = 1;
checkCudaErrors(cudaGraphAddMemsetNode(&memsetNode, graph, NULL, 0, &memsetParams));
nodeDependencies.push_back(memsetNode);
memset(&kernelNodeParams, 0, sizeof(kernelNodeParams));
kernelNodeParams.func = (void *)reduceFinal;
kernelNodeParams.gridDim = dim3(1, 1, 1);
kernelNodeParams.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
kernelNodeParams.sharedMemBytes = 0;
void *kernelArgs2[3] = {(void *)&outputVec_d, (void *)&result_d, &numOfBlocks};
kernelNodeParams.kernelParams = kernelArgs2;
kernelNodeParams.extra = NULL;
checkCudaErrors(cudaGraphAddKernelNode(
&kernelNode, graph, nodeDependencies.data(), nodeDependencies.size(), &kernelNodeParams));
nodeDependencies.clear();
nodeDependencies.push_back(kernelNode);
memset(&memcpyParams, 0, sizeof(memcpyParams));
memcpyParams.srcArray = NULL;
memcpyParams.srcPos = make_cudaPos(0, 0, 0);
memcpyParams.srcPtr = make_cudaPitchedPtr(result_d, sizeof(double), 1, 1);
memcpyParams.dstArray = NULL;
memcpyParams.dstPos = make_cudaPos(0, 0, 0);
memcpyParams.dstPtr = make_cudaPitchedPtr(&result_h, sizeof(double), 1, 1);
memcpyParams.extent = make_cudaExtent(sizeof(double), 1, 1);
memcpyParams.kind = cudaMemcpyDeviceToHost;
checkCudaErrors(
cudaGraphAddMemcpyNode(&memcpyNode, graph, nodeDependencies.data(), nodeDependencies.size(), &memcpyParams));
nodeDependencies.clear();
nodeDependencies.push_back(memcpyNode);
cudaGraphNode_t hostNode;
cudaHostNodeParams hostParams = {0};
hostParams.fn = myHostNodeCallback;
callBackData_t hostFnData;
hostFnData.data = &result_h;
hostFnData.fn_name = "cudaGraphsManual";
hostParams.userData = &hostFnData;
checkCudaErrors(
cudaGraphAddHostNode(&hostNode, graph, nodeDependencies.data(), nodeDependencies.size(), &hostParams));
cudaGraphNode_t *nodes = NULL;
size_t numNodes = 0;
checkCudaErrors(cudaGraphGetNodes(graph, nodes, &numNodes));
printf("\nNum of nodes in the graph created manually = %zu\n", numNodes);
cudaGraphExec_t graphExec;
checkCudaErrors(cudaGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
cudaGraph_t clonedGraph;
cudaGraphExec_t clonedGraphExec;
checkCudaErrors(cudaGraphClone(&clonedGraph, graph));
checkCudaErrors(cudaGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0));
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
checkCudaErrors(cudaGraphLaunch(graphExec, streamForGraph));
}
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
printf("Cloned Graph Output.. \n");
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
checkCudaErrors(cudaGraphLaunch(clonedGraphExec, streamForGraph));
}
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
checkCudaErrors(cudaGraphExecDestroy(graphExec));
checkCudaErrors(cudaGraphExecDestroy(clonedGraphExec));
checkCudaErrors(cudaGraphDestroy(graph));
checkCudaErrors(cudaGraphDestroy(clonedGraph));
checkCudaErrors(cudaStreamDestroy(streamForGraph));
}
void cudaGraphsUsingStreamCapture(float *inputVec_h,
float *inputVec_d,
double *outputVec_d,
double *result_d,
size_t inputSize,
size_t numOfBlocks)
{
cudaStream_t stream1, stream2, stream3, streamForGraph;
cudaEvent_t forkStreamEvent, memsetEvent1, memsetEvent2;
cudaGraph_t graph;
double result_h = 0.0;
checkCudaErrors(cudaStreamCreate(&stream1));
checkCudaErrors(cudaStreamCreate(&stream2));
checkCudaErrors(cudaStreamCreate(&stream3));
checkCudaErrors(cudaStreamCreate(&streamForGraph));
checkCudaErrors(cudaEventCreate(&forkStreamEvent));
checkCudaErrors(cudaEventCreate(&memsetEvent1));
checkCudaErrors(cudaEventCreate(&memsetEvent2));
checkCudaErrors(cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal));
checkCudaErrors(cudaEventRecord(forkStreamEvent, stream1));
checkCudaErrors(cudaStreamWaitEvent(stream2, forkStreamEvent, 0));
checkCudaErrors(cudaStreamWaitEvent(stream3, forkStreamEvent, 0));
checkCudaErrors(cudaMemcpyAsync(inputVec_d, inputVec_h, sizeof(float) * inputSize, cudaMemcpyDefault, stream1));
checkCudaErrors(cudaMemsetAsync(outputVec_d, 0, sizeof(double) * numOfBlocks, stream2));
checkCudaErrors(cudaEventRecord(memsetEvent1, stream2));
checkCudaErrors(cudaMemsetAsync(result_d, 0, sizeof(double), stream3));
checkCudaErrors(cudaEventRecord(memsetEvent2, stream3));
checkCudaErrors(cudaStreamWaitEvent(stream1, memsetEvent1, 0));
reduce<<<numOfBlocks, THREADS_PER_BLOCK, 0, stream1>>>(inputVec_d, outputVec_d, inputSize, numOfBlocks);
checkCudaErrors(cudaStreamWaitEvent(stream1, memsetEvent2, 0));
reduceFinal<<<1, THREADS_PER_BLOCK, 0, stream1>>>(outputVec_d, result_d, numOfBlocks);
checkCudaErrors(cudaMemcpyAsync(&result_h, result_d, sizeof(double), cudaMemcpyDefault, stream1));
callBackData_t hostFnData = {0};
hostFnData.data = &result_h;
hostFnData.fn_name = "cudaGraphsUsingStreamCapture";
cudaHostFn_t fn = myHostNodeCallback;
checkCudaErrors(cudaLaunchHostFunc(stream1, fn, &hostFnData));
checkCudaErrors(cudaStreamEndCapture(stream1, &graph));
cudaGraphNode_t *nodes = NULL;
size_t numNodes = 0;
checkCudaErrors(cudaGraphGetNodes(graph, nodes, &numNodes));
printf("\nNum of nodes in the graph created using stream capture API = %zu\n", numNodes);
cudaGraphExec_t graphExec;
checkCudaErrors(cudaGraphInstantiate(&graphExec, graph, NULL, NULL, 0));
cudaGraph_t clonedGraph;
cudaGraphExec_t clonedGraphExec;
checkCudaErrors(cudaGraphClone(&clonedGraph, graph));
checkCudaErrors(cudaGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0));
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
checkCudaErrors(cudaGraphLaunch(graphExec, streamForGraph));
}
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
printf("Cloned Graph Output.. \n");
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
checkCudaErrors(cudaGraphLaunch(clonedGraphExec, streamForGraph));
}
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
checkCudaErrors(cudaGraphExecDestroy(graphExec));
checkCudaErrors(cudaGraphExecDestroy(clonedGraphExec));
checkCudaErrors(cudaGraphDestroy(graph));
checkCudaErrors(cudaGraphDestroy(clonedGraph));
checkCudaErrors(cudaStreamDestroy(stream1));
checkCudaErrors(cudaStreamDestroy(stream2));
checkCudaErrors(cudaStreamDestroy(streamForGraph));
}
int main(int argc, char **argv)
{
size_t size = 1 << 24; // number of elements to reduce
size_t maxBlocks = 512;
// This will pick the best possible CUDA capable device
int devID = findCudaDevice(argc, (const char **)argv);
printf("%zu elements\n", size);
printf("threads per block = %d\n", THREADS_PER_BLOCK);
printf("Graph Launch iterations = %d\n", GRAPH_LAUNCH_ITERATIONS);
float *inputVec_d = NULL, *inputVec_h = NULL;
double *outputVec_d = NULL, *result_d;
checkCudaErrors(cudaMallocHost(&inputVec_h, sizeof(float) * size));
checkCudaErrors(cudaMalloc(&inputVec_d, sizeof(float) * size));
checkCudaErrors(cudaMalloc(&outputVec_d, sizeof(double) * maxBlocks));
checkCudaErrors(cudaMalloc(&result_d, sizeof(double)));
init_input(inputVec_h, size);
cudaGraphsManual(inputVec_h, inputVec_d, outputVec_d, result_d, size, maxBlocks);
cudaGraphsUsingStreamCapture(inputVec_h, inputVec_d, outputVec_d, result_d, size, maxBlocks);
checkCudaErrors(cudaFree(inputVec_d));
checkCudaErrors(cudaFree(outputVec_d));
checkCudaErrors(cudaFree(result_d));
checkCudaErrors(cudaFreeHost(inputVec_h));
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,106 @@
/* Copyright (c) 2026, 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.
*/
/*
* Shared code for the simpleCudaGraphs sample. Both the explicit-graph and
* stream-capture demos build a graph around the same two-pass reduction, so the
* reduction kernels, the host callback and its data type, and the input-fill
* helper live here to avoid duplicating them across the two .cu files.
*/
#pragma once
#include <cub/cub.cuh>
#include <cuda_runtime.h>
#include <cstdio>
#include <cstdlib>
#define THREADS_PER_BLOCK 512
// Payload passed to the host-callback node: the demo name and the reduced result.
typedef struct callBackData
{
const char *fn_name;
double *data;
} callBackData_t;
// Host-callback node body: prints the reduced result, then resets it for the next launch.
inline void CUDART_CB myHostNodeCallback(void *data)
{
callBackData_t *tmp = (callBackData_t *)(data);
double *result = (double *)(tmp->data);
printf("[%s] Host callback final reduced sum = %lf\n", tmp->fn_name, *result);
*result = 0.0; // reset the result
}
// Fill the host input buffer with fresh pseudo-random values. Called before each
// graph launch so the same graph processes different data every iteration.
inline void init_input(float *inputVec, size_t size)
{
for (size_t i = 0; i < size; i++)
inputVec[i] = (rand() & 0xFF) / (float)RAND_MAX;
}
// Pass 1: reduce the input float vector to one partial sum per block.
__global__ void reduce(float *inputVec, double *outputVec, size_t inputSize, size_t outputSize)
{
typedef cub::BlockReduce<double, THREADS_PER_BLOCK> BlockReduceT;
__shared__ typename BlockReduceT::TempStorage temp_storage;
size_t globaltid = blockIdx.x * blockDim.x + threadIdx.x;
// Each thread adds its assigned elements into a local partial sum
double temp_sum = 0.0;
for (size_t i = globaltid; i < inputSize; i += (size_t)gridDim.x * blockDim.x)
temp_sum += (double)inputVec[i];
// CUB reduces all per-thread partial sums to a single block sum; result lands on thread 0
double block_sum = BlockReduceT(temp_storage).Sum(temp_sum);
if (threadIdx.x == 0 && blockIdx.x < outputSize)
outputVec[blockIdx.x] = block_sum;
}
// Pass 2: reduce the per-block partial sums to a single scalar result.
__global__ void reduceFinal(double *inputVec, double *result, size_t inputSize)
{
typedef cub::BlockReduce<double, THREADS_PER_BLOCK> BlockReduceT;
__shared__ typename BlockReduceT::TempStorage temp_storage;
size_t globaltid = blockIdx.x * blockDim.x + threadIdx.x;
// Each thread adds its assigned elements into a local partial sum
double temp_sum = 0.0;
for (size_t i = globaltid; i < inputSize; i += (size_t)gridDim.x * blockDim.x)
temp_sum += (double)inputVec[i];
// CUB reduces all per-thread partial sums to a single block sum; result lands on thread 0
double block_sum = BlockReduceT(temp_storage).Sum(temp_sum);
if (threadIdx.x == 0)
result[0] = block_sum;
}

View File

@@ -0,0 +1,156 @@
/* Copyright (c) 2026, 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.
*/
/*
* Demonstrates CUDA Graph construction via stream capture.
*
* Operations are issued to a stream between cudaStreamBeginCapture and
* cudaStreamEndCapture. Instead of executing, they are recorded and the
* runtime automatically builds this graph:
*
* memcpy (H2D) -> reduce -> reduceFinal -> memcpy (D2H) -> host callback
*
* The workload is a two-pass reduction: an input float vector is reduced to
* per-block partial sums (reduce), then to a single double result (reduceFinal).
* The graph is instantiated once and launched GRAPH_LAUNCH_ITERATIONS times,
* then cloned and launched again.
*/
#include "simpleCudaGraphs.cuh"
#include <cuda_runtime.h>
#include <cstdio>
#define GRAPH_LAUNCH_ITERATIONS 3
void cudaGraphsUsingStreamCapture(float *inputVec_h,
float *inputVec_d,
double *outputVec_d,
double *result_d,
size_t inputSize,
size_t numOfBlocks)
{
cudaStream_t stream1, streamForGraph;
cudaGraph_t graph;
double result_h = 0.0;
cudaStreamCreate(&stream1);
cudaStreamCreate(&streamForGraph);
// Begin capture: operations issued to stream1 are recorded, not executed.
cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal);
cudaMemcpyAsync(inputVec_d, inputVec_h, sizeof(float) * inputSize, cudaMemcpyDefault, stream1);
reduce<<<numOfBlocks, THREADS_PER_BLOCK, 0, stream1>>>(inputVec_d, outputVec_d, inputSize, numOfBlocks);
reduceFinal<<<1, THREADS_PER_BLOCK, 0, stream1>>>(outputVec_d, result_d, numOfBlocks);
cudaMemcpyAsync(&result_h, result_d, sizeof(double), cudaMemcpyDefault, stream1);
callBackData_t hostFnData = {0};
hostFnData.data = &result_h;
hostFnData.fn_name = "cudaGraphsUsingStreamCapture";
cudaLaunchHostFunc(stream1, myHostNodeCallback, &hostFnData);
// End capture: the runtime builds a graph from everything recorded above.
// The resulting graph is structurally identical to the one built manually.
cudaStreamEndCapture(stream1, &graph);
size_t numNodes = 0;
cudaGraphGetNodes(graph, NULL, &numNodes);
printf("Graph node count: %zu\n", numNodes);
// Instantiate the captured graph into an executable form.
cudaGraphExec_t graphExec;
cudaGraphInstantiate(&graphExec, graph, NULL, NULL, 0);
// Demonstrates cudaGraphClone — in practice, cloning is useful when multiple CPU
// threads need to launch the same graph concurrently, each with its own independent graphExec.
cudaGraph_t clonedGraph;
cudaGraphExec_t clonedGraphExec;
cudaGraphClone(&clonedGraph, graph);
cudaGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0);
// Refill the host input before each launch so the graph's H2D copy processes
// new data every time — one instantiated graph reused for different data.
// The per-iteration sync ensures that copy finishes before we overwrite the buffer.
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
init_input(inputVec_h, inputSize);
cudaGraphLaunch(graphExec, streamForGraph);
cudaStreamSynchronize(streamForGraph);
}
printf("\nCloned graph:\n");
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
init_input(inputVec_h, inputSize);
cudaGraphLaunch(clonedGraphExec, streamForGraph);
cudaStreamSynchronize(streamForGraph);
}
cudaGraphExecDestroy(graphExec);
cudaGraphExecDestroy(clonedGraphExec);
cudaGraphDestroy(graph);
cudaGraphDestroy(clonedGraph);
cudaStreamDestroy(stream1);
cudaStreamDestroy(streamForGraph);
}
int main()
{
size_t size = 1 << 24; // number of elements to reduce, 16M elements
size_t maxBlocks = 512;
int devID = 0;
cudaSetDevice(devID);
int major, minor, smCount;
cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID);
cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID);
cudaDeviceGetAttribute(&smCount, cudaDevAttrMultiProcessorCount, devID);
printf("GPU Device %d: compute capability %d.%d, %d SMs\n\n", devID, major, minor, smCount);
printf("Reducing %zu elements\n", size);
printf("Threads per block : %d\n", THREADS_PER_BLOCK);
printf("Graph launch iterations: %d\n\n", GRAPH_LAUNCH_ITERATIONS);
float *inputVec_h = NULL, *inputVec_d = NULL;
double *outputVec_d = NULL, *result_d = NULL;
cudaMallocHost(&inputVec_h, sizeof(float) * size);
cudaMalloc(&inputVec_d, sizeof(float) * size);
cudaMalloc(&outputVec_d, sizeof(double) * maxBlocks);
cudaMalloc(&result_d, sizeof(double));
printf("=== Stream Capture ===\n");
cudaGraphsUsingStreamCapture(inputVec_h, inputVec_d, outputVec_d, result_d, size, maxBlocks);
cudaFree(inputVec_d);
cudaFree(outputVec_d);
cudaFree(result_d);
cudaFreeHost(inputVec_h);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,236 @@
/* Copyright (c) 2026, 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.
*/
/*
* Demonstrates explicit CUDA Graph construction using the unified cudaGraphAddNode API.
*
* Nodes and edges are added one at a time to build this graph:
*
* memcpy (H2D) -> reduce -> reduceFinal -> memcpy (D2H) -> host callback
*
* The workload is a two-pass reduction: an input float vector is reduced to
* per-block partial sums (reduce), then to a single double result (reduceFinal).
* The graph is instantiated once and launched GRAPH_LAUNCH_ITERATIONS times,
* then cloned and launched again.
*/
#include "simpleCudaGraphs.cuh"
#include <cuda_runtime.h>
#include <cstdio>
#include <vector>
#define GRAPH_LAUNCH_ITERATIONS 3
void cudaGraphsManual(float *inputVec_h,
float *inputVec_d,
double *outputVec_d,
double *result_d,
size_t inputSize,
size_t numOfBlocks)
{
cudaStream_t streamForGraph;
cudaGraph_t graph;
std::vector<cudaGraphNode_t> nodeDependencies;
cudaGraphNode_t memcpyNode, kernelNode;
double result_h = 0.0;
cudaStreamCreate(&streamForGraph);
// cudaGraphAddNode is the unified node-creation API: one call for every node type,
// driven by a cudaGraphNodeParams struct (a .type tag + a union of per-type params).
// It replaces the previously used cudaGraphAddMemcpyNode/cudaGraphAddKernelNode calls. The struct
// has reserved fields that must be zero, so it is re-zeroed with "= {}" before each node below.
cudaGraphNodeParams nodeParams = {};
cudaMemcpy3DParms memcpyParams = {0};
memcpyParams.srcArray = NULL;
memcpyParams.srcPos = make_cudaPos(0, 0, 0);
memcpyParams.srcPtr = make_cudaPitchedPtr(inputVec_h, sizeof(float) * inputSize, inputSize, 1);
memcpyParams.dstArray = NULL;
memcpyParams.dstPos = make_cudaPos(0, 0, 0);
memcpyParams.dstPtr = make_cudaPitchedPtr(inputVec_d, sizeof(float) * inputSize, inputSize, 1);
memcpyParams.extent = make_cudaExtent(sizeof(float) * inputSize, 1, 1);
memcpyParams.kind = cudaMemcpyHostToDevice;
// Create an empty graph; nodes and edges will be added below.
cudaGraphCreate(&graph, 0);
// Node 1: H2D memcpy — no dependencies (NULL, 0), so it can start immediately.
// For a memcpy node the cudaMemcpy3DParms goes into nodeParams.memcpy.copyParams
// (the .memcpy union member is a wrapper struct, so the copy descriptor nests one level deeper).
nodeParams = {};
nodeParams.type = cudaGraphNodeTypeMemcpy;
nodeParams.memcpy.copyParams = memcpyParams;
cudaGraphAddNode(&memcpyNode, graph, NULL, /*dependencyData=*/NULL, 0, &nodeParams);
// Make the next node wait for this memcpy to finish before starting.
nodeDependencies.push_back(memcpyNode);
void *kernelArgs[4] = {(void *)&inputVec_d, (void *)&outputVec_d, &inputSize, &numOfBlocks};
// Node 2: first reduction kernel — depends on the H2D memcpy completing.
// Kernel params are set directly on the .kernel union member.
nodeParams = {};
nodeParams.type = cudaGraphNodeTypeKernel;
nodeParams.kernel.func = (void *)reduce;
nodeParams.kernel.gridDim = dim3(numOfBlocks, 1, 1);
nodeParams.kernel.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
nodeParams.kernel.sharedMemBytes = 0;
nodeParams.kernel.kernelParams = (void **)kernelArgs;
nodeParams.kernel.extra = NULL;
cudaGraphAddNode(
&kernelNode, graph, nodeDependencies.data(), /*dependencyData=*/NULL, nodeDependencies.size(), &nodeParams);
// Move dependency forward: the next node waits for this kernel.
nodeDependencies.clear();
nodeDependencies.push_back(kernelNode);
void *kernelArgs2[3] = {(void *)&outputVec_d, (void *)&result_d, &numOfBlocks};
// Node 3: final reduction kernel — depends on Node 2.
nodeParams = {};
nodeParams.type = cudaGraphNodeTypeKernel;
nodeParams.kernel.func = (void *)reduceFinal;
nodeParams.kernel.gridDim = dim3(1, 1, 1);
nodeParams.kernel.blockDim = dim3(THREADS_PER_BLOCK, 1, 1);
nodeParams.kernel.sharedMemBytes = 0;
nodeParams.kernel.kernelParams = kernelArgs2;
nodeParams.kernel.extra = NULL;
cudaGraphAddNode(
&kernelNode, graph, nodeDependencies.data(), /*dependencyData=*/NULL, nodeDependencies.size(), &nodeParams);
nodeDependencies.clear();
nodeDependencies.push_back(kernelNode);
memset(&memcpyParams, 0, sizeof(memcpyParams));
memcpyParams.srcArray = NULL;
memcpyParams.srcPos = make_cudaPos(0, 0, 0);
memcpyParams.srcPtr = make_cudaPitchedPtr(result_d, sizeof(double), 1, 1);
memcpyParams.dstArray = NULL;
memcpyParams.dstPos = make_cudaPos(0, 0, 0);
memcpyParams.dstPtr = make_cudaPitchedPtr(&result_h, sizeof(double), 1, 1);
memcpyParams.extent = make_cudaExtent(sizeof(double), 1, 1);
memcpyParams.kind = cudaMemcpyDeviceToHost;
// Node 4: D2H memcpy — copies the scalar result back to the host.
// Again the copy descriptor nests in nodeParams.memcpy.copyParams.
nodeParams = {};
nodeParams.type = cudaGraphNodeTypeMemcpy;
nodeParams.memcpy.copyParams = memcpyParams;
cudaGraphAddNode(&memcpyNode, graph, nodeDependencies.data(), /*dependencyData=*/NULL, nodeDependencies.size(), &nodeParams);
nodeDependencies.clear();
nodeDependencies.push_back(memcpyNode);
cudaGraphNode_t hostNode;
callBackData_t hostFnData;
hostFnData.data = &result_h;
hostFnData.fn_name = "cudaGraphsManual";
// Node 5: host callback — runs on the CPU after the D2H copy completes.
// The .host member is cudaHostNodeParamsV2 (fn + userData, plus a syncMode field
// left at 0 by the zero-init above).
nodeParams = {};
nodeParams.type = cudaGraphNodeTypeHost;
nodeParams.host.fn = myHostNodeCallback;
nodeParams.host.userData = &hostFnData;
cudaGraphAddNode(&hostNode, graph, nodeDependencies.data(), /*dependencyData=*/NULL, nodeDependencies.size(), &nodeParams);
size_t numNodes = 0;
cudaGraphGetNodes(graph, NULL, &numNodes);
printf("Graph node count: %zu\n", numNodes);
// Instantiate: compile the graph into an executable form (one-time cost).
// This is where CUDA optimizes the schedule; repeated launches reuse this.
cudaGraphExec_t graphExec;
cudaGraphInstantiate(&graphExec, graph, NULL, NULL, 0);
// Demonstrates cudaGraphClone — in practice, cloning is useful when multiple CPU
// threads need to launch the same graph concurrently, each with its own independent graphExec.
cudaGraph_t clonedGraph;
cudaGraphExec_t clonedGraphExec;
cudaGraphClone(&clonedGraph, graph);
cudaGraphInstantiate(&clonedGraphExec, clonedGraph, NULL, NULL, 0);
// Refill the host input before each launch so the graph's H2D copy processes
// new data every time — one instantiated graph reused for different data.
// The per-iteration sync ensures that copy finishes before we overwrite the buffer.
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
init_input(inputVec_h, inputSize);
cudaGraphLaunch(graphExec, streamForGraph);
cudaStreamSynchronize(streamForGraph);
}
printf("\nCloned graph:\n");
for (int i = 0; i < GRAPH_LAUNCH_ITERATIONS; i++) {
init_input(inputVec_h, inputSize);
cudaGraphLaunch(clonedGraphExec, streamForGraph);
cudaStreamSynchronize(streamForGraph);
}
cudaGraphExecDestroy(graphExec);
cudaGraphExecDestroy(clonedGraphExec);
cudaGraphDestroy(graph);
cudaGraphDestroy(clonedGraph);
cudaStreamDestroy(streamForGraph);
}
int main()
{
size_t size = 1 << 24; // number of elements to reduce, 16M elements
size_t maxBlocks = 512;
int devID = 0;
cudaSetDevice(devID);
int major, minor, smCount;
cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID);
cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID);
cudaDeviceGetAttribute(&smCount, cudaDevAttrMultiProcessorCount, devID);
printf("GPU Device %d: compute capability %d.%d, %d SMs\n\n", devID, major, minor, smCount);
printf("Reducing %zu elements\n", size);
printf("Threads per block : %d\n", THREADS_PER_BLOCK);
printf("Graph launch iterations: %d\n\n", GRAPH_LAUNCH_ITERATIONS);
float *inputVec_h = NULL, *inputVec_d = NULL;
double *outputVec_d = NULL, *result_d = NULL;
cudaMallocHost(&inputVec_h, sizeof(float) * size);
cudaMalloc(&inputVec_d, sizeof(float) * size);
cudaMalloc(&outputVec_d, sizeof(double) * maxBlocks);
cudaMalloc(&result_d, sizeof(double));
printf("=== Explicit Graph Construction ===\n");
cudaGraphsManual(inputVec_h, inputVec_d, outputVec_d, result_d, size, maxBlocks);
cudaFree(inputVec_d);
cudaFree(outputVec_d);
cudaFree(result_d);
cudaFreeHost(inputVec_h);
return EXIT_SUCCESS;
}

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,23 +1,18 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(tf32TensorCoreGemm LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# This sample is not supported on QNX
@@ -26,16 +21,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
return()
endif()
# Source file
# Add target for tf32TensorCoreGemm
add_executable(tf32TensorCoreGemm tf32TensorCoreGemm.cu)
target_compile_options(tf32TensorCoreGemm PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(tf32TensorCoreGemm PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(tf32TensorCoreGemm PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()

View File

@@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/../../../Common"
],
"defines": [],
"compilerPath": "/usr/local/cuda/bin/nvcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"nvidia.nsight-vscode-edition",
"ms-vscode.cpptools",
"ms-vscode.makefile-tools"
]
}

View File

@@ -1,34 +1,25 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/DetectCudaArch.cmake")
if(SAMPLE_SKIP_BUILD)
return()
endif()
project(warpAggregatedAtomicsCG LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add target for warpAggregatedAtomicsCG
add_executable(warpAggregatedAtomicsCG warpAggregatedAtomicsCG.cu)
target_compile_options(warpAggregatedAtomicsCG PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(warpAggregatedAtomicsCG PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(warpAggregatedAtomicsCG PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
include(InstallSamples)
setup_samples_install()