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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
871 changed files with 6843 additions and 321849 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ build
build-*/ build-*/
test-results*/ test-results*/
.vs .vs
.vscode
.clangd .clangd
test test
settings.json settings.json

View File

@ -1,5 +1,29 @@
## Changelog ## Changelog
### CUDA 13.4
* Removed obsolete samples `simpleHyperQ`, `simpleOccupancy`, `mergeSort`, `simpleTemplates`, `template`, `p2pBandwidthLatencyTest`.
* Removed redundant `_nvrtc` sample variants (`clock_nvrtc`, `matrixMul_nvrtc`, `simpleAssert_nvrtc`, `simpleAtomicIntrinsics_nvrtc`, `inlinePTX_nvrtc`, `binomialOptions_nvrtc`, `BlackScholes_nvrtc`, `quasirandomGenerator_nvrtc`); `vectorAdd_nvrtc` remains as the canonical NVRTC example.
* Rewrote `cpp/0_Introduction/simpleMultiGPU` to replace the hand-written reduction with `cub::BlockReduce` and the SDK stopwatch timer with CUDA events, removed helper header dependencies and merged `simpleMultiGPU.h` into the `.cu` for a single-file sample, modernized the code to C++17 (`std::vector`, `constexpr`), and added a minimum two-GPU check; updated README accordingly.
* Modernized `cpp/3_CUDA_Features/simpleCudaGraphs`: dropped `helper_cuda.h`/`cooperative_groups.h`; used `cub::BlockReduce`; migrated to the unified `cudaGraphAddNode` API; split into `simpleCudaGraphs_explicit` and `simpleCudaGraphs_capture` sharing `simpleCudaGraphs.cuh`; added a graph-reuse demo (fresh input each launch); rewrote README.
* Rewrote `cpp/0_Introduction/simpleAtomicIntrinsics` to show race conditions by comparing non-atomic vs atomic kernels (`atomicAdd`, `atomicMax`, `atomicCAS`), removed helper header dependencies; updated README accordingly.
* Reorganized CMake build system for all C++ samples: centralized GPU architecture detection (`DetectCudaArch.cmake`) and common build setup (`CudaSampleCommon.cmake`) into shared modules. Samples with restricted arch support now declare a `SAMPLE_DISALLOW_ARCHS` list instead of hardcoding their own arch list, and are gracefully skipped at configure time when the requested arch is unsupported.
* Added `sm_103` to the default set of GPU architectures the C++ samples build for.
* Added `sm_107` to the default set of GPU architectures the C++ samples build for.
* Rewrote `cpp/0_Introduction/simpleCallback` to replace the deprecated `cudaStreamAddCallback` with `cudaLaunchHostFunc`, replaced the `multithreading.h/.cpp` helpers with standard C++ `std::thread`, and simplified to a single-GPU, single-workload C++17 example; updated README accordingly.
* Rewrote `cpp/0_Introduction/simpleStreams` to simplify code and remove helper header dependencies; updated README accordingly.
* Added `python/2_CoreConcepts/persistentProgramCache` to demonstrate persisting and reusing compiled CUDA artifacts with `cuda.core` and `FileStreamProgramCache`.
* Updated `cpp/0_Introduction/clock` to replace the manual shared-memory tree reduction with `cub::BlockReduce` min-reduction, removed dependency on `helper_cuda.h` and `helper_functions.h`, and updated README.
* Rewrote `cpp/0_Introduction/vectorAdd` to match the corresponding example in the CUDA Programming Guide. The sample now uses Unified Memory (`cudaMallocManaged`) instead of explicit `cudaMalloc`/`cudaMemcpy`.
* Restructured the `cpp/0_Introduction/simplePrintf` README with newer style and updated sample code by removing helper dependency.
* Updated the `cpp/0_Introduction/simpleAssert` README to newer style, simplified code for better understanding.
* Added `cpp/3_CUDA_Features/dmabufInterop` - a Linux-only CUDA dma-buf interoperability sample demonstrating three scenarios in a single binary: (1) same-process round-trip export/import, (2) cross-process IPC via `fork()` + `SCM_RIGHTS`, and (3) cross-GPU sharing across processes (self-skips on systems without a qualifying GPU pair).
* Removed the unnecessary `set(CMAKE_POSITION_INDEPENDENT_CODE ON)` from the C++ sample `CMakeLists.txt` files.
* Removed `CUDA_SEPARABLE_COMPILATION ON` from C++ samples that don't require relocatable device code (kept for the CDP samples).
* Removed 26 math library samples from `cpp/4_CUDA_Libraries/` that are maintained in the [CUDA Library Samples](https://github.com/NVIDIA/CUDALibrarySamples) repository: cuBLAS (`simpleCUBLAS`, `simpleCUBLAS_LU`, `simpleCUBLASXT`, `matrixMulCUBLAS`, `batchCUBLAS`), cuFFT (`simpleCUFFT`, `simpleCUFFT_MGPU`, `simpleCUFFT_2d_MGPU`, `simpleCUFFT_callback`), cuRAND (`MersenneTwisterGP11213`), cuSOLVER (`cuSolverDn_LinearSolver`, `cuSolverRf`, `cuSolverSp_LinearSolver`, `cuSolverSp_LowlevelCholesky`, `cuSolverSp_LowlevelQR`), cuSPARSE (`conjugateGradient`, `conjugateGradientPrecond`, `conjugateGradientUM`), NPP (`boxFilterNPP`, `cannyEdgeDetectorNPP`, `FilterBorderControlNPP`, `freeImageInteropNPP`, `histEqualizationNPP`, `watershedSegmentationNPP`), and nvJPEG (`nvJPEG`, `nvJPEG_encoder`).
* Lifted the LLVM 14 upper bound on `cpp/7_libNVVM/cuda-c-linking`, which now builds against LLVM 15 and newer.
* Added samples for locality domains in `cpp/3_CUDA_FEATURES/localityDomains` and `cpp/3_CUDA_FEATURES/localityDomainsDrv`.
* Added Windows on Arm support: `cpp/5_Domain_Specific/marchingCubes` now detects the `glew32` GLEW library name used on Windows on Arm, and `cpp/7_libNVVM` searches the `nvvm/lib/arm64` directory for libNVVM.
### CUDA 13.3 ### CUDA 13.3
* Added **CUDA Tile C++** samples under `cpp/9_CUDA_Tile`. * Added **CUDA Tile C++** samples under `cpp/9_CUDA_Tile`.
* Added a set of **CCCL 3.3 feature samples** under `cpp/4_CUDA_Libraries/`, each built against CCCL fetched via CPM (pinned to v3.3.3, with an optional `CCCL_SOURCE_DIR` override): * Added a set of **CCCL 3.3 feature samples** under `cpp/4_CUDA_Libraries/`, each built against CCCL fetched via CPM (pinned to v3.3.3, with an optional `CCCL_SOURCE_DIR` override):

View File

@ -1,33 +1,31 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/CudaSampleArchs.cmake)
# Default to all supported architectures if the user does not specify.
# Gated on CUDA_SAMPLES_ARCHS_DEFAULTED rather than CMAKE_CUDA_ARCHITECTURES so this
# decision is made once (on the first configure) and does not flip on reconfigure,
# when CMAKE_CUDA_ARCHITECTURES is already defined from our own cached default.
# The decision is revisited when the list itself moves, which the user can do with -D
# on any later configure of the same build directory. Keep the list each configure
# ends up with, so that such a change is told apart from our own cached default.
if(NOT DEFINED CUDA_SAMPLES_ARCHS_DEFAULTED)
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
list(JOIN CUDA_SAMPLES_MASTER_ARCHS ";" _default_archs)
set(CMAKE_CUDA_ARCHITECTURES "${_default_archs}" CACHE STRING "CUDA architectures")
unset(_default_archs)
set(CUDA_SAMPLES_ARCHS_DEFAULTED TRUE CACHE INTERNAL "")
else()
set(CUDA_SAMPLES_ARCHS_DEFAULTED FALSE CACHE INTERNAL "")
endif()
elseif(NOT "${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "${CUDA_SAMPLES_LAST_CONFIGURED_ARCHS}")
set(CUDA_SAMPLES_ARCHS_DEFAULTED FALSE CACHE INTERNAL "")
endif()
set(CUDA_SAMPLES_LAST_CONFIGURED_ARCHS "${CMAKE_CUDA_ARCHITECTURES}" CACHE INTERNAL "")
project(cuda-samples LANGUAGES C CXX CUDA) project(cuda-samples LANGUAGES C CXX CUDA)
find_package(CUDAToolkit REQUIRED) include(cmake/CudaSampleCommon.cmake)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED 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()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --extended-lambda")
# Add MSVC-specific flags for standard-conforming preprocessor (required for CCCL)
if(MSVC)
add_compile_options($<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/Zc:preprocessor>)
endif()
# Include installation configuration before processing samples
include(cmake/InstallSamples.cmake)
add_subdirectory(cpp) add_subdirectory(cpp)

View File

@ -1,197 +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.
*/
#ifndef NV_UTIL_NPP_EXCEPTIONS_H
#define NV_UTIL_NPP_EXCEPTIONS_H
#include <string>
#include <sstream>
#include <iostream>
/// All npp related C++ classes are put into the npp namespace.
namespace npp
{
/// Exception base class.
/// This exception base class will be used for everything C++ throught
/// the NPP project.
/// The exception contains a string message, as well as data fields for a string
/// containing the name of the file as well as the line number where the exception was thrown.
/// The easiest way of throwing exceptions and providing filename and line number is
/// to use one of the ASSERT macros defined for that purpose.
class Exception
{
public:
/// Constructor.
/// \param rMessage A message with information as to why the exception was thrown.
/// \param rFileName The name of the file where the exception was thrown.
/// \param nLineNumber Line number in the file where the exception was thrown.
explicit
Exception(const std::string &rMessage = "", const std::string &rFileName = "", unsigned int nLineNumber = 0)
: sMessage_(rMessage), sFileName_(rFileName), nLineNumber_(nLineNumber)
{ };
Exception(const Exception &rException)
: sMessage_(rException.sMessage_), sFileName_(rException.sFileName_), nLineNumber_(rException.nLineNumber_)
{ };
virtual
~Exception()
{ };
/// Get the exception's message.
const
std::string &
message()
const
{
return sMessage_;
}
/// Get the exception's file info.
const
std::string &
fileName()
const
{
return sFileName_;
}
/// Get the exceptions's line info.
unsigned int
lineNumber()
const
{
return nLineNumber_;
}
/// Create a clone of this exception.
/// This creates a new Exception object on the heap. It is
/// the responsibility of the user of this function to free this memory
/// (delete x).
virtual
Exception *
clone()
const
{
return new Exception(*this);
}
/// Create a single string with all the exceptions information.
/// The virtual toString() method is used by the operator<<()
/// so that all exceptions derived from this base-class can print
/// their full information correctly even if a reference to their
/// exact type is not had at the time of printing (i.e. the basic
/// operator<<() is used).
virtual
std::string
toString()
const
{
std::ostringstream oOutputString;
oOutputString << fileName() << ":" << lineNumber() << ": " << message();
return oOutputString.str();
}
private:
std::string sMessage_; ///< Message regarding the cause of the exception.
std::string sFileName_; ///< Name of the file where the exception was thrown.
unsigned int nLineNumber_; ///< Line number in the file where the exception was thrown
};
/// Output stream inserter for Exception.
/// \param rOutputStream The stream the exception information is written to.
/// \param rException The exception that's being written.
/// \return Reference to the output stream being used.
std::ostream &
operator << (std::ostream &rOutputStream, const Exception &rException)
{
rOutputStream << rException.toString();
return rOutputStream;
}
/// Basic assert macro.
/// This macro should be used to enforce any kind of pre or post conditions.
/// Unlike the C-runtime assert macro, this macro does not abort execution, but throws
/// a C++ exception. The exception is automatically filled with information about the failing
/// condition, the filename and line number where the exception was thrown.
/// \note The macro is written in such a way that omitting a semicolon after its usage
/// causes a compiler error. The correct way to invoke this macro is:
/// NPP_ASSERT(n < MAX);
#define NPP_ASSERT(C) do {if (!(C)) throw npp::Exception(#C " assertion faild!", __FILE__, __LINE__);} while(false)
// ASSERT macro.
// Same functionality as the basic assert macro with the added ability to pass
// a message M. M should be a string literal.
// Note: Never use code inside ASSERT() that causes a side-effect ASSERT macros may get compiled
// out in release mode.
#define NPP_ASSERT_MSG(C, M) do {if (!(C)) throw npp::Exception(#C " assertion faild! Message: " M, __FILE__, __LINE__);} while(false)
#ifdef _DEBUG
/// Basic debug assert macro.
/// This macro is identical in every respect to NPP_ASSERT(C) but it does get compiled to a
/// no-op in release builds. It is therefor of utmost importance to not put statements into
/// this macro that cause side effects required for correct program execution.
#define NPP_DEBUG_ASSERT(C) do {if (!(C)) throw npp::Exception(#C " debug assertion faild!", __FILE__, __LINE__);} while(false)
#else
#define NPP_DEBUG_ASSERT(C)
#endif
/// ASSERT for null-pointer test.
/// It is safe to put code with side effects into this macro. Also: This macro never
/// gets compiled to a no-op because resource allocation may fail based on external causes not under
/// control of a software developer.
#define NPP_ASSERT_NOT_NULL(P) do {if ((P) == 0) throw npp::Exception(#P " not null assertion faild!", __FILE__, __LINE__);} while(false)
/// Macro for flagging methods as not implemented.
/// The macro throws an exception with a message that an implementation was missing
#define NPP_NOT_IMPLEMENTED() do {throw npp::Exception("Implementation missing!", __FILE__, __LINE__);} while(false)
/// Macro for checking error return code of CUDA (runtime) calls.
/// This macro never gets disabled.
#define NPP_CHECK_CUDA(S) do {cudaError_t eCUDAResult; \
eCUDAResult = S; \
if (eCUDAResult != cudaSuccess) std::cout << "NPP_CHECK_CUDA - eCUDAResult = " << eCUDAResult << std::endl; \
NPP_ASSERT(eCUDAResult == cudaSuccess);} while (false)
/// Macro for checking error return code for NPP calls.
#define NPP_CHECK_NPP(S) do {NppStatus eStatusNPP; \
eStatusNPP = S; \
if (eStatusNPP != NPP_SUCCESS) std::cout << "NPP_CHECK_NPP - eStatusNPP = " << _cudaGetErrorEnum(eStatusNPP) << "("<< eStatusNPP << ")" << std::endl; \
NPP_ASSERT(eStatusNPP == NPP_SUCCESS);} while (false)
/// Macro for checking error return codes from cuFFT calls.
#define NPP_CHECK_CUFFT(S) do {cufftResult eCUFFTResult; \
eCUFFTResult = S; \
if (eCUFFTResult != NPP_SUCCESS) std::cout << "NPP_CHECK_CUFFT - eCUFFTResult = " << eCUFFTResult << std::endl; \
NPP_ASSERT(eCUFFTResult == CUFFT_SUCCESS);} while (false)
} // npp namespace
#endif // NV_UTIL_NPP_EXCEPTIONS_H

View File

@ -1,155 +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.
*/
#ifndef NV_UTIL_NPP_IMAGE_H
#define NV_UTIL_NPP_IMAGE_H
#include <cstddef>
namespace npp
{
class Image
{
public:
struct Size
{
unsigned int nWidth;
unsigned int nHeight;
Size() : nWidth(0), nHeight(0)
{ };
Size(unsigned int nWidthNew, unsigned nHeightNew) : nWidth(nWidthNew), nHeight(nHeightNew)
{ };
Size(const Size &rSize) : nWidth(rSize.nWidth), nHeight(rSize.nHeight)
{ };
Size &
operator= (const Size &rSize)
{
if (&rSize == this)
{
return *this;
}
nWidth = rSize.nWidth;
nHeight = rSize.nHeight;
return *this;
}
void
swap(Size &rSize)
{
unsigned int nTemp;
nTemp = nWidth;
nWidth = rSize.nWidth;
rSize.nWidth = nTemp;
nTemp = nHeight;
nHeight = rSize.nHeight;
rSize.nHeight = nTemp;
}
};
Image()
{ };
Image(unsigned int nWidth, unsigned int nHeight) : oSize_(nWidth, nHeight)
{ };
Image(const Image::Size &rSize) : oSize_(rSize)
{ };
Image(const Image &rImage) : oSize_(rImage.oSize_)
{ };
virtual
~Image()
{ };
Image &
operator= (const Image &rImage)
{
if (&rImage == this)
{
return *this;
}
oSize_ = rImage.oSize_;
return *this;
};
unsigned int
width()
const
{
return oSize_.nWidth;
}
unsigned int
height()
const
{
return oSize_.nHeight;
}
Size
size()
const
{
return oSize_;
}
void
swap(Image &rImage)
{
oSize_.swap(rImage.oSize_);
}
private:
Size oSize_;
};
bool
operator== (const Image::Size &rFirst, const Image::Size &rSecond)
{
return rFirst.nWidth == rSecond.nWidth && rFirst.nHeight == rSecond.nHeight;
}
bool
operator!= (const Image::Size &rFirst, const Image::Size &rSecond)
{
return rFirst.nWidth != rSecond.nWidth || rFirst.nHeight != rSecond.nHeight;
}
} // npp namespace
#endif // NV_UTIL_NPP_IMAGE_H

View File

@ -1,80 +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.
*/
#ifndef NV_UTIL_NPP_IMAGE_ALLOCATORS_CPU_H
#define NV_UTIL_NPP_IMAGE_ALLOCATORS_CPU_H
#include "Exceptions.h"
namespace npp
{
template <typename D, size_t N>
class ImageAllocatorCPU
{
public:
static
D *
Malloc2D(unsigned int nWidth, unsigned int nHeight, unsigned int *pPitch)
{
NPP_ASSERT(nWidth * nHeight > 0);
D *pResult = new D[nWidth * N * nHeight];
*pPitch = nWidth * sizeof(D) * N;
return pResult;
};
static
void
Free2D(D *pPixels)
{
delete[] pPixels;
};
static
void
Copy2D(D *pDst, size_t nDstPitch, const D *pSrc, size_t nSrcPitch, size_t nWidth, size_t nHeight)
{
const void *pSrcLine = pSrc;
void *pDstLine = pDst;
for (size_t iLine = 0; iLine < nHeight; ++iLine)
{
// copy one line worth of data
memcpy(pDst, pSrc, nWidth * N * sizeof(D));
// move data pointers to next line
pDst += nDstPitch;
pSrc += nSrcPitch;
}
};
};
} // npp namespace
#endif // NV_UTIL_NPP_IMAGE_ALLOCATORS_CPU_H

File diff suppressed because it is too large Load Diff

View File

@ -1,149 +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.
*/
#ifndef NV_UTIL_NPP_IMAGE_IO_H
#define NV_UTIL_NPP_IMAGE_IO_H
#include "ImagesCPU.h"
#include "ImagesNPP.h"
#include "FreeImage.h"
#include "Exceptions.h"
#include <string>
#include "string.h"
// Error handler for FreeImage library.
// In case this handler is invoked, it throws an NPP exception.
void
FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif, const char *zMessage)
{
throw npp::Exception(zMessage);
}
namespace npp
{
// Load a gray-scale image from disk.
void
loadImage(const std::string &rFileName, ImageCPU_8u_C1 &rImage)
{
// set your own FreeImage error handler
FreeImage_SetOutputMessage(FreeImageErrorHandler);
FREE_IMAGE_FORMAT eFormat = FreeImage_GetFileType(rFileName.c_str());
// no signature? try to guess the file format from the file extension
if (eFormat == FIF_UNKNOWN)
{
eFormat = FreeImage_GetFIFFromFilename(rFileName.c_str());
}
NPP_ASSERT(eFormat != FIF_UNKNOWN);
// check that the plugin has reading capabilities ...
FIBITMAP *pBitmap;
if (FreeImage_FIFSupportsReading(eFormat))
{
pBitmap = FreeImage_Load(eFormat, rFileName.c_str());
}
NPP_ASSERT(pBitmap != 0);
// make sure this is an 8-bit single channel image
NPP_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK);
NPP_ASSERT(FreeImage_GetBPP(pBitmap) == 8);
// create an ImageCPU to receive the loaded image data
ImageCPU_8u_C1 oImage(FreeImage_GetWidth(pBitmap), FreeImage_GetHeight(pBitmap));
// Copy the FreeImage data into the new ImageCPU
unsigned int nSrcPitch = FreeImage_GetPitch(pBitmap);
const Npp8u *pSrcLine = FreeImage_GetBits(pBitmap) + nSrcPitch * (FreeImage_GetHeight(pBitmap) -1);
Npp8u *pDstLine = oImage.data();
unsigned int nDstPitch = oImage.pitch();
for (size_t iLine = 0; iLine < oImage.height(); ++iLine)
{
memcpy(pDstLine, pSrcLine, oImage.width() * sizeof(Npp8u));
pSrcLine -= nSrcPitch;
pDstLine += nDstPitch;
}
// swap the user given image with our result image, effecively
// moving our newly loaded image data into the user provided shell
oImage.swap(rImage);
}
// Save an gray-scale image to disk.
void
saveImage(const std::string &rFileName, const ImageCPU_8u_C1 &rImage)
{
// create the result image storage using FreeImage so we can easily
// save
FIBITMAP *pResultBitmap = FreeImage_Allocate(rImage.width(), rImage.height(), 8 /* bits per pixel */);
NPP_ASSERT_NOT_NULL(pResultBitmap);
unsigned int nDstPitch = FreeImage_GetPitch(pResultBitmap);
Npp8u *pDstLine = FreeImage_GetBits(pResultBitmap) + nDstPitch * (rImage.height()-1);
const Npp8u *pSrcLine = rImage.data();
unsigned int nSrcPitch = rImage.pitch();
for (size_t iLine = 0; iLine < rImage.height(); ++iLine)
{
memcpy(pDstLine, pSrcLine, rImage.width() * sizeof(Npp8u));
pSrcLine += nSrcPitch;
pDstLine -= nDstPitch;
}
// now save the result image
bool bSuccess;
bSuccess = FreeImage_Save(FIF_PGM, pResultBitmap, rFileName.c_str(), 0) == TRUE;
NPP_ASSERT_MSG(bSuccess, "Failed to save result image.");
}
// Load a gray-scale image from disk.
void
loadImage(const std::string &rFileName, ImageNPP_8u_C1 &rImage)
{
ImageCPU_8u_C1 oImage;
loadImage(rFileName, oImage);
ImageNPP_8u_C1 oResult(oImage);
rImage.swap(oResult);
}
// Save an gray-scale image to disk.
void
saveImage(const std::string &rFileName, const ImageNPP_8u_C1 &rImage)
{
ImageCPU_8u_C1 oHostImage(rImage.size());
// copy the device result data
rImage.copyTo(oHostImage.data(), oHostImage.pitch());
saveImage(rFileName, oHostImage);
}
}
#endif // NV_UTIL_NPP_IMAGE_IO_H

View File

@ -1,171 +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.
*/
#ifndef NV_UTIL_NPP_IMAGE_PACKED_H
#define NV_UTIL_NPP_IMAGE_PACKED_H
#include "Image.h"
#include "Pixel.h"
namespace npp
{
template<typename D, size_t N, class A>
class ImagePacked: public npp::Image
{
public:
typedef npp::Pixel<D, N> tPixel;
typedef D tData;
static const size_t gnChannels = N;
typedef npp::Image::Size tSize;
ImagePacked(): aPixels_(0)
, nPitch_(0)
{
;
}
ImagePacked(unsigned int nWidth, unsigned int nHeight): Image(nWidth, nHeight)
, aPixels_(0)
, nPitch_(0)
{
aPixels_ = A::Malloc2D(width(), height(), &nPitch_);
}
ImagePacked(unsigned int nWidth, unsigned int nHeight, bool bTight): Image(nWidth, nHeight)
, aPixels_(0)
, nPitch_(0)
{
aPixels_ = A::Malloc2D(width(), height(), &nPitch_, bTight);
}
ImagePacked(const tSize &rSize): Image(rSize)
, aPixels_(0)
, nPitch_(0)
{
aPixels_ = A::Malloc2D(width(), height(), &nPitch_);
}
ImagePacked(const ImagePacked<D, N, A> &rImage): Image(rImage)
, aPixels_(0)
, nPitch_(rImage.pitch())
{
aPixels_ = A::Malloc2D(width(), height(), &nPitch_);
A::Copy2D(aPixels_, nPitch_, rImage.pixels(), rImage.pitch(), width(), height());
}
virtual
~ImagePacked()
{
A::Free2D(aPixels_);
}
ImagePacked &
operator= (const ImagePacked<D, N, A> &rImage)
{
// in case of self-assignment
if (&rImage == this)
{
return *this;
}
A::Free2D(aPixels_);
aPixels_ = 0;
nPitch_ = 0;
// assign parent class's data fields (width, height)
Image::operator =(rImage);
aPixels_ = A::Malloc2D(width(), height(), &nPitch_);
A::Copy2D(aPixels_, nPitch_, rImage.data(), rImage.pitch(), width(), height());
return *this;
}
unsigned int
pitch()
const
{
return nPitch_;
}
/// Get a pointer to the pixel array.
/// The result pointer can be offset to pixel at position (x, y) and
/// even negative offsets are allowed.
/// \param nX Horizontal pointer/array offset.
/// \param nY Vertical pointer/array offset.
/// \return Pointer to the pixel array (or first pixel in array with coordinates (nX, nY).
tPixel *
pixels(int nX = 0, int nY = 0)
{
return reinterpret_cast<tPixel *>(reinterpret_cast<unsigned char *>(aPixels_) + nY * pitch() + nX * gnChannels * sizeof(D));
}
const
tPixel *
pixels(int nX = 0, int nY = 0)
const
{
return reinterpret_cast<const tPixel *>(reinterpret_cast<unsigned char *>(aPixels_) + nY * pitch() + nX * gnChannels * sizeof(D));
}
D *
data(int nX = 0, int nY = 0)
{
return reinterpret_cast<D *>(pixels(nX, nY));
}
const
D *
data(int nX = 0, int nY = 0)
const
{
return reinterpret_cast<const D *>(pixels(nX, nY));
}
void
swap(ImagePacked<D, N, A> &rImage)
{
Image::swap(rImage);
tData *aTemp = aPixels_;
aPixels_ = rImage.aPixels_;
rImage.aPixels_ = aTemp;
unsigned int nTemp = nPitch_;
nPitch_ = rImage.nPitch_;
rImage.nPitch_ = nTemp;
}
private:
D *aPixels_;
unsigned int nPitch_;
};
} // npp namespace
#endif // NV_IMAGE_IPP_H

