From b458dafcd620d73e67a6fa2f67c336e3a8d301c7 Mon Sep 17 00:00:00 2001 From: Mahesh Doijade Date: Wed, 23 Jan 2019 01:34:43 +0530 Subject: [PATCH] Add and update samples with CUDA 10.1 support --- Common/helper_cuda.h | 36 + Common/helper_multiprocess.cpp | 178 ++++ Common/helper_multiprocess.h | 71 ++ Samples/UnifiedMemoryPerf/Makefile | 10 + Samples/UnifiedMemoryPerf/NsightEclipse.xml | 1 + Samples/UnifiedMemoryPerf/README.md | 4 +- .../UnifiedMemoryPerf_vs2012.vcxproj | 4 +- .../UnifiedMemoryPerf_vs2013.vcxproj | 4 +- .../UnifiedMemoryPerf_vs2015.vcxproj | 4 +- .../UnifiedMemoryPerf_vs2017.vcxproj | 4 +- Samples/bandwidthTest/Makefile | 304 ++++++ Samples/bandwidthTest/NsightEclipse.xml | 79 ++ Samples/bandwidthTest/README.md | 94 ++ Samples/bandwidthTest/bandwidthTest.cu | 969 ++++++++++++++++++ .../bandwidthTest/bandwidthTest_vs2012.sln | 20 + .../bandwidthTest_vs2012.vcxproj | 107 ++ .../bandwidthTest/bandwidthTest_vs2013.sln | 20 + .../bandwidthTest_vs2013.vcxproj | 107 ++ .../bandwidthTest/bandwidthTest_vs2015.sln | 20 + .../bandwidthTest_vs2015.vcxproj | 107 ++ .../bandwidthTest/bandwidthTest_vs2017.sln | 20 + .../bandwidthTest_vs2017.vcxproj | 108 ++ Samples/conjugateGradientCudaGraphs/Makefile | 6 +- .../NsightEclipse.xml | 2 + Samples/conjugateGradientCudaGraphs/README.md | 4 +- .../conjugateGradientCudaGraphs.cu | 2 +- ...conjugateGradientCudaGraphs_vs2012.vcxproj | 4 +- ...conjugateGradientCudaGraphs_vs2013.vcxproj | 4 +- ...conjugateGradientCudaGraphs_vs2015.vcxproj | 4 +- ...conjugateGradientCudaGraphs_vs2017.vcxproj | 4 +- .../conjugateGradientMultiBlockCG/Makefile | 4 + .../NsightEclipse.xml | 1 + .../conjugateGradientMultiBlockCG/README.md | 4 +- ...njugateGradientMultiBlockCG_vs2012.vcxproj | 4 +- ...njugateGradientMultiBlockCG_vs2013.vcxproj | 4 +- ...njugateGradientMultiBlockCG_vs2015.vcxproj | 4 +- ...njugateGradientMultiBlockCG_vs2017.vcxproj | 4 +- .../conjugateGradientMultiDeviceCG/Makefile | 4 + .../NsightEclipse.xml | 1 + .../conjugateGradientMultiDeviceCG/README.md | 4 +- .../conjugateGradientMultiDeviceCG.cu | 5 +- ...jugateGradientMultiDeviceCG_vs2012.vcxproj | 4 +- ...jugateGradientMultiDeviceCG_vs2013.vcxproj | 4 +- ...jugateGradientMultiDeviceCG_vs2015.vcxproj | 4 +- ...jugateGradientMultiDeviceCG_vs2017.vcxproj | 4 +- Samples/cudaTensorCoreGemm/Makefile | 10 +- Samples/cudaTensorCoreGemm/NsightEclipse.xml | 4 + Samples/cudaTensorCoreGemm/README.md | 10 +- .../cudaTensorCoreGemm/cudaTensorCoreGemm.cu | 71 +- .../cudaTensorCoreGemm_vs2012.vcxproj | 4 +- .../cudaTensorCoreGemm_vs2013.vcxproj | 4 +- .../cudaTensorCoreGemm_vs2015.vcxproj | 4 +- .../cudaTensorCoreGemm_vs2017.vcxproj | 4 +- Samples/deviceQuery/Makefile | 4 + Samples/deviceQuery/NsightEclipse.xml | 1 + Samples/deviceQuery/README.md | 4 +- .../deviceQuery/deviceQuery_vs2012.vcxproj | 4 +- .../deviceQuery/deviceQuery_vs2013.vcxproj | 4 +- .../deviceQuery/deviceQuery_vs2015.vcxproj | 4 +- .../deviceQuery/deviceQuery_vs2017.vcxproj | 4 +- Samples/immaTensorCoreGemm/Makefile | 318 ++++++ Samples/immaTensorCoreGemm/NsightEclipse.xml | 64 ++ Samples/immaTensorCoreGemm/README.md | 70 ++ .../immaTensorCoreGemm/immaTensorCoreGemm.cu | 655 ++++++++++++ .../immaTensorCoreGemm_vs2012.sln | 20 + .../immaTensorCoreGemm_vs2012.vcxproj | 107 ++ .../immaTensorCoreGemm_vs2013.sln | 20 + .../immaTensorCoreGemm_vs2013.vcxproj | 107 ++ .../immaTensorCoreGemm_vs2015.sln | 20 + .../immaTensorCoreGemm_vs2015.vcxproj | 107 ++ .../immaTensorCoreGemm_vs2017.sln | 20 + .../immaTensorCoreGemm_vs2017.vcxproj | 108 ++ Samples/matrixMul/Makefile | 4 + Samples/matrixMul/NsightEclipse.xml | 1 + Samples/matrixMul/README.md | 4 +- Samples/matrixMul/matrixMul_vs2012.vcxproj | 4 +- Samples/matrixMul/matrixMul_vs2013.vcxproj | 4 +- Samples/matrixMul/matrixMul_vs2015.vcxproj | 4 +- Samples/matrixMul/matrixMul_vs2017.vcxproj | 4 +- Samples/matrixMulDrv/README.md | 4 +- .../matrixMulDrv/matrixMulDrv_vs2012.vcxproj | 4 +- .../matrixMulDrv/matrixMulDrv_vs2013.vcxproj | 4 +- .../matrixMulDrv/matrixMulDrv_vs2015.vcxproj | 4 +- .../matrixMulDrv/matrixMulDrv_vs2017.vcxproj | 4 +- Samples/nvJPEG/Makefile | 301 ++++++ Samples/nvJPEG/NsightEclipse.xml | 58 ++ Samples/nvJPEG/README.md | 61 ++ Samples/nvJPEG/images/img1.jpg | Bin 0 -> 67716 bytes Samples/nvJPEG/images/img2.jpg | Bin 0 -> 51012 bytes Samples/nvJPEG/images/img3.jpg | Bin 0 -> 34914 bytes Samples/nvJPEG/images/img4.jpg | Bin 0 -> 30198 bytes Samples/nvJPEG/images/img5.jpg | Bin 0 -> 81385 bytes Samples/nvJPEG/images/img6.jpg | Bin 0 -> 64806 bytes Samples/nvJPEG/images/img7.jpg | Bin 0 -> 94376 bytes Samples/nvJPEG/images/img8.jpg | Bin 0 -> 53180 bytes Samples/nvJPEG/nvJPEG.cpp | 559 ++++++++++ Samples/nvJPEG/nvJPEG_helper.hxx | 338 ++++++ Samples/p2pBandwidthLatencyTest/Makefile | 4 + .../p2pBandwidthLatencyTest/NsightEclipse.xml | 1 + Samples/p2pBandwidthLatencyTest/README.md | 4 +- .../p2pBandwidthLatencyTest_vs2012.vcxproj | 4 +- .../p2pBandwidthLatencyTest_vs2013.vcxproj | 4 +- .../p2pBandwidthLatencyTest_vs2015.vcxproj | 4 +- .../p2pBandwidthLatencyTest_vs2017.vcxproj | 4 +- Samples/reduction/Makefile | 307 ++++++ Samples/reduction/NsightEclipse.xml | 67 ++ Samples/reduction/README.md | 91 ++ Samples/reduction/reduction.cpp | 563 ++++++++++ Samples/reduction/reduction.h | 36 + Samples/reduction/reduction_kernel.cu | 666 ++++++++++++ Samples/reduction/reduction_vs2012.sln | 20 + Samples/reduction/reduction_vs2012.vcxproj | 108 ++ Samples/reduction/reduction_vs2013.sln | 20 + Samples/reduction/reduction_vs2013.vcxproj | 108 ++ Samples/reduction/reduction_vs2015.sln | 20 + Samples/reduction/reduction_vs2015.vcxproj | 108 ++ Samples/reduction/reduction_vs2017.sln | 20 + Samples/reduction/reduction_vs2017.vcxproj | 109 ++ Samples/shfl_scan/Makefile | 4 + Samples/shfl_scan/NsightEclipse.xml | 1 + Samples/shfl_scan/README.md | 4 +- Samples/shfl_scan/shfl_scan_vs2012.vcxproj | 4 +- Samples/shfl_scan/shfl_scan_vs2013.vcxproj | 4 +- Samples/shfl_scan/shfl_scan_vs2015.vcxproj | 4 +- Samples/shfl_scan/shfl_scan_vs2017.vcxproj | 4 +- Samples/simpleCUBLAS/NsightEclipse.xml | 1 + Samples/simpleCUBLAS/README.md | 4 +- .../simpleCUBLAS/simpleCUBLAS_vs2012.vcxproj | 4 +- .../simpleCUBLAS/simpleCUBLAS_vs2013.vcxproj | 4 +- .../simpleCUBLAS/simpleCUBLAS_vs2015.vcxproj | 4 +- .../simpleCUBLAS/simpleCUBLAS_vs2017.vcxproj | 4 +- Samples/simpleCUBLASXT/NsightEclipse.xml | 1 + Samples/simpleCUBLASXT/README.md | 4 +- .../simpleCUBLASXT_vs2012.vcxproj | 4 +- .../simpleCUBLASXT_vs2013.vcxproj | 4 +- .../simpleCUBLASXT_vs2015.vcxproj | 4 +- .../simpleCUBLASXT_vs2017.vcxproj | 4 +- Samples/simpleCUFFT/Makefile | 4 + Samples/simpleCUFFT/NsightEclipse.xml | 1 + Samples/simpleCUFFT/README.md | 4 +- .../simpleCUFFT/simpleCUFFT_vs2012.vcxproj | 4 +- .../simpleCUFFT/simpleCUFFT_vs2013.vcxproj | 4 +- .../simpleCUFFT/simpleCUFFT_vs2015.vcxproj | 4 +- .../simpleCUFFT/simpleCUFFT_vs2017.vcxproj | 4 +- Samples/simpleCudaGraphs/Makefile | 4 + Samples/simpleCudaGraphs/NsightEclipse.xml | 1 + Samples/simpleCudaGraphs/README.md | 4 +- Samples/simpleCudaGraphs/simpleCudaGraphs.cu | 4 +- .../simpleCudaGraphs_vs2012.vcxproj | 4 +- .../simpleCudaGraphs_vs2013.vcxproj | 4 +- .../simpleCudaGraphs_vs2015.vcxproj | 4 +- .../simpleCudaGraphs_vs2017.vcxproj | 4 +- Samples/simpleD3D12/NsightEclipse.xml | 1 + Samples/simpleD3D12/README.md | 4 +- .../simpleD3D12/simpleD3D12_vs2015.vcxproj | 4 +- .../simpleD3D12/simpleD3D12_vs2017.vcxproj | 4 +- Samples/simpleIPC/Makefile | 325 ++++++ Samples/simpleIPC/NsightEclipse.xml | 74 ++ Samples/simpleIPC/README.md | 74 ++ Samples/simpleIPC/simpleIPC.cu | 336 ++++++ Samples/simpleIPC/simpleIPC_vs2012.sln | 20 + Samples/simpleIPC/simpleIPC_vs2012.vcxproj | 108 ++ Samples/simpleIPC/simpleIPC_vs2013.sln | 20 + Samples/simpleIPC/simpleIPC_vs2013.vcxproj | 108 ++ Samples/simpleIPC/simpleIPC_vs2015.sln | 20 + Samples/simpleIPC/simpleIPC_vs2015.vcxproj | 108 ++ Samples/simpleIPC/simpleIPC_vs2017.sln | 20 + Samples/simpleIPC/simpleIPC_vs2017.vcxproj | 109 ++ Samples/simpleVoteIntrinsics/Makefile | 4 + .../simpleVoteIntrinsics/NsightEclipse.xml | 1 + Samples/simpleVoteIntrinsics/README.md | 4 +- .../simpleVoteIntrinsics_vs2012.vcxproj | 4 +- .../simpleVoteIntrinsics_vs2013.vcxproj | 4 +- .../simpleVoteIntrinsics_vs2015.vcxproj | 4 +- .../simpleVoteIntrinsics_vs2017.vcxproj | 4 +- Samples/simpleVulkan/Build_instructions.txt | 9 +- Samples/simpleVulkan/Makefile | 14 +- Samples/simpleVulkan/NsightEclipse.xml | 12 +- Samples/simpleVulkan/README.md | 10 +- Samples/simpleVulkan/shader_sine.frag | 1 + Samples/simpleVulkan/shader_sine.vert | 2 +- .../simpleVulkan/simpleVulkan_vs2013.vcxproj | 9 +- .../simpleVulkan/simpleVulkan_vs2015.vcxproj | 9 +- .../simpleVulkan/simpleVulkan_vs2017.vcxproj | 9 +- Samples/simpleVulkan/vulkanCUDASinewave.cu | 4 +- Samples/systemWideAtomics/Makefile | 4 + Samples/systemWideAtomics/NsightEclipse.xml | 1 + Samples/systemWideAtomics/README.md | 4 +- Samples/vectorAdd_nvrtc/Makefile | 6 + Samples/vectorAdd_nvrtc/README.md | 4 +- .../vectorAdd_nvrtc_vs2012.vcxproj | 4 +- .../vectorAdd_nvrtc_vs2013.vcxproj | 4 +- .../vectorAdd_nvrtc_vs2015.vcxproj | 4 +- .../vectorAdd_nvrtc_vs2017.vcxproj | 4 +- Samples/warpAggregatedAtomicsCG/Makefile | 4 + .../warpAggregatedAtomicsCG/NsightEclipse.xml | 1 + Samples/warpAggregatedAtomicsCG/README.md | 4 +- .../warpAggregatedAtomicsCG_vs2012.vcxproj | 4 +- .../warpAggregatedAtomicsCG_vs2013.vcxproj | 4 +- .../warpAggregatedAtomicsCG_vs2015.vcxproj | 4 +- .../warpAggregatedAtomicsCG_vs2017.vcxproj | 4 +- 201 files changed, 9072 insertions(+), 286 deletions(-) create mode 100644 Common/helper_multiprocess.cpp create mode 100644 Common/helper_multiprocess.h create mode 100644 Samples/bandwidthTest/Makefile create mode 100644 Samples/bandwidthTest/NsightEclipse.xml create mode 100644 Samples/bandwidthTest/README.md create mode 100644 Samples/bandwidthTest/bandwidthTest.cu create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2012.sln create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2012.vcxproj create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2013.sln create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2013.vcxproj create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2015.sln create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2015.vcxproj create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2017.sln create mode 100644 Samples/bandwidthTest/bandwidthTest_vs2017.vcxproj create mode 100644 Samples/immaTensorCoreGemm/Makefile create mode 100644 Samples/immaTensorCoreGemm/NsightEclipse.xml create mode 100644 Samples/immaTensorCoreGemm/README.md create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm.cu create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.sln create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.vcxproj create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.sln create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.vcxproj create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.sln create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.vcxproj create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.sln create mode 100644 Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.vcxproj create mode 100644 Samples/nvJPEG/Makefile create mode 100644 Samples/nvJPEG/NsightEclipse.xml create mode 100644 Samples/nvJPEG/README.md create mode 100644 Samples/nvJPEG/images/img1.jpg create mode 100644 Samples/nvJPEG/images/img2.jpg create mode 100644 Samples/nvJPEG/images/img3.jpg create mode 100644 Samples/nvJPEG/images/img4.jpg create mode 100644 Samples/nvJPEG/images/img5.jpg create mode 100644 Samples/nvJPEG/images/img6.jpg create mode 100644 Samples/nvJPEG/images/img7.jpg create mode 100644 Samples/nvJPEG/images/img8.jpg create mode 100644 Samples/nvJPEG/nvJPEG.cpp create mode 100644 Samples/nvJPEG/nvJPEG_helper.hxx create mode 100644 Samples/reduction/Makefile create mode 100644 Samples/reduction/NsightEclipse.xml create mode 100644 Samples/reduction/README.md create mode 100644 Samples/reduction/reduction.cpp create mode 100644 Samples/reduction/reduction.h create mode 100644 Samples/reduction/reduction_kernel.cu create mode 100644 Samples/reduction/reduction_vs2012.sln create mode 100644 Samples/reduction/reduction_vs2012.vcxproj create mode 100644 Samples/reduction/reduction_vs2013.sln create mode 100644 Samples/reduction/reduction_vs2013.vcxproj create mode 100644 Samples/reduction/reduction_vs2015.sln create mode 100644 Samples/reduction/reduction_vs2015.vcxproj create mode 100644 Samples/reduction/reduction_vs2017.sln create mode 100644 Samples/reduction/reduction_vs2017.vcxproj create mode 100644 Samples/simpleIPC/Makefile create mode 100644 Samples/simpleIPC/NsightEclipse.xml create mode 100644 Samples/simpleIPC/README.md create mode 100644 Samples/simpleIPC/simpleIPC.cu create mode 100644 Samples/simpleIPC/simpleIPC_vs2012.sln create mode 100644 Samples/simpleIPC/simpleIPC_vs2012.vcxproj create mode 100644 Samples/simpleIPC/simpleIPC_vs2013.sln create mode 100644 Samples/simpleIPC/simpleIPC_vs2013.vcxproj create mode 100644 Samples/simpleIPC/simpleIPC_vs2015.sln create mode 100644 Samples/simpleIPC/simpleIPC_vs2015.vcxproj create mode 100644 Samples/simpleIPC/simpleIPC_vs2017.sln create mode 100644 Samples/simpleIPC/simpleIPC_vs2017.vcxproj diff --git a/Common/helper_cuda.h b/Common/helper_cuda.h index e5b8e9f3..0ef40206 100644 --- a/Common/helper_cuda.h +++ b/Common/helper_cuda.h @@ -282,6 +282,42 @@ static const char *_cudaGetErrorEnum(curandStatus_t error) { } #endif +#ifdef NVJPEGAPI +// nvJPEG API errors +static const char *_cudaGetErrorEnum(nvjpegStatus_t error) { + switch (error) { + case NVJPEG_STATUS_SUCCESS: + return "NVJPEG_STATUS_SUCCESS"; + + case NVJPEG_STATUS_NOT_INITIALIZED: + return "NVJPEG_STATUS_NOT_INITIALIZED"; + + case NVJPEG_STATUS_INVALID_PARAMETER: + return "NVJPEG_STATUS_INVALID_PARAMETER"; + + case NVJPEG_STATUS_BAD_JPEG: + return "NVJPEG_STATUS_BAD_JPEG"; + + case NVJPEG_STATUS_JPEG_NOT_SUPPORTED: + return "NVJPEG_STATUS_JPEG_NOT_SUPPORTED"; + + case NVJPEG_STATUS_ALLOCATOR_FAILURE: + return "NVJPEG_STATUS_ALLOCATOR_FAILURE"; + + case NVJPEG_STATUS_EXECUTION_FAILED: + return "NVJPEG_STATUS_EXECUTION_FAILED"; + + case NVJPEG_STATUS_ARCH_MISMATCH: + return "NVJPEG_STATUS_ARCH_MISMATCH"; + + case NVJPEG_STATUS_INTERNAL_ERROR: + return "NVJPEG_STATUS_INTERNAL_ERROR"; + } + + return ""; +} +#endif + #ifdef NV_NPPIDEFS_H // NPP API errors static const char *_cudaGetErrorEnum(NppStatus error) { diff --git a/Common/helper_multiprocess.cpp b/Common/helper_multiprocess.cpp new file mode 100644 index 00000000..9fb95560 --- /dev/null +++ b/Common/helper_multiprocess.cpp @@ -0,0 +1,178 @@ +/* Copyright (c) 2018, 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 "helper_multiprocess.h" +#include +#include + +int sharedMemoryCreate(const char *name, size_t sz, sharedMemoryInfo *info) +{ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + info->size = sz; + info->shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + (DWORD)sz, + name); + if (info->shmHandle == 0) { + return GetLastError(); + } + + info->addr = MapViewOfFile(info->shmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sz); + if (info->addr == NULL) { + return GetLastError(); + } + + return 0; +#else + int status = 0; + + info->size = sz; + + info->shmFd = shm_open(name, O_RDWR | O_CREAT, 0777); + if (info->shmFd < 0) { + return errno; + } + + status = ftruncate(info->shmFd, sz); + if (status != 0) { + return status; + } + + info->addr = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, info->shmFd, 0); + if (info->addr == NULL) { + return errno; + } + + return 0; +#endif +} + +int sharedMemoryOpen(const char *name, size_t sz, sharedMemoryInfo *info) +{ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + info->size = sz; + + info->shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name); + if (info->shmHandle == 0) { + return GetLastError(); + } + + info->addr = MapViewOfFile(info->shmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sz); + if (info->addr == NULL) { + return GetLastError(); + } + + return 0; +#else + info->size = sz; + + info->shmFd = shm_open(name, O_RDWR, 0777); + if (info->shmFd < 0) { + return errno; + } + + info->addr = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, info->shmFd, 0); + if (info->addr == NULL) { + return errno; + } + + return 0; +#endif +} + +void sharedMemoryClose(sharedMemoryInfo *info) +{ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + if (info->addr) { + UnmapViewOfFile(info->addr); + } + if (info->shmHandle) { + CloseHandle(info->shmHandle); + } +#else + if (info->addr) { + munmap(info->addr, info->size); + } + if (info->shmFd) { + close(info->shmFd); + } +#endif +} + +int spawnProcess(Process *process, const char *app, char * const *args) +{ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + STARTUPINFO si = {0}; + BOOL status; + size_t arglen = 0; + size_t argIdx = 0; + std::string arg_string; + memset(process, 0, sizeof(*process)); + + while (*args) { + arg_string.append(*args).append(1, ' '); + args++; + } + + status = CreateProcess(app, LPSTR(arg_string.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, process); + + return status ? 0 : GetLastError(); +#else + *process = fork(); + if (*process == 0) { + if (0 > execvp(app, args)) { + return errno; + } + } + else if (*process < 0) { + return errno; + } + return 0; +#endif +} + +int waitProcess(Process *process) +{ +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + DWORD exitCode; + WaitForSingleObject(process->hProcess, INFINITE); + GetExitCodeProcess(process->hProcess, &exitCode); + CloseHandle(process->hProcess); + CloseHandle(process->hThread); + return (int)exitCode; +#else + int status = 0; + do { + if (0 > waitpid(*process, &status, 0)) { + return errno; + } + } while (!WIFEXITED(status)); + return WEXITSTATUS(status); +#endif +} diff --git a/Common/helper_multiprocess.h b/Common/helper_multiprocess.h new file mode 100644 index 00000000..9f1d3dbf --- /dev/null +++ b/Common/helper_multiprocess.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2018, 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 HELPER_MULTIPROCESS_H +#define HELPER_MULTIPROCESS_H + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#include +#include +#include +#include +#include +#endif + +typedef struct sharedMemoryInfo_st { + void *addr; + size_t size; +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + HANDLE shmHandle; +#else + int shmFd; +#endif +} sharedMemoryInfo; + +int sharedMemoryCreate(const char *name, size_t sz, sharedMemoryInfo *info); + +int sharedMemoryOpen(const char *name, size_t sz, sharedMemoryInfo *info); + +void sharedMemoryClose(sharedMemoryInfo *info); + + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +typedef PROCESS_INFORMATION Process; +#else +typedef pid_t Process; +#endif + +int spawnProcess(Process *process, const char *app, char * const *args); + +int waitProcess(Process *process); + +#endif // HELPER_MULTIPROCESS_H diff --git a/Samples/UnifiedMemoryPerf/Makefile b/Samples/UnifiedMemoryPerf/Makefile index 628ebd40..ca4f20da 100644 --- a/Samples/UnifiedMemoryPerf/Makefile +++ b/Samples/UnifiedMemoryPerf/Makefile @@ -234,6 +234,12 @@ ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) SAMPLE_ENABLED := 1 +# This sample is not supported on QNX +ifeq ($(TARGET_OS),qnx) + $(info >>> WARNING - UnifiedMemoryPerf is not supported on QNX - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + ALL_LDFLAGS := ALL_LDFLAGS += $(ALL_CCFLAGS) ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) @@ -246,7 +252,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/UnifiedMemoryPerf/NsightEclipse.xml b/Samples/UnifiedMemoryPerf/NsightEclipse.xml index 32ab4ef2..b2567d4b 100644 --- a/Samples/UnifiedMemoryPerf/NsightEclipse.xml +++ b/Samples/UnifiedMemoryPerf/NsightEclipse.xml @@ -52,6 +52,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/UnifiedMemoryPerf/README.md b/Samples/UnifiedMemoryPerf/README.md index da827faf..3e4d0343 100644 --- a/Samples/UnifiedMemoryPerf/README.md +++ b/Samples/UnifiedMemoryPerf/README.md @@ -10,7 +10,7 @@ CUDA Systems Integration, Unified Memory, CUDA Streams and Events, Pinned System ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cudaMallocManaged, cudaStreamAttachMemAsync, cudaMemcpyAsync, cudaMallocHost, cu ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2012.vcxproj b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2012.vcxproj index 68259eda..d8cddae0 100644 --- a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2012.vcxproj +++ b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -105,6 +105,6 @@ - + diff --git a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2013.vcxproj b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2013.vcxproj index 1bb100bf..f129b608 100644 --- a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2013.vcxproj +++ b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -105,6 +105,6 @@ - + diff --git a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2015.vcxproj b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2015.vcxproj index cfe0e652..aa83dcb2 100644 --- a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2015.vcxproj +++ b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -105,6 +105,6 @@ - + diff --git a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2017.vcxproj b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2017.vcxproj index 8aa9ef46..09daab5d 100644 --- a/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2017.vcxproj +++ b/Samples/UnifiedMemoryPerf/UnifiedMemoryPerf_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -106,6 +106,6 @@ - + diff --git a/Samples/bandwidthTest/Makefile b/Samples/bandwidthTest/Makefile new file mode 100644 index 00000000..5bc74dbf --- /dev/null +++ b/Samples/bandwidthTest/Makefile @@ -0,0 +1,304 @@ +################################################################################ +# Copyright (c) 2018, 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. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Location of the CUDA Toolkit +CUDA_PATH ?= /usr/local/cuda + +############################## +# start deprecated interface # +############################## +ifeq ($(x86_64),1) + $(info WARNING - x86_64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=x86_64 instead) + TARGET_ARCH ?= x86_64 +endif +ifeq ($(ARMv7),1) + $(info WARNING - ARMv7 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=armv7l instead) + TARGET_ARCH ?= armv7l +endif +ifeq ($(aarch64),1) + $(info WARNING - aarch64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=aarch64 instead) + TARGET_ARCH ?= aarch64 +endif +ifeq ($(ppc64le),1) + $(info WARNING - ppc64le variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=ppc64le instead) + TARGET_ARCH ?= ppc64le +endif +ifneq ($(GCC),) + $(info WARNING - GCC variable has been deprecated) + $(info WARNING - please use HOST_COMPILER=$(GCC) instead) + HOST_COMPILER ?= $(GCC) +endif +ifneq ($(abi),) + $(error ERROR - abi variable has been removed) +endif +############################ +# end deprecated interface # +############################ + +# architecture +HOST_ARCH := $(shell uname -m) +TARGET_ARCH ?= $(HOST_ARCH) +ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l)) + ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le)) + TARGET_SIZE := 64 + else ifneq (,$(filter $(TARGET_ARCH),armv7l)) + TARGET_SIZE := 32 + endif + else + TARGET_SIZE := $(shell getconf LONG_BIT) + endif +else + $(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!) +endif +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le)) + $(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!) + endif +endif + +# When on native aarch64 system with userspace of 32-bit, change TARGET_ARCH to armv7l +ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_SIZE),aarch64-aarch64-32) + TARGET_ARCH = armv7l +endif + +# operating system +HOST_OS := $(shell uname -s 2>/dev/null | tr "[:upper:]" "[:lower:]") +TARGET_OS ?= $(HOST_OS) +ifeq (,$(filter $(TARGET_OS),linux darwin qnx android)) + $(error ERROR - unsupported value $(TARGET_OS) for TARGET_OS!) +endif + +# host compiler +ifeq ($(TARGET_OS),darwin) + ifeq ($(shell expr `xcodebuild -version | grep -i xcode | awk '{print $$2}' | cut -d'.' -f1` \>= 5),1) + HOST_COMPILER ?= clang++ + endif +else ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(HOST_ARCH)-$(TARGET_ARCH),x86_64-armv7l) + ifeq ($(TARGET_OS),linux) + HOST_COMPILER ?= arm-linux-gnueabihf-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/arm-unknown-nto-qnx6.6.0eabi-g++ + else ifeq ($(TARGET_OS),android) + HOST_COMPILER ?= arm-linux-androideabi-g++ + endif + else ifeq ($(TARGET_ARCH),aarch64) + ifeq ($(TARGET_OS), linux) + HOST_COMPILER ?= aarch64-linux-gnu-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ + else ifeq ($(TARGET_OS), android) + HOST_COMPILER ?= aarch64-linux-android-clang++ + endif + else ifeq ($(TARGET_ARCH),ppc64le) + HOST_COMPILER ?= powerpc64le-linux-gnu-g++ + endif +endif +HOST_COMPILER ?= g++ +NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER) + +# internal flags +NVCCFLAGS := -m${TARGET_SIZE} +CCFLAGS := +LDFLAGS := + +# build flags +ifeq ($(TARGET_OS),darwin) + LDFLAGS += -rpath $(CUDA_PATH)/lib + CCFLAGS += -arch $(HOST_ARCH) +else ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_OS),x86_64-armv7l-linux) + LDFLAGS += --dynamic-linker=/lib/ld-linux-armhf.so.3 + CCFLAGS += -mfloat-abi=hard +else ifeq ($(TARGET_OS),android) + LDFLAGS += -pie + CCFLAGS += -fpie -fpic -fexceptions +endif + +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/arm-linux-gnueabihf + endif + endif + ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu + LDFLAGS += --unresolved-symbols=ignore-in-shared-libs + CCFLAGS += -isystem=$(TARGET_FS)/usr/include + CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu + endif + endif +endif + +ifeq ($(TARGET_OS),qnx) + CCFLAGS += -DWIN_INTERFACE_CUSTOM + LDFLAGS += -lsocket +endif + +# Install directory of different arch +CUDA_INSTALL_TARGET_DIR := +ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-qnx) + CUDA_INSTALL_TARGET_DIR = targets/ARMv7-linux-QNX/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-qnx/ +else ifeq ($(TARGET_ARCH),ppc64le) + CUDA_INSTALL_TARGET_DIR = targets/ppc64le-linux/ +endif + +# Debug build flags +ifeq ($(dbg),1) + NVCCFLAGS += -g -G + BUILD_TYPE := debug +else + BUILD_TYPE := release +endif + +ALL_CCFLAGS := +ALL_CCFLAGS += $(NVCCFLAGS) +ALL_CCFLAGS += $(EXTRA_NVCCFLAGS) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(CCFLAGS)) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) + +SAMPLE_ENABLED := 1 + +ALL_LDFLAGS := +ALL_LDFLAGS += $(ALL_CCFLAGS) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(EXTRA_LDFLAGS)) + +# Common includes and paths for CUDA +INCLUDES := -I../../Common +LIBRARIES := + +################################################################################ + +# Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else +SMS ?= 30 35 37 50 52 60 61 70 75 +endif + +ifeq ($(SMS),) +$(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) +SAMPLE_ENABLED := 0 +endif + +ifeq ($(GENCODE_FLAGS),) +# Generate SASS code for each SM architecture listed in $(SMS) +$(foreach sm,$(SMS),$(eval GENCODE_FLAGS += -gencode arch=compute_$(sm),code=sm_$(sm))) + +# Generate PTX code from the highest SM architecture in $(SMS) to guarantee forward-compatibility +HIGHEST_SM := $(lastword $(sort $(SMS))) +ifneq ($(HIGHEST_SM),) +GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM) +endif +endif + +ifeq ($(SAMPLE_ENABLED),0) +EXEC ?= @echo "[@]" +endif + +################################################################################ + +# Target rules +all: build + +build: bandwidthTest + +check.deps: +ifeq ($(SAMPLE_ENABLED),0) + @echo "Sample will be waived due to the above missing dependencies" +else + @echo "Sample is ready - all dependencies have been met" +endif + +bandwidthTest.o:bandwidthTest.cu + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +bandwidthTest: bandwidthTest.o + $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o $@ $+ $(LIBRARIES) + $(EXEC) mkdir -p ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + $(EXEC) cp $@ ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + +run: build + $(EXEC) ./bandwidthTest + +clean: + rm -f bandwidthTest bandwidthTest.o + rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/bandwidthTest + +clobber: clean diff --git a/Samples/bandwidthTest/NsightEclipse.xml b/Samples/bandwidthTest/NsightEclipse.xml new file mode 100644 index 00000000..5aeaead5 --- /dev/null +++ b/Samples/bandwidthTest/NsightEclipse.xml @@ -0,0 +1,79 @@ + + + + bandwidthTest + + cudaSetDevice + cudaHostAlloc + cudaFree + cudaMallocHost + cudaFreeHost + cudaMemcpy + cudaMemcpyAsync + cudaEventCreate + cudaEventRecord + cudaEventDestroy + cudaDeviceSynchronize + cudaEventElapsedTime + + + whole + + ./ + ../ + ../../common/inc + + + CUDA Streams and Events + Performance Strategies + + + GPGPU + bandwidth + + + + + + true + bandwidthTest.cu + + 1:CUDA Basic Topics + 1:Performance Strategies + + sm30 + sm35 + sm37 + sm50 + sm52 + sm60 + sm61 + sm70 + sm72 + sm75 + + + x86_64 + linux + + + windows7 + + + x86_64 + macosx + + + arm + + + ppc64le + linux + + + + all + + Bandwidth Test + exe + diff --git a/Samples/bandwidthTest/README.md b/Samples/bandwidthTest/README.md new file mode 100644 index 00000000..8348179c --- /dev/null +++ b/Samples/bandwidthTest/README.md @@ -0,0 +1,94 @@ +# bandwidthTest - Bandwidth Test + +## Description + +This is a simple test program to measure the memcopy bandwidth of the GPU and memcpy bandwidth across PCI-e. This test application is capable of measuring device to device copy bandwidth, host to device copy bandwidth for pageable and page-locked memory, and device to host copy bandwidth for pageable and page-locked memory. + +## Key Concepts + +CUDA Streams and Events, Performance Strategies + +## Supported SM Architectures + +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) + +## Supported OSes + +Linux, Windows, MacOSX + +## Supported CPU Architecture + +x86_64, ppc64le, armv7l + +## CUDA APIs involved + +### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) +cudaSetDevice, cudaHostAlloc, cudaFree, cudaMallocHost, cudaFreeHost, cudaMemcpy, cudaMemcpyAsync, cudaEventCreate, cudaEventRecord, cudaEventDestroy, cudaDeviceSynchronize, cudaEventElapsedTime + +## Prerequisites + +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. + +## Build and Run + +### Windows +The Windows samples are built using the Visual Studio IDE. Solution files (.sln) are provided for each supported version of Visual Studio, using the format: +``` +*_vs.sln - for Visual Studio +``` +Each individual sample has its own set of solution files in its directory: + +To build/examine all the samples at once, the complete solution files should be used. To build/examine a single sample, the individual sample solution files should be used. +> **Note:** Some samples require that the Microsoft DirectX SDK (June 2010 or newer) be installed and that the VC++ directory paths are properly set up (**Tools > Options...**). Check DirectX Dependencies section for details." + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le, armv7l. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
`$ make TARGET_ARCH=armv7l`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + +### Mac +The Mac samples are built using makefiles. To use the makefiles, change directory into the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` + +The samples makefiles can take advantage of certain options: + +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` + +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where "A B ..." is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use SMS="50 60". + ``` + $ make SMS="A B ..." + ``` + +* **HOST_COMPILER=** - override the default clang host compiler. See the [Mac Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html#system-requirements) for a list of supported host compilers. + ``` + $ make HOST_COMPILER=clang + ``` + +## References (for more details) + diff --git a/Samples/bandwidthTest/bandwidthTest.cu b/Samples/bandwidthTest/bandwidthTest.cu new file mode 100644 index 00000000..dbb8582e --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest.cu @@ -0,0 +1,969 @@ +/* Copyright (c) 2019, 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 is a simple test program to measure the memcopy bandwidth of the GPU. + * It can measure device to device copy bandwidth, host to device copy bandwidth + * for pageable and pinned memory, and device to host copy bandwidth for + * pageable and pinned memory. + * + * Usage: + * ./bandwidthTest [option]... + */ + +// CUDA runtime +#include + +// includes +#include // helper functions for CUDA error checking and initialization +#include // helper for shared functions common to CUDA Samples + +#include + +#include +#include +#include + +static const char *sSDKsample = "CUDA Bandwidth Test"; + +// defines, project +#define MEMCOPY_ITERATIONS 100 +#define DEFAULT_SIZE (32 * (1e6)) // 32 M +#define DEFAULT_INCREMENT (4 * (1e6)) // 4 M +#define CACHE_CLEAR_SIZE (16 * (1e6)) // 16 M + +// shmoo mode defines +#define SHMOO_MEMSIZE_MAX (64 * (1e6)) // 64 M +#define SHMOO_MEMSIZE_START (1e3) // 1 KB +#define SHMOO_INCREMENT_1KB (1e3) // 1 KB +#define SHMOO_INCREMENT_2KB (2 * 1e3) // 2 KB +#define SHMOO_INCREMENT_10KB (10 * (1e3)) // 10KB +#define SHMOO_INCREMENT_100KB (100 * (1e3)) // 100 KB +#define SHMOO_INCREMENT_1MB (1e6) // 1 MB +#define SHMOO_INCREMENT_2MB (2 * 1e6) // 2 MB +#define SHMOO_INCREMENT_4MB (4 * 1e6) // 4 MB +#define SHMOO_LIMIT_20KB (20 * (1e3)) // 20 KB +#define SHMOO_LIMIT_50KB (50 * (1e3)) // 50 KB +#define SHMOO_LIMIT_100KB (100 * (1e3)) // 100 KB +#define SHMOO_LIMIT_1MB (1e6) // 1 MB +#define SHMOO_LIMIT_16MB (16 * 1e6) // 16 MB +#define SHMOO_LIMIT_32MB (32 * 1e6) // 32 MB + +// CPU cache flush +#define FLUSH_SIZE (256 * 1024 * 1024) +char *flush_buf; + +// enums, project +enum testMode { QUICK_MODE, RANGE_MODE, SHMOO_MODE }; +enum memcpyKind { DEVICE_TO_HOST, HOST_TO_DEVICE, DEVICE_TO_DEVICE }; +enum printMode { USER_READABLE, CSV }; +enum memoryMode { PINNED, PAGEABLE }; + +const char *sMemoryCopyKind[] = {"Device to Host", "Host to Device", + "Device to Device", NULL}; + +const char *sMemoryMode[] = {"PINNED", "PAGEABLE", NULL}; + +// if true, use CPU based timing for everything +static bool bDontUseGPUTiming; + +int *pArgc = NULL; +char **pArgv = NULL; + +//////////////////////////////////////////////////////////////////////////////// +// declaration, forward +int runTest(const int argc, const char **argv); +void testBandwidth(unsigned int start, unsigned int end, unsigned int increment, + testMode mode, memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, bool wc); +void testBandwidthQuick(unsigned int size, memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, + bool wc); +void testBandwidthRange(unsigned int start, unsigned int end, + unsigned int increment, memcpyKind kind, + printMode printmode, memoryMode memMode, + int startDevice, int endDevice, bool wc); +void testBandwidthShmoo(memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, + bool wc); +float testDeviceToHostTransfer(unsigned int memSize, memoryMode memMode, + bool wc); +float testHostToDeviceTransfer(unsigned int memSize, memoryMode memMode, + bool wc); +float testDeviceToDeviceTransfer(unsigned int memSize); +void printResultsReadable(unsigned int *memSizes, double *bandwidths, + unsigned int count, memcpyKind kind, + memoryMode memMode, int iNumDevs, bool wc); +void printResultsCSV(unsigned int *memSizes, double *bandwidths, + unsigned int count, memcpyKind kind, memoryMode memMode, + int iNumDevs, bool wc); +void printHelp(void); + +//////////////////////////////////////////////////////////////////////////////// +// Program main +//////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) { + pArgc = &argc; + pArgv = argv; + + flush_buf = (char *)malloc(FLUSH_SIZE); + + // set logfile name and start logs + printf("[%s] - Starting...\n", sSDKsample); + + int iRetVal = runTest(argc, (const char **)argv); + + if (iRetVal < 0) { + checkCudaErrors(cudaSetDevice(0)); + } + + // finish + printf("%s\n", (iRetVal == 0) ? "Result = PASS" : "Result = FAIL"); + + printf( + "\nNOTE: The CUDA Samples are not meant for performance measurements. " + "Results may vary when GPU Boost is enabled.\n"); + + free(flush_buf); + + exit((iRetVal == 0) ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/////////////////////////////////////////////////////////////////////////////// +// Parse args, run the appropriate tests +/////////////////////////////////////////////////////////////////////////////// +int runTest(const int argc, const char **argv) { + int start = DEFAULT_SIZE; + int end = DEFAULT_SIZE; + int startDevice = 0; + int endDevice = 0; + int increment = DEFAULT_INCREMENT; + testMode mode = QUICK_MODE; + bool htod = false; + bool dtoh = false; + bool dtod = false; + bool wc = false; + char *modeStr; + char *device = NULL; + printMode printmode = USER_READABLE; + char *memModeStr = NULL; + memoryMode memMode = PINNED; + + // process command line args + if (checkCmdLineFlag(argc, argv, "help")) { + printHelp(); + return 0; + } + + if (checkCmdLineFlag(argc, argv, "csv")) { + printmode = CSV; + } + + if (getCmdLineArgumentString(argc, argv, "memory", &memModeStr)) { + if (strcmp(memModeStr, "pageable") == 0) { + memMode = PAGEABLE; + } else if (strcmp(memModeStr, "pinned") == 0) { + memMode = PINNED; + } else { + printf("Invalid memory mode - valid modes are pageable or pinned\n"); + printf("See --help for more information\n"); + return -1000; + } + } else { + // default - pinned memory + memMode = PINNED; + } + + if (getCmdLineArgumentString(argc, argv, "device", &device)) { + int deviceCount; + cudaError_t error_id = cudaGetDeviceCount(&deviceCount); + + if (error_id != cudaSuccess) { + printf("cudaGetDeviceCount returned %d\n-> %s\n", (int)error_id, + cudaGetErrorString(error_id)); + exit(EXIT_FAILURE); + } + + if (deviceCount == 0) { + printf("!!!!!No devices found!!!!!\n"); + return -2000; + } + + if (strcmp(device, "all") == 0) { + printf( + "\n!!!!!Cumulative Bandwidth to be computed from all the devices " + "!!!!!!\n\n"); + startDevice = 0; + endDevice = deviceCount - 1; + } else { + startDevice = endDevice = atoi(device); + + if (startDevice >= deviceCount || startDevice < 0) { + printf( + "\n!!!!!Invalid GPU number %d given hence default gpu %d will be " + "used !!!!!\n", + startDevice, 0); + startDevice = endDevice = 0; + } + } + } + + printf("Running on...\n\n"); + + for (int currentDevice = startDevice; currentDevice <= endDevice; + currentDevice++) { + cudaDeviceProp deviceProp; + cudaError_t error_id = cudaGetDeviceProperties(&deviceProp, currentDevice); + + if (error_id == cudaSuccess) { + printf(" Device %d: %s\n", currentDevice, deviceProp.name); + + if (deviceProp.computeMode == cudaComputeModeProhibited) { + fprintf(stderr, + "Error: device is running in , no " + "threads can use ::cudaSetDevice().\n"); + checkCudaErrors(cudaSetDevice(currentDevice)); + + exit(EXIT_FAILURE); + } + } else { + printf("cudaGetDeviceProperties returned %d\n-> %s\n", (int)error_id, + cudaGetErrorString(error_id)); + checkCudaErrors(cudaSetDevice(currentDevice)); + + exit(EXIT_FAILURE); + } + } + + if (getCmdLineArgumentString(argc, argv, "mode", &modeStr)) { + // figure out the mode + if (strcmp(modeStr, "quick") == 0) { + printf(" Quick Mode\n\n"); + mode = QUICK_MODE; + } else if (strcmp(modeStr, "shmoo") == 0) { + printf(" Shmoo Mode\n\n"); + mode = SHMOO_MODE; + } else if (strcmp(modeStr, "range") == 0) { + printf(" Range Mode\n\n"); + mode = RANGE_MODE; + } else { + printf("Invalid mode - valid modes are quick, range, or shmoo\n"); + printf("See --help for more information\n"); + return -3000; + } + } else { + // default mode - quick + printf(" Quick Mode\n\n"); + mode = QUICK_MODE; + } + + if (checkCmdLineFlag(argc, argv, "htod")) { + htod = true; + } + + if (checkCmdLineFlag(argc, argv, "dtoh")) { + dtoh = true; + } + + if (checkCmdLineFlag(argc, argv, "dtod")) { + dtod = true; + } + +#if CUDART_VERSION >= 2020 + + if (checkCmdLineFlag(argc, argv, "wc")) { + wc = true; + } + +#endif + + if (checkCmdLineFlag(argc, argv, "cputiming")) { + bDontUseGPUTiming = true; + } + + if (!htod && !dtoh && !dtod) { + // default: All + htod = true; + dtoh = true; + dtod = true; + } + + if (RANGE_MODE == mode) { + if (checkCmdLineFlag(argc, (const char **)argv, "start")) { + start = getCmdLineArgumentInt(argc, argv, "start"); + + if (start <= 0) { + printf("Illegal argument - start must be greater than zero\n"); + return -4000; + } + } else { + printf("Must specify a starting size in range mode\n"); + printf("See --help for more information\n"); + return -5000; + } + + if (checkCmdLineFlag(argc, (const char **)argv, "end")) { + end = getCmdLineArgumentInt(argc, argv, "end"); + + if (end <= 0) { + printf("Illegal argument - end must be greater than zero\n"); + return -6000; + } + + if (start > end) { + printf("Illegal argument - start is greater than end\n"); + return -7000; + } + } else { + printf("Must specify an end size in range mode.\n"); + printf("See --help for more information\n"); + return -8000; + } + + if (checkCmdLineFlag(argc, argv, "increment")) { + increment = getCmdLineArgumentInt(argc, argv, "increment"); + + if (increment <= 0) { + printf("Illegal argument - increment must be greater than zero\n"); + return -9000; + } + } else { + printf("Must specify an increment in user mode\n"); + printf("See --help for more information\n"); + return -10000; + } + } + + if (htod) { + testBandwidth((unsigned int)start, (unsigned int)end, + (unsigned int)increment, mode, HOST_TO_DEVICE, printmode, + memMode, startDevice, endDevice, wc); + } + + if (dtoh) { + testBandwidth((unsigned int)start, (unsigned int)end, + (unsigned int)increment, mode, DEVICE_TO_HOST, printmode, + memMode, startDevice, endDevice, wc); + } + + if (dtod) { + testBandwidth((unsigned int)start, (unsigned int)end, + (unsigned int)increment, mode, DEVICE_TO_DEVICE, printmode, + memMode, startDevice, endDevice, wc); + } + + // Ensure that we reset all CUDA Devices in question + for (int nDevice = startDevice; nDevice <= endDevice; nDevice++) { + cudaSetDevice(nDevice); + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// Run a bandwidth test +/////////////////////////////////////////////////////////////////////////////// +void testBandwidth(unsigned int start, unsigned int end, unsigned int increment, + testMode mode, memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, + bool wc) { + switch (mode) { + case QUICK_MODE: + testBandwidthQuick(DEFAULT_SIZE, kind, printmode, memMode, startDevice, + endDevice, wc); + break; + + case RANGE_MODE: + testBandwidthRange(start, end, increment, kind, printmode, memMode, + startDevice, endDevice, wc); + break; + + case SHMOO_MODE: + testBandwidthShmoo(kind, printmode, memMode, startDevice, endDevice, wc); + break; + + default: + break; + } +} + +////////////////////////////////////////////////////////////////////// +// Run a quick mode bandwidth test +////////////////////////////////////////////////////////////////////// +void testBandwidthQuick(unsigned int size, memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, + bool wc) { + testBandwidthRange(size, size, DEFAULT_INCREMENT, kind, printmode, memMode, + startDevice, endDevice, wc); +} + +/////////////////////////////////////////////////////////////////////// +// Run a range mode bandwidth test +////////////////////////////////////////////////////////////////////// +void testBandwidthRange(unsigned int start, unsigned int end, + unsigned int increment, memcpyKind kind, + printMode printmode, memoryMode memMode, + int startDevice, int endDevice, bool wc) { + // count the number of copies we're going to run + unsigned int count = 1 + ((end - start) / increment); + + unsigned int *memSizes = (unsigned int *)malloc(count * sizeof(unsigned int)); + double *bandwidths = (double *)malloc(count * sizeof(double)); + + // Before calculating the cumulative bandwidth, initialize bandwidths array to + // NULL + for (unsigned int i = 0; i < count; i++) { + bandwidths[i] = 0.0; + } + + // Use the device asked by the user + for (int currentDevice = startDevice; currentDevice <= endDevice; + currentDevice++) { + cudaSetDevice(currentDevice); + + // run each of the copies + for (unsigned int i = 0; i < count; i++) { + memSizes[i] = start + i * increment; + + switch (kind) { + case DEVICE_TO_HOST: + bandwidths[i] += testDeviceToHostTransfer(memSizes[i], memMode, wc); + break; + + case HOST_TO_DEVICE: + bandwidths[i] += testHostToDeviceTransfer(memSizes[i], memMode, wc); + break; + + case DEVICE_TO_DEVICE: + bandwidths[i] += testDeviceToDeviceTransfer(memSizes[i]); + break; + } + } + } // Complete the bandwidth computation on all the devices + + // print results + if (printmode == CSV) { + printResultsCSV(memSizes, bandwidths, count, kind, memMode, + (1 + endDevice - startDevice), wc); + } else { + printResultsReadable(memSizes, bandwidths, count, kind, memMode, + (1 + endDevice - startDevice), wc); + } + + // clean up + free(memSizes); + free(bandwidths); +} + +////////////////////////////////////////////////////////////////////////////// +// Intense shmoo mode - covers a large range of values with varying increments +////////////////////////////////////////////////////////////////////////////// +void testBandwidthShmoo(memcpyKind kind, printMode printmode, + memoryMode memMode, int startDevice, int endDevice, + bool wc) { + // count the number of copies to make + unsigned int count = + 1 + (SHMOO_LIMIT_20KB / SHMOO_INCREMENT_1KB) + + ((SHMOO_LIMIT_50KB - SHMOO_LIMIT_20KB) / SHMOO_INCREMENT_2KB) + + ((SHMOO_LIMIT_100KB - SHMOO_LIMIT_50KB) / SHMOO_INCREMENT_10KB) + + ((SHMOO_LIMIT_1MB - SHMOO_LIMIT_100KB) / SHMOO_INCREMENT_100KB) + + ((SHMOO_LIMIT_16MB - SHMOO_LIMIT_1MB) / SHMOO_INCREMENT_1MB) + + ((SHMOO_LIMIT_32MB - SHMOO_LIMIT_16MB) / SHMOO_INCREMENT_2MB) + + ((SHMOO_MEMSIZE_MAX - SHMOO_LIMIT_32MB) / SHMOO_INCREMENT_4MB); + + unsigned int *memSizes = (unsigned int *)malloc(count * sizeof(unsigned int)); + double *bandwidths = (double *)malloc(count * sizeof(double)); + + // Before calculating the cumulative bandwidth, initialize bandwidths array to + // NULL + for (unsigned int i = 0; i < count; i++) { + bandwidths[i] = 0.0; + } + + // Use the device asked by the user + for (int currentDevice = startDevice; currentDevice <= endDevice; + currentDevice++) { + cudaSetDevice(currentDevice); + // Run the shmoo + int iteration = 0; + unsigned int memSize = 0; + + while (memSize <= SHMOO_MEMSIZE_MAX) { + if (memSize < SHMOO_LIMIT_20KB) { + memSize += SHMOO_INCREMENT_1KB; + } else if (memSize < SHMOO_LIMIT_50KB) { + memSize += SHMOO_INCREMENT_2KB; + } else if (memSize < SHMOO_LIMIT_100KB) { + memSize += SHMOO_INCREMENT_10KB; + } else if (memSize < SHMOO_LIMIT_1MB) { + memSize += SHMOO_INCREMENT_100KB; + } else if (memSize < SHMOO_LIMIT_16MB) { + memSize += SHMOO_INCREMENT_1MB; + } else if (memSize < SHMOO_LIMIT_32MB) { + memSize += SHMOO_INCREMENT_2MB; + } else { + memSize += SHMOO_INCREMENT_4MB; + } + + memSizes[iteration] = memSize; + + switch (kind) { + case DEVICE_TO_HOST: + bandwidths[iteration] += + testDeviceToHostTransfer(memSizes[iteration], memMode, wc); + break; + + case HOST_TO_DEVICE: + bandwidths[iteration] += + testHostToDeviceTransfer(memSizes[iteration], memMode, wc); + break; + + case DEVICE_TO_DEVICE: + bandwidths[iteration] += + testDeviceToDeviceTransfer(memSizes[iteration]); + break; + } + + iteration++; + printf("."); + fflush(0); + } + } // Complete the bandwidth computation on all the devices + + // print results + printf("\n"); + + if (CSV == printmode) { + printResultsCSV(memSizes, bandwidths, count, kind, memMode, + (1 + endDevice - startDevice), wc); + } else { + printResultsReadable(memSizes, bandwidths, count, kind, memMode, + (1 + endDevice - startDevice), wc); + } + + // clean up + free(memSizes); + free(bandwidths); +} + +/////////////////////////////////////////////////////////////////////////////// +// test the bandwidth of a device to host memcopy of a specific size +/////////////////////////////////////////////////////////////////////////////// +float testDeviceToHostTransfer(unsigned int memSize, memoryMode memMode, + bool wc) { + StopWatchInterface *timer = NULL; + float elapsedTimeInMs = 0.0f; + float bandwidthInGBs = 0.0f; + unsigned char *h_idata = NULL; + unsigned char *h_odata = NULL; + cudaEvent_t start, stop; + + sdkCreateTimer(&timer); + checkCudaErrors(cudaEventCreate(&start)); + checkCudaErrors(cudaEventCreate(&stop)); + + // allocate host memory + if (PINNED == memMode) { + // pinned memory mode - use special function to get OS-pinned memory +#if CUDART_VERSION >= 2020 + checkCudaErrors(cudaHostAlloc((void **)&h_idata, memSize, + (wc) ? cudaHostAllocWriteCombined : 0)); + checkCudaErrors(cudaHostAlloc((void **)&h_odata, memSize, + (wc) ? cudaHostAllocWriteCombined : 0)); +#else + checkCudaErrors(cudaMallocHost((void **)&h_idata, memSize)); + checkCudaErrors(cudaMallocHost((void **)&h_odata, memSize)); +#endif + } else { + // pageable memory mode - use malloc + h_idata = (unsigned char *)malloc(memSize); + h_odata = (unsigned char *)malloc(memSize); + + if (h_idata == 0 || h_odata == 0) { + fprintf(stderr, "Not enough memory avaialable on host to run test!\n"); + exit(EXIT_FAILURE); + } + } + + // initialize the memory + for (unsigned int i = 0; i < memSize / sizeof(unsigned char); i++) { + h_idata[i] = (unsigned char)(i & 0xff); + } + + // allocate device memory + unsigned char *d_idata; + checkCudaErrors(cudaMalloc((void **)&d_idata, memSize)); + + // initialize the device memory + checkCudaErrors( + cudaMemcpy(d_idata, h_idata, memSize, cudaMemcpyHostToDevice)); + + // copy data from GPU to Host + if (PINNED == memMode) { + if (bDontUseGPUTiming) sdkStartTimer(&timer); + checkCudaErrors(cudaEventRecord(start, 0)); + for (unsigned int i = 0; i < MEMCOPY_ITERATIONS; i++) { + checkCudaErrors(cudaMemcpyAsync(h_odata, d_idata, memSize, + cudaMemcpyDeviceToHost, 0)); + } + checkCudaErrors(cudaEventRecord(stop, 0)); + checkCudaErrors(cudaDeviceSynchronize()); + checkCudaErrors(cudaEventElapsedTime(&elapsedTimeInMs, start, stop)); + if (bDontUseGPUTiming) { + sdkStopTimer(&timer); + elapsedTimeInMs = sdkGetTimerValue(&timer); + sdkResetTimer(&timer); + } + } else { + elapsedTimeInMs = 0; + for (unsigned int i = 0; i < MEMCOPY_ITERATIONS; i++) { + sdkStartTimer(&timer); + checkCudaErrors( + cudaMemcpy(h_odata, d_idata, memSize, cudaMemcpyDeviceToHost)); + sdkStopTimer(&timer); + elapsedTimeInMs += sdkGetTimerValue(&timer); + sdkResetTimer(&timer); + memset(flush_buf, i, FLUSH_SIZE); + } + } + + // calculate bandwidth in GB/s + double time_s = elapsedTimeInMs / 1e3; + bandwidthInGBs = (memSize * (float)MEMCOPY_ITERATIONS) / (double)1e9; + bandwidthInGBs = bandwidthInGBs / time_s; + // clean up memory + checkCudaErrors(cudaEventDestroy(stop)); + checkCudaErrors(cudaEventDestroy(start)); + sdkDeleteTimer(&timer); + + if (PINNED == memMode) { + checkCudaErrors(cudaFreeHost(h_idata)); + checkCudaErrors(cudaFreeHost(h_odata)); + } else { + free(h_idata); + free(h_odata); + } + + checkCudaErrors(cudaFree(d_idata)); + + return bandwidthInGBs; +} + +/////////////////////////////////////////////////////////////////////////////// +//! test the bandwidth of a host to device memcopy of a specific size +/////////////////////////////////////////////////////////////////////////////// +float testHostToDeviceTransfer(unsigned int memSize, memoryMode memMode, + bool wc) { + StopWatchInterface *timer = NULL; + float elapsedTimeInMs = 0.0f; + float bandwidthInGBs = 0.0f; + cudaEvent_t start, stop; + sdkCreateTimer(&timer); + checkCudaErrors(cudaEventCreate(&start)); + checkCudaErrors(cudaEventCreate(&stop)); + + // allocate host memory + unsigned char *h_odata = NULL; + + if (PINNED == memMode) { +#if CUDART_VERSION >= 2020 + // pinned memory mode - use special function to get OS-pinned memory + checkCudaErrors(cudaHostAlloc((void **)&h_odata, memSize, + (wc) ? cudaHostAllocWriteCombined : 0)); +#else + // pinned memory mode - use special function to get OS-pinned memory + checkCudaErrors(cudaMallocHost((void **)&h_odata, memSize)); +#endif + } else { + // pageable memory mode - use malloc + h_odata = (unsigned char *)malloc(memSize); + + if (h_odata == 0) { + fprintf(stderr, "Not enough memory available on host to run test!\n"); + exit(EXIT_FAILURE); + } + } + + unsigned char *h_cacheClear1 = (unsigned char *)malloc(CACHE_CLEAR_SIZE); + unsigned char *h_cacheClear2 = (unsigned char *)malloc(CACHE_CLEAR_SIZE); + + if (h_cacheClear1 == 0 || h_cacheClear2 == 0) { + fprintf(stderr, "Not enough memory available on host to run test!\n"); + exit(EXIT_FAILURE); + } + + // initialize the memory + for (unsigned int i = 0; i < memSize / sizeof(unsigned char); i++) { + h_odata[i] = (unsigned char)(i & 0xff); + } + + for (unsigned int i = 0; i < CACHE_CLEAR_SIZE / sizeof(unsigned char); i++) { + h_cacheClear1[i] = (unsigned char)(i & 0xff); + h_cacheClear2[i] = (unsigned char)(0xff - (i & 0xff)); + } + + // allocate device memory + unsigned char *d_idata; + checkCudaErrors(cudaMalloc((void **)&d_idata, memSize)); + + // copy host memory to device memory + if (PINNED == memMode) { + if (bDontUseGPUTiming) sdkStartTimer(&timer); + checkCudaErrors(cudaEventRecord(start, 0)); + for (unsigned int i = 0; i < MEMCOPY_ITERATIONS; i++) { + checkCudaErrors(cudaMemcpyAsync(d_idata, h_odata, memSize, + cudaMemcpyHostToDevice, 0)); + } + checkCudaErrors(cudaEventRecord(stop, 0)); + checkCudaErrors(cudaDeviceSynchronize()); + checkCudaErrors(cudaEventElapsedTime(&elapsedTimeInMs, start, stop)); + if (bDontUseGPUTiming) { + sdkStopTimer(&timer); + elapsedTimeInMs = sdkGetTimerValue(&timer); + sdkResetTimer(&timer); + } + } else { + elapsedTimeInMs = 0; + for (unsigned int i = 0; i < MEMCOPY_ITERATIONS; i++) { + sdkStartTimer(&timer); + checkCudaErrors( + cudaMemcpy(d_idata, h_odata, memSize, cudaMemcpyHostToDevice)); + sdkStopTimer(&timer); + elapsedTimeInMs += sdkGetTimerValue(&timer); + sdkResetTimer(&timer); + memset(flush_buf, i, FLUSH_SIZE); + } + } + + // calculate bandwidth in GB/s + double time_s = elapsedTimeInMs / 1e3; + bandwidthInGBs = (memSize * (float)MEMCOPY_ITERATIONS) / (double)1e9; + bandwidthInGBs = bandwidthInGBs / time_s; + // clean up memory + checkCudaErrors(cudaEventDestroy(stop)); + checkCudaErrors(cudaEventDestroy(start)); + sdkDeleteTimer(&timer); + + if (PINNED == memMode) { + checkCudaErrors(cudaFreeHost(h_odata)); + } else { + free(h_odata); + } + + free(h_cacheClear1); + free(h_cacheClear2); + checkCudaErrors(cudaFree(d_idata)); + + return bandwidthInGBs; +} + +/////////////////////////////////////////////////////////////////////////////// +//! test the bandwidth of a device to device memcopy of a specific size +/////////////////////////////////////////////////////////////////////////////// +float testDeviceToDeviceTransfer(unsigned int memSize) { + StopWatchInterface *timer = NULL; + float elapsedTimeInMs = 0.0f; + float bandwidthInGBs = 0.0f; + cudaEvent_t start, stop; + + sdkCreateTimer(&timer); + checkCudaErrors(cudaEventCreate(&start)); + checkCudaErrors(cudaEventCreate(&stop)); + + // allocate host memory + unsigned char *h_idata = (unsigned char *)malloc(memSize); + + if (h_idata == 0) { + fprintf(stderr, "Not enough memory avaialable on host to run test!\n"); + exit(EXIT_FAILURE); + } + + // initialize the host memory + for (unsigned int i = 0; i < memSize / sizeof(unsigned char); i++) { + h_idata[i] = (unsigned char)(i & 0xff); + } + + // allocate device memory + unsigned char *d_idata; + checkCudaErrors(cudaMalloc((void **)&d_idata, memSize)); + unsigned char *d_odata; + checkCudaErrors(cudaMalloc((void **)&d_odata, memSize)); + + // initialize memory + checkCudaErrors( + cudaMemcpy(d_idata, h_idata, memSize, cudaMemcpyHostToDevice)); + + // run the memcopy + sdkStartTimer(&timer); + checkCudaErrors(cudaEventRecord(start, 0)); + + for (unsigned int i = 0; i < MEMCOPY_ITERATIONS; i++) { + checkCudaErrors( + cudaMemcpy(d_odata, d_idata, memSize, cudaMemcpyDeviceToDevice)); + } + + checkCudaErrors(cudaEventRecord(stop, 0)); + + // Since device to device memory copies are non-blocking, + // cudaDeviceSynchronize() is required in order to get + // proper timing. + checkCudaErrors(cudaDeviceSynchronize()); + + // get the total elapsed time in ms + sdkStopTimer(&timer); + checkCudaErrors(cudaEventElapsedTime(&elapsedTimeInMs, start, stop)); + + if (bDontUseGPUTiming) { + elapsedTimeInMs = sdkGetTimerValue(&timer); + } + + // calculate bandwidth in GB/s + double time_s = elapsedTimeInMs / 1e3; + bandwidthInGBs = (2.0f * memSize * (float)MEMCOPY_ITERATIONS) / (double)1e9; + bandwidthInGBs = bandwidthInGBs / time_s; + + // clean up memory + sdkDeleteTimer(&timer); + free(h_idata); + checkCudaErrors(cudaEventDestroy(stop)); + checkCudaErrors(cudaEventDestroy(start)); + checkCudaErrors(cudaFree(d_idata)); + checkCudaErrors(cudaFree(d_odata)); + + return bandwidthInGBs; +} + +///////////////////////////////////////////////////////// +// print results in an easily read format +//////////////////////////////////////////////////////// +void printResultsReadable(unsigned int *memSizes, double *bandwidths, + unsigned int count, memcpyKind kind, + memoryMode memMode, int iNumDevs, bool wc) { + printf(" %s Bandwidth, %i Device(s)\n", sMemoryCopyKind[kind], iNumDevs); + printf(" %s Memory Transfers\n", sMemoryMode[memMode]); + + if (wc) { + printf(" Write-Combined Memory Writes are Enabled"); + } + + printf(" Transfer Size (Bytes)\tBandwidth(GB/s)\n"); + unsigned int i; + + for (i = 0; i < (count - 1); i++) { + printf(" %u\t\t\t%s%.1f\n", memSizes[i], + (memSizes[i] < 10000) ? "\t" : "", bandwidths[i]); + } + + printf(" %u\t\t\t%s%.1f\n\n", memSizes[i], + (memSizes[i] < 10000) ? "\t" : "", bandwidths[i]); +} + +/////////////////////////////////////////////////////////////////////////// +// print results in a database format +/////////////////////////////////////////////////////////////////////////// +void printResultsCSV(unsigned int *memSizes, double *bandwidths, + unsigned int count, memcpyKind kind, memoryMode memMode, + int iNumDevs, bool wc) { + std::string sConfig; + + // log config information + if (kind == DEVICE_TO_DEVICE) { + sConfig += "D2D"; + } else { + if (kind == DEVICE_TO_HOST) { + sConfig += "D2H"; + } else if (kind == HOST_TO_DEVICE) { + sConfig += "H2D"; + } + + if (memMode == PAGEABLE) { + sConfig += "-Paged"; + } else if (memMode == PINNED) { + sConfig += "-Pinned"; + + if (wc) { + sConfig += "-WriteCombined"; + } + } + } + + unsigned int i; + double dSeconds = 0.0; + + for (i = 0; i < count; i++) { + dSeconds = (double)memSizes[i] / (bandwidths[i] * (double)(1 << 20)); + printf( + "bandwidthTest-%s, Bandwidth = %.1f GB/s, Time = %.5f s, Size = %u " + "bytes, NumDevsUsed = %d\n", + sConfig.c_str(), bandwidths[i], dSeconds, memSizes[i], iNumDevs); + } +} + +/////////////////////////////////////////////////////////////////////////// +// Print help screen +/////////////////////////////////////////////////////////////////////////// +void printHelp(void) { + printf("Usage: bandwidthTest [OPTION]...\n"); + printf( + "Test the bandwidth for device to host, host to device, and device to " + "device transfers\n"); + printf("\n"); + printf( + "Example: measure the bandwidth of device to host pinned memory copies " + "in the range 1024 Bytes to 102400 Bytes in 1024 Byte increments\n"); + printf( + "./bandwidthTest --memory=pinned --mode=range --start=1024 --end=102400 " + "--increment=1024 --dtoh\n"); + + printf("\n"); + printf("Options:\n"); + printf("--help\tDisplay this help menu\n"); + printf("--csv\tPrint results as a CSV\n"); + printf("--device=[deviceno]\tSpecify the device device to be used\n"); + printf(" all - compute cumulative bandwidth on all the devices\n"); + printf(" 0,1,2,...,n - Specify any particular device to be used\n"); + printf("--memory=[MEMMODE]\tSpecify which memory mode to use\n"); + printf(" pageable - pageable memory\n"); + printf(" pinned - non-pageable system memory\n"); + printf("--mode=[MODE]\tSpecify the mode to use\n"); + printf(" quick - performs a quick measurement\n"); + printf(" range - measures a user-specified range of values\n"); + printf(" shmoo - performs an intense shmoo of a large range of values\n"); + + printf("--htod\tMeasure host to device transfers\n"); + printf("--dtoh\tMeasure device to host transfers\n"); + printf("--dtod\tMeasure device to device transfers\n"); +#if CUDART_VERSION >= 2020 + printf("--wc\tAllocate pinned memory as write-combined\n"); +#endif + printf("--cputiming\tForce CPU-based timing always\n"); + + printf("Range mode options\n"); + printf("--start=[SIZE]\tStarting transfer size in bytes\n"); + printf("--end=[SIZE]\tEnding transfer size in bytes\n"); + printf("--increment=[SIZE]\tIncrement size in bytes\n"); +} diff --git a/Samples/bandwidthTest/bandwidthTest_vs2012.sln b/Samples/bandwidthTest/bandwidthTest_vs2012.sln new file mode 100644 index 00000000..12f46461 --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2012.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bandwidthTest", "bandwidthTest_vs2012.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/bandwidthTest/bandwidthTest_vs2012.vcxproj b/Samples/bandwidthTest/bandwidthTest_vs2012.vcxproj new file mode 100644 index 00000000..f567519c --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2012.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + bandwidthTest_vs2012 + bandwidthTest + + + + + Application + MultiByte + v110 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/bandwidthTest.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/bandwidthTest/bandwidthTest_vs2013.sln b/Samples/bandwidthTest/bandwidthTest_vs2013.sln new file mode 100644 index 00000000..63178742 --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2013.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 13.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bandwidthTest", "bandwidthTest_vs2013.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/bandwidthTest/bandwidthTest_vs2013.vcxproj b/Samples/bandwidthTest/bandwidthTest_vs2013.vcxproj new file mode 100644 index 00000000..04c193b5 --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2013.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + bandwidthTest_vs2013 + bandwidthTest + + + + + Application + MultiByte + v120 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/bandwidthTest.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/bandwidthTest/bandwidthTest_vs2015.sln b/Samples/bandwidthTest/bandwidthTest_vs2015.sln new file mode 100644 index 00000000..749f041e --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2015.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bandwidthTest", "bandwidthTest_vs2015.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/bandwidthTest/bandwidthTest_vs2015.vcxproj b/Samples/bandwidthTest/bandwidthTest_vs2015.vcxproj new file mode 100644 index 00000000..e4fda909 --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2015.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + bandwidthTest_vs2015 + bandwidthTest + + + + + Application + MultiByte + v140 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/bandwidthTest.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/bandwidthTest/bandwidthTest_vs2017.sln b/Samples/bandwidthTest/bandwidthTest_vs2017.sln new file mode 100644 index 00000000..53bbf3de --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2017.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2017 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bandwidthTest", "bandwidthTest_vs2017.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/bandwidthTest/bandwidthTest_vs2017.vcxproj b/Samples/bandwidthTest/bandwidthTest_vs2017.vcxproj new file mode 100644 index 00000000..f17a5e2c --- /dev/null +++ b/Samples/bandwidthTest/bandwidthTest_vs2017.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + bandwidthTest_vs2017 + bandwidthTest + + + + + Application + MultiByte + v141 + 10.0.15063.0 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/bandwidthTest.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/conjugateGradientCudaGraphs/Makefile b/Samples/conjugateGradientCudaGraphs/Makefile index 0130308e..98e29ee1 100644 --- a/Samples/conjugateGradientCudaGraphs/Makefile +++ b/Samples/conjugateGradientCudaGraphs/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) @@ -264,7 +268,7 @@ GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM) endif endif -LIBRARIES += -lcublas_static -lcusparse_static -lculibos +LIBRARIES += -lcublas_static -lcublasLt_static -lcusparse_static -lculibos ifeq ($(SAMPLE_ENABLED),0) EXEC ?= @echo "[@]" diff --git a/Samples/conjugateGradientCudaGraphs/NsightEclipse.xml b/Samples/conjugateGradientCudaGraphs/NsightEclipse.xml index 8d06fc36..8362bbd9 100644 --- a/Samples/conjugateGradientCudaGraphs/NsightEclipse.xml +++ b/Samples/conjugateGradientCudaGraphs/NsightEclipse.xml @@ -31,6 +31,7 @@ cublas_static + cublasLt_static cusparse_static culibos @@ -55,6 +56,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/conjugateGradientCudaGraphs/README.md b/Samples/conjugateGradientCudaGraphs/README.md index 5a829f54..62346a12 100644 --- a/Samples/conjugateGradientCudaGraphs/README.md +++ b/Samples/conjugateGradientCudaGraphs/README.md @@ -10,7 +10,7 @@ Linear Algebra, CUBLAS Library, CUSPARSE Library ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cudaStreamBeginCapture, cudaStreamEndCapture, cudaGraphCreate, cudaGraphLaunch, ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs.cu b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs.cu index b6b83fba..61e755f5 100644 --- a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs.cu +++ b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs.cu @@ -323,7 +323,7 @@ int main(int argc, char **argv) { checkCudaErrors(cudaStreamCreate(&streamForGraph)); checkCudaErrors(cublasSetStream(cublasHandle, stream1)); checkCudaErrors(cusparseSetStream(cusparseHandle, stream1)); - checkCudaErrors(cudaStreamBeginCapture(stream1)); + checkCudaErrors(cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal)); r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_r0, d_b); cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE); diff --git a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2012.vcxproj b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2012.vcxproj index 4a583fc9..52c7d2de 100644 --- a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2012.vcxproj +++ b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2013.vcxproj b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2013.vcxproj index eeb90636..1659a3ff 100644 --- a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2013.vcxproj +++ b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2015.vcxproj b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2015.vcxproj index 69312b05..9d6d0206 100644 --- a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2015.vcxproj +++ b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2017.vcxproj b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2017.vcxproj index 13de64fc..099dc018 100644 --- a/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2017.vcxproj +++ b/Samples/conjugateGradientCudaGraphs/conjugateGradientCudaGraphs_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiBlockCG/Makefile b/Samples/conjugateGradientMultiBlockCG/Makefile index 2092da3b..7c05f18f 100644 --- a/Samples/conjugateGradientMultiBlockCG/Makefile +++ b/Samples/conjugateGradientMultiBlockCG/Makefile @@ -264,7 +264,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 60 61 70 72 75 +else SMS ?= 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/conjugateGradientMultiBlockCG/NsightEclipse.xml b/Samples/conjugateGradientMultiBlockCG/NsightEclipse.xml index 067f3f07..a7b88e1e 100644 --- a/Samples/conjugateGradientMultiBlockCG/NsightEclipse.xml +++ b/Samples/conjugateGradientMultiBlockCG/NsightEclipse.xml @@ -42,6 +42,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/conjugateGradientMultiBlockCG/README.md b/Samples/conjugateGradientMultiBlockCG/README.md index 101b692a..fcfad8ef 100644 --- a/Samples/conjugateGradientMultiBlockCG/README.md +++ b/Samples/conjugateGradientMultiBlockCG/README.md @@ -10,7 +10,7 @@ Unified Memory, Linear Algebra, Cooperative Groups, MultiBlock Cooperative Group ## Supported SM Architectures -[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.5 ](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) ## Supported OSes @@ -27,7 +27,7 @@ x86_64, ppc64le ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2012.vcxproj b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2012.vcxproj index fdf29d91..f3030349 100644 --- a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2012.vcxproj +++ b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2013.vcxproj b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2013.vcxproj index 3ff37342..f1efeff6 100644 --- a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2013.vcxproj +++ b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2015.vcxproj b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2015.vcxproj index 0a5ad150..e6f5de81 100644 --- a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2015.vcxproj +++ b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2017.vcxproj b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2017.vcxproj index 69e2bf9f..f6764ec8 100644 --- a/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2017.vcxproj +++ b/Samples/conjugateGradientMultiBlockCG/conjugateGradientMultiBlockCG_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -104,6 +104,6 @@ - + diff --git a/Samples/conjugateGradientMultiDeviceCG/Makefile b/Samples/conjugateGradientMultiDeviceCG/Makefile index cfeb8783..62dc80da 100644 --- a/Samples/conjugateGradientMultiDeviceCG/Makefile +++ b/Samples/conjugateGradientMultiDeviceCG/Makefile @@ -264,7 +264,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 60 61 70 72 75 +else SMS ?= 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/conjugateGradientMultiDeviceCG/NsightEclipse.xml b/Samples/conjugateGradientMultiDeviceCG/NsightEclipse.xml index b17237fc..19570b77 100644 --- a/Samples/conjugateGradientMultiDeviceCG/NsightEclipse.xml +++ b/Samples/conjugateGradientMultiDeviceCG/NsightEclipse.xml @@ -49,6 +49,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/conjugateGradientMultiDeviceCG/README.md b/Samples/conjugateGradientMultiDeviceCG/README.md index cc989f40..bc508730 100644 --- a/Samples/conjugateGradientMultiDeviceCG/README.md +++ b/Samples/conjugateGradientMultiDeviceCG/README.md @@ -10,7 +10,7 @@ Unified Memory, Linear Algebra, Cooperative Groups, MultiDevice Cooperative Grou ## Supported SM Architectures -[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.5 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cudaMemAdvise, cudaMemPrefetchAsync, cudaLaunchCooperativeKernelMultiDevice, cud ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG.cu b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG.cu index f71233b4..e823911c 100644 --- a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG.cu +++ b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG.cu @@ -415,7 +415,7 @@ void getIdenticalGPUs(int num_of_gpus, std::set &identicalGPUs) { identicalGPUs.erase(it); } if (!deviceProp.cooperativeMultiDeviceLaunch || - !deviceProp.concurrentManagedAccess) { + !deviceProp.managedMemory) { identicalGPUs.erase(it); } it++; @@ -450,8 +450,7 @@ int main(int argc, char **argv) { if (identicalGPUs.size() <= 1) { printf( "No Two or more GPUs with same architecture capable of " - "cooperativeMultiDeviceLaunch & concurrentManagedAccess found. " - "\nWaiving the sample\n"); + "cooperativeMultiDeviceLaunch & managedMemory found. \nWaiving the sample\n"); exit(EXIT_WAIVED); } diff --git a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2012.vcxproj b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2012.vcxproj index 3e2d3377..8b59da3a 100644 --- a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2012.vcxproj +++ b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2013.vcxproj b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2013.vcxproj index c8afcd5e..7cf463c2 100644 --- a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2013.vcxproj +++ b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2015.vcxproj b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2015.vcxproj index 8c4961b1..37a092c6 100644 --- a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2015.vcxproj +++ b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2017.vcxproj b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2017.vcxproj index a1198775..d08c4992 100644 --- a/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2017.vcxproj +++ b/Samples/conjugateGradientMultiDeviceCG/conjugateGradientMultiDeviceCG_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -104,6 +104,6 @@ - + diff --git a/Samples/cudaTensorCoreGemm/Makefile b/Samples/cudaTensorCoreGemm/Makefile index b44fe082..8a0b5024 100644 --- a/Samples/cudaTensorCoreGemm/Makefile +++ b/Samples/cudaTensorCoreGemm/Makefile @@ -246,12 +246,6 @@ ifeq ($(TARGET_ARCH),armv7l) SAMPLE_ENABLED := 0 endif -# This sample is not supported on aarch64 -ifeq ($(TARGET_ARCH),aarch64) - $(info >>> WARNING - cudaTensorCoreGemm is not supported on aarch64 - waiving sample <<<) - SAMPLE_ENABLED := 0 -endif - ALL_LDFLAGS := ALL_LDFLAGS += $(ALL_CCFLAGS) ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) @@ -264,7 +258,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 70 72 75 +else SMS ?= 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/cudaTensorCoreGemm/NsightEclipse.xml b/Samples/cudaTensorCoreGemm/NsightEclipse.xml index 73020e63..b8b24e8c 100644 --- a/Samples/cudaTensorCoreGemm/NsightEclipse.xml +++ b/Samples/cudaTensorCoreGemm/NsightEclipse.xml @@ -43,12 +43,16 @@ In addition to that, it demonstrates the use of the new CUDA function attribute 1:CUDA Basic Topics sm70 + sm72 sm75 x86_64 linux + + aarch64 + windows7 diff --git a/Samples/cudaTensorCoreGemm/README.md b/Samples/cudaTensorCoreGemm/README.md index 4cc8e332..83c833f5 100644 --- a/Samples/cudaTensorCoreGemm/README.md +++ b/Samples/cudaTensorCoreGemm/README.md @@ -14,7 +14,7 @@ Matrix Multiply, WMMA, Tensor Cores ## Supported SM Architectures -[SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](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) ## Supported OSes @@ -22,7 +22,7 @@ Linux, Windows ## Supported CPU Architecture -x86_64, ppc64le +x86_64, ppc64le, aarch64 ## CUDA APIs involved @@ -31,7 +31,7 @@ cudaMallocManaged, cudaDeviceSynchronize, cudaFuncSetAttribute, cudaEventCreate, ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run @@ -52,9 +52,9 @@ $ cd $ make ``` The samples makefiles can take advantage of certain options: -* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le. +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le, aarch64. By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
-`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
`$ make TARGET_ARCH=aarch64`
See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. * **dbg=1** - build with debug symbols ``` diff --git a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm.cu b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm.cu index d2ce38ec..8a945d2a 100644 --- a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm.cu +++ b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm.cu @@ -180,16 +180,16 @@ using namespace nvcuda; -__host__ void init_host_matrices(float *a, float *b, float *c) { +__host__ void init_host_matrices(half *a, half *b, float *c) { for (int i = 0; i < M_GLOBAL; i++) { for (int j = 0; j < K_GLOBAL; j++) { - a[i * K_GLOBAL + j] = static_cast(rand() % 3); + a[i * K_GLOBAL + j] = (half)(rand() % 3); } } for (int i = 0; i < N_GLOBAL; i++) { for (int j = 0; j < K_GLOBAL; j++) { - b[i * K_GLOBAL + j] = static_cast(rand() % 3); + b[i * K_GLOBAL + j] = (half)(rand() % 3); } } @@ -198,26 +198,6 @@ __host__ void init_host_matrices(float *a, float *b, float *c) { } } -__global__ void init_device_matrices(const float *A_h, const float *B_h, - const float *C_h, half *A, half *B, - float *C, float *D) { - for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < M_GLOBAL * K_GLOBAL; - i += gridDim.x * blockDim.x) - A[i] = __float2half(A_h[i]); - - for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < N_GLOBAL * K_GLOBAL; - i += gridDim.x * blockDim.x) - B[i] = __float2half(B_h[i]); - - for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < M_GLOBAL * N_GLOBAL; - i += gridDim.x * blockDim.x) - C[i] = C_h[i]; - - for (int i = blockDim.x * blockIdx.x + threadIdx.x; i < M_GLOBAL * N_GLOBAL; - i += gridDim.x * blockDim.x) - D[i] = 0; -} - __global__ void compute_gemm(const half *A, const half *B, const float *C, float *D, float alpha, float beta) { extern __shared__ half shmem[][CHUNK_K * K + SKEW_HALF]; @@ -486,7 +466,7 @@ __global__ void simple_wmma_gemm(half *a, half *b, float *c, float *d, int m_ld, } } -__host__ void matMultiplyOnHost(float *A, float *B, float *C, float alpha, +__host__ void matMultiplyOnHost(half *A, half *B, float *C, float alpha, float beta, int numARows, int numAColumns, int numBRows, int numBColumns, int numCRows, int numCColumns) { @@ -495,7 +475,7 @@ __host__ void matMultiplyOnHost(float *A, float *B, float *C, float alpha, float temp = 0.0; for (int k = 0; k < numAColumns; k++) { - temp += A[i * numAColumns + k] * B[j * numBRows + k]; + temp += (float)A[i * numAColumns + k] * (float)B[j * numBRows + k]; } C[i * numCColumns + j] = temp * alpha + beta * C[i * numCColumns + j]; @@ -514,7 +494,7 @@ int main(int argc, char **argv) { // Tensor cores require a GPU of Volta (SM7X) architecture or higher. if (deviceProp.major < 7) { printf( - "cudaTensorCoreGemm requires requires SM 7.0 or higher to use Tensor " + "cudaTensorCoreGemm requires SM 7.0 or higher to use Tensor " "Cores. Exiting...\n"); exit(EXIT_WAIVED); } @@ -523,25 +503,20 @@ int main(int argc, char **argv) { printf("N: %d (%d x %d)\n", N_GLOBAL, N, N_TILES); printf("K: %d (%d x %d)\n", K_GLOBAL, K, K_TILES); - float *A_h = NULL; - float *B_h = NULL; + half *A_h = NULL; + half *B_h = NULL; float *C_h = NULL; #if CPU_DEBUG float *result_hD = NULL; float *result_host = NULL; #endif - checkCudaErrors(cudaMallocManaged(reinterpret_cast(&A_h), - sizeof(float) * M_GLOBAL * K_GLOBAL)); - checkCudaErrors(cudaMallocManaged(reinterpret_cast(&B_h), - sizeof(float) * K_GLOBAL * N_GLOBAL)); - checkCudaErrors(cudaMallocManaged(reinterpret_cast(&C_h), - sizeof(float) * M_GLOBAL * N_GLOBAL)); + A_h = (half *)malloc(sizeof(half) * M_GLOBAL * K_GLOBAL); + B_h = (half *)malloc(sizeof(half) * K_GLOBAL * N_GLOBAL); + C_h = (float *)malloc(sizeof(float) * M_GLOBAL * N_GLOBAL); #if CPU_DEBUG - checkCudaErrors(cudaMallocManaged((void **)&result_hD, - sizeof(float) * M_GLOBAL * N_GLOBAL)); - checkCudaErrors(cudaMallocManaged((void **)&result_host, - sizeof(float) * M_GLOBAL * N_GLOBAL)); + result_hD = (float *)malloc(sizeof(float) * M_GLOBAL * N_GLOBAL); + result_host = (float *)malloc(sizeof(float) * M_GLOBAL * N_GLOBAL); #endif half *A = NULL; @@ -567,11 +542,13 @@ int main(int argc, char **argv) { printf("Preparing data for GPU...\n"); - checkKernelErrors( - (init_device_matrices<<>>(A_h, B_h, C_h, A, B, C, D))); - - checkCudaErrors(cudaDeviceSynchronize()); + checkCudaErrors(cudaMemcpy(A, A_h, sizeof(half) * M_GLOBAL * K_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(B, B_h, sizeof(half) * N_GLOBAL * K_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(C, C_h, sizeof(float) * M_GLOBAL * N_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemset(D, 0, sizeof(float) * M_GLOBAL * N_GLOBAL)); enum { // Compute the right amount of shared memory to request. @@ -650,6 +627,8 @@ int main(int argc, char **argv) { printf("mismatch i=%d result_hD=%f result_host=%f\n", i, result_hD[i], result_host[i]); } + free(result_hD); + free(result_host); #endif float milliseconds = 0; @@ -662,9 +641,9 @@ int main(int argc, char **argv) { (milliseconds / 1000.)) / 1e12); - checkCudaErrors(cudaFree(reinterpret_cast(A_h))); - checkCudaErrors(cudaFree(reinterpret_cast(B_h))); - checkCudaErrors(cudaFree(reinterpret_cast(C_h))); + free(A_h); + free(B_h); + free(C_h); checkCudaErrors(cudaFree(reinterpret_cast(A))); checkCudaErrors(cudaFree(reinterpret_cast(B))); checkCudaErrors(cudaFree(reinterpret_cast(C))); diff --git a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2012.vcxproj b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2012.vcxproj index bf77cf93..29f45dec 100644 --- a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2012.vcxproj +++ b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2013.vcxproj b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2013.vcxproj index d8afbc90..757336c4 100644 --- a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2013.vcxproj +++ b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2015.vcxproj b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2015.vcxproj index b6e3fb60..1c2ffc7e 100644 --- a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2015.vcxproj +++ b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2017.vcxproj b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2017.vcxproj index da8345fc..9a4d3f30 100644 --- a/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2017.vcxproj +++ b/Samples/cudaTensorCoreGemm/cudaTensorCoreGemm_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/deviceQuery/Makefile b/Samples/deviceQuery/Makefile index 09ef57d6..7d2ff2c0 100644 --- a/Samples/deviceQuery/Makefile +++ b/Samples/deviceQuery/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/deviceQuery/NsightEclipse.xml b/Samples/deviceQuery/NsightEclipse.xml index e93f0864..04bfe94a 100644 --- a/Samples/deviceQuery/NsightEclipse.xml +++ b/Samples/deviceQuery/NsightEclipse.xml @@ -39,6 +39,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/deviceQuery/README.md b/Samples/deviceQuery/README.md index 29182b74..e0e217df 100644 --- a/Samples/deviceQuery/README.md +++ b/Samples/deviceQuery/README.md @@ -10,7 +10,7 @@ CUDA Runtime API, Device Query ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cudaSetDevice, cudaGetDeviceCount, cudaGetDeviceProperties, cudaDriverGetVersion ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/deviceQuery/deviceQuery_vs2012.vcxproj b/Samples/deviceQuery/deviceQuery_vs2012.vcxproj index 43281e98..27e81701 100644 --- a/Samples/deviceQuery/deviceQuery_vs2012.vcxproj +++ b/Samples/deviceQuery/deviceQuery_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/deviceQuery/deviceQuery_vs2013.vcxproj b/Samples/deviceQuery/deviceQuery_vs2013.vcxproj index 73e0e3ee..1433399f 100644 --- a/Samples/deviceQuery/deviceQuery_vs2013.vcxproj +++ b/Samples/deviceQuery/deviceQuery_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/deviceQuery/deviceQuery_vs2015.vcxproj b/Samples/deviceQuery/deviceQuery_vs2015.vcxproj index 60fb078b..45024d45 100644 --- a/Samples/deviceQuery/deviceQuery_vs2015.vcxproj +++ b/Samples/deviceQuery/deviceQuery_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/deviceQuery/deviceQuery_vs2017.vcxproj b/Samples/deviceQuery/deviceQuery_vs2017.vcxproj index b6c0f478..b5d52c6e 100644 --- a/Samples/deviceQuery/deviceQuery_vs2017.vcxproj +++ b/Samples/deviceQuery/deviceQuery_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/immaTensorCoreGemm/Makefile b/Samples/immaTensorCoreGemm/Makefile new file mode 100644 index 00000000..5236c7f4 --- /dev/null +++ b/Samples/immaTensorCoreGemm/Makefile @@ -0,0 +1,318 @@ +################################################################################ +# Copyright (c) 2018, 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. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Location of the CUDA Toolkit +CUDA_PATH ?= /usr/local/cuda + +############################## +# start deprecated interface # +############################## +ifeq ($(x86_64),1) + $(info WARNING - x86_64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=x86_64 instead) + TARGET_ARCH ?= x86_64 +endif +ifeq ($(ARMv7),1) + $(info WARNING - ARMv7 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=armv7l instead) + TARGET_ARCH ?= armv7l +endif +ifeq ($(aarch64),1) + $(info WARNING - aarch64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=aarch64 instead) + TARGET_ARCH ?= aarch64 +endif +ifeq ($(ppc64le),1) + $(info WARNING - ppc64le variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=ppc64le instead) + TARGET_ARCH ?= ppc64le +endif +ifneq ($(GCC),) + $(info WARNING - GCC variable has been deprecated) + $(info WARNING - please use HOST_COMPILER=$(GCC) instead) + HOST_COMPILER ?= $(GCC) +endif +ifneq ($(abi),) + $(error ERROR - abi variable has been removed) +endif +############################ +# end deprecated interface # +############################ + +# architecture +HOST_ARCH := $(shell uname -m) +TARGET_ARCH ?= $(HOST_ARCH) +ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l)) + ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le)) + TARGET_SIZE := 64 + else ifneq (,$(filter $(TARGET_ARCH),armv7l)) + TARGET_SIZE := 32 + endif + else + TARGET_SIZE := $(shell getconf LONG_BIT) + endif +else + $(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!) +endif +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le)) + $(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!) + endif +endif + +# When on native aarch64 system with userspace of 32-bit, change TARGET_ARCH to armv7l +ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_SIZE),aarch64-aarch64-32) + TARGET_ARCH = armv7l +endif + +# operating system +HOST_OS := $(shell uname -s 2>/dev/null | tr "[:upper:]" "[:lower:]") +TARGET_OS ?= $(HOST_OS) +ifeq (,$(filter $(TARGET_OS),linux darwin qnx android)) + $(error ERROR - unsupported value $(TARGET_OS) for TARGET_OS!) +endif + +# host compiler +ifeq ($(TARGET_OS),darwin) + ifeq ($(shell expr `xcodebuild -version | grep -i xcode | awk '{print $$2}' | cut -d'.' -f1` \>= 5),1) + HOST_COMPILER ?= clang++ + endif +else ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(HOST_ARCH)-$(TARGET_ARCH),x86_64-armv7l) + ifeq ($(TARGET_OS),linux) + HOST_COMPILER ?= arm-linux-gnueabihf-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/arm-unknown-nto-qnx6.6.0eabi-g++ + else ifeq ($(TARGET_OS),android) + HOST_COMPILER ?= arm-linux-androideabi-g++ + endif + else ifeq ($(TARGET_ARCH),aarch64) + ifeq ($(TARGET_OS), linux) + HOST_COMPILER ?= aarch64-linux-gnu-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ + else ifeq ($(TARGET_OS), android) + HOST_COMPILER ?= aarch64-linux-android-clang++ + endif + else ifeq ($(TARGET_ARCH),ppc64le) + HOST_COMPILER ?= powerpc64le-linux-gnu-g++ + endif +endif +HOST_COMPILER ?= g++ +NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER) + +# internal flags +NVCCFLAGS := -m${TARGET_SIZE} +CCFLAGS := +LDFLAGS := + +# build flags +ifeq ($(TARGET_OS),darwin) + LDFLAGS += -rpath $(CUDA_PATH)/lib + CCFLAGS += -arch $(HOST_ARCH) +else ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_OS),x86_64-armv7l-linux) + LDFLAGS += --dynamic-linker=/lib/ld-linux-armhf.so.3 + CCFLAGS += -mfloat-abi=hard +else ifeq ($(TARGET_OS),android) + LDFLAGS += -pie + CCFLAGS += -fpie -fpic -fexceptions +endif + +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/arm-linux-gnueabihf + endif + endif + ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu + LDFLAGS += --unresolved-symbols=ignore-in-shared-libs + CCFLAGS += -isystem=$(TARGET_FS)/usr/include + CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu + endif + endif +endif + +ifeq ($(TARGET_OS),qnx) + CCFLAGS += -DWIN_INTERFACE_CUSTOM + LDFLAGS += -lsocket +endif + +# Install directory of different arch +CUDA_INSTALL_TARGET_DIR := +ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-qnx) + CUDA_INSTALL_TARGET_DIR = targets/ARMv7-linux-QNX/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-qnx/ +else ifeq ($(TARGET_ARCH),ppc64le) + CUDA_INSTALL_TARGET_DIR = targets/ppc64le-linux/ +endif + +# Debug build flags +ifeq ($(dbg),1) + NVCCFLAGS += -g -G + BUILD_TYPE := debug +else + BUILD_TYPE := release +endif + +ALL_CCFLAGS := +ALL_CCFLAGS += $(NVCCFLAGS) +ALL_CCFLAGS += $(EXTRA_NVCCFLAGS) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(CCFLAGS)) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) + +SAMPLE_ENABLED := 1 + +# This sample is not supported on Mac OSX +ifeq ($(TARGET_OS),darwin) + $(info >>> WARNING - immaTensorCoreGemm is not supported on Mac OSX - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +# This sample is not supported on ARMv7 +ifeq ($(TARGET_ARCH),armv7l) + $(info >>> WARNING - immaTensorCoreGemm is not supported on ARMv7 - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +ALL_LDFLAGS := +ALL_LDFLAGS += $(ALL_CCFLAGS) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(EXTRA_LDFLAGS)) + +# Common includes and paths for CUDA +INCLUDES := -I../../Common +LIBRARIES := + +################################################################################ + +# Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 72 75 +else +SMS ?= 75 +endif + +ifeq ($(SMS),) +$(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) +SAMPLE_ENABLED := 0 +endif + +ifeq ($(GENCODE_FLAGS),) +# Generate SASS code for each SM architecture listed in $(SMS) +$(foreach sm,$(SMS),$(eval GENCODE_FLAGS += -gencode arch=compute_$(sm),code=sm_$(sm))) + +# Generate PTX code from the highest SM architecture in $(SMS) to guarantee forward-compatibility +HIGHEST_SM := $(lastword $(sort $(SMS))) +ifneq ($(HIGHEST_SM),) +GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM) +endif +endif + +ALL_CCFLAGS += -maxrregcount=255 + +ifeq ($(SAMPLE_ENABLED),0) +EXEC ?= @echo "[@]" +endif + +################################################################################ + +# Target rules +all: build + +build: immaTensorCoreGemm + +check.deps: +ifeq ($(SAMPLE_ENABLED),0) + @echo "Sample will be waived due to the above missing dependencies" +else + @echo "Sample is ready - all dependencies have been met" +endif + +immaTensorCoreGemm.o:immaTensorCoreGemm.cu + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +immaTensorCoreGemm: immaTensorCoreGemm.o + $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o $@ $+ $(LIBRARIES) + $(EXEC) mkdir -p ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + $(EXEC) cp $@ ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + +run: build + $(EXEC) ./immaTensorCoreGemm + +clean: + rm -f immaTensorCoreGemm immaTensorCoreGemm.o + rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/immaTensorCoreGemm + +clobber: clean diff --git a/Samples/immaTensorCoreGemm/NsightEclipse.xml b/Samples/immaTensorCoreGemm/NsightEclipse.xml new file mode 100644 index 00000000..d87551ca --- /dev/null +++ b/Samples/immaTensorCoreGemm/NsightEclipse.xml @@ -0,0 +1,64 @@ + + + + immaTensorCoreGemm + + -maxrregcount=255 + + + cudaMallocManaged + cudaDeviceSynchronize + cudaFuncSetAttribute + cudaEventCreate + cudaEventRecord + cudaEventSynchronize + cudaEventElapsedTime + cudaFree + + + whole + + ./ + ../ + ../../common/inc + + + Matrix Multiply + WMMA + Tensor Cores + + + + + + + + true + immaTensorCoreGemm.cu + + 1:CUDA Basic Topics + + sm72 + sm75 + + + x86_64 + linux + + + aarch64 + + + windows7 + + + ppc64le + linux + + + + 7.2 + + Tensor Core GEMM Integer MMA + exe + diff --git a/Samples/immaTensorCoreGemm/README.md b/Samples/immaTensorCoreGemm/README.md new file mode 100644 index 00000000..6d52d628 --- /dev/null +++ b/Samples/immaTensorCoreGemm/README.md @@ -0,0 +1,70 @@ +# immaTensorCoreGemm - Tensor Core GEMM Integer MMA + +## Description + +CUDA sample demonstrating a integer GEMM computation using the Warp Matrix Multiply and Accumulate (WMMA) API for integer introduced in CUDA 10. This sample demonstrates the use of the CUDA WMMA API employing the Tensor Cores introduced in the Volta chip family for faster matrix operations. In addition to that, it demonstrates the use of the new CUDA function attribute cudaFuncAttributeMaxDynamicSharedMemorySize that allows the application to reserve an extended amount of shared memory than it is available by default. + +## Key Concepts + +Matrix Multiply, WMMA, Tensor Cores + +## Supported SM Architectures + +[SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) + +## Supported OSes + +Linux, Windows + +## Supported CPU Architecture + +x86_64, ppc64le, aarch64 + +## CUDA APIs involved + +### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) +cudaMallocManaged, cudaDeviceSynchronize, cudaFuncSetAttribute, cudaEventCreate, cudaEventRecord, cudaEventSynchronize, cudaEventElapsedTime, cudaFree + +## Prerequisites + +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. + +## Build and Run + +### Windows +The Windows samples are built using the Visual Studio IDE. Solution files (.sln) are provided for each supported version of Visual Studio, using the format: +``` +*_vs.sln - for Visual Studio +``` +Each individual sample has its own set of solution files in its directory: + +To build/examine all the samples at once, the complete solution files should be used. To build/examine a single sample, the individual sample solution files should be used. +> **Note:** Some samples require that the Microsoft DirectX SDK (June 2010 or newer) be installed and that the VC++ directory paths are properly set up (**Tools > Options...**). Check DirectX Dependencies section for details." + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le, aarch64. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
`$ make TARGET_ARCH=aarch64`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + +## References (for more details) + diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm.cu b/Samples/immaTensorCoreGemm/immaTensorCoreGemm.cu new file mode 100644 index 00000000..08369aa4 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm.cu @@ -0,0 +1,655 @@ +/* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// CUDA sample demonstrating a integer GEMM computation using the Warp Matrix +// Multiply and Accumulate API. + +// In this program, the compute_gemm kernel computes the result of a matrix +// multiplication and addition: D = alpha * A * B + beta * C. The dimensions of +// both C and D matrices are M_GLOBAL x N_GLOBAL. The A matrix is M_GLOBAL x +// K_GLOBAL (row-major), the B matrix is K_GLOBAL x N_GLOBAL (column-major). In +// that kernel, each CTA computes one 128 x 128 tile of the resulting matrix per +// iteration. When the tile is computed, the CTA stores it to the global memory +// and begins a new iteration, selecting a new 128 x 128 tile to compute. +// Each CTA consists of eight warps. For the 128 x 128 tile, each warp computes +// eight 16 x 16 subtiles, organized in a 2 x 4 two-dimensional array. Warps +// compute the 16 x 16 subtiles using nvcuda::wmma::mma_sync operations by +// moving through the K_GLOBAL dimension of the A and B matrices and +// accumulating the intermediate result in the local thread state. + +// There are a number of simple optimizations used in the algorithm: +// - The CTA copies the 128 x 128 tile of the C matrix from the global memory to +// shared memory. After that is done, each warp loads the C matrix fragments +// from shared memory, thus avoiding a random global memory access. +// - On each internal iteration, the CTA copies a portion of the A and B +// matrices from +// global memory to shared memory. After that, all warps in the CTA reuse the +// A and B data from shared memory, thus reducing the number of data copies +// from global memory. +// - The portions of the A and B matrices are stored in shared memory with an +// additional +// padding (skew) to reduce the number of shared memory access bank conflicts. +// (See a detailed explanation near the SKEW_HALF macro definition.) +// - When the CTA finishes computing the tiles of the resulting matrix, each +// warp stores +// its subtiles to shared memory. The CTA then copies the shared memory +// contents to global memory, again avoiding redundant random global memory +// accesses. +// - Note that the CTA tile size is chosen to maximize the GPU register +// utilization, +// but carefully enough to avoid local memory use. + +#include +#include +#include +#include + +// helper functions and utilities to work with CUDA +#include +#include + +// Externally configurable parameters. + +#ifndef CPU_DEBUG +// Set this to 1 to verify the correctness of the GPU-computed matrix. +#define CPU_DEBUG 0 +#endif + +#ifndef SHARED_MEMORY_LIMIT_64K +// Set this to 0 to use more than 64 Kb of shared memory to cache data, to +// improve the performance of the computations on GPU. +// Note that you need a GPU that can have more than 64 Kb of shared memory +// per multiprocessor. +#define SHARED_MEMORY_LIMIT_64K 1 +#endif + +// GPU configuration. + +#define WARP_SIZE 32 + +// MMA matrix tile dimensions. + +#define M 16 +#define N 16 +#define K 16 + +#define WMMA_M 16 +#define WMMA_N 16 +#define WMMA_K 16 + +// GEMM configuration. + +#define M_TILES 256 +#define N_TILES 256 +#define K_TILES 256 + +#define M_GLOBAL (M * M_TILES) +#define N_GLOBAL (N * N_TILES) +#define K_GLOBAL (K * K_TILES) + +#define C_LAYOUT wmma::mem_row_major + +// Implementation constants. + +#define WARPS_PER_BLOCK 8 +#define THREADS_PER_BLOCK (WARP_SIZE * WARPS_PER_BLOCK) + +#if SHARED_MEMORY_LIMIT_64K +// With only 64 Kb shared memory available, we can fit two 8-tile chunks of +// the A and B matrix data, that are 16 * 16 * 8 * 8 * 2 = 32 Kb each +// (i.e. two 8x8 arrays of tiles of 16x16 uint8_t-typed elements per CTA). +// But we cannot account the 8 Kb total skew overhead, without which the +// performance would be severely impacted. So we choose to reduce the chunk size +// in half, i.e. the amount of A and B matrix data we cache in shared memory. +// Accordingly, this doubles the number of outer iterations across the global K +// dimension, which only slightly impacts the performance. +#define CHUNK_K 8 +#else +#define CHUNK_K 16 +#endif + +#define CHUNK_LINE_BYTES (CHUNK_K * K * sizeof(uint8_t)) +#define WARP_COPY_BYTES (WARP_SIZE * sizeof(int4)) +#define CHUNK_COPY_LINES_PER_WARP (WARP_COPY_BYTES / CHUNK_LINE_BYTES) +#define CHUNK_COPY_LINE_LANES (WARP_SIZE / CHUNK_COPY_LINES_PER_WARP) + +#define BLOCK_ROW_WARPS 2 +#define BLOCK_COL_WARPS 4 + +#define WARP_ROW_TILES 4 +#define WARP_COL_TILES 2 + +#define BLOCK_ROW_TILES (WARP_ROW_TILES * BLOCK_ROW_WARPS) +#define BLOCK_COL_TILES (WARP_COL_TILES * BLOCK_COL_WARPS) + +#define GLOBAL_MEM_STRIDE N_GLOBAL + +#define SHMEM_STRIDE (N * BLOCK_ROW_TILES) +#define SHMEM_OFFSET (N * WARP_ROW_TILES) + +// The macro below is used to shift rows of the A matrix and columns of the B +// matrix in shared memory to minimize possible bank conflicts. Before +// performing the nvcuda::wmma::mma_sync operation, the warp must load the +// matrix data using the nvcuda::wmma::load_matrix_sync operation. Although the +// memory access pattern is not specified for that function, each lane in the +// warp can read one or multiple matrix elements from different matrix rows or +// columns. For shared memory, such access can result in bank conflicts if +// different rows / columns of the matrix map to the same bank. By shifting each +// row and column by a few bytes, we make sure that they map to different banks, +// thus reducing the number of possible bank conflicts. The number of 16 +// one-byte "uint8_t" elements is chosen as the minimum possible shift because +// we must keep each row and column 128-bit aligned, as required by +// nvcuda::wmma::load_matrix_sync. +#define SKEW_UINT8 16 + +#define checkKernelErrors(expr) \ + do { \ + expr; \ + \ + cudaError_t __err = cudaGetLastError(); \ + if (__err != cudaSuccess) { \ + printf("Line %d: '%s' failed: %s\n", __LINE__, #expr, \ + cudaGetErrorString(__err)); \ + abort(); \ + } \ + } while (0) + +using namespace nvcuda; + +__host__ void init_host_matrices(uint8_t *a, uint8_t *b, int *c) { + for (int i = 0; i < M_GLOBAL; i++) { + for (int j = 0; j < K_GLOBAL; j++) { + a[i * K_GLOBAL + j] = (uint8_t)(rand() % 3); + } + } + + for (int i = 0; i < N_GLOBAL; i++) { + for (int j = 0; j < K_GLOBAL; j++) { + b[i * K_GLOBAL + j] = (uint8_t)(rand() % 3); + } + } + + for (int t = 0; t < M_GLOBAL * N_GLOBAL; t++) { + c[t] = (rand() % 3); + } +} + +__global__ void compute_gemm_imma(const uint8_t *A, const uint8_t *B, + const int *C, int *D, int alpha, int beta) { + extern __shared__ uint8_t shmem[][CHUNK_K * K + SKEW_UINT8]; + + // Warp and lane identification. + const unsigned int warpId = threadIdx.x / WARP_SIZE; + const unsigned int laneId = threadIdx.x % WARP_SIZE; + + // Offset in shared memory from which the B matrix is stored. + const size_t shmem_idx_b_off = BLOCK_COL_TILES * M; + + // This pointer is used to access the C and D matrix tiles this warp computes. + int *shmem_warp_tile_ptr = (int *)&shmem[0][0] + + (warpId / 2) * SHMEM_STRIDE * K * 2 + + (warpId % 2) * SHMEM_OFFSET; + + // This pointer is used to stream the C and D matrices block-wide tile to and + // from shared memory. + int *shmem_warp_stream_ptr = (int *)&shmem[0][0] + warpId * SHMEM_STRIDE * K; + + // Adjust the beta scaler, as it'll be multiplied by alpha at the end of + // each tile computation. Technically this is not generally correct (may + // result in a loss of precision). Zero still needs to be specially handled + // though. + beta /= alpha; + + // Each CTA slides along the 128 x 128 tiles from the top left corner of the + // matrix to the right and down, and selects the next tile to compute. Once + // there's no such tile, all warps in this CTA exit. + for (unsigned int block_pos = blockIdx.x;; block_pos += gridDim.x) { + const unsigned int block_tile_i = + ((block_pos * BLOCK_ROW_TILES) / N_TILES) * (BLOCK_COL_TILES); + const unsigned int block_tile_j = (block_pos * BLOCK_COL_TILES) % N_TILES; + + // Stop when there are no more D matrix tiles to compute in this CTA. + if (block_tile_i >= M_TILES) { + break; + } + + // This warp's pointer to the C matrix data to copy memory from to shared + // memory. + const size_t gmem_idx = + (block_tile_i + warpId) * M * GLOBAL_MEM_STRIDE + block_tile_j * N; + const int *src_gmem_warp_stream_ptr = &C[gmem_idx]; + + // Stream multiple C tiles to shared memory. +#pragma unroll + for (int i = 0; i < K; i++) { + typedef int4 copy_t; + + *((copy_t *)(shmem_warp_stream_ptr + SHMEM_STRIDE * i) + laneId) = + *((copy_t *)(src_gmem_warp_stream_ptr + GLOBAL_MEM_STRIDE * i) + + laneId); + } + + __syncthreads(); + + // These fragments will accumulate the result of A and B matrix fragment + // multiplications along the K_GLOBAL dimension. + wmma::fragment c[WARP_COL_TILES] + [WARP_ROW_TILES]; + + // Load the C matrix tiles into fragments from shared memory. +#pragma unroll + for (int i = 0; i < WARP_COL_TILES; i++) { +#pragma unroll + for (int j = 0; j < WARP_ROW_TILES; j++) { + const int *tile_ptr = + shmem_warp_tile_ptr + i * SHMEM_STRIDE * K + j * N; + + wmma::load_matrix_sync(c[i][j], tile_ptr, SHMEM_STRIDE, C_LAYOUT); + } + } + + __syncthreads(); + + // Scale the C matrix. +#pragma unroll + for (int i = 0; i < WARP_COL_TILES; i++) { +#pragma unroll + for (int j = 0; j < WARP_ROW_TILES; j++) { +#pragma unroll + for (int t = 0; t < c[i][j].num_elements; t++) { + c[i][j].x[t] *= beta; + } + } + } + + // Select what warp copies what matrix to shared memory. + // Warps 0-3 copy the A matrix, warps 4-7 copy the B matrix. + const uint8_t *warp_ptr = (warpId < 4) ? (&A[block_tile_i * M * K_GLOBAL] + + M * K_GLOBAL * (warpId % 4) * 2) + : (&B[block_tile_j * N * K_GLOBAL] + + N * K_GLOBAL * (warpId % 4) * 2); + + // Go through the global K dimension by a fixed step at a time. +#pragma unroll + for (int tile_k = 0; tile_k < K_TILES; tile_k += CHUNK_K) { + // Copy slices of the A and B matrices to shared memory. + // The first half of the warps in the CTA copy the A matrix, the rest copy + // the B matrix. + size_t shmem_idx = + warpId < (WARPS_PER_BLOCK / 2) + ? (M * (warpId % (WARPS_PER_BLOCK / 2)) * 2) + : (N * (warpId % (WARPS_PER_BLOCK / 2)) * 2 + shmem_idx_b_off); + + // First half of the warp copies the first row / column of the matrix, + // the second half of the warp copies the next. + int4 *lane_ptr = (int4 *)(warp_ptr + tile_k * K + + (laneId / CHUNK_COPY_LINE_LANES) * K_GLOBAL) + + (laneId % CHUNK_COPY_LINE_LANES); + + // Shift the second half of the warp to the next row / column in the + // shared memory. + shmem_idx += laneId / CHUNK_COPY_LINE_LANES; + +#pragma unroll + for (int i = 0; i < ((WARP_SIZE / 2) / CHUNK_COPY_LINES_PER_WARP) * 2; + i++) { + // Copy 16 bytes at once in each lane. + *((int4 *)&shmem[shmem_idx][0] + (laneId % CHUNK_COPY_LINE_LANES)) = + *lane_ptr; + + // Advance the global memory pointer and the shared memory index. + lane_ptr = (int4 *)((uint8_t *)lane_ptr + + K_GLOBAL * CHUNK_COPY_LINES_PER_WARP); + shmem_idx += CHUNK_COPY_LINES_PER_WARP; + } + + __syncthreads(); + + // Compute a grid of C matrix tiles in each warp. +#pragma unroll + for (int k_step = 0; k_step < CHUNK_K; k_step++) { + wmma::fragment + a[WARP_COL_TILES]; + wmma::fragment + b[WARP_ROW_TILES]; + +#pragma unroll + for (int i = 0; i < WARP_COL_TILES; i++) { + size_t shmem_idx_a = (warpId / 2) * M * 2 + (i * M); + const uint8_t *tile_ptr = &shmem[shmem_idx_a][k_step * K]; + + wmma::load_matrix_sync(a[i], tile_ptr, K * CHUNK_K + SKEW_UINT8); + +#pragma unroll + for (int j = 0; j < WARP_ROW_TILES; j++) { + if (i == 0) { + // Load the B matrix fragment once, because it is going to be + // reused against the other A matrix fragments. + size_t shmem_idx_b = shmem_idx_b_off + + (WARP_ROW_TILES * N) * (warpId % 2) + + (j * N); + const uint8_t *tile_ptr = &shmem[shmem_idx_b][k_step * K]; + + wmma::load_matrix_sync(b[j], tile_ptr, K * CHUNK_K + SKEW_UINT8); + } + + wmma::mma_sync(c[i][j], a[i], b[j], c[i][j]); + } + } + } + + __syncthreads(); + } + + // Store the D fragments to shared memory. +#pragma unroll + for (int i = 0; i < WARP_COL_TILES; i++) { +#pragma unroll + for (int j = 0; j < WARP_ROW_TILES; j++) { +#pragma unroll + // Uniform, point-wise transformations of ALL fragment elements by ALL + // threads in the warp are well-defined even though element indices + // within fragment storage are not defined. + for (int t = 0; t < c[i][j].num_elements; t++) c[i][j].x[t] *= alpha; + + int *tile_ptr = shmem_warp_tile_ptr + i * SHMEM_STRIDE * K + j * N; + + wmma::store_matrix_sync(tile_ptr, c[i][j], SHMEM_STRIDE, C_LAYOUT); + } + } + + __syncthreads(); + + // Now that shared memory contains all the D tiles, stream them to global + // memory. + int *dst_gmem_warp_stream_ptr = &D[gmem_idx]; + +#pragma unroll + for (int i = 0; i < K; i++) { + *((int4 *)(dst_gmem_warp_stream_ptr + GLOBAL_MEM_STRIDE * i) + laneId) = + *((int4 *)(shmem_warp_stream_ptr + SHMEM_STRIDE * i) + laneId); + } + + __syncthreads(); + } +} + +// Performs an MxNxK GEMM (C=alpha*A*B + beta*C) assuming: +// 1) Matrices are packed in memory. +// 2) M, N and K are multiples of 16. +// 3) Neither A nor B are transposed. +// Note: This is a less performant version of the compute_gemm_imma kernel. It +// is designed for +// demonstration purposes only to show the CUDA WMMA API use without +// relying on availability of the shared memory. +__global__ void simple_wmma_gemm_imma(const uint8_t *a, const uint8_t *b, + const int *c, int *d, int m_ld, int n_ld, + int k_ld, int alpha, int beta) { + // Leading dimensions. Packed with no transpositions. + int lda = m_ld; + int ldb = k_ld; + int ldc = n_ld; + + // Tile using a 2D grid + int warpM = (blockIdx.x * blockDim.x + threadIdx.x) / warpSize; + int warpN = (blockIdx.y * blockDim.y + threadIdx.y); + + // Declare the fragments + wmma::fragment + a_frag; + wmma::fragment + b_frag; + wmma::fragment acc_frag; + wmma::fragment c_frag; + + wmma::fill_fragment(acc_frag, 0.0f); + + // Loop over k + for (int i = 0; i < k_ld; i += WMMA_K) { + int aCol = i; + int aRow = warpM * WMMA_M; + + int bCol = i; + int bRow = warpN * WMMA_N; + + // Bounds checking + if (aRow < m_ld && aCol < k_ld && bRow < k_ld && bCol < n_ld) { + // Load the inputs + wmma::load_matrix_sync(a_frag, a + aCol + aRow * lda, lda); + wmma::load_matrix_sync(b_frag, b + bCol + bRow * ldb, ldb); + + // Perform the matrix multiplication + wmma::mma_sync(acc_frag, a_frag, b_frag, acc_frag); + } + } + + // Load in the current value of c, scale it by beta, and add this our result + // scaled by alpha + int cCol = warpN * WMMA_N; + int cRow = warpM * WMMA_M; + + if (cRow < m_ld && cCol < n_ld) { + wmma::load_matrix_sync(c_frag, c + cCol + cRow * ldc, ldc, + wmma::mem_row_major); + + for (int i = 0; i < c_frag.num_elements; i++) { + c_frag.x[i] = alpha * acc_frag.x[i] + beta * c_frag.x[i]; + } + + // Store the output + wmma::store_matrix_sync(d + cCol + cRow * ldc, c_frag, ldc, + wmma::mem_row_major); + } +} + +__host__ void matMultiplyOnHost(uint8_t *A, uint8_t *B, int *C, int alpha, + int beta, int numARows, int numAColumns, + int numBRows, int numBColumns, int numCRows, + int numCColumns) { + for (int i = 0; i < numCRows; i++) { + for (int j = 0; j < numCColumns; j++) { + int temp = 0; + + for (int k = 0; k < numAColumns; k++) { + temp += A[i * numAColumns + k] * B[j * numBRows + k]; + } + + C[i * numCColumns + j] = temp * alpha + beta * C[i * numCColumns + j]; + } + } +} + +int main(int argc, char **argv) { + printf("Initializing...\n"); + + int dev = findCudaDevice(argc, (const char **)argv); + + cudaDeviceProp deviceProp; + checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev)); + + // Tensor cores require a GPU of Volta (SM72) architecture or higher. + if (deviceProp.major < 7 || (deviceProp.major <= 7 && deviceProp.minor < 2)) { + printf( + "immaTensorCoreGemm requires SM 7.2 or higher to use Tensor Cores. " + "Exiting...\n"); + exit(EXIT_WAIVED); + } + + printf("M: %d (%d x %d)\n", M_GLOBAL, M, M_TILES); + printf("N: %d (%d x %d)\n", N_GLOBAL, N, N_TILES); + printf("K: %d (%d x %d)\n", K_GLOBAL, K, K_TILES); + + uint8_t *A_h = NULL; + uint8_t *B_h = NULL; + int *C_h = NULL; +#if CPU_DEBUG + int *result_hD = NULL; + int *result_host = NULL; +#endif + + A_h = (uint8_t *)malloc(sizeof(uint8_t) * M_GLOBAL * K_GLOBAL); + B_h = (uint8_t *)malloc(sizeof(uint8_t) * K_GLOBAL * N_GLOBAL); + C_h = (int *)malloc(sizeof(int) * M_GLOBAL * N_GLOBAL); +#if CPU_DEBUG + result_hD = (int *)malloc(sizeof(int) * M_GLOBAL * N_GLOBAL); + result_host = (int *)malloc(sizeof(int) * M_GLOBAL * N_GLOBAL); +#endif + + uint8_t *A = NULL; + uint8_t *B = NULL; + int *C = NULL; + int *D = NULL; + + checkCudaErrors( + cudaMalloc(reinterpret_cast(&A), sizeof(uint8_t) * M_GLOBAL * K_GLOBAL)); + checkCudaErrors( + cudaMalloc(reinterpret_cast(&B), sizeof(uint8_t) * N_GLOBAL * K_GLOBAL)); + checkCudaErrors(cudaMalloc(reinterpret_cast(&C), sizeof(int) * M_GLOBAL * N_GLOBAL)); + checkCudaErrors(cudaMalloc(reinterpret_cast(&D), sizeof(int) * M_GLOBAL * N_GLOBAL)); + + assert(((unsigned long long)A) % 128 == 0); + assert(((unsigned long long)B) % 128 == 0); + assert(((unsigned long long)C) % 128 == 0); + assert(((unsigned long long)D) % 128 == 0); + + init_host_matrices(A_h, B_h, C_h); + + checkCudaErrors(cudaMemcpy(A, A_h, sizeof(uint8_t) * M_GLOBAL * K_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(B, B_h, sizeof(uint8_t) * N_GLOBAL * K_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(C, C_h, sizeof(int) * M_GLOBAL * N_GLOBAL, + cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemset(D, 0, sizeof(int) * M_GLOBAL * N_GLOBAL)); + + printf("Preparing data for GPU...\n"); + + assert(((unsigned long long)A) % 128 == 0); + assert(((unsigned long long)B) % 128 == 0); + assert(((unsigned long long)C) % 128 == 0); + assert(((unsigned long long)D) % 128 == 0); + + enum { + // Compute the right amount of shared memory to request. + // We need shared memory to hold per-CTA C and D matrix tiles, and to cache + // per-CTA chunks + // of the A and B matrices. Therefore, the right amount to request is the + // maximum of those + // two numbers. + SHMEM_SZ = MAX(sizeof(uint8_t) * (BLOCK_COL_TILES * M) * + (CHUNK_K * K + SKEW_UINT8) * 2, + M * (BLOCK_ROW_WARPS * WARP_ROW_TILES) * N * + (BLOCK_COL_WARPS * WARP_COL_TILES) * sizeof(int)) + }; + + printf("Required shared memory size: %lu Kb\n", SHMEM_SZ / 1024UL); + + int alpha = 1; + int beta = 1; + + cudaEvent_t start, stop; + + checkCudaErrors(cudaEventCreate(&start)); + checkCudaErrors(cudaEventCreate(&stop)); + checkCudaErrors(cudaEventRecord(start)); + + // If enough shared memory available on the GPU use high performant kernel + if (deviceProp.sharedMemPerMultiprocessor >= SHMEM_SZ) { + printf("Computing... using high performance kernel compute_gemm_imma \n"); + + checkCudaErrors(cudaFuncSetAttribute( + compute_gemm_imma, cudaFuncAttributeMaxDynamicSharedMemorySize, + SHMEM_SZ)); + checkKernelErrors( + (compute_gemm_imma<<>>(A, B, C, D, alpha, beta))); +#if CPU_DEBUG + checkCudaErrors(cudaMemcpy(result_hD, D, sizeof(int) * M_GLOBAL * N_GLOBAL, + cudaMemcpyDeviceToHost)); +#endif + } else { + dim3 gridDim; + dim3 blockDim; + + // blockDim.x must be a multiple of warpSize + // 128x4 means we have 16 warps and a block computes a 64x64 output tile + blockDim.x = 128; + blockDim.y = 4; + + gridDim.x = (M_GLOBAL + (WMMA_M * blockDim.x / 32 - 1)) / + (WMMA_M * blockDim.x / 32); + gridDim.y = (N_GLOBAL + WMMA_N * blockDim.y - 1) / (WMMA_N * blockDim.y); + + printf("Computing... using simple_wmma_gemm_imma kernel\n"); + simple_wmma_gemm_imma<<>>(A, B, C, D, M_GLOBAL, N_GLOBAL, + K_GLOBAL, alpha, beta); +#if CPU_DEBUG + checkCudaErrors(cudaMemcpy(result_hD, D, sizeof(int) * M_GLOBAL * N_GLOBAL, + cudaMemcpyDeviceToHost)); +#endif + } + + checkCudaErrors(cudaEventRecord(stop)); + checkCudaErrors(cudaEventSynchronize(stop)); + +#if CPU_DEBUG + printf("Verifying correctness of the computations...\n"); + + memcpy(result_host, C_h, sizeof(int) * M_GLOBAL * N_GLOBAL); + + matMultiplyOnHost(A_h, B_h, result_host, alpha, beta, M_GLOBAL, K_GLOBAL, + K_GLOBAL, N_GLOBAL, M_GLOBAL, N_GLOBAL); + + for (int i = 0; i < N_GLOBAL * M_GLOBAL; i++) { + if (abs(result_hD[i] - result_host[i]) > 0) { + printf("mismatch i=%d result_hD=%d result_host=%d\n", i, result_hD[i], + result_host[i]); + } + } + free(result_host); + free(result_hD); +#endif + + float milliseconds = 0; + + checkCudaErrors(cudaEventElapsedTime(&milliseconds, start, stop)); + + printf("Time: %f ms\n", milliseconds); + printf("TOPS: %.2f\n", (((double)M_GLOBAL * N_GLOBAL * K_GLOBAL * 2)/(milliseconds/1000.)) / 1e12); + + free(A_h); + free(B_h); + free(C_h); + checkCudaErrors(cudaFree(reinterpret_cast(A))); + checkCudaErrors(cudaFree(reinterpret_cast(B))); + checkCudaErrors(cudaFree(reinterpret_cast(C))); + checkCudaErrors(cudaFree(reinterpret_cast(D))); + + return EXIT_SUCCESS; +} diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.sln b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.sln new file mode 100644 index 00000000..fccd0a25 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "immaTensorCoreGemm", "immaTensorCoreGemm_vs2012.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.vcxproj b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.vcxproj new file mode 100644 index 00000000..d9a369da --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2012.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + immaTensorCoreGemm_vs2012 + immaTensorCoreGemm + + + + + Application + MultiByte + v110 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/immaTensorCoreGemm.exe + + + compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.sln b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.sln new file mode 100644 index 00000000..e389a707 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 13.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "immaTensorCoreGemm", "immaTensorCoreGemm_vs2013.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.vcxproj b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.vcxproj new file mode 100644 index 00000000..a4d88545 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2013.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + immaTensorCoreGemm_vs2013 + immaTensorCoreGemm + + + + + Application + MultiByte + v120 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/immaTensorCoreGemm.exe + + + compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.sln b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.sln new file mode 100644 index 00000000..b630ed5e --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "immaTensorCoreGemm", "immaTensorCoreGemm_vs2015.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.vcxproj b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.vcxproj new file mode 100644 index 00000000..e4a8b3e1 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2015.vcxproj @@ -0,0 +1,107 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + immaTensorCoreGemm_vs2015 + immaTensorCoreGemm + + + + + Application + MultiByte + v140 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/immaTensorCoreGemm.exe + + + compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.sln b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.sln new file mode 100644 index 00000000..5579f261 --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2017 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "immaTensorCoreGemm", "immaTensorCoreGemm_vs2017.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.vcxproj b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.vcxproj new file mode 100644 index 00000000..0c260dca --- /dev/null +++ b/Samples/immaTensorCoreGemm/immaTensorCoreGemm_vs2017.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + immaTensorCoreGemm_vs2017 + immaTensorCoreGemm + + + + + Application + MultiByte + v141 + 10.0.15063.0 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/immaTensorCoreGemm.exe + + + compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + diff --git a/Samples/matrixMul/Makefile b/Samples/matrixMul/Makefile index e5ade9c2..c4ab15e5 100644 --- a/Samples/matrixMul/Makefile +++ b/Samples/matrixMul/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/matrixMul/NsightEclipse.xml b/Samples/matrixMul/NsightEclipse.xml index 38ea6b03..364b84c1 100644 --- a/Samples/matrixMul/NsightEclipse.xml +++ b/Samples/matrixMul/NsightEclipse.xml @@ -46,6 +46,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/matrixMul/README.md b/Samples/matrixMul/README.md index ae3bdf71..36927ba4 100644 --- a/Samples/matrixMul/README.md +++ b/Samples/matrixMul/README.md @@ -10,7 +10,7 @@ CUDA Runtime API, Linear Algebra ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cudaEventCreate, cudaEventRecord, cudaEventQuery, cudaEventDestroy, cudaEventEla ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/matrixMul/matrixMul_vs2012.vcxproj b/Samples/matrixMul/matrixMul_vs2012.vcxproj index 10980117..365318d5 100644 --- a/Samples/matrixMul/matrixMul_vs2012.vcxproj +++ b/Samples/matrixMul/matrixMul_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/matrixMul/matrixMul_vs2013.vcxproj b/Samples/matrixMul/matrixMul_vs2013.vcxproj index fc8f1580..373420eb 100644 --- a/Samples/matrixMul/matrixMul_vs2013.vcxproj +++ b/Samples/matrixMul/matrixMul_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/matrixMul/matrixMul_vs2015.vcxproj b/Samples/matrixMul/matrixMul_vs2015.vcxproj index 135f764c..65f33412 100644 --- a/Samples/matrixMul/matrixMul_vs2015.vcxproj +++ b/Samples/matrixMul/matrixMul_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/matrixMul/matrixMul_vs2017.vcxproj b/Samples/matrixMul/matrixMul_vs2017.vcxproj index d145fa07..5b9e1e58 100644 --- a/Samples/matrixMul/matrixMul_vs2017.vcxproj +++ b/Samples/matrixMul/matrixMul_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/matrixMulDrv/README.md b/Samples/matrixMulDrv/README.md index e22bee66..5096f524 100644 --- a/Samples/matrixMulDrv/README.md +++ b/Samples/matrixMulDrv/README.md @@ -10,7 +10,7 @@ CUDA Driver API, Matrix Multiply ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cuModuleLoad, cuModuleLoadDataEx, cuModuleGetFunction, cuMemAlloc, cuMemFree, cu ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/matrixMulDrv/matrixMulDrv_vs2012.vcxproj b/Samples/matrixMulDrv/matrixMulDrv_vs2012.vcxproj index e13d4bad..51d15d5d 100644 --- a/Samples/matrixMulDrv/matrixMulDrv_vs2012.vcxproj +++ b/Samples/matrixMulDrv/matrixMulDrv_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -106,6 +106,6 @@ - + diff --git a/Samples/matrixMulDrv/matrixMulDrv_vs2013.vcxproj b/Samples/matrixMulDrv/matrixMulDrv_vs2013.vcxproj index 827374d7..ed0d8bee 100644 --- a/Samples/matrixMulDrv/matrixMulDrv_vs2013.vcxproj +++ b/Samples/matrixMulDrv/matrixMulDrv_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -106,6 +106,6 @@ - + diff --git a/Samples/matrixMulDrv/matrixMulDrv_vs2015.vcxproj b/Samples/matrixMulDrv/matrixMulDrv_vs2015.vcxproj index 6bff3567..638d1bb5 100644 --- a/Samples/matrixMulDrv/matrixMulDrv_vs2015.vcxproj +++ b/Samples/matrixMulDrv/matrixMulDrv_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -106,6 +106,6 @@ - + diff --git a/Samples/matrixMulDrv/matrixMulDrv_vs2017.vcxproj b/Samples/matrixMulDrv/matrixMulDrv_vs2017.vcxproj index bd5d4078..c04b3487 100644 --- a/Samples/matrixMulDrv/matrixMulDrv_vs2017.vcxproj +++ b/Samples/matrixMulDrv/matrixMulDrv_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -107,6 +107,6 @@ - + diff --git a/Samples/nvJPEG/Makefile b/Samples/nvJPEG/Makefile new file mode 100644 index 00000000..0d7452f3 --- /dev/null +++ b/Samples/nvJPEG/Makefile @@ -0,0 +1,301 @@ +################################################################################ +# Copyright (c) 2018, 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. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Location of the CUDA Toolkit +CUDA_PATH ?= /usr/local/cuda + +############################## +# start deprecated interface # +############################## +ifeq ($(x86_64),1) + $(info WARNING - x86_64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=x86_64 instead) + TARGET_ARCH ?= x86_64 +endif +ifeq ($(ARMv7),1) + $(info WARNING - ARMv7 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=armv7l instead) + TARGET_ARCH ?= armv7l +endif +ifeq ($(aarch64),1) + $(info WARNING - aarch64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=aarch64 instead) + TARGET_ARCH ?= aarch64 +endif +ifeq ($(ppc64le),1) + $(info WARNING - ppc64le variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=ppc64le instead) + TARGET_ARCH ?= ppc64le +endif +ifneq ($(GCC),) + $(info WARNING - GCC variable has been deprecated) + $(info WARNING - please use HOST_COMPILER=$(GCC) instead) + HOST_COMPILER ?= $(GCC) +endif +ifneq ($(abi),) + $(error ERROR - abi variable has been removed) +endif +############################ +# end deprecated interface # +############################ + +# architecture +HOST_ARCH := $(shell uname -m) +TARGET_ARCH ?= $(HOST_ARCH) +ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l)) + ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le)) + TARGET_SIZE := 64 + else ifneq (,$(filter $(TARGET_ARCH),armv7l)) + TARGET_SIZE := 32 + endif + else + TARGET_SIZE := $(shell getconf LONG_BIT) + endif +else + $(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!) +endif +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le)) + $(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!) + endif +endif + +# When on native aarch64 system with userspace of 32-bit, change TARGET_ARCH to armv7l +ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_SIZE),aarch64-aarch64-32) + TARGET_ARCH = armv7l +endif + +# operating system +HOST_OS := $(shell uname -s 2>/dev/null | tr "[:upper:]" "[:lower:]") +TARGET_OS ?= $(HOST_OS) +ifeq (,$(filter $(TARGET_OS),linux darwin qnx android)) + $(error ERROR - unsupported value $(TARGET_OS) for TARGET_OS!) +endif + +# host compiler +ifeq ($(TARGET_OS),darwin) + ifeq ($(shell expr `xcodebuild -version | grep -i xcode | awk '{print $$2}' | cut -d'.' -f1` \>= 5),1) + HOST_COMPILER ?= clang++ + endif +else ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(HOST_ARCH)-$(TARGET_ARCH),x86_64-armv7l) + ifeq ($(TARGET_OS),linux) + HOST_COMPILER ?= arm-linux-gnueabihf-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/arm-unknown-nto-qnx6.6.0eabi-g++ + else ifeq ($(TARGET_OS),android) + HOST_COMPILER ?= arm-linux-androideabi-g++ + endif + else ifeq ($(TARGET_ARCH),aarch64) + ifeq ($(TARGET_OS), linux) + HOST_COMPILER ?= aarch64-linux-gnu-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ + else ifeq ($(TARGET_OS), android) + HOST_COMPILER ?= aarch64-linux-android-clang++ + endif + else ifeq ($(TARGET_ARCH),ppc64le) + HOST_COMPILER ?= powerpc64le-linux-gnu-g++ + endif +endif +HOST_COMPILER ?= g++ +NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER) + +# internal flags +NVCCFLAGS := -m${TARGET_SIZE} +CCFLAGS := +LDFLAGS := + +# build flags +ifeq ($(TARGET_OS),darwin) + LDFLAGS += -rpath $(CUDA_PATH)/lib + CCFLAGS += -arch $(HOST_ARCH) +else ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_OS),x86_64-armv7l-linux) + LDFLAGS += --dynamic-linker=/lib/ld-linux-armhf.so.3 + CCFLAGS += -mfloat-abi=hard +else ifeq ($(TARGET_OS),android) + LDFLAGS += -pie + CCFLAGS += -fpie -fpic -fexceptions +endif + +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/arm-linux-gnueabihf + endif + endif + ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu + LDFLAGS += --unresolved-symbols=ignore-in-shared-libs + CCFLAGS += -isystem=$(TARGET_FS)/usr/include + CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu + endif + endif +endif + +ifeq ($(TARGET_OS),qnx) + CCFLAGS += -DWIN_INTERFACE_CUSTOM + LDFLAGS += -lsocket +endif + +# Install directory of different arch +CUDA_INSTALL_TARGET_DIR := +ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-qnx) + CUDA_INSTALL_TARGET_DIR = targets/ARMv7-linux-QNX/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-qnx/ +else ifeq ($(TARGET_ARCH),ppc64le) + CUDA_INSTALL_TARGET_DIR = targets/ppc64le-linux/ +endif + +# Debug build flags +ifeq ($(dbg),1) + NVCCFLAGS += -g -G + BUILD_TYPE := debug +else + BUILD_TYPE := release +endif + +ALL_CCFLAGS := +ALL_CCFLAGS += $(NVCCFLAGS) +ALL_CCFLAGS += $(EXTRA_NVCCFLAGS) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(CCFLAGS)) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) + +SAMPLE_ENABLED := 1 + +# This sample is not supported on Mac OSX +ifeq ($(TARGET_OS),darwin) + $(info >>> WARNING - nvJPEG is not supported on Mac OSX - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +# This sample is not supported on ARMv7 +ifeq ($(TARGET_ARCH),armv7l) + $(info >>> WARNING - nvJPEG is not supported on ARMv7 - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +# This sample is not supported on aarch64 +ifeq ($(TARGET_ARCH),aarch64) + $(info >>> WARNING - nvJPEG is not supported on aarch64 - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +ALL_LDFLAGS := +ALL_LDFLAGS += $(ALL_CCFLAGS) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(EXTRA_LDFLAGS)) + +# Common includes and paths for CUDA +INCLUDES := -I../../Common +LIBRARIES := + +################################################################################ + +LIBRARIES += -lnvjpeg + +ifeq ($(SAMPLE_ENABLED),0) +EXEC ?= @echo "[@]" +endif + +################################################################################ + +# Target rules +all: build + +build: nvJPEG + +check.deps: +ifeq ($(SAMPLE_ENABLED),0) + @echo "Sample will be waived due to the above missing dependencies" +else + @echo "Sample is ready - all dependencies have been met" +endif + +nvJPEG.o:nvJPEG.cpp + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +nvJPEG: nvJPEG.o + $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o $@ $+ $(LIBRARIES) + $(EXEC) mkdir -p ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + $(EXEC) cp $@ ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + +run: build + $(EXEC) ./nvJPEG + +clean: + rm -f nvJPEG nvJPEG.o + rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/nvJPEG + +clobber: clean diff --git a/Samples/nvJPEG/NsightEclipse.xml b/Samples/nvJPEG/NsightEclipse.xml new file mode 100644 index 00000000..1485c97b --- /dev/null +++ b/Samples/nvJPEG/NsightEclipse.xml @@ -0,0 +1,58 @@ + + + + nvJPEG + + whole + + ./ + ../ + ../../common/inc + + + Image Decoding + NVJPEG Library + + + NVJPEG + JPEG Decoding + + + nvjpeg + + + + true + nvJPEG.cpp + + -i ../../../../Samples/nvJPEG/images/ + + + NVJPEG + + + 1:CUDA Basic Topics + 3:JPEG Decoding + + sm30 + sm35 + sm37 + sm50 + sm52 + sm60 + sm61 + sm70 + sm72 + sm75 + + + x86_64 + linux + + + + 3.0 + + NVJPEG simple + exe + diff --git a/Samples/nvJPEG/README.md b/Samples/nvJPEG/README.md new file mode 100644 index 00000000..19454c31 --- /dev/null +++ b/Samples/nvJPEG/README.md @@ -0,0 +1,61 @@ +# nvJPEG - NVJPEG simple + +## Description + +A CUDA Sample that demonstrates single and batched decoding of jpeg images using NVJPEG Library. + +## Key Concepts + +Image Decoding, NVJPEG Library + +## Supported SM Architectures + +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) + +## Supported OSes + +Linux + +## Supported CPU Architecture + +x86_64 + +## CUDA APIs involved + +## Dependencies needed to build/run +[NVJPEG](../../README.md#nvjpeg) + +## Prerequisites + +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Make sure the dependencies mentioned in [Dependencies]() section above are installed. + +## Build and Run + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + +## References (for more details) + diff --git a/Samples/nvJPEG/images/img1.jpg b/Samples/nvJPEG/images/img1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7413faf057cc0dbf25f1fde917a4672c0995c623 GIT binary patch literal 67716 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 T^(0j literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/images/img3.jpg b/Samples/nvJPEG/images/img3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41b1d9b48b7b561e21ce9d9a13402f70f7b5d137 GIT binary patch literal 34914 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

$`Y}lQ_;f=; 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 literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/images/img5.jpg b/Samples/nvJPEG/images/img5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..148ccb41596f9876491cc4765a7363b700b7de36 GIT binary patch literal 81385 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

PGB19m&108CzS5mcV<9o-7y8sQbVc~_oFMqZa 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 E*}&ZirvLx| literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/images/img6.jpg b/Samples/nvJPEG/images/img6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a58ef7c5fb603ace2ecec05f276f7d31687e78a3 GIT binary patch literal 64806 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 K0yBZ$ga6qC4KJJk literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/images/img7.jpg b/Samples/nvJPEG/images/img7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f49d9122eeb657da82cc708c75bab610c6cafc2e GIT binary patch literal 94376 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 z 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�nn5*};_ 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 literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/images/img8.jpg b/Samples/nvJPEG/images/img8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab51a789be10e9f88f51787f057ff68df8325091 GIT binary patch literal 53180 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 Q)wIkJhsdLk1*J|O=^nG6h!SM0JWq_9 zM@K9T93fwb&pRZZxh<3!;Cq9_7|C+wYxMpCXzm`0)>e-}4CU{jx}+85?l^8sO1^Xv zN9(&}p#+10jg10yURo=Pf-xXL}DBjuo+=!h3p0d*Qgaxc1 zVet^-c#NP?@nnrDQ0#GLQ?hfiSCD!%NzItoaB|;8%Jr1XlOFq=(ON~1`FadBW9WbI zk83)eUAbBu9xBHZ=kRQm1PJDP`j?v6Om+yB>H3EfXKipq*{Nf_XH?krMvu|gc5@!L$ zEw7=QlQ;mCXLCTmY~;Lv+Mh0_7jtlE;3jfrRGsu&MDo~)>O^^|bV%8-FM|eqWZiO5 z?R2)Wr8NUXezVB*^QYp|*CQT0J@1Gr?K>q|;Ob8^fi@DFV^q&k+)OHvniB66BPD7* zVuYzP!%`bOV1{t>FJLJB)pqM4Lixd4!!>% z`3u>@2X#V)DYr!;(`l_tS|h|_b(=*)nUByleFskU>gqAiyY;lavEvDF^xBJkp@=T; zp&l8H90(WJ?|lpP@bHj?-6ftsom zlIGg6o+bHzu#c2fr5eCpQFM3;_toiEY~BP0qO?F575{)=DYb04oT8msQnzxaRxHLD zsziIm$!whQN9DI5xi;C?#J&@U%uq}A6QNXDW4aOH-YDx3+Jdf9S=E}DvMo#{XtvSO zR6p3!n;wy&S(3JypK!B?@nMh*IF=QEp(J!^I{_Dg`sT*SEqj)~b9#DlVH3zxR3xXu zh_tT=q_f|7L8`IXW7kCOlA5%0SEGtiGD<`as3?wouSW50;=V4^Q1L3#_oYH>wq{-! zBzE%`#IUPAG^hM#^_lwQHu{j*&v8!2cR}YhHZLil zT2j#pv)1X_>yQltG*kXgK*3U9AYjoZ4_q-tBa6?)b(9Vn-5v4mSr0Y#&;9Th5c|uT*Ko(s zAQZ7NF!rJkjQtcS7-vVf8Nn0T(nS;(!Q zA?WH*Yofe#gS);1{}>lzSF&JycB1+rmN0hQ=qx3Rt;WXs%Ot(u^`~BqPTv$ocN}?C z$9!8BdTkcleV@~gs;@gm>EdPRgPfZC)$4?f&3KM9B0pUJba}jrik*)-#jrJQ&g>AJ zT3r$J^ZXQV?cXnkzrp0Bp<+(6fykr z94dfEmpX}y$7U{7=EcTsH;MIc(#9nFo(4C;9dFFY;%;Gim6`=;sZysyJS`cUFg#*c zwB!N$5aRXRS%8r?m6dJ^V*u=21J5xEZW7ScCOM zT#BW)o%Mq1{Sp#Z;3_zN=H^pv(Rhuk>dM$8KUZeF<*p~x!ZGfnf4sTAvwlAIE2!*S zN1VhCYcjhZHS_kn|1LIzP=T_YwFk6`hYz**v!q%IQK(a+e^z<^|QG$mRt3W*t1)fymNP>e?nzhtLOyC{%42-s}r$nrM$aqnZ@R3b~t61 zKL8WtI7D%2ar2hVpww1@=D!b13M_GZLYQs`n0iVJ&~LjpnsY}i50P)m-!E~)=xlU$ z8*lkG@rqu^D78tSbm6)RFqUNvF!WY%{5Jk&iQ0iA>dqqCvqn`gF29ud3wc{EmvP1a z0w+AQC$J?9b4c54%&qmgyy0FEs^y{3?}{~>!y}eolVkBUzfyin)ay5Jw9H(w%)Ekl z=-qx2E$z%>9?TWF#{8Ce$I9}i=r?3hwXP)JmSa-YUtBo67{Su#c4u_p#7ub4bRK!u z`dNUpt7E!I#Dt;1-Q?32RHHKv%;pb zZ-QW6p`+g3oeCdL(TltCdm&S|x708XD~hIo+#uFu@f#`d`-g*r(XMMyjbM=$S%Qqh zt1vS7JN*Jq-(!5OaG`S*7tBxr{iNy@zK#Gmy;DWFIx zM_2y^QC@wXd_NTr};uWI&xN)OqBnW-_sw5O=dwR>S^O ztGcH~GI|6!6yq=wC;b=TCI1=*x6fr`ivF#e5~C=dv6!9vpxf)Uy@Xruk~LD}Wm6fN z-uw2v>N)M@lQKgEUjJ;pkDT9bY2J=mf||`u<2`V5O5~ z7N&kzkHD7wXf}`T0G@sTN)#~6FBlh1u(T~=Qkq)!wCG(32RQD?Dz<TG;Luj^IOyPO z)84FAPAq-gw)v(YjX#~gx@G?O)q3)W68v~B_>(MH^-oEznJN}-304NeqT9Jj<8YeN zuuJ+fx$Rj}<~z>t>{A0MTe9N&4vhZ9g1-Qn1nqN4%nF6bKCH}4wd5ei#J4p-PC{pr ze63kc?wpW(8L9Ashmum!(GgY@23rFGkf7tv_m-P_I+tczvirEaSp)r2WV zM$(;?;K-@VtDKCaiEq@~Pk0>L{s zFL5XiGoK8jSm`%Uzu;S2*$(7%P!Jsc$wuF-pHzhYB7Juyk$3eaPB5L$73oWaQ-vIVotHv;Ni{4L#6lH!Y8~mpviO{ffupXd=^ndV>}%UVr(J z{};e_SN)&PewEkziNlE}^|_tuJ!s0cP?;4tX4dYh9B_VY0+PR@muY6cZnnp6=JvIa!yJ8jTg3ADq(cn^rNKf`#2qp zz=?tX^xd0TG`Na?dr~LF(;s1E2NUOa92$xlbjkDoG+6N3Pi7hZnlh4TtvVO6e)xIqm-yF{gGMWs!GyuA z*Eaw&G+#FBA@^2N#aB_w;Qvq+ccxpst?ibyrQSZcVa)z_OjWY4l@^bzG1`I(cyj7y|BvNyk|G<&z66g%~E@Kd@rIHJsU=&KZs+J6oJyZKaRTW;Qm|v`XL?KM8V1l0`@0^ zS62T36x+oBRnsDk%L2}fLmXnVMzwb@nItZ_QSG1K{{U6;HI<`4 z+rEOCf>R*NGXQu2O=tLX1e;fdwC^1C@s(q^^Vr#h+MSltv*i&x6}Kc zYK!p=6NOU2dIP&B=S)n<1aY;;IN@{C?OIG{$rV~21duY43OOEC4b$t|uk9m`e10U7 z22q@*a1Xz&XRRI~A@E2%_in#>Z}H5M6%wFgKP+I9ezY~BPY3T_EBl7tBp|K{<7qy? zbfH0Js=*dAbH+=5nfX$dxlN_kQds8zXCvuPw5BBvHm-BQRR`yuw35P`E%eJ6BXhFe zNiIR@A;OP-4l3w;IcKS1o;8j5R#hOV_9Hy~>oKQZ%X2!izm#UBb5G z0MH#SEtm0DTjW;i2;IBar$b)4OPSzV_L8hK@}(?o3%rD`4Mk)z^fVS`9c!7%=Cm^! zYo{xNOYURI=D0{Bt#}*^3IMXQk9!YF(c7#ss+^40N*US`Ij3X0l0p}E6%{&M)*AzT z95LZrk}8sTro5c_iBf7XL%Bg`t1C8Cd~jHHDnE$Tos%@+oeWM&;s(Yb0J6 zClzTFut=CVtlQGk!3DXK9D`0ncmNrx6h_VfsGD>mq-W(fW@D8FivIvIis*^nFm~X2 zcc#`HsaWG=Q`61K`c;*lop~|@g4e`%IPn?0qu({(RFTgz*;xga{2nkmLv8+=$jmr`^Bn|~W zvP(1q1dkzb%y(z?rQx)iYlz|&^2sEeA`#1D&{o6YKZ0+yY1(^>$n9Z9*w*O#q(0t* z_v=fN=6hiiPtl*V(6t?6c!F+ASxF5$@Bjy&nf4X+-6>ob078@nG< z`UT*lvf@rEhf28aS3TM<4~r47fE^Cb!bd?2!?H;Xwx#q4;|0=T>QM zWhAPAhbo{dWNvtZ!{MB5Pu(vsW0uJ11yo8EF)O<()z{&Xi+E^uM1+Hrx3y=cvv;0i;g}g+GJO?s z$JFELUrI)TZB`eV6~75=N!l_?o<@E6p*O?P3uT@~UKhj!lb`h;-n3l4JrLtho~6ab zj+G$5MqfEnGq@fP*MU~LKA^)&wwYKLVZRN|*7P4g-mT#HZf!zQb8z9Kc?3wic-w=L zM{LsTpfq<0X$pmb12*H>t}%c=^5^JlPbp-nXtRr2Lx2|{l$?69umBVF&&r&&J_<&L zW>Xpfan3>i00mV^@cqW0ZVJ1p#$G})S9Sov?!a;LBAd3;ZoGAUyA?13I~QPYzIg+lj~+z^Su%QYR|prvs=Sl$;Xmftf;i20811I{j$kNh6DC2!&7+ z!7cLk?f0zBMlG+}2j3Ik^^TXbu=@JnYWJw|?Ahu()I zlSLW)ENkJbW$-v(KzJN??a!_$>kf?`p>qY~mavdYtjm#~f7+7x&r`C~bUB3bFphGm zu`#)apsK5QZf-Wo;-QgPlDXtyj=sLX)~J3fNpGKQ$XOKep1(e5mE~QE>la2hUDX>^ z)P&0zf*90C6iRXtNA;}z@gne}@{9o-Rh-d;xsiJ-5mfqw%Pr4RLX1~;AG3#%@3DCy zMPj>$sL1LlLNYo7lTA)TqP_v=*PKv#^f}4RZekA$fu7aiL%7J}rFh`vWOeIP0YZYg z>qrLFD=(OliX>6H5UaR?I-Y`nj2wUz4k`3f2n{DK#yXSpsbfeiHpW6W$D9y1lbny8 zUBRMDEG(wq^9&8o)Svu%;N@R$Y100hAK^ZwOq{{Z98@knBeaXlj}GJVgr zSjHk-wV3|^6U&|bbM2m|p8o)9v$c&($`&}m$1foTz4AZ56rHiCMn>O8VkJb~!O3tA z0rn>XtL|;2GYAq^Wnav^Hcz?dHT4VF?W0Ioq82Jb#>~M-a!3GHQt|99?y(w2_=g^0 z6nO*gb4^>pIVvFWp@1+dia1acllK%@wOf-u$S%vW zRW}p(Eaha`<>#CO>@WG`D~$aBsm&yE9LT^rbI2r-Ng!;Ez04t=H}DJu`I(UUPq^pqD#|Na?p*>4V{Av3 zMci?Zu+Ls=IBwN147Tq6862+SKiajL72FWPyeoN*=Z`rGJwOz#KZ2o}D-9k+2ggVm zNc`JzpH1BJ^RHZ3$)`;rfLkOkL1iP%hrh8DoZ8fJ+wY1%oDHGL+QZ+tsx4#UxmMKp zIAs75GJL-y-~Fp4G+&Yz*R<)PFCz{CB(Y7P`vcynapC@9jM3%zg6~p~Y^4Nv>(3tf zAJ(`GGg_*){xU2Tj>#YlSYF2M35cFnyObUd8QP1sd7@Ib*0@2BLSMN1e;Hg=CL|e z;YJF^wsts`GhEj=&WU=97_P!En9%3dqd|aqpgoJbb>g^m)bG}%VMpg{H|KP(wGMF^ z>T6e{>lW>8zTkL17JMWbIUIAxa(!zr44a5=3GE9kM!V`XZyA@LL_W$E9!#wwfQCep7YL8zn>gy_8PCp|bkkDX>O zb$M@CtYjo7-ODn`9>jbGBl8iSn5m~T+b&fIia3$F7*z_YL2+Z59wOldvSNC#DSGD!vehl z1Q0%yON{_(H}RDxs3!yW`&W&$+I_=9tPUR-YTCP6N_g;ZO|wf)HZjbb0VTaaCm255 zRTMF#x~jz(;bbQYa&w&h`c|V&fQxSoju>Z-$2`*7W|nPrNv4E#kKgF5eURxNqtG zsQZT(cw2HZv4NatsXn!tyVhWe z@!A`cB9qP^gX@kd+g(O0s5h%iA#9B289wK*tMO#&FRlI|Smcst1S#i`Kfzf)i2fyc z8P*h0yYiAb9k`@!uA#S{U99rRI|4xYW~lB=lb!BVk-#c)0QuIj33g?5@Fjd-!Nz$# zO;Mb)V;Lf^wNoX$Xh0iC+H=lx+Nl-D0f5iY#P!70AjI5G6u{5 zf2scfF5ylsQeQ-}Fr#zZM`smxj?;yhC8OHZ!Kj+G| zEvJi=ca>f;7dhjPsqgaXRsR5mOM+YmAOJJBXvhBmZ|z*k_HN9DkP}`wZxz}6?$RJp zk3c~u`c>RPa({+Z0P=!)Kcz~2DqP7eyWp=rF=E6X;AeqK+D1j-5dI~%cXr6feoh5j zVn|m}j_u)+Q*|709&?kG9_KZhj>c96t(it9U#9g`{vB3alDQyYl= zG54t5+gi1=xK#!*hK`R*Mnl3c|LBRoNe93quJLIwf$G_2Fdd2r7XgitfNlz_+UOhs{prnwFP zFUDINv-PWh1)_#75eUW*0fX&CvA9SeAxvspk4${A{VEqXP9xhK%7u?dJ%2(z^Z+TR zmUu*F>6urdcEQL003rQqp_hHhjHsF!tGKrOOgAIwbzPhLHsz(EN~UZK<6~;D@Iy3O}vZ{a5L&TrKY({ zdA3ZY6!U?C5BcdxdJbqeY?sQrzfAmg7(411@}|#F zS)!Tw=`K8XJD41hIl#fK&%%EJ-)g~cZy`4NcpJxw`P?7$f%~34Gfrq<59wL}TfI^U zZm(CEp&oTlLjI@Qp!cgg{{V=uu9IrKk*+rFL64RXwQb4B>-CO|ibj2=R$>_nlXLdmMske(92V*IHxCOWe=iavTW-zO? z;bd(30h%N>HxpefY#KEFXFO(yXL5?9;|Kjf_4gj%t!cD*;gA>+!YClH9r*S2ta&M= z(YGA0lE+WbtgPYQ;LH~}VZr))^s7jWNIZz>tURj22P4-VC~-#H8^esp9!3KZ&U*3M zh|#N=2pgS&=O>?-`BxP;r&Oelg`Fkw7#CLL0!b&+ueCX2bXMiv2H^Z{BWcK}EJ0Bt zJ(nag?e9_Y!?i=Ikas5DoqPAqCGSO8)(+}g1&*|;&W1VHo#TcdQB^u-ffkAJ6oGDL zm7d*+4Kj%vNo~?Hko`)+&>*iiD?kgMckHOa0 z%Y4`Hkvq%cWc3;3eT8WbXSxS1p-8?E@I+TKUtL^E%nR(0g*@i~^*=h(9X1rVOFLQR zONJgu%!SIITpok39St7W;2Udr{6G1f@sa`@ zt*YD&OZt_=;agiRyk0}d0**U&3je4c+4;( z4cS(5;9|aWtlOB$3hvH-nYuCi*0cSzHL2{xU+J$DrJ>%;I}W+`t1UlKhSyJM9(giX zJ5^3W{*?0R(imOJvyPj&{*`lKrXxnXL?H_DT{+L`T@RDs#Yf3OZ49^NT4?+`eC-^S z-H+ci?C{HRB5uJT?Nvd*9@T8n#WeBwO%o(%1Y?~04wP%8hSiabZ1_8iZXlm(m0HSk zh9lz3ac>+T#>h`X>@oBo*0V67EDqD{SHBWpKBK9f@ho^80^5kBVqXX;8(3$aYp!~e zlDlM~MkAaPk4^& za>omJdD>hdz&_omnr57CL+s^%Jf4H=TP+-@+n$Gz%(QzB> zYTMyhts=LcH8?mSgnP12ecdzdR%rJYSAHJ`F^6_`U@#A+2fa6=Y9ec9j7O8ajlsDi zsKx=s72LJRF@|!=$jqz?f!lURA1dT@{!WCFT^12tt=P-mO>lT3IM-^A{JsAG+oc`} z5-{l zdE!$nnByxN#!t^2{-&v7w~|BSMw1o|`Q1n*et5?pDtzir@IFH@Y-a~=*N$m>+lV2z zJ9nh4xmlbBC)+upE$CZ^u62ikGb_qfc*L&!A7D8CwMnUKiz04G8Kf(n$o!vtcdC2Y zShd3!h%09!aRi^Y_NL&PNVXzv z4*cPVLF?&DOAXU_!A{eB)M*xHA*wS$js~fRlDLl!-k}=obkh#2(ZrKwo7>^TSz~{L1 zpbHzz-1w5f>Qexw4sE~i=iJ%DxN`_XJ{gj>v`48!u0NA1*mifxggRl6uq z9vDaF8SDP^hC68^z>63uhdA6%l=1ld01 z1F>uaRa4DxB&=5<^U8oQK3MHlESg_O1N-!+Z0{t2)uTNsycHdK8Z2iAgT+%srqT56 z6IF)t-B)n&amcGiyAkj*YvmTV(%ViNER1&*x6yCS=b7AObVwMW10))@Gs7R*F_2u2Ar~RYj9DZQg`f zU}ObV@It8ru18bby*d=cOq&A}&;z$<_w}x8N z!_PcNo^}ujA8Hhis=&OUh{$cDu5riT(ybwNnjq?1b~z1^kEL9$%&wY1WXZS383P=2 ztcBz)`12kyv}BNdO>JKXjlhxEdR955FR$DqbBVE!VO8Sli{Y$HX6iJv(_=;jWp>XU zvF}+;Lhr+H>Tt??*1zHz;P3!kZcoy_X*J@>e#+eEfDLI=mCQc?Sk7WLVEg|%X=O7ICkSK0Bzj$Tz2{P zq+~@^IZe?4hQ~W|#|N5zbR`Ulu(3QG^N(-sS>1MKx3xH$K!9TaWR*|YXBG3^OHsJFx^Zu7Aq4(nD%y0G{$0|ux$U{htBn)k_*!u#!QIHhV>zvt z>Mvz2mZ0|bra5h;G6B(gpKO!Tfg~5YgLsBBZ3r18wtr#GeLh_}&e{_4qv z>XO=Mx@j$eBMzWv{Q6hSH9N`g<|~k~6X}7Et#olt_F>6i0u3+x!grO>#gmfckp8Hvvs{$D{yh>0(hM=3s1o0V`7k^jKfsjUmTnAD-$FM))tEjBwxiM~cEHWIjV{(p|BO5{W?^Rl+mlSuA zJP9HPY%1WKAL>2m)Wa~<#R|QNMu`NQPQw@+Fz0FM*XdRFcJ|jgQeDL%GN{0E2`G9V zKc~GrrCdDLfn-ql$}q{xe`8BuMq(4BQV7tTc?cXH;{!SN=}R#o>79y6p6WD=XQ*}n zscd(~eQ27Egm*UJC-B=mhCJuE!@+M^!cwXW0TiqOV5)Q(>(A>{Neh;e z;#>%%M?;3m$OGH_=9oxU3u0yBWiG61mwb zxg6sMu^IdDX^8b1EhdUn8W@z2QaJJIF^us}D#bKX!Xrmqc%nxn9l+=1{jw?>!qPKh zJBx|LZRHJ|Cr+O#I@#}w%8X@Ek^t(z?OMa7+C!U`j2{_GoxO586(7^RQe4~k(fE)V z5#4bPkLTsa#5EG!AQaR=QL$z3&jDVFA~iogpg!&+|;1C10lgZvPEj1 znY1$-I;lN=bzy0JHMz>MUtAuvh$`pWjHPlZ=7}>&YpzP_6mwU)ak#kvxHvuQ6KKK< zfcVPikzYvCq_%5CkqB-$0ot^OaD zcU`DK=NTEt%+{L6;g*U-7dZ+OaRD;FFP(DNDn|3h*^-Y=H*6haW*((UQCh7#;Xej1 z5QcM&+dJpJMQI_^7Tz>41Xev591m=YV`qj8L^O^+GbkA+uiKjCu4O4I88^2Dc6th9TNK-NFPNTaM=zEHIEf{zI z0J*z)8%|dp2l~44U4?uoge~Y-F z7Ky_ozl&YhF_lh{k&}U+IXwJ;tB5X`BBI1L=dOEt)mlp&O}<72wtz^$eGwM$(( z+9)Fc4=Mmp%=fN^EiV0+%gZhPs}MVTSTyJxCkUgGMFqsOO|c@BD<BOg&-D7%f>w;K1-mxyHuBq+m14GPwC$e-CVHQ3HxXK`&Q-+15UEp;O>y9 z=NyCjRjG|_?N~rj6phV=8ToU-tzRd?Gw}N}QRybpJpLR^2bxDbDEsEK-woe%MiZ!IDtP&Kr0%W%023gLT(gDG5w?5(05HY?`BIyD6)O*& z*y&(OH^y;|+qYxujOXuHHrKP-xplyL3G(KNih52b$6;Nl3Qb z6O3hf`R1W>rOz#p@N*oIkU&v}`X1t}^qnG7#(6xFsK(&gQYw1ptN06Yw(%=Tj1!zz zicH%u+P0etFrMv)jgC=QAc5Z<&QE&E>KBm-9hM7^K0`SjLH__cRgSCiMC~&r-J=92 zrV0IeQmcJ$G7ZC#%Eyp1o}7PL)>au;WhuW=+n zi+w)UkJ+K*?YX{d|}0#6tNrg=F1s=SHu(=;v8dv}s4)PTdpLfnCl zxc2s_C8o=*tsx*_5uA=kzkl|ve0p}3J1~kkm6$T1Y>a?#Iqox6_qr{j#{0oLs3X(vDcNjfk``$4@*?eZ z95MN+?mA|Rrs;PVSFy}sl_Z3RVS)(Y1J8UP(AKsM21zj~Bk`sX#$Lqq#(nracdXr{ z%23ar9~OBOVcA#!c*g8>C(!%)^{suSj6k7zo-oUt4^hT*`uzx_Txho~;&_Y%tGESa z0VO!fpInd#`TNx=*BaeaDjyAS?)b?ezcS;o&P7XpUW!XSm$&lx5dewcvtWhBS8ht2 zdSkcH8lnkvXK>J5sbrQQcZdFL@JH?S_N%tnppqGY!GUs0;BE}SboRje)m`?eE*W4u z3%djZjB&|7Ub&?@RbiRCxLH-vm6W5G2h{%nnW0;d>AL{tosl6%A+YQTS5w?}Kebk> z{u)PB$&YuJ}haa~i-HK7BMI-e_b?N^#Etu2J!8=S&VIqg}n z-flY4lW|fDkZ+>jR+uy@1L4EYI8xrD9C7X{X)(B4d6wEpfPX6N#_xW40Oq_S)@1O_ER(o)c3&bzlk79v zp0z5H2`;3}r^+z69-IL}Ys(uIL<&>Q`4`r>*AF$pHsMNvmC42rL!K#NBTO=pBLmMHnWCD@d|O zxeBvqI~#aDi3n+D0D?mBNL=>MT3wnED(^X)7-r>( zA2ZwSRh<%b#IhG*Aq}0O*Ej>OLH44@AL1?c$%B!|VV|G)DJiuWRaJ8g1c)NJGh_>n=w00=(0 z?OUsBp?LhCNxYfjRogqB4;b%D+FOh1!%Hbr2RlzBihauLQH3f%8;5%BrMfl8ix-u1 z$f0s;E5{H?bic!4<6Iy)FrHfSjtY)3#sa@$Tg^gL3WtsHva%aS9W?l zHs8t#sY(16?IN2?(PM;oj-2)fwJE9;1(inTJy4I<%#RRf{pw`zjR*D9f~RXVUfxc8$&c=1gXj#!Yyk27(OgWIX6X0!2b z43YS8I6S89?wR%HijJqJrJ;HE?E}oG1a2Mr)`{=4HktHo3*rZrAPjkyJdShCTwdKv za{z3(1mNv8fzWOQb6a78s2i8KU_1WezLOobyF#)Cz<)8p@7kr5im|5&7)Vte#sL`T z6!pG|Zo6(30^`iMJc@47Ad-I+ZdU*d4=Cf>i+QYA!c1N$E!=_9qt|8oc#3^rQoV{F z2F#==ILYf-iLGvKST)to=5vjskJhwzx0Y>_Bkf=2Eyg?57NZzO62#AfI0W;Kybj&J z&avj%egIoZu|!iQB`1Km$?J}_SAFnpf;_Us9a$J3n~~ep{?$)&uUuJO7h?wxyLBZ4U#5wBCxsBKi`TwE+sG&8IHfFXrc1a13lH-vZQalgdj6uVH0!&099lC3GB}nt zZgAiL@t?M8uJ1}|r6%1%0)e>fNYCylx^=TJgz|v$tM3Q-i-V8qD@W*s?A}`H4IHRM zJ}gRA7YC{~N6&-18T2F4tSt3dmeIuVf_AC`jk^Q`&JS?FjC`vh1(b>!OL=4^_)Q0k~&op3H0~Kh7d88}m?NeF& z;DsdD09<=iqCkg^MJ9%Q`r-^ZyQU3J$#-2elFv;L==sO-O zm-E0tnFB7~2`6_yDqnibx@0V=yOZ1xZ|zJymQ&s$_+mZFw}1#Ej-4tH&MpB|iH9UJ zvgfDHiET2mj0P@Po>&dIrf+R_vi=fSq(=?nZYMeIw;d{`8%>#2B=7_gK^*Ss9{E^f zE(pNy+Z48SxgpkV8BXwq#cb4tWeYC+WvN^&NBLS!}KU01sC&Cl|mK|=+f zX~sPXqizK42d4(4upvi?**Q=*W7ed>R%cZ{3t>#vYje&fe^X>lB#0@NWDu4o+>7JiD&U_21!*gKPdBerZgMfCQU_EPJ z7{u7xNTrQ2??v2v#yRa%#X=nTV?Ah<=|b5&=j`UtJ6EfY+eT}O;f6t}tWN{8jxx2H z*I|8(+>Q)e_`BLdM<}@-#)CSuv&l2Yk%N-i%MV~rPo*>>gjE2~>V z*^eAyv)esJIOiVJgk>7yM|G7>cPes7KBGL6efak6TP?#UnkRFqP92ik7hDWuZq`ws zPw!T?*TYk=@Z=JBjTRdqVTkH#FKuB8w35XONI)vA4*vl6KD3l~OAe&gVYUPZ{+{iUuX|kO08?o;z35 zbbB(^qf${RMMhv!Z%O&2?}2rIp-~O0xJ-aIMrg z$bA0ilhU}C_b+i7Wpc;!DQ; z3>X|76^{U%{QRTqPHTPvqL%K;*HMjkk-A3lH~SNe{Z9kdtEJGRlY1Z~l{fHtAaFl_ z*0d>cX0a^6e~BR>HuNNLFg=eelX(nf)tpbT62S8>Vr-~c|gqN6t_&hGSk%Ty{O z-nkjU;B~*W9H_^m1D~H-r+qF_Gmsl`lb@zWe$+@owB}SLlon=QNCzLU z1Mgb1Gj9f@BeJ%*wm^JoJWzwS0m%IUs;`J0WR-TI@cM?&Qciz*MCy|n{0JFiiZlQ# zautX;`tmuWiByAcGZqIV9AuAQ*qVf}rp(fK^UQL`C5d8s`eL*iO{`Ndhbst!x}yg^ zVgWrp`d61sm7OJtSjDx;D!3<{f%oU>PieNggjl%|s1TADfDb1feR(J8MNmwS+-NI2 z4H+NAkqa;!spkhigQh-}OLy?t&#OVOjc^1mgQlOyVBqOUebo#41AH>k&t}| z{XwJ!yn&?TVSg#?*yH^9R=PVkgG!zm0+o+yFmFxRCyz}1s*39J2+CW*(OM^1e2&Bs(3t$?N@Q{7!Tb7t z_3T@p;I`Q0X7Yo{W7wauu0~8S5b@-KBLYK>iaH#6oKa(il{{D%#OFNlQL)WD7M_i! zm?(*Z%E0;fB}cIwQ?Lgzpq#GZ`9K^K{b_3`rpgH-2_82#cLS4GBHXsq8mS68lgJd( z*M@aib~|Z2Qu1vZPaB6B`PL)i--~y|$!h-q#wDT!Na1n$zFEa7tbBDf)xM#nP2s_N zZ6J&VCk~z2NIda_gVWy?g^-yfQJjH{lidFRYU*<`vP@RDteo>pJjOyW9g8;J)i_Sn z!0C*AXbP>4x#zAiLW<}y9vDBw2M?Z@rG*wqF^L@Y7~77OIO8KP)RD-~8SP73vGCXh zF2|^2(~RPri6n4)9087kp_E0UMcOfwvVkiolLM2C;+=HC$si~k=99P{R>v9kq`j0g z@b#Kt)?q{N)y_dMj+)xRGcFfG#D291VP<0BtB{Pn6`%^DR~+D8q8irD-L zbunN}v$NVaA~|x(epx(yD_WGN$eDfkpHg3n%Hz!pfcMVd(yZ)$A%gL?bZ?$(AfnxX z5?ch%`bQM~jBrIR_{b!B8kyyzWf&~V#OL~cmCa+~NVLe_)d&X|3%H-ucB*SIvBoBs^U2R&Ha=dJaV%9sZ0apb z$iNoq{J?zG0-b`{MKsfjI=A)+Rl3y^6RK^eHIpF$m zdizu~%S)sp>TI*OJDIX`^8WR#(}zN`N8)1{9Wm=q&?TmqM$+MiDC1OJ>N#w3O>3>~ ztPW%}q^rg5r+4GAXHQra-FpZHsh{ySHl0KmGS0_rA zNKAi-lgeW;fyVy;DgDbat4&kk`1~o2yA_gc&E*`N_WFzp%G_%Ac7h0}4)QGKcXE0F zqyRpERrg+n>)B~>pv`>o8IYAwSmU5M&+0Musww^*)pXgUn%R#fasL3vckNoOKUxe~ zgGlj~@CuHA;ZA>CeQQZ}VV)@`w>#Nz|8d4Z#Fyu7n8*`DLDJS|?9xoEwK(a){F5%a% z2XC+MTTVXA>r*vW@%}1nap7PRz~`OEZ>P^cYHIgL7S;;>7%VNoeE$Hep5Nz6W8pX! zOHpv{##r|{mgi^k;CuD`D$C*sk#vco$zKjN0D>}ozWAth*wplV=IYKtG>AOWhE{wK zGFLd~OdcS^YyQvY69-t zRf=4*qU}43wo1Grk6%0>Ic0k8HeKzq}a($Y>mDRna!$EB(#c49+ z9FjpJZ_}vjOwJ5?ax|bfh}#L^w&Fm8JFwX$}25GxX zyKO^GmfmDz;mEAt>RcZ%`XAiV?=)s>NSIuiqmfKWZ11^WsmKaf=u~6od(!&0mu~aN zBNbdpwCz#==O+Wd<{v{^ShUqQ6HA3KnH`;!o*NsN<_%~b-l3civ!^t87u@(e{9mwfSGAi78QZXYCP5{W`zoD-IBh_q!FXC-x@mM1Q zS7|0E*!Y(+kC6HC zT~wG{U^hQ}e}ng_WnNQ`G0DvlGFok{Mn!1E5=jo`RYJi4$sVSs_-K*DLjVlz8Rs6g z1Oh8oj4lq+NgSV@b54p$t{zzdSoi~XQ-S+uCZUY7w?t4fF`pnFxE#}`kZ=ak&mHMp z?wT?Nc=`dwHW&D82{`o?ofLtEa=VBlw+E@D??;q_%8qgJs{o)3DLEs#=~dc+3Z!yH zCG4XmG=Gf0NHLwxEA3h)iTFzh)er(y9PPmAUn}@$O_Nsmy3PpOZe;UdaXBRQa8hLse z%FK1iCAf;zsw$r=liS+9hj0?=G9(!tuyIwgTSS>C5A~^Yg{u2LZ2Br$vrly1B_slKTgac^a0b}Eb< zWx4N~^fGErxB@todV<}5&bh9G5U^;oG&UA=44@?^W4_cMfgiivW!W+o!sX)ojxy9UZe zfD8p2xcb%_>6>OBO|rG{KmdD_R*HBTtoOs(!s=-(ioujfLgW2BWAv-wdR4BBIX6zo z10e^dD;x19gd0q_Xt+Kfl#Z%t5+v zl3Nujv6V%^z$E08{{Z_?lA~7KpJg|;?G|Oh-cKWrP60nG58AMw5bcWQY2=JFEtOmx zU;sh;ng*AyH1UMa{38Tx_Z>f>rZ3@^>N6axk+3@v*qoY5d|3Ro9nz$=X;36(OmE^7 zyx_Sx`s0ez>GzW*w5>087zct7Wc};qUM9l6avk zNb!V@r=0FM`*10{c8|oEBtR&W053TMkKTo;TD#0u#?8B1%faWU`3e`Xeu`GpMx$7FyGaksC}r4vDjX~ymlyMxAAPB=Lj&N~d$x2S1$ zJ$V9L+qJPHz-8EE-OA&EkJI(43r#${3B#dD@cwTw>Hs6#7^_RWh+~Pa*zHxqN#)?M z;F0UxVymsL(%)COw2{QGy@oN!AmkJDAFT_}Gq#rx5*u(>%B$iKryw>~#KgQv+(KGmVUy0o&5yl{Nzd?`Tu-}wHgp5I!}-#{bOCbyKR z5g!gdak<&^*X8ImTABq**!yu_F$Ou0^f{kucFzFShVQ9z?F~KJ!d5Hf2<@-^ghBEG3 zcDN!P!0tbroR4~pY`d~f1}K`mG27k+MB1ftnc(9jf3+(c4=*?*^flWrqmq|r=u3GP zNk@mskxG`?j0}49qND;SWWwz~>I1HNX1G=f6e|spWMgX_oF1Hh)XXq}F(H4Hk-_Qn z&3Kr44S=8SV0`jnXTyvQ8kkxM`1twQ>nO5G&?7{{Y1)ab=4#;Vw5Tf_eZ*Ao{mMo|rWs zjQ%f{>AwkNf-=0bqvv>K>F6<&pQT}=X%5gwBZG|LM{a9)jP_>PCvW5Q!(?(jan_xT zos9hn0|JqCZxbMA7}}@zrlNhtM>r>()_`_35#M@>4Nv&=3GOb%8&b@}GG{!QT|kD4X>kjm%Gv`Kz0HjrXT20-J~)_YxfY&9#Q z#D*(``I^jTTc!;wF(aYJO4?z26Q}6#$j=Q5?<5!)?btm5R3h4LlMS_^(vC zXhatJag+nQbDXaoGCG>T>N=LCay&VND0BJ9+5!3h0BW|?J|%msfo~^1t&EDS{8SPI z4{ghEa-ieoT@atjF}A%TpqSB@#nk{KrqunZn^R~XYw9xK;DsarKHu7`&Yun0CIXR; z#X$bF70_->-^93$VlW4@!Ic#4z*HPB zzqzky>uqUi98l+ZP)Ru4-%8M0vt))s$&3;0SkpF?A@I(ta2xQq{!@*h2i$X?tx74Dp9I<) zTLmmINgc7+59wP1*sAD!2yOhBTnyrsU2@&hLR<_I4t+r8tjd-mmrYbwVr zoUpbGiMd1f<&G;m9I?ZAC7pJ)zV_M%Gqiv|sHB_B8q)|vL4bE`#~kDipFEn0 z(;iDEl^YDMHXfZA{{U*##F0&=nRb~TNWmEXP}nEv2{l}+4W_L$Ux#o2R$THJjFLyp zW|xrsL^K;;`o`Ym4Vyq?$;j*Xt6gf;BDTO8@cUdIMo;%6A2UGz0QyUvs>oZAnCd{! z_o-@fsJ4nv4cW`>%HUyo{^WhCcd_6dK2-+J^)`hPY$T4S{l-4ke|ddx3L*s}6)O1$ zgzL}hc&zQTp==%yHmWrMIWPHfYNCMQ}JDWC10F29U#Ww@x1Ofr+*A-J?0gS~l#Pco4Es=w?4xaoE z&{d`W>zhg9Dd$kdSZ8ot4h)=UkVzo(?d!m+oi|IHP`F#E2a$=Ms!@mhats$yeTSaGc3`ncB zRhx1CUZ?i0b^0}|PI0*b$;WZi?O#3AZm!z+M4Onhlx73hj31UiT+@fFDPf4!?@h$w zM0RMGvy2cr57MCvhe5RQk6L#2%*iCDC|yf#1HL-r=tmyaQx+}m3W7Eho(BTE=h4Mp z&(m>R#;&g%EEwZFb)&q6oJ7H}Mt92{XRZgR-N2W2kx|j=AZLGv~ zJ-z+w$4NEUv$^i}KXZ9(vc(nQNCP-U@fZNj*n9k| zJMcgH(Ub-Vapu84BT+@zFmg!etrbvi^I!}P2VqtS35}IMG2BjBnDIvus8&@ZFaxDQ z@gpyM^FNvou!VgStp!ccx%p=+cS82!xlHQdK6pIqh z!}xeOKdnM*g0jS?IXyr<=t(07$ycil3P4>sLd=s^PWf;;EuE#s9B^Q zICb65(b#`_1-!@c8`d@Ff=JI_Po{aMq_%y_8qCtgjF}^DndbtvQ{pdX@BSP3FzV7p z5*1d2uqVGG{Q6hZv!0dne}QzVEv{m|kl;F$P!37?*U(+DfmE+i&&xltIU^1{z#7T? zTQv3>d72o@FCdZHwODYu%}{(tGB%eqGV-Kzk(yz~p5i|}{7TYX-z3e0y>dvTEo3o= zRdxu#1_Qo2W}nx*vj|w^s}ig|DLp>cTbY$2P|SF(7owlB%V#1*V7rJp0=Jqi;IPx= zX`>3xLn~vDNA4+2D@3)hRBNCO&tJ?)T5@o1q}WIbI0`zN!mrDuZ8M#f+PB7tCGgW^ zZPOueDym&-N#cFPvVb%1^7X3!0E%rA)-_}*u1U_}(Ek8RLJtx2wu?~nM5J-lgZK8OQ%k$G1H+MDXyH#o_0A|3dbIX(cvmqDsp3Q!HG641 zbB2)s^-~$ZC){?e8feehv^MuMH-=J3i*#f>k74Os&xigPNc8rS?V4HNmfYL6`U=fJ z8fjHx1>CUD9H+U>eH%f-+4v_X1G&lPJfF2?bZIht=JZ`z>T{^VD9f|sB&g3HQ~fJj z@aCc}V`iLy?7PlKJYapf$I_wkUW{adNg@~qHUqa%Mt<4*(mF<)JokopN!hS+4_p(+ z=qUFi^v%S&JU0u583Yn>Ou?jE#b>+$l7#2pp0$f?SZ<&U=7A;HTQwl$Z`u0)0KF;b z8_^q^nC;p>IRTdk>IN$_Y2nZKu&g&F%PTH(kb3@^rG6v2c6*4EDi$!=C!BIJJ;5XN zs!cmsk_*`jsPOI=ApZd7qo>_Z-n7oNkCRhx8zrK^vK0!&GoA+r1pP5xxMm5mLzgTD zas1fGKYFc$ScK1U8#1h3LNGfwAk%Y9+nqCwz=j*T9tipIiplPp71x^Kwfr5zIog*G z6o`A|0)JDVyN-7vkVUkqO~jBdN(8*QZGBwzP7p#<>&gB!irKX091h z;6o&6puTaAoE|>M^u<-*X+9ki}kI z+%3hj1vuP6Tn?wu{?$RQLoKq!BZes^)d~k=&-wDF4Bv^ifo+NLVu-K=er>(}!!+;{ z0@I1D95i@xM<;``anI0tdsS4W@3n6cn|xuwBcIE_t61$WUN16_5E7u^^#0Y$m?B7{ zP(S`55~vuv00=Q1cZ~$;et}{%qnJjJPRx63d-MzycfPPAEMR+Girz+~q*U#Y;SZH$+Wt`~QgU@QFC=Z~#uG@TGyY@X{4BIK&$ zgeO09&MPk_UL-rCSX!Ybsj0D2mxzP*gjsp6Dka2f0rMK|T~B8#?y&oX z_NfM+Yb>`L#A%$Pe>v;{$LU`r*1jOVyttA(i=!l4ju!w94;UTJJJ&V8i09O1hGr}l zBEUr56O)X3_T<)j(5$6^cXScc7l01$;tk-SmGieNyi*#u=lGc2&5-smfO6Hk)HnaXySE?F2^M0 zkF5$eS9QQ(agqrA>4~Cg(NK^9Jb~#zz`%Dik=41*dVJ}DgaqR`uM$mC%0-jL3?$o?VYz78-b5QK6hk#R8`M0EAm&0Iy zF(i z5_r=@k2I{#pzavzeQFTqa-#=n$PJFY@l6=zk7E)FvBIh26>2a}g4$Y!j7Zy*9>48c zy$eH%Wc+Qw&8%mH&I_6!!}=t*;U~BZmVo4z9dYUHTDOPBK^#$?iGZr3fIaIQX0n6W zO6Km_@KsU3RUI&W{#C6j{7jn0Mp`!76@x@L%HuyO*TXN5ZjyA$`vDhV)1K2cizM(v=D0><(eJ4Vsd-1-Xn?zoFB@o8Kgx!m1=^c8LE4k_{M z`R&G;KCO1^3X)Z`yRgk^G<_z+LQfib5^KNZ;9-BgMom@=XDI@Kk_VT)DRpZ1h|(Od zQ+!=h0n4#a@O5IPV#)6m~K z0p%Ia;72E(#+*%3I8l27 zM<66X&+40%EBFQ zpqCf1rTbcggCrY=%p6v8@oeyx(sdmEUgbUO%e4ye5c zpQZFX1(y`i|r-f;6;Xj%pT(&#s zcl8ysn&CW0a^RUIRwp>lJAJDscOquy7H$q12V<+t80%d*S&ElErT0F)I+m z9QDX1u9rkh?C-^s!{7vox5^)r{{W86pKOk5sc(gzqE)=m1W23z0P*YhG}gHsQ>0VD zCSF%&IPAQG^6F~5T9&z$rwVtu1Jk+Ae$>-mAoooih_l&1Q8To@Td)TNfByh4@-)Sb z?3XqQ7?%)*VxSC$7#%&%e)PVVH;R+#jEr`v3!Vs5*B>L#)YDpJmn_gfoAQH>x$B>i z6`N*>9ZLqgg~Y5`oNmT{G0uOzIcs2HX<5Myxm$2K>6+{t(o9AOc%4}Z^dp+HvNFjj zLm0`(>Mi{c71xe)eCm8l1)6opaVvltSf=VbMgB)i+ z=jl{eT1?Vv$t+QDt)H)dy;<8&b2CKFg(OxRgLhw1T9_^^7>@{`Y;p+AEn;|PY;6kN ztOO7MIaAZ0U!kkWG^67yvo7An`uym3^T8P17(+80pElem>UtlxC^p)X+*_=PERlod z+jm#47enviczESHkTjPZdSVY8B-o8&tF zl}T}Wk}{o}*>XrJhu(dM0{~~9e)NU5xfJ(q&`T$cf}1>27Cdz$JcD>MXBCK9QzHU_K zob}|B_VlLG`EI3#0SdWxF|3h{KOlxDJqhQZLGCJ_;)}>FAd1%2WJO}Z*^Y1r8#D48 z){?d171Ang_gqX^`ksxl0#B>BJ0}O9UA?L1 zfLn5M?8Bb)yv5$`Ms@}uGP&u}xos8QJBv3Q8qS-TmEw4wP0{o{Gf}y^k?lM&!6VGs<-TUBIGQHy zQovsjd}sr`wTcst8dg8BtPZ2A&2rm3MsJX-9Y)sUa|q&WAN2E8)_OJ6l4g5(0+Y|_ z)Yh1h8dqC@NRfjsPIqG>w6-{CLhp@}INj4D+x+yVqS4*}7(zrn)rUQLieYp@97?KD zXKDUv`VBuJyD1RnnYQTo=K!0=qDjdPKL z0rMPl^6NoV+j$zU3%Y^>1MAn0qLQYA5laS>EO~6Qw>bcQZzQe-7(csVZE;Vo8Bg@|DO9o`6=LNca~{(->SZ@n$MVJu%l9 z^rc*whNrV36}9Y|crnD%6#%RB8;XJYar)A_U&FT%G`DiyB&Cpmt&_)LAST0It&KI-iw|W%u!jQb%+)8?9jP)4n*PpFuw4EO6 z!4`Kyq{rW!Vu1{DYZ~>cah&dzm%c0LSC;XJiV#X;ZZnE^%U*(b*R$t3wWNAwgUHK? z2+UXm%AjMPzwKBvde<6)!=E6|N7E*?zZ_~i6Jhhqvz z20&b6j+JJDGzTA?^~ue0*CTA`nMnxCr{Z1e!9$JXkIRZ>tfGn~nSbso;~C(JJe!F* z!Q1Qpbg0WBB8|k8o&e^jL(x%qiz_Y&Dt|CFM?B4Cm5s7?`9?Zb{mc>`BV_>cOB@gV zQgZ2b-gzZ;X@Bx0E(h!Mt)Us!2*aq}OiC)Y;f$W&e?$E#*PWpuA9S)7+^Zi&`LV$5 zRC>6Y*vB+dDME0uAR`0R<2=$H9P*$uzv0yRkC=i+GD{M880P?1su7=)G+*tiLYs>Pj{Xk!JXbJ#Nz$IJGtH;r*=0EW#Zjt3mf(X%|D z`Y7m69Fw1wX!J;*@SEh*u3%i9uPd1(kot(%p!YZeok~ESvFjaKH0w2v=fYl#gd~CX z<+1klH2vPJ0wdcScC<|S_n;j5l0P^90B*l(qtz3_iRYRrVvW^;$ufdh*d9)Of2}2R zr(0?;TZWiQ{4f(rLIoX4f!4A#H9j?*PXz68CD)ALF4YVNrV0Aw^GItkSl`>?2)tQK z?=nFd-0V+6#2hH9*VJK(DB!cUge)J!S)XB1z|O)?lzj4OSoIrwsR+5dWrJZ|u>i%F zJ=>oCm>!v+1n+JeO}~oL))jLaoHNEr2fhax!1Wz!xiuMW;|iu@HsaZKB%%2Zt&gA| zT6+q6kuZ`IU#+$PtUop*0u`SF{lS| z$FGj^KQV9t9D+v_iHIIpUd_^J(LEE<&#!moyR~)JV zD;}939>R&WSy!JToDBO^ak^1}aHH;fR)i840c0tGye{+4O#c8{HN1g`86^6SF++|Z zWOB>-fEhgfDsaS1g^QdH-qe^N%BNuU9muZqVl(phq8?iVrYIu{%t7RiovI2T2@Jyo z5_fY!kb#Vz`5e(?aJm1}Blv09VsL;T$jxM^IgWT?mvZZoPTHtuq#prsqibYfbomG>X>US=3>ragtB; ztpJb}$?ev>*6f2VhH8m`vi&PPWpq+%_t3@&z|U&VzMqYjt*!h7Iy#xl4{~T9#ub2KK*I+aNKPer7jWNF^uCJ^I7Rg z91=w;>?j7_frS!9iZpK`k5wasRiB7tbCH~!H5zFczzY(?*S;#m2IebS18$51>bwzI z?Lyk$a_npXau_x+eQ1$OajRXmwYfe_27Z85<*tKgYmMkl-l zrh;a2K`OnlI+`e!P@y((JJq5@rD#(`3KdW)YIO}-(vsp(@#l`c>o2X_D?uaY4gonG z{&lCiw`AH0$j>IJbtoF*-QrR=k%3&xrgeKpN8w`s0P|w%GnF|tw$x-rhs^jm81<~) zlVI9-lW#K4cjB%f!Ot;=>Gul{`Y)y8=G+-T!K{b?83bS{{UP#p809? zYamP;c7UndJ*e1skO3P2Kh^xz%V7<@vgEzgfCVh1V?8UHmGj!7#@qKX@*=4$ewE6& ze$D>?A?vHC;8N^D0l?26;HNv~Zt$1=9{$y5ax83(uk{{VuvjyXnmZJM>z=XiWsZhR~Na9H7eiS<3n=|{NMC7#eoC5AO$ zDzcHe&OQ42bpF+vH-gdD&dy+npdGRhqED+}W}HZ+zqpO?uPDOpf>l*a`W^ruEd1+F z6FnEz*5Tu6CB0~%k0)n~w4b2s=~XtGw4iu#tHz7YS2-uwCqCcOt~F@ZA4;W2;!&VISi+MWn{*H*ljR3*IbSnvKJ@()Z8PeJwPiqS5+a4y*{ zC%8zED2mw0fPKi%&yL(==cZ=QREthvmUB%5k>-VLPEYXUi@@+{{7X{=ES1 zMtEL}TMJ0+WSW2CBA*RY7-@((3y(~Up53|Z*WskKF=fETEb+5yp}|w0j~(kPJCF-tCNM`~7M8rnhL#g|j`~<;VTvsKlxcaHF8lI0pk9 znoa!;Aeyb+kc!kF0VGvsfg{ZSgG)0K6yP0u2kbeh@=K&&izt2*_-@}# zBJyuF0UjP#A!B7VV5wUBV^_IqUPJ?qtfY0PCJy?*`c=)dq{ByC4h zl!4+bE4PlBJpTYn#p#x3QJC5yhGyf(bL5ZIumGQ7Uqtvq7`_;mA}15HqY{-Ih4ja6 zdVaN4N_~sPwbAtlUs?mmk&b@V2EB@FZx$I9l#K9cO+G25xRT~`jmv~jLH+9*dio}3 ztzqSr<>3?pd$(#Qf>u5bPp&9TPVRtHF}MhKbfmj2^tu*`HZp*D%`rSm5CL3_{{S1x z4hMRZ<&8f`O}53B6#(E@4VWvF^`?LTdkP)p%352rkJ6l^f~K8 zcv6!}FAx9#`&1;IdkE;_rRlwt)#M$ zEzjbJIojJWJ+c8Gdbxyz?Xs@!@vfoF5Jts$5v+TM)PcwAS=(#)ZtmriQPg9!5T6fW zV59#4uQ|ukhdlR_RKEh3U>k-SMAm&A`9dxAfDw1{l_ zg{if-j9x){BvJrefUyks1oBNd_Yp;gxFTzUcSjs@hG_sDh6nlHzI@*hX&3f!`10Rd z$%0*S=Z-OefN||t@O(#a6_ADlJmz7;PcsEU&p(tOprZpsHH5m7?n&iY7bE`Dk%jig zc>bodS0*s%scUxR5=Vx+x%R<7deYt-YruRQZ!?#W5DsM8K^W|yp8fJoN;_EXZA-nw31uaWaE9Dh{{WV9 z2f6D>YI?Fr787tA!(1XqmIVI*e|iuV_IJO6ka$wM&EE_GA7F9w%~;KMatV>7p5j*+ zP3@39!1nbuSz~K@T+8?_TRU0sgP&|3YX1OB_#Bs>S2Bj3)lLe5BW2ZF4GC}ZxKOvEW`cfBdEQBI~gU)ft{{TH`(h|b~ zw=RD5$dC^{MmhnW^a%Kf+%hsa9I@_bk#Wf9Jd;CUvB%~hF926zX4{j1Na06eR!CnH z4pRr`LYiQT*y=|Dy)*0^j|aUYB%q@fJPwp4qR{>zaDH9sQED!3BVFNFZ~$i+6lh~` z1fC+CC~PlW`cU-=rDO^r5QcG<3;B<+{?)X}n`MYU^1Y=bFBajFj4*w@zuLQR18Ns* zu_P?cd?f=UkDtFkDpya5Wz=ofNKC7cyE<=f-%9$mkHe2`0$mGOQSR6*Y#1DM;2y(@ zbn$c&we}C;%Q2-{$)~*GW0}E~%5LWzd+ikJz!4;o91|JH^&>rKiv(8ksyh`qD=Eo6 z2T#AfN@8VQv5=|M4>ui742f;UhN4&z_4*njF* zuR+)CSt%F8zPGu!pUA4i1a9fhIPa0i%9NktJs?db!iRu5{{S+PmIJ5)wN&4uClZgM zX%29rWpzJZ{^;rWaVTb=~6teH(*FUthh%G7ET` zR6bmfT6IbKCL)v8Mh!_K(Ia_0?HT~fo_MP3)2M2&A%Y(cBgiko$H>!~PLVcR;`9uh z6^pRP-%9P7uWga66HKK-3W#QPYx- zk&jxey}6GBZcxLq>q)kBad69fOtTkpGd9*%>Co0M<3EoEl{(q!xRUL-IQ~)o8mQN` z)YEeym?=szR9 zB=CpvFg{&t<9a>zyLl>`8)Zb#=V9d^GHZEnH1>9j`1``{2bit^2imf}m``ZgEznHn zL7$yX^_XqrW?;DEzgqczukoFosF7p3cYFbk4l5gZ@s-r-#aU}f(Ysbe-&gxIE zYWn1NQ5W%1VqQqywEgQ5seDrK`R$4nC$gS?r;5wPJeSb!QyaHZN`(27=H{#J$l?T% zNNfONlOTNXD|H5L{*R*RI)&7*JlL7ja2bvQIXy;3?2oNo+q|q;NeoFFb&b5_{L~T+ zV15qxjM?JN@9yL-Hj8+n&JKNZpS5mprjUeKTFn@YGF)v!caoc7*4Hju%dtobeS37Rh1bMsBm&wsb>t$+ zB4Pk~adW3lctDfF*chnw+DXCo1XCKeu{2X6I>fLb&d8$L#GjBj1KPfQ@aM%Z z1lykeSjlXd1WM79>$DJl=CtpBaWp@P-yfOI*DHV{ zyRr!N$r-90PU<_j$d>C3w-Lal+Xv~9M)-?Xx_hT-omqo_{9B5r)PcDEm7aU>&*KN0 zTZS7{ZybF1{VJsp==Pg&_)SGxLZhKz&(F)#KE}2m^GP*DYbgYg$AHEzU7OIHt79Fj z=kXV7(99UN?6wXKZFJSUdv#lT7Ds>PUNQ4D>kv<5Q4%pEajc3!!lQHdJ*t-O;z%V$ z5-!n`w~ib2t(-p!>bDp(+!zstaE+hTQ}!S5^1xzAR#~4vo<{zapX8KUhGVp;46tV4 zGmxaJmL$l>*mn0lt4kH8v3Y3{2%xlq231J>pCQhFO4dW6rL-kPF-I8mT;z`YQ<1~dYfp!gHVYNFgdPF@WA&}i z{IhXr-ADtFSoA*Tj<&GItF|!A7~~$Df1T<1u<lCtwo-Y*6f}V zf)w&e10eMr{{VV=J9QB6=zw*`G3i}bSnb~@a3c=GsUH5dol|AZq)B2}Se54=%eU>* zp`xHIhB593{Y$|A0D9TPR8wrvCJwEhcascFD zU}v0sjV~FE@`%a@bC2)VnMQD)9(NC537`Q21c!Jdz7*tr>ye@{M&88q!R=D<6fWg| zA^u#c#3}JG+bCwI&KDEU_8wePY)G_|FgWPS)02NP|;EtSk&uZQ18d_-a2QJGrssT{h z2t9sh`cZbJ1Vg4ZqG&K_Q3=$U?+TDk)3pvc!2Z8Jm2Tly<`iETqM>k`auoXv{*`5Y zt00aeVFL*SdpBWE7{+iuwOea(4}lVhpLlF;RwNJx0O!4O-D%Mi_DozLm?$h2xCb2k zsE8$sDJ7JaiPtO%#(Cfx58CVAaXv{k-BTq z=rss+2@H1g;uz#RfIUbYf_*F3x0bdDrKM$<45%GX%y#*j!Rt5eqFb3(bx9;}(ZHmu zH>o&1J5?O|rRBuZ!qJFUM%>b8JYaP7{*_;ezR{mACyMCU-)pTd{{RSti~> zrg4ho@vw-ZC^&7U@Ob{*RF0{4{{Sri0GG2VwnN6%!OnBR>OX#Jf7!o(15wV87%cf^ zK5DSB)Lzqh4obIfy!!K0R+1_+VFuIG6IKxUz&RY8Z3p$N{TJ`qe;35~gvTNQARbmd z{*s65ll;jSW?^rL3 zJ}tbqWmtr5Gj}VHKfP{dh9!?1M?Hb1Vfbd+{^K!O2asgBE4YE&^Xpd+zgjM9@?CU% zvd2Nyek{8eSBzta{{Y(A>DK^vt(B+3T1KC>gl_B(OGtS?PL-f&RTpz%Ht?VfW7?}V zE3*x&pAA`Yklu!yy0?Z3RF%4~#MZhjUJax#j<&EMX21uw0`wm|o|J3PgA-9G z*Eee(1^|W-ihv%O>-ROER z{5jF1aMB5;JZE!p&$#bb)?W|lc8mW2PiYijd6kuU2kL5{@+EpgTrK-PF{Ej_g5PdS zFUx{_XmgL2dVTBZR<_bhY!vCNBvJf~V?cdDKhPS}jWW&#Q{f`29IFn8KBMPGk|iTD z5s-2Ydsa`C*P_=NUeBCrUj$$3rJHrEK!2lqW9Cm^u%+$4;fkby-CjF(Dx+`sE9%Ib zfj$uQ$idIhbgoR1gSY|z0FXQk`x-wji^5D!o$y74teA=(2Sz-T_3c_T(;>EjHphk; z#s>gZv~L(dnc4y9M|w`~>|4v?2OE%vQH=9TU3)7MArMHvDdh2<^k}X;EMyMjAm=|i zpql35=4ly9f==W2slu|E7$)LL>cb!5qr_fC+}A!cg-`)Jdr;5_WMb{*>BdPulmvoC zK#auWr3!SGE$y6VgOS(inrRP96}XCGW6vYhU=u`B9zwsA^(wsk3ZRW;k944%kfJi09rX*3?@h<9A=H-2Ro0MdSHrz zh+2`2gpI?4lh%uv_J9zn&uk7y%Aw)-N)Rx>?de1>7+znIki6%LKn+#-S985{kjDUh z>yj{zG6LtyK<1^rWx|3EIu3yT_0tRNAqm_F1ha8K3$$uLB_Dy4pKn1^1H=orAcKH# zKAh7#5r+MUtfw3t?*7y%JS9RhG6~~$aX=BuLZl>YPz-a%eevF)0~bHSPCF<7b6oKU z;$w(0-JV9=@sICJx;iSb>Y3wiNgaCnQUQMt%2>t%X9fKQ2~)&UNd-p$U~%>BO^A{} zyGRImEMbwJD`a!Jkr9OECYFg_g2Q1Oh?>$T(?n+i`P)FqjT8&qQ%JkaB8N=t4h zjjN1&@N1@I=c>WRi||v4At@_&JMq`HDTyODHisuJFjzX|mHw6Hw1e=`EU`%pt~UZ( zhCTkBD_QW@!@esEse?q3V4!YGudvkKO7YPiTr|`&G9k8fR^AdO%>sQ)m!dgv=0cQgaMo#ko0KHFA_;$+u znmf5?Xk!9T!=T!(I~F}pJw`s#B{_;FdQwX|DytfOfh_W)pZstr6nm&BTloO^_12~|T9 zH+l^E1~s9KHN*`p>fR)bJc*ESJC5CQDxTv{7MCzxTg~F!!8e9bl{ z7EzCU&<%@78^ywi#yBmG{*=aN;AI#u^KRoFqN41Powzt&N%!`yGno)PWFups=7DKE z?sYD5y-#WomRN~+qRs9a+bR8pDtqUpdI> zlh5f@`h}Wb#ADpRvFbVsxRM1couKYqXXWcll_O$=450F(BXFlZFnymJ_?Jn2I`&xi zE2ux5Fe4vMm79?nPCutw`*x+FS?WdE;v3VIWKq-De_E=8;B6VDX(U^ToN~(}e@g70 zb)B5m#P_4*dr3GPpK7?%z7^H=5~3?dRc=GcWp3`q@Zy8*26cT>*Xd-B^ zq$%S(57wr?k@SIZ{hvG1{{Z2rQ@c{RB#yDharZT>wD>zlwAdoDP6!}L<}7{5tA}mM z!M2gqVDpb^V0d#zqa}bC~A zIST{Wblp<~Zv?S8>Q7Nn(PWu0*fgovud(4 zGRRbn;A8yejddFo3c*O+aqEv$Relo4a##b8^z`=4TEbcnKB48v8}sThibgwmCX;iP z+D>o>0mcnE@?Y;xC6I734+GMyV~D6FS91Z#twX6(VS`gf^ptVGs0cI}7&bCNpOJQO5{QbDeMO}hvf>e%V; zT#1~5B;B|YMo$D(=~zhE#3E3jA7V4bN5b-eMh<#*$Igt5!)t~)2Oyl_eJjS{z!H+of zK9qp$v9ybo0e9er9sYC)5=M{siH9fik6L0WSg8z{=L2t0DDzsz(D;tKNj!%AGe8x{ z4$SaZB$C}n`&UB*!h^}@3V0uSfe4NjSg39Q>J3Ua2#dG|Z}lE2k`&B>MM6n(c~s<| z?Oi)ilII6F!99Jb`A0b!I8nwr(Aqfs&f-L1GBSTKq%lJii-{$SAY+iBSP*@A^sauCoQ@Re}z1r=0s#RFgX>8TTvC?LZQW8Ka8?f=?<32NcR%_>Gn!N2>nS z6B4;iv9JT4bKBCSWiFvZ0v7~-W1h5_@ch_~B(AHs4Ua0Q>Fz4RB-{Ibb%SLC4GGT2F=k9Ften3`vg-Q+$rzQaI>6ewFApk~q?AzR+~X z)Fk{x<*+aSxe~|5;B$o;{I#^RD|8sDs))%@hs)pg9jY?PGbC^vKjDx>s63z!{j1jS zJa83R50vj21E(1W?Oc48>7AT%r58p^3G~$rvc1mL1S0S;o;^BNe(K(6V~b|>50X*8 zm;;gbrdnxL!2}rDx49f-j+hnb?nKFSz8e&j4!u*JnEh)ydR(j#OPGbW))-=Zo4W9G ziiBCeo>3q#z-{l66nl5#tu;GaIMM?Oh(J&V)4L~(@_N$C;l&iK3K1Y9Br#FXA3S?d z)^sHIvQ~2zS5YDX5iyoi%C~d+)fDzxq~8$2t2=lOjhB_bgm}g=*Zu24ma<$~&Agyu zMo+09`l-ok(t&X^AK(BUMHwR}x33i`;i7nef5!5KCx^U{agcxaOC4G%1F~eGI3SKgRe!>=h%K%( z*;fw(uw=$|sW|{2PyJE+mUmEiyO(odZ5i9&r_zkpx|_&0$EEH2b{6~)L^vpM!5_!31D&l^xCK^y8wF9oV1uE@#)1GpLBj! z9XlSBU}@ICAxFz6y)8Jw$<8y|nkg)L72C9D)D!+1fhh)MvAvJi4tBx9TpN-_Z;D&+IX z$>NueH*d;-FZt4s5zF{t0b-@Lp5S$%jT2jV8JtNch6p=+yRv;fhrIy{Z{{*Nz&Yth z+6l%o2*@6u)JWHS`$8NZ$1GjNuk~>n-&W1;i3zs$?Q;Db{D$%GyF;PXLdUFG=69Dr&-f&956_4cMB1gcyJ!6Hq&u-!4zyh-1Y zocHhaG)LOZu1b~z1GYVDiTp>x)|O77t20QJXeZ2}}CLk`XqXB$r#AKrxOc>W#}c1a_yJ*rBs0)_-K z4oEr3`B0>|D&8BmLCyeE_o>2=$WZ05PW)U(W2z+9dI$t1d|w5X?GRl%g^49k}?JW0n_b3(K4Zd zRvUf6>qFcVXi!03K+bVec|1bCd@wk{Zj~7pKM)5kwE-oShU}V=kY^0pcJnC>mK@@w zX2?5PPySnuXjdsctjdA6#P~e7n+K7_6Jb`#U8RRoJJTdAGPrec;{fDf;8CTTc}`Wy zJbq!v+Lu{2w*;OBG24%NoO1>R2@Tt5JpAYabHZ`H24Xsr20{8)B}jvKd>%J>+po4O z&6VNE-Z>aK>FZv}lRIMEdouA%MC6@giDN;QZktCz^RIZW;S?Myoc?T&mOgdNsZ+ao zKs%4i#RtVlTm><*jzRtC0kyb^hlIlopH8(81-xPyFbsc~A1L`!q_V%6yuCpfB%hyZ zk|~BYJ4rvx1Ds&~-#P&kCE`-BFbFUM1Rrdv(LBFhY`cCGHuBuI_0IA_}=j51V?0s8*{YPV11g+D|igu6*Jakdx` zaCv4?#yv(eLo&!CSl&YAn9+Bx$dU*4RS=1FErZd^N% zMhNN8K~;f7Z0)&~17PmpQ1f~he;~wSDGbq;ecWfT0RGi45ur%(iqRGunGSuac{3`j zAL2IbuRBlLy*-4o?s)EGj!=PBS0oXf@;zy(`v$~qV~sVtiAxC9BifT!K0IpH?P#>=C5Y7l_66g7;LwZfgtnO9ci@v zi&kM(9g%qZ3^dK1Ij18kbKtJz8X%2RPbGT%w>FM;TN5c=zjCCWAVhu49Q@snH zES!#+$?aT?wgbHzlY+o;nuAHb$Xsku#_vqm9XCh;<~|#*^ri=lg;#n8+`|W&7;+am z;B*xyCjjj#Ms|-{Rz?cTg(Ey3dQt$}_b52ddS{@ct1O5R9v86V=TMJNzFjnGJ_|Lb zNZpZ~dgIeI#BxS+g2N?gwVuH=#st9~RP0UIY?kBv;+m2hX&NIOs=ZjV0>c^3-YGSV zZOCDdKzdPpKvNq%zO^_o%mS_yt1qtHSCp;}<=d0~8iKl&!Ax_`1#@vAl|Pr95z>qR zrPp*}6aYG$^~EH*e-%co;Zcv~zk&X`yU3bbB4}qRDkTYI{c#J{7BRvm#d4#jTDuaT+_dP0V zGC^P%Dg2~&?^19;@~#g-jB{MzsSF4{q+>pxTBJ$P5M%{mo=$uF)LHf*DZ6pV#w&ot zyLSr{kJCL282IXUT!`d3+_XB(Ub#&Ab!jA5NXklNIX*kN!a*dMgtBqrv%cBvlTqHeNRzOPXjo>9Qt+53&WG3=Z>8!S!h_pC_w)J znRFBVm+)R2{$p&&<*r z2$H)3&ytzO7m$8+Aj+o;xZq@GkJr5i{?OXng9F>O0X%k`w%}tK>Ny_5nIkM@XorZ% z#GW|LJt_{!Bg(eXj_Z+{ftM!$1}lTO9C7JIQoN}^>^%5xr2A*BAUokYw}}!ckDfu` z{W}_srL(sA0b&#qa&i~nik{LUS3&?M0dRZ#>yYXb+8v5jij%rN$LEe{Ui%yC(I$K- z-G(^M?C0(8LuD-695<@%_4Lm}Kr+oW!@kto*&$S5A7ClSRN)w=)42Ia=zT>1kN?@C C1wecN literal 0 HcmV?d00001 diff --git a/Samples/nvJPEG/nvJPEG.cpp b/Samples/nvJPEG/nvJPEG.cpp new file mode 100644 index 00000000..b52f52b0 --- /dev/null +++ b/Samples/nvJPEG/nvJPEG.cpp @@ -0,0 +1,559 @@ +/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This sample needs at least CUDA 10.0. It demonstrates usages of the nvJPEG +// library nvJPEG supports single and multiple image(batched) decode. Multiple +// images can be decoded using the API for batch mode + +#include +#include "nvJPEG_helper.hxx" + +int dev_malloc(void **p, size_t s) { return (int)cudaMalloc(p, s); } + +int dev_free(void *p) { return (int)cudaFree(p); } + +typedef std::vector FileNames; +typedef std::vector > FileData; + +struct decode_params_t { + std::string input_dir; + int batch_size; + int total_images; + int dev; + int warmup; + + nvjpegJpegState_t nvjpeg_state; + nvjpegHandle_t nvjpeg_handle; + cudaStream_t stream; + + nvjpegOutputFormat_t fmt; + bool write_decoded; + std::string output_dir; + + bool pipelined; + bool batched; +}; + +int read_next_batch(FileNames &image_names, int batch_size, + FileNames::iterator &cur_iter, FileData &raw_data, + std::vector &raw_len, FileNames ¤t_names) { + int counter = 0; + + while (counter < batch_size) { + if (cur_iter == image_names.end()) { + std::cerr << "Image list is too short to fill the batch, adding files " + "from the beginning of the image list" + << std::endl; + cur_iter = image_names.begin(); + } + + if (image_names.size() == 0) { + std::cerr << "No valid images left in the input list, exit" << std::endl; + return EXIT_FAILURE; + } + + // Read an image from disk. + std::ifstream input(cur_iter->c_str(), + std::ios::in | std::ios::binary | std::ios::ate); + if (!(input.is_open())) { + std::cerr << "Cannot open image: " << *cur_iter + << ", removing it from image list" << std::endl; + image_names.erase(cur_iter); + continue; + } + + // Get the size + std::streamsize file_size = input.tellg(); + input.seekg(0, std::ios::beg); + // resize if buffer is too small + if (raw_data[counter].size() < file_size) { + raw_data[counter].resize(file_size); + } + if (!input.read(raw_data[counter].data(), file_size)) { + std::cerr << "Cannot read from file: " << *cur_iter + << ", removing it from image list" << std::endl; + image_names.erase(cur_iter); + continue; + } + raw_len[counter] = file_size; + + current_names[counter] = *cur_iter; + + counter++; + cur_iter++; + } + return EXIT_SUCCESS; +} + +// prepare buffers for RGBi output format +int prepare_buffers(FileData &file_data, std::vector &file_len, + std::vector &img_width, std::vector &img_height, + std::vector &ibuf, + std::vector &isz, FileNames ¤t_names, + decode_params_t ¶ms) { + int widths[NVJPEG_MAX_COMPONENT]; + int heights[NVJPEG_MAX_COMPONENT]; + int channels; + nvjpegChromaSubsampling_t subsampling; + + for (int i = 0; i < file_data.size(); i++) { + checkCudaErrors(nvjpegGetImageInfo( + params.nvjpeg_handle, (unsigned char *)file_data[i].data(), file_len[i], + &channels, &subsampling, widths, heights)); + + img_width[i] = widths[0]; + img_height[i] = heights[0]; + + std::cout << "Processing: " << current_names[i] << std::endl; + std::cout << "Image is " << channels << " channels." << std::endl; + for (int c = 0; c < channels; c++) { + std::cout << "Channel #" << c << " size: " << widths[c] << " x " + << heights[c] << std::endl; + } + + switch (subsampling) { + case NVJPEG_CSS_444: + std::cout << "YUV 4:4:4 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_440: + std::cout << "YUV 4:4:0 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_422: + std::cout << "YUV 4:2:2 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_420: + std::cout << "YUV 4:2:0 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_411: + std::cout << "YUV 4:1:1 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_410: + std::cout << "YUV 4:1:0 chroma subsampling" << std::endl; + break; + case NVJPEG_CSS_GRAY: + std::cout << "Grayscale JPEG " << std::endl; + break; + case NVJPEG_CSS_UNKNOWN: + std::cout << "Unknown chroma subsampling" << std::endl; + return EXIT_FAILURE; + } + + int mul = 1; + // in the case of interleaved RGB output, write only to single channel, but + // 3 samples at once + if (params.fmt == NVJPEG_OUTPUT_RGBI || params.fmt == NVJPEG_OUTPUT_BGRI) { + channels = 1; + mul = 3; + } + // in the case of rgb create 3 buffers with sizes of original image + else if (params.fmt == NVJPEG_OUTPUT_RGB || + params.fmt == NVJPEG_OUTPUT_BGR) { + channels = 3; + widths[1] = widths[2] = widths[0]; + heights[1] = heights[2] = heights[0]; + } + + // realloc output buffer if required + for (int c = 0; c < channels; c++) { + int aw = mul * widths[c]; + int ah = heights[c]; + int sz = aw * ah; + ibuf[i].pitch[c] = aw; + if (sz > isz[i].pitch[c]) { + if (ibuf[i].channel[c]) { + checkCudaErrors(cudaFree(ibuf[i].channel[c])); + } + checkCudaErrors(cudaMalloc(&ibuf[i].channel[c], sz)); + isz[i].pitch[c] = sz; + } + } + } + return EXIT_SUCCESS; +} + +void release_buffers(std::vector &ibuf) { + for (int i = 0; i < ibuf.size(); i++) { + for (int c = 0; c < NVJPEG_MAX_COMPONENT; c++) + if (ibuf[i].channel[c]) checkCudaErrors(cudaFree(ibuf[i].channel[c])); + } +} + +int decode_images(const FileData &img_data, const std::vector &img_len, + std::vector &out, decode_params_t ¶ms, + double &time) { + checkCudaErrors(cudaStreamSynchronize(params.stream)); + nvjpegStatus_t err; + StopWatchInterface *timer = NULL; + sdkCreateTimer(&timer); + + if (!params.batched) { + if (!params.pipelined) // decode one image at a time + { + int thread_idx = 0; + sdkStartTimer(&timer); + for (int i = 0; i < params.batch_size; i++) { + checkCudaErrors(nvjpegDecode(params.nvjpeg_handle, params.nvjpeg_state, + (const unsigned char *)img_data[i].data(), + img_len[i], params.fmt, &out[i], + params.stream)); + checkCudaErrors(cudaStreamSynchronize(params.stream)); + } + } else { + int thread_idx = 0; + sdkStartTimer(&timer); + for (int i = 0; i < params.batch_size; i++) { + checkCudaErrors( + nvjpegDecodePhaseOne(params.nvjpeg_handle, params.nvjpeg_state, + (const unsigned char *)img_data[i].data(), + img_len[i], params.fmt, params.stream)); + checkCudaErrors(cudaStreamSynchronize(params.stream)); + checkCudaErrors(nvjpegDecodePhaseTwo( + params.nvjpeg_handle, params.nvjpeg_state, params.stream)); + checkCudaErrors(nvjpegDecodePhaseThree( + params.nvjpeg_handle, params.nvjpeg_state, &out[i], params.stream)); + } + checkCudaErrors(cudaStreamSynchronize(params.stream)); + } + } else { + std::vector raw_inputs; + for (int i = 0; i < params.batch_size; i++) { + raw_inputs.push_back((const unsigned char *)img_data[i].data()); + } + + if (!params.pipelined) // decode multiple images in a single batch + { + sdkStartTimer(&timer); + checkCudaErrors(nvjpegDecodeBatched( + params.nvjpeg_handle, params.nvjpeg_state, raw_inputs.data(), + img_len.data(), out.data(), params.stream)); + checkCudaErrors(cudaStreamSynchronize(params.stream)); + } else { + int thread_idx = 0; + for (int i = 0; i < params.batch_size; i++) { + checkCudaErrors(nvjpegDecodeBatchedPhaseOne( + params.nvjpeg_handle, params.nvjpeg_state, raw_inputs[i], + img_len[i], i, thread_idx, params.stream)); + } + checkCudaErrors(nvjpegDecodeBatchedPhaseTwo( + params.nvjpeg_handle, params.nvjpeg_state, params.stream)); + checkCudaErrors(nvjpegDecodeBatchedPhaseThree(params.nvjpeg_handle, + params.nvjpeg_state, + out.data(), params.stream)); + checkCudaErrors(cudaStreamSynchronize(params.stream)); + } + } + sdkStopTimer(&timer); + time = sdkGetAverageTimerValue(&timer)/1000.0f; + + return EXIT_SUCCESS; +} + +int write_images(std::vector &iout, std::vector &widths, + std::vector &heights, decode_params_t ¶ms, + FileNames &filenames) { + for (int i = 0; i < params.batch_size; i++) { + // Get the file name, without extension. + // This will be used to rename the output file. + size_t position = filenames[i].rfind("/"); + std::string sFileName = + (std::string::npos == position) + ? filenames[i] + : filenames[i].substr(position + 1, filenames[i].size()); + position = sFileName.rfind("."); + sFileName = (std::string::npos == position) ? sFileName + : sFileName.substr(0, position); + std::string fname(params.output_dir + "/" + sFileName + ".bmp"); + + int err; + if (params.fmt == NVJPEG_OUTPUT_RGB || params.fmt == NVJPEG_OUTPUT_BGR) { + err = writeBMP(fname.c_str(), iout[i].channel[0], iout[i].pitch[0], + iout[i].channel[1], iout[i].pitch[1], iout[i].channel[2], + iout[i].pitch[2], widths[i], heights[i]); + } else if (params.fmt == NVJPEG_OUTPUT_RGBI || + params.fmt == NVJPEG_OUTPUT_BGRI) { + // Write BMP from interleaved data + err = writeBMPi(fname.c_str(), iout[i].channel[0], iout[i].pitch[0], + widths[i], heights[i]); + } + if (err) { + std::cout << "Cannot write output file: " << fname << std::endl; + return EXIT_FAILURE; + } + std::cout << "Done writing decoded image to file: " << fname << std::endl; + } +} + +double process_images(FileNames &image_names, decode_params_t ¶ms, + double &total) { + // vector for storing raw files and file lengths + FileData file_data(params.batch_size); + std::vector file_len(params.batch_size); + FileNames current_names(params.batch_size); + std::vector widths(params.batch_size); + std::vector heights(params.batch_size); + // we wrap over image files to process total_images of files + FileNames::iterator file_iter = image_names.begin(); + + // stream for decoding + checkCudaErrors( + cudaStreamCreateWithFlags(¶ms.stream, cudaStreamNonBlocking)); + + int total_processed = 0; + + // output buffers + std::vector iout(params.batch_size); + // output buffer sizes, for convenience + std::vector isz(params.batch_size); + + for (int i = 0; i < iout.size(); i++) { + for (int c = 0; c < NVJPEG_MAX_COMPONENT; c++) { + iout[i].channel[c] = NULL; + iout[i].pitch[c] = 0; + isz[i].pitch[c] = 0; + } + } + + double test_time = 0; + int warmup = 0; + while (total_processed < params.total_images) { + if (read_next_batch(image_names, params.batch_size, file_iter, file_data, + file_len, current_names)) + return EXIT_FAILURE; + + if (prepare_buffers(file_data, file_len, widths, heights, iout, isz, + current_names, params)) + return EXIT_FAILURE; + + double time; + if (decode_images(file_data, file_len, iout, params, time)) + return EXIT_FAILURE; + if (warmup < params.warmup) { + warmup++; + } else { + total_processed += params.batch_size; + test_time += time; + } + + if (params.write_decoded) + write_images(iout, widths, heights, params, current_names); + } + total = test_time; + + release_buffers(iout); + + checkCudaErrors(cudaStreamDestroy(params.stream)); + + return EXIT_SUCCESS; +} + +// parse parameters +int findParamIndex(const char **argv, int argc, const char *parm) { + int count = 0; + int index = -1; + + for (int i = 0; i < argc; i++) { + if (strncmp(argv[i], parm, 100) == 0) { + index = i; + count++; + } + } + + if (count == 0 || count == 1) { + return index; + } else { + std::cout << "Error, parameter " << parm + << " has been specified more than once, exiting\n" + << std::endl; + return -1; + } + + return -1; +} + +int main(int argc, const char *argv[]) { + int pidx; + + if ((pidx = findParamIndex(argv, argc, "-h")) != -1 || + (pidx = findParamIndex(argv, argc, "--help")) != -1) { + std::cout << "Usage: " << argv[0] + << " -i images_dir [-b batch_size] [-t total_images] [-device= " + "device_id] [-w warmup_iterations] [-o output_dir] " + "[-pipelined] [-batched] [-fmt output_format]\n"; + std::cout << "Parameters: " << std::endl; + std::cout << "\timages_dir\t:\tPath to single image or directory of images" + << std::endl; + std::cout << "\tbatch_size\t:\tDecode images from input by batches of " + "specified size" + << std::endl; + std::cout << "\ttotal_images\t:\tDecode this much images, if there are " + "less images \n" + << "\t\t\t\t\tin the input than total images, decoder will loop " + "over the input" + << std::endl; + std::cout << "\tdevice_id\t:\tWhich device to use for decoding" + << std::endl; + std::cout << "\twarmup_iterations\t:\tRun this amount of batches first " + "without measuring performance" + << std::endl; + std::cout + << "\toutput_dir\t:\tWrite decoded images as BMPs to this directory" + << std::endl; + std::cout << "\tpipelined\t:\tUse decoding in phases" << std::endl; + std::cout << "\tbatched\t\t:\tUse batched interface" << std::endl; + std::cout << "\toutput_format\t:\tnvJPEG output format for decoding. One " + "of [rgb, rgbi, bgr, bgri, yuv, y, unchanged]" + << std::endl; + return EXIT_SUCCESS; + } + + decode_params_t params; + + params.input_dir = "./"; + if ((pidx = findParamIndex(argv, argc, "-i")) != -1) { + params.input_dir = argv[pidx + 1]; + } else { + std::cerr << "Please specify input directory with encoded images" + << std::endl; + return EXIT_WAIVED; + } + + params.batch_size = 1; + if ((pidx = findParamIndex(argv, argc, "-b")) != -1) { + params.batch_size = std::atoi(argv[pidx + 1]); + } + + params.total_images = -1; + if ((pidx = findParamIndex(argv, argc, "-t")) != -1) { + params.total_images = std::atoi(argv[pidx + 1]); + } + + params.dev = 0; + params.dev = findCudaDevice(argc, argv); + + params.warmup = 0; + if ((pidx = findParamIndex(argv, argc, "-w")) != -1) { + params.warmup = std::atoi(argv[pidx + 1]); + } + + params.batched = false; + if ((pidx = findParamIndex(argv, argc, "-batched")) != -1) { + params.batched = true; + } + + params.pipelined = false; + if ((pidx = findParamIndex(argv, argc, "-pipelined")) != -1) { + params.pipelined = true; + } + + params.fmt = NVJPEG_OUTPUT_RGB; + if ((pidx = findParamIndex(argv, argc, "-fmt")) != -1) { + std::string sfmt = argv[pidx + 1]; + if (sfmt == "rgb") + params.fmt = NVJPEG_OUTPUT_RGB; + else if (sfmt == "bgr") + params.fmt = NVJPEG_OUTPUT_BGR; + else if (sfmt == "rgbi") + params.fmt = NVJPEG_OUTPUT_RGBI; + else if (sfmt == "bgri") + params.fmt = NVJPEG_OUTPUT_BGRI; + else if (sfmt == "yuv") + params.fmt = NVJPEG_OUTPUT_YUV; + else if (sfmt == "y") + params.fmt = NVJPEG_OUTPUT_Y; + else if (sfmt == "unchanged") + params.fmt = NVJPEG_OUTPUT_UNCHANGED; + else { + std::cout << "Unknown format: " << sfmt << std::endl; + return EXIT_FAILURE; + } + } + + params.write_decoded = false; + if ((pidx = findParamIndex(argv, argc, "-o")) != -1) { + params.output_dir = argv[pidx + 1]; + if (params.fmt != NVJPEG_OUTPUT_RGB && params.fmt != NVJPEG_OUTPUT_BGR && + params.fmt != NVJPEG_OUTPUT_RGBI && params.fmt != NVJPEG_OUTPUT_BGRI) { + std::cout << "We can write ony BMPs, which require output format be " + "either RGB/BGR or RGBi/BGRi" + << std::endl; + return EXIT_FAILURE; + } + params.write_decoded = true; + } + + cudaDeviceProp props; + checkCudaErrors(cudaGetDeviceProperties(&props, params.dev)); + + printf("Using GPU %d (%s, %d SMs, %d th/SM max, CC %d.%d, ECC %s)\n", + params.dev, props.name, props.multiProcessorCount, + props.maxThreadsPerMultiProcessor, props.major, props.minor, + props.ECCEnabled ? "on" : "off"); + + nvjpegDevAllocator_t dev_allocator = {&dev_malloc, &dev_free}; + checkCudaErrors(nvjpegCreate(NVJPEG_BACKEND_DEFAULT, &dev_allocator, + ¶ms.nvjpeg_handle)); + checkCudaErrors( + nvjpegJpegStateCreate(params.nvjpeg_handle, ¶ms.nvjpeg_state)); + checkCudaErrors( + nvjpegDecodeBatchedInitialize(params.nvjpeg_handle, params.nvjpeg_state, + params.batch_size, 1, params.fmt)); + + // read source images + FileNames image_names; + readInput(params.input_dir, image_names); + + if (params.total_images == -1) { + params.total_images = image_names.size(); + } else if (params.total_images % params.batch_size) { + params.total_images = + ((params.total_images) / params.batch_size) * params.batch_size; + std::cout << "Changing total_images number to " << params.total_images + << " to be multiple of batch_size - " << params.batch_size + << std::endl; + } + + std::cout << "Decoding images in directory: " << params.input_dir + << ", total " << params.total_images << ", batchsize " + << params.batch_size << std::endl; + + double total; + if (process_images(image_names, params, total)) return EXIT_FAILURE; + std::cout << "Total decoding time: " << total << std::endl; + std::cout << "Avg decoding time per image: " << total / params.total_images + << std::endl; + std::cout << "Avg images per sec: " << params.total_images / total + << std::endl; + std::cout << "Avg decoding time per batch: " + << total / ((params.total_images + params.batch_size - 1) / + params.batch_size) + << std::endl; + + checkCudaErrors(nvjpegJpegStateDestroy(params.nvjpeg_state)); + checkCudaErrors(nvjpegDestroy(params.nvjpeg_handle)); + + return EXIT_SUCCESS; +} diff --git a/Samples/nvJPEG/nvJPEG_helper.hxx b/Samples/nvJPEG/nvJPEG_helper.hxx new file mode 100644 index 00000000..9bff952c --- /dev/null +++ b/Samples/nvJPEG/nvJPEG_helper.hxx @@ -0,0 +1,338 @@ +/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This sample needs at least CUDA 10.0. +// It demonstrates usages of the nvJPEG library + +#ifndef NV_JPEG_EXAMPLE +#define NV_JPEG_EXAMPLE + +#include "cuda_runtime.h" +#include "nvjpeg.h" +#include "helper_cuda.h" +#include "helper_timer.h" + +#include +#include +#include +#include +#include +#include + +#include // strcmpi +#include // timings + +#include // linux dir traverse +#include +#include +#include + +// write bmp, input - RGB, device +int writeBMP(const char *filename, const unsigned char *d_chanR, int pitchR, + const unsigned char *d_chanG, int pitchG, + const unsigned char *d_chanB, int pitchB, int width, int height) { + unsigned int headers[13]; + FILE *outfile; + int extrabytes; + int paddedsize; + int x; + int y; + int n; + int red, green, blue; + + std::vector vchanR(height * width); + std::vector vchanG(height * width); + std::vector vchanB(height * width); + unsigned char *chanR = vchanR.data(); + unsigned char *chanG = vchanG.data(); + unsigned char *chanB = vchanB.data(); + checkCudaErrors(cudaMemcpy2D(chanR, (size_t)width, d_chanR, (size_t)pitchR, + width, height, cudaMemcpyDeviceToHost)); + checkCudaErrors(cudaMemcpy2D(chanG, (size_t)width, d_chanG, (size_t)pitchR, + width, height, cudaMemcpyDeviceToHost)); + checkCudaErrors(cudaMemcpy2D(chanB, (size_t)width, d_chanB, (size_t)pitchR, + width, height, cudaMemcpyDeviceToHost)); + + extrabytes = + 4 - ((width * 3) % 4); // How many bytes of padding to add to each + // horizontal line - the size of which must + // be a multiple of 4 bytes. + if (extrabytes == 4) extrabytes = 0; + + paddedsize = ((width * 3) + extrabytes) * height; + + // Headers... + // Note that the "BM" identifier in bytes 0 and 1 is NOT included in these + // "headers". + + headers[0] = paddedsize + 54; // bfSize (whole file size) + headers[1] = 0; // bfReserved (both) + headers[2] = 54; // bfOffbits + headers[3] = 40; // biSize + headers[4] = width; // biWidth + headers[5] = height; // biHeight + + // Would have biPlanes and biBitCount in position 6, but they're shorts. + // It's easier to write them out separately (see below) than pretend + // they're a single int, especially with endian issues... + + headers[7] = 0; // biCompression + headers[8] = paddedsize; // biSizeImage + headers[9] = 0; // biXPelsPerMeter + headers[10] = 0; // biYPelsPerMeter + headers[11] = 0; // biClrUsed + headers[12] = 0; // biClrImportant + + if (!(outfile = fopen(filename, "wb"))) { + std::cerr << "Cannot open file: " << filename << std::endl; + return 1; + } + + // + // Headers begin... + // When printing ints and shorts, we write out 1 character at a time to avoid + // endian issues. + // + fprintf(outfile, "BM"); + + for (n = 0; n <= 5; n++) { + fprintf(outfile, "%c", headers[n] & 0x000000FF); + fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); + fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); + fprintf(outfile, "%c", (headers[n] & (unsigned int)0xFF000000) >> 24); + } + + // These next 4 characters are for the biPlanes and biBitCount fields. + + fprintf(outfile, "%c", 1); + fprintf(outfile, "%c", 0); + fprintf(outfile, "%c", 24); + fprintf(outfile, "%c", 0); + + for (n = 7; n <= 12; n++) { + fprintf(outfile, "%c", headers[n] & 0x000000FF); + fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); + fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); + fprintf(outfile, "%c", (headers[n] & (unsigned int)0xFF000000) >> 24); + } + + // + // Headers done, now write the data... + // + + for (y = height - 1; y >= 0; + y--) // BMP image format is written from bottom to top... + { + for (x = 0; x <= width - 1; x++) { + red = chanR[y * width + x]; + green = chanG[y * width + x]; + blue = chanB[y * width + x]; + + if (red > 255) red = 255; + if (red < 0) red = 0; + if (green > 255) green = 255; + if (green < 0) green = 0; + if (blue > 255) blue = 255; + if (blue < 0) blue = 0; + // Also, it's written in (b,g,r) format... + + fprintf(outfile, "%c", blue); + fprintf(outfile, "%c", green); + fprintf(outfile, "%c", red); + } + if (extrabytes) // See above - BMP lines must be of lengths divisible by 4. + { + for (n = 1; n <= extrabytes; n++) { + fprintf(outfile, "%c", 0); + } + } + } + + fclose(outfile); + return 0; +} + +// write bmp, input - RGB, device +int writeBMPi(const char *filename, const unsigned char *d_RGB, int pitch, + int width, int height) { + unsigned int headers[13]; + FILE *outfile; + int extrabytes; + int paddedsize; + int x; + int y; + int n; + int red, green, blue; + + std::vector vchanRGB(height * width * 3); + unsigned char *chanRGB = vchanRGB.data(); + checkCudaErrors(cudaMemcpy2D(chanRGB, (size_t)width * 3, d_RGB, (size_t)pitch, + width * 3, height, cudaMemcpyDeviceToHost)); + + extrabytes = + 4 - ((width * 3) % 4); // How many bytes of padding to add to each + // horizontal line - the size of which must + // be a multiple of 4 bytes. + if (extrabytes == 4) extrabytes = 0; + + paddedsize = ((width * 3) + extrabytes) * height; + + // Headers... + // Note that the "BM" identifier in bytes 0 and 1 is NOT included in these + // "headers". + headers[0] = paddedsize + 54; // bfSize (whole file size) + headers[1] = 0; // bfReserved (both) + headers[2] = 54; // bfOffbits + headers[3] = 40; // biSize + headers[4] = width; // biWidth + headers[5] = height; // biHeight + + // Would have biPlanes and biBitCount in position 6, but they're shorts. + // It's easier to write them out separately (see below) than pretend + // they're a single int, especially with endian issues... + + headers[7] = 0; // biCompression + headers[8] = paddedsize; // biSizeImage + headers[9] = 0; // biXPelsPerMeter + headers[10] = 0; // biYPelsPerMeter + headers[11] = 0; // biClrUsed + headers[12] = 0; // biClrImportant + + if (!(outfile = fopen(filename, "wb"))) { + std::cerr << "Cannot open file: " << filename << std::endl; + return 1; + } + + // + // Headers begin... + // When printing ints and shorts, we write out 1 character at a time to avoid + // endian issues. + // + + fprintf(outfile, "BM"); + + for (n = 0; n <= 5; n++) { + fprintf(outfile, "%c", headers[n] & 0x000000FF); + fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); + fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); + fprintf(outfile, "%c", (headers[n] & (unsigned int)0xFF000000) >> 24); + } + + // These next 4 characters are for the biPlanes and biBitCount fields. + + fprintf(outfile, "%c", 1); + fprintf(outfile, "%c", 0); + fprintf(outfile, "%c", 24); + fprintf(outfile, "%c", 0); + + for (n = 7; n <= 12; n++) { + fprintf(outfile, "%c", headers[n] & 0x000000FF); + fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); + fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); + fprintf(outfile, "%c", (headers[n] & (unsigned int)0xFF000000) >> 24); + } + + // + // Headers done, now write the data... + // + for (y = height - 1; y >= 0; + y--) // BMP image format is written from bottom to top... + { + for (x = 0; x <= width - 1; x++) { + red = chanRGB[(y * width + x) * 3]; + green = chanRGB[(y * width + x) * 3 + 1]; + blue = chanRGB[(y * width + x) * 3 + 2]; + + if (red > 255) red = 255; + if (red < 0) red = 0; + if (green > 255) green = 255; + if (green < 0) green = 0; + if (blue > 255) blue = 255; + if (blue < 0) blue = 0; + // Also, it's written in (b,g,r) format... + + fprintf(outfile, "%c", blue); + fprintf(outfile, "%c", green); + fprintf(outfile, "%c", red); + } + if (extrabytes) // See above - BMP lines must be of lengths divisible by 4. + { + for (n = 1; n <= extrabytes; n++) { + fprintf(outfile, "%c", 0); + } + } + } + + fclose(outfile); + return 0; +} + +int readInput(const std::string &sInputPath, + std::vector &filelist) { + int error_code = 1; + struct stat s; + + if (stat(sInputPath.c_str(), &s) == 0) { + if (s.st_mode & S_IFREG) { + filelist.push_back(sInputPath); + } else if (s.st_mode & S_IFDIR) { + // processing each file in directory + DIR *dir_handle; + struct dirent *dir; + dir_handle = opendir(sInputPath.c_str()); + std::vector filenames; + if (dir_handle) { + error_code = 0; + while ((dir = readdir(dir_handle)) != NULL) { + if (dir->d_type == DT_REG) { + std::string sFileName = sInputPath + dir->d_name; + filelist.push_back(sFileName); + } else if (dir->d_type == DT_DIR) { + std::string sname = dir->d_name; + if (sname != "." && sname != "..") { + readInput(sInputPath + sname + "/", filelist); + } + } + } + closedir(dir_handle); + } else { + std::cout << "Cannot open input directory: " << sInputPath << std::endl; + return error_code; + } + } else { + std::cout << "Cannot open input: " << sInputPath << std::endl; + return error_code; + } + } else { + std::cout << "Cannot find input path " << sInputPath << std::endl; + return error_code; + } + + return 0; +} + +#endif diff --git a/Samples/p2pBandwidthLatencyTest/Makefile b/Samples/p2pBandwidthLatencyTest/Makefile index 07a4c9d5..5492855b 100644 --- a/Samples/p2pBandwidthLatencyTest/Makefile +++ b/Samples/p2pBandwidthLatencyTest/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/p2pBandwidthLatencyTest/NsightEclipse.xml b/Samples/p2pBandwidthLatencyTest/NsightEclipse.xml index 383a2972..7ce8df08 100644 --- a/Samples/p2pBandwidthLatencyTest/NsightEclipse.xml +++ b/Samples/p2pBandwidthLatencyTest/NsightEclipse.xml @@ -48,6 +48,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/p2pBandwidthLatencyTest/README.md b/Samples/p2pBandwidthLatencyTest/README.md index 47f0ca01..b0e56d10 100644 --- a/Samples/p2pBandwidthLatencyTest/README.md +++ b/Samples/p2pBandwidthLatencyTest/README.md @@ -10,7 +10,7 @@ Performance Strategies, Asynchronous Data Transfers, Unified Virtual Address Spa ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cudaDeviceCanAccessPeer, cudaDeviceEnablePeerAccess, cudaDeviceDisablePeerAccess ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2012.vcxproj b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2012.vcxproj index c763b1da..bd0efa07 100644 --- a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2012.vcxproj +++ b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2013.vcxproj b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2013.vcxproj index 2fa7ab33..5375cc4d 100644 --- a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2013.vcxproj +++ b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2015.vcxproj b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2015.vcxproj index e6db5568..e4675666 100644 --- a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2015.vcxproj +++ b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2017.vcxproj b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2017.vcxproj index 7b8ec8f6..412d8f97 100644 --- a/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2017.vcxproj +++ b/Samples/p2pBandwidthLatencyTest/p2pBandwidthLatencyTest_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/reduction/Makefile b/Samples/reduction/Makefile new file mode 100644 index 00000000..62142612 --- /dev/null +++ b/Samples/reduction/Makefile @@ -0,0 +1,307 @@ +################################################################################ +# Copyright (c) 2018, 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. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Location of the CUDA Toolkit +CUDA_PATH ?= /usr/local/cuda + +############################## +# start deprecated interface # +############################## +ifeq ($(x86_64),1) + $(info WARNING - x86_64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=x86_64 instead) + TARGET_ARCH ?= x86_64 +endif +ifeq ($(ARMv7),1) + $(info WARNING - ARMv7 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=armv7l instead) + TARGET_ARCH ?= armv7l +endif +ifeq ($(aarch64),1) + $(info WARNING - aarch64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=aarch64 instead) + TARGET_ARCH ?= aarch64 +endif +ifeq ($(ppc64le),1) + $(info WARNING - ppc64le variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=ppc64le instead) + TARGET_ARCH ?= ppc64le +endif +ifneq ($(GCC),) + $(info WARNING - GCC variable has been deprecated) + $(info WARNING - please use HOST_COMPILER=$(GCC) instead) + HOST_COMPILER ?= $(GCC) +endif +ifneq ($(abi),) + $(error ERROR - abi variable has been removed) +endif +############################ +# end deprecated interface # +############################ + +# architecture +HOST_ARCH := $(shell uname -m) +TARGET_ARCH ?= $(HOST_ARCH) +ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l)) + ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le)) + TARGET_SIZE := 64 + else ifneq (,$(filter $(TARGET_ARCH),armv7l)) + TARGET_SIZE := 32 + endif + else + TARGET_SIZE := $(shell getconf LONG_BIT) + endif +else + $(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!) +endif +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le)) + $(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!) + endif +endif + +# When on native aarch64 system with userspace of 32-bit, change TARGET_ARCH to armv7l +ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_SIZE),aarch64-aarch64-32) + TARGET_ARCH = armv7l +endif + +# operating system +HOST_OS := $(shell uname -s 2>/dev/null | tr "[:upper:]" "[:lower:]") +TARGET_OS ?= $(HOST_OS) +ifeq (,$(filter $(TARGET_OS),linux darwin qnx android)) + $(error ERROR - unsupported value $(TARGET_OS) for TARGET_OS!) +endif + +# host compiler +ifeq ($(TARGET_OS),darwin) + ifeq ($(shell expr `xcodebuild -version | grep -i xcode | awk '{print $$2}' | cut -d'.' -f1` \>= 5),1) + HOST_COMPILER ?= clang++ + endif +else ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(HOST_ARCH)-$(TARGET_ARCH),x86_64-armv7l) + ifeq ($(TARGET_OS),linux) + HOST_COMPILER ?= arm-linux-gnueabihf-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/arm-unknown-nto-qnx6.6.0eabi-g++ + else ifeq ($(TARGET_OS),android) + HOST_COMPILER ?= arm-linux-androideabi-g++ + endif + else ifeq ($(TARGET_ARCH),aarch64) + ifeq ($(TARGET_OS), linux) + HOST_COMPILER ?= aarch64-linux-gnu-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ + else ifeq ($(TARGET_OS), android) + HOST_COMPILER ?= aarch64-linux-android-clang++ + endif + else ifeq ($(TARGET_ARCH),ppc64le) + HOST_COMPILER ?= powerpc64le-linux-gnu-g++ + endif +endif +HOST_COMPILER ?= g++ +NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER) + +# internal flags +NVCCFLAGS := -m${TARGET_SIZE} +CCFLAGS := +LDFLAGS := + +# build flags +ifeq ($(TARGET_OS),darwin) + LDFLAGS += -rpath $(CUDA_PATH)/lib + CCFLAGS += -arch $(HOST_ARCH) +else ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_OS),x86_64-armv7l-linux) + LDFLAGS += --dynamic-linker=/lib/ld-linux-armhf.so.3 + CCFLAGS += -mfloat-abi=hard +else ifeq ($(TARGET_OS),android) + LDFLAGS += -pie + CCFLAGS += -fpie -fpic -fexceptions +endif + +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/arm-linux-gnueabihf + endif + endif + ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu + LDFLAGS += --unresolved-symbols=ignore-in-shared-libs + CCFLAGS += -isystem=$(TARGET_FS)/usr/include + CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu + endif + endif +endif + +ifeq ($(TARGET_OS),qnx) + CCFLAGS += -DWIN_INTERFACE_CUSTOM + LDFLAGS += -lsocket +endif + +# Install directory of different arch +CUDA_INSTALL_TARGET_DIR := +ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-qnx) + CUDA_INSTALL_TARGET_DIR = targets/ARMv7-linux-QNX/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-qnx/ +else ifeq ($(TARGET_ARCH),ppc64le) + CUDA_INSTALL_TARGET_DIR = targets/ppc64le-linux/ +endif + +# Debug build flags +ifeq ($(dbg),1) + NVCCFLAGS += -g -G + BUILD_TYPE := debug +else + BUILD_TYPE := release +endif + +ALL_CCFLAGS := +ALL_CCFLAGS += $(NVCCFLAGS) +ALL_CCFLAGS += $(EXTRA_NVCCFLAGS) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(CCFLAGS)) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) + +SAMPLE_ENABLED := 1 + +ALL_LDFLAGS := +ALL_LDFLAGS += $(ALL_CCFLAGS) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(EXTRA_LDFLAGS)) + +# Common includes and paths for CUDA +INCLUDES := -I../../Common +LIBRARIES := + +################################################################################ + +# Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else +SMS ?= 30 35 37 50 52 60 61 70 75 +endif + +ifeq ($(SMS),) +$(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) +SAMPLE_ENABLED := 0 +endif + +ifeq ($(GENCODE_FLAGS),) +# Generate SASS code for each SM architecture listed in $(SMS) +$(foreach sm,$(SMS),$(eval GENCODE_FLAGS += -gencode arch=compute_$(sm),code=sm_$(sm))) + +# Generate PTX code from the highest SM architecture in $(SMS) to guarantee forward-compatibility +HIGHEST_SM := $(lastword $(sort $(SMS))) +ifneq ($(HIGHEST_SM),) +GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM) +endif +endif + +ifeq ($(SAMPLE_ENABLED),0) +EXEC ?= @echo "[@]" +endif + +################################################################################ + +# Target rules +all: build + +build: reduction + +check.deps: +ifeq ($(SAMPLE_ENABLED),0) + @echo "Sample will be waived due to the above missing dependencies" +else + @echo "Sample is ready - all dependencies have been met" +endif + +reduction.o:reduction.cpp + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +reduction_kernel.o:reduction_kernel.cu + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +reduction: reduction.o reduction_kernel.o + $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o $@ $+ $(LIBRARIES) + $(EXEC) mkdir -p ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + $(EXEC) cp $@ ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + +run: build + $(EXEC) ./reduction + +clean: + rm -f reduction reduction.o reduction_kernel.o + rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/reduction + +clobber: clean diff --git a/Samples/reduction/NsightEclipse.xml b/Samples/reduction/NsightEclipse.xml new file mode 100644 index 00000000..48c36bb7 --- /dev/null +++ b/Samples/reduction/NsightEclipse.xml @@ -0,0 +1,67 @@ + + + + reduction + + whole + + ./ + ../ + ../../common/inc + + + Data-Parallel Algorithms + Performance Strategies + + + CUDA + GPGPU + Parallel Reduction + + + + + + true + reduction.cpp + + 1:CUDA Advanced Topics + 1:Data-Parallel Algorithms + 1:Performance Strategies + + sm30 + sm35 + sm37 + sm50 + sm52 + sm60 + sm61 + sm70 + sm72 + sm75 + + + x86_64 + linux + + + windows7 + + + x86_64 + macosx + + + arm + + + ppc64le + linux + + + + all + + CUDA Parallel Reduction + exe + diff --git a/Samples/reduction/README.md b/Samples/reduction/README.md new file mode 100644 index 00000000..7b6a7e8c --- /dev/null +++ b/Samples/reduction/README.md @@ -0,0 +1,91 @@ +# reduction - CUDA Parallel Reduction + +## Description + +A parallel sum reduction that computes the sum of a large arrays of values. This sample demonstrates several important optimization strategies for Data-Parallel Algorithms like reduction. + +## Key Concepts + +Data-Parallel Algorithms, Performance Strategies + +## Supported SM Architectures + +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) + +## Supported OSes + +Linux, Windows, MacOSX + +## Supported CPU Architecture + +x86_64, ppc64le, armv7l + +## CUDA APIs involved + +## Prerequisites + +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. + +## Build and Run + +### Windows +The Windows samples are built using the Visual Studio IDE. Solution files (.sln) are provided for each supported version of Visual Studio, using the format: +``` +*_vs.sln - for Visual Studio +``` +Each individual sample has its own set of solution files in its directory: + +To build/examine all the samples at once, the complete solution files should be used. To build/examine a single sample, the individual sample solution files should be used. +> **Note:** Some samples require that the Microsoft DirectX SDK (June 2010 or newer) be installed and that the VC++ directory paths are properly set up (**Tools > Options...**). Check DirectX Dependencies section for details." + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le, armv7l. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
`$ make TARGET_ARCH=armv7l`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + +### Mac +The Mac samples are built using makefiles. To use the makefiles, change directory into the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` + +The samples makefiles can take advantage of certain options: + +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` + +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where "A B ..." is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use SMS="50 60". + ``` + $ make SMS="A B ..." + ``` + +* **HOST_COMPILER=** - override the default clang host compiler. See the [Mac Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html#system-requirements) for a list of supported host compilers. + ``` + $ make HOST_COMPILER=clang + ``` + +## References (for more details) + diff --git a/Samples/reduction/reduction.cpp b/Samples/reduction/reduction.cpp new file mode 100644 index 00000000..972ae361 --- /dev/null +++ b/Samples/reduction/reduction.cpp @@ -0,0 +1,563 @@ +/* Copyright (c) 2019, 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. + */ + +/* + Parallel reduction + + This sample shows how to perform a reduction operation on an array of values + to produce a single value. + + Reductions are a very common computation in parallel algorithms. Any time + an array of values needs to be reduced to a single value using a binary + associative operator, a reduction can be used. Example applications include + statistics computations such as mean and standard deviation, and image + processing applications such as finding the total luminance of an + image. + + This code performs sum reductions, but any associative operator such as + min() or max() could also be used. + + It assumes the input size is a power of 2. + + COMMAND LINE ARGUMENTS + + "--shmoo": Test performance for 1 to 32M elements with each of the 7 + different kernels + "--n=": Specify the number of elements to reduce (default + 1048576) + "--threads=": Specify the number of threads per block (default 128) + "--kernel=": Specify which kernel to run (0-6, default 6) + "--maxblocks=": Specify the maximum number of thread blocks to launch + (kernel 6 only, default 64) + "--cpufinal": Read back the per-block results and do final sum of block + sums on CPU (default false) + "--cputhresh=": The threshold of number of blocks sums below which to + perform a CPU final reduction (default 1) + "-type=": The datatype for the reduction, where T is "int", + "float", or "double" (default int) +*/ + +// CUDA Runtime +#include + +// Utilities and system includes +#include +#include +#include + +// includes, project +#include "reduction.h" + +enum ReduceType { REDUCE_INT, REDUCE_FLOAT, REDUCE_DOUBLE }; + +//////////////////////////////////////////////////////////////////////////////// +// declaration, forward +template +bool runTest(int argc, char **argv, ReduceType datatype); + +#define MAX_BLOCK_DIM_SIZE 65535 + +#ifdef WIN32 +#define strcasecmp strcmpi +#endif + +extern "C" bool isPow2(unsigned int x) { return ((x & (x - 1)) == 0); } + +const char *getReduceTypeString(const ReduceType type) { + switch (type) { + case REDUCE_INT: + return "int"; + case REDUCE_FLOAT: + return "float"; + case REDUCE_DOUBLE: + return "double"; + default: + return "unknown"; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Program main +//////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) { + printf("%s Starting...\n\n", argv[0]); + + char *typeInput = 0; + getCmdLineArgumentString(argc, (const char **)argv, "type", &typeInput); + + ReduceType datatype = REDUCE_INT; + + if (0 != typeInput) { + if (!strcasecmp(typeInput, "float")) { + datatype = REDUCE_FLOAT; + } else if (!strcasecmp(typeInput, "double")) { + datatype = REDUCE_DOUBLE; + } else if (strcasecmp(typeInput, "int")) { + printf("Type %s is not recognized. Using default type int.\n\n", + typeInput); + } + } + + cudaDeviceProp deviceProp; + int dev; + + dev = findCudaDevice(argc, (const char **)argv); + + checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev)); + + printf("Using Device %d: %s\n\n", dev, deviceProp.name); + checkCudaErrors(cudaSetDevice(dev)); + + printf("Reducing array of type %s\n\n", getReduceTypeString(datatype)); + + bool bResult = false; + + switch (datatype) { + default: + case REDUCE_INT: + bResult = runTest(argc, argv, datatype); + break; + + case REDUCE_FLOAT: + bResult = runTest(argc, argv, datatype); + break; + + case REDUCE_DOUBLE: + bResult = runTest(argc, argv, datatype); + break; + } + + printf(bResult ? "Test passed\n" : "Test failed!\n"); +} + +//////////////////////////////////////////////////////////////////////////////// +//! Compute sum reduction on CPU +//! We use Kahan summation for an accurate sum of large arrays. +//! http://en.wikipedia.org/wiki/Kahan_summation_algorithm +//! +//! @param data pointer to input data +//! @param size number of input data elements +//////////////////////////////////////////////////////////////////////////////// +template +T reduceCPU(T *data, int size) { + T sum = data[0]; + T c = (T)0.0; + + for (int i = 1; i < size; i++) { + T y = data[i] - c; + T t = sum + y; + c = (t - sum) - y; + sum = t; + } + + return sum; +} + +unsigned int nextPow2(unsigned int x) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + +#ifndef MIN +#define MIN(x, y) ((x < y) ? x : y) +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Compute the number of threads and blocks to use for the given reduction +// kernel For the kernels >= 3, we set threads / block to the minimum of +// maxThreads and n/2. For kernels < 3, we set to the minimum of maxThreads and +// n. For kernel 6, we observe the maximum specified number of blocks, because +// each thread in that kernel can process a variable number of elements. +//////////////////////////////////////////////////////////////////////////////// +void getNumBlocksAndThreads(int whichKernel, int n, int maxBlocks, + int maxThreads, int &blocks, int &threads) { + // get device capability, to avoid block/grid size exceed the upper bound + cudaDeviceProp prop; + int device; + checkCudaErrors(cudaGetDevice(&device)); + checkCudaErrors(cudaGetDeviceProperties(&prop, device)); + + if (whichKernel < 3) { + threads = (n < maxThreads) ? nextPow2(n) : maxThreads; + blocks = (n + threads - 1) / threads; + } else { + threads = (n < maxThreads * 2) ? nextPow2((n + 1) / 2) : maxThreads; + blocks = (n + (threads * 2 - 1)) / (threads * 2); + } + + if ((float)threads * blocks > + (float)prop.maxGridSize[0] * prop.maxThreadsPerBlock) { + printf("n is too large, please choose a smaller number!\n"); + } + + if (blocks > prop.maxGridSize[0]) { + printf( + "Grid size <%d> exceeds the device capability <%d>, set block size as " + "%d (original %d)\n", + blocks, prop.maxGridSize[0], threads * 2, threads); + + blocks /= 2; + threads *= 2; + } + + if (whichKernel == 6) { + blocks = MIN(maxBlocks, blocks); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// This function performs a reduction of the input data multiple times and +// measures the average reduction time. +//////////////////////////////////////////////////////////////////////////////// +template +T benchmarkReduce(int n, int numThreads, int numBlocks, int maxThreads, + int maxBlocks, int whichKernel, int testIterations, + bool cpuFinalReduction, int cpuFinalThreshold, + StopWatchInterface *timer, T *h_odata, T *d_idata, + T *d_odata) { + T gpu_result = 0; + bool needReadBack = true; + + T *d_intermediateSums; + checkCudaErrors( + cudaMalloc((void **)&d_intermediateSums, sizeof(T) * numBlocks)); + + for (int i = 0; i < testIterations; ++i) { + gpu_result = 0; + + cudaDeviceSynchronize(); + sdkStartTimer(&timer); + + // execute the kernel + reduce(n, numThreads, numBlocks, whichKernel, d_idata, d_odata); + + // check if kernel execution generated an error + getLastCudaError("Kernel execution failed"); + + if (cpuFinalReduction) { + // sum partial sums from each block on CPU + // copy result from device to host + checkCudaErrors(cudaMemcpy(h_odata, d_odata, numBlocks * sizeof(T), + cudaMemcpyDeviceToHost)); + + for (int i = 0; i < numBlocks; i++) { + gpu_result += h_odata[i]; + } + + needReadBack = false; + } else { + // sum partial block sums on GPU + int s = numBlocks; + int kernel = whichKernel; + + while (s > cpuFinalThreshold) { + int threads = 0, blocks = 0; + getNumBlocksAndThreads(kernel, s, maxBlocks, maxThreads, blocks, + threads); + checkCudaErrors(cudaMemcpy(d_intermediateSums, d_odata, s * sizeof(T), + cudaMemcpyDeviceToDevice)); + reduce(s, threads, blocks, kernel, d_intermediateSums, d_odata); + + if (kernel < 3) { + s = (s + threads - 1) / threads; + } else { + s = (s + (threads * 2 - 1)) / (threads * 2); + } + } + + if (s > 1) { + // copy result from device to host + checkCudaErrors(cudaMemcpy(h_odata, d_odata, s * sizeof(T), + cudaMemcpyDeviceToHost)); + + for (int i = 0; i < s; i++) { + gpu_result += h_odata[i]; + } + + needReadBack = false; + } + } + + cudaDeviceSynchronize(); + sdkStopTimer(&timer); + } + + if (needReadBack) { + // copy final sum from device to host + checkCudaErrors( + cudaMemcpy(&gpu_result, d_odata, sizeof(T), cudaMemcpyDeviceToHost)); + } + checkCudaErrors(cudaFree(d_intermediateSums)); + return gpu_result; +} + +//////////////////////////////////////////////////////////////////////////////// +// This function calls benchmarkReduce multiple times for a range of array sizes +// and prints a report in CSV (comma-separated value) format that can be used +// for generating a "shmoo" plot showing the performance for each kernel +// variation over a wide range of input sizes. +//////////////////////////////////////////////////////////////////////////////// +template +void shmoo(int minN, int maxN, int maxThreads, int maxBlocks, + ReduceType datatype) { + // create random input data on CPU + unsigned int bytes = maxN * sizeof(T); + + T *h_idata = (T *)malloc(bytes); + + for (int i = 0; i < maxN; i++) { + // Keep the numbers small so we don't get truncation error in the sum + if (datatype == REDUCE_INT) { + h_idata[i] = (T)(rand() & 0xFF); + } else { + h_idata[i] = (rand() & 0xFF) / (T)RAND_MAX; + } + } + + int maxNumBlocks = MIN(maxN / maxThreads, MAX_BLOCK_DIM_SIZE); + + // allocate mem for the result on host side + T *h_odata = (T *)malloc(maxNumBlocks * sizeof(T)); + + // allocate device memory and data + T *d_idata = NULL; + T *d_odata = NULL; + + checkCudaErrors(cudaMalloc((void **)&d_idata, bytes)); + checkCudaErrors(cudaMalloc((void **)&d_odata, maxNumBlocks * sizeof(T))); + + // copy data directly to device memory + checkCudaErrors(cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(d_odata, h_idata, maxNumBlocks * sizeof(T), + cudaMemcpyHostToDevice)); + + // warm-up + for (int kernel = 0; kernel < 7; kernel++) { + reduce(maxN, maxThreads, maxNumBlocks, kernel, d_idata, d_odata); + } + + int testIterations = 100; + + StopWatchInterface *timer = 0; + sdkCreateTimer(&timer); + + // print headers + printf( + "Time in milliseconds for various numbers of elements for each " + "kernel\n\n\n"); + printf("Kernel"); + + for (int i = minN; i <= maxN; i *= 2) { + printf(", %d", i); + } + + for (int kernel = 0; kernel < 7; kernel++) { + printf("\n%d", kernel); + + for (int i = minN; i <= maxN; i *= 2) { + sdkResetTimer(&timer); + int numBlocks = 0; + int numThreads = 0; + getNumBlocksAndThreads(kernel, i, maxBlocks, maxThreads, numBlocks, + numThreads); + + float reduceTime; + + if (numBlocks <= MAX_BLOCK_DIM_SIZE) { + benchmarkReduce(i, numThreads, numBlocks, maxThreads, maxBlocks, kernel, + testIterations, false, 1, timer, h_odata, d_idata, + d_odata); + reduceTime = sdkGetAverageTimerValue(&timer); + } else { + reduceTime = -1.0; + } + + printf(", %.5f", reduceTime); + } + } + + // cleanup + sdkDeleteTimer(&timer); + free(h_idata); + free(h_odata); + + checkCudaErrors(cudaFree(d_idata)); + checkCudaErrors(cudaFree(d_odata)); +} + +//////////////////////////////////////////////////////////////////////////////// +// The main function which runs the reduction test. +//////////////////////////////////////////////////////////////////////////////// +template +bool runTest(int argc, char **argv, ReduceType datatype) { + int size = 1 << 24; // number of elements to reduce + int maxThreads = 256; // number of threads per block + int whichKernel = 6; + int maxBlocks = 64; + bool cpuFinalReduction = false; + int cpuFinalThreshold = 1; + + if (checkCmdLineFlag(argc, (const char **)argv, "n")) { + size = getCmdLineArgumentInt(argc, (const char **)argv, "n"); + } + + if (checkCmdLineFlag(argc, (const char **)argv, "threads")) { + maxThreads = getCmdLineArgumentInt(argc, (const char **)argv, "threads"); + } + + if (checkCmdLineFlag(argc, (const char **)argv, "kernel")) { + whichKernel = getCmdLineArgumentInt(argc, (const char **)argv, "kernel"); + } + + if (checkCmdLineFlag(argc, (const char **)argv, "maxblocks")) { + maxBlocks = getCmdLineArgumentInt(argc, (const char **)argv, "maxblocks"); + } + + printf("%d elements\n", size); + printf("%d threads (max)\n", maxThreads); + + cpuFinalReduction = checkCmdLineFlag(argc, (const char **)argv, "cpufinal"); + + if (checkCmdLineFlag(argc, (const char **)argv, "cputhresh")) { + cpuFinalThreshold = + getCmdLineArgumentInt(argc, (const char **)argv, "cputhresh"); + } + + bool runShmoo = checkCmdLineFlag(argc, (const char **)argv, "shmoo"); + + if (runShmoo) { + shmoo(1, 33554432, maxThreads, maxBlocks, datatype); + } else { + // create random input data on CPU + unsigned int bytes = size * sizeof(T); + + T *h_idata = (T *)malloc(bytes); + + for (int i = 0; i < size; i++) { + // Keep the numbers small so we don't get truncation error in the sum + if (datatype == REDUCE_INT) { + h_idata[i] = (T)(rand() & 0xFF); + } else { + h_idata[i] = (rand() & 0xFF) / (T)RAND_MAX; + } + } + + int numBlocks = 0; + int numThreads = 0; + getNumBlocksAndThreads(whichKernel, size, maxBlocks, maxThreads, numBlocks, + numThreads); + + if (numBlocks == 1) { + cpuFinalThreshold = 1; + } + + // allocate mem for the result on host side + T *h_odata = (T *)malloc(numBlocks * sizeof(T)); + + printf("%d blocks\n\n", numBlocks); + + // allocate device memory and data + T *d_idata = NULL; + T *d_odata = NULL; + + checkCudaErrors(cudaMalloc((void **)&d_idata, bytes)); + checkCudaErrors(cudaMalloc((void **)&d_odata, numBlocks * sizeof(T))); + + // copy data directly to device memory + checkCudaErrors( + cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice)); + checkCudaErrors(cudaMemcpy(d_odata, h_idata, numBlocks * sizeof(T), + cudaMemcpyHostToDevice)); + + // warm-up + reduce(size, numThreads, numBlocks, whichKernel, d_idata, d_odata); + + int testIterations = 100; + + StopWatchInterface *timer = 0; + sdkCreateTimer(&timer); + + T gpu_result = 0; + + gpu_result = + benchmarkReduce(size, numThreads, numBlocks, maxThreads, maxBlocks, + whichKernel, testIterations, cpuFinalReduction, + cpuFinalThreshold, timer, h_odata, d_idata, d_odata); + + double reduceTime = sdkGetAverageTimerValue(&timer) * 1e-3; + printf( + "Reduction, Throughput = %.4f GB/s, Time = %.5f s, Size = %u Elements, " + "NumDevsUsed = %d, Workgroup = %u\n", + 1.0e-9 * ((double)bytes) / reduceTime, reduceTime, size, 1, numThreads); + + // compute reference solution + T cpu_result = reduceCPU(h_idata, size); + + int precision = 0; + double threshold = 0; + double diff = 0; + + if (datatype == REDUCE_INT) { + printf("\nGPU result = %d\n", (int)gpu_result); + printf("CPU result = %d\n\n", (int)cpu_result); + } else { + if (datatype == REDUCE_FLOAT) { + precision = 8; + threshold = 1e-8 * size; + } else { + precision = 12; + threshold = 1e-12 * size; + } + + printf("\nGPU result = %.*f\n", precision, (double)gpu_result); + printf("CPU result = %.*f\n\n", precision, (double)cpu_result); + + diff = fabs((double)gpu_result - (double)cpu_result); + } + + // cleanup + sdkDeleteTimer(&timer); + free(h_idata); + free(h_odata); + + checkCudaErrors(cudaFree(d_idata)); + checkCudaErrors(cudaFree(d_odata)); + + if (datatype == REDUCE_INT) { + return (gpu_result == cpu_result); + } else { + return (diff < threshold); + } + } + + return true; +} diff --git a/Samples/reduction/reduction.h b/Samples/reduction/reduction.h new file mode 100644 index 00000000..9727bd58 --- /dev/null +++ b/Samples/reduction/reduction.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2019, 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 __REDUCTION_H__ +#define __REDUCTION_H__ + +template +void reduce(int size, int threads, int blocks, + int whichKernel, T *d_idata, T *d_odata); + +#endif diff --git a/Samples/reduction/reduction_kernel.cu b/Samples/reduction/reduction_kernel.cu new file mode 100644 index 00000000..0aaee929 --- /dev/null +++ b/Samples/reduction/reduction_kernel.cu @@ -0,0 +1,666 @@ +/* Copyright (c) 2019, 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. + */ + +/* + Parallel reduction kernels +*/ + +#ifndef _REDUCE_KERNEL_H_ +#define _REDUCE_KERNEL_H_ + +#include +#include + +namespace cg = cooperative_groups; + +// Utility class used to avoid linker errors with extern +// unsized shared memory arrays with templated type +template +struct SharedMemory { + __device__ inline operator T *() { + extern __shared__ int __smem[]; + return (T *)__smem; + } + + __device__ inline operator const T *() const { + extern __shared__ int __smem[]; + return (T *)__smem; + } +}; + +// specialize for double to avoid unaligned memory +// access compile errors +template <> +struct SharedMemory { + __device__ inline operator double *() { + extern __shared__ double __smem_d[]; + return (double *)__smem_d; + } + + __device__ inline operator const double *() const { + extern __shared__ double __smem_d[]; + return (double *)__smem_d; + } +}; + +/* + Parallel sum reduction using shared memory + - takes log(n) steps for n input elements + - uses n threads + - only works for power-of-2 arrays +*/ + +/* This reduction interleaves which threads are active by using the modulo + operator. This operator is very expensive on GPUs, and the interleaved + inactivity means that no whole warps are active, which is also very + inefficient */ +template +__global__ void reduce0(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // load shared mem + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + sdata[tid] = (i < n) ? g_idata[i] : 0; + + cg::sync(cta); + + // do reduction in shared mem + for (unsigned int s = 1; s < blockDim.x; s *= 2) { + // modulo arithmetic is slow! + if ((tid % (2 * s)) == 0) { + sdata[tid] += sdata[tid + s]; + } + + cg::sync(cta); + } + + // write result for this block to global mem + if (tid == 0) g_odata[blockIdx.x] = sdata[0]; +} + +/* This version uses contiguous threads, but its interleaved + addressing results in many shared memory bank conflicts. +*/ +template +__global__ void reduce1(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // load shared mem + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + sdata[tid] = (i < n) ? g_idata[i] : 0; + + cg::sync(cta); + + // do reduction in shared mem + for (unsigned int s = 1; s < blockDim.x; s *= 2) { + int index = 2 * s * tid; + + if (index < blockDim.x) { + sdata[index] += sdata[index + s]; + } + + cg::sync(cta); + } + + // write result for this block to global mem + if (tid == 0) g_odata[blockIdx.x] = sdata[0]; +} + +/* + This version uses sequential addressing -- no divergence or bank conflicts. +*/ +template +__global__ void reduce2(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // load shared mem + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; + + sdata[tid] = (i < n) ? g_idata[i] : 0; + + cg::sync(cta); + + // do reduction in shared mem + for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) { + if (tid < s) { + sdata[tid] += sdata[tid + s]; + } + + cg::sync(cta); + } + + // write result for this block to global mem + if (tid == 0) g_odata[blockIdx.x] = sdata[0]; +} + +/* + This version uses n/2 threads -- + it performs the first level of reduction when reading from global memory. +*/ +template +__global__ void reduce3(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // perform first level of reduction, + // reading from global memory, writing to shared memory + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * (blockDim.x * 2) + threadIdx.x; + + T mySum = (i < n) ? g_idata[i] : 0; + + if (i + blockDim.x < n) mySum += g_idata[i + blockDim.x]; + + sdata[tid] = mySum; + cg::sync(cta); + + // do reduction in shared mem + for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) { + if (tid < s) { + sdata[tid] = mySum = mySum + sdata[tid + s]; + } + + cg::sync(cta); + } + + // write result for this block to global mem + if (tid == 0) g_odata[blockIdx.x] = mySum; +} + +/* + This version uses the warp shuffle operation if available to reduce + warp synchronization. When shuffle is not available the final warp's + worth of work is unrolled to reduce looping overhead. + + See + http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/ + for additional information about using shuffle to perform a reduction + within a warp. + + Note, this kernel needs a minimum of 64*sizeof(T) bytes of shared memory. + In other words if blockSize <= 32, allocate 64*sizeof(T) bytes. + If blockSize > 32, allocate blockSize*sizeof(T) bytes. +*/ +template +__global__ void reduce4(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // perform first level of reduction, + // reading from global memory, writing to shared memory + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * (blockDim.x * 2) + threadIdx.x; + + T mySum = (i < n) ? g_idata[i] : 0; + + if (i + blockSize < n) mySum += g_idata[i + blockSize]; + + sdata[tid] = mySum; + cg::sync(cta); + + // do reduction in shared mem + for (unsigned int s = blockDim.x / 2; s > 32; s >>= 1) { + if (tid < s) { + sdata[tid] = mySum = mySum + sdata[tid + s]; + } + + cg::sync(cta); + } + + cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta); + + if (cta.thread_rank() < 32) { + // Fetch final intermediate sum from 2nd warp + if (blockSize >= 64) mySum += sdata[tid + 32]; + // Reduce final warp using shuffle + for (int offset = tile32.size() / 2; offset > 0; offset /= 2) { + mySum += tile32.shfl_down(mySum, offset); + } + } + + // write result for this block to global mem + if (cta.thread_rank() == 0) g_odata[blockIdx.x] = mySum; +} + +/* + This version is completely unrolled, unless warp shuffle is available, then + shuffle is used within a loop. It uses a template parameter to achieve + optimal code for any (power of 2) number of threads. This requires a switch + statement in the host code to handle all the different thread block sizes at + compile time. When shuffle is available, it is used to reduce warp + synchronization. + + Note, this kernel needs a minimum of 64*sizeof(T) bytes of shared memory. + In other words if blockSize <= 32, allocate 64*sizeof(T) bytes. + If blockSize > 32, allocate blockSize*sizeof(T) bytes. +*/ +template +__global__ void reduce5(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // perform first level of reduction, + // reading from global memory, writing to shared memory + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * (blockSize * 2) + threadIdx.x; + + T mySum = (i < n) ? g_idata[i] : 0; + + if (i + blockSize < n) mySum += g_idata[i + blockSize]; + + sdata[tid] = mySum; + cg::sync(cta); + + // do reduction in shared mem + if ((blockSize >= 512) && (tid < 256)) { + sdata[tid] = mySum = mySum + sdata[tid + 256]; + } + + cg::sync(cta); + + if ((blockSize >= 256) && (tid < 128)) { + sdata[tid] = mySum = mySum + sdata[tid + 128]; + } + + cg::sync(cta); + + if ((blockSize >= 128) && (tid < 64)) { + sdata[tid] = mySum = mySum + sdata[tid + 64]; + } + + cg::sync(cta); + + cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta); + + if (cta.thread_rank() < 32) { + // Fetch final intermediate sum from 2nd warp + if (blockSize >= 64) mySum += sdata[tid + 32]; + // Reduce final warp using shuffle + for (int offset = tile32.size() / 2; offset > 0; offset /= 2) { + mySum += tile32.shfl_down(mySum, offset); + } + } + + // write result for this block to global mem + if (cta.thread_rank() == 0) g_odata[blockIdx.x] = mySum; +} + +/* + This version adds multiple elements per thread sequentially. This reduces + the overall cost of the algorithm while keeping the work complexity O(n) and + the step complexity O(log n). (Brent's Theorem optimization) + + Note, this kernel needs a minimum of 64*sizeof(T) bytes of shared memory. + In other words if blockSize <= 32, allocate 64*sizeof(T) bytes. + If blockSize > 32, allocate blockSize*sizeof(T) bytes. +*/ +template +__global__ void reduce6(T *g_idata, T *g_odata, unsigned int n) { + // Handle to thread block group + cg::thread_block cta = cg::this_thread_block(); + T *sdata = SharedMemory(); + + // perform first level of reduction, + // reading from global memory, writing to shared memory + unsigned int tid = threadIdx.x; + unsigned int i = blockIdx.x * blockSize * 2 + threadIdx.x; + unsigned int gridSize = blockSize * 2 * gridDim.x; + + T mySum = 0; + + // we reduce multiple elements per thread. The number is determined by the + // number of active thread blocks (via gridDim). More blocks will result + // in a larger gridSize and therefore fewer elements per thread + while (i < n) { + mySum += g_idata[i]; + + // ensure we don't read out of bounds -- this is optimized away for powerOf2 + // sized arrays + if (nIsPow2 || i + blockSize < n) mySum += g_idata[i + blockSize]; + + i += gridSize; + } + + // each thread puts its local sum into shared memory + sdata[tid] = mySum; + cg::sync(cta); + + // do reduction in shared mem + if ((blockSize >= 512) && (tid < 256)) { + sdata[tid] = mySum = mySum + sdata[tid + 256]; + } + + cg::sync(cta); + + if ((blockSize >= 256) && (tid < 128)) { + sdata[tid] = mySum = mySum + sdata[tid + 128]; + } + + cg::sync(cta); + + if ((blockSize >= 128) && (tid < 64)) { + sdata[tid] = mySum = mySum + sdata[tid + 64]; + } + + cg::sync(cta); + + cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta); + + if (cta.thread_rank() < 32) { + // Fetch final intermediate sum from 2nd warp + if (blockSize >= 64) mySum += sdata[tid + 32]; + // Reduce final warp using shuffle + for (int offset = tile32.size() / 2; offset > 0; offset /= 2) { + mySum += tile32.shfl_down(mySum, offset); + } + } + + // write result for this block to global mem + if (cta.thread_rank() == 0) g_odata[blockIdx.x] = mySum; +} + +extern "C" bool isPow2(unsigned int x); + +//////////////////////////////////////////////////////////////////////////////// +// Wrapper function for kernel launch +//////////////////////////////////////////////////////////////////////////////// +template +void reduce(int size, int threads, int blocks, int whichKernel, T *d_idata, + T *d_odata) { + dim3 dimBlock(threads, 1, 1); + dim3 dimGrid(blocks, 1, 1); + + // when there is only one warp per block, we need to allocate two warps + // worth of shared memory so that we don't index shared memory out of bounds + int smemSize = + (threads <= 32) ? 2 * threads * sizeof(T) : threads * sizeof(T); + + // choose which of the optimized versions of reduction to launch + switch (whichKernel) { + case 0: + reduce0<<>>(d_idata, d_odata, size); + break; + + case 1: + reduce1<<>>(d_idata, d_odata, size); + break; + + case 2: + reduce2<<>>(d_idata, d_odata, size); + break; + + case 3: + reduce3<<>>(d_idata, d_odata, size); + break; + + case 4: + switch (threads) { + case 512: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 256: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 128: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 64: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 32: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 16: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 8: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 4: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 2: + reduce4 + <<>>(d_idata, d_odata, size); + break; + + case 1: + reduce4 + <<>>(d_idata, d_odata, size); + break; + } + + break; + + case 5: + switch (threads) { + case 512: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 256: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 128: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 64: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 32: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 16: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 8: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 4: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 2: + reduce5 + <<>>(d_idata, d_odata, size); + break; + + case 1: + reduce5 + <<>>(d_idata, d_odata, size); + break; + } + + break; + + case 6: + default: + if (isPow2(size)) { + switch (threads) { + case 512: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 256: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 128: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 64: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 32: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 16: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 8: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 4: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 2: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 1: + reduce6 + <<>>(d_idata, d_odata, size); + break; + } + } else { + switch (threads) { + case 512: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 256: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 128: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 64: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 32: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 16: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 8: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 4: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 2: + reduce6 + <<>>(d_idata, d_odata, size); + break; + + case 1: + reduce6 + <<>>(d_idata, d_odata, size); + break; + } + } + + break; + } +} + +// Instantiate the reduction function for 3 types +template void reduce(int size, int threads, int blocks, int whichKernel, + int *d_idata, int *d_odata); + +template void reduce(int size, int threads, int blocks, int whichKernel, + float *d_idata, float *d_odata); + +template void reduce(int size, int threads, int blocks, int whichKernel, + double *d_idata, double *d_odata); + +#endif // #ifndef _REDUCE_KERNEL_H_ diff --git a/Samples/reduction/reduction_vs2012.sln b/Samples/reduction/reduction_vs2012.sln new file mode 100644 index 00000000..dbd1bfc4 --- /dev/null +++ b/Samples/reduction/reduction_vs2012.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reduction", "reduction_vs2012.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/reduction/reduction_vs2012.vcxproj b/Samples/reduction/reduction_vs2012.vcxproj new file mode 100644 index 00000000..9cc806f7 --- /dev/null +++ b/Samples/reduction/reduction_vs2012.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + reduction_vs2012 + reduction + + + + + Application + MultiByte + v110 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/reduction.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/reduction/reduction_vs2013.sln b/Samples/reduction/reduction_vs2013.sln new file mode 100644 index 00000000..a04f9b38 --- /dev/null +++ b/Samples/reduction/reduction_vs2013.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 13.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reduction", "reduction_vs2013.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/reduction/reduction_vs2013.vcxproj b/Samples/reduction/reduction_vs2013.vcxproj new file mode 100644 index 00000000..fc6ebd5a --- /dev/null +++ b/Samples/reduction/reduction_vs2013.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + reduction_vs2013 + reduction + + + + + Application + MultiByte + v120 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/reduction.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/reduction/reduction_vs2015.sln b/Samples/reduction/reduction_vs2015.sln new file mode 100644 index 00000000..528951f4 --- /dev/null +++ b/Samples/reduction/reduction_vs2015.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reduction", "reduction_vs2015.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/reduction/reduction_vs2015.vcxproj b/Samples/reduction/reduction_vs2015.vcxproj new file mode 100644 index 00000000..72804717 --- /dev/null +++ b/Samples/reduction/reduction_vs2015.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + reduction_vs2015 + reduction + + + + + Application + MultiByte + v140 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/reduction.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/reduction/reduction_vs2017.sln b/Samples/reduction/reduction_vs2017.sln new file mode 100644 index 00000000..4dc8b942 --- /dev/null +++ b/Samples/reduction/reduction_vs2017.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2017 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reduction", "reduction_vs2017.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/reduction/reduction_vs2017.vcxproj b/Samples/reduction/reduction_vs2017.vcxproj new file mode 100644 index 00000000..4f72d0b0 --- /dev/null +++ b/Samples/reduction/reduction_vs2017.vcxproj @@ -0,0 +1,109 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + reduction_vs2017 + reduction + + + + + Application + MultiByte + v141 + 10.0.15063.0 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/reduction.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/shfl_scan/Makefile b/Samples/shfl_scan/Makefile index fcb778ce..6e5df239 100644 --- a/Samples/shfl_scan/Makefile +++ b/Samples/shfl_scan/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/shfl_scan/NsightEclipse.xml b/Samples/shfl_scan/NsightEclipse.xml index f7e1801d..4899f979 100644 --- a/Samples/shfl_scan/NsightEclipse.xml +++ b/Samples/shfl_scan/NsightEclipse.xml @@ -42,6 +42,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/shfl_scan/README.md b/Samples/shfl_scan/README.md index f2726ddb..b70d5531 100644 --- a/Samples/shfl_scan/README.md +++ b/Samples/shfl_scan/README.md @@ -10,7 +10,7 @@ Data-Parallel Algorithms, Performance Strategies ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -24,7 +24,7 @@ x86_64, ppc64le, armv7l, aarch64 ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/shfl_scan/shfl_scan_vs2012.vcxproj b/Samples/shfl_scan/shfl_scan_vs2012.vcxproj index ffb126f9..f96b4c23 100644 --- a/Samples/shfl_scan/shfl_scan_vs2012.vcxproj +++ b/Samples/shfl_scan/shfl_scan_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/shfl_scan/shfl_scan_vs2013.vcxproj b/Samples/shfl_scan/shfl_scan_vs2013.vcxproj index 08f212cb..da289482 100644 --- a/Samples/shfl_scan/shfl_scan_vs2013.vcxproj +++ b/Samples/shfl_scan/shfl_scan_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/shfl_scan/shfl_scan_vs2015.vcxproj b/Samples/shfl_scan/shfl_scan_vs2015.vcxproj index 0debbb65..22742a7d 100644 --- a/Samples/shfl_scan/shfl_scan_vs2015.vcxproj +++ b/Samples/shfl_scan/shfl_scan_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/shfl_scan/shfl_scan_vs2017.vcxproj b/Samples/shfl_scan/shfl_scan_vs2017.vcxproj index 93573298..ddde4c99 100644 --- a/Samples/shfl_scan/shfl_scan_vs2017.vcxproj +++ b/Samples/shfl_scan/shfl_scan_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -104,6 +104,6 @@ - + diff --git a/Samples/simpleCUBLAS/NsightEclipse.xml b/Samples/simpleCUBLAS/NsightEclipse.xml index 06b96ee0..05c2a4fd 100644 --- a/Samples/simpleCUBLAS/NsightEclipse.xml +++ b/Samples/simpleCUBLAS/NsightEclipse.xml @@ -41,6 +41,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleCUBLAS/README.md b/Samples/simpleCUBLAS/README.md index 7acb9182..1dd206ac 100644 --- a/Samples/simpleCUBLAS/README.md +++ b/Samples/simpleCUBLAS/README.md @@ -10,7 +10,7 @@ Image Processing, CUBLAS Library ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ x86_64, ppc64le, armv7l, aarch64 ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/simpleCUBLAS/simpleCUBLAS_vs2012.vcxproj b/Samples/simpleCUBLAS/simpleCUBLAS_vs2012.vcxproj index 5b9f1601..36437c3e 100644 --- a/Samples/simpleCUBLAS/simpleCUBLAS_vs2012.vcxproj +++ b/Samples/simpleCUBLAS/simpleCUBLAS_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLAS/simpleCUBLAS_vs2013.vcxproj b/Samples/simpleCUBLAS/simpleCUBLAS_vs2013.vcxproj index ba1a17c4..072145b8 100644 --- a/Samples/simpleCUBLAS/simpleCUBLAS_vs2013.vcxproj +++ b/Samples/simpleCUBLAS/simpleCUBLAS_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLAS/simpleCUBLAS_vs2015.vcxproj b/Samples/simpleCUBLAS/simpleCUBLAS_vs2015.vcxproj index 24a93d51..23992ba8 100644 --- a/Samples/simpleCUBLAS/simpleCUBLAS_vs2015.vcxproj +++ b/Samples/simpleCUBLAS/simpleCUBLAS_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLAS/simpleCUBLAS_vs2017.vcxproj b/Samples/simpleCUBLAS/simpleCUBLAS_vs2017.vcxproj index d2beef3d..b20a411e 100644 --- a/Samples/simpleCUBLAS/simpleCUBLAS_vs2017.vcxproj +++ b/Samples/simpleCUBLAS/simpleCUBLAS_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/simpleCUBLASXT/NsightEclipse.xml b/Samples/simpleCUBLASXT/NsightEclipse.xml index 37cd8805..10f2775d 100644 --- a/Samples/simpleCUBLASXT/NsightEclipse.xml +++ b/Samples/simpleCUBLASXT/NsightEclipse.xml @@ -40,6 +40,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleCUBLASXT/README.md b/Samples/simpleCUBLASXT/README.md index 63260e6d..59c2f4e4 100644 --- a/Samples/simpleCUBLASXT/README.md +++ b/Samples/simpleCUBLASXT/README.md @@ -10,7 +10,7 @@ CUBLAS-XT Library ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ x86_64, ppc64le, aarch64 ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2012.vcxproj b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2012.vcxproj index 60731c2a..fa170b48 100644 --- a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2012.vcxproj +++ b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2013.vcxproj b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2013.vcxproj index 861f6692..d46d0908 100644 --- a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2013.vcxproj +++ b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2015.vcxproj b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2015.vcxproj index 747e9a4b..f1da4ca2 100644 --- a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2015.vcxproj +++ b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2017.vcxproj b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2017.vcxproj index 07c44de1..a33be8d2 100644 --- a/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2017.vcxproj +++ b/Samples/simpleCUBLASXT/simpleCUBLASXT_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/simpleCUFFT/Makefile b/Samples/simpleCUFFT/Makefile index f2a261a9..c235dab3 100644 --- a/Samples/simpleCUFFT/Makefile +++ b/Samples/simpleCUFFT/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/simpleCUFFT/NsightEclipse.xml b/Samples/simpleCUFFT/NsightEclipse.xml index 27a3e9ff..1d8ac3b1 100644 --- a/Samples/simpleCUFFT/NsightEclipse.xml +++ b/Samples/simpleCUFFT/NsightEclipse.xml @@ -39,6 +39,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleCUFFT/README.md b/Samples/simpleCUFFT/README.md index 95724675..d128956a 100644 --- a/Samples/simpleCUFFT/README.md +++ b/Samples/simpleCUFFT/README.md @@ -10,7 +10,7 @@ Image Processing, CUFFT Library ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ x86_64, ppc64le, armv7l, aarch64 ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/simpleCUFFT/simpleCUFFT_vs2012.vcxproj b/Samples/simpleCUFFT/simpleCUFFT_vs2012.vcxproj index a29e47cf..8eb2145f 100644 --- a/Samples/simpleCUFFT/simpleCUFFT_vs2012.vcxproj +++ b/Samples/simpleCUFFT/simpleCUFFT_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUFFT/simpleCUFFT_vs2013.vcxproj b/Samples/simpleCUFFT/simpleCUFFT_vs2013.vcxproj index cb78fb43..fc95fd17 100644 --- a/Samples/simpleCUFFT/simpleCUFFT_vs2013.vcxproj +++ b/Samples/simpleCUFFT/simpleCUFFT_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUFFT/simpleCUFFT_vs2015.vcxproj b/Samples/simpleCUFFT/simpleCUFFT_vs2015.vcxproj index 4d4ef344..bc54d35d 100644 --- a/Samples/simpleCUFFT/simpleCUFFT_vs2015.vcxproj +++ b/Samples/simpleCUFFT/simpleCUFFT_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCUFFT/simpleCUFFT_vs2017.vcxproj b/Samples/simpleCUFFT/simpleCUFFT_vs2017.vcxproj index 1f5b2dfc..c2e1fe04 100644 --- a/Samples/simpleCUFFT/simpleCUFFT_vs2017.vcxproj +++ b/Samples/simpleCUFFT/simpleCUFFT_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/simpleCudaGraphs/Makefile b/Samples/simpleCudaGraphs/Makefile index 9341732a..5a76d924 100644 --- a/Samples/simpleCudaGraphs/Makefile +++ b/Samples/simpleCudaGraphs/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/simpleCudaGraphs/NsightEclipse.xml b/Samples/simpleCudaGraphs/NsightEclipse.xml index 8c4e9870..9137ab80 100644 --- a/Samples/simpleCudaGraphs/NsightEclipse.xml +++ b/Samples/simpleCudaGraphs/NsightEclipse.xml @@ -49,6 +49,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleCudaGraphs/README.md b/Samples/simpleCudaGraphs/README.md index a4a226b4..8fbbc65b 100644 --- a/Samples/simpleCudaGraphs/README.md +++ b/Samples/simpleCudaGraphs/README.md @@ -10,7 +10,7 @@ CUDA Graphs, Stream Capture ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cudaStreamBeginCapture, cudaStreamEndCapture, cudaLaunchHostFunc, cudaGraphCreat ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/simpleCudaGraphs/simpleCudaGraphs.cu b/Samples/simpleCudaGraphs/simpleCudaGraphs.cu index 6db123f8..af6b4eb6 100644 --- a/Samples/simpleCudaGraphs/simpleCudaGraphs.cu +++ b/Samples/simpleCudaGraphs/simpleCudaGraphs.cu @@ -302,7 +302,7 @@ void cudaGraphsUsingStreamCapture(float *inputVec_h, float *inputVec_d, checkCudaErrors(cudaStreamCreate(&streamForGraph)); checkCudaErrors(cudaEventCreate(&reduceKernelEvent)); - checkCudaErrors(cudaStreamBeginCapture(stream1)); + checkCudaErrors(cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal)); checkCudaErrors(cudaMemcpyAsync(inputVec_d, inputVec_h, sizeof(float) * inputSize, cudaMemcpyDefault, @@ -396,4 +396,4 @@ int main(int argc, char **argv) { checkCudaErrors(cudaFree(outputVec_d)); checkCudaErrors(cudaFree(result_d)); return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2012.vcxproj b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2012.vcxproj index ec603e11..50897567 100644 --- a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2012.vcxproj +++ b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2013.vcxproj b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2013.vcxproj index def552f5..a72646da 100644 --- a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2013.vcxproj +++ b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2015.vcxproj b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2015.vcxproj index d3632742..135022ec 100644 --- a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2015.vcxproj +++ b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2017.vcxproj b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2017.vcxproj index 57c7e22a..12042576 100644 --- a/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2017.vcxproj +++ b/Samples/simpleCudaGraphs/simpleCudaGraphs_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/simpleD3D12/NsightEclipse.xml b/Samples/simpleD3D12/NsightEclipse.xml index 3fdff74f..902723ba 100644 --- a/Samples/simpleD3D12/NsightEclipse.xml +++ b/Samples/simpleD3D12/NsightEclipse.xml @@ -48,6 +48,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleD3D12/README.md b/Samples/simpleD3D12/README.md index 6e236a72..52cc6803 100644 --- a/Samples/simpleD3D12/README.md +++ b/Samples/simpleD3D12/README.md @@ -10,7 +10,7 @@ Graphics Interop, CUDA DX12 Interop, Image Processing ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cudaWaitExternalSemaphoresAsync, cudaSignalExternalSemaphoresAsync, cudaImportEx ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/simpleD3D12/simpleD3D12_vs2015.vcxproj b/Samples/simpleD3D12/simpleD3D12_vs2015.vcxproj index 522781de..f9074545 100644 --- a/Samples/simpleD3D12/simpleD3D12_vs2015.vcxproj +++ b/Samples/simpleD3D12/simpleD3D12_vs2015.vcxproj @@ -38,7 +38,7 @@ - + @@ -119,6 +119,6 @@ - + diff --git a/Samples/simpleD3D12/simpleD3D12_vs2017.vcxproj b/Samples/simpleD3D12/simpleD3D12_vs2017.vcxproj index 94e39cbe..64366956 100644 --- a/Samples/simpleD3D12/simpleD3D12_vs2017.vcxproj +++ b/Samples/simpleD3D12/simpleD3D12_vs2017.vcxproj @@ -39,7 +39,7 @@ - + @@ -120,6 +120,6 @@ - + diff --git a/Samples/simpleIPC/Makefile b/Samples/simpleIPC/Makefile new file mode 100644 index 00000000..12396b36 --- /dev/null +++ b/Samples/simpleIPC/Makefile @@ -0,0 +1,325 @@ +################################################################################ +# Copyright (c) 2018, 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. +# +################################################################################ +# +# Makefile project only supported on Mac OS X and Linux Platforms) +# +################################################################################ + +# Location of the CUDA Toolkit +CUDA_PATH ?= /usr/local/cuda + +############################## +# start deprecated interface # +############################## +ifeq ($(x86_64),1) + $(info WARNING - x86_64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=x86_64 instead) + TARGET_ARCH ?= x86_64 +endif +ifeq ($(ARMv7),1) + $(info WARNING - ARMv7 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=armv7l instead) + TARGET_ARCH ?= armv7l +endif +ifeq ($(aarch64),1) + $(info WARNING - aarch64 variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=aarch64 instead) + TARGET_ARCH ?= aarch64 +endif +ifeq ($(ppc64le),1) + $(info WARNING - ppc64le variable has been deprecated) + $(info WARNING - please use TARGET_ARCH=ppc64le instead) + TARGET_ARCH ?= ppc64le +endif +ifneq ($(GCC),) + $(info WARNING - GCC variable has been deprecated) + $(info WARNING - please use HOST_COMPILER=$(GCC) instead) + HOST_COMPILER ?= $(GCC) +endif +ifneq ($(abi),) + $(error ERROR - abi variable has been removed) +endif +############################ +# end deprecated interface # +############################ + +# architecture +HOST_ARCH := $(shell uname -m) +TARGET_ARCH ?= $(HOST_ARCH) +ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l)) + ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le)) + TARGET_SIZE := 64 + else ifneq (,$(filter $(TARGET_ARCH),armv7l)) + TARGET_SIZE := 32 + endif + else + TARGET_SIZE := $(shell getconf LONG_BIT) + endif +else + $(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!) +endif +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le)) + $(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!) + endif +endif + +# When on native aarch64 system with userspace of 32-bit, change TARGET_ARCH to armv7l +ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_SIZE),aarch64-aarch64-32) + TARGET_ARCH = armv7l +endif + +# operating system +HOST_OS := $(shell uname -s 2>/dev/null | tr "[:upper:]" "[:lower:]") +TARGET_OS ?= $(HOST_OS) +ifeq (,$(filter $(TARGET_OS),linux darwin qnx android)) + $(error ERROR - unsupported value $(TARGET_OS) for TARGET_OS!) +endif + +# host compiler +ifeq ($(TARGET_OS),darwin) + ifeq ($(shell expr `xcodebuild -version | grep -i xcode | awk '{print $$2}' | cut -d'.' -f1` \>= 5),1) + HOST_COMPILER ?= clang++ + endif +else ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(HOST_ARCH)-$(TARGET_ARCH),x86_64-armv7l) + ifeq ($(TARGET_OS),linux) + HOST_COMPILER ?= arm-linux-gnueabihf-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/arm-unknown-nto-qnx6.6.0eabi-g++ + else ifeq ($(TARGET_OS),android) + HOST_COMPILER ?= arm-linux-androideabi-g++ + endif + else ifeq ($(TARGET_ARCH),aarch64) + ifeq ($(TARGET_OS), linux) + HOST_COMPILER ?= aarch64-linux-gnu-g++ + else ifeq ($(TARGET_OS),qnx) + ifeq ($(QNX_HOST),) + $(error ERROR - QNX_HOST must be passed to the QNX host toolchain) + endif + ifeq ($(QNX_TARGET),) + $(error ERROR - QNX_TARGET must be passed to the QNX target toolchain) + endif + export QNX_HOST + export QNX_TARGET + HOST_COMPILER ?= $(QNX_HOST)/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ + else ifeq ($(TARGET_OS), android) + HOST_COMPILER ?= aarch64-linux-android-clang++ + endif + else ifeq ($(TARGET_ARCH),ppc64le) + HOST_COMPILER ?= powerpc64le-linux-gnu-g++ + endif +endif +HOST_COMPILER ?= g++ +NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(HOST_COMPILER) + +# internal flags +NVCCFLAGS := -m${TARGET_SIZE} +CCFLAGS := +LDFLAGS := + +# build flags +ifeq ($(TARGET_OS),darwin) + LDFLAGS += -rpath $(CUDA_PATH)/lib + CCFLAGS += -arch $(HOST_ARCH) +else ifeq ($(HOST_ARCH)-$(TARGET_ARCH)-$(TARGET_OS),x86_64-armv7l-linux) + LDFLAGS += --dynamic-linker=/lib/ld-linux-armhf.so.3 + CCFLAGS += -mfloat-abi=hard +else ifeq ($(TARGET_OS),android) + LDFLAGS += -pie + CCFLAGS += -fpie -fpic -fexceptions +endif + +ifneq ($(TARGET_ARCH),$(HOST_ARCH)) + ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/arm-linux-gnueabihf + endif + endif + ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + ifneq ($(TARGET_FS),) + GCCVERSIONLTEQ46 := $(shell expr `$(HOST_COMPILER) -dumpversion` \<= 4.6) + ifeq ($(GCCVERSIONLTEQ46),1) + CCFLAGS += --sysroot=$(TARGET_FS) + endif + LDFLAGS += --sysroot=$(TARGET_FS) + LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib + LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu + LDFLAGS += --unresolved-symbols=ignore-in-shared-libs + CCFLAGS += -isystem=$(TARGET_FS)/usr/include + CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu + endif + endif +endif + +ifeq ($(TARGET_OS),qnx) + CCFLAGS += -DWIN_INTERFACE_CUSTOM + LDFLAGS += -lsocket +endif + +# Install directory of different arch +CUDA_INSTALL_TARGET_DIR := +ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android) + CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux-androideabi/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-qnx) + CUDA_INSTALL_TARGET_DIR = targets/ARMv7-linux-QNX/ +else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx) + CUDA_INSTALL_TARGET_DIR = targets/aarch64-qnx/ +else ifeq ($(TARGET_ARCH),ppc64le) + CUDA_INSTALL_TARGET_DIR = targets/ppc64le-linux/ +endif + +# Debug build flags +ifeq ($(dbg),1) + NVCCFLAGS += -g -G + BUILD_TYPE := debug +else + BUILD_TYPE := release +endif + +ALL_CCFLAGS := +ALL_CCFLAGS += $(NVCCFLAGS) +ALL_CCFLAGS += $(EXTRA_NVCCFLAGS) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(CCFLAGS)) +ALL_CCFLAGS += $(addprefix -Xcompiler ,$(EXTRA_CCFLAGS)) + +SAMPLE_ENABLED := 1 + +# This sample is not supported on Mac OSX +ifeq ($(TARGET_OS),darwin) + $(info >>> WARNING - simpleIPC is not supported on Mac OSX - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +# This sample is not supported on ARMv7 +ifeq ($(TARGET_ARCH),armv7l) + $(info >>> WARNING - simpleIPC is not supported on ARMv7 - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +# This sample is not supported on aarch64 +ifeq ($(TARGET_ARCH),aarch64) + $(info >>> WARNING - simpleIPC is not supported on aarch64 - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + +ALL_LDFLAGS := +ALL_LDFLAGS += $(ALL_CCFLAGS) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) +ALL_LDFLAGS += $(addprefix -Xlinker ,$(EXTRA_LDFLAGS)) + +# Common includes and paths for CUDA +INCLUDES := -I../../Common +LIBRARIES := + +################################################################################ + +# Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else +SMS ?= 30 35 37 50 52 60 61 70 75 +endif + +ifeq ($(SMS),) +$(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) +SAMPLE_ENABLED := 0 +endif + +ifeq ($(GENCODE_FLAGS),) +# Generate SASS code for each SM architecture listed in $(SMS) +$(foreach sm,$(SMS),$(eval GENCODE_FLAGS += -gencode arch=compute_$(sm),code=sm_$(sm))) + +# Generate PTX code from the highest SM architecture in $(SMS) to guarantee forward-compatibility +HIGHEST_SM := $(lastword $(sort $(SMS))) +ifneq ($(HIGHEST_SM),) +GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM) +endif +endif + +ifeq ($(SAMPLE_ENABLED),0) +EXEC ?= @echo "[@]" +endif + +################################################################################ + +# Target rules +all: build + +build: simpleIPC + +check.deps: +ifeq ($(SAMPLE_ENABLED),0) + @echo "Sample will be waived due to the above missing dependencies" +else + @echo "Sample is ready - all dependencies have been met" +endif + +helper_multiprocess.o:../../Common/helper_multiprocess.cpp + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +simpleIPC.o:simpleIPC.cu + $(EXEC) $(NVCC) $(INCLUDES) $(ALL_CCFLAGS) $(GENCODE_FLAGS) -o $@ -c $< + +simpleIPC: helper_multiprocess.o simpleIPC.o + $(EXEC) $(NVCC) $(ALL_LDFLAGS) $(GENCODE_FLAGS) -o $@ $+ $(LIBRARIES) + $(EXEC) mkdir -p ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + $(EXEC) cp $@ ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE) + +run: build + $(EXEC) ./simpleIPC + +clean: + rm -f simpleIPC helper_multiprocess.o simpleIPC.o + rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/simpleIPC + +clobber: clean diff --git a/Samples/simpleIPC/NsightEclipse.xml b/Samples/simpleIPC/NsightEclipse.xml new file mode 100644 index 00000000..8ac258f2 --- /dev/null +++ b/Samples/simpleIPC/NsightEclipse.xml @@ -0,0 +1,74 @@ + + + + simpleIPC + + cudaIpcGetEventHandle + cudaIpcOpenMemHandle + cudaIpcCloseMemHandle + cudaMemcpyAsync + + + whole + + ../../Common/helper_multiprocess.cpp + + + ./ + ../ + ../../common/inc + + + CUDA Systems Integration + Peer to Peer + InterProcess Communication + + + GPGPU + + + + + + true + simpleIPC.cu + + IPC + + + 1:CUDA Basic Topics + 1:CUDA Systems Integration + + sm30 + sm35 + sm37 + sm50 + sm52 + sm60 + sm61 + sm70 + sm72 + sm75 + + ../../Common/helper_multiprocess.cpp + ../../Common/helper_multiprocess.h + + + + x86_64 + linux + + + ppc64le + linux + + + windows7 + + + + all + + simpleIPC + exe + diff --git a/Samples/simpleIPC/README.md b/Samples/simpleIPC/README.md new file mode 100644 index 00000000..0542a9e1 --- /dev/null +++ b/Samples/simpleIPC/README.md @@ -0,0 +1,74 @@ +# simpleIPC - simpleIPC + +## Description + +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 + +## Key Concepts + +CUDA Systems Integration, Peer to Peer, InterProcess Communication + +## Supported SM Architectures + +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) + +## Supported OSes + +Linux, Windows + +## Supported CPU Architecture + +x86_64, ppc64le + +## CUDA APIs involved + +### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html) +cudaIpcGetEventHandle, cudaIpcOpenMemHandle, cudaIpcCloseMemHandle, cudaMemcpyAsync + +## Dependencies needed to build/run +[IPC](../../README.md#ipc) + +## Prerequisites + +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Make sure the dependencies mentioned in [Dependencies]() section above are installed. + +## Build and Run + +### Windows +The Windows samples are built using the Visual Studio IDE. Solution files (.sln) are provided for each supported version of Visual Studio, using the format: +``` +*_vs.sln - for Visual Studio +``` +Each individual sample has its own set of solution files in its directory: + +To build/examine all the samples at once, the complete solution files should be used. To build/examine a single sample, the individual sample solution files should be used. +> **Note:** Some samples require that the Microsoft DirectX SDK (June 2010 or newer) be installed and that the VC++ directory paths are properly set up (**Tools > Options...**). Check DirectX Dependencies section for details." + +### Linux +The Linux samples are built using makefiles. To use the makefiles, change the current directory to the sample directory you wish to build, and run make: +``` +$ cd +$ make +``` +The samples makefiles can take advantage of certain options: +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, ppc64le. + By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=ppc64le`
+ See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. +* **dbg=1** - build with debug symbols + ``` + $ make dbg=1 + ``` +* **SMS="A B ..."** - override the SM architectures for which the sample will be built, where `"A B ..."` is a space-delimited list of SM architectures. For example, to generate SASS for SM 50 and SM 60, use `SMS="50 60"`. + ``` + $ make SMS="50 60" + ``` + +* **HOST_COMPILER=** - override the default g++ host compiler. See the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#system-requirements) for a list of supported host compilers. +``` + $ make HOST_COMPILER=g++ +``` + +## References (for more details) + diff --git a/Samples/simpleIPC/simpleIPC.cu b/Samples/simpleIPC/simpleIPC.cu new file mode 100644 index 00000000..5dd71352 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC.cu @@ -0,0 +1,336 @@ +/* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This sample demonstrates Inter Process Communication + * using one process per GPU for computation. + */ +#include +#include +#include +#include "helper_cuda.h" +#include "helper_multiprocess.h" +static const char shmName[] = "simpleIPCshm"; +// For direct NVLINK and PCI-E peers, at max 8 simultaneous peers are allowed +// For NVSWITCH connected peers like DGX-2, simultaneous peers are not limited +// in the same way. +#define MAX_DEVICES (32) +#define DATA_SIZE (64ULL << 20ULL) // 64MB + +#if defined(__linux__) +#define cpu_atomic_add32(a, x) __sync_add_and_fetch(a, x) +#elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define cpu_atomic_add32(a, x) InterlockedAdd((volatile LONG *)a, x) +#else +#error Unsupported system +#endif + +typedef struct shmStruct_st { + size_t nprocesses; + int barrier; + int sense; + int devices[MAX_DEVICES]; + cudaIpcMemHandle_t memHandle[MAX_DEVICES]; + cudaIpcEventHandle_t eventHandle[MAX_DEVICES]; +} shmStruct; + +__global__ void simpleKernel(char *ptr, int sz, char val) { + int idx = blockIdx.x * blockDim.x + threadIdx.x; + for (; idx < sz; idx += (gridDim.x * blockDim.x)) { + ptr[idx] = val; + } +} + +static void barrierWait(volatile int *barrier, volatile int *sense, + unsigned int n) { + int count; + + // Check-in + count = cpu_atomic_add32(barrier, 1); + if (count == n) // Last one in + *sense = 1; + while (!*sense) + ; + + // Check-out + count = cpu_atomic_add32(barrier, -1); + if (count == 0) // Last one out + *sense = 0; + while (*sense) + ; +} + +static void childProcess(int id) { + volatile shmStruct *shm = NULL; + cudaStream_t stream; + sharedMemoryInfo info; + size_t procCount, i; + int blocks = 0; + int threads = 128; + cudaDeviceProp prop; + std::vector ptrs; + std::vector events; + std::vector verification_buffer(DATA_SIZE); + + if (sharedMemoryOpen(shmName, sizeof(shmStruct), &info) != 0) { + printf("Failed to create shared memory slab\n"); + exit(EXIT_FAILURE); + } + shm = (volatile shmStruct *)info.addr; + procCount = shm->nprocesses; + + printf("Process %d: Starting on device %d...\n", id, shm->devices[id]); + + checkCudaErrors(cudaSetDevice(shm->devices[id])); + checkCudaErrors(cudaGetDeviceProperties(&prop, shm->devices[id])); + checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); + checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor( + &blocks, simpleKernel, threads, 0)); + blocks *= prop.multiProcessorCount; + + // Open and track all the allocations and events created in the master + // process for use later + for (i = 0; i < procCount; i++) { + void *ptr = NULL; + cudaEvent_t event; + + // Notice, we don't need to explicitly enable peer access for + // allocations on other devices. + checkCudaErrors( + cudaIpcOpenMemHandle(&ptr, *(cudaIpcMemHandle_t *)&shm->memHandle[i], + cudaIpcMemLazyEnablePeerAccess)); + checkCudaErrors(cudaIpcOpenEventHandle( + &event, *(cudaIpcEventHandle_t *)&shm->eventHandle[i])); + + ptrs.push_back(ptr); + events.push_back(event); + } + + // At each iteration of the loop, each sibling process will push work on + // their respective devices accessing the next peer mapped buffer allocated + // by the master process (these can come from other sibling processes as + // well). To coordinate each process' access, we force the stream to wait for + // the work already accessing this buffer asynchronously through IPC events, + // allowing the CPU processes to continue to queue more work. + for (i = 0; i < procCount; i++) { + size_t bufferId = (i + id) % procCount; + // Wait for the buffer to be accessed to be ready + checkCudaErrors(cudaStreamWaitEvent(stream, events[bufferId], 0)); + // Push a simple kernel on it + simpleKernel<<>>((char *)ptrs[bufferId], + DATA_SIZE, id); + checkCudaErrors(cudaGetLastError()); + // Signal that this buffer is ready for the next consumer + checkCudaErrors(cudaEventRecord(events[bufferId], stream)); + // Wait for all my sibling processes to push this stage of their work + // before proceeding to the next. This prevents siblings from racing + // ahead and clobbering the recorded event or waiting on the wrong + // recorded event. + barrierWait(&shm->barrier, &shm->sense, (unsigned int)procCount); + if (id == 0) { + printf("Step %lld done\n", (unsigned long long)i); + } + } + + // Now wait for my buffer to be ready so I can copy it locally and verify it + checkCudaErrors(cudaStreamWaitEvent(stream, events[id], 0)); + checkCudaErrors(cudaMemcpyAsync(&verification_buffer[0], ptrs[id], DATA_SIZE, + cudaMemcpyDeviceToHost, stream)); + // And wait for all the queued up work to complete + checkCudaErrors(cudaStreamSynchronize(stream)); + + printf("Process %d: verifying...\n", id); + + // The contents should have the id of the sibling just after me + char compareId = (char)((id + 1) % procCount); + for (unsigned long long j = 0; j < DATA_SIZE; j++) { + if (verification_buffer[j] != compareId) { + printf("Process %d: Verification mismatch at %lld: %d != %d\n", id, j, + (int)verification_buffer[j], (int)compareId); + } + } + + // Clean up! + for (i = 0; i < procCount; i++) { + checkCudaErrors(cudaIpcCloseMemHandle(ptrs[i])); + checkCudaErrors(cudaEventDestroy(events[i])); + } + + checkCudaErrors(cudaStreamDestroy(stream)); + + printf("Process %d complete!\n", id); +} + +static void parentProcess(char *app) { + sharedMemoryInfo info; + int devCount, i; + volatile shmStruct *shm = NULL; + std::vector ptrs; + std::vector events; + std::vector processes; + + checkCudaErrors(cudaGetDeviceCount(&devCount)); + + if (sharedMemoryCreate(shmName, sizeof(*shm), &info) != 0) { + printf("Failed to create shared memory slab\n"); + exit(EXIT_FAILURE); + } + shm = (volatile shmStruct *)info.addr; + memset((void *)shm, 0, sizeof(*shm)); + + // Pick all the devices that can access each other's memory for this test + // Keep in mind that CUDA has minimal support for fork() without a + // corresponding exec() in the child process, but in this case our + // spawnProcess will always exec, so no need to worry. + for (i = 0; i < devCount; i++) { + bool allPeers = true; + cudaDeviceProp prop; + checkCudaErrors(cudaGetDeviceProperties(&prop, i)); + + // CUDA IPC is only supported on devices with unified addressing + if (!prop.unifiedAddressing) { + printf("Device %d does not support unified addressing, skipping...\n", i); + continue; + } + // This sample requires two processes accessing each device, so we need + // to ensure exclusive or prohibited mode is not set + if (prop.computeMode != cudaComputeModeDefault) { + printf("Device %d is in an unsupported compute mode for this sample\n", + i); + continue; + } +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) + // CUDA IPC on Windows is only supported on TCC + if (!prop.tccDriver) { + printf("Device %d is not in TCC mode\n", i); + continue; + } +#endif + + for (int j = 0; j < shm->nprocesses; j++) { + int canAccessPeerIJ, canAccessPeerJI; + checkCudaErrors( + cudaDeviceCanAccessPeer(&canAccessPeerJI, shm->devices[j], i)); + checkCudaErrors( + cudaDeviceCanAccessPeer(&canAccessPeerIJ, i, shm->devices[j])); + if (!canAccessPeerIJ || !canAccessPeerJI) { + allPeers = false; + break; + } + } + if (allPeers) { + // Enable peers here. This isn't necessary for IPC, but it will + // setup the peers for the device. For systems that only allow 8 + // peers per GPU at a time, this acts to remove devices from CanAccessPeer + for (int j = 0; j < shm->nprocesses; j++) { + checkCudaErrors(cudaSetDevice(i)); + checkCudaErrors(cudaDeviceEnablePeerAccess(shm->devices[j], 0)); + checkCudaErrors(cudaSetDevice(shm->devices[j])); + checkCudaErrors(cudaDeviceEnablePeerAccess(i, 0)); + } + shm->devices[shm->nprocesses++] = i; + if (shm->nprocesses >= MAX_DEVICES) break; + } else { + printf( + "Device %d is not peer capable with some other selected peers, " + "skipping\n", + i); + } + } + + if (shm->nprocesses == 0) { + printf("No CUDA devices support IPC\n"); + exit(EXIT_WAIVED); + } + + // Now allocate memory and an event for each process and fill the shared + // memory buffer with the IPC handles to communicate + for (i = 0; i < shm->nprocesses; i++) { + void *ptr = NULL; + cudaEvent_t event; + + checkCudaErrors(cudaSetDevice(shm->devices[i])); + checkCudaErrors(cudaMalloc(&ptr, DATA_SIZE)); + checkCudaErrors( + cudaIpcGetMemHandle((cudaIpcMemHandle_t *)&shm->memHandle[i], ptr)); + checkCudaErrors(cudaEventCreate( + &event, cudaEventDisableTiming | cudaEventInterprocess)); + checkCudaErrors(cudaIpcGetEventHandle( + (cudaIpcEventHandle_t *)&shm->eventHandle[i], event)); + + ptrs.push_back(ptr); + events.push_back(event); + } + + // Launch the child processes! + for (i = 0; i < shm->nprocesses; i++) { + char devIdx[10]; + char *const args[] = {app, devIdx, NULL}; + Process process; + + SPRINTF(devIdx, "%d", i); + + if (spawnProcess(&process, app, args)) { + printf("Failed to create process\n"); + exit(EXIT_FAILURE); + } + + processes.push_back(process); + } + + // And wait for them to finish + for (i = 0; i < processes.size(); i++) { + if (waitProcess(&processes[i]) != EXIT_SUCCESS) { + printf("Process %d failed!\n", i); + exit(EXIT_FAILURE); + } + } + + // Clean up! + for (i = 0; i < shm->nprocesses; i++) { + checkCudaErrors(cudaSetDevice(shm->devices[i])); + checkCudaErrors(cudaEventSynchronize(events[i])); + checkCudaErrors(cudaEventDestroy(events[i])); + checkCudaErrors(cudaFree(ptrs[i])); + } + + sharedMemoryClose(&info); +} + +int main(int argc, char **argv) { +#if defined(__arm__) || defined(__aarch64__) + printf("Not supported on ARM\n"); + return EXIT_WAIVED; +#else + if (argc == 1) { + parentProcess(argv[0]); + } else { + childProcess(atoi(argv[1])); + } + return EXIT_SUCCESS; +#endif +} diff --git a/Samples/simpleIPC/simpleIPC_vs2012.sln b/Samples/simpleIPC/simpleIPC_vs2012.sln new file mode 100644 index 00000000..d6650401 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2012.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleIPC", "simpleIPC_vs2012.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/simpleIPC/simpleIPC_vs2012.vcxproj b/Samples/simpleIPC/simpleIPC_vs2012.vcxproj new file mode 100644 index 00000000..9c5d7e4f --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2012.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + simpleIPC_vs2012 + simpleIPC + + + + + Application + MultiByte + v110 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/simpleIPC.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/simpleIPC/simpleIPC_vs2013.sln b/Samples/simpleIPC/simpleIPC_vs2013.sln new file mode 100644 index 00000000..16384816 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2013.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 13.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleIPC", "simpleIPC_vs2013.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/simpleIPC/simpleIPC_vs2013.vcxproj b/Samples/simpleIPC/simpleIPC_vs2013.vcxproj new file mode 100644 index 00000000..dadc5399 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2013.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + simpleIPC_vs2013 + simpleIPC + + + + + Application + MultiByte + v120 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/simpleIPC.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/simpleIPC/simpleIPC_vs2015.sln b/Samples/simpleIPC/simpleIPC_vs2015.sln new file mode 100644 index 00000000..d798eb74 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2015.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 2015 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleIPC", "simpleIPC_vs2015.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/simpleIPC/simpleIPC_vs2015.vcxproj b/Samples/simpleIPC/simpleIPC_vs2015.vcxproj new file mode 100644 index 00000000..7e2570cd --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2015.vcxproj @@ -0,0 +1,108 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + simpleIPC_vs2015 + simpleIPC + + + + + Application + MultiByte + v140 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/simpleIPC.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/simpleIPC/simpleIPC_vs2017.sln b/Samples/simpleIPC/simpleIPC_vs2017.sln new file mode 100644 index 00000000..93eb4ac5 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2017.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2017 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleIPC", "simpleIPC_vs2017.vcxproj", "{997E0757-EA74-4A4E-A0FC-47D8C8831A15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.ActiveCfg = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Debug|x64.Build.0 = Debug|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.ActiveCfg = Release|x64 + {997E0757-EA74-4A4E-A0FC-47D8C8831A15}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/simpleIPC/simpleIPC_vs2017.vcxproj b/Samples/simpleIPC/simpleIPC_vs2017.vcxproj new file mode 100644 index 00000000..e4366cd2 --- /dev/null +++ b/Samples/simpleIPC/simpleIPC_vs2017.vcxproj @@ -0,0 +1,109 @@ + + + + $(VCTargetsPath)\BuildCustomizations + + + + Debug + x64 + + + Release + x64 + + + + {997E0757-EA74-4A4E-A0FC-47D8C8831A15} + simpleIPC_vs2017 + simpleIPC + + + + + Application + MultiByte + v141 + 10.0.15063.0 + + + true + + + true + + + + + + + + + + + $(Platform)/$(Configuration)/ + $(IncludePath) + AllRules.ruleset + + + + + ../../bin/win64/$(Configuration)/ + + + + Level3 + WIN32;_MBCS;%(PreprocessorDefinitions) + ./;$(CudaToolkitDir)/include;../../Common; + + + Console + cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(CudaToolkitLibDir); + $(OutDir)/simpleIPC.exe + + + compute_30,sm_30;compute_35,sm_35;compute_37,sm_37;compute_50,sm_50;compute_52,sm_52;compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75; + -Xcompiler "/wd 4819" %(AdditionalOptions) + ./;../../Common + WIN32 + + + + + Disabled + MultiThreadedDebug + + + true + Default + + + MTd + 64 + + + + + MaxSpeed + MultiThreaded + + + false + UseLinkTimeCodeGeneration + + + MT + 64 + + + + + + + + + + + + diff --git a/Samples/simpleVoteIntrinsics/Makefile b/Samples/simpleVoteIntrinsics/Makefile index 288a0289..b953c296 100644 --- a/Samples/simpleVoteIntrinsics/Makefile +++ b/Samples/simpleVoteIntrinsics/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/simpleVoteIntrinsics/NsightEclipse.xml b/Samples/simpleVoteIntrinsics/NsightEclipse.xml index 3e5cadfe..f7c2618f 100644 --- a/Samples/simpleVoteIntrinsics/NsightEclipse.xml +++ b/Samples/simpleVoteIntrinsics/NsightEclipse.xml @@ -40,6 +40,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/simpleVoteIntrinsics/README.md b/Samples/simpleVoteIntrinsics/README.md index b9a4d9e6..1f11c718 100644 --- a/Samples/simpleVoteIntrinsics/README.md +++ b/Samples/simpleVoteIntrinsics/README.md @@ -10,7 +10,7 @@ Vote Intrinsics ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -27,7 +27,7 @@ cudaMalloc, cudaFree, cudaMemcpy, cudaFreeHost ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2012.vcxproj b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2012.vcxproj index ef5ca072..2fd4df8c 100644 --- a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2012.vcxproj +++ b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2013.vcxproj b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2013.vcxproj index c7dcd465..01d3b586 100644 --- a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2013.vcxproj +++ b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2015.vcxproj b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2015.vcxproj index c58c4a88..b9e89adb 100644 --- a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2015.vcxproj +++ b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2017.vcxproj b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2017.vcxproj index 184ad6a3..68cb2153 100644 --- a/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2017.vcxproj +++ b/Samples/simpleVoteIntrinsics/simpleVoteIntrinsics_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/simpleVulkan/Build_instructions.txt b/Samples/simpleVulkan/Build_instructions.txt index 2b19ed36..e7517d42 100644 --- a/Samples/simpleVulkan/Build_instructions.txt +++ b/Samples/simpleVulkan/Build_instructions.txt @@ -10,9 +10,14 @@ To add the GLFW3 headers path -- In Property pages window go to "VC++ Directories" section. Here in "Include Directories" edit and add path to GLFW3 headers include directory location. ** Make sure to add path to glfw3.dll in your PATH environment variable** - For Linux: -- Install the Vulkan SDK from https://www.lunarg.com/vulkan-sdk/ and follow environment setup instructions. -- Install GLFW3 library through your OS package repository. For example: apt-get for Ubuntu and dnf for RHEL/CentOS -- Install "libxcb1-dev" and "xorg-dev" as GLFW3 is depended on it --- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH \ No newline at end of file +-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH + +For Linux aarch64(L4T): +-- Install GLFW3 library using "apt-get install libglfw3-dev" this will provide glfw3 +-- install above will also provide libvulkan-dev as dependencies +-- Add Vulkan and GLFW3 libraries directories to LD_LIBRARY_PATH +-- Pass path to vulkan sdk while building 'make VULKAN_SDK_PATH=', VULKAN_SDK_PATH in this scenario is typically "/usr" diff --git a/Samples/simpleVulkan/Makefile b/Samples/simpleVulkan/Makefile index f4745812..f8c353f1 100644 --- a/Samples/simpleVulkan/Makefile +++ b/Samples/simpleVulkan/Makefile @@ -246,9 +246,9 @@ ifeq ($(TARGET_ARCH),armv7l) SAMPLE_ENABLED := 0 endif -# This sample is not supported on aarch64 -ifeq ($(TARGET_ARCH),aarch64) - $(info >>> WARNING - simpleVulkan is not supported on aarch64 - waiving sample <<<) +# This sample is not supported on QNX +ifeq ($(TARGET_OS),qnx) + $(info >>> WARNING - simpleVulkan is not supported on QNX - waiving sample <<<) SAMPLE_ENABLED := 0 endif @@ -301,7 +301,11 @@ ifeq ($(TARGET_OS),linux) endif # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) @@ -331,8 +335,6 @@ endif all: build build: simpleVulkan - $(EXEC) $(VULKAN_SDK_PATH)/bin/glslangValidator -V shader_sine.vert - $(EXEC) $(VULKAN_SDK_PATH)/bin/glslangValidator -V shader_sine.frag check.deps: ifeq ($(SAMPLE_ENABLED),0) @@ -355,7 +357,5 @@ run: build clean: rm -f simpleVulkan vulkanCUDASinewave.o rm -rf ../../bin/$(TARGET_ARCH)/$(TARGET_OS)/$(BUILD_TYPE)/simpleVulkan - rm -rf vert.spv - rm -rf frag.spv clobber: clean diff --git a/Samples/simpleVulkan/NsightEclipse.xml b/Samples/simpleVulkan/NsightEclipse.xml index 7682326e..34f7fae4 100644 --- a/Samples/simpleVulkan/NsightEclipse.xml +++ b/Samples/simpleVulkan/NsightEclipse.xml @@ -38,14 +38,6 @@ true - - $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.vert - $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - $(VULKAN_SDK_PATH)/bin/glslangValidator -V shader_sine.vert - $(VULKAN_SDK_PATH)/bin/glslangValidator -V shader_sine.frag - rm -rf vert.spv - rm -rf frag.spv - vulkanCUDASinewave.cu X11 @@ -64,6 +56,7 @@ sm60 sm61 sm70 + sm72 sm75 @@ -73,6 +66,9 @@ windows7 + + aarch64 + all diff --git a/Samples/simpleVulkan/README.md b/Samples/simpleVulkan/README.md index 766f826f..eb76cce8 100644 --- a/Samples/simpleVulkan/README.md +++ b/Samples/simpleVulkan/README.md @@ -10,7 +10,7 @@ Graphics Interop, CUDA Vulkan Interop, Data Parallel Algorithms ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -18,7 +18,7 @@ Linux, Windows ## Supported CPU Architecture -x86_64 +x86_64, aarch64 ## CUDA APIs involved @@ -30,7 +30,7 @@ cudaImportExternalMemory, cudaExternalMemoryGetMappedBuffer, cudaImportExternalS ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run @@ -52,9 +52,9 @@ $ cd $ make ``` The samples makefiles can take advantage of certain options: -* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64. +* **TARGET_ARCH=** - cross-compile targeting a specific architecture. Allowed architectures are x86_64, aarch64. By default, TARGET_ARCH is set to HOST_ARCH. On a x86_64 machine, not setting TARGET_ARCH is the equivalent of setting TARGET_ARCH=x86_64.
-`$ make TARGET_ARCH=x86_64`
+`$ make TARGET_ARCH=x86_64`
`$ make TARGET_ARCH=aarch64`
See [here](http://docs.nvidia.com/cuda/cuda-samples/index.html#cross-samples) for more details. * **dbg=1** - build with debug symbols ``` diff --git a/Samples/simpleVulkan/shader_sine.frag b/Samples/simpleVulkan/shader_sine.frag index 1730b4f1..b096569c 100644 --- a/Samples/simpleVulkan/shader_sine.frag +++ b/Samples/simpleVulkan/shader_sine.frag @@ -1,5 +1,6 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +#extension GL_NV_gpu_shader5 : enable layout(location = 0) in vec3 fragColor; diff --git a/Samples/simpleVulkan/shader_sine.vert b/Samples/simpleVulkan/shader_sine.vert index 80196343..849558b3 100644 --- a/Samples/simpleVulkan/shader_sine.vert +++ b/Samples/simpleVulkan/shader_sine.vert @@ -1,6 +1,6 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable - +#extension GL_NV_gpu_shader5 : enable layout(binding = 0) uniform UniformBufferObject { mat4 model; diff --git a/Samples/simpleVulkan/simpleVulkan_vs2013.vcxproj b/Samples/simpleVulkan/simpleVulkan_vs2013.vcxproj index 0f630f8c..7b35a538 100644 --- a/Samples/simpleVulkan/simpleVulkan_vs2013.vcxproj +++ b/Samples/simpleVulkan/simpleVulkan_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -67,11 +67,6 @@ ./;../../Common WIN32 - - $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.vert -$(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - - @@ -117,6 +112,6 @@ $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - + diff --git a/Samples/simpleVulkan/simpleVulkan_vs2015.vcxproj b/Samples/simpleVulkan/simpleVulkan_vs2015.vcxproj index 0e4e9d64..b09f4086 100644 --- a/Samples/simpleVulkan/simpleVulkan_vs2015.vcxproj +++ b/Samples/simpleVulkan/simpleVulkan_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -67,11 +67,6 @@ ./;../../Common WIN32 - - $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.vert -$(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - - @@ -117,6 +112,6 @@ $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - + diff --git a/Samples/simpleVulkan/simpleVulkan_vs2017.vcxproj b/Samples/simpleVulkan/simpleVulkan_vs2017.vcxproj index 7c45957f..c2f7bf78 100644 --- a/Samples/simpleVulkan/simpleVulkan_vs2017.vcxproj +++ b/Samples/simpleVulkan/simpleVulkan_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -68,11 +68,6 @@ ./;../../Common WIN32 - - $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.vert -$(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - - @@ -118,6 +113,6 @@ $(VULKAN_SDK)/Bin/glslangValidator.exe -V shader_sine.frag - + diff --git a/Samples/simpleVulkan/vulkanCUDASinewave.cu b/Samples/simpleVulkan/vulkanCUDASinewave.cu index a5755a27..fa266e93 100644 --- a/Samples/simpleVulkan/vulkanCUDASinewave.cu +++ b/Samples/simpleVulkan/vulkanCUDASinewave.cu @@ -883,8 +883,8 @@ class vulkanCudaApp { } void createGraphicsPipeline() { - auto vertShaderCode = readFile("vert.spv"); - auto fragShaderCode = readFile("frag.spv"); + auto vertShaderCode = readFile("shader_sine.vert"); + auto fragShaderCode = readFile("shader_sine.frag"); VkShaderModule vertShaderModule; VkShaderModule fragShaderModule; diff --git a/Samples/systemWideAtomics/Makefile b/Samples/systemWideAtomics/Makefile index ac55d319..162ab601 100644 --- a/Samples/systemWideAtomics/Makefile +++ b/Samples/systemWideAtomics/Makefile @@ -264,7 +264,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 60 61 70 72 75 +else SMS ?= 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/systemWideAtomics/NsightEclipse.xml b/Samples/systemWideAtomics/NsightEclipse.xml index b977c6da..5108b3af 100644 --- a/Samples/systemWideAtomics/NsightEclipse.xml +++ b/Samples/systemWideAtomics/NsightEclipse.xml @@ -39,6 +39,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/systemWideAtomics/README.md b/Samples/systemWideAtomics/README.md index 462eb23c..eaaa57ca 100644 --- a/Samples/systemWideAtomics/README.md +++ b/Samples/systemWideAtomics/README.md @@ -10,7 +10,7 @@ Atomic Intrinsics, Unified Memory ## Supported SM Architectures -[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.5 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cudaMalloc, cudaFree, cudaMemcpy, cudaFreeHost ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/vectorAdd_nvrtc/Makefile b/Samples/vectorAdd_nvrtc/Makefile index 5561b18a..a23cd7a5 100644 --- a/Samples/vectorAdd_nvrtc/Makefile +++ b/Samples/vectorAdd_nvrtc/Makefile @@ -242,6 +242,12 @@ ifeq ($(TARGET_ARCH),armv7l) SAMPLE_ENABLED := 0 endif +# This sample is not supported on QNX +ifeq ($(TARGET_OS),qnx) + $(info >>> WARNING - vectorAdd_nvrtc is not supported on QNX - waiving sample <<<) + SAMPLE_ENABLED := 0 +endif + ALL_LDFLAGS := ALL_LDFLAGS += $(ALL_CCFLAGS) ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS)) diff --git a/Samples/vectorAdd_nvrtc/README.md b/Samples/vectorAdd_nvrtc/README.md index aa9308d3..db3c0dc8 100644 --- a/Samples/vectorAdd_nvrtc/README.md +++ b/Samples/vectorAdd_nvrtc/README.md @@ -10,7 +10,7 @@ CUDA Driver API, Vector Addition, Runtime Compilation ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -30,7 +30,7 @@ cuMemAlloc, cuMemFree, cuMemcpyHtoD, cuMemcpyDtoH ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Make sure the dependencies mentioned in [Dependencies]() section above are installed. ## Build and Run diff --git a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2012.vcxproj b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2012.vcxproj index ae30b7a2..4ec98759 100644 --- a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2012.vcxproj +++ b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2013.vcxproj b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2013.vcxproj index 99e6a833..ee52dec6 100644 --- a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2013.vcxproj +++ b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2015.vcxproj b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2015.vcxproj index 3ba3e437..00564844 100644 --- a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2015.vcxproj +++ b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2017.vcxproj b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2017.vcxproj index 5caded61..c9d8a55b 100644 --- a/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2017.vcxproj +++ b/Samples/vectorAdd_nvrtc/vectorAdd_nvrtc_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - + diff --git a/Samples/warpAggregatedAtomicsCG/Makefile b/Samples/warpAggregatedAtomicsCG/Makefile index 5353f6fe..2cf3bbf5 100644 --- a/Samples/warpAggregatedAtomicsCG/Makefile +++ b/Samples/warpAggregatedAtomicsCG/Makefile @@ -246,7 +246,11 @@ LIBRARIES := ################################################################################ # Gencode arguments +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64)) +SMS ?= 30 35 37 50 52 60 61 70 72 75 +else SMS ?= 30 35 37 50 52 60 61 70 75 +endif ifeq ($(SMS),) $(info >>> WARNING - no SM architectures have been specified - waiving sample <<<) diff --git a/Samples/warpAggregatedAtomicsCG/NsightEclipse.xml b/Samples/warpAggregatedAtomicsCG/NsightEclipse.xml index 49a896d3..67bf4eed 100644 --- a/Samples/warpAggregatedAtomicsCG/NsightEclipse.xml +++ b/Samples/warpAggregatedAtomicsCG/NsightEclipse.xml @@ -34,6 +34,7 @@ sm60 sm61 sm70 + sm72 sm75 diff --git a/Samples/warpAggregatedAtomicsCG/README.md b/Samples/warpAggregatedAtomicsCG/README.md index dacffd13..f958302d 100644 --- a/Samples/warpAggregatedAtomicsCG/README.md +++ b/Samples/warpAggregatedAtomicsCG/README.md @@ -10,7 +10,7 @@ Cooperative Groups, Atomic Intrinsics ## Supported SM Architectures -[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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.5 ](https://developer.nvidia.com/cuda-gpus) +[SM 3.0 ](https://developer.nvidia.com/cuda-gpus) [SM 3.5 ](https://developer.nvidia.com/cuda-gpus) [SM 3.7 ](https://developer.nvidia.com/cuda-gpus) [SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](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) ## Supported OSes @@ -24,7 +24,7 @@ x86_64, ppc64le, armv7l, aarch64 ## Prerequisites -Download and install the [CUDA Toolkit 10.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. +Download and install the [CUDA Toolkit 10.1](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. ## Build and Run diff --git a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2012.vcxproj b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2012.vcxproj index 4f0f3838..740dc190 100644 --- a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2012.vcxproj +++ b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2012.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2013.vcxproj b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2013.vcxproj index cc4187be..8075939c 100644 --- a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2013.vcxproj +++ b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2013.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2015.vcxproj b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2015.vcxproj index cc614a67..7a2c1c80 100644 --- a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2015.vcxproj +++ b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2015.vcxproj @@ -33,7 +33,7 @@ - + @@ -102,6 +102,6 @@ - + diff --git a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2017.vcxproj b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2017.vcxproj index a36350c5..2613a64f 100644 --- a/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2017.vcxproj +++ b/Samples/warpAggregatedAtomicsCG/warpAggregatedAtomicsCG_vs2017.vcxproj @@ -34,7 +34,7 @@ - + @@ -103,6 +103,6 @@ - +