View File

@ -1,121 +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.
*/
#ifndef NV_UTIL_NPP_IMAGES_CPU_H
#define NV_UTIL_NPP_IMAGES_CPU_H
#include "ImagePacked.h"
#include "ImageAllocatorsCPU.h"
#include "Exceptions.h"
#include <npp.h>
namespace npp
{
template<typename D, unsigned int N, class A>
class ImageCPU: public npp::ImagePacked<D, N, A>
{
public:
ImageCPU()
{
;
}
ImageCPU(unsigned int nWidth, unsigned int nHeight): ImagePacked<D, N, A>(nWidth, nHeight)
{
;
}
explicit
ImageCPU(const npp::Image::Size &rSize): ImagePacked<D, N, A>(rSize)
{
;
}
ImageCPU(const ImageCPU<D, N, A> &rImage): Image(rImage)
{
;
}
virtual
~ImageCPU()
{
;
}
ImageCPU &
operator= (const ImageCPU<D, N, A> &rImage)
{
ImagePacked<D, N, A>::operator= (rImage);
return *this;
}
npp::Pixel<D, N> &
operator()(unsigned int iX, unsigned int iY)
{
return *ImagePacked<D, N, A>::pixels(iX, iY);
}
npp::Pixel<D, N>
operator()(unsigned int iX, unsigned int iY)
const
{
return *ImagePacked<D, N, A>::pixels(iX, iY);
}
};
typedef ImageCPU<Npp8u, 1, npp::ImageAllocatorCPU<Npp8u, 1> > ImageCPU_8u_C1;
typedef ImageCPU<Npp8u, 2, npp::ImageAllocatorCPU<Npp8u, 2> > ImageCPU_8u_C2;
typedef ImageCPU<Npp8u, 3, npp::ImageAllocatorCPU<Npp8u, 3> > ImageCPU_8u_C3;
typedef ImageCPU<Npp8u, 4, npp::ImageAllocatorCPU<Npp8u, 4> > ImageCPU_8u_C4;
typedef ImageCPU<Npp16u, 1, npp::ImageAllocatorCPU<Npp16u, 1> > ImageCPU_16u_C1;
typedef ImageCPU<Npp16u, 3, npp::ImageAllocatorCPU<Npp16u, 3> > ImageCPU_16u_C3;
typedef ImageCPU<Npp16u, 4, npp::ImageAllocatorCPU<Npp16u, 4> > ImageCPU_16u_C4;
typedef ImageCPU<Npp16s, 1, npp::ImageAllocatorCPU<Npp16s, 1> > ImageCPU_16s_C1;
typedef ImageCPU<Npp16s, 3, npp::ImageAllocatorCPU<Npp16s, 3> > ImageCPU_16s_C3;
typedef ImageCPU<Npp16s, 4, npp::ImageAllocatorCPU<Npp16s, 4> > ImageCPU_16s_C4;
typedef ImageCPU<Npp32s, 1, npp::ImageAllocatorCPU<Npp32s, 1> > ImageCPU_32s_C1;
typedef ImageCPU<Npp32s, 3, npp::ImageAllocatorCPU<Npp32s, 3> > ImageCPU_32s_C3;
typedef ImageCPU<Npp32s, 4, npp::ImageAllocatorCPU<Npp32s, 4> > ImageCPU_32s_C4;
typedef ImageCPU<Npp32f, 1, npp::ImageAllocatorCPU<Npp32f, 1> > ImageCPU_32f_C1;
typedef ImageCPU<Npp32f, 3, npp::ImageAllocatorCPU<Npp32f, 3> > ImageCPU_32f_C3;
typedef ImageCPU<Npp32f, 4, npp::ImageAllocatorCPU<Npp32f, 4> > ImageCPU_32f_C4;
} // npp namespace
#endif // NV_IMAGE_IPP_H

View File

@ -1,149 +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.
*/
#ifndef NV_UTIL_NPP_IMAGES_NPP_H
#define NV_UTIL_NPP_IMAGES_NPP_H
#include "Exceptions.h"
#include "ImagePacked.h"
#include "ImageAllocatorsNPP.h"
#include <cuda_runtime.h>
namespace npp
{
// forward declaration
template<typename D, unsigned int N, class A> class ImageCPU;
template<typename D, unsigned int N>
class ImageNPP: public npp::ImagePacked<D, N, npp::ImageAllocator<D, N> >
{
public:
ImageNPP()
{
;
}
ImageNPP(unsigned int nWidth, unsigned int nHeight, bool bTight = false): ImagePacked<D, N, npp::ImageAllocator<D, N> >(nWidth, nHeight, bTight)
{
;
}
ImageNPP(const npp::Image::Size &rSize): ImagePacked<D, N, npp::ImageAllocator<D, N> >(rSize)
{
;
}
ImageNPP(const ImageNPP<D, N> &rImage): Image(rImage)
{
;
}
template<class X>
explicit
ImageNPP(const ImageCPU<D, N, X> &rImage, bool bTight = false): ImagePacked<D, N, npp::ImageAllocator<D, N> >(rImage.width(), rImage.height(), bTight)
{
npp::ImageAllocator<D, N>::HostToDeviceCopy2D(ImagePacked<D, N, npp::ImageAllocator<D, N> >::data(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::pitch(),
rImage.data(),
rImage.pitch(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::width(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::height());
}
virtual
~ImageNPP()
{
;
}
ImageNPP &
operator= (const ImageNPP<D, N> &rImage)
{
ImagePacked<D, N, npp::ImageAllocator<D, N> >::operator= (rImage);
return *this;
}
void
copyTo(D *pData, unsigned int nPitch)
const
{
NPP_ASSERT((ImagePacked<D, N, npp::ImageAllocator<D, N> >::width() * sizeof(npp::Pixel<D, N>) <= nPitch));
npp::ImageAllocator<D, N>::DeviceToHostCopy2D(pData,
nPitch,
ImagePacked<D, N, npp::ImageAllocator<D, N> >::data(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::pitch(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::width(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::height());
}
void
copyFrom(D *pData, unsigned int nPitch)
{
NPP_ASSERT((ImagePacked<D, N, npp::ImageAllocator<D, N> >::width() * sizeof(npp::Pixel<D, N>) <= nPitch));
npp::ImageAllocator<D, N>::HostToDeviceCopy2D(ImagePacked<D, N, npp::ImageAllocator<D, N> >::data(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::pitch(),
pData,
nPitch,
ImagePacked<D, N, npp::ImageAllocator<D, N> >::width(),
ImagePacked<D, N, npp::ImageAllocator<D, N> >::height());
}
};
typedef ImageNPP<Npp8u, 1> ImageNPP_8u_C1;
typedef ImageNPP<Npp8u, 2> ImageNPP_8u_C2;
typedef ImageNPP<Npp8u, 3> ImageNPP_8u_C3;
typedef ImageNPP<Npp8u, 4> ImageNPP_8u_C4;
typedef ImageNPP<Npp16u, 1> ImageNPP_16u_C1;
typedef ImageNPP<Npp16u, 2> ImageNPP_16u_C2;
typedef ImageNPP<Npp16u, 3> ImageNPP_16u_C3;
typedef ImageNPP<Npp16u, 4> ImageNPP_16u_C4;
typedef ImageNPP<Npp16s, 1> ImageNPP_16s_C1;
typedef ImageNPP<Npp16s, 3> ImageNPP_16s_C3;
typedef ImageNPP<Npp16s, 4> ImageNPP_16s_C4;
typedef ImageNPP<Npp32s, 1> ImageNPP_32s_C1;
typedef ImageNPP<Npp32s, 3> ImageNPP_32s_C3;
typedef ImageNPP<Npp32s, 4> ImageNPP_32s_C4;
typedef ImageNPP<Npp32f, 1> ImageNPP_32f_C1;
typedef ImageNPP<Npp32f, 2> ImageNPP_32f_C2;
typedef ImageNPP<Npp32f, 3> ImageNPP_32f_C3;
typedef ImageNPP<Npp32f, 4> ImageNPP_32f_C4;
typedef ImageNPP<Npp64f, 1> ImageNPP_64f_C1;
typedef ImageNPP<Npp64f, 2> ImageNPP_64f_C2;
typedef ImageNPP<Npp64f, 3> ImageNPP_64f_C3;
typedef ImageNPP<Npp64f, 4> ImageNPP_64f_C4;
} // npp namespace
#endif // NV_UTIL_NPP_IMAGES_NPP_H

View File

@ -1,126 +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.
*/
#ifndef NV_UTIL_PIXEL_H
#define NV_UTIL_PIXEL_H
#include "Exceptions.h"
namespace npp
{
template <typename D, size_t N>
struct Pixel
{ };
template <typename D>
struct Pixel<D, 1>
{
D x;
const D &
operator[](size_t iChannel)
const
{
NPP_ASSERT(iChannel < 1);
return (&x)[iChannel];
}
D &
operator[](size_t iChannel)
{
NPP_ASSERT(iChannel < 1);
return (&x)[iChannel];
}
};
template <typename D>
struct Pixel<D, 2>
{
D x,y;
const D &
operator[](size_t iChannel)
const
{
NPP_ASSERT(iChannel < 2);
return (&x)[iChannel];
}
D &
operator[](size_t iChannel)
{
NPP_ASSERT(iChannel < 2);
return (&x)[iChannel];
}
};
template <typename D>
struct Pixel<D, 3>
{
D x,y,z;
const D &
operator[](size_t iChannel)
const
{
NPP_ASSERT(iChannel < 3);
return (&x)[iChannel];
}
D &
operator[](size_t iChannel)
{
NPP_ASSERT(iChannel < 3);
return (&x)[iChannel];
}
};
template <typename D>
struct Pixel<D, 4>
{
D x, y, z, w;
const D &
operator[](size_t iChannel)
const
{
NPP_ASSERT(iChannel < 4);
return (&x)[iChannel];
}
D &
operator[](size_t iChannel)
{
NPP_ASSERT(iChannel < 4);
return (&x)[iChannel];
}
};
} // npp namespace
#endif // NV_UTIL_PIXEL_H

View File

@ -1,168 +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.
*/
#ifndef NV_UTIL_NPP_SIGNAL_H
#define NV_UTIL_NPP_SIGNAL_H
#include <cstring>
namespace npp
{
class Signal
{
public:
Signal() : nSize_(0)
{ };
explicit
Signal(size_t nSize) : nSize_(nSize)
{ };
Signal(const Signal &rSignal) : nSize_(rSignal.nSize_)
{ };
virtual
~Signal()
{ }
Signal &
operator= (const Signal &rSignal)
{
nSize_ = rSignal.nSize_;
return *this;
}
size_t
size()
const
{
return nSize_;
}
void
swap(Signal &rSignal)
{
size_t nTemp = nSize_;
nSize_ = rSignal.nSize_;
rSignal.nSize_ = nTemp;
}
private:
size_t nSize_;
};
template<typename D, class A>
class SignalTemplate: public Signal
{
public:
typedef D tData;
SignalTemplate(): aValues_(0)
{
;
}
SignalTemplate(size_t nSize): Signal(nSize)
, aValues_(0)
{
aValues_ = A::Malloc1D(size());
}
SignalTemplate(const SignalTemplate<D, A> &rSignal): Signal(rSignal)
, aValues_(0)
{
aValues_ = A::Malloc1D(size());
A::Copy1D(aValues_, rSignal.values(), size());
}
virtual
~SignalTemplate()
{
A::Free1D(aValues_);
}
SignalTemplate &
operator= (const SignalTemplate<D, A> &rSignal)
{
// in case of self-assignment
if (&rSignal == this)
{
return *this;
}
A::Free1D(aValues_);
this->aPixels_ = 0;
// assign parent class's data fields (width, height)
Signal::operator =(rSignal);
aValues_ = A::Malloc1D(size());
A::Copy1D(aValues_, rSignal.value(), size());
return *this;
}
/// Get a pointer to the pixel array.
/// The result pointer can be offset to pixel at position (x, y) and
/// even negative offsets are allowed.
/// \param nX Horizontal pointer/array offset.
/// \param nY Vertical pointer/array offset.
/// \return Pointer to the pixel array (or first pixel in array with coordinates (nX, nY).
tData *
values(int i = 0)
{
return aValues_ + i;
}
const
tData *
values(int i = 0)
const
{
return aValues_ + i;
}
void
swap(SignalTemplate<D, A> &rSignal)
{
Signal::swap(rSignal);
tData *aTemp = this->aValues_;
this->aValues_ = rSignal.aValues_;
rSignal.aValues_ = aTemp;
}
private:
D *aValues_;
};
} // npp namespace
#endif // NV_UTIL_NPP_SIGNAL_H

View File

@ -1,66 +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.
*/
#ifndef NV_UTIL_NPP_SIGNAL_ALLOCATORS_CPU_H
#define NV_UTIL_NPP_SIGNAL_ALLOCATORS_CPU_H
#include "Exceptions.h"
namespace npp
{
template <typename D>
class SignalAllocatorCPU
{
public:
static
D *
Malloc1D(unsigned int nSize)
{
return new D[nSize];;
};
static
void
Free1D(D *pPixels)
{
delete[] pPixels;
};
static
void
Copy1D(D *pDst, const D *pSrc, size_t nSize)
{
memcpy(pDst, pSrc, nSize * sizeof(D));
};
};
} // npp namespace
#endif // NV_UTIL_NPP_SIGNAL_ALLOCATORS_CPU_H

View File

@ -1,684 +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.
*/
#ifndef NV_UTIL_NPP_SIGNAL_ALLOCATORS_NPP_H
#define NV_UTIL_NPP_SIGNAL_ALLOCATORS_NPP_H
#include "Exceptions.h"
#include <npps.h>
#include <cuda_runtime.h>
namespace npp
{
template <typename D>
class SignalAllocator
{
};
template<>
class SignalAllocator<Npp8u>
{
public:
static
Npp8u *
Malloc1D(size_t nSize)
{
Npp8u *pResult = nppsMalloc_8u(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp8u *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp8u *pDst, const Npp8u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp8u),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp8u *pDst, const Npp8u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp8u), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp8u *pDst, const Npp8u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp8u), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp16s>
{
public:
static
Npp16s *
Malloc1D(size_t nSize)
{
Npp16s *pResult = nppsMalloc_16s(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp16s *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp16s *pDst, const Npp16s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16s),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp16s *pDst, const Npp16s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16s), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp16s *pDst, const Npp16s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16s), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp16u>
{
public:
static
Npp16u *
Malloc1D(size_t nSize)
{
Npp16u *pResult = nppsMalloc_16u(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp16u *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp16u *pDst, const Npp16u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16u),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp16u *pDst, const Npp16u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16u), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp16u *pDst, const Npp16u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16u), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp16sc>
{
public:
static
Npp16sc *
Malloc1D(size_t nSize)
{
Npp16sc *pResult = nppsMalloc_16sc(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp16sc *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp16sc *pDst, const Npp16sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16sc),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp16sc *pDst, const Npp16sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16sc), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp16sc *pDst, const Npp16sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp16sc), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp32u>
{
public:
static
Npp32u *
Malloc1D(size_t nSize)
{
Npp32u *pResult = nppsMalloc_32u(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp32u *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp32u *pDst, const Npp32u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32u),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp32u *pDst, const Npp32u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32u), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp32u *pDst, const Npp32u *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32u), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp32s>
{
public:
static
Npp32s *
Malloc1D(size_t nSize)
{
Npp32s *pResult = nppsMalloc_32s(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp32s *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp32s *pDst, const Npp32s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32s),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp32s *pDst, const Npp32s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32s), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp32s *pDst, const Npp32s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32s), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp32sc>
{
public:
static
Npp32sc *
Malloc1D(size_t nSize)
{
Npp32sc *pResult = nppsMalloc_32sc(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp32sc *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp32sc *pDst, const Npp32sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32sc),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp32sc *pDst, const Npp32sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32sc), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp32sc *pDst, const Npp32sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32sc), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp32f>
{
public:
static
Npp32f *
Malloc1D(size_t nSize)
{
Npp32f *pResult = nppsMalloc_32f(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp32f *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp32f *pDst, const Npp32f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32f),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp32f *pDst, const Npp32f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32f), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp32f *pDst, const Npp32f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32f), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp32fc>
{
public:
static
Npp32fc *
Malloc1D(size_t nSize)
{
Npp32fc *pResult = nppsMalloc_32fc(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp32fc *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp32fc *pDst, const Npp32fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32fc),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp32fc *pDst, const Npp32fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32fc), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp32fc *pDst, const Npp32fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp32fc), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp64s>
{
public:
static
Npp64s *
Malloc1D(size_t nSize)
{
Npp64s *pResult = nppsMalloc_64s(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp64s *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp64s *pDst, const Npp64s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64s),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp64s *pDst, const Npp64s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64s), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp64s *pDst, const Npp64s *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64s), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp64sc>
{
public:
static
Npp64sc *
Malloc1D(size_t nSize)
{
Npp64sc *pResult = nppsMalloc_64sc(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp64sc *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp64sc *pDst, const Npp64sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64sc),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp64sc *pDst, const Npp64sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64sc), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp64sc *pDst, const Npp64sc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64sc), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp64f>
{
public:
static
Npp64f *
Malloc1D(size_t nSize)
{
Npp64f *pResult = nppsMalloc_64f(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp64f *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp64f *pDst, const Npp64f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64f),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp64f *pDst, const Npp64f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64f), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp64f *pDst, const Npp64f *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64f), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
template<>
class SignalAllocator<Npp64fc>
{
public:
static
Npp64fc *
Malloc1D(size_t nSize)
{
Npp64fc *pResult = nppsMalloc_64fc(static_cast<int>(nSize));
NPP_ASSERT(pResult != 0);
return pResult;
};
static
void
Free1D(Npp64fc *pValues)
{
nppsFree(pValues);
};
static
void
Copy1D(Npp64fc *pDst, const Npp64fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64fc),cudaMemcpyDeviceToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
HostToDeviceCopy1D(Npp64fc *pDst, const Npp64fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64fc), cudaMemcpyHostToDevice);
NPP_ASSERT(cudaSuccess == eResult);
};
static
void
DeviceToHostCopy1D(Npp64fc *pDst, const Npp64fc *pSrc, size_t nSize)
{
cudaError_t eResult;
eResult = cudaMemcpy(pDst, pSrc, nSize * sizeof(Npp64fc), cudaMemcpyDeviceToHost);
NPP_ASSERT(cudaSuccess == eResult);
};
};
} // npp namespace
#endif // NV_UTIL_NPP_SIGNAL_ALLOCATORS_NPP_H

View File

@ -1,107 +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.
*/
#ifndef NV_UTIL_NPP_SIGNALS_CPU_H
#define NV_UTIL_NPP_SIGNALS_CPU_H
#include "Signal.h"
#include "SignalAllocatorsCPU.h"
#include "Exceptions.h"
#include <npp.h>
namespace npp
{
template<typename D, class A>
class SignalCPU: public npp::SignalTemplate<D, A>
{
public:
typedef typename npp::SignalTemplate<D, A>::tData tData;
SignalCPU()
{
;
}
SignalCPU(size_t nSize): SignalTemplate<D, A>(nSize)
{
;
}
SignalCPU(const SignalCPU<D, A> &rSignal): SignalTemplate<D, A>(rSignal)
{
;
}
virtual
~SignalCPU()
{
;
}
SignalCPU &
operator= (const SignalCPU<D,A> &rSignal)
{
SignalTemplate<D, A>::operator= (rSignal);
return *this;
}
tData &
operator [](unsigned int i)
{
return *SignalTemplate<D, A>::values(i);
}
tData
operator [](unsigned int i)
const
{
return *SignalTemplate<D, A>::values(i);
}
};
typedef SignalCPU<Npp8u, npp::SignalAllocatorCPU<Npp8u> > SignalCPU_8u;
typedef SignalCPU<Npp32s, npp::SignalAllocatorCPU<Npp32s> > SignalCPU_32s;
typedef SignalCPU<Npp16s, npp::SignalAllocatorCPU<Npp16s> > SignalCPU_16s;
typedef SignalCPU<Npp16sc, npp::SignalAllocatorCPU<Npp16sc> > SignalCPU_16sc;
typedef SignalCPU<Npp32sc, npp::SignalAllocatorCPU<Npp32sc> > SignalCPU_32sc;
typedef SignalCPU<Npp32f, npp::SignalAllocatorCPU<Npp32f> > SignalCPU_32f;
typedef SignalCPU<Npp32fc, npp::SignalAllocatorCPU<Npp32fc> > SignalCPU_32fc;
typedef SignalCPU<Npp64s, npp::SignalAllocatorCPU<Npp64s> > SignalCPU_64s;
typedef SignalCPU<Npp64sc, npp::SignalAllocatorCPU<Npp64sc> > SignalCPU_64sc;
typedef SignalCPU<Npp64f, npp::SignalAllocatorCPU<Npp64f> > SignalCPU_64f;
typedef SignalCPU<Npp64fc, npp::SignalAllocatorCPU<Npp64fc> > SignalCPU_64fc;
} // npp namespace
#endif // NV_UTIL_NPP_SIGNALS_CPU_H

View File

@ -1,113 +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.
*/
#ifndef NV_UTIL_NPP_SIGNALS_NPP_H
#define NV_UTIL_NPP_SIGNALS_NPP_H
#include "Exceptions.h"
#include "Signal.h"
#include "SignalAllocatorsNPP.h"
#include <cuda_runtime.h>
namespace npp
{
// forward declaration
template<typename D, class A> class SignalCPU;
template<typename D>
class SignalNPP: public npp::SignalTemplate<D, npp::SignalAllocator<D> >
{
public:
SignalNPP()
{
;
}
explicit
SignalNPP(size_t nSize): SignalTemplate<D, npp::SignalAllocator<D> >(nSize)
{
;
}
SignalNPP(const SignalNPP<D> &rSignal): SignalTemplate<D, npp::SignalAllocator<D> >(rSignal)
{
;
}
template<class X>
explicit
SignalNPP(const SignalCPU<D, X> &rSignal): SignalTemplate<D, npp::SignalAllocator<D> >(rSignal.size())
{
npp::SignalAllocator<D>::HostToDeviceCopy1D(SignalTemplate<D, npp::SignalAllocator<D> >::values(),
rSignal.values(), SignalTemplate<D, npp::SignalAllocator<D> >::size());
}
virtual
~SignalNPP()
{
;
}
SignalNPP &
operator= (const SignalNPP<D> &rSignal)
{
SignalTemplate<D, npp::SignalAllocator<D> >::operator= (rSignal);
return *this;
}
void
copyTo(D *pValues)
const
{
npp::SignalAllocator<D>::DeviceToHostCopy1D(pValues, SignalTemplate<D, npp::SignalAllocator<D> >::values(), SignalTemplate<D, npp::SignalAllocator<D> >::size());
}
void
copyFrom(D *pValues)
{
npp::SignalAllocator<D>::HostToDeviceCopy1D(SignalTemplate<D, npp::SignalAllocator<D> >::values(), pValues, SignalTemplate<D, npp::SignalAllocator<D> >::size());
}
};
typedef SignalNPP<Npp8u> SignalNPP_8u;
typedef SignalNPP<Npp16s> SignalNPP_16s;
typedef SignalNPP<Npp16sc> SignalNPP_16sc;
typedef SignalNPP<Npp32s> SignalNPP_32s;
typedef SignalNPP<Npp32sc> SignalNPP_32sc;
typedef SignalNPP<Npp32f> SignalNPP_32f;
typedef SignalNPP<Npp32fc> SignalNPP_32fc;
typedef SignalNPP<Npp64s> SignalNPP_64s;
typedef SignalNPP<Npp64sc> SignalNPP_64sc;
typedef SignalNPP<Npp64f> SignalNPP_64f;
typedef SignalNPP<Npp64fc> SignalNPP_64fc;
} // npp namespace
#endif // NV_UTIL_NPP_SIGNALS_NPP_H

View File

@ -674,6 +674,7 @@ inline int _ConvertSMVer2Cores(int major, int minor) {
{0xa0, 128}, {0xa0, 128},
{0xa1, 128}, {0xa1, 128},
{0xa3, 128}, {0xa3, 128},
{0xa7, 128},
{0xb0, 128}, {0xb0, 128},
{0xc0, 128}, {0xc0, 128},
{0xc1, 128}, {0xc1, 128},
@ -729,6 +730,7 @@ inline const char* _ConvertSMVer2ArchName(int major, int minor) {
{0xa0, "Blackwell"}, {0xa0, "Blackwell"},
{0xa1, "Blackwell"}, {0xa1, "Blackwell"},
{0xa3, "Blackwell"}, {0xa3, "Blackwell"},
{0xa7, "Rubin"},
{0xb0, "Blackwell"}, {0xb0, "Blackwell"},
{0xc0, "Blackwell"}, {0xc0, "Blackwell"},
{0xc1, "Blackwell"}, {0xc1, "Blackwell"},

View File

@ -119,6 +119,7 @@ inline int _ConvertSMVer2CoresDRV(int major, int minor) {
{0xa0, 128}, {0xa0, 128},
{0xa1, 128}, {0xa1, 128},
{0xa3, 128}, {0xa3, 128},
{0xa7, 128},
{0xb0, 128}, {0xb0, 128},
{0xc0, 128}, {0xc0, 128},
{0xc1, 128}, {0xc1, 128},

View File

@ -1143,10 +1143,16 @@ inline __host__ __device__ uint4 max(uint4 a, uint4 b)
// - linear interpolation between a and b, based on value t in [0, 1] range // - linear interpolation between a and b, based on value t in [0, 1] range
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// std::lerp (C++20) is pulled into the global namespace by GCC's <cmath>;
// only define our own scalar overload when std::lerp is unavailable, to avoid
// a redeclaration / ambiguous-overload clash. (The float2/3/4 overloads below
// take distinct argument types and never conflict.)
#if !defined(__cplusplus) || (__cplusplus < 202002L)
inline __device__ __host__ float lerp(float a, float b, float t) inline __device__ __host__ float lerp(float a, float b, float t)
{ {
return a + t*(b-a); return a + t*(b-a);
} }
#endif
inline __device__ __host__ float2 lerp(float2 a, float2 b, float t) inline __device__ __host__ float2 lerp(float2 a, float2 b, float t)
{ {
return a + t*(b-a); return a + t*(b-a);

View File

@ -185,22 +185,24 @@ int ipcCreateSocket(ipcHandle *&handle, const char *name,
return -1; return -1;
} }
char path_name[50]; char path_name[sizeof(servaddr.sun_path)];
// Create unique name for the socket with path if SOCK_FOLDER is set. // Create unique name for the socket with path if SOCK_FOLDER is set.
sprintf(path_name, "%s/%u", getSocketFolder().c_str(), getpid()); int written = snprintf(path_name, sizeof(path_name), "%s/%u",
getSocketFolder().c_str(), getpid());
if (written < 0 || (size_t)written >= sizeof(path_name)) {
perror("IPC failure: Cannot bind provided name to socket. Name too large");
close(server_fd);
delete handle;
handle = NULL;
return -1;
}
unlink(path_name); unlink(path_name);
memset(&servaddr, 0, sizeof(servaddr)); memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX; servaddr.sun_family = AF_UNIX;
size_t len = strlen(path_name); strncpy(servaddr.sun_path, path_name, sizeof(servaddr.sun_path) - 1);
if (len > (sizeof(servaddr.sun_path) - 1)) {
perror("IPC failure: Cannot bind provided name to socket. Name too large");
return -1;
}
strncpy(servaddr.sun_path, path_name, len);
if (bind(server_fd, (struct sockaddr *)&servaddr, SUN_LEN(&servaddr)) < 0) { if (bind(server_fd, (struct sockaddr *)&servaddr, SUN_LEN(&servaddr)) < 0) {
perror("IPC failure: Binding socket failed"); perror("IPC failure: Binding socket failed");
@ -227,10 +229,18 @@ int ipcOpenSocket(ipcHandle *&handle) {
memset(&cliaddr, 0, sizeof(cliaddr)); memset(&cliaddr, 0, sizeof(cliaddr));
cliaddr.sun_family = AF_UNIX; cliaddr.sun_family = AF_UNIX;
char temp[50]; char temp[sizeof(cliaddr.sun_path)];
// Create unique name for the socket with path if SOCK_FOLDER is set. // Create unique name for the socket with path if SOCK_FOLDER is set.
sprintf(temp, "%s/%u", getSocketFolder().c_str(), getpid()); int written = snprintf(temp, sizeof(temp), "%s/%u", getSocketFolder().c_str(),
getpid());
if (written < 0 || (size_t)written >= sizeof(temp)) {
perror("IPC failure: Cannot bind provided name to socket. Name too large");
close(sock);
delete handle;
handle = NULL;
return -1;
}
strcpy(cliaddr.sun_path, temp); strcpy(cliaddr.sun_path, temp);
if (bind(sock, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) { if (bind(sock, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) {
@ -366,8 +376,14 @@ int ipcSendShareableHandle(ipcHandle *handle,
// Construct client address to send this SHareable handle to // Construct client address to send this SHareable handle to
memset(&cliaddr, 0, sizeof(cliaddr)); memset(&cliaddr, 0, sizeof(cliaddr));
cliaddr.sun_family = AF_UNIX; cliaddr.sun_family = AF_UNIX;
char temp[20]; char temp[sizeof(cliaddr.sun_path)];
sprintf(temp, "%s/%u", getSocketFolder().c_str(), process); int written =
snprintf(temp, sizeof(temp), "%s/%u", getSocketFolder().c_str(), process);
if (written < 0 || (size_t)written >= sizeof(temp)) {
perror("IPC failure: Cannot address client socket. Name too large");
free(control_un.control);
return -1;
}
strcpy(cliaddr.sun_path, temp); strcpy(cliaddr.sun_path, temp);
len = sizeof(cliaddr); len = sizeof(cliaddr);

View File

@ -1,6 +1,6 @@
# CUDA Samples # CUDA Samples
Samples for CUDA Developers which demonstrates features in CUDA Toolkit. This version supports [CUDA Toolkit 13.3](https://developer.nvidia.com/cuda-downloads). Samples for CUDA Developers which demonstrates features in CUDA Toolkit. This version supports [CUDA Toolkit 13.4](https://developer.nvidia.com/cuda-downloads).
## Release Notes ## Release Notes
@ -28,8 +28,6 @@ Without using git the easiest way to use these samples is to download the zip fi
## Building CUDA Samples ## Building CUDA Samples
### Building CUDA Samples
The CUDA Samples are built using CMake. Follow the instructions below for building on Linux, Windows, and for cross-compilation to Tegra devices. The CUDA Samples are built using CMake. Follow the instructions below for building on Linux, Windows, and for cross-compilation to Tegra devices.
### Linux ### Linux
@ -51,7 +49,27 @@ Build the samples:
``` ```
make -j$(nproc) make -j$(nproc)
``` ```
Run the samples from their respective directories in the build folder. You can also follow this process from and subdirectory of the samples repo, or from within any individual sample.
By default, samples are compiled for all GPU architectures supported by this release. If you only need to target a specific GPU, you can override this to build for a single architecture and reduce build time considerably:
```
cmake -DCMAKE_CUDA_ARCHITECTURES=<arch> ..
```
Replace `<arch>` with your GPU's SM version (e.g. `90` for sm_90).
Run the samples from their respective directories in the build folder.
### Building a Single Sample
To build just one sample, configure CMake from within the sample's directory. You must explicitly specify a GPU architecture — standalone builds have no top-level default:
```bash
cd cpp/<category>/<sampleName>
mkdir -p build && cd build
cmake -DCMAKE_CUDA_ARCHITECTURES=<arch> ..
make
```
Replace `<arch>` with your GPU's SM version (e.g. `90` for sm_90).
### Windows ### Windows
@ -170,23 +188,66 @@ $ make -j$(nproc) --ignore-errors # or --keep-going
### QNX ### QNX
Cross-compilation for QNX with CMake is supported in the CUDA 13.0 samples release and newer. An example build for Cross-compilation for QNX with CMake is supported in the CUDA 13.0 samples release and newer.
the Tegra Thor QNX platform might look like this:
Set up the QNX SDP paths:
```bash
export QNX_HOST=/path/to/qnx/host
export QNX_TARGET=/path/to/qnx/target
``` ```
$ mkdir build
$ cd build
QNX_HOST=/path/to/qnx/host \ Build the samples for the Tegra Thor QNX platform:
QNX_TARGET=/path/to/qnx/target \
```bash
mkdir -p build && cd build
cmake .. \ cmake .. \
-DBUILD_TEGRA=True \ -DBUILD_TEGRA=True \
-DCMAKE_CUDA_COMPILER=/usr/local/cuda-13.3/bin/nvcc \ -DCMAKE_CUDA_COMPILER=/usr/local/cuda-13.3/bin/nvcc \
-DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/toolchain-aarch64-qnx.cmake \ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/toolchain-aarch64-qnx.cmake \
-DCMAKE_LIBRARY_PATH=/usr/local/cuda-13.3/thor/targets/aarch64-qnx/lib/stubs/ \ -DTARGET_FS=/path/to/qnx/targetfs \
-DCMAKE_INCLUDE_PATH=/usr/local/cuda-13.3/thor/targets/aarch64-qnx/include/ -DCMAKE_LIBRARY_PATH=/usr/local/cuda-13.3/thor/targets/aarch64-qnx/lib/stubs/ \
-DCMAKE_INCLUDE_PATH=/usr/local/cuda-13.3/thor/targets/aarch64-qnx/include/
cmake --build .
``` ```
`TARGET_FS` is the QNX target filesystem of your board. The `cudaNvSci` sample needs it, because the NvSci headers and libraries ship with the target filesystem and not with the CUDA toolkit. Without `TARGET_FS` the build reports `NvSCI not found` and skips the sample.
The target filesystem is part of the NVIDIA DRIVE OS QNX SDK, which registered users download from [NVONLINE](https://partners.nvidia.com). After the SDK is installed, the filesystem is in the DRIVE OS workspace: `<NV_WORKSPACE>/drive-qnx` for the standard SDK and `<NV_WORKSPACE>/drive-qnx-safety` for the safety SDK. See the [DRIVE OS documentation](https://docs.nvidia.com/drive/) for the installation guides.
For both QNX toolchains the build looks for `nvscibuf.h` in `<TARGET_FS>/include`, `<TARGET_FS>/../include` and `<TARGET_FS>/usr/include`, and for `libnvscibuf.so` in `<TARGET_FS>/lib-target`, `<TARGET_FS>/usr/libnvidia` and `<TARGET_FS>/usr/lib`. If your filesystem uses a different layout, set `NVSCIBUF_INCLUDE_DIR`, `NVSCISYNC_INCLUDE_DIR`, `NVSCIBUF_LIBRARY` and `NVSCISYNC_LIBRARY` on the cmake command line instead.
### QNX Safety (CUDA Safe toolkit)
Cross-compilation for **QNX Safety** uses the CUDA Safe toolkit (for example `/usr/local/cuda-13.3-safe`).
Set up the QNX SDP and Safe toolkit paths:
```bash
export QNX_HOST=/path/to/qnx/host
export QNX_TARGET=/path/to/qnx/target
export CUDA_PATH=/usr/local/cuda-13.3-safe
export PATH=$CUDA_PATH/nvvm/bin:$PATH
```
Build a single sample (standalone configure from the sample directory).
```bash
mkdir -p build && cd build
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=../../../cmake/toolchains/toolchain-aarch64-qnx-safe.cmake \
-DCMAKE_CUDA_COMPILER=$CUDA_PATH/bin/nvcc \
-DCMAKE_CUDA_ARCHITECTURES=110 \
-DTARGET_FS=/path/to/qnx/safety/targetfs
cmake --build .
```
The safe toolchain sets `-safety-compat`, links shared `libcudart` and `libcuda`, and uses QNX `q++` as the CUDA host compiler (`CMAKE_CUDA_HOST_COMPILER`). Set `CMAKE_CUDA_ARCHITECTURES` to match your GPU (`87` for Orin, `110` for Thor).
Supported QNX Safety samples: `matrixMul`, `cudaNvSci`.
`TARGET_FS` is only needed for `cudaNvSci`, which links the NvSci libraries from the safety target filesystem (`<NV_WORKSPACE>/drive-qnx-safety`, part of the DRIVE OS QNX Safety SDK). `matrixMul` builds without it. The NvSci search paths are the same as for the standard QNX build above.
### Forward Compatibility ### Forward Compatibility
To build samples with new CUDA Toolkit(CUDA 13.0 or later) and UMD(Version 580 or later) and old KMD(Version 550 or earlier)you need to set the `CMAKE_PREFIX_PATH` for using new driver library, the command might like this: To build samples with new CUDA Toolkit(CUDA 13.0 or later) and UMD(Version 580 or later) and old KMD(Version 550 or earlier)you need to set the `CMAKE_PREFIX_PATH` for using new driver library, the command might like this:

View File

@ -0,0 +1 @@
set(CUDA_SAMPLES_MASTER_ARCHS 75 80 86 87 89 90 100 103 107 110 120)

View File

@ -0,0 +1,19 @@
include_guard(GLOBAL)
get_filename_component(_cuda_sample_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
list(APPEND CMAKE_MODULE_PATH "${_cuda_sample_cmake_dir}")
list(APPEND CMAKE_MODULE_PATH "${_cuda_sample_cmake_dir}/Modules")
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(ENABLE_CUDA_DEBUG)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G")
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo")
endif()
if(MSVC)
add_compile_options($<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/Zc:preprocessor>)
endif()
unset(_cuda_sample_cmake_dir)

View File

@ -0,0 +1,66 @@
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
message(FATAL_ERROR
"CMAKE_CUDA_ARCHITECTURES is not set.\n"
"For standalone sample builds, specify a target architecture explicitly:\n"
" cmake -DCMAKE_CUDA_ARCHITECTURES=<arch> <path-to-sample>\n"
"Example: cmake -DCMAKE_CUDA_ARCHITECTURES=90 .")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/CudaSampleArchs.cmake")
# Master list of all CUDA architectures supported by this repo and CUDA 13.x.
# Each sample may define SAMPLE_DISALLOW_ARCHS to exclude architectures it does not support.
set(_master_archs ${CUDA_SAMPLES_MASTER_ARCHS})
# Compute this sample's effective arch list: master minus any disallowed archs.
set(_effective_archs ${_master_archs})
if(DEFINED SAMPLE_DISALLOW_ARCHS)
foreach(_arch ${SAMPLE_DISALLOW_ARCHS})
list(REMOVE_ITEM _effective_archs "${_arch}")
endforeach()
endif()
get_filename_component(_sample_dir "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
# CMAKE_CUDA_ARCHITECTURES is set by the top-level CMakeLists.txt (defaulting to the
# full master list if the user did not specify). Build only for the intersection with
# the effective list; skip the sample if no requested arch is supported.
# CMake special keywords (all, all-major, native) are passed through as-is.
set(_passthrough_values "all" "all-major" "native")
if(CMAKE_CUDA_ARCHITECTURES IN_LIST _passthrough_values)
set(_passthrough TRUE)
else()
set(_passthrough FALSE)
endif()
if(NOT _passthrough)
set(_build_archs)
foreach(_arch ${CMAKE_CUDA_ARCHITECTURES})
if(_arch IN_LIST _effective_archs)
list(APPEND _build_archs "${_arch}")
endif()
endforeach()
if(NOT _build_archs)
if(NOT CUDA_SAMPLES_ARCHS_DEFAULTED)
message(WARNING
"Sample in directory '${_sample_dir}' skipped: "
"user specified '${CMAKE_CUDA_ARCHITECTURES}' but this sample only supports '${_effective_archs}'")
endif()
set(SAMPLE_SKIP_BUILD TRUE)
elseif(NOT "${_build_archs}" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}" AND NOT CUDA_SAMPLES_ARCHS_DEFAULTED)
message(WARNING
"Sample in directory '${_sample_dir}': user requested some architecture(s) that are not supported. "
"Only building for '${_build_archs}'")
set(CMAKE_CUDA_ARCHITECTURES "${_build_archs}")
else()
set(CMAKE_CUDA_ARCHITECTURES "${_build_archs}")
endif()
unset(_build_archs)
endif()
unset(_master_archs)
unset(_effective_archs)
unset(_sample_dir)
unset(_passthrough)
unset(_passthrough_values)

View File

@ -1,17 +0,0 @@
find_path(FreeImage_INCLUDE_DIR
NAMES freeimage.h FreeImage.h
PATHS /usr/include /usr/local/include
)
find_library(FreeImage_LIBRARY
NAMES freeimage FreeImage
PATHS /usr/lib /usr/local/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FreeImage DEFAULT_MSG FreeImage_LIBRARY FreeImage_INCLUDE_DIR)
if(FreeImage_FOUND)
set(FreeImage_LIBRARIES ${FreeImage_LIBRARY})
set(FreeImage_INCLUDE_DIRS ${FreeImage_INCLUDE_DIR})
endif()

View File

@ -0,0 +1,136 @@
# Toolchain for QNX Safety builds with the CUDA Safe toolkit (QNX SAFE stack).
# Use this file instead of toolchain-aarch64-qnx.cmake for safe-toolkit installs.
set(CMAKE_SYSTEM_NAME QNX)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(QNX_HOST $ENV{QNX_HOST})
set(QNX_TARGET $ENV{QNX_TARGET})
message(STATUS "QNX_HOST = ${QNX_HOST}")
message(STATUS "QNX_TARGET = ${QNX_TARGET}")
find_program(QNX_QCC NAMES qcc PATHS "${QNX_HOST}/usr/bin")
find_program(QNX_QPLUS NAMES q++ PATHS "${QNX_HOST}/usr/bin")
if(NOT QNX_QCC OR NOT QNX_QPLUS)
message(FATAL_ERROR "Could not find qcc or q++ in QNX_HOST=${QNX_HOST}/usr/bin")
endif()
set(CMAKE_C_COMPILER ${QNX_QCC})
set(CMAKE_CXX_COMPILER ${QNX_QPLUS})
set(CMAKE_C_COMPILER_TARGET aarch64)
set(CMAKE_CXX_COMPILER_TARGET aarch64)
# Toolkit root: required so CUDA compiler ID test does not expand empty CUDA_ROOT into -I/include, etc.
if(CMAKE_CUDA_COMPILER)
get_filename_component(_cuda_nvcc_dir "${CMAKE_CUDA_COMPILER}" DIRECTORY)
get_filename_component(CUDA_TOOLKIT_ROOT "${_cuda_nvcc_dir}" DIRECTORY)
elseif(DEFINED ENV{CUDA_PATH})
set(CUDA_TOOLKIT_ROOT "$ENV{CUDA_PATH}")
endif()
if(CUDA_TOOLKIT_ROOT)
set(CUDA_TOOLKIT_ROOT "${CUDA_TOOLKIT_ROOT}" CACHE PATH "CUDA Toolkit root")
set(CUDA_ROOT "${CUDA_TOOLKIT_ROOT}" CACHE PATH "CUDA Toolkit root (nvcc / legacy CMake)" FORCE)
endif()
if(NOT __qnx_gcc_ver)
set(__qnx_gcc_ver "12.2.0" CACHE STRING "QNX qcc/q++ toolchain version for -V / --qpp-config (match your SDP)")
endif()
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING "" FORCE)
set(_cuda_safe_target "aarch64-qnx")
# CUDA Safe toolkit flags: -safety-compat keeps the kernel-launch ABI consistent; the safe toolkit
# ships only a shared cudart (no static/cudadevrt); -I/-L point at its headers/libs;
# --unresolved-symbols defers libcudart's rootfs-resident deps (nvdvms_*, NvOs*) to runtime.
if(CUDA_TOOLKIT_ROOT)
set(_cuda_safe_inc "${CUDA_TOOLKIT_ROOT}/targets/${_cuda_safe_target}/include")
set(_cuda_safe_lib "${CUDA_TOOLKIT_ROOT}/targets/${_cuda_safe_target}/lib")
set(_cuda_safe_stubs "${CUDA_TOOLKIT_ROOT}/targets/${_cuda_safe_target}/lib/stubs")
endif()
set(_cuda_safe_flags "-safety-compat --cudart=shared --cudadevrt=none -target-dir ${_cuda_safe_target} --qpp-config=${__qnx_gcc_ver},gcc_ntoaarch64le")
if(CUDA_TOOLKIT_ROOT)
string(APPEND _cuda_safe_flags " -I${_cuda_safe_inc} -L${_cuda_safe_lib} -L${_cuda_safe_stubs}")
endif()
string(APPEND _cuda_safe_flags " -Xlinker --unresolved-symbols=ignore-in-shared-libs")
set(CMAKE_C_FLAGS " \"-V${__qnx_gcc_ver},gcc_ntoaarch64le\"")
set(CMAKE_CXX_FLAGS " \"-V${__qnx_gcc_ver},gcc_ntoaarch64le\"")
# Host .cpp TUs are built by q++ directly, so give them the CUDA include too.
if(CUDA_TOOLKIT_ROOT)
string(APPEND CMAKE_C_FLAGS " -I${_cuda_safe_inc}")
string(APPEND CMAKE_CXX_FLAGS " -I${_cuda_safe_inc}")
endif()
set(CMAKE_CUDA_FLAGS " ${_cuda_safe_flags}")
separate_arguments(_automagic_nvcc_flags UNIX_COMMAND "${_cuda_safe_flags}")
set(AUTOMAGIC_NVCC_FLAGS ${_automagic_nvcc_flags}
CACHE STRING "automagic feature detection flags for QNX Safe cross build")
# Safe toolkit has no cudadevrt/static cudart, so disable CMake's implicit runtime libs and link the
# shared cudart ourselves. Also link the driver (-lcuda): the shared libcudart.so references safety-
# stack symbols (nvdvms_*, NvOs*) that are transitive deps of libcuda.so.1, so the exe must pull in
# libcuda for them to resolve/load on the target. STANDARD_LIBRARIES_INIT covers ABI checks; the
# HOST_LINK options cover real targets.
set(CMAKE_CUDA_RUNTIME_LIBRARY "None" CACHE STRING "CUDA runtime library (safe toolkit: linked manually)")
set(CMAKE_CUDA_STANDARD_LIBRARIES_INIT "-lcudart -lcuda")
if(CUDA_TOOLKIT_ROOT)
add_link_options("$<HOST_LINK:-L${_cuda_safe_lib}>" "$<HOST_LINK:-L${_cuda_safe_stubs}>"
"$<HOST_LINK:-lcudart>" "$<HOST_LINK:-lcuda>")
endif()
# -V on the host link only; nvcc would comma-split it at the device link (which uses --qpp-config).
add_link_options("$<HOST_LINK:-V${__qnx_gcc_ver}$<COMMA>gcc_ntoaarch64le>")
# Defer libcudart's rootfs-resident deps to runtime.
add_link_options("-Wl,--unresolved-symbols=ignore-in-shared-libs")
set(CROSS_COMPILE_FOR_QNX ON CACHE BOOL "Cross compiling for QNX platforms")
string(APPEND CMAKE_CXX_FLAGS " -D_QNX_SOURCE")
string(APPEND CMAKE_CUDA_FLAGS " -D_QNX_SOURCE")
# cudaNvSci needs NvSci headers/libs from the QNX safety rootfs; point TARGET_FS at it. This
# pre-seeds FindNVSCI's cache vars and auto-detects the header/lib dirs across rootfs layouts.
if(DEFINED TARGET_FS)
# Expand a leading ~ so paths reach the linker absolute.
if(TARGET_FS MATCHES "^~")
string(REGEX REPLACE "^~" "$ENV{HOME}" TARGET_FS "${TARGET_FS}")
endif()
get_filename_component(_nvsci_sdk_root "${TARGET_FS}" DIRECTORY)
# Header dir varies by rootfs layout.
foreach(_inc "${TARGET_FS}/include" "${_nvsci_sdk_root}/include" "${TARGET_FS}/usr/include")
if(NOT _nvsci_inc AND EXISTS "${_inc}/nvscibuf.h")
set(_nvsci_inc "${_inc}")
endif()
endforeach()
# Lib dir varies by rootfs layout.
foreach(_lib "${TARGET_FS}/lib-target" "${TARGET_FS}/usr/libnvidia" "${TARGET_FS}/usr/lib")
if(NOT _nvsci_lib AND EXISTS "${_lib}/libnvscibuf.so")
set(_nvsci_lib "${_lib}")
endif()
endforeach()
if(NOT _nvsci_inc OR NOT _nvsci_lib)
message(FATAL_ERROR
"Could not locate NvSci headers/libs from TARGET_FS='${TARGET_FS}'. "
"Checked include roots for nvscibuf.h and lib roots for libnvscibuf.so. "
"Please set TARGET_FS (or NVSCIBUF/NVSCISYNC cache vars) to a valid QNX safety rootfs.")
endif()
set(NVSCIBUF_INCLUDE_DIR "${_nvsci_inc}" CACHE PATH "NvSciBuf headers (QNX safe)")
set(NVSCISYNC_INCLUDE_DIR "${_nvsci_inc}" CACHE PATH "NvSciSync headers (QNX safe)")
set(NVSCIBUF_LIBRARY "${_nvsci_lib}/libnvscibuf.so" CACHE FILEPATH "NvSciBuf library (QNX safe)")
set(NVSCISYNC_LIBRARY "${_nvsci_lib}/libnvscisync.so" CACHE FILEPATH "NvSciSync library (QNX safe)")
# rpath-link the rootfs lib dirs so NvSci's transitive deps resolve at link time.
foreach(_dir "${_nvsci_lib}" "${TARGET_FS}/lib-target" "${TARGET_FS}/usr/libnvidia" "${TARGET_FS}/usr/lib")
if(IS_DIRECTORY "${_dir}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${_dir}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath-link,${_dir}")
endif()
endforeach()
endif()

View File

@ -35,3 +35,50 @@ add_link_options("-V${__qnx_gcc_ver},gcc_ntoaarch64le")
set(CROSS_COMPILE_FOR_QNX ON CACHE BOOL "Cross compiling for QNX platforms") set(CROSS_COMPILE_FOR_QNX ON CACHE BOOL "Cross compiling for QNX platforms")
string(APPEND CMAKE_CXX_FLAGS " -D_QNX_SOURCE") string(APPEND CMAKE_CXX_FLAGS " -D_QNX_SOURCE")
string(APPEND CMAKE_CUDA_FLAGS " -D_QNX_SOURCE") string(APPEND CMAKE_CUDA_FLAGS " -D_QNX_SOURCE")
# cudaNvSci needs NvSci headers/libs from the QNX rootfs; point TARGET_FS at it. This pre-seeds
# FindNVSCI's cache vars and auto-detects the header/lib dirs across rootfs layouts.
if(DEFINED TARGET_FS)
# Expand a leading ~ so paths reach the linker absolute.
if(TARGET_FS MATCHES "^~")
string(REGEX REPLACE "^~" "$ENV{HOME}" TARGET_FS "${TARGET_FS}")
endif()
get_filename_component(_nvsci_sdk_root "${TARGET_FS}" DIRECTORY)
# Header dir varies by rootfs layout. Both headers are required, so accept a dir only if it
# holds both.
foreach(_inc "${TARGET_FS}/include" "${_nvsci_sdk_root}/include" "${TARGET_FS}/usr/include")
if(NOT _nvsci_inc AND EXISTS "${_inc}/nvscibuf.h" AND EXISTS "${_inc}/nvscisync.h")
set(_nvsci_inc "${_inc}")
endif()
endforeach()
# Lib dir varies by rootfs layout. FindNVSCI needs both libraries, so accept a dir only if it
# holds both.
foreach(_lib "${TARGET_FS}/lib-target" "${TARGET_FS}/usr/libnvidia" "${TARGET_FS}/usr/lib")
if(NOT _nvsci_lib AND EXISTS "${_lib}/libnvscibuf.so" AND EXISTS "${_lib}/libnvscisync.so")
set(_nvsci_lib "${_lib}")
endif()
endforeach()
# A rootfs without NvSci is not an error: FindNVSCI then reports NvSci as missing and only the
# NvSci samples are skipped.
if(_nvsci_inc AND _nvsci_lib)
set(NVSCIBUF_INCLUDE_DIR "${_nvsci_inc}" CACHE PATH "NvSciBuf headers")
set(NVSCISYNC_INCLUDE_DIR "${_nvsci_inc}" CACHE PATH "NvSciSync headers")
set(NVSCIBUF_LIBRARY "${_nvsci_lib}/libnvscibuf.so" CACHE FILEPATH "NvSciBuf library")
set(NVSCISYNC_LIBRARY "${_nvsci_lib}/libnvscisync.so" CACHE FILEPATH "NvSciSync library")
# rpath-link the rootfs lib dirs so NvSci's transitive deps resolve at link time.
# NvSci pulls in NvRm/NvOs/NvSciIpc, which can sit in a lib dir of their own.
foreach(_dir "${_nvsci_lib}" "${TARGET_FS}/lib-target" "${_nvsci_sdk_root}/lib-target"
"${TARGET_FS}/usr/libnvidia" "${TARGET_FS}/usr/lib")
if(IS_DIRECTORY "${_dir}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${_dir}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath-link,${_dir}")
endif()
endforeach()
else()
message(STATUS "NvSci headers/libs not found in TARGET_FS='${TARGET_FS}'")
endif()
endif()

View File

@ -1,44 +1,35 @@
add_subdirectory(UnifiedMemoryStreams) add_subdirectory(UnifiedMemoryStreams)
add_subdirectory(asyncAPI) add_subdirectory(asyncAPI)
add_subdirectory(clock) add_subdirectory(clock)
add_subdirectory(clock_nvrtc)
add_subdirectory(cudaOpenMP) add_subdirectory(cudaOpenMP)
add_subdirectory(fp16ScalarProduct) add_subdirectory(fp16ScalarProduct)
add_subdirectory(matrixMul) add_subdirectory(matrixMul)
add_subdirectory(matrixMulDrv) add_subdirectory(matrixMulDrv)
add_subdirectory(matrixMulDynlinkJIT) add_subdirectory(matrixMulDynlinkJIT)
add_subdirectory(matrixMul_nvrtc)
add_subdirectory(mergeSort)
add_subdirectory(simpleAWBarrier) add_subdirectory(simpleAWBarrier)
add_subdirectory(simpleAssert) add_subdirectory(simpleAssert)
add_subdirectory(simpleAssert_nvrtc)
add_subdirectory(simpleAtomicIntrinsics) add_subdirectory(simpleAtomicIntrinsics)
add_subdirectory(simpleAtomicIntrinsics_nvrtc)
add_subdirectory(simpleAttributes) add_subdirectory(simpleAttributes)
add_subdirectory(simpleCUDA2GL) add_subdirectory(simpleCUDA2GL)
add_subdirectory(simpleCallback) add_subdirectory(simpleCallback)
add_subdirectory(simpleCooperativeGroups) add_subdirectory(simpleCooperativeGroups)
add_subdirectory(simpleCubemapTexture) add_subdirectory(simpleCubemapTexture)
add_subdirectory(simpleDrvRuntime) add_subdirectory(simpleDrvRuntime)
add_subdirectory(simpleHyperQ)
add_subdirectory(simpleIPC) add_subdirectory(simpleIPC)
add_subdirectory(simpleLayeredTexture) add_subdirectory(simpleLayeredTexture)
add_subdirectory(simpleMPI) add_subdirectory(simpleMPI)
add_subdirectory(simpleMultiCopy) add_subdirectory(simpleMultiCopy)
add_subdirectory(simpleMultiGPU) add_subdirectory(simpleMultiGPU)
add_subdirectory(simpleOccupancy)
add_subdirectory(simpleP2P) add_subdirectory(simpleP2P)
add_subdirectory(simplePitchLinearTexture) add_subdirectory(simplePitchLinearTexture)
add_subdirectory(simplePrintf) add_subdirectory(simplePrintf)
add_subdirectory(simpleStreams) add_subdirectory(simpleStreams)
add_subdirectory(simpleSurfaceWrite) add_subdirectory(simpleSurfaceWrite)
add_subdirectory(simpleTemplates)
add_subdirectory(simpleTexture) add_subdirectory(simpleTexture)
add_subdirectory(simpleTexture3D) add_subdirectory(simpleTexture3D)
add_subdirectory(simpleTextureDrv) add_subdirectory(simpleTextureDrv)
add_subdirectory(simpleVoteIntrinsics) add_subdirectory(simpleVoteIntrinsics)
add_subdirectory(simpleZeroCopy) add_subdirectory(simpleZeroCopy)
add_subdirectory(template)
add_subdirectory(systemWideAtomics) add_subdirectory(systemWideAtomics)
add_subdirectory(vectorAdd) add_subdirectory(vectorAdd)
add_subdirectory(vectorAddDrv) add_subdirectory(vectorAddDrv)

View File

@ -7,9 +7,6 @@ This sample illustrates the usage of CUDA events for both GPU timing and overlap
### [clock](./clock) ### [clock](./clock)
This example shows how to use the clock function to measure the performance of block of threads of a kernel accurately. This example shows how to use the clock function to measure the performance of block of threads of a kernel accurately.
### [clock_nvrtc](./clock_nvrtc)
This example shows how to use the clock function using libNVRTC to measure the performance of block of threads of a kernel accurately.
### [cudaOpenMP](./cudaOpenMP) ### [cudaOpenMP](./cudaOpenMP)
This sample demonstrates how to use OpenMP API to write an application for multiple GPUs. This sample demonstrates how to use OpenMP API to write an application for multiple GPUs.
@ -19,30 +16,18 @@ Calculates scalar product of two vectors of FP16 numbers.
### [matrixMul](./matrixMul) ### [matrixMul](./matrixMul)
This sample implements matrix multiplication and is exactly the same as Chapter 6 of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the new CUDA 4.0 interface for CUBLAS to demonstrate high-performance performance for matrix multiplication. This sample implements matrix multiplication and is exactly the same as Chapter 6 of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the new CUDA 4.0 interface for CUBLAS to demonstrate high-performance performance for matrix multiplication.
### [matrixMul_nvrtc](./matrixMul_nvrtc)
This sample implements matrix multiplication and is exactly the same as Chapter 6 of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the new CUDA 4.0 interface for CUBLAS to demonstrate high-performance performance for matrix multiplication.
### [matrixMulDrv](./matrixMulDrv) ### [matrixMulDrv](./matrixMulDrv)
This sample implements matrix multiplication and uses the new CUDA 4.0 kernel launch Driver API. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. CUBLAS provides high-performance matrix multiplication. This sample implements matrix multiplication and uses the new CUDA 4.0 kernel launch Driver API. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. CUBLAS provides high-performance matrix multiplication.
### [matrixMulDynlinkJIT](./matrixMulDynlinkJIT) ### [matrixMulDynlinkJIT](./matrixMulDynlinkJIT)
This sample revisits matrix multiplication using the CUDA driver API. It demonstrates how to link to CUDA driver at runtime and how to use JIT (just-in-time) compilation from PTX code. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. CUBLAS provides high-performance matrix multiplication. This sample revisits matrix multiplication using the CUDA driver API. It demonstrates how to link to CUDA driver at runtime and how to use JIT (just-in-time) compilation from PTX code. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. CUBLAS provides high-performance matrix multiplication.
### [mergeSort](./mergeSort)
This sample implements a merge sort (also known as Batcher's sort), algorithms belonging to the class of sorting networks. While generally subefficient on large sequences compared to algorithms with better asymptotic algorithmic complexity (i.e. merge sort or radix sort), may be the algorithms of choice for sorting batches of short- to mid-sized (key, value) array pairs. Refer to the excellent tutorial by H. W. Lang http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/indexen.htm
### [simpleAssert](./simpleAssert) ### [simpleAssert](./simpleAssert)
This CUDA Runtime API sample is a very basic sample that implements how to use the assert function in the device code. Requires Compute Capability 2.0 . This CUDA Runtime API sample is a very basic sample that implements how to use the assert function in the device code. Requires Compute Capability 2.0 .
### [simpleAssert_nvrtc](./simpleAssert_nvrtc)
This CUDA Runtime API sample is a very basic sample that implements how to use the assert function in the device code. Requires Compute Capability 2.0 .
### [simpleAtomicIntrinsics](./simpleAtomicIntrinsics) ### [simpleAtomicIntrinsics](./simpleAtomicIntrinsics)
A simple demonstration of global memory atomic instructions. A simple demonstration of global memory atomic instructions.
### [simpleAtomicIntrinsics_nvrtc](./simpleAtomicIntrinsics_nvrtc)
A simple demonstration of global memory atomic instructions.This sample makes use of NVRTC for Runtime Compilation.
### [simpleAttributes](./simpleAttributes) ### [simpleAttributes](./simpleAttributes)
This CUDA Runtime API sample is a very basic example that implements how to use the stream attributes that affect L2 locality. Performance improvement due to use of L2 access policy window can only be noticed on Compute capability 8.0 or higher. This CUDA Runtime API sample is a very basic example that implements how to use the stream attributes that affect L2 locality. Performance improvement due to use of L2 access policy window can only be noticed on Compute capability 8.0 or higher.
@ -64,9 +49,6 @@ This sample shows how to copy CUDA image back to OpenGL using the most efficient
### [simpleDrvRuntime](./simpleDrvRuntime) ### [simpleDrvRuntime](./simpleDrvRuntime)
A simple example which demonstrates how CUDA Driver and Runtime APIs can work together to load cuda fatbinary of vector add kernel and performing vector addition. A simple example which demonstrates how CUDA Driver and Runtime APIs can work together to load cuda fatbinary of vector add kernel and performing vector addition.
### [simpleHyperQ](./simpleHyperQ)
This sample demonstrates the use of CUDA streams for concurrent execution of several kernels on devices which provide HyperQ (SM 3.5). Devices without HyperQ (SM 2.0 and SM 3.0) will run a maximum of two kernels concurrently.
### [simpleIPC](./simpleIPC) ### [simpleIPC](./simpleIPC)
This CUDA Runtime API sample is a very basic sample that demonstrates Inter Process Communication with one process per GPU for computation. Requires Compute Capability 3.0 or higher and a Linux Operating System, or a Windows Operating System with TCC enabled GPUs This CUDA Runtime API sample is a very basic sample that demonstrates Inter Process Communication with one process per GPU for computation. Requires Compute Capability 3.0 or higher and a Linux Operating System, or a Windows Operating System with TCC enabled GPUs
@ -82,9 +64,6 @@ Supported in GPUs with Compute Capability 1.1, overlapping compute with one memc
### [simpleMultiGPU](./simpleMultiGPU) ### [simpleMultiGPU](./simpleMultiGPU)
This application demonstrates how to use the new CUDA 4.0 API for CUDA context management and multi-threaded access to run CUDA kernels on multiple-GPUs. This application demonstrates how to use the new CUDA 4.0 API for CUDA context management and multi-threaded access to run CUDA kernels on multiple-GPUs.
### [simpleOccupancy](./simpleOccupancy)
This sample demonstrates the basic usage of the CUDA occupancy calculator and occupancy-based launch configurator APIs by launching a kernel with the launch configurator, and measures the utilization difference against a manually configured launch.
### [simpleP2P](./simpleP2P) ### [simpleP2P](./simpleP2P)
This application demonstrates CUDA APIs that support Peer-To-Peer (P2P) copies, Peer-To-Peer (P2P) addressing, and Unified Virtual Memory Addressing (UVA) between multiple GPUs. In general, P2P is supported between two same GPUs with some exceptions, such as some Tesla and Quadro GPUs. This application demonstrates CUDA APIs that support Peer-To-Peer (P2P) copies, Peer-To-Peer (P2P) addressing, and Unified Virtual Memory Addressing (UVA) between multiple GPUs. In general, P2P is supported between two same GPUs with some exceptions, such as some Tesla and Quadro GPUs.
@ -100,9 +79,6 @@ This sample uses CUDA streams to overlap kernel executions with memory copies be
### [simpleSurfaceWrite](./simpleSurfaceWrite) ### [simpleSurfaceWrite](./simpleSurfaceWrite)
Simple example that demonstrates the use of 2D surface references (Write-to-Texture) Simple example that demonstrates the use of 2D surface references (Write-to-Texture)
### [simpleTemplates](./simpleTemplates)
This sample is a templatized version of the template project. It also shows how to correctly templatize dynamically allocated shared memory arrays.
### [simpleTexture](./simpleTexture) ### [simpleTexture](./simpleTexture)
Simple example that demonstrates use of Textures in CUDA. Simple example that demonstrates use of Textures in CUDA.
@ -121,9 +97,6 @@ This sample illustrates how to use Zero MemCopy, kernels can read and write dire
### [systemWideAtomics](./systemWideAtomics) ### [systemWideAtomics](./systemWideAtomics)
A simple demonstration of system wide atomic instructions. A simple demonstration of system wide atomic instructions.
### [template](./template)
A trivial template project that can be used as a starting point to create new CUDA projects.
### [UnifiedMemoryStreams](./UnifiedMemoryStreams) ### [UnifiedMemoryStreams](./UnifiedMemoryStreams)
This sample demonstrates the use of OpenMP and streams with Unified Memory on a single GPU. This sample demonstrates the use of OpenMP and streams with Unified Memory on a single GPU.

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) 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(UnifiedMemoryStreams LANGUAGES C CXX CUDA) project(UnifiedMemoryStreams LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# This sample is not supported on QNX # This sample is not supported on QNX
@ -31,23 +27,15 @@ endif()
find_package(OpenMP COMPONENTS CXX) find_package(OpenMP COMPONENTS CXX)
if(OpenMP_CXX_FOUND) if(OpenMP_CXX_FOUND)
# Add target for UnifiedMemoryStreams
add_executable(UnifiedMemoryStreams UnifiedMemoryStreams.cu) add_executable(UnifiedMemoryStreams UnifiedMemoryStreams.cu)
target_compile_options(UnifiedMemoryStreams PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_options(UnifiedMemoryStreams PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_features(UnifiedMemoryStreams PRIVATE cxx_std_17 cuda_std_17)
target_compile_features(UnifiedMemoryStreams PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(UnifiedMemoryStreams PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_link_libraries(UnifiedMemoryStreams PUBLIC target_link_libraries(UnifiedMemoryStreams PUBLIC
CUDA::cublas CUDA::cublas
OpenMP::OpenMP_CXX OpenMP::OpenMP_CXX
) )
include(InstallSamples)
setup_samples_install()
else() else()
message(STATUS "OpenMP not found - will not build sample 'UnifiedMemoryStreams'") message(STATUS "OpenMP not found - will not build sample 'UnifiedMemoryStreams'")
endif() 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,34 +1,25 @@
cmake_minimum_required(VERSION 3.20) 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(asyncAPI LANGUAGES C CXX CUDA) project(asyncAPI LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file
# Add target for asyncAPI
add_executable(asyncAPI asyncAPI.cu) add_executable(asyncAPI asyncAPI.cu)
target_compile_options(asyncAPI PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(asyncAPI PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(asyncAPI PRIVATE cxx_std_17 cuda_std_17) target_compile_features(asyncAPI PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(asyncAPI PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() 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) 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(clock LANGUAGES C CXX CUDA) project(clock LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file
# Add target for asyncAPI
add_executable(clock clock.cu) add_executable(clock clock.cu)
target_compile_options(clock PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(clock PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(clock PRIVATE cxx_std_17 cuda_std_17) target_compile_features(clock PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(clock PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() setup_samples_install()

View File

@ -1,32 +1,79 @@
# clock - Clock # clock - Per-Block Kernel Timing with CUB Reduction
## Description ## Description
This example shows how to use the clock function to measure the performance of block of threads of a kernel accurately. A CUDA sample that demonstrates how to use the `clock()` function to accurately measure kernel execution time on a per-block basis. Each of the 64 blocks records its own start and end SM cycle counter, then performs a block-wide parallel **min-reduction** over 512 float elements using CUB's `BlockReduce`. The host collects all timestamps and computes the average elapsed clock cycles across all blocks.
Because blocks execute in parallel and out of order with no cross-block synchronization, each block independently measures its own execution time — this is the correct way to time GPU work at block granularity.
## What You'll Learn
- Using `clock()` inside a CUDA kernel to capture per-block SM cycle counts
- Performing a block-wide parallel reduction with `cub::BlockReduce` using a custom binary operator
- Loading multiple elements per thread (`ITEMS_PER_THREAD = 2`) for CUB reductions
- Understanding why only thread 0 holds the valid aggregate after a `BlockReduce`
- Querying device properties (`cudaDeviceGetAttribute`) without helper libraries
- Computing average elapsed clocks on the host from per-block timestamps
## Key Concepts ## Key Concepts
Performance Strategies - **SM Clock Counter**`clock()` reads the streaming multiprocessor's cycle counter; difference between two samples gives elapsed cycles for that block
- **CUB BlockReduce** — warp-shuffle-based block-scope reduction; default constructor allocates shared memory internally via `PrivateStorage()`, no explicit `TempStorage` needed
- **Items per thread** — each thread owns 2 elements; CUB's array overload of `Reduce` combines them before the cross-thread reduction
- **Per-block timing** — since blocks run independently, each block times itself; the host averages results across all blocks
## Supported SM Architectures ## Key APIs
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus) ### CUDA Runtime
- `cudaSetDevice` — select the active GPU for all subsequent CUDA calls
- `cudaDeviceGetAttribute` — query device properties (compute capability, SM count) without `cudaGetDeviceProperties`
- `cudaMalloc` / `cudaFree` — allocate and release device memory
- `cudaMemcpy` — transfer data between host and device
- `clock()` — device-side SM cycle counter (returns `clock_t`)
## Supported OSes ### CUB
- `cub::BlockReduce<T, BLOCK_THREADS>` — block-scope reduction template
- `BlockReduce::Reduce(T (&input)[ITEMS_PER_THREAD], ReductionOp op)` — reduce multiple items per thread with a custom binary operator
Linux, Windows ## Requirements
## Supported CPU Architecture ### Hardware
- NVIDIA GPU with Compute Capability 7.5 or higher
x86_64, armv7l ### Software
- CMake 3.20 or newer
- A C++17-capable host compiler
## CUDA APIs involved ## How to Build
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) 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.
cudaMalloc, cudaMemcpy, cudaFree
## Prerequisites ## How to Run
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ```bash
./clock
```
## References (for more details) No command-line arguments are required. The sample always runs on device 0.
## Expected Output
```text
CUDA Clock sample
GPU Device 0: with compute capability 8.9 and Number of SMs 142
Average clocks/block = 1239.640625
```
The average clocks value varies by GPU and reflects how many SM cycles each block takes to complete the reduction. Blocks scheduled later on a busy GPU will show higher elapsed times.
## Files
- `clock.cu` — kernel implementation and host driver
- `README.md` — this file
- `CMakeLists.txt` — build configuration
## See Also
- [CUB BlockReduce documentation](https://nvidia.github.io/cccl/unstable/cub/developer/block_scope.html)
- [CUDA C++ Programming Guide — clock()](https://docs.nvidia.com/cuda/cuda-programming-guide/05-appendices/cpp-language-support.html#clock-and-clock64)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. /* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -41,45 +41,36 @@
// CUDA runtime // CUDA runtime
#include <cuda_runtime.h> #include <cuda_runtime.h>
// helper functions and utilities to work with CUDA // CUB for block-scope reduction
#include <helper_cuda.h> #include <cub/cub.cuh>
#include <helper_functions.h>
#define NUM_BLOCKS 64
#define NUM_THREADS 256
// This kernel computes a standard parallel reduction and evaluates the // This kernel computes a standard parallel reduction and evaluates the
// time it takes to do that for each block. The timing results are stored // time it takes to do that for each block. The timing results are stored
// in device memory. // in device memory.
__global__ static void timedReduction(const float *input, float *output, clock_t *timer) __global__ static void timedReduction(const float *input, float *output, clock_t *timer)
{ {
// __shared__ float shared[2 * blockDim.x];
extern __shared__ float shared[];
const int tid = threadIdx.x; const int tid = threadIdx.x;
const int bid = blockIdx.x; const int bid = blockIdx.x;
if (tid == 0) if (tid == 0)
timer[bid] = clock(); timer[bid] = clock();
// Copy input. // Each thread loads 2 elements and reduces them to a local min.
shared[tid] = input[tid]; float thread_data[2];
shared[tid + blockDim.x] = input[tid + blockDim.x]; thread_data[0] = input[tid];
thread_data[1] = input[tid + blockDim.x];
// Perform reduction to find minimum. // Block-wide min-reduction using CUB. Default constructor allocates
for (int d = blockDim.x; d > 0; d /= 2) { // shared memory internally via PrivateStorage().
__syncthreads(); using BlockReduce = cub::BlockReduce<float, NUM_THREADS>;
float block_min = BlockReduce().Reduce(thread_data, [] __device__(float a, float b) { return fminf(a, b); });
if (tid < d) { // Only thread 0 holds the valid aggregate.
float f0 = shared[tid];
float f1 = shared[tid + d];
if (f1 < f0) {
shared[tid] = f1;
}
}
}
// Write result.
if (tid == 0) if (tid == 0)
output[bid] = shared[0]; output[bid] = block_min;
__syncthreads(); __syncthreads();
@ -87,33 +78,25 @@ __global__ static void timedReduction(const float *input, float *output, clock_t
timer[bid + gridDim.x] = clock(); timer[bid + gridDim.x] = clock();
} }
#define NUM_BLOCKS 64
#define NUM_THREADS 256
// It's interesting to change the number of blocks and the number of threads to
// understand how to keep the hardware busy.
//
// Here are some numbers I get on my G80:
// blocks - clocks
// 1 - 3096
// 8 - 3232
// 16 - 3364
// 32 - 4615
// 64 - 9981
//
// With less than 16 blocks some of the multiprocessors of the device are idle.
// With more than 16 you are using all the multiprocessors, but there's only one
// block per multiprocessor and that doesn't allow you to hide the latency of
// the memory. With more than 32 the speed scales linearly.
// Start the main CUDA Sample here // Start the main CUDA Sample here
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
printf("CUDA Clock sample\n"); printf("CUDA Clock sample\n");
// This will pick the best possible CUDA capable device // Select device 0 as the active GPU
int dev = findCudaDevice(argc, (const char **)argv); int devID = 0;
cudaSetDevice(devID);
// Query compute capability (major.minor) and number of SMs on the device
int major = 0, minor = 0, smCount = 0;
cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID);
cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID);
cudaDeviceGetAttribute(&smCount, cudaDevAttrMultiProcessorCount, devID);
// Print device info
printf("GPU Device %d: with compute capability %d.%d and Number of SMs %d\n\n", devID, major, minor, smCount);
// Device pointers for input data, per-block minimum output, and clock timestamps
float *dinput = NULL; float *dinput = NULL;
float *doutput = NULL; float *doutput = NULL;
clock_t *dtimer = NULL; clock_t *dtimer = NULL;
@ -125,19 +108,19 @@ int main(int argc, char **argv)
input[i] = (float)i; input[i] = (float)i;
} }
checkCudaErrors(cudaMalloc((void **)&dinput, sizeof(float) * NUM_THREADS * 2)); cudaMalloc((void **)&dinput, sizeof(float) * NUM_THREADS * 2);
checkCudaErrors(cudaMalloc((void **)&doutput, sizeof(float) * NUM_BLOCKS)); cudaMalloc((void **)&doutput, sizeof(float) * NUM_BLOCKS);
checkCudaErrors(cudaMalloc((void **)&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2)); cudaMalloc((void **)&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2);
checkCudaErrors(cudaMemcpy(dinput, input, sizeof(float) * NUM_THREADS * 2, cudaMemcpyHostToDevice)); cudaMemcpy(dinput, input, sizeof(float) * NUM_THREADS * 2, cudaMemcpyHostToDevice);
timedReduction<<<NUM_BLOCKS, NUM_THREADS, sizeof(float) * 2 * NUM_THREADS>>>(dinput, doutput, dtimer); timedReduction<<<NUM_BLOCKS, NUM_THREADS>>>(dinput, doutput, dtimer);
checkCudaErrors(cudaMemcpy(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2, cudaMemcpyDeviceToHost)); cudaMemcpy(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2, cudaMemcpyDeviceToHost);
checkCudaErrors(cudaFree(dinput)); cudaFree(dinput);
checkCudaErrors(cudaFree(doutput)); cudaFree(doutput);
checkCudaErrors(cudaFree(dtimer)); cudaFree(dtimer);
long double avgElapsedClocks = 0; long double avgElapsedClocks = 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,43 +0,0 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(clock_nvrtc 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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add sample target executable
add_executable(clock_nvrtc clock.cpp)
target_compile_options(clock_nvrtc PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(clock_nvrtc PRIVATE cxx_std_17 cuda_std_17)
target_link_libraries(clock_nvrtc PRIVATE
CUDA::nvrtc
CUDA::cuda_driver
)
# Copy clock_kernel.cu to the output directory
add_custom_command(TARGET clock_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/clock_kernel.cu ${CMAKE_CURRENT_BINARY_DIR}
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@ -1,39 +0,0 @@
# clock_nvrtc - Clock libNVRTC
## Description
This example shows how to use the clock function using libNVRTC to measure the performance of block of threads of a kernel accurately.
## Key Concepts
Performance Strategies, Runtime Compilation
## Supported SM Architectures
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
## Supported OSes
Linux, Windows, QNX
## Supported CPU Architecture
x86_64, aarch64
## CUDA APIs involved
### [CUDA Driver API](http://docs.nvidia.com/cuda/cuda-driver-api/index.html)
cuMemcpyDtoH, cuLaunchKernel, cuMemcpyHtoD, cuCtxSynchronize, cuMemAlloc, cuMemFree, cuModuleGetFunction
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
cudaBlockSize, cudaGridSize
## Dependencies needed to build/run
[NVRTC](../../../README.md#nvrtc)
## Prerequisites
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

View File

@ -1,137 +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.
*/
/*
* This example shows how to use the clock function to measure the performance
* of block of threads of a kernel accurately. Blocks are executed in parallel
* and out of order. Since there's no synchronization mechanism between blocks,
* we measure the clock once for each block. The clock samples are written to
* device memory.
*/
// System includes
#include <assert.h>
#include <cuda_runtime.h>
#include <nvrtc_helper.h>
#include <stdint.h>
#include <stdio.h>
// helper functions and utilities to work with CUDA
#include <helper_functions.h>
#define NUM_BLOCKS 64
#define NUM_THREADS 256
// It's interesting to change the number of blocks and the number of threads to
// understand how to keep the hardware busy.
//
// Here are some numbers I get on my G80:
// blocks - clocks
// 1 - 3096
// 8 - 3232
// 16 - 3364
// 32 - 4615
// 64 - 9981
//
// With less than 16 blocks some of the multiprocessors of the device are idle.
// With
// more than 16 you are using all the multiprocessors, but there's only one
// block per
// multiprocessor and that doesn't allow you to hide the latency of the memory.
// With
// more than 32 the speed scales linearly.
// Start the main CUDA Sample here
int main(int argc, char **argv)
{
printf("CUDA Clock sample\n");
typedef long clock_t;
clock_t timer[NUM_BLOCKS * 2];
float input[NUM_THREADS * 2];
for (int i = 0; i < NUM_THREADS * 2; i++) {
input[i] = (float)i;
}
char *cubin, *kernel_file;
size_t cubinSize;
kernel_file = sdkFindFilePath("clock_kernel.cu", argv[0]);
compileFileToCUBIN(kernel_file, argc, argv, &cubin, &cubinSize, 0);
CUmodule module = loadCUBIN(cubin, argc, argv);
CUfunction kernel_addr;
checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "timedReduction"));
dim3 cudaBlockSize(NUM_THREADS, 1, 1);
dim3 cudaGridSize(NUM_BLOCKS, 1, 1);
CUdeviceptr dinput, doutput, dtimer;
checkCudaErrors(cuMemAlloc(&dinput, sizeof(float) * NUM_THREADS * 2));
checkCudaErrors(cuMemAlloc(&doutput, sizeof(float) * NUM_BLOCKS));
checkCudaErrors(cuMemAlloc(&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
checkCudaErrors(cuMemcpyHtoD(dinput, input, sizeof(float) * NUM_THREADS * 2));
void *arr[] = {(void *)&dinput, (void *)&doutput, (void *)&dtimer};
checkCudaErrors(cuLaunchKernel(kernel_addr,
cudaGridSize.x,
cudaGridSize.y,
cudaGridSize.z, /* grid dim */
cudaBlockSize.x,
cudaBlockSize.y,
cudaBlockSize.z, /* block dim */
sizeof(float) * 2 * NUM_THREADS,
0, /* shared mem, stream */
&arr[0], /* arguments */
0));
checkCudaErrors(cuCtxSynchronize());
checkCudaErrors(cuMemcpyDtoH(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
checkCudaErrors(cuMemFree(dinput));
checkCudaErrors(cuMemFree(doutput));
checkCudaErrors(cuMemFree(dtimer));
long double avgElapsedClocks = 0;
for (int i = 0; i < NUM_BLOCKS; i++) {
avgElapsedClocks += (long double)(timer[i + NUM_BLOCKS] - timer[i]);
}
avgElapsedClocks = avgElapsedClocks / NUM_BLOCKS;
printf("Average clocks/block = %Lf\n", avgElapsedClocks);
return EXIT_SUCCESS;
}

View File

@ -1,77 +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.
*/
/*
* This example shows how to use the clock function to measure the performance
* of block of threads of a kernel accurately. Blocks are executed in parallel
* and out of order. Since there's no synchronization mechanism between blocks,
* we measure the clock once for each block. The clock samples are written to
* device memory.
*/
// This kernel computes a standard parallel reduction and evaluates the
// time it takes to do that for each block. The timing results are stored
// in device memory.
extern "C" __global__ void timedReduction(const float *input, float *output, clock_t *timer)
{
// __shared__ float shared[2 * blockDim.x];
extern __shared__ float shared[];
const int tid = threadIdx.x;
const int bid = blockIdx.x;
if (tid == 0)
timer[bid] = clock();
// Copy input.
shared[tid] = input[tid];
shared[tid + blockDim.x] = input[tid + blockDim.x];
// Perform reduction to find minimum.
for (int d = blockDim.x; d > 0; d /= 2) {
__syncthreads();
if (tid < d) {
float f0 = shared[tid];
float f1 = shared[tid + d];
if (f1 < f0) {
shared[tid] = f1;
}
}
}
// Write result.
if (tid == 0)
output[bid] = shared[0];
__syncthreads();
if (tid == 0)
timer[bid + gridDim.x] = clock();
}

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,43 +1,35 @@
cmake_minimum_required(VERSION 3.20) 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(cudaOpenMP LANGUAGES C CXX CUDA) project(cudaOpenMP LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
find_package(OpenMP) find_package(OpenMP)
# Source file
if(OpenMP_CXX_FOUND) if(OpenMP_CXX_FOUND)
# Add target for asyncAPI
add_executable(cudaOpenMP cudaOpenMP.cu) add_executable(cudaOpenMP cudaOpenMP.cu)
target_compile_options(cudaOpenMP PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(cudaOpenMP PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(cudaOpenMP PRIVATE cxx_std_17 cuda_std_17) target_compile_features(cudaOpenMP PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(cudaOpenMP PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_link_libraries(cudaOpenMP PUBLIC target_link_libraries(cudaOpenMP PUBLIC
OpenMP::OpenMP_CXX OpenMP::OpenMP_CXX
) )
include(InstallSamples)
setup_samples_install()
else() else()
message(STATUS "OpenMP not found - will not build sample 'cudaOpenMP'") message(STATUS "OpenMP not found - will not build sample 'cudaOpenMP'")
endif() 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,33 +1,31 @@
cmake_minimum_required(VERSION 3.20) 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(fp16ScalarProduct LANGUAGES C CXX CUDA) project(fp16ScalarProduct LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) 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} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else() else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries
include_directories(../../../Common) include_directories(../../../Common)
# Source file
# Add target for asyncAPI
add_executable(fp16ScalarProduct fp16ScalarProduct.cu) add_executable(fp16ScalarProduct fp16ScalarProduct.cu)
target_compile_options(fp16ScalarProduct PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(fp16ScalarProduct PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(fp16ScalarProduct PRIVATE cxx_std_17 cuda_std_17) target_compile_features(fp16ScalarProduct PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(fp16ScalarProduct PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() 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) 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(matrixMul LANGUAGES C CXX CUDA) project(matrixMul LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file
# Add target for asyncAPI
add_executable(matrixMul matrixMul.cu) add_executable(matrixMul matrixMul.cu)
target_compile_options(matrixMul PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(matrixMul PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(matrixMul PRIVATE cxx_std_17 cuda_std_17) target_compile_features(matrixMul PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(matrixMul PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() setup_samples_install()

View File

@ -2,7 +2,7 @@
## Description ## Description
This sample implements matrix multiplication and is exactly the same as the second example of the [Shared Memory](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory) section of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the CUDA 4.0+ interface for cuBLAS to demonstrate high-performance performance for matrix multiplication. This sample implements matrix multiplication. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the CUDA 4.0+ interface for cuBLAS to demonstrate high-performance matrix multiplication.
## Key Concepts ## Key Concepts
@ -14,7 +14,7 @@ CUDA Runtime API, Linear Algebra
## Supported OSes ## Supported OSes
Linux, Windows Linux, Windows, QNX (QNX Safety cross-build with CUDA Safe toolkit)
## Supported CPU Architecture ## Supported CPU Architecture

View File

@ -44,8 +44,12 @@
#include <stdio.h> #include <stdio.h>
// CUDA runtime // CUDA runtime
#include <cuda_profiler_api.h>
#include <cuda_runtime.h> #include <cuda_runtime.h>
// The CUDA Safe runtime does not ship the profiler API; gate it on header availability.
#if defined(__has_include) && __has_include(<cuda_profiler_api.h>)
#include <cuda_profiler_api.h>
#define HAVE_CUDA_PROFILER_API 1
#endif
// Helper functions and utilities to work with CUDA // Helper functions and utilities to work with CUDA
#include <helper_cuda.h> #include <helper_cuda.h>
@ -141,11 +145,11 @@ int MatrixMultiply(int argc, char **argv, int block_size, const dim3 &dimsA, con
unsigned int size_A = dimsA.x * dimsA.y; unsigned int size_A = dimsA.x * dimsA.y;
unsigned int mem_size_A = sizeof(float) * size_A; unsigned int mem_size_A = sizeof(float) * size_A;
float *h_A; float *h_A;
checkCudaErrors(cudaMallocHost(&h_A, mem_size_A)); checkCudaErrors(cudaMallocHost(&h_A, mem_size_A, 0));
unsigned int size_B = dimsB.x * dimsB.y; unsigned int size_B = dimsB.x * dimsB.y;
unsigned int mem_size_B = sizeof(float) * size_B; unsigned int mem_size_B = sizeof(float) * size_B;
float *h_B; float *h_B;
checkCudaErrors(cudaMallocHost(&h_B, mem_size_B)); checkCudaErrors(cudaMallocHost(&h_B, mem_size_B, 0));
cudaStream_t stream; cudaStream_t stream;
// Initialize host memory // Initialize host memory
@ -160,7 +164,7 @@ int MatrixMultiply(int argc, char **argv, int block_size, const dim3 &dimsA, con
dim3 dimsC(dimsB.x, dimsA.y, 1); dim3 dimsC(dimsB.x, dimsA.y, 1);
unsigned int mem_size_C = dimsC.x * dimsC.y * sizeof(float); unsigned int mem_size_C = dimsC.x * dimsC.y * sizeof(float);
float *h_C; float *h_C;
checkCudaErrors(cudaMallocHost(&h_C, mem_size_C)); checkCudaErrors(cudaMallocHost(&h_C, mem_size_C, 0));
if (h_C == NULL) { if (h_C == NULL) {
fprintf(stderr, "Failed to allocate host matrix C!\n"); fprintf(stderr, "Failed to allocate host matrix C!\n");
@ -334,9 +338,13 @@ int main(int argc, char **argv)
printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, dimsB.y); printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, dimsB.y);
#ifdef HAVE_CUDA_PROFILER_API
checkCudaErrors(cudaProfilerStart()); checkCudaErrors(cudaProfilerStart());
#endif
int matrix_result = MatrixMultiply(argc, argv, block_size, dimsA, dimsB); int matrix_result = MatrixMultiply(argc, argv, block_size, dimsA, dimsB);
#ifdef HAVE_CUDA_PROFILER_API
checkCudaErrors(cudaProfilerStop()); checkCudaErrors(cudaProfilerStop());
#endif
exit(matrix_result); exit(matrix_result);
} }

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) 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(matrixMulDrv LANGUAGES C CXX CUDA) project(matrixMulDrv LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file
# Add target for matrixMulDrv
add_executable(matrixMulDrv matrixMulDrv.cpp) add_executable(matrixMulDrv matrixMulDrv.cpp)
target_compile_options(matrixMulDrv PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(matrixMulDrv PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(matrixMulDrv PRIVATE cxx_std_17 cuda_std_17) target_compile_features(matrixMulDrv PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(matrixMulDrv PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
target_include_directories(matrixMulDrv PRIVATE target_include_directories(matrixMulDrv PRIVATE
${CUDAToolkit_INCLUDE_DIRS} ${CUDAToolkit_INCLUDE_DIRS}
) )
@ -56,7 +48,7 @@ endif()
add_custom_command( add_custom_command(
OUTPUT ${CUDA_FATBIN_FILE} OUTPUT ${CUDA_FATBIN_FILE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE} COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE}
DEPENDS ${CUDA_KERNEL_SOURCE} DEPENDS ${CUDA_KERNEL_SOURCE}
COMMENT "Building CUDA fatbin: ${CUDA_FATBIN_FILE}" COMMENT "Building CUDA fatbin: ${CUDA_FATBIN_FILE}"
) )
@ -67,6 +59,5 @@ add_custom_target(generate_fatbin_matmulDrv ALL DEPENDS ${CUDA_FATBIN_FILE})
# Ensure matrixMulDrv depends on the fatbin # Ensure matrixMulDrv depends on the fatbin
add_dependencies(matrixMulDrv generate_fatbin_matmulDrv) add_dependencies(matrixMulDrv generate_fatbin_matmulDrv)
# Include installation configuration include(InstallSamples)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() 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,26 +1,20 @@
cmake_minimum_required(VERSION 3.20) 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(matrixMulDynlinkJIT LANGUAGES C CXX CUDA) project(matrixMulDynlinkJIT LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file
# Add target for matrixMulDynlinkJIT
add_executable(matrixMulDynlinkJIT cuda_drvapi_dynlink.c matrixMulDynlinkJIT.cpp matrixMul_gold.cpp matrixMul_kernel_32_ptxdump.c matrixMul_kernel_64_ptxdump.c) add_executable(matrixMulDynlinkJIT cuda_drvapi_dynlink.c matrixMulDynlinkJIT.cpp matrixMul_gold.cpp matrixMul_kernel_32_ptxdump.c matrixMul_kernel_64_ptxdump.c)
target_compile_options(matrixMulDynlinkJIT PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(matrixMulDynlinkJIT PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
@ -28,7 +22,6 @@ target_compile_options(matrixMulDynlinkJIT PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--
target_compile_features(matrixMulDynlinkJIT PRIVATE cxx_std_17 cuda_std_17) target_compile_features(matrixMulDynlinkJIT PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(matrixMulDynlinkJIT PROPERTIES set_target_properties(matrixMulDynlinkJIT PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
POSITION_INDEPENDENT_CODE OFF POSITION_INDEPENDENT_CODE OFF
) )
@ -46,6 +39,5 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_link_libraries(matrixMulDynlinkJIT PUBLIC dl) target_link_libraries(matrixMulDynlinkJIT PUBLIC dl)
endif() endif()
# Include installation configuration include(InstallSamples)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() 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,61 +0,0 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(matrixMul_nvrtc 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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add sample target executable
add_executable(matrixMul_nvrtc matrixMul.cpp)
target_compile_options(matrixMul_nvrtc PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(matrixMul_nvrtc PRIVATE cxx_std_17 cuda_std_17)
target_link_libraries(matrixMul_nvrtc PRIVATE
CUDA::nvrtc
CUDA::cuda_driver
)
# The primary directory of CUDAToolkit_INCLUDE_DIRS is the CUDA Toolkit's include directory for finding the header files.
list(GET CUDAToolkit_INCLUDE_DIRS 0 CUDA_INCLUDE_DIR)
# Copy clock_kernel.cu to the output directory
add_custom_command(TARGET matrixMul_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/matrixMul_kernel.cu ${CUDA_INCLUDE_DIR}/cooperative_groups.h ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_command(TARGET matrixMul_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CUDA_INCLUDE_DIR}/cooperative_groups ${CMAKE_CURRENT_BINARY_DIR}/cooperative_groups
)
add_custom_command(TARGET matrixMul_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CUDA_INCLUDE_DIR}/cccl/nv ${CMAKE_CURRENT_BINARY_DIR}/nv
)
add_custom_command(TARGET matrixMul_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CUDA_INCLUDE_DIR}/cccl/cuda ${CMAKE_CURRENT_BINARY_DIR}/cuda
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@ -1,36 +0,0 @@
# matrixMul_nvrtc - Matrix Multiplication with libNVRTC
## Description
This sample implements matrix multiplication and is exactly the same as the second example of the [Shared Memory](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory) section of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the CUDA 4.0+ interface for cuBLAS to demonstrate high-performance performance for matrix multiplication.
## Key Concepts
CUDA Runtime API, Linear Algebra, Runtime Compilation
## Supported SM Architectures
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
## Supported OSes
Linux, Windows, QNX
## Supported CPU Architecture
x86_64, aarch64
## CUDA APIs involved
### [CUDA Driver API](http://docs.nvidia.com/cuda/cuda-driver-api/index.html)
cuMemcpyDtoH, cuLaunchKernel, cuMemcpyHtoD, cuCtxSynchronize, cuMemAlloc, cuMemFree, cuModuleGetFunction
## Dependencies needed to build/run
[NVRTC](../../../README.md#nvrtc)
## Prerequisites
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

View File

@ -1,249 +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.
*/
/**
* Matrix multiplication: C = A * B.
* Host code.
*
* This sample implements matrix multiplication as described in Chapter 3
* of the programming guide.
* It has been written for clarity of exposition to illustrate various CUDA
* programming principles, not with the goal of providing the most
* performant generic kernel for matrix multiplication.
*
* See also:
* V. Volkov and J. Demmel, "Benchmarking GPUs to tune dense linear algebra,"
* in Proc. 2008 ACM/IEEE Conf. on Supercomputing (SC '08),
* Piscataway, NJ: IEEE Press, 2008, pp. Art. 31:1-11.
*/
// System includes
#include <assert.h>
#include <stdio.h>
// CUDA runtime
#include <cuda_runtime.h>
#include "nvrtc_helper.h"
// Helper functions and utilities to work with CUDA
#include <helper_functions.h>
void constantInit(float *data, int size, float val)
{
for (int i = 0; i < size; ++i) {
data[i] = val;
}
}
/**
* Run a simple test of matrix multiplication using CUDA
*/
int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA, dim3 &dimsB)
{
// Allocate host memory for matrices A and B
unsigned int size_A = dimsA.x * dimsA.y;
unsigned int mem_size_A = sizeof(float) * size_A;
float *h_A = (float *)malloc(mem_size_A);
unsigned int size_B = dimsB.x * dimsB.y;
unsigned int mem_size_B = sizeof(float) * size_B;
float *h_B = (float *)malloc(mem_size_B);
// Initialize host memory
const float valB = 0.01f;
constantInit(h_A, size_A, 1.0f);
constantInit(h_B, size_B, valB);
// Allocate device memory
CUdeviceptr d_A, d_B, d_C;
char *cubin, *kernel_file;
size_t cubinSize;
kernel_file = sdkFindFilePath("matrixMul_kernel.cu", argv[0]);
compileFileToCUBIN(kernel_file, argc, argv, &cubin, &cubinSize, 1);
CUmodule module = loadCUBIN(cubin, argc, argv);
// Allocate host matrix C
dim3 dimsC(dimsB.x, dimsA.y, 1);
unsigned int mem_size_C = dimsC.x * dimsC.y * sizeof(float);
float *h_C = (float *)malloc(mem_size_C);
if (h_C == NULL) {
fprintf(stderr, "Failed to allocate host matrix C!\n");
exit(EXIT_FAILURE);
}
checkCudaErrors(cuMemAlloc(&d_A, mem_size_A));
checkCudaErrors(cuMemAlloc(&d_B, mem_size_B));
checkCudaErrors(cuMemAlloc(&d_C, mem_size_C));
// copy host memory to device
checkCudaErrors(cuMemcpyHtoD(d_A, h_A, mem_size_A));
checkCudaErrors(cuMemcpyHtoD(d_B, h_B, mem_size_B));
// Setup execution parameters
dim3 threads(block_size, block_size);
dim3 grid(dimsB.x / threads.x, dimsA.y / threads.y);
// Create and start timer
printf("Computing result using CUDA Kernel...\n");
CUfunction kernel_addr;
if (block_size == 16) {
checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block16"));
}
else {
checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block32"));
}
void *arr[] = {(void *)&d_C, (void *)&d_A, (void *)&d_B, (void *)&dimsA.x, (void *)&dimsB.x};
// Execute the kernel
int nIter = 300;
for (int j = 0; j < nIter; j++) {
checkCudaErrors(cuLaunchKernel(kernel_addr,
grid.x,
grid.y,
grid.z, /* grid dim */
threads.x,
threads.y,
threads.z, /* block dim */
0,
0, /* shared mem, stream */
&arr[0], /* arguments */
0));
checkCudaErrors(cuCtxSynchronize());
}
// Copy result from device to host
checkCudaErrors(cuMemcpyDtoH(h_C, d_C, mem_size_C));
printf("Checking computed result for correctness: ");
bool correct = true;
// test relative error by the formula
// |<x, y>_cpu - <x,y>_gpu|/<|x|, |y|> < eps
double eps = 1.e-6; // machine zero
for (int i = 0; i < (int)(dimsC.x * dimsC.y); i++) {
double abs_err = fabs(h_C[i] - (dimsA.x * valB));
double dot_length = dimsA.x;
double abs_val = fabs(h_C[i]);
double rel_err = abs_err / abs_val / dot_length;
if (rel_err > eps) {
printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > %E\n", i, h_C[i], dimsA.x * valB, eps);
correct = false;
}
}
printf("%s\n", correct ? "Result = PASS" : "Result = FAIL");
printf("\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n");
// Clean up memory
free(h_A);
free(h_B);
free(h_C);
checkCudaErrors(cuMemFree(d_A));
checkCudaErrors(cuMemFree(d_B));
checkCudaErrors(cuMemFree(d_C));
if (correct) {
return EXIT_SUCCESS;
}
else {
return EXIT_FAILURE;
}
}
/**
* Program main
*/
int main(int argc, char **argv)
{
printf("[Matrix Multiply Using CUDA] - Starting...\n");
if (checkCmdLineFlag(argc, (const char **)argv, "help") || checkCmdLineFlag(argc, (const char **)argv, "?")) {
printf("Usage -device=n (n >= 0 for deviceID)\n");
printf(" -wA=WidthA -hA=HeightA (Width x Height of Matrix A)\n");
printf(" -wB=WidthB -hB=HeightB (Width x Height of Matrix B)\n");
printf(" Note: Outer matrix dimensions of A & B matrices must be equal.\n");
exit(EXIT_SUCCESS);
}
int block_size = 32;
// original:
dim3 dimsA(5 * 2 * block_size, 5 * 2 * block_size, 1);
dim3 dimsB(5 * 4 * block_size, 5 * 2 * block_size, 1);
// reduce sizes to avoid running out of memory
// dim3 dimsA(32,32, 1);
// dim3 dimsB(32,32,1);
// width of Matrix A
if (checkCmdLineFlag(argc, (const char **)argv, "wA")) {
dimsA.x = getCmdLineArgumentInt(argc, (const char **)argv, "wA");
}
// height of Matrix A
if (checkCmdLineFlag(argc, (const char **)argv, "hA")) {
dimsA.y = getCmdLineArgumentInt(argc, (const char **)argv, "hA");
}
// width of Matrix B
if (checkCmdLineFlag(argc, (const char **)argv, "wB")) {
dimsB.x = getCmdLineArgumentInt(argc, (const char **)argv, "wB");
}
// height of Matrix B
if (checkCmdLineFlag(argc, (const char **)argv, "hB")) {
dimsB.y = getCmdLineArgumentInt(argc, (const char **)argv, "hB");
}
if (dimsA.x != dimsB.y) {
printf("Error: outer matrix dimensions must be equal. (%d != %d)\n", dimsA.x, dimsB.y);
exit(EXIT_FAILURE);
}
printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, dimsB.y);
int matrix_result = matrixMultiply(argc, argv, block_size, dimsA, dimsB);
exit(matrix_result);
}

View File

@ -1,130 +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.
*/
/**
* Matrix multiplication: C = A * B.
* Host code.
*
* This sample implements matrix multiplication as described in Chapter 3
* of the programming guide.
* It has been written for clarity of exposition to illustrate various CUDA
* programming principles, not with the goal of providing the most
* performant generic kernel for matrix multiplication.
*
* See also:
* V. Volkov and J. Demmel, "Benchmarking GPUs to tune dense linear algebra,"
* in Proc. 2008 ACM/IEEE Conf. on Supercomputing (SC '08),
* Piscataway, NJ: IEEE Press, 2008, pp. Art. 31:1-11.
*/
/**
* Matrix multiplication (CUDA Kernel) on the device: C = A * B
* wA is A's width and wB is B's width
*/
#include <cooperative_groups.h>
template <int BLOCK_SIZE> __device__ void matrixMulCUDA(float *C, float *A, float *B, int wA, int wB)
{
// Handle to thread block group
cooperative_groups::thread_block cta = cooperative_groups::this_thread_block();
// Block index
int bx = blockIdx.x;
int by = blockIdx.y;
// Thread index
int tx = threadIdx.x;
int ty = threadIdx.y;
// Index of the first sub-matrix of A processed by the block
int aBegin = wA * BLOCK_SIZE * by;
// Index of the last sub-matrix of A processed by the block
int aEnd = aBegin + wA - 1;
// Step size used to iterate through the sub-matrices of A
int aStep = BLOCK_SIZE;
// Index of the first sub-matrix of B processed by the block
int bBegin = BLOCK_SIZE * bx;
// Step size used to iterate through the sub-matrices of B
int bStep = BLOCK_SIZE * wB;
// Csub is used to store the element of the block sub-matrix
// that is computed by the thread
float Csub = 0;
// Loop over all the sub-matrices of A and B
// required to compute the block sub-matrix
for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) {
// Declaration of the shared memory array As used to
// store the sub-matrix of A
__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
// Declaration of the shared memory array Bs used to
// store the sub-matrix of B
__shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
// Load the matrices from device memory
// to shared memory; each thread loads
// one element of each matrix
As[ty][tx] = A[a + wA * ty + tx];
Bs[ty][tx] = B[b + wB * ty + tx];
// Synchronize to make sure the matrices are loaded
cooperative_groups::sync(cta);
// Multiply the two matrices together;
// each thread computes one element
// of the block sub-matrix
#pragma unroll
for (int k = 0; k < BLOCK_SIZE; ++k) {
Csub += As[ty][k] * Bs[k][tx];
}
// Synchronize to make sure that the preceding
// computation is done before loading two new
// sub-matrices of A and B in the next iteration
cooperative_groups::sync(cta);
}
// Write the block sub-matrix to device memory;
// each thread writes one element
int c = wB * BLOCK_SIZE * by + BLOCK_SIZE * bx;
C[c + wB * ty + tx] = Csub;
}
extern "C" __global__ void matrixMulCUDA_block16(float *C, float *A, float *B, int wA, int wB)
{
matrixMulCUDA<16>(C, A, B, wA, wB);
}
extern "C" __global__ void matrixMulCUDA_block32(float *C, float *A, float *B, int wA, int wB)
{
matrixMulCUDA<32>(C, A, B, wA, wB);
}

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,32 +0,0 @@
# mergeSort - Merge Sort
## Description
This sample implements a merge sort (also known as Batcher's sort), algorithms belonging to the class of sorting networks. While generally subefficient on large sequences compared to algorithms with better asymptotic algorithmic complexity (i.e. merge sort or radix sort), may be the algorithms of choice for sorting batches of short- to mid-sized (key, value) array pairs. Refer to the excellent tutorial by H. W. Lang http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/indexen.htm
## Key Concepts
Data-Parallel Algorithms
## Supported SM Architectures
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
## Supported OSes
Linux, Windows
## Supported CPU Architecture
x86_64, armv7l
## CUDA APIs involved
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
cudaMalloc, cudaDeviceSynchronize, cudaMemcpy, cudaFree
## Prerequisites
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details)

View File

@ -1,281 +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>
namespace cg = cooperative_groups;
#include <assert.h>
#include <helper_cuda.h>
#include "mergeSort_common.h"
inline __device__ void Comparator(uint &keyA, uint &valA, uint &keyB, uint &valB, uint arrowDir)
{
uint t;
if ((keyA > keyB) == arrowDir) {
t = keyA;
keyA = keyB;
keyB = t;
t = valA;
valA = valB;
valB = t;
}
}
__global__ void
bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, uint *d_SrcVal, uint arrayLength, uint sortDir)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
// Shared memory storage for one or more short vectors
__shared__ uint s_key[SHARED_SIZE_LIMIT];
__shared__ uint s_val[SHARED_SIZE_LIMIT];
// Offset to the beginning of subbatch and load data
d_SrcKey += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_SrcVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_DstKey += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
s_key[threadIdx.x + 0] = d_SrcKey[0];
s_val[threadIdx.x + 0] = d_SrcVal[0];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcKey[(SHARED_SIZE_LIMIT / 2)];
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
for (uint size = 2; size < arrayLength; size <<= 1) {
// Bitonic merge
uint dir = (threadIdx.x & (size / 2)) != 0;
for (uint stride = size / 2; stride > 0; stride >>= 1) {
cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], s_val[pos + stride], dir);
}
}
// ddd == sortDir for the last bitonic merge step
{
for (uint stride = arrayLength / 2; stride > 0; stride >>= 1) {
cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], s_val[pos + stride], sortDir);
}
}
cg::sync(cta);
d_DstKey[0] = s_key[threadIdx.x + 0];
d_DstVal[0] = s_val[threadIdx.x + 0];
d_DstKey[(SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
d_DstVal[(SHARED_SIZE_LIMIT / 2)] = s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
}
// Helper function (also used by odd-even merge sort)
extern "C" uint factorRadix2(uint *log2L, uint L)
{
if (!L) {
*log2L = 0;
return 0;
}
else {
for (*log2L = 0; (L & 1) == 0; L >>= 1, *log2L++)
;
return L;
}
}
extern "C" void bitonicSortShared(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir)
{
// Nothing to sort
if (arrayLength < 2) {
return;
}
// Only power-of-two array lengths are supported by this implementation
uint log2L;
uint factorizationRemainder = factorRadix2(&log2L, arrayLength);
assert(factorizationRemainder == 1);
uint blockCount = batchSize * arrayLength / SHARED_SIZE_LIMIT;
uint threadCount = SHARED_SIZE_LIMIT / 2;
assert(arrayLength <= SHARED_SIZE_LIMIT);
assert((batchSize * arrayLength) % SHARED_SIZE_LIMIT == 0);
bitonicSortSharedKernel<<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength, sortDir);
getLastCudaError("bitonicSortSharedKernel<<<>>> failed!\n");
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 3: merge elementary intervals
////////////////////////////////////////////////////////////////////////////////
static inline __host__ __device__ uint iDivUp(uint a, uint b) { return ((a % b) == 0) ? (a / b) : (a / b + 1); }
static inline __host__ __device__ uint getSampleCount(uint dividend) { return iDivUp(dividend, SAMPLE_STRIDE); }
template <uint sortDir>
static inline __device__ void
ComparatorExtended(uint &keyA, uint &valA, uint &flagA, uint &keyB, uint &valB, uint &flagB, uint arrowDir)
{
uint t;
if ((!(flagA || flagB) && ((keyA > keyB) == arrowDir)) || ((arrowDir == sortDir) && (flagA == 1))
|| ((arrowDir != sortDir) && (flagB == 1))) {
t = keyA;
keyA = keyB;
keyB = t;
t = valA;
valA = valB;
valB = t;
t = flagA;
flagA = flagB;
flagB = t;
}
}
template <uint sortDir>
__global__ void bitonicMergeElementaryIntervalsKernel(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[2 * SAMPLE_STRIDE];
__shared__ uint s_val[2 * SAMPLE_STRIDE];
__shared__ uint s_inf[2 * SAMPLE_STRIDE];
const uint intervalI = blockIdx.x & ((2 * stride) / SAMPLE_STRIDE - 1);
const uint segmentBase = (blockIdx.x - intervalI) * SAMPLE_STRIDE;
d_SrcKey += segmentBase;
d_SrcVal += segmentBase;
d_DstKey += segmentBase;
d_DstVal += segmentBase;
// Set up threadblock-wide parameters
__shared__ uint startSrcA, lenSrcA, startSrcB, lenSrcB, startDst;
if (threadIdx.x == 0) {
uint segmentElementsA = stride;
uint segmentElementsB = umin(stride, N - segmentBase - stride);
uint segmentSamplesA = stride / SAMPLE_STRIDE;
uint segmentSamplesB = getSampleCount(segmentElementsB);
uint segmentSamples = segmentSamplesA + segmentSamplesB;
startSrcA = d_LimitsA[blockIdx.x];
startSrcB = d_LimitsB[blockIdx.x];
startDst = startSrcA + startSrcB;
uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] : segmentElementsA;
uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1] : segmentElementsB;
lenSrcA = endSrcA - startSrcA;
lenSrcB = endSrcB - startSrcB;
}
s_inf[threadIdx.x + 0] = 1;
s_inf[threadIdx.x + SAMPLE_STRIDE] = 1;
// Load input data
cg::sync(cta);
if (threadIdx.x < lenSrcA) {
s_key[threadIdx.x] = d_SrcKey[0 + startSrcA + threadIdx.x];
s_val[threadIdx.x] = d_SrcVal[0 + startSrcA + threadIdx.x];
s_inf[threadIdx.x] = 0;
}
// Prepare for bitonic merge by inversing the ordering
if (threadIdx.x < lenSrcB) {
s_key[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = d_SrcKey[stride + startSrcB + threadIdx.x];
s_val[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = d_SrcVal[stride + startSrcB + threadIdx.x];
s_inf[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = 0;
}
//"Extended" bitonic merge
for (uint stride = SAMPLE_STRIDE; stride > 0; stride >>= 1) {
cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
ComparatorExtended<sortDir>(s_key[pos + 0],
s_val[pos + 0],
s_inf[pos + 0],
s_key[pos + stride],
s_val[pos + stride],
s_inf[pos + stride],
sortDir);
}
// Store sorted data
cg::sync(cta);
d_DstKey += startDst;
d_DstVal += startDst;
if (threadIdx.x < lenSrcA) {
d_DstKey[threadIdx.x] = s_key[threadIdx.x];
d_DstVal[threadIdx.x] = s_val[threadIdx.x];
}
if (threadIdx.x < lenSrcB) {
d_DstKey[lenSrcA + threadIdx.x] = s_key[lenSrcA + threadIdx.x];
d_DstVal[lenSrcA + threadIdx.x] = s_val[lenSrcA + threadIdx.x];
}
}
extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
if (sortDir) {
bitonicMergeElementaryIntervalsKernel<1U>
<<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n");
}
else {
bitonicMergeElementaryIntervalsKernel<0U>
<<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n");
}
}

View File

@ -1,119 +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 <assert.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#include <stdio.h>
#include <stdlib.h>
#include "mergeSort_common.h"
////////////////////////////////////////////////////////////////////////////////
// Test driver
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
uint *h_SrcKey, *h_SrcVal, *h_DstKey, *h_DstVal;
uint *d_SrcKey, *d_SrcVal, *d_BufKey, *d_BufVal, *d_DstKey, *d_DstVal;
StopWatchInterface *hTimer = NULL;
const uint N = 4 * 1048576;
const uint DIR = 1;
const uint numValues = 65536;
printf("%s Starting...\n\n", argv[0]);
int dev = findCudaDevice(argc, (const char **)argv);
if (dev == -1) {
return EXIT_FAILURE;
}
printf("Allocating and initializing host arrays...\n\n");
sdkCreateTimer(&hTimer);
h_SrcKey = (uint *)malloc(N * sizeof(uint));
h_SrcVal = (uint *)malloc(N * sizeof(uint));
h_DstKey = (uint *)malloc(N * sizeof(uint));
h_DstVal = (uint *)malloc(N * sizeof(uint));
srand(2009);
for (uint i = 0; i < N; i++) {
h_SrcKey[i] = rand() % numValues;
}
fillValues(h_SrcVal, N);
printf("Allocating and initializing CUDA arrays...\n\n");
checkCudaErrors(cudaMalloc((void **)&d_DstKey, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_DstVal, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_BufKey, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_BufVal, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_SrcKey, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_SrcVal, N * sizeof(uint)));
checkCudaErrors(cudaMemcpy(d_SrcKey, h_SrcKey, N * sizeof(uint), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_SrcVal, h_SrcVal, N * sizeof(uint), cudaMemcpyHostToDevice));
printf("Initializing GPU merge sort...\n");
initMergeSort();
printf("Running GPU merge sort...\n");
checkCudaErrors(cudaDeviceSynchronize());
sdkResetTimer(&hTimer);
sdkStartTimer(&hTimer);
mergeSort(d_DstKey, d_DstVal, d_BufKey, d_BufVal, d_SrcKey, d_SrcVal, N, DIR);
checkCudaErrors(cudaDeviceSynchronize());
sdkStopTimer(&hTimer);
printf("Time: %f ms\n", sdkGetTimerValue(&hTimer));
printf("Reading back GPU merge sort results...\n");
checkCudaErrors(cudaMemcpy(h_DstKey, d_DstKey, N * sizeof(uint), cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_DstVal, d_DstVal, N * sizeof(uint), cudaMemcpyDeviceToHost));
printf("Inspecting the results...\n");
uint keysFlag = validateSortedKeys(h_DstKey, h_SrcKey, 1, N, numValues, DIR);
uint valuesFlag = validateSortedValues(h_DstKey, h_DstVal, h_SrcKey, 1, N);
printf("Shutting down...\n");
closeMergeSort();
sdkDeleteTimer(&hTimer);
checkCudaErrors(cudaFree(d_SrcVal));
checkCudaErrors(cudaFree(d_SrcKey));
checkCudaErrors(cudaFree(d_BufVal));
checkCudaErrors(cudaFree(d_BufKey));
checkCudaErrors(cudaFree(d_DstVal));
checkCudaErrors(cudaFree(d_DstKey));
free(h_DstVal);
free(h_DstKey);
free(h_SrcVal);
free(h_SrcKey);
exit((keysFlag && valuesFlag) ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@ -1,537 +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.
*/
/*
* Based on "Designing efficient sorting algorithms for manycore GPUs"
* by Nadathur Satish, Mark Harris, and Michael Garland
* http://mgarland.org/files/papers/gpusort-ipdps09.pdf
*
* Victor Podlozhnyuk 09/24/2009
*/
#include <assert.h>
#include <cooperative_groups.h>
namespace cg = cooperative_groups;
#include <helper_cuda.h>
#include "mergeSort_common.h"
////////////////////////////////////////////////////////////////////////////////
// Helper functions
////////////////////////////////////////////////////////////////////////////////
static inline __host__ __device__ uint iDivUp(uint a, uint b) { return ((a % b) == 0) ? (a / b) : (a / b + 1); }
static inline __host__ __device__ uint getSampleCount(uint dividend) { return iDivUp(dividend, SAMPLE_STRIDE); }
#define W (sizeof(uint) * 8)
static inline __device__ uint nextPowerOfTwo(uint x)
{
/*
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
*/
return 1U << (W - __clz(x - 1));
}
template <uint sortDir> static inline __device__ uint binarySearchInclusive(uint val, uint *data, uint L, uint stride)
{
if (L == 0) {
return 0;
}
uint pos = 0;
for (; stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] <= val)) || (!sortDir && (data[newPos - 1] >= val))) {
pos = newPos;
}
}
return pos;
}
template <uint sortDir> static inline __device__ uint binarySearchExclusive(uint val, uint *data, uint L, uint stride)
{
if (L == 0) {
return 0;
}
uint pos = 0;
for (; stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] < val)) || (!sortDir && (data[newPos - 1] > val))) {
pos = newPos;
}
}
return pos;
}
////////////////////////////////////////////////////////////////////////////////
// Bottom-level merge sort (binary search-based)
////////////////////////////////////////////////////////////////////////////////
template <uint sortDir>
__global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, uint *d_SrcVal, uint arrayLength)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[SHARED_SIZE_LIMIT];
__shared__ uint s_val[SHARED_SIZE_LIMIT];
d_SrcKey += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_SrcVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_DstKey += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
s_key[threadIdx.x + 0] = d_SrcKey[0];
s_val[threadIdx.x + 0] = d_SrcVal[0];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcKey[(SHARED_SIZE_LIMIT / 2)];
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
for (uint stride = 1; stride < arrayLength; stride <<= 1) {
uint lPos = threadIdx.x & (stride - 1);
uint *baseKey = s_key + 2 * (threadIdx.x - lPos);
uint *baseVal = s_val + 2 * (threadIdx.x - lPos);
cg::sync(cta);
uint keyA = baseKey[lPos + 0];
uint valA = baseVal[lPos + 0];
uint keyB = baseKey[lPos + stride];
uint valB = baseVal[lPos + stride];
uint posA = binarySearchExclusive<sortDir>(keyA, baseKey + stride, stride, stride) + lPos;
uint posB = binarySearchInclusive<sortDir>(keyB, baseKey + 0, stride, stride) + lPos;
cg::sync(cta);
baseKey[posA] = keyA;
baseVal[posA] = valA;
baseKey[posB] = keyB;
baseVal[posB] = valB;
}
cg::sync(cta);
d_DstKey[0] = s_key[threadIdx.x + 0];
d_DstVal[0] = s_val[threadIdx.x + 0];
d_DstKey[(SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
d_DstVal[(SHARED_SIZE_LIMIT / 2)] = s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
}
static void mergeSortShared(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir)
{
if (arrayLength < 2) {
return;
}
assert(SHARED_SIZE_LIMIT % arrayLength == 0);
assert(((batchSize * arrayLength) % SHARED_SIZE_LIMIT) == 0);
uint blockCount = batchSize * arrayLength / SHARED_SIZE_LIMIT;
uint threadCount = SHARED_SIZE_LIMIT / 2;
if (sortDir) {
mergeSortSharedKernel<1U><<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength);
getLastCudaError("mergeSortShared<1><<<>>> failed\n");
}
else {
mergeSortSharedKernel<0U><<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength);
getLastCudaError("mergeSortShared<0><<<>>> failed\n");
}
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 1: generate sample ranks
////////////////////////////////////////////////////////////////////////////////
template <uint sortDir>
__global__ void
generateSampleRanksKernel(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey, uint stride, uint N, uint threadCount)
{
uint pos = blockIdx.x * blockDim.x + threadIdx.x;
if (pos >= threadCount) {
return;
}
const uint i = pos & ((stride / SAMPLE_STRIDE) - 1);
const uint segmentBase = (pos - i) * (2 * SAMPLE_STRIDE);
d_SrcKey += segmentBase;
d_RanksA += segmentBase / SAMPLE_STRIDE;
d_RanksB += segmentBase / SAMPLE_STRIDE;
const uint segmentElementsA = stride;
const uint segmentElementsB = umin(stride, N - segmentBase - stride);
const uint segmentSamplesA = getSampleCount(segmentElementsA);
const uint segmentSamplesB = getSampleCount(segmentElementsB);
if (i < segmentSamplesA) {
d_RanksA[i] = i * SAMPLE_STRIDE;
d_RanksB[i] = binarySearchExclusive<sortDir>(
d_SrcKey[i * SAMPLE_STRIDE], d_SrcKey + stride, segmentElementsB, nextPowerOfTwo(segmentElementsB));
}
if (i < segmentSamplesB) {
d_RanksB[(stride / SAMPLE_STRIDE) + i] = i * SAMPLE_STRIDE;
d_RanksA[(stride / SAMPLE_STRIDE) + i] = binarySearchInclusive<sortDir>(
d_SrcKey[stride + i * SAMPLE_STRIDE], d_SrcKey + 0, segmentElementsA, nextPowerOfTwo(segmentElementsA));
}
}
static void generateSampleRanks(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey, uint stride, uint N, uint sortDir)
{
uint lastSegmentElements = N % (2 * stride);
uint threadCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
if (sortDir) {
generateSampleRanksKernel<1U>
<<<iDivUp(threadCount, 256), 256>>>(d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount);
getLastCudaError("generateSampleRanksKernel<1U><<<>>> failed\n");
}
else {
generateSampleRanksKernel<0U>
<<<iDivUp(threadCount, 256), 256>>>(d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount);
getLastCudaError("generateSampleRanksKernel<0U><<<>>> failed\n");
}
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 2: generate sample ranks and indices
////////////////////////////////////////////////////////////////////////////////
__global__ void mergeRanksAndIndicesKernel(uint *d_Limits, uint *d_Ranks, uint stride, uint N, uint threadCount)
{
uint pos = blockIdx.x * blockDim.x + threadIdx.x;
if (pos >= threadCount) {
return;
}
const uint i = pos & ((stride / SAMPLE_STRIDE) - 1);
const uint segmentBase = (pos - i) * (2 * SAMPLE_STRIDE);
d_Ranks += (pos - i) * 2;
d_Limits += (pos - i) * 2;
const uint segmentElementsA = stride;
const uint segmentElementsB = umin(stride, N - segmentBase - stride);
const uint segmentSamplesA = getSampleCount(segmentElementsA);
const uint segmentSamplesB = getSampleCount(segmentElementsB);
if (i < segmentSamplesA) {
uint dstPos = binarySearchExclusive<1U>(
d_Ranks[i], d_Ranks + segmentSamplesA, segmentSamplesB, nextPowerOfTwo(segmentSamplesB))
+ i;
d_Limits[dstPos] = d_Ranks[i];
}
if (i < segmentSamplesB) {
uint dstPos = binarySearchInclusive<1U>(
d_Ranks[segmentSamplesA + i], d_Ranks, segmentSamplesA, nextPowerOfTwo(segmentSamplesA))
+ i;
d_Limits[dstPos] = d_Ranks[segmentSamplesA + i];
}
}
static void mergeRanksAndIndices(uint *d_LimitsA, uint *d_LimitsB, uint *d_RanksA, uint *d_RanksB, uint stride, uint N)
{
uint lastSegmentElements = N % (2 * stride);
uint threadCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>(d_LimitsA, d_RanksA, stride, N, threadCount);
getLastCudaError("mergeRanksAndIndicesKernel(A)<<<>>> failed\n");
mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>(d_LimitsB, d_RanksB, stride, N, threadCount);
getLastCudaError("mergeRanksAndIndicesKernel(B)<<<>>> failed\n");
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 3: merge elementary intervals
////////////////////////////////////////////////////////////////////////////////
template <uint sortDir>
inline __device__ void merge(uint *dstKey,
uint *dstVal,
uint *srcAKey,
uint *srcAVal,
uint *srcBKey,
uint *srcBVal,
uint lenA,
uint nPowTwoLenA,
uint lenB,
uint nPowTwoLenB,
cg::thread_block cta)
{
uint keyA, valA, keyB, valB, dstPosA, dstPosB;
if (threadIdx.x < lenA) {
keyA = srcAKey[threadIdx.x];
valA = srcAVal[threadIdx.x];
dstPosA = binarySearchExclusive<sortDir>(keyA, srcBKey, lenB, nPowTwoLenB) + threadIdx.x;
}
if (threadIdx.x < lenB) {
keyB = srcBKey[threadIdx.x];
valB = srcBVal[threadIdx.x];
dstPosB = binarySearchInclusive<sortDir>(keyB, srcAKey, lenA, nPowTwoLenA) + threadIdx.x;
}
cg::sync(cta);
if (threadIdx.x < lenA) {
dstKey[dstPosA] = keyA;
dstVal[dstPosA] = valA;
}
if (threadIdx.x < lenB) {
dstKey[dstPosB] = keyB;
dstVal[dstPosB] = valB;
}
}
template <uint sortDir>
__global__ void mergeElementaryIntervalsKernel(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[2 * SAMPLE_STRIDE];
__shared__ uint s_val[2 * SAMPLE_STRIDE];
const uint intervalI = blockIdx.x & ((2 * stride) / SAMPLE_STRIDE - 1);
const uint segmentBase = (blockIdx.x - intervalI) * SAMPLE_STRIDE;
d_SrcKey += segmentBase;
d_SrcVal += segmentBase;
d_DstKey += segmentBase;
d_DstVal += segmentBase;
// Set up threadblock-wide parameters
__shared__ uint startSrcA, startSrcB, lenSrcA, lenSrcB, startDstA, startDstB;
if (threadIdx.x == 0) {
uint segmentElementsA = stride;
uint segmentElementsB = umin(stride, N - segmentBase - stride);
uint segmentSamplesA = getSampleCount(segmentElementsA);
uint segmentSamplesB = getSampleCount(segmentElementsB);
uint segmentSamples = segmentSamplesA + segmentSamplesB;
startSrcA = d_LimitsA[blockIdx.x];
startSrcB = d_LimitsB[blockIdx.x];
uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] : segmentElementsA;
uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1] : segmentElementsB;
lenSrcA = endSrcA - startSrcA;
lenSrcB = endSrcB - startSrcB;
startDstA = startSrcA + startSrcB;
startDstB = startDstA + lenSrcA;
}
// Load main input data
cg::sync(cta);
if (threadIdx.x < lenSrcA) {
s_key[threadIdx.x + 0] = d_SrcKey[0 + startSrcA + threadIdx.x];
s_val[threadIdx.x + 0] = d_SrcVal[0 + startSrcA + threadIdx.x];
}
if (threadIdx.x < lenSrcB) {
s_key[threadIdx.x + SAMPLE_STRIDE] = d_SrcKey[stride + startSrcB + threadIdx.x];
s_val[threadIdx.x + SAMPLE_STRIDE] = d_SrcVal[stride + startSrcB + threadIdx.x];
}
// Merge data in shared memory
cg::sync(cta);
merge<sortDir>(s_key,
s_val,
s_key + 0,
s_val + 0,
s_key + SAMPLE_STRIDE,
s_val + SAMPLE_STRIDE,
lenSrcA,
SAMPLE_STRIDE,
lenSrcB,
SAMPLE_STRIDE,
cta);
// Store merged data
cg::sync(cta);
if (threadIdx.x < lenSrcA) {
d_DstKey[startDstA + threadIdx.x] = s_key[threadIdx.x];
d_DstVal[startDstA + threadIdx.x] = s_val[threadIdx.x];
}
if (threadIdx.x < lenSrcB) {
d_DstKey[startDstB + threadIdx.x] = s_key[lenSrcA + threadIdx.x];
d_DstVal[startDstB + threadIdx.x] = s_val[lenSrcA + threadIdx.x];
}
}
static void mergeElementaryIntervals(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
if (sortDir) {
mergeElementaryIntervalsKernel<1U>
<<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n");
}
else {
mergeElementaryIntervalsKernel<0U>
<<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n");
}
}
extern "C" void bitonicSortShared(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir);
extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey,
uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N,
uint sortDir);
static uint *d_RanksA, *d_RanksB, *d_LimitsA, *d_LimitsB;
static const uint MAX_SAMPLE_COUNT = 32768;
extern "C" void initMergeSort(void)
{
checkCudaErrors(cudaMalloc((void **)&d_RanksA, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_RanksB, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_LimitsA, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_LimitsB, MAX_SAMPLE_COUNT * sizeof(uint)));
}
extern "C" void closeMergeSort(void)
{
checkCudaErrors(cudaFree(d_RanksA));
checkCudaErrors(cudaFree(d_RanksB));
checkCudaErrors(cudaFree(d_LimitsB));
checkCudaErrors(cudaFree(d_LimitsA));
}
extern "C" void mergeSort(uint *d_DstKey,
uint *d_DstVal,
uint *d_BufKey,
uint *d_BufVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint N,
uint sortDir)
{
uint stageCount = 0;
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1, stageCount++)
;
uint *ikey, *ival, *okey, *oval;
if (stageCount & 1) {
ikey = d_BufKey;
ival = d_BufVal;
okey = d_DstKey;
oval = d_DstVal;
}
else {
ikey = d_DstKey;
ival = d_DstVal;
okey = d_BufKey;
oval = d_BufVal;
}
assert(N <= (SAMPLE_STRIDE * MAX_SAMPLE_COUNT));
assert(N % SHARED_SIZE_LIMIT == 0);
mergeSortShared(ikey, ival, d_SrcKey, d_SrcVal, N / SHARED_SIZE_LIMIT, SHARED_SIZE_LIMIT, sortDir);
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1) {
uint lastSegmentElements = N % (2 * stride);
// Find sample ranks and prepare for limiters merge
generateSampleRanks(d_RanksA, d_RanksB, ikey, stride, N, sortDir);
// Merge ranks and indices
mergeRanksAndIndices(d_LimitsA, d_LimitsB, d_RanksA, d_RanksB, stride, N);
// Merge elementary intervals
mergeElementaryIntervals(okey, oval, ikey, ival, d_LimitsA, d_LimitsB, stride, N, sortDir);
if (lastSegmentElements <= stride) {
// Last merge segment consists of a single array which just needs to be
// passed through
checkCudaErrors(cudaMemcpy(okey + (N - lastSegmentElements),
ikey + (N - lastSegmentElements),
lastSegmentElements * sizeof(uint),
cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemcpy(oval + (N - lastSegmentElements),
ival + (N - lastSegmentElements),
lastSegmentElements * sizeof(uint),
cudaMemcpyDeviceToDevice));
}
uint *t;
t = ikey;
ikey = okey;
okey = t;
t = ival;
ival = oval;
oval = t;
}
}

View File

@ -1,60 +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.
*/
////////////////////////////////////////////////////////////////////////////////
// Shortcut definitions
////////////////////////////////////////////////////////////////////////////////
typedef unsigned int uint;
#define SHARED_SIZE_LIMIT 1024U
#define SAMPLE_STRIDE 128
////////////////////////////////////////////////////////////////////////////////
// Extensive sort validation routine
////////////////////////////////////////////////////////////////////////////////
extern "C" uint
validateSortedKeys(uint *resKey, uint *srcKey, uint batchSize, uint arrayLength, uint numValues, uint sortDir);
extern "C" void fillValues(uint *val, uint N);
extern "C" int validateSortedValues(uint *resKey, uint *resVal, uint *srcKey, uint batchSize, uint arrayLength);
////////////////////////////////////////////////////////////////////////////////
// CUDA merge sort
////////////////////////////////////////////////////////////////////////////////
extern "C" void initMergeSort(void);
extern "C" void closeMergeSort(void);
extern "C" void
mergeSort(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir);
////////////////////////////////////////////////////////////////////////////////
// CPU "emulation"
////////////////////////////////////////////////////////////////////////////////
extern "C" void
mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir);

View File

@ -1,363 +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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mergeSort_common.h"
////////////////////////////////////////////////////////////////////////////////
// Helper functions
////////////////////////////////////////////////////////////////////////////////
static void checkOrder(uint *data, uint N, uint sortDir)
{
if (N <= 1) {
return;
}
for (uint i = 0; i < N - 1; i++)
if ((sortDir && (data[i] > data[i + 1])) || (!sortDir && (data[i] < data[i + 1]))) {
fprintf(stderr, "checkOrder() failed!!!\n");
exit(EXIT_FAILURE);
}
}
static uint umin(uint a, uint b) { return (a <= b) ? a : b; }
static uint getSampleCount(uint dividend)
{
return ((dividend % SAMPLE_STRIDE) != 0) ? (dividend / SAMPLE_STRIDE + 1) : (dividend / SAMPLE_STRIDE);
}
static uint nextPowerOfTwo(uint x)
{
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
static uint binarySearchInclusive(uint val, uint *data, uint L, uint sortDir)
{
if (L == 0) {
return 0;
}
uint pos = 0;
for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] <= val)) || (!sortDir && (data[newPos - 1] >= val))) {
pos = newPos;
}
}
return pos;
}
static uint binarySearchExclusive(uint val, uint *data, uint L, uint sortDir)
{
if (L == 0) {
return 0;
}
uint pos = 0;
for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] < val)) || (!sortDir && (data[newPos - 1] > val))) {
pos = newPos;
}
}
return pos;
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 1: find sample ranks in each segment
////////////////////////////////////////////////////////////////////////////////
static void generateSampleRanks(uint *ranksA, uint *ranksB, uint *srcKey, uint stride, uint N, uint sortDir)
{
uint lastSegmentElements = N % (2 * stride);
uint sampleCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
for (uint pos = 0; pos < sampleCount; pos++) {
const uint i = pos & ((stride / SAMPLE_STRIDE) - 1);
const uint segmentBase = (pos - i) * (2 * SAMPLE_STRIDE);
const uint lenA = stride;
const uint lenB = umin(stride, N - segmentBase - stride);
const uint nA = stride / SAMPLE_STRIDE;
const uint nB = getSampleCount(lenB);
if (i < nA) {
ranksA[(segmentBase + 0) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE;
ranksB[(segmentBase + 0) / SAMPLE_STRIDE + i] = binarySearchExclusive(
srcKey[segmentBase + i * SAMPLE_STRIDE], srcKey + segmentBase + stride, lenB, sortDir);
}
if (i < nB) {
ranksB[(segmentBase + stride) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE;
ranksA[(segmentBase + stride) / SAMPLE_STRIDE + i] = binarySearchInclusive(
srcKey[segmentBase + stride + i * SAMPLE_STRIDE], srcKey + segmentBase, lenA, sortDir);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 2: merge ranks and indices to derive elementary intervals
////////////////////////////////////////////////////////////////////////////////
static void mergeRanksAndIndices(uint *limits, uint *ranks, uint stride, uint N)
{
uint lastSegmentElements = N % (2 * stride);
uint sampleCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
for (uint pos = 0; pos < sampleCount; pos++) {
const uint i = pos & ((stride / SAMPLE_STRIDE) - 1);
const uint segmentBase = (pos - i) * (2 * SAMPLE_STRIDE);
const uint lenA = stride;
const uint lenB = umin(stride, N - segmentBase - stride);
const uint nA = stride / SAMPLE_STRIDE;
const uint nB = getSampleCount(lenB);
if (i < nA) {
uint dstPosA =
binarySearchExclusive(
ranks[(segmentBase + 0) / SAMPLE_STRIDE + i], ranks + (segmentBase + stride) / SAMPLE_STRIDE, nB, 1)
+ i;
assert(dstPosA < nA + nB);
limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = ranks[(segmentBase + 0) / SAMPLE_STRIDE + i];
}
if (i < nB) {
uint dstPosA =
binarySearchInclusive(
ranks[(segmentBase + stride) / SAMPLE_STRIDE + i], ranks + (segmentBase + 0) / SAMPLE_STRIDE, nA, 1)
+ i;
assert(dstPosA < nA + nB);
limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = ranks[(segmentBase + stride) / SAMPLE_STRIDE + i];
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Merge step 3: merge elementary intervals (each interval is <= SAMPLE_STRIDE)
////////////////////////////////////////////////////////////////////////////////
static void merge(uint *dstKey,
uint *dstVal,
uint *srcAKey,
uint *srcAVal,
uint *srcBKey,
uint *srcBVal,
uint lenA,
uint lenB,
uint sortDir)
{
checkOrder(srcAKey, lenA, sortDir);
checkOrder(srcBKey, lenB, sortDir);
for (uint i = 0; i < lenA; i++) {
uint dstPos = binarySearchExclusive(srcAKey[i], srcBKey, lenB, sortDir) + i;
assert(dstPos < lenA + lenB);
dstKey[dstPos] = srcAKey[i];
dstVal[dstPos] = srcAVal[i];
}
for (uint i = 0; i < lenB; i++) {
uint dstPos = binarySearchInclusive(srcBKey[i], srcAKey, lenA, sortDir) + i;
assert(dstPos < lenA + lenB);
dstKey[dstPos] = srcBKey[i];
dstVal[dstPos] = srcBVal[i];
}
}
static void mergeElementaryIntervals(uint *dstKey,
uint *dstVal,
uint *srcKey,
uint *srcVal,
uint *limitsA,
uint *limitsB,
uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
for (uint pos = 0; pos < mergePairs; pos++) {
uint i = pos & ((2 * stride) / SAMPLE_STRIDE - 1);
uint segmentBase = (pos - i) * SAMPLE_STRIDE;
const uint lenA = stride;
const uint lenB = umin(stride, N - segmentBase - stride);
const uint nA = stride / SAMPLE_STRIDE;
const uint nB = getSampleCount(lenB);
const uint n = nA + nB;
const uint startPosA = limitsA[pos];
const uint endPosA = (i + 1 < n) ? limitsA[pos + 1] : lenA;
const uint startPosB = limitsB[pos];
const uint endPosB = (i + 1 < n) ? limitsB[pos + 1] : lenB;
const uint startPosDst = startPosA + startPosB;
assert(startPosA <= endPosA && endPosA <= lenA);
assert(startPosB <= endPosB && endPosB <= lenB);
assert((endPosA - startPosA) <= SAMPLE_STRIDE);
assert((endPosB - startPosB) <= SAMPLE_STRIDE);
merge(dstKey + segmentBase + startPosDst,
dstVal + segmentBase + startPosDst,
(srcKey + segmentBase + 0) + startPosA,
(srcVal + segmentBase + 0) + startPosA,
(srcKey + segmentBase + stride) + startPosB,
(srcVal + segmentBase + stride) + startPosB,
endPosA - startPosA,
endPosB - startPosB,
sortDir);
}
}
////////////////////////////////////////////////////////////////////////////////
// Retarded bubble sort
////////////////////////////////////////////////////////////////////////////////
static void bubbleSort(uint *key, uint *val, uint N, uint sortDir)
{
if (N <= 1) {
return;
}
for (uint bottom = 0; bottom < N - 1; bottom++) {
uint savePos = bottom;
uint saveKey = key[bottom];
for (uint i = bottom + 1; i < N; i++)
if ((sortDir && (key[i] < saveKey)) || (!sortDir && (key[i] > saveKey))) {
savePos = i;
saveKey = key[i];
}
if (savePos != bottom) {
uint t;
t = key[savePos];
key[savePos] = key[bottom];
key[bottom] = t;
t = val[savePos];
val[savePos] = val[bottom];
val[bottom] = t;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Interface function
////////////////////////////////////////////////////////////////////////////////
extern "C" void
mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir)
{
uint *ikey, *ival, *okey, *oval;
uint stageCount = 0;
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1, stageCount++)
;
if (stageCount & 1) {
ikey = bufKey;
ival = bufVal;
okey = dstKey;
oval = dstVal;
}
else {
ikey = dstKey;
ival = dstVal;
okey = bufKey;
oval = bufVal;
}
printf("Bottom-level sort...\n");
memcpy(ikey, srcKey, N * sizeof(uint));
memcpy(ival, srcVal, N * sizeof(uint));
for (uint pos = 0; pos < N; pos += SHARED_SIZE_LIMIT) {
bubbleSort(ikey + pos, ival + pos, umin(SHARED_SIZE_LIMIT, N - pos), sortDir);
}
printf("Merge...\n");
uint *ranksA = (uint *)malloc(getSampleCount(N) * sizeof(uint));
uint *ranksB = (uint *)malloc(getSampleCount(N) * sizeof(uint));
uint *limitsA = (uint *)malloc(getSampleCount(N) * sizeof(uint));
uint *limitsB = (uint *)malloc(getSampleCount(N) * sizeof(uint));
memset(ranksA, 0xFF, getSampleCount(N) * sizeof(uint));
memset(ranksB, 0xFF, getSampleCount(N) * sizeof(uint));
memset(limitsA, 0xFF, getSampleCount(N) * sizeof(uint));
memset(limitsB, 0xFF, getSampleCount(N) * sizeof(uint));
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1) {
uint lastSegmentElements = N % (2 * stride);
// Find sample ranks and prepare for limiters merge
generateSampleRanks(ranksA, ranksB, ikey, stride, N, sortDir);
// Merge ranks and indices
mergeRanksAndIndices(limitsA, ranksA, stride, N);
mergeRanksAndIndices(limitsB, ranksB, stride, N);
// Merge elementary intervals
mergeElementaryIntervals(okey, oval, ikey, ival, limitsA, limitsB, stride, N, sortDir);
if (lastSegmentElements <= stride) {
// Last merge segment consists of a single array which just needs to be
// passed through
memcpy(
okey + (N - lastSegmentElements), ikey + (N - lastSegmentElements), lastSegmentElements * sizeof(uint));
memcpy(
oval + (N - lastSegmentElements), ival + (N - lastSegmentElements), lastSegmentElements * sizeof(uint));
}
uint *t;
t = ikey;
ikey = okey;
okey = t;
t = ival;
ival = oval;
oval = t;
}
free(limitsB);
free(limitsA);
free(ranksB);
free(ranksA);
}

View File

@ -1,128 +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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mergeSort_common.h"
////////////////////////////////////////////////////////////////////////////////
// Validate sorted keys array (check for integrity and proper order)
////////////////////////////////////////////////////////////////////////////////
extern "C" uint
validateSortedKeys(uint *resKey, uint *srcKey, uint batchSize, uint arrayLength, uint numValues, uint sortDir)
{
uint *srcHist;
uint *resHist;
if (arrayLength < 2) {
printf("validateSortedKeys(): arrays too short, exiting...\n");
return 1;
}
printf("...inspecting keys array: ");
srcHist = (uint *)malloc(numValues * sizeof(uint));
resHist = (uint *)malloc(numValues * sizeof(uint));
int flag = 1;
for (uint j = 0; j < batchSize; j++, srcKey += arrayLength, resKey += arrayLength) {
// Build histograms for keys arrays
memset(srcHist, 0, numValues * sizeof(uint));
memset(resHist, 0, numValues * sizeof(uint));
for (uint i = 0; i < arrayLength; i++) {
if ((srcKey[i] < numValues) && (resKey[i] < numValues)) {
srcHist[srcKey[i]]++;
resHist[resKey[i]]++;
}
else {
fprintf(stderr, "***Set %u source/result key arrays are not limited properly***\n", j);
flag = 0;
goto brk;
}
}
// Compare the histograms
for (uint i = 0; i < numValues; i++)
if (srcHist[i] != resHist[i]) {
fprintf(stderr, "***Set %u source/result keys histograms do not match***\n", j);
flag = 0;
goto brk;
}
// Finally check the ordering
for (uint i = 0; i < arrayLength - 1; i++)
if ((sortDir && (resKey[i] > resKey[i + 1])) || (!sortDir && (resKey[i] < resKey[i + 1]))) {
fprintf(stderr, "***Set %u result key array is not ordered properly***\n", j);
flag = 0;
goto brk;
}
}
brk:
free(resHist);
free(srcHist);
if (flag)
printf("OK\n");
return flag;
}
////////////////////////////////////////////////////////////////////////////////
// Value validation / stability check routines
////////////////////////////////////////////////////////////////////////////////
extern "C" void fillValues(uint *val, uint N)
{
for (uint i = 0; i < N; i++)
val[i] = i;
}
extern "C" int validateSortedValues(uint *resKey, uint *resVal, uint *srcKey, uint batchSize, uint arrayLength)
{
int correctFlag = 1, stableFlag = 1;
printf("...inspecting keys and values array: ");
for (uint i = 0; i < batchSize; i++, resKey += arrayLength, resVal += arrayLength) {
for (uint j = 0; j < arrayLength; j++) {
if (resKey[j] != srcKey[resVal[j]])
correctFlag = 0;
if ((j < arrayLength - 1) && (resKey[j] == resKey[j + 1]) && (resVal[j] > resVal[j + 1]))
stableFlag = 0;
}
}
printf(correctFlag ? "OK\n" : "***corrupted!!!***\n");
printf(stableFlag ? "...stability property: stable!\n" : "...stability property: NOT stable\n");
return correctFlag;
}

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) 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(simpleAWBarrier LANGUAGES C CXX CUDA) project(simpleAWBarrier LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# This sample is not supported on QNX # This sample is not supported on QNX
@ -26,16 +21,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
return() return()
endif() endif()
# Source file
# Add target for simpleAWBarrier
add_executable(simpleAWBarrier simpleAWBarrier.cu) add_executable(simpleAWBarrier simpleAWBarrier.cu)
target_compile_options(simpleAWBarrier PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(simpleAWBarrier PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(simpleAWBarrier PRIVATE cxx_std_17 cuda_std_17) target_compile_features(simpleAWBarrier PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(simpleAWBarrier PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() 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,37 +1,28 @@
cmake_minimum_required(VERSION 3.20) 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(simpleAssert LANGUAGES C CXX CUDA) project(simpleAssert LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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()
# Removes -DNDEBUG For Print specific logs in this sample. # Removes -DNDEBUG For Print specific logs in this sample.
string(REPLACE "-DNDEBUG" "" CMAKE_CUDA_FLAGS_RELEASE "${CMAKE_CUDA_FLAGS_RELEASE}") string(REPLACE "-DNDEBUG" "" CMAKE_CUDA_FLAGS_RELEASE "${CMAKE_CUDA_FLAGS_RELEASE}")
# Include directories and libraries
include_directories(../../../Common) include_directories(../../../Common)
# Source file
# Add target for simpleAssert
add_executable(simpleAssert simpleAssert.cu) add_executable(simpleAssert simpleAssert.cu)
target_compile_options(simpleAssert PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(simpleAssert PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(simpleAssert PRIVATE cxx_std_17 cuda_std_17) target_compile_features(simpleAssert PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(simpleAssert PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() setup_samples_install()

View File

@ -1,32 +1,83 @@
# simpleAssert - simpleAssert # Sample: Device-Side assert (simpleAssert)
## Description ## Description
This CUDA Runtime API sample is a very basic sample that implements how to use the assert function in the device code. Requires Compute Capability 2.0 . Use the standard C `assert` macro **inside a CUDA kernel**. The sample launches threads that each assert `gtid < N`; threads whose global index reaches `N` trip the assertion, print a diagnostic message to the host, and cause the kernel to fail. The host detects this through the `cudaErrorAssert` status returned by `cudaDeviceSynchronize` and reports it as the expected outcome.
This sample demonstrates device-side `assert`, a debugging aid for catching invalid conditions in kernel code, and shows how an assertion failure surfaces on the host as an asynchronous CUDA error.
## What You'll Learn
- Calling `assert` directly from device code (`__global__` kernel)
- How a failed device assertion is reported to the host as `cudaErrorAssert`
- Detecting that error after the launch via `cudaDeviceSynchronize`
- Computing a global thread index from `blockIdx`, `blockDim`, and `threadIdx`
- Turning an error code into a human-readable message with `cudaGetErrorString`
## Key Concepts ## Key Concepts
Assert - **Device-side `assert`**`assert(condition)` in a kernel; a false condition halts the kernel, prints `file:line: function: block: ... Assertion ... failed`, and flags the launch as failed
- **Asynchronous error reporting** — the assertion failure is not seen at launch time; it is surfaced at the next synchronization point as `cudaErrorAssert`
- **Global thread indexing**`blockIdx.x * blockDim.x + threadIdx.x`
## Supported SM Architectures ## Key APIs
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus) ### CUDA Runtime
- `cudaSetDevice` — select the active GPU
- `cudaDeviceGetAttribute` — query compute capability (major, minor) and SM count
- `cudaDeviceSynchronize` — block the host until the kernel finishes; flushes assert output and returns `cudaErrorAssert` if an assertion failed
- `cudaGetErrorString` — convert a `cudaError_t` into a readable description
## Supported OSes ## Requirements
Linux, Windows ### Hardware
- NVIDIA GPU with Compute Capability 7.5 or higher
## Supported CPU Architecture ### Software
- CMake 3.20 or newer
- A C++17-capable host compiler
x86_64, armv7l ## How to Build
## CUDA APIs involved 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.
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) ## How to Run
cudaDeviceSynchronize, cudaGetErrorString
## Prerequisites ```bash
./simpleAssert
```
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Expected Output
## References (for more details) The kernel launches 2 blocks × 32 threads = 64 threads and asserts `gtid < 60`, so the 4 threads with global indices 6063 fail the assertion. The assertion failures are **expected** — the sample reports `OK` because it successfully detected `cudaErrorAssert`:
```text
simpleAssert starting...
GPU Device 0: with compute capability X.Y and Number of SMs <smCount>
Launch kernel to generate assertion failures
-- Begin assert output
simpleAssert.cu:50: void simpleAssertKernel(int): block: [1,0,0], thread: [28,0,0] Assertion `gtid < N` failed.
...
-- End assert output
Device assert failed as expected, CUDA error message is: device-side assert triggered
simpleAssert completed, returned OK
```
The order and exact set of failing-thread lines may vary between runs.
## Files
- `simpleAssert.cu` — device-side `assert` kernel + host driver
- `README.md` — this file
- `CMakeLists.txt` — build configuration
## See Also
- [CUDA C++ Programming Guide - Assertion](https://docs.nvidia.com/cuda/cuda-programming-guide/05-appendices/cpp-language-extensions.html#assertion)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. /* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -25,86 +25,47 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifdef _WIN32 // System includes
#define WINDOWS_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
// Includes, system
#include <cassert> #include <cassert>
#include <stdio.h> #include <stdio.h>
// Includes CUDA // CUDA runtime
#include <cuda_runtime.h> #include <cuda_runtime.h>
// Utilities and timing functions
#include <helper_functions.h> // includes cuda.h and cuda_runtime_api.h
// CUDA helper functions
#include <helper_cuda.h> // helper functions for CUDA error check
const char *sampleName = "simpleAssert"; const char *sampleName = "simpleAssert";
////////////////////////////////////////////////////////////////////////////////
// Auto-Verification Code // Auto-Verification Code
bool testResult = true; bool testResult = true;
//////////////////////////////////////////////////////////////////////////////// // Each thread computes its global index and asserts it is below N. Threads with
// Kernels // gtid >= N trip the assertion, which aborts the kernel and surfaces on the host
//////////////////////////////////////////////////////////////////////////////// // as cudaErrorAssert at the next synchronization point.
//! Tests assert function. __global__ void simpleAssertKernel(int N)
//! Thread whose id > N will print assertion failed error message.
////////////////////////////////////////////////////////////////////////////////
__global__ void testKernel(int N)
{ {
int gtid = blockIdx.x * blockDim.x + threadIdx.x; int gtid = blockIdx.x * blockDim.x + threadIdx.x;
assert(gtid < N); assert(gtid < N);
} }
////////////////////////////////////////////////////////////////////////////////
// Declaration, forward
void runTest(int argc, char **argv);
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName);
runTest(argc, argv);
printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!");
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
void runTest(int argc, char **argv)
{ {
int Nblocks = 2; int Nblocks = 2;
int Nthreads = 32; int Nthreads = 32;
cudaError_t error; cudaError_t error;
#ifndef _WIN32 printf("%s starting...\n\n", sampleName);
utsname OS_System_Type;
uname(&OS_System_Type);
printf("OS_System_Type.release = %s\n", OS_System_Type.release); // Select device 0 as the active GPU
int devID = 0;
cudaSetDevice(devID);
if (!strcasecmp(OS_System_Type.sysname, "Darwin")) { // Query compute capability (major.minor) and number of SMs on the device
printf("simpleAssert is not current supported on Mac OSX\n\n"); int major = 0, minor = 0, smCount = 0;
exit(EXIT_SUCCESS); cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID);
} cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID);
else { cudaDeviceGetAttribute(&smCount, cudaDevAttrMultiProcessorCount, devID);
printf("OS Info: <%s>\n\n", OS_System_Type.version);
}
#endif // Print device info
printf("GPU Device %d: with compute capability %d.%d and Number of SMs %d\n\n", devID, major, minor, smCount);
// This will pick the best possible CUDA capable device
findCudaDevice(argc, (const char **)argv);
// Kernel configuration, where a one-dimensional // Kernel configuration, where a one-dimensional
// grid and one-dimensional blocks are configured. // grid and one-dimensional blocks are configured.
@ -112,7 +73,7 @@ void runTest(int argc, char **argv)
dim3 dimBlock(Nthreads); dim3 dimBlock(Nthreads);
printf("Launch kernel to generate assertion failures\n"); printf("Launch kernel to generate assertion failures\n");
testKernel<<<dimGrid, dimBlock>>>(60); simpleAssertKernel<<<dimGrid, dimBlock>>>(60);
// Synchronize (flushes assert output). // Synchronize (flushes assert output).
printf("\n-- Begin assert output\n\n"); printf("\n-- Begin assert output\n\n");
@ -127,4 +88,7 @@ void runTest(int argc, char **argv)
} }
testResult = error == cudaErrorAssert; testResult = error == cudaErrorAssert;
printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!");
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }

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,43 +0,0 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(simpleAssert_nvrtc 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()
# Include directories and libraries
include_directories(../../../Common)
# Source file
# Add sample target executable
add_executable(simpleAssert_nvrtc simpleAssert.cpp)
target_compile_options(simpleAssert_nvrtc PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(simpleAssert_nvrtc PRIVATE cxx_std_17 cuda_std_17)
target_link_libraries(simpleAssert_nvrtc PRIVATE
CUDA::nvrtc
CUDA::cuda_driver
)
# Copy clock_kernel.cu to the output directory
add_custom_command(TARGET simpleAssert_nvrtc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/simpleAssert_kernel.cu ${CMAKE_CURRENT_BINARY_DIR}
)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install()

View File

@ -1,36 +0,0 @@
# simpleAssert_nvrtc - simpleAssert with libNVRTC
## Description
This CUDA Runtime API sample is a very basic sample that implements how to use the assert function in the device code. Requires Compute Capability 2.0 .
## Key Concepts
Assert, Runtime Compilation
## Supported SM Architectures
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
## Supported OSes
Linux, Windows, QNX
## Supported CPU Architecture
x86_64, aarch64
## CUDA APIs involved
### [CUDA Driver API](http://docs.nvidia.com/cuda/cuda-driver-api/index.html)
cuModuleGetFunction, cuLaunchKernel, cuCtxSynchronize
## Dependencies needed to build/run
[NVRTC](../../../README.md#nvrtc)
## Prerequisites
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

View File

@ -1,121 +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.
*/
#ifdef _WIN32
#define WINDOWS_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#else
#include <sys/utsname.h>
#endif
// Includes, system
#include <cassert>
#include <stdio.h>
// Includes CUDA
#include <cuda_runtime.h>
#include "nvrtc_helper.h"
// Utilities and timing functions
#include <helper_functions.h> // includes cuda.h and cuda_runtime_api.h
const char *sampleName = "simpleAssert_nvrtc";
////////////////////////////////////////////////////////////////////////////////
// Auto-Verification Code
bool testResult = true;
////////////////////////////////////////////////////////////////////////////////
// Declaration, forward
void runTest(int argc, char **argv);
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName);
runTest(argc, argv);
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
void runTest(int argc, char **argv)
{
int Nblocks = 2;
int Nthreads = 32;
// Kernel configuration, where a one-dimensional
// grid and one-dimensional blocks are configured.
dim3 dimGrid(Nblocks);
dim3 dimBlock(Nthreads);
printf("Launch kernel to generate assertion failures\n");
char *cubin, *kernel_file;
size_t cubinSize;
kernel_file = sdkFindFilePath("simpleAssert_kernel.cu", argv[0]);
compileFileToCUBIN(kernel_file, argc, argv, &cubin, &cubinSize, 0);
CUmodule module = loadCUBIN(cubin, argc, argv);
CUfunction kernel_addr;
checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "testKernel"));
int count = 60;
void *args[] = {(void *)&count};
checkCudaErrors(cuLaunchKernel(kernel_addr,
dimGrid.x,
dimGrid.y,
dimGrid.z, /* grid dim */
dimBlock.x,
dimBlock.y,
dimBlock.z, /* block dim */
0,
0, /* shared mem, stream */
&args[0], /* arguments */
0));
// Synchronize (flushes assert output).
printf("\n-- Begin assert output\n\n");
CUresult res = cuCtxSynchronize();
printf("\n-- End assert output\n\n");
// Check for errors and failed asserts in asynchronous kernel launch.
if (res == CUDA_ERROR_ASSERT) {
printf("Device assert failed as expected\n");
}
testResult = res == CUDA_ERROR_ASSERT;
}

View File

@ -1,39 +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.
*/
////////////////////////////////////////////////////////////////////////////////
// Kernels
////////////////////////////////////////////////////////////////////////////////
//! Tests assert function.
//! Thread whose id > N will print assertion failed error message.
////////////////////////////////////////////////////////////////////////////////
extern "C" __global__ void testKernel(int N)
{
int gtid = blockIdx.x * blockDim.x + threadIdx.x;
assert(gtid < N);
}

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) 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(simpleAtomicIntrinsics LANGUAGES C CXX CUDA) project(simpleAtomicIntrinsics LANGUAGES C CXX CUDA)
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/CudaSampleCommon.cmake")
find_package(CUDAToolkit REQUIRED) 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) include_directories(../../../Common)
# Source file add_executable(simpleAtomicIntrinsics simpleAtomicIntrinsics.cu)
# Add target for simpleAtomicIntrinsics
add_executable(simpleAtomicIntrinsics simpleAtomicIntrinsics.cu simpleAtomicIntrinsics_cpu.cpp)
target_compile_options(simpleAtomicIntrinsics PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>) target_compile_options(simpleAtomicIntrinsics PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
target_compile_features(simpleAtomicIntrinsics PRIVATE cxx_std_17 cuda_std_17) target_compile_features(simpleAtomicIntrinsics PRIVATE cxx_std_17 cuda_std_17)
set_target_properties(simpleAtomicIntrinsics PROPERTIES CUDA_SEPARABLE_COMPILATION ON) include(InstallSamples)
# Include installation configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
setup_samples_install() setup_samples_install()

View File

@ -1,32 +1,123 @@
# simpleAtomicIntrinsics - Simple Atomic Intrinsics # simpleAtomicIntrinsics - Atomic vs. Non-Atomic Operations
## Description ## Description
A simple demonstration of global memory atomic instructions. A CUDA sample that demonstrates **why atomic operations are needed** by running the same work with and without atomics under heavy contention. 1,000,000 threads write into an array of just 10 integers, so roughly 100,000 threads collide on every element. Three operations — add, max, and compare-and-swap — are each shown four ways: a non-atomic kernel, the CUDA atomic intrinsic, `cuda::std::atomic_ref` from CCCL (the `std::atomic` API in device code), and `cuda::atomic_ref` from CCCL (the CUDA-specific variant that natively supports thread scopes):
Both CCCL variants use `atomic_ref` rather than `atomic` so they act on the *existing* plain-`int` array — this matches the behavior of the intrinsic atomics, which also adds atomic access to memory that already exists. `atomic<int>` would instead require the array elements themselves to be declared separately as the atomic type.
| Operation | Non-atomic | Intrinsic | cuda::std::atomic_ref | cuda::atomic_ref |
|---|---|---|---|---|
| Add 1 to an element | `increment` | `increment_atomic` | `increment_atomic_std` | `increment_atomic_cuda` |
| Keep the maximum value | `max` | `max_atomic` | `max_atomic_std` | `max_atomic_cuda` |
| Increment via compare-and-swap | `cas` | `cas_atomic` | `cas_atomic_std` | `cas_atomic_cuda` |
The non-atomic kernels perform the read-modify-write as separate steps, so concurrent threads interleave and lose updates. The atomic kernels perform it as one indivisible hardware operation and produce the exact expected result every time.
## What You'll Learn
- What a race condition looks like: the non-atomic results are dramatically (add, CAS) or subtly (max) wrong
- Using the atomic intrinsics `atomicAdd`, `atomicMax`, and `atomicCAS` on global memory
- Building an atomic operation from an `atomicCAS` retry loop — the pattern that can implement any read-modify-write atomically
- Using `cuda::std::atomic_ref` (libcu++/CCCL) to write the same atomics with the standard `std::atomic` API in device code
- Using `cuda::atomic_ref` (CCCL) — the CUDA-specific variant that shares the same API as `cuda::std::atomic_ref` but natively supports CUDA thread scopes
- Why dedicated intrinsics beat CAS loops under contention (compare the `cas_atomic` timing against `increment_atomic`)
- Timing GPU work with CUDA events (`cudaEventRecord` / `cudaEventElapsedTime`)
- Resetting device buffers between runs with `cudaMemset`
## Key Concepts ## Key Concepts
Atomic Intrinsics - **Race condition** — a plain `g[i] = g[i] + 1` is three steps (read, modify, write); two threads can read the same old value and one increment is lost
- **Atomic read-modify-write** — the hardware serializes atomic updates to the same address (performed at the L2 cache), so no update is lost
- **Compare-and-swap (CAS)**`atomicCAS(addr, expected, desired)` swaps only if the current value equals `expected` and returns the value it found; looping until the swap succeeds makes any operation atomic
- **Contention cost** — atomics are correct but serialize colliding threads; the CAS retry loop shows this at its most extreme
## Supported SM Architectures ## Key APIs
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus) ### CUDA Device Intrinsics
- `atomicAdd` — atomically add a value to a memory location
- `atomicMax` — atomically store the maximum of the current and a proposed value
- `atomicCAS` — atomically compare-and-swap; returns the previous value
## Supported OSes ### libcu++ (CCCL)
- `cuda::std::atomic_ref<int>` — wraps plain memory with the standard `std::atomic` interface, usable in device code; header: `<cuda/std/atomic>`
- `cuda::atomic_ref<int>` — CUDA-specific version of `std::atomic_ref`; same API but natively supports CUDA thread scopes (e.g. `cuda::thread_scope_device`); header: `<cuda/atomic>`
- `fetch_add` — atomic add, `std::atomic` style
- `load` / `compare_exchange_weak` — the standard CAS retry loop; used to build max (which `std::atomic` lacks) and the CAS increment
Linux, Windows, QNX ### CUDA Runtime
- `cudaMalloc` / `cudaFree` — allocate and release device memory
- `cudaMemset` — fill device memory with a byte value (zero the array between runs)
- `cudaMemcpy` — copy results back to the host
- `cudaEventCreate` / `cudaEventRecord` / `cudaEventSynchronize` / `cudaEventElapsedTime` / `cudaEventDestroy` — GPU-timeline timing of each kernel
## Supported CPU Architecture ## Requirements
x86_64, armv7l, aarch64 ### Hardware
- NVIDIA GPU with Compute Capability 7.5 or higher
## CUDA APIs involved ### Software
- CUDA Toolkit
- CMake 3.20 or newer
- A C++17-capable host compiler
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) ## How to Build
cudaStreamCreateWithFlags, cudaFree, cudaMallocHost, cudaFreeHost, cudaStreamSynchronize, cudaMalloc, cudaMemcpyAsync
## Prerequisites 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.
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## How to Run
## References (for more details) ```bash
./simpleAtomicIntrinsics
```
No command-line arguments are required. The sample always runs on device 0.
## Expected Output
```text
=== Atomic vs. non-atomic operations (intrinsics, cuda::std::atomic_ref, cuda::atomic_ref) ===
GPU Device 0: with compute capability X.Y and Number of SMs <smCount>
1000000 total threads in 1000 blocks writing into 10 array elements
[add] expected: every element = 100000
non-atomic (0.19 ms): { 13 13 13 13 13 13 13 13 13 13 }
atomicAdd() (0.19 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
cuda::std::atomic_ref::fetch_add() (0.26 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
cuda::atomic_ref::fetch_add() (0.26 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
[max] expected: element i = 999990 + i
non-atomic (0.013 ms): { 998070 998071 998072 998073 998064 998065 998066 998067 998068 998069 }
atomicMax() (0.18 ms): { 999990 999991 999992 999993 999994 999995 999996 999997 999998 999999 }
cuda::std::atomic_ref::compare_exchange_weak() (1.0 ms): { 999990 999991 999992 999993 999994 999995 999996 999997 999998 999999 }
cuda::atomic_ref::compare_exchange_weak() (1.0 ms): { 999990 999991 999992 999993 999994 999995 999996 999997 999998 999999 }
[CAS] expected: every element = 100000
non-atomic (0.014 ms): { 13 13 13 13 13 13 13 13 13 13 }
atomicCAS() (1716 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
cuda::std::atomic_ref::compare_exchange_weak() (9934 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
cuda::atomic_ref::compare_exchange_weak() (9934 ms): { 100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 }
The non-atomic kernels lose updates when threads race on the same
element; the atomic kernels match the expected values exactly.
```
**Reading the numbers:**
- The non-atomic values vary from run to run — that nondeterminism is the race condition itself
- `max` is the sneakiest failure: 998070 looks plausible next to the correct 999990
- `cas_atomic` is orders of magnitude slower than `increment_atomic` for the same result: with ~100,000 threads contending per element, almost every CAS attempt fails and retries — use the dedicated intrinsic when one exists
- The `_std` and `_cuda` kernels are correct but slower than the intrinsics: both `cuda::std::atomic_ref` and `cuda::atomic_ref` default to sequentially-consistent ordering at system scope — a stronger guarantee than the relaxed device-scope intrinsics (which is why their timings match each other in every section above)
## Files
- `simpleAtomicIntrinsics.cu` — the twelve kernels and the host driver
- `README.md` — this file
- `CMakeLists.txt` — build configuration
## See Also
- [CUDA Programming Guide — Atomics](https://docs.nvidia.com/cuda/cuda-programming-guide/02-basics/writing-cuda-kernels.html#atomics)
- [CUDA Programming Guide — Atomic Functions](https://docs.nvidia.com/cuda/cuda-programming-guide/05-appendices/cpp-language-extensions.html#atomic-functions)
- [CUDA Core Compute Libraries — cuda::atomic](https://nvidia.github.io/cccl/unstable/libcudacxx/extended_api/synchronization_primitives/atomic.html)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. /* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -25,110 +25,428 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* A simple program demonstrating trivial use of global memory atomic /* A simple program demonstrating why atomic operations are needed, using the
* device functions (atomic*() functions). * atomic intrinsics atomicAdd, atomicMax, and atomicCAS.
*
* 1,000,000 threads write into an array of only 10 integers (each thread maps
* to a slot with index % ARRAY_SIZE), so ~100,000 threads update every element
* at the same time. A plain update like g[i] = g[i] + 1 is three separate
* steps: read the value, modify it, write it back. When two threads interleave
* (both read the same old value, both write back the same result), one update
* silently overwrites the other and is lost. This is a race condition: the
* result depends on thread timing, not program logic, and changes every run.
*
* Each operation is therefore run four ways: a non-atomic kernel that loses
* most of its updates to these race conditions, and three atomic kernels that
* do the read-modify-write as one indivisible operation and give the exact
* result — first with the CUDA atomic intrinsics, then with
* cuda::std::atomic_ref from CCCL (the std::atomic API in device code), and
* finally with cuda::atomic_ref from CCCL (the CUDA-specific variant that
* natively supports CUDA thread scopes).
*/ */
// includes, system // includes, system
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#define WINDOWS_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#endif
// Includes CUDA // Includes CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
// Utilities and timing functions // Includes CCCL: std::atomic as usable in device code (cuda::std::atomic_ref)
#include <helper_functions.h> // includes cuda.h and cuda_runtime_api.h #include <cuda/std/atomic>
// CUDA helper functions // cuda::atomic_ref<T>: like cuda::std::atomic_ref but CUDA-specific, supports thread scopes
#include <helper_cuda.h> // helper functions for CUDA error check #include <cuda/atomic>
// Includes, kernels // and cuda::ceil_div for computing the launch grid size
#include "simpleAtomicIntrinsics_kernel.cuh" #include <cuda/cmath>
const char *sampleName = "simpleAtomicIntrinsics";
//////////////////////////////////////////////////////////////////////////////// // Launch configuration: many threads hammering a small array
// Auto-Verification Code #define NUM_THREADS 1000000
bool testResult = true; #define BLOCK_WIDTH 1000
#define ARRAY_SIZE 10
//////////////////////////////////////////////////////////////////////////////// // Increment without atomics: threads race on shared elements and lose updates
// Declaration, forward __global__ void increment(int *g)
void runTest(int argc, char **argv); {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
// ceil_div rounds up the grid, this may launch extra threads
// Adding this guard to ignore extra threads
if (tid < NUM_THREADS) {
// each thread increments one element, wrapping at ARRAY_SIZE
int i = tid % ARRAY_SIZE;
g[i] = g[i] + 1;
}
}
extern "C" bool computeGold(int *gpuData, const int len); // Increment with atomicAdd: read-modify-write is one indivisible operation
__global__ void increment_atomic(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
atomicAdd(&g[i], 1);
}
}
// Increment with cuda::std::atomic_ref: wraps the plain int in g[] and exposes
// the exact std::atomic API (fetch_add, load, store, ...) inside device code
__global__ void increment_atomic_std(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::std::atomic_ref<int> ref(g[i]);
ref.fetch_add(1);
}
}
// Increment with cuda::atomic_ref: like cuda::std::atomic_ref but CUDA-specific
// and natively supports CUDA thread scopes
__global__ void increment_atomic_cuda(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::atomic_ref<int> ref(g[i]);
ref.fetch_add(1);
}
}
// Max without atomics: another thread can write between the compare and the
// store, so a smaller value can overwrite a larger one
__global__ void max(int *g)
{
// each thread contributes its global index as the value
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
if (g[i] < tid)
g[i] = tid;
}
}
// Max with atomicMax: the compare and the store happen as one operation
__global__ void max_atomic(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
atomicMax(&g[i], tid);
}
}
// Max with cuda::std::atomic_ref: std::atomic has no fetch_max, so max is
// built the standard C++ way — a compare_exchange loop that stops as soon as
// the stored value is already >= ours
__global__ void max_atomic_std(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::std::atomic_ref<int> ref(g[i]);
int expected = ref.load();
while (expected < tid && !ref.compare_exchange_weak(expected, tid)) {
}
}
}
// Max with cuda::atomic_ref: same compare_exchange loop as the _std variant
__global__ void max_atomic_cuda(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::atomic_ref<int> ref(g[i]);
int expected = ref.load();
while (expected < tid && !ref.compare_exchange_weak(expected, tid)) {
}
}
}
// Increment written as compare-and-swap, without atomics: the value can change
// between the compare and the swap, so increments are lost
__global__ void cas(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
int expected = g[i]; // read
if (g[i] == expected) // compare
g[i] = expected + 1; // swap (not atomic with the compare!)
}
}
// Increment with an atomicCAS retry loop: the classic pattern for building
// any atomic operation out of compare-and-swap. atomicCAS returns the value
// it found: if another thread interfered, the swap did not happen and we retry
__global__ void cas_atomic(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
int old = g[i];
int assumed;
do {
assumed = old;
old = atomicCAS(&g[i], assumed, assumed + 1);
} while (old != assumed);
}
}
// Increment with cuda::std::atomic_ref compare_exchange: the std::atomic way
// to write a CAS retry loop. On failure, expected is updated with the value
// actually found, so the loop just retries with fresh data
__global__ void cas_atomic_std(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::std::atomic_ref<int> ref(g[i]);
int expected = ref.load();
while (!ref.compare_exchange_weak(expected, expected + 1)) {
}
}
}
// CAS increment with cuda::atomic_ref: same retry loop as the _std variant
__global__ void cas_atomic_cuda(int *g)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < NUM_THREADS) {
int i = tid % ARRAY_SIZE;
cuda::atomic_ref<int> ref(g[i]);
int expected = ref.load();
while (!ref.compare_exchange_weak(expected, expected + 1)) {
}
}
}
// Print every element of the array
void print_array(int *array, int size)
{
printf("{ ");
for (int i = 0; i < size; i++)
printf("%d ", array[i]);
printf("}\n");
}
////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
printf("%s starting...\n", sampleName); printf("=== Atomic vs. non-atomic operations (intrinsics, cuda::std::atomic_ref, cuda::atomic_ref) ===\n\n");
runTest(argc, argv); // Select device 0 as the active GPU
int devID = 0;
cudaSetDevice(devID);
printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!"); // Query compute capability (major.minor) and number of SMs on the device
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); int major = 0, minor = 0, smCount = 0;
} cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID);
cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID);
//////////////////////////////////////////////////////////////////////////////// cudaDeviceGetAttribute(&smCount, cudaDevAttrMultiProcessorCount, devID);
//! Run a simple test for CUDA
//////////////////////////////////////////////////////////////////////////////// // Print device info
void runTest(int argc, char **argv) printf("GPU Device %d: with compute capability %d.%d and Number of SMs %d\n\n", devID, major, minor, smCount);
{
cudaStream_t stream; // enough blocks to cover all threads, rounding up if not evenly divisible
// This will pick the best possible CUDA capable device int numBlocks = cuda::ceil_div(NUM_THREADS, BLOCK_WIDTH);
findCudaDevice(argc, (const char **)argv); printf("%d total threads in %d blocks writing into %d array elements\n\n",
NUM_THREADS, numBlocks, ARRAY_SIZE);
StopWatchInterface *timer;
sdkCreateTimer(&timer); // declare and allocate host memory
sdkStartTimer(&timer); int h_array[ARRAY_SIZE];
const int ARRAY_BYTES = ARRAY_SIZE * sizeof(int);
unsigned int numThreads = 256;
unsigned int numBlocks = 64; // declare and allocate GPU memory (zeroed with cudaMemset before each run)
unsigned int numData = 11; int *d_array;
unsigned int memSize = sizeof(int) * numData; cudaMalloc((void **)&d_array, ARRAY_BYTES);
// allocate mem for the result on host side // CUDA events record timestamps on the GPU stream to measure device time
int *hOData; cudaEvent_t start, stop;
checkCudaErrors(cudaMallocHost(&hOData, memSize)); cudaEventCreate(&start);
cudaEventCreate(&stop);
// initialize the memory float elapsed_ms;
for (unsigned int i = 0; i < numData; i++)
hOData[i] = 0; // ----- add: every thread adds 1, each element should reach 100000 -----
printf("[add] expected: every element = %d\n", NUM_THREADS / ARRAY_SIZE);
// To make the AND and XOR tests generate something other than 0...
hOData[8] = hOData[10] = 0xff; cudaMemset((void *)d_array, 0, ARRAY_BYTES);
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); cudaEventRecord(start);
// allocate device memory for result increment<<<numBlocks, BLOCK_WIDTH>>>(d_array);
int *dOData; cudaEventRecord(stop);
checkCudaErrors(cudaMalloc((void **)&dOData, memSize));
// copy host memory to device to initialize to zero cudaEventSynchronize(stop);
checkCudaErrors(cudaMemcpyAsync(dOData, hOData, memSize, cudaMemcpyHostToDevice, stream)); cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
// execute the kernel
testKernel<<<numBlocks, numThreads, 0, stream>>>(dOData); printf("%-36s (%g ms): ", "non-atomic", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
// Copy result from device to host
checkCudaErrors(cudaMemcpyAsync(hOData, dOData, memSize, cudaMemcpyDeviceToHost, stream)); cudaMemset((void *)d_array, 0, ARRAY_BYTES);
checkCudaErrors(cudaStreamSynchronize(stream));
cudaEventRecord(start);
sdkStopTimer(&timer); increment_atomic<<<numBlocks, BLOCK_WIDTH>>>(d_array);
printf("Processing time: %f (ms)\n", sdkGetTimerValue(&timer)); cudaEventRecord(stop);
sdkDeleteTimer(&timer);
cudaEventSynchronize(stop);
// Compute reference solution cudaEventElapsedTime(&elapsed_ms, start, stop);
testResult = computeGold(hOData, numThreads * numBlocks); cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
// Cleanup memory printf("%-36s (%g ms): ", "atomicAdd()", elapsed_ms);
checkCudaErrors(cudaFreeHost(hOData)); print_array(h_array, ARRAY_SIZE);
checkCudaErrors(cudaFree(dOData));
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
increment_atomic_std<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-36s (%g ms): ", "cuda::std::atomic_ref::fetch_add()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
increment_atomic_cuda<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-36s (%g ms): ", "cuda::atomic_ref::fetch_add()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
// ----- max: every thread offers its index, element i should reach
// the largest index that maps to it: NUM_THREADS - ARRAY_SIZE + i -----
printf("\n[max] expected: element i = %d + i\n", NUM_THREADS - ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
max<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "non-atomic", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
max_atomic<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "atomicMax()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
max_atomic_std<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "cuda::std::atomic_ref::compare_exchange_weak()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
max_atomic_cuda<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "cuda::atomic_ref::compare_exchange_weak()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
// ----- CAS: increment built from compare-and-swap, same expected
// result as add -----
printf("\n[CAS] expected: every element = %d\n", NUM_THREADS / ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
cas<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "non-atomic", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
cas_atomic<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "atomicCAS()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
cas_atomic_std<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "cuda::std::atomic_ref::compare_exchange_weak()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
cudaMemset((void *)d_array, 0, ARRAY_BYTES);
cudaEventRecord(start);
cas_atomic_cuda<<<numBlocks, BLOCK_WIDTH>>>(d_array);
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsed_ms, start, stop);
cudaMemcpy(h_array, d_array, ARRAY_BYTES, cudaMemcpyDeviceToHost);
printf("%-46s (%g ms): ", "cuda::atomic_ref::compare_exchange_weak()", elapsed_ms);
print_array(h_array, ARRAY_SIZE);
printf("\nThe non-atomic kernels lose updates when threads race on the same\n");
printf("element; the atomic kernels match the expected values exactly.\n");
// free GPU memory allocation and timing events, then exit
cudaEventDestroy(start);
cudaEventDestroy(stop);
cudaFree(d_array);
return 0;
} }

View File

@ -1,183 +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 <math.h>
#include <stdio.h>
#define min(a, b) (a) < (b) ? (a) : (b)
#define max(a, b) (a) > (b) ? (a) : (b)
////////////////////////////////////////////////////////////////////////////////
// export C interface
extern "C" int computeGold(int *gpuData, const int len);
////////////////////////////////////////////////////////////////////////////////
//! Compute reference data set
//! Each element is multiplied with the number of threads / array length
//! @param reference reference data, computed but preallocated
//! @param idata input data as provided to device
//! @param len number of elements in reference / idata
////////////////////////////////////////////////////////////////////////////////
int computeGold(int *gpuData, const int len)
{
int val = 0;
for (int i = 0; i < len; ++i) {
val += 10;
}
if (val != gpuData[0]) {
printf("atomicAdd failed\n");
return false;
}
val = 0;
for (int i = 0; i < len; ++i) {
val -= 10;
}
if (val != gpuData[1]) {
printf("atomicSub failed\n");
return false;
}
bool found = false;
for (int i = 0; i < len; ++i) {
// third element should be a member of [0, len)
if (i == gpuData[2]) {
found = true;
break;
}
}
if (!found) {
printf("atomicExch failed\n");
return false;
}
val = -(1 << 8);
for (int i = 0; i < len; ++i) {
// fourth element should be len-1
val = max(val, i);
}
if (val != gpuData[3]) {
printf("atomicMax failed\n");
return false;
}
val = 1 << 8;
for (int i = 0; i < len; ++i) {
val = min(val, i);
}
if (val != gpuData[4]) {
printf("atomicMin failed\n");
return false;
}
int limit = 17;
val = 0;
for (int i = 0; i < len; ++i) {
val = (val >= limit) ? 0 : val + 1;
}
if (val != gpuData[5]) {
printf("atomicInc failed\n");
return false;
}
limit = 137;
val = 0;
for (int i = 0; i < len; ++i) {
val = ((val == 0) || (val > limit)) ? limit : val - 1;
}
if (val != gpuData[6]) {
printf("atomicDec failed\n");
return false;
}
found = false;
for (int i = 0; i < len; ++i) {
// eighth element should be a member of [0, len)
if (i == gpuData[7]) {
found = true;
break;
}
}
if (!found) {
printf("atomicCAS failed\n");
return false;
}
val = 0xff;
for (int i = 0; i < len; ++i) {
// 9th element should be 1
val &= (2 * i + 7);
}
if (val != gpuData[8]) {
printf("atomicAnd failed\n");
return false;
}
val = 0;
for (int i = 0; i < len; ++i) {
// 10th element should be 0xff
val |= (1 << i);
}
if (val != gpuData[9]) {
printf("atomicOr failed\n");
return false;
}
val = 0xff;
for (int i = 0; i < len; ++i) {
// 11th element should be 0xff
val ^= i;
}
if (val != gpuData[10]) {
printf("atomicXor failed\n");
return false;
}
return true;
}

View File

@ -1,83 +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.
*/
/* Simple kernel demonstrating atomic functions in device code. */
#ifndef _SIMPLEATOMICS_KERNEL_H_
#define _SIMPLEATOMICS_KERNEL_H_
////////////////////////////////////////////////////////////////////////////////
//! Simple test kernel for atomic instructions
//! @param g_idata input data in global memory
//! @param g_odata output data in global memory
////////////////////////////////////////////////////////////////////////////////
__global__ void testKernel(int *g_odata)
{
// access thread id
const unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x;
// Test various atomic instructions
// Arithmetic atomic instructions
// Atomic addition
atomicAdd(&g_odata[0], 10);
// Atomic subtraction (final should be 0)
atomicSub(&g_odata[1], 10);
// Atomic exchange
atomicExch(&g_odata[2], tid);
// Atomic maximum
atomicMax(&g_odata[3], tid);
// Atomic minimum
atomicMin(&g_odata[4], tid);
// Atomic increment (modulo 17+1)
atomicInc((unsigned int *)&g_odata[5], 17);
// Atomic decrement
atomicDec((unsigned int *)&g_odata[6], 137);
// Atomic compare-and-swap
atomicCAS(&g_odata[7], tid - 1, tid);
// Bitwise atomic instructions
// Atomic AND
atomicAnd(&g_odata[8], 2 * tid + 7);
// Atomic OR
atomicOr(&g_odata[9], 1 << tid);
// Atomic XOR
atomicXor(&g_odata[10], tid);
}
#endif // #ifndef _SIMPLEATOMICS_KERNEL_H_

Some files were not shown because too many files have changed in this diff Show More