Compare commits

...

82 Commits

Author SHA1 Message Date
Rob Armstrong
8a9e2c830c
Update 1_Utilities/README.md to redirect bandwidthTest to NVBandwidth (#371) 2025-05-22 11:43:14 -07:00
Rob Armstrong
adacf1cffd
Merge pull request #368 from XSShawnZeng/master
Update the vulkan headers include sequence and the transpose code format check
2025-05-21 09:27:13 -07:00
shawnz
da3b7a2b3c Update the vulkanImageCUDA/vulkanImageCUDA.cu for Windows headers 2025-05-19 17:43:08 +08:00
shawnz
5987a9e9fa Update transpose for code format check 2025-05-19 17:38:42 +08:00
shawnz
107f3f537f Update the include files sequence for vulkan samples on Windows 2025-05-19 17:38:22 +08:00
Francesco Rizzi
b530f1cf42
Fix bug in 6_Performance/transpose: copy sharedmem kernel (#363)
Update kernel loop bounds handling, main loop data copy to avoid incorrect reuse of output results.

---------

Authored-by: Francesco Rizzi <francesco.rizzi@ng-analytics.com>
2025-05-05 08:43:23 -07:00
Rob Armstrong
cab7c66b4f Update pre-config to include Python and JSON for EOL, whitespace checks 2025-05-01 10:17:42 -07:00
Rob Armstrong
8d400cfb7f Additional minor changes to run_tests.py output formatting 2025-05-01 10:14:09 -07:00
Rob Armstrong
6d6d964f97 Minor changes to run_tests.py output formatting 2025-05-01 09:54:25 -07:00
Rob Armstrong
ab68d58d59 Remove unused bin/x86_64 directory hierarchy 2025-05-01 09:53:54 -07:00
Rob Armstrong
c70d79cf3b Final 12.9 README updates 2025-05-01 09:39:06 -07:00
Rob Armstrong
14b1bfdcc4 Replace README references to "CUDA Toolkit 12.5" with general "CUDA Toolkit" 2025-04-30 09:46:45 -07:00
Rob Armstrong
c14a0114d6 Some samples require multiple GPUs. Update 'run_tests.py' to skip them on single- or no-GPU systems. 2025-04-30 09:45:20 -07:00
Rob Armstrong
ee15cc0fe2 Merge branch 'shawnz_bugs_fix' into 'master'
Bug fix for 5241914, 5164417 and 5097376

See merge request cuda-samples/cuda-samples!107
2025-04-28 08:53:11 -07:00
shawnz
3438fd4875 Update README for OpenMP 2025-04-28 23:44:45 +08:00
shawnz
b27b55ec70 Bug 5241914: Fix the error message for cuSolverDn_LinearSolver 2025-04-27 16:57:02 +08:00
shawnz
49159f3739 Bug 5164417 and 5097376: Fix the OpenMP issue finding issue for MSVC and Glang 2025-04-27 16:50:12 +08:00
Rob Armstrong
1680a1dc7f Update Windows FreeImage configuration instructions in README.md 2025-04-21 09:20:22 -07:00
Rob Armstrong
49daf0e4e0 Merge Bug 5199167: Fix the includes issue for 5_Domain_Specific\simpleD3D12
See merge request cuda-samples/cuda-samples!106
2025-04-21 08:11:52 -07:00
shawnz
a45fd3bd7c Bug 5199167: Fix the includes issue for 5_Domain_Specific\simpleD3D12 2025-04-21 11:52:33 +08:00
Rob Armstrong
0345908807 Update run_tests.py to enable multithreading 2025-04-07 08:48:44 -07:00
Rob Armstrong
3b9c8ce2e9 Merge branch 'shawnz_bugs_fix' into 'master'
Bug 5207005: Append pid in shmName for Linux only as this is for MIG scenario

See merge request cuda-samples/cuda-samples!100
2025-04-07 08:21:40 -07:00
shawnz
e77d6eb5ab Bug 5207005: Append pid in shmName for Linux only as this is for MIG scenario 2025-04-07 17:17:17 +08:00
Rob Armstrong
ac700327a2 Add folders to CMakeLists.txt for supporting generators and IDEs 2025-04-05 09:54:24 -07:00
Rob Armstrong
17703dd426 Merge branch 'shawnz_bugs_fix' into 'master'
Bug 5196977: Update includes for nbody

See merge request cuda-samples/cuda-samples!98
2025-04-03 01:16:20 -07:00
shawnz
a32d5badf7 Bug 5196977: Update includes for nbody 2025-04-03 15:30:05 +08:00
Rob Armstrong
1fd22429c3 Merge branch 'shawnz_bugs_fix' into 'master'
Change for fixing bugs: 5196977, 4914019, 4191696 and 5199167 .

See merge request cuda-samples/cuda-samples!97
2025-04-02 22:28:17 -07:00
Rob Armstrong
00ac0a1673 Remove bandwidthTest subdirectory from CMakeLists.txt 2025-04-02 22:27:30 -07:00
shawnz
b013387a39 Update code format 2025-04-03 11:23:26 +08:00
Rob Armstrong
9d921e0fe7 Add CONTRIBUTING.md 2025-04-02 11:29:16 -07:00
Rob Armstrong
7d1730f348 Remove outdated bandwidthTest sample 2025-04-02 11:19:48 -07:00
shawnz
718fe6486d Bug 5199167: Adjust the include header files sequence for simpleD3D11/simpleD3D11Texture 2025-04-02 15:10:29 +08:00
shawnz
ad9908e32b Bug4914019 & 4191696: Append pid in shmName for MIG multiple thread scenario 2025-04-02 11:20:09 +08:00
shawnz
952d6edf92 Bug 5196977: Include helper_gl.h before cuda_gl_interop.h 2025-04-01 16:07:32 +08:00
Rob Armstrong
685709bfc7 Merge branch 'shawnz_bugs_fix' into 'master'
Bug fix for bug 5194249, 5188945 and 5164374

See merge request cuda-samples/cuda-samples!95
2025-03-31 08:00:50 -07:00
shawnz
0c92c34ca9 Bug 5164374: Remove the register keyword has been deprecated and removed from the C++17 standard 2025-03-31 15:13:56 +08:00
shawnz
0d82634f70 5188945: Add freeglut and glew64 .dll files for minsizeRel/RelWithDebInfo build 2025-03-31 15:07:29 +08:00
shawnz
4abbdf4e80 Bug 5194249: Need to include cuda_runtime.h for cudaNvSci after the clang format change 2025-03-31 14:57:31 +08:00
Rob Armstrong
914ca00f89 Small update to README.md to clarify test script usage. 2025-03-28 15:16:10 -07:00
Rob Armstrong
c8034f368a Add helper utility to test run all built samples (see README.md for usage details) 2025-03-28 15:07:07 -07:00
Rob Armstrong
ceab6e8bcc Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks. 2025-03-27 10:30:07 -07:00
Rob Armstrong
2cd58fbc9a Update README version for 12.9 2025-03-26 10:24:22 -07:00
Rob Armstrong
c0ab53f986 Update all sample CMakeLists.txt to include ENABLE_CUDA_DEBUG flag to enable cuda-gdb 2025-03-26 10:08:59 -07:00
Rob Armstrong
b87c243bbb Add -lineinfo flag to all targets to include line information for developer tools 2025-03-26 09:44:20 -07:00
Rob Armstrong
e214cd29aa Update gencode arguments for separate kernel fatbin builds 2025-03-26 09:28:37 -07:00
Rob Armstrong
06d72496c2 Merge branch 'shawnz_tegra_crossbuild_toolchain' into 'master'
Bug 5133197: Add cmake toolchain and and update the CMakeList of some sample...

See merge request cuda-samples/cuda-samples!94
2025-03-25 14:52:02 -07:00
shawnz
2848d3bd21 Bug 5176886: Enable nvJPEG samples for aarch64 2025-03-21 13:02:14 +08:00
shawnz
bd0f630bf4 Bug 5133197: Add cmake toolchain and and update the CMakeList of some sample for tegra linux cross build 2025-03-20 12:43:44 +08:00
shawnz
ab9166a6b2 Bug 5139353 and 5139213: Enhancement for streamOrderedAllocationIPC 2025-03-12 15:28:54 +08:00
Rob Armstrong
c90a1c6981 Merge public repo changes 2025-03-08 08:30:35 -08:00
Rob Armstrong
9370f11e69 graphConditionalNodes: Additional tweaks to launch dimension initialization (#348) 2025-03-05 18:18:37 -08:00
Rob Armstrong
291435e0b4
graphConditionalNodes: Additional tweaks to launch dimension initialization (#348) 2025-03-05 18:17:27 -08:00
Rob Armstrong
8d901e745d graphConditionalNodes: Change launch dimension initialization for better cross-platform compatibility (#346) 2025-03-05 08:33:35 -08:00
Rob Armstrong
990ebc01c2
graphConditionalNodes: Change launch dimension initialization for better cross-platform compatibility (#346) 2025-03-05 08:32:58 -08:00
Shawn Zeng
9adce9d9f2 Update file CMakeLists.txt 2025-03-03 19:19:50 -08:00
Rob Armstrong
bcad2c9e61 graphConditionalNodes: Add switch, while, if/else conditional examples and minor cleanup (#344) 2025-03-03 17:50:22 -08:00
Rob Armstrong
e7b23470d5
graphConditionalNodes: Add switch, while, if/else conditional examples and minor cleanup (#344) 2025-03-03 17:49:17 -08:00
Shawn Zeng
310e7f2a11 Bug 5143332: Remove the redundant content in 0_Introduction/CMakeLists.txt 2025-03-03 17:37:48 -08:00
Shawn Zeng
7f0f63f311 Bug 5034785: Update all non-ctx nppi APIs to ctx APIs as per latest change on NPP 2025-02-27 03:01:47 -08:00
Shawn Zeng
acd3a015c8 Revert "Bug 5034785: Update all non-ctx nppi APIs to ctx APIs as per latest change on NPP"
This reverts commit a9869fd6eaeecc748fc5f10f4b331fa41efbdaca
2025-02-27 02:48:03 -08:00
shawnz
a9869fd6ea Bug 5034785: Update all non-ctx nppi APIs to ctx APIs as per latest change on NPP 2025-02-27 18:43:53 +08:00
XSShawnZeng
3e8f91d1a1
Several small bug fixes for Windows platforms
* Enhancement for GLFW include and lib search

* Fixing issue #321: A potential bug in memMapIPCDrv/memMapIpc.cpp

* Update CMakelist.txt for the sample 0_Introduction/template

* Copy .dll to correct dir for 5_Domain_Specific/Mandelbrot

* Fix typo

* Update changelog for cudaNvSciBufMultiplanar
2025-02-26 08:23:39 -08:00
Jonathan Bentz
f3b7c41ad6
cudaNvSci: Update README.md fixing typo (#337)
Fixes #193
2025-02-21 09:21:43 -08:00
Jonathan Bentz
29fb758e62
conjugateGradient: Ensure allocated memory is freed (#336)
Fixes #202
2025-02-21 09:20:53 -08:00
Jonathan Bentz
3bc08136ff
Update README.md link for sortingNetworks (#335)
Fixes #302
2025-02-21 09:19:21 -08:00
Jonathan Bentz
85eefa06c4
boxFilter: Remove unused parameter (#338)
Fixes: #122
2025-02-21 09:17:45 -08:00
XSShawnZeng
c357dd1e6b
Fixing issue #321: A potential bug in memMapIPCDrv/memMapIpc.cpp (#334) 2025-02-21 09:14:25 -08:00
Jonathan Bentz
efb46383e0
Transpose: Change TILE_DIM to 32 to fix bank conflicts
Fixes #175
2025-02-20 15:46:44 -08:00
XSShawnZeng
8d564d5e3a
Enhancement for GLFW include and lib search (#331)
Fixes NVIDIA bug 5115098
2025-02-20 08:06:40 -08:00
Jake Hemstad
37c5bcbef4 Update kernels.cuh 2025-02-19 17:33:10 -08:00
Rob Armstrong
940a4c7a91
memMapIpc: Resolve build-time warnings and minor potential issues (#329)
* Fix compute performance calculation type casting in gpuGetMaxGflopsDeviceIdDRV() for #109

* 3_CUDA_Features/memMapIPCDrv: Increase procIdx buffer size to prevent potential buffer overflow

* memMapIPCDrv: Fix memory leaks and improve header inclusion

- Remove redundant string.h header
- Add memory cleanup for dynamically allocated JIT options and log buffer
- Fix printf format specifier for unsigned long long
2025-02-19 15:52:20 -08:00
ohmaya
61bd39800d
simplePrintf.cu: "Compute capability" text (#299)
Compute %d.%d capability => Compute capability %d.%d
2025-02-19 15:22:34 -08:00
Rob Armstrong
8a96d2eee7
Fix compute performance calculation type casting in gpuGetMaxGflopsDeviceIdDRV() for #109 2025-02-19 10:43:18 -08:00
Rob Armstrong
e762d58260
Merge pull request #247 from sangeetsatheesh/master
Fix typo from Open issue #161
2025-02-18 17:22:48 -08:00
Rob Armstrong
8fd1701744
Merge branch 'master' into master 2025-02-18 17:22:04 -08:00
Rob Armstrong
94765c1597
Fix minor typo in README.md (#326) 2025-02-18 17:14:14 -08:00
Rob Armstrong
c87881f02c
Update matrix multiplication sample README references (#325)
- Clarify reference to Shared Memory section in CUDA programming guide
- Update cuBLAS interface version description
- Add hyperlink to Shared Memory documentation
2025-02-18 14:02:59 -08:00
Rob Armstrong
25400b6b3c
Merge pull request #287 from steffen-v/patch-1
fix "gridy" comandline argument for initMC
2025-02-18 13:30:27 -08:00
Rob Armstrong
e24f62e28c
Fix README.md version number typo
Fix inadvertent reference to prior release in README.md
2025-02-15 13:37:51 -08:00
steffen-v
22424227e7
fix "gridy" comandline argument for initMC 2024-07-26 14:42:05 +02:00
Sangeet S
42ff742bf5
Merge pull request #1 from sangeetsatheesh/sangeetsatheesh-fix-typo
Fix typo #161
2024-01-17 13:16:53 -05:00
Sangeet S
8ccb13c6f0
Fix typo #161
Fix typo in line 14 from "simple exemple" to simple "example"
2024-01-17 13:16:01 -05:00
1375 changed files with 108912 additions and 258785 deletions

49
.clang-format Normal file
View File

@ -0,0 +1,49 @@
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterExternBlock: true
AfterFunction: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
ColumnLimit: 120
DerivePointerAlignment: false
FixNamespaceComments: true
IncludeCategories:
- Regex: '^<.*>'
Priority: 1
- Regex: '^".*"'
Priority: 2
SortIncludes: true
IncludeBlocks: Regroup
IndentWidth: 4
MaxEmptyLinesToKeep: 2
PointerAlignment: Right
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
Standard: c++17
TabWidth: 4
UseTab: Never
...

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
build build
.vs .vs
.clangd .clangd
test
settings.json
launch.json

106
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,106 @@
# Copyright (c) 2024, NVIDIA CORPORATION.
ci:
autofix_commit_msg: |
[pre-commit.ci] auto code formatting
autofix_prs: false
autoupdate_branch: ''
autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate'
autoupdate_schedule: quarterly
skip: []
submodules: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
exclude: |
(?x)^(
.*\.raw$|
.*\.bin$|
.*\.dat$|
.*\.nv12$|
data/.*|
Common/.*
)
files: |
(?x)^(
.*\.txt$|
.*\.md$|
.*\.cpp$|
.*\.cxx$|
.*\.hpp$|
.*\.h$|
.*\.cu$|
.*\.cuh$|
.*\.py$|
.*\.json$
)
- id: mixed-line-ending
exclude: |
(?x)^(
.*\.raw$|
.*\.bin$|
.*\.dat$|
.*\.nv12$|
data/.*|
Common/.*
)
files: |
(?x)^(
.*\.txt$|
.*\.md$|
.*\.cpp$|
.*\.cxx$|
.*\.hpp$|
.*\.h$|
.*\.cu$|
.*\.cuh$|
.*\.py$|
.*\.json$
)
- id: trailing-whitespace
exclude: |
(?x)^(
.*\.raw$|
.*\.bin$|
.*\.dat$|
.*\.nv12$|
data/.*|
Common/.*
)
files: |
(?x)^(
.*\.txt$|
.*\.md$|
.*\.cpp$|
.*\.cxx$|
.*\.hpp$|
.*\.h$|
.*\.cu$|
.*\.cuh$|
.*\.py$|
.*\.json$
)
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.6
hooks:
- id: clang-format
types_or: [file]
files: |
(?x)^(
^.*\.c$|
^.*\.cpp$|
^.*\.cu$|
^.*\.cuh$|
^.*\.cxx$|
^.*\.h$|
^.*\.hpp$|
^.*\.inl$|
^.*\.mm$
)
exclude: |
(?x)^(
Common/.*
)
args: ["-fallback-style=none", "-style=file", "-i"]

View File

@ -1,5 +1,15 @@
## Changelog ## Changelog
### CUDA 12.9
* Updated toolchain for cross-compilation for Tegra Linux platforms.
* Added `run_tests.py` utility to exercise all samples. See README.md for details
* Repository has been updated with consistent code formatting across all samples
* Many small code tweaks and bug fixes (see commit history for details)
* Removed the following outdated samples:
* `1_Utilities`
* `bandwidthTest` - this sample was out of date and did not produce accurate results. For bandwidth
testing of NVIDIA GPU platforms, please refer to [NVBandwidth](https://github.com/NVIDIA/nvbandwidth)
### CUDA 12.8 ### CUDA 12.8
* Updated build system across the repository to CMake. Removed Visual Studio project files and Makefiles. * Updated build system across the repository to CMake. Removed Visual Studio project files and Makefiles.
* Removed the following outdated samples: * Removed the following outdated samples:
@ -36,6 +46,7 @@
* `cuDLALayerwiseStatsHybrid` * `cuDLALayerwiseStatsHybrid`
* `cuDLALayerwiseStatsStandalone` * `cuDLALayerwiseStatsStandalone`
* `cuDLAStandaloneMode` * `cuDLAStandaloneMode`
* `cudaNvSciBufMultiplanar`
* `cudaNvSciNvMedia` * `cudaNvSciNvMedia`
* `fluidsGLES` * `fluidsGLES`
* `nbody_opengles` * `nbody_opengles`

View File

@ -16,8 +16,10 @@ set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --extended-lambda") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --extended-lambda")

103
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,103 @@
# Contributing to the CUDA Samples
Thank you for your interest in contributing to the CUDA Samples!
## Getting Started
1. **Fork & Clone the Repository**:
Fork the reporistory and clone the fork. For more information, check [GitHub's documentation on forking](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) and [cloning a repository](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository).
## Making Changes
1. **Create a New Branch**:
```bash
git checkout -b your-feature-branch
```
2. **Make Changes**.
3. **Build and Test**:
Ensure changes don't break existing functionality by building and running tests.
For more details on building and testing, refer to the [Building and Testing](#building-and-testing) section below.
4. **Commit Changes**:
```bash
git commit -m "Brief description of the change"
```
## Building and Testing
For information on building a running tests on the samples, please refer to the main [README](README.md)
## Creating a Pull Request
1. Push changes to your fork
2. Create a pull request targeting the `master` branch of the original CUDA Samples repository. Refer to [GitHub's documentation](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) for more information on creating a pull request.
3. Describe the purpose and context of the changes in the pull request description.
## Code Formatting (pre-commit hooks)
The CUDA Samples repository uses [pre-commit](https://pre-commit.com/) to execute all code linters and formatters. These
tools ensure a consistent coding style throughout the project. Using pre-commit ensures that linter
versions and options are aligned for all developers. Additionally, there is a CI check in place to
enforce that committed code follows our standards.
The linters used by the CUDA Samples are listed in `.pre-commit-config.yaml`.
For example, C++ and CUDA code is formatted with [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html).
To use `pre-commit`, install via `conda` or `pip`:
```bash
conda config --add channels conda-forge
conda install pre-commit
```
```bash
pip install pre-commit
```
Then run pre-commit hooks before committing code:
```bash
pre-commit run
```
By default, pre-commit runs on staged files (only changes and additions that will be committed).
To run pre-commit checks on all files, execute:
```bash
pre-commit run --all-files
```
Optionally, you may set up the pre-commit hooks to run automatically when you make a git commit. This can be done by running:
```bash
pre-commit install
```
Now code linters and formatters will be run each time you commit changes.
You can skip these checks with `git commit --no-verify` or with the short version `git commit -n`, althoguh please note
that this may result in pull requests being rejected if subsequent checks fail.
## Review Process
Once submitted, maintainers will be automatically assigned to review the pull request. They might suggest changes or improvements. Constructive feedback is a part of the collaborative process, aimed at ensuring the highest quality code.
For constructive feedback and effective communication during reviews, we recommend following [Conventional Comments](https://conventionalcomments.org/).
Further recommended reading for successful PR reviews:
- [How to Do Code Reviews Like a Human (Part One)](https://mtlynch.io/human-code-reviews-1/)
- [How to Do Code Reviews Like a Human (Part Two)](https://mtlynch.io/human-code-reviews-2/)
## Thank You
Your contributions enhance the CUDA Samples for the entire community. We appreciate your effort and collaboration!

View File

@ -241,7 +241,7 @@ inline int gpuGetMaxGflopsDeviceIdDRV() {
} }
unsigned long long compute_perf = unsigned long long compute_perf =
(unsigned long long)(multiProcessorCount * sm_per_multiproc * ((unsigned long long)multiProcessorCount * sm_per_multiproc *
clockRate); clockRate);
if (compute_perf > max_compute_perf) { if (compute_perf > max_compute_perf) {

View File

@ -258,7 +258,7 @@ namespace nv
s[2] = &r3[0]; s[2] = &r3[0];
s[3] = &r4[0]; s[3] = &r4[0];
register int i,j,p,jj; int i,j,p,jj;
for (i=0; i<4; i++) for (i=0; i<4; i++)
{ {

189
README.md
View File

@ -1,6 +1,6 @@
# CUDA Samples # CUDA Samples
Samples for CUDA Developers which demonstrates features in CUDA Toolkit. This version supports [CUDA Toolkit 12.6](https://developer.nvidia.com/cuda-downloads). Samples for CUDA Developers which demonstrates features in CUDA Toolkit. This version supports [CUDA Toolkit 12.9](https://developer.nvidia.com/cuda-downloads).
## Release Notes ## Release Notes
@ -14,7 +14,7 @@ This section describes the release notes for the CUDA Samples on GitHub only.
### Prerequisites ### Prerequisites
Download and install the [CUDA Toolkit 12.8](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
For system requirements and installation instructions of cuda toolkit, please refer to the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/), and the [Windows Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html). For system requirements and installation instructions of cuda toolkit, please refer to the [Linux Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-linux/), and the [Windows Installation Guide](http://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html).
### Getting the CUDA Samples ### Getting the CUDA Samples
@ -72,6 +72,17 @@ Open the generated solution file CUDA_Samples.sln in Visual Studio. Build the sa
Run the samples from the output directories specified in Visual Studio. Run the samples from the output directories specified in Visual Studio.
### Enabling On-GPU Debugging
NVIDIA GPUs support on-GPU debugging through cuda-gdb. Enabling this may significantly affect application performance as certain compiler optimizations are disabled
in this configuration, hence it's not on by default. Enablement of on-device debugging is controlled via the `-G` switch to nvcc.
To enable cuda-gdb for samples builds, define the `ENABLE_CUDA_DEBUG` flag on the CMake command line. For example:
```
cmake -DENABLE_CUDA_DEBUG=True ...
```
### Platform-Specific Samples ### Platform-Specific Samples
Some CUDA samples are specific to certain platforms, and require passing flags into CMake to enable. In particular, we define the following platform-specific flags: Some CUDA samples are specific to certain platforms, and require passing flags into CMake to enable. In particular, we define the following platform-specific flags:
@ -94,9 +105,9 @@ Navigate to the root of the cloned repository and create a build directory:
``` ```
mkdir build && cd build mkdir build && cd build
``` ```
Configure the project with CMake, specifying the Tegra toolchain file: Configure the project with CMake, specifying the Tegra toolchain file. And you can use -DTARGET_FS to point to the target file system root path for necessary include and library files:
``` ```
cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/tegra/toolchain.cmake cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/toolchain-aarch64-linux.cmake -DTARGET_FS=/path/to/target/system/file/system
``` ```
Build the samples: Build the samples:
``` ```
@ -111,7 +122,7 @@ Instead of being in the default location, `/usr/local/cuda/include` or `/usr/loc
`/usr/local/cuda/<ARCH>/targets/aarch64-linux/lib` `/usr/local/cuda/<ARCH>/targets/aarch64-linux/lib`
and and
`/usr/local/cuda-12.8/<ARCH>/include` `/usr/local/cuda/<ARCH>/include`
An example build might look like this: An example build might look like this:
@ -128,6 +139,168 @@ Note that in the current branch sample cross-compilation for QNX is not fully va
near future with QNX cross-compilation instructions. In the meantime, if you want to cross-compile for QNX please check out one near future with QNX cross-compilation instructions. In the meantime, if you want to cross-compile for QNX please check out one
of the previous tags prior to the CMake build system transition in 12.8. of the previous tags prior to the CMake build system transition in 12.8.
## Running All Samples as Tests
It's important to note that the CUDA samples are _not_ intended as a validation suite for CUDA. They do not cover corner cases, they do not completely cover the
runtime and driver APIs, are not intended for performance benchmarking, etc. That said, it can sometimes be useful to run all of the samples as a quick sanity check and
we provide a script to do so, `run_tests.py`.
This Python3 script finds all executables in a subdirectory you choose, matching application names with command line arguments specified in `test_args.json`. It accepts
the following command line arguments:
| Switch | Purpose | Example |
| ---------- | -------------------------------------------------------------------------------------------------------------- | ----------------------- |
| --dir | Specify the root directory to search for executables (recursively) | --dir ./build/Samples |
| --config | JSON configuration file for executable arguments | --config test_args.json |
| --output | Output directory for test results (stdout saved to .txt files - directory will be created if it doesn't exist) | --output ./test |
| --args | Global arguments to pass to all executables (not currently used) | --args arg_1 arg_2 ... |
| --parallel | Number of applications to execute in parallel. | --parallel 8 |
Application configurations are loaded from `test_args.json` and matched against executable names (discarding the `.exe` extension on Windows).
The script returns 0 on success, or the first non-zero error code encountered during testing on failure. It will also print a condensed list of samples that failed, if any.
There are three primary modes of configuration:
**Skip**
An executable configured with "skip" will not be executed. These generally rely on having attached graphical displays and are not suited to this kind of automation.
Configuration example:
```json
"fluidsGL": {
"skip": true
}
```
You will see:
```
Skipping fluidsGL (marked as skip in config)
```
**Single Run**
For executables to run one time only with arguments, specify each argument as a list entry. Each entry in the JSON file will be appended to the command line, separated
by a space.
All applications execute from their current directory, so all paths are relative to the application's location.
Note that if an application needs no arguments, this entry is optional. An executable found without a matching entry in the JSON will just run as `./application` from its
current directory.
Configuration example:
```json
"ptxgen": {
"args": [
"test.ll",
"-arch=compute_75"
]
}
```
You will see:
```
Running ptxgen
Command: ./ptxgen test.ll -arch=compute_75
Test completed with return code 0
```
**Multiple Runs**
For executables to run multiple times with different command line arguments, specify any number of sets of args within a "runs" list.
As with single runs, all applications execute from their current directory, so all paths are relative to the application's location.
Configuration example:
```json
"recursiveGaussian": {
"runs": [
{
"args": [
"-sigma=10",
"-file=data/ref_10.ppm"
]
},
{
"args": [
"-sigma=14",
"-file=data/ref_14.ppm"
]
},
{
"args": [
"-sigma=18",
"-file=data/ref_18.ppm"
]
},
{
"args": [
"-sigma=22",
"-file=data/ref_22.ppm"
]
}
]
}
```
You will see:
```
Running recursiveGaussian (run 1/4)
Command: ./recursiveGaussian -sigma=10 -file=data/ref_10.ppm
Test completed with return code 0
Running recursiveGaussian (run 2/4)
Command: ./recursiveGaussian -sigma=14 -file=data/ref_14.ppm
Test completed with return code 0
Running recursiveGaussian (run 3/4)
Command: ./recursiveGaussian -sigma=18 -file=data/ref_18.ppm
Test completed with return code 0
Running recursiveGaussian (run 4/4)
Command: ./recursiveGaussian -sigma=22 -file=data/ref_22.ppm
Test completed with return code 0
```
### Example Usage
Here is an example set of commands to build and test all of the samples.
First, build:
```bash
mkdir build
cd build
cmake ..
make -j$(nproc)
```
Now, return to the samples root directory and run the test script:
```bash
cd ..
python3 run_tests.py --output ./test --dir ./build/Samples --config test_args.json
```
If all applications run successfully, you will see something similar to this (the specific number of samples will depend on your build type
and system configuration):
```
Test Summary:
Ran 199 test runs for 180 executables.
All test runs passed!
```
If some samples fail, you will see something like this:
```
Test Summary:
Ran 199 test runs for 180 executables.
Failed runs (2):
bicubicTexture (run 1/5): Failed (code 1)
Mandelbrot (run 1/2): Failed (code 1)
```
You can inspect the stdout logs in the output directory (generally `APM_<application_name>.txt` or `APM_<application_name>.run<n>.txt`) to help
determine what may have gone wrong from the output logs. Please file issues against the samples repository if you believe a sample is failing
incorrectly on your system.
## Samples list ## Samples list
### [0. Introduction](./Samples/0_Introduction/README.md) ### [0. Introduction](./Samples/0_Introduction/README.md)
@ -170,7 +343,7 @@ These third-party dependencies are required by some CUDA samples. If available,
FreeImage is an open source imaging library. FreeImage can usually be installed on Linux using your distribution's package manager system. FreeImage can also be downloaded from the FreeImage website. FreeImage is an open source imaging library. FreeImage can usually be installed on Linux using your distribution's package manager system. FreeImage can also be downloaded from the FreeImage website.
To set up FreeImage on a Windows system, extract the FreeImage DLL distribution into the folder `../../../Common/FreeImage/Dist/x64` such that it contains the .h and .lib files. Copy the .dll file to the Release/ Debug/ execution folder or pass the FreeImage folder when cmake configuring with the `-DFREEIMAGE_INCLUDE_DIR` and `-DFREEIMAGE_LIBRARY` options. To set up FreeImage on a Windows system, extract the FreeImage DLL distribution into the folder `./Common/FreeImage/Dist/x64` such that it contains the .h and .lib files. Copy the .dll file to the Release/ Debug/ execution folder or pass the FreeImage folder when cmake configuring with the `-DFreeImage_INCLUDE_DIR` and `-DFreeImage_LIBRARY` options.
#### Message Passing Interface #### Message Passing Interface
@ -203,11 +376,11 @@ Vulkan is a low-overhead, cross-platform 3D graphics and compute API. Vulkan tar
#### GLFW #### GLFW
GLFW is a lightweight, open-source library designed for managing OpenGL, OpenGL ES, and Vulkan contexts. It simplifies the process of creating and managing windows, handling user input (keyboard, mouse, and joystick), and working with multiple monitors in a cross-platform manner. GLFW is a lightweight, open-source library designed for managing OpenGL, OpenGL ES, and Vulkan contexts. It simplifies the process of creating and managing windows, handling user input (keyboard, mouse, and joystick), and working with multiple monitors in a cross-platform manner.
To set up GLFW on a Windows system, Download the pre-built binaries from [GLFW website](https://www.glfw.org/download.html) and extract the zip file into the folder, pass the GLFW include header as `-DGLFW_INCLUDE_DIR` for cmake configuring and follow the Build_instructions.txt in the sample folder to set up the t. To set up GLFW on a Windows system, Download the pre-built binaries from [GLFW website](https://www.glfw.org/download.html) and extract the zip file into the folder, pass the GLFW include header folder as `-DGLFW_INCLUDE_DIR` and lib folder as `-DGLFW_LIB_DIR` for cmake configuring.
#### OpenMP #### OpenMP
OpenMP is an API for multiprocessing programming. OpenMP can be installed using your Linux distribution's package manager system. It usually comes preinstalled with GCC. It can also be found at the [OpenMP website](http://openmp.org/). OpenMP is an API for multiprocessing programming. OpenMP can be installed using your Linux distribution's package manager system. It usually comes preinstalled with GCC. It can also be found at the [OpenMP website](http://openmp.org/). For compilers such as clang, `libomp.so` and other components for LLVM must be installed separated. You will also need to set additional flags in your CMake configuration files, such as: `-DOpenMP_CXX_FLAGS="-fopenmp=libomp" -DOpenMP_CXX_LIB_NAMES="omp" -DOpenMP_omp_LIBRARY="/path/to/libomp.so"`.
#### Screen #### Screen

View File

@ -1,20 +1,3 @@
cmake_minimum_required(VERSION 3.20)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
project(simpleCallback LANGUAGES C CXX CUDA)
find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive)
endif()
add_subdirectory(UnifiedMemoryStreams) add_subdirectory(UnifiedMemoryStreams)
add_subdirectory(asyncAPI) add_subdirectory(asyncAPI)
add_subdirectory(clock) add_subdirectory(clock)
@ -55,6 +38,7 @@ add_subdirectory(simpleTexture3D)
add_subdirectory(simpleTextureDrv) add_subdirectory(simpleTextureDrv)
add_subdirectory(simpleVoteIntrinsics) add_subdirectory(simpleVoteIntrinsics)
add_subdirectory(simpleZeroCopy) add_subdirectory(simpleZeroCopy)
add_subdirectory(template)
add_subdirectory(systemWideAtomics) add_subdirectory(systemWideAtomics)
add_subdirectory(vectorAdd) add_subdirectory(vectorAdd)
add_subdirectory(vectorAddDrv) add_subdirectory(vectorAddDrv)

View File

@ -10,15 +10,21 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries
include_directories(../../../Common) include_directories(../../../Common)
# Source file # Source file
find_package(OpenMP REQUIRED) if(CMAKE_GENERATOR MATCHES "Visual Studio")
find_package(OpenMP REQUIRED C CXX)
else()
find_package(OpenMP REQUIRED)
endif()
if(${OpenMP_FOUND}) if(${OpenMP_FOUND})
# Add target for UnifiedMemoryStreams # Add target for UnifiedMemoryStreams

View File

@ -28,7 +28,7 @@ cudaStreamDestroy, cudaFree, cudaMallocManaged, cudaStreamAttachMemAsync, cudaSe
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -31,10 +31,10 @@
*/ */
// system includes // system includes
#include <algorithm>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include <vector> #include <vector>
#include <algorithm>
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
#include <pthread.h> #include <pthread.h>
#else #else
@ -58,15 +58,25 @@ double drand48() { return double(rand()) / RAND_MAX; }
const char *sSDKname = "UnifiedMemoryStreams"; const char *sSDKname = "UnifiedMemoryStreams";
// simple task // simple task
template <typename T> template <typename T> struct Task
struct Task { {
unsigned int size, id; unsigned int size, id;
T *data; T *data;
T *result; T *result;
T *vector; T *vector;
Task() : size(0), id(0), data(NULL), result(NULL), vector(NULL){}; Task()
Task(unsigned int s) : size(s), id(0), data(NULL), result(NULL) { : size(0)
, id(0)
, data(NULL)
, result(NULL)
, vector(NULL) {};
Task(unsigned int s)
: size(s)
, id(0)
, data(NULL)
, result(NULL)
{
// allocate unified memory -- the operation performed in this example will // allocate unified memory -- the operation performed in this example will
// be a DGEMV // be a DGEMV
checkCudaErrors(cudaMallocManaged(&data, sizeof(T) * size * size)); checkCudaErrors(cudaMallocManaged(&data, sizeof(T) * size * size));
@ -75,7 +85,8 @@ struct Task {
checkCudaErrors(cudaDeviceSynchronize()); checkCudaErrors(cudaDeviceSynchronize());
} }
~Task() { ~Task()
{
// ensure all memory is deallocated // ensure all memory is deallocated
checkCudaErrors(cudaDeviceSynchronize()); checkCudaErrors(cudaDeviceSynchronize());
checkCudaErrors(cudaFree(data)); checkCudaErrors(cudaFree(data));
@ -83,7 +94,8 @@ struct Task {
checkCudaErrors(cudaFree(vector)); checkCudaErrors(cudaFree(vector));
} }
void allocate(const unsigned int s, const unsigned int unique_id) { void allocate(const unsigned int s, const unsigned int unique_id)
{
// allocate unified memory outside of constructor // allocate unified memory outside of constructor
id = unique_id; id = unique_id;
size = s; size = s;
@ -105,7 +117,8 @@ struct Task {
}; };
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
struct threadData_t { struct threadData_t
{
int tid; int tid;
Task<double> *TaskListPtr; Task<double> *TaskListPtr;
cudaStream_t *streams; cudaStream_t *streams;
@ -117,8 +130,8 @@ typedef struct threadData_t threadData;
#endif #endif
// simple host dgemv: assume data is in row-major format and square // simple host dgemv: assume data is in row-major format and square
template <typename T> template <typename T> void gemv(int m, int n, T alpha, T *A, T *x, T beta, T *result)
void gemv(int m, int n, T alpha, T *A, T *x, T beta, T *result) { {
// rows // rows
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
result[i] *= beta; result[i] *= beta;
@ -131,7 +144,8 @@ void gemv(int m, int n, T alpha, T *A, T *x, T beta, T *result) {
// execute a single task on either host or device depending on size // execute a single task on either host or device depending on size
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
void *execute(void *inpArgs) { void *execute(void *inpArgs)
{
threadData *dataPtr = (threadData *)inpArgs; threadData *dataPtr = (threadData *)inpArgs;
cudaStream_t *stream = dataPtr->streams; cudaStream_t *stream = dataPtr->streams;
cublasHandle_t *handle = dataPtr->handles; cublasHandle_t *handle = dataPtr->handles;
@ -142,92 +156,75 @@ void *execute(void *inpArgs) {
if (t.size < 100) { if (t.size < 100) {
// perform on host // perform on host
printf("Task [%d], thread [%d] executing on host (%d)\n", t.id, tid, printf("Task [%d], thread [%d] executing on host (%d)\n", t.id, tid, t.size);
t.size);
// attach managed memory to a (dummy) stream to allow host access while // attach managed memory to a (dummy) stream to allow host access while
// the device is running // the device is running
checkCudaErrors( checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.data, 0, cudaMemAttachHost));
cudaStreamAttachMemAsync(stream[0], t.data, 0, cudaMemAttachHost)); checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.vector, 0, cudaMemAttachHost));
checkCudaErrors( checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.result, 0, cudaMemAttachHost));
cudaStreamAttachMemAsync(stream[0], t.vector, 0, cudaMemAttachHost));
checkCudaErrors(
cudaStreamAttachMemAsync(stream[0], t.result, 0, cudaMemAttachHost));
// necessary to ensure Async cudaStreamAttachMemAsync calls have finished // necessary to ensure Async cudaStreamAttachMemAsync calls have finished
checkCudaErrors(cudaStreamSynchronize(stream[0])); checkCudaErrors(cudaStreamSynchronize(stream[0]));
// call the host operation // call the host operation
gemv(t.size, t.size, 1.0, t.data, t.vector, 0.0, t.result); gemv(t.size, t.size, 1.0, t.data, t.vector, 0.0, t.result);
} else { }
else {
// perform on device // perform on device
printf("Task [%d], thread [%d] executing on device (%d)\n", t.id, tid, printf("Task [%d], thread [%d] executing on device (%d)\n", t.id, tid, t.size);
t.size);
double one = 1.0; double one = 1.0;
double zero = 0.0; double zero = 0.0;
// attach managed memory to my stream // attach managed memory to my stream
checkCudaErrors(cublasSetStream(handle[tid + 1], stream[tid + 1])); checkCudaErrors(cublasSetStream(handle[tid + 1], stream[tid + 1]));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.data, 0, checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.data, 0, cudaMemAttachSingle));
cudaMemAttachSingle)); checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.vector, 0, cudaMemAttachSingle));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.vector, 0, checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.result, 0, cudaMemAttachSingle));
cudaMemAttachSingle));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.result, 0,
cudaMemAttachSingle));
// call the device operation // call the device operation
checkCudaErrors(cublasDgemv(handle[tid + 1], CUBLAS_OP_N, t.size, t.size, checkCudaErrors(cublasDgemv(
&one, t.data, t.size, t.vector, 1, &zero, handle[tid + 1], CUBLAS_OP_N, t.size, t.size, &one, t.data, t.size, t.vector, 1, &zero, t.result, 1));
t.result, 1));
} }
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
#else #else
template <typename T> template <typename T> void execute(Task<T> &t, cublasHandle_t *handle, cudaStream_t *stream, int tid)
void execute(Task<T> &t, cublasHandle_t *handle, cudaStream_t *stream, {
int tid) {
if (t.size < 100) { if (t.size < 100) {
// perform on host // perform on host
printf("Task [%d], thread [%d] executing on host (%d)\n", t.id, tid, printf("Task [%d], thread [%d] executing on host (%d)\n", t.id, tid, t.size);
t.size);
// attach managed memory to a (dummy) stream to allow host access while the // attach managed memory to a (dummy) stream to allow host access while the
// device is running // device is running
checkCudaErrors( checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.data, 0, cudaMemAttachHost));
cudaStreamAttachMemAsync(stream[0], t.data, 0, cudaMemAttachHost)); checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.vector, 0, cudaMemAttachHost));
checkCudaErrors( checkCudaErrors(cudaStreamAttachMemAsync(stream[0], t.result, 0, cudaMemAttachHost));
cudaStreamAttachMemAsync(stream[0], t.vector, 0, cudaMemAttachHost));
checkCudaErrors(
cudaStreamAttachMemAsync(stream[0], t.result, 0, cudaMemAttachHost));
// necessary to ensure Async cudaStreamAttachMemAsync calls have finished // necessary to ensure Async cudaStreamAttachMemAsync calls have finished
checkCudaErrors(cudaStreamSynchronize(stream[0])); checkCudaErrors(cudaStreamSynchronize(stream[0]));
// call the host operation // call the host operation
gemv(t.size, t.size, 1.0, t.data, t.vector, 0.0, t.result); gemv(t.size, t.size, 1.0, t.data, t.vector, 0.0, t.result);
} else { }
else {
// perform on device // perform on device
printf("Task [%d], thread [%d] executing on device (%d)\n", t.id, tid, printf("Task [%d], thread [%d] executing on device (%d)\n", t.id, tid, t.size);
t.size);
double one = 1.0; double one = 1.0;
double zero = 0.0; double zero = 0.0;
// attach managed memory to my stream // attach managed memory to my stream
checkCudaErrors(cublasSetStream(handle[tid + 1], stream[tid + 1])); checkCudaErrors(cublasSetStream(handle[tid + 1], stream[tid + 1]));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.data, 0, checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.data, 0, cudaMemAttachSingle));
cudaMemAttachSingle)); checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.vector, 0, cudaMemAttachSingle));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.vector, 0, checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.result, 0, cudaMemAttachSingle));
cudaMemAttachSingle));
checkCudaErrors(cudaStreamAttachMemAsync(stream[tid + 1], t.result, 0,
cudaMemAttachSingle));
// call the device operation // call the device operation
checkCudaErrors(cublasDgemv(handle[tid + 1], CUBLAS_OP_N, t.size, t.size, checkCudaErrors(cublasDgemv(
&one, t.data, t.size, t.vector, 1, &zero, handle[tid + 1], CUBLAS_OP_N, t.size, t.size, &one, t.data, t.size, t.vector, 1, &zero, t.result, 1));
t.result, 1));
} }
} }
#endif #endif
// populate a list of tasks with random sizes // populate a list of tasks with random sizes
template <typename T> template <typename T> void initialise_tasks(std::vector<Task<T>> &TaskList)
void initialise_tasks(std::vector<Task<T> > &TaskList) { {
for (unsigned int i = 0; i < TaskList.size(); i++) { for (unsigned int i = 0; i < TaskList.size(); i++) {
// generate random size // generate random size
int size; int size;
@ -236,7 +233,8 @@ void initialise_tasks(std::vector<Task<T> > &TaskList) {
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv)
{
// set device // set device
cudaDeviceProp device_prop; cudaDeviceProp device_prop;
int dev_id = findCudaDevice(argc, (const char **)argv); int dev_id = findCudaDevice(argc, (const char **)argv);
@ -276,7 +274,7 @@ int main(int argc, char **argv) {
// create list of N tasks // create list of N tasks
unsigned int N = 40; unsigned int N = 40;
std::vector<Task<double> > TaskList(N); std::vector<Task<double>> TaskList(N);
initialise_tasks(TaskList); initialise_tasks(TaskList);
printf("Executing tasks on host / device\n"); printf("Executing tasks on host / device\n");
@ -294,19 +292,17 @@ int main(int argc, char **argv) {
if ((TaskList.size() / nthreads) == 0) { if ((TaskList.size() / nthreads) == 0) {
InputToThreads[i].taskSize = (TaskList.size() / nthreads); InputToThreads[i].taskSize = (TaskList.size() / nthreads);
InputToThreads[i].TaskListPtr = InputToThreads[i].TaskListPtr = &TaskList[i * (TaskList.size() / nthreads)];
&TaskList[i * (TaskList.size() / nthreads)]; }
} else { else {
if (i == nthreads - 1) { if (i == nthreads - 1) {
InputToThreads[i].taskSize = InputToThreads[i].taskSize = (TaskList.size() / nthreads) + (TaskList.size() % nthreads);
(TaskList.size() / nthreads) + (TaskList.size() % nthreads);
InputToThreads[i].TaskListPtr = InputToThreads[i].TaskListPtr =
&TaskList[i * (TaskList.size() / nthreads) + &TaskList[i * (TaskList.size() / nthreads) + (TaskList.size() % nthreads)];
(TaskList.size() % nthreads)]; }
} else { else {
InputToThreads[i].taskSize = (TaskList.size() / nthreads); InputToThreads[i].taskSize = (TaskList.size() / nthreads);
InputToThreads[i].TaskListPtr = InputToThreads[i].TaskListPtr = &TaskList[i * (TaskList.size() / nthreads)];
&TaskList[i * (TaskList.size() / nthreads)];
} }
} }
@ -334,7 +330,7 @@ int main(int argc, char **argv) {
} }
// Free TaskList // Free TaskList
std::vector<Task<double> >().swap(TaskList); std::vector<Task<double>>().swap(TaskList);
printf("All Done!\n"); printf("All Done!\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaProfilerStop, cudaMalloc, cudaMemcpyAsync, cudaFree, cudaMallocHost, cudaPro
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -38,19 +38,21 @@
#include <stdio.h> #include <stdio.h>
// includes CUDA Runtime // includes CUDA Runtime
#include <cuda_runtime.h>
#include <cuda_profiler_api.h> #include <cuda_profiler_api.h>
#include <cuda_runtime.h>
// includes, project // includes, project
#include <helper_cuda.h> #include <helper_cuda.h>
#include <helper_functions.h> // helper utility functions #include <helper_functions.h> // helper utility functions
__global__ void increment_kernel(int *g_data, int inc_value) { __global__ void increment_kernel(int *g_data, int inc_value)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x; int idx = blockIdx.x * blockDim.x + threadIdx.x;
g_data[idx] = g_data[idx] + inc_value; g_data[idx] = g_data[idx] + inc_value;
} }
bool correct_output(int *data, const int n, const int x) { bool correct_output(int *data, const int n, const int x)
{
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
if (data[i] != x) { if (data[i] != x) {
printf("Error! data[%d] = %d, ref = %d\n", i, data[i], x); printf("Error! data[%d] = %d, ref = %d\n", i, data[i], x);
@ -60,7 +62,8 @@ bool correct_output(int *data, const int n, const int x) {
return true; return true;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
int devID; int devID;
cudaDeviceProp deviceProps; cudaDeviceProp deviceProps;
@ -126,8 +129,7 @@ int main(int argc, char *argv[]) {
// print the cpu and gpu times // print the cpu and gpu times
printf("time spent executing by the GPU: %.2f\n", gpu_time); printf("time spent executing by the GPU: %.2f\n", gpu_time);
printf("time spent by CPU in CUDA calls: %.2f\n", sdkGetTimerValue(&timer)); printf("time spent by CPU in CUDA calls: %.2f\n", sdkGetTimerValue(&timer));
printf("CPU executed %lu iterations while waiting for GPU to finish\n", printf("CPU executed %lu iterations while waiting for GPU to finish\n", counter);
counter);
// check the output for correctness // check the output for correctness
bool bFinalResults = correct_output(a, n, value); bool bFinalResults = correct_output(a, n, value);

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaMalloc, cudaMemcpy, cudaFree
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -48,15 +48,16 @@
// This kernel computes a standard parallel reduction and evaluates the // This kernel computes a standard parallel reduction and evaluates the
// time it takes to do that for each block. The timing results are stored // time it takes to do that for each block. The timing results are stored
// in device memory. // in device memory.
__global__ static void timedReduction(const float *input, float *output, __global__ static void timedReduction(const float *input, float *output, clock_t *timer)
clock_t *timer) { {
// __shared__ float shared[2 * blockDim.x]; // __shared__ float shared[2 * blockDim.x];
extern __shared__ float shared[]; extern __shared__ float shared[];
const int tid = threadIdx.x; const int tid = threadIdx.x;
const int bid = blockIdx.x; const int bid = blockIdx.x;
if (tid == 0) timer[bid] = clock(); if (tid == 0)
timer[bid] = clock();
// Copy input. // Copy input.
shared[tid] = input[tid]; shared[tid] = input[tid];
@ -77,11 +78,13 @@ __global__ static void timedReduction(const float *input, float *output,
} }
// Write result. // Write result.
if (tid == 0) output[bid] = shared[0]; if (tid == 0)
output[bid] = shared[0];
__syncthreads(); __syncthreads();
if (tid == 0) timer[bid + gridDim.x] = clock(); if (tid == 0)
timer[bid + gridDim.x] = clock();
} }
#define NUM_BLOCKS 64 #define NUM_BLOCKS 64
@ -104,7 +107,8 @@ __global__ static void timedReduction(const float *input, float *output,
// the memory. With more than 32 the speed scales linearly. // the memory. With more than 32 the speed scales linearly.
// Start the main CUDA Sample here // Start the main CUDA Sample here
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("CUDA Clock sample\n"); printf("CUDA Clock sample\n");
// This will pick the best possible CUDA capable device // This will pick the best possible CUDA capable device
@ -121,20 +125,15 @@ int main(int argc, char **argv) {
input[i] = (float)i; input[i] = (float)i;
} }
checkCudaErrors( checkCudaErrors(cudaMalloc((void **)&dinput, sizeof(float) * NUM_THREADS * 2));
cudaMalloc((void **)&dinput, sizeof(float) * NUM_THREADS * 2));
checkCudaErrors(cudaMalloc((void **)&doutput, sizeof(float) * NUM_BLOCKS)); checkCudaErrors(cudaMalloc((void **)&doutput, sizeof(float) * NUM_BLOCKS));
checkCudaErrors( checkCudaErrors(cudaMalloc((void **)&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
cudaMalloc((void **)&dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
checkCudaErrors(cudaMemcpy(dinput, input, sizeof(float) * NUM_THREADS * 2, checkCudaErrors(cudaMemcpy(dinput, input, sizeof(float) * NUM_THREADS * 2, cudaMemcpyHostToDevice));
cudaMemcpyHostToDevice));
timedReduction<<<NUM_BLOCKS, NUM_THREADS, sizeof(float) * 2 * NUM_THREADS>>>( timedReduction<<<NUM_BLOCKS, NUM_THREADS, sizeof(float) * 2 * NUM_THREADS>>>(dinput, doutput, dtimer);
dinput, doutput, dtimer);
checkCudaErrors(cudaMemcpy(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2, checkCudaErrors(cudaMemcpy(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2, cudaMemcpyDeviceToHost));
cudaMemcpyDeviceToHost));
checkCudaErrors(cudaFree(dinput)); checkCudaErrors(cudaFree(dinput));
checkCudaErrors(cudaFree(doutput)); checkCudaErrors(cudaFree(doutput));

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -33,7 +33,7 @@ cudaBlockSize, cudaGridSize
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -34,12 +34,11 @@
*/ */
// System includes // System includes
#include <stdio.h>
#include <stdint.h>
#include <assert.h> #include <assert.h>
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include <nvrtc_helper.h> #include <nvrtc_helper.h>
#include <stdint.h>
#include <stdio.h>
// helper functions and utilities to work with CUDA // helper functions and utilities to work with CUDA
#include <helper_functions.h> #include <helper_functions.h>
@ -71,7 +70,8 @@
// Start the main CUDA Sample here // Start the main CUDA Sample here
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("CUDA Clock sample\n"); printf("CUDA Clock sample\n");
typedef long clock_t; typedef long clock_t;
@ -106,17 +106,20 @@ int main(int argc, char **argv) {
void *arr[] = {(void *)&dinput, (void *)&doutput, (void *)&dtimer}; void *arr[] = {(void *)&dinput, (void *)&doutput, (void *)&dtimer};
checkCudaErrors(cuLaunchKernel( checkCudaErrors(cuLaunchKernel(kernel_addr,
kernel_addr, cudaGridSize.x, cudaGridSize.y, cudaGridSize.x,
cudaGridSize.y,
cudaGridSize.z, /* grid dim */ cudaGridSize.z, /* grid dim */
cudaBlockSize.x, cudaBlockSize.y, cudaBlockSize.z, /* block dim */ cudaBlockSize.x,
sizeof(float) * 2 * NUM_THREADS, 0, /* shared mem, stream */ cudaBlockSize.y,
cudaBlockSize.z, /* block dim */
sizeof(float) * 2 * NUM_THREADS,
0, /* shared mem, stream */
&arr[0], /* arguments */ &arr[0], /* arguments */
0)); 0));
checkCudaErrors(cuCtxSynchronize()); checkCudaErrors(cuCtxSynchronize());
checkCudaErrors( checkCudaErrors(cuMemcpyDtoH(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
cuMemcpyDtoH(timer, dtimer, sizeof(clock_t) * NUM_BLOCKS * 2));
checkCudaErrors(cuMemFree(dinput)); checkCudaErrors(cuMemFree(dinput));
checkCudaErrors(cuMemFree(doutput)); checkCudaErrors(cuMemFree(doutput));
checkCudaErrors(cuMemFree(dtimer)); checkCudaErrors(cuMemFree(dtimer));

View File

@ -37,15 +37,16 @@
// time it takes to do that for each block. The timing results are stored // time it takes to do that for each block. The timing results are stored
// in device memory. // in device memory.
extern "C" __global__ void timedReduction(const float *input, float *output, extern "C" __global__ void timedReduction(const float *input, float *output, clock_t *timer)
clock_t *timer) { {
// __shared__ float shared[2 * blockDim.x]; // __shared__ float shared[2 * blockDim.x];
extern __shared__ float shared[]; extern __shared__ float shared[];
const int tid = threadIdx.x; const int tid = threadIdx.x;
const int bid = blockIdx.x; const int bid = blockIdx.x;
if (tid == 0) timer[bid] = clock(); if (tid == 0)
timer[bid] = clock();
// Copy input. // Copy input.
shared[tid] = input[tid]; shared[tid] = input[tid];
@ -66,9 +67,11 @@ extern "C" __global__ void timedReduction(const float *input, float *output,
} }
// Write result. // Write result.
if (tid == 0) output[bid] = shared[0]; if (tid == 0)
output[bid] = shared[0];
__syncthreads(); __syncthreads();
if (tid == 0) timer[bid + gridDim.x] = clock(); if (tid == 0)
timer[bid + gridDim.x] = clock();
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -30,7 +30,7 @@ cudaMemcpy, cudaGetErrorString, cudaFree, cudaGetLastError, cudaSetDevice, cudaG
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -37,20 +37,24 @@
using namespace std; using namespace std;
// a simple kernel that simply increments each array element by b // a simple kernel that simply increments each array element by b
__global__ void kernelAddConstant(int *g_a, const int b) { __global__ void kernelAddConstant(int *g_a, const int b)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x; int idx = blockIdx.x * blockDim.x + threadIdx.x;
g_a[idx] += b; g_a[idx] += b;
} }
// a predicate that checks whether each array element is set to its index plus b // a predicate that checks whether each array element is set to its index plus b
int correctResult(int *data, const int n, const int b) { int correctResult(int *data, const int n, const int b)
{
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
if (data[i] != i + b) return 0; if (data[i] != i + b)
return 0;
return 1; return 1;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
int num_gpus = 0; // number of CUDA GPUs int num_gpus = 0; // number of CUDA GPUs
printf("%s Starting...\n\n", argv[0]); printf("%s Starting...\n\n", argv[0]);
@ -93,7 +97,8 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
for (unsigned int i = 0; i < n; i++) a[i] = i; for (unsigned int i = 0; i < n; i++)
a[i] = i;
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// run as many CPU threads as there are CUDA devices // run as many CPU threads as there are CUDA devices
@ -105,8 +110,7 @@ int main(int argc, char *argv[]) {
// Recall that all variables declared inside an "omp parallel" scope are // Recall that all variables declared inside an "omp parallel" scope are
// local to each CPU thread // local to each CPU thread
// //
omp_set_num_threads( omp_set_num_threads(num_gpus); // create as many CPU threads as there are CUDA devices
num_gpus); // create as many CPU threads as there are CUDA devices
// omp_set_num_threads(2*num_gpus);// create twice as many CPU threads as there // omp_set_num_threads(2*num_gpus);// create twice as many CPU threads as there
// are CUDA devices // are CUDA devices
#pragma omp parallel #pragma omp parallel
@ -116,31 +120,23 @@ int main(int argc, char *argv[]) {
// set and check the CUDA device for this CPU thread // set and check the CUDA device for this CPU thread
int gpu_id = -1; int gpu_id = -1;
checkCudaErrors(cudaSetDevice( checkCudaErrors(
cpu_thread_id % cudaSetDevice(cpu_thread_id % num_gpus)); // "% num_gpus" allows more CPU threads than GPU devices
num_gpus)); // "% num_gpus" allows more CPU threads than GPU devices
checkCudaErrors(cudaGetDevice(&gpu_id)); checkCudaErrors(cudaGetDevice(&gpu_id));
printf("CPU thread %d (of %d) uses CUDA device %d\n", cpu_thread_id, printf("CPU thread %d (of %d) uses CUDA device %d\n", cpu_thread_id, num_cpu_threads, gpu_id);
num_cpu_threads, gpu_id);
int *d_a = int *d_a = 0; // pointer to memory on the device associated with this CPU thread
0; // pointer to memory on the device associated with this CPU thread int *sub_a = a + cpu_thread_id * n / num_cpu_threads; // pointer to this CPU thread's portion of data
int *sub_a =
a +
cpu_thread_id * n /
num_cpu_threads; // pointer to this CPU thread's portion of data
unsigned int nbytes_per_kernel = nbytes / num_cpu_threads; unsigned int nbytes_per_kernel = nbytes / num_cpu_threads;
dim3 gpu_threads(128); // 128 threads per block dim3 gpu_threads(128); // 128 threads per block
dim3 gpu_blocks(n / (gpu_threads.x * num_cpu_threads)); dim3 gpu_blocks(n / (gpu_threads.x * num_cpu_threads));
checkCudaErrors(cudaMalloc((void **)&d_a, nbytes_per_kernel)); checkCudaErrors(cudaMalloc((void **)&d_a, nbytes_per_kernel));
checkCudaErrors(cudaMemset(d_a, 0, nbytes_per_kernel)); checkCudaErrors(cudaMemset(d_a, 0, nbytes_per_kernel));
checkCudaErrors( checkCudaErrors(cudaMemcpy(d_a, sub_a, nbytes_per_kernel, cudaMemcpyHostToDevice));
cudaMemcpy(d_a, sub_a, nbytes_per_kernel, cudaMemcpyHostToDevice));
kernelAddConstant<<<gpu_blocks, gpu_threads>>>(d_a, b); kernelAddConstant<<<gpu_blocks, gpu_threads>>>(d_a, b);
checkCudaErrors( checkCudaErrors(cudaMemcpy(sub_a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost));
cudaMemcpy(sub_a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaFree(d_a)); checkCudaErrors(cudaFree(d_a));
} }
printf("---------------------------\n"); printf("---------------------------\n");
@ -153,7 +149,8 @@ int main(int argc, char *argv[]) {
// //
bool bResult = correctResult(a, n, b); bool bResult = correctResult(a, n, b);
if (a) free(a); // free CPU memory if (a)
free(a); // free CPU memory
exit(bResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(bResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }

View File

@ -9,8 +9,10 @@ find_package(CUDAToolkit REQUIRED)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 60 61 70 72 75 80 86 87 89 90 100 101 120)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -30,7 +30,7 @@ cudaMemcpy, cudaFree, cudaMallocHost, cudaFreeHost, cudaMalloc, cudaGetDevicePro
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -25,17 +25,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "cuda_fp16.h"
#include "helper_cuda.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include "cuda_fp16.h"
#include "helper_cuda.h"
#define NUM_OF_BLOCKS 128 #define NUM_OF_BLOCKS 128
#define NUM_OF_THREADS 128 #define NUM_OF_THREADS 128
__forceinline__ __device__ void reduceInShared_intrinsics(half2 *const v) { __forceinline__ __device__ void reduceInShared_intrinsics(half2 *const v)
{
if (threadIdx.x < 64) if (threadIdx.x < 64)
v[threadIdx.x] = __hadd2(v[threadIdx.x], v[threadIdx.x + 64]); v[threadIdx.x] = __hadd2(v[threadIdx.x], v[threadIdx.x + 64]);
__syncthreads(); __syncthreads();
@ -59,27 +60,34 @@ __forceinline__ __device__ void reduceInShared_intrinsics(half2 *const v) {
__syncthreads(); __syncthreads();
} }
__forceinline__ __device__ void reduceInShared_native(half2 *const v) { __forceinline__ __device__ void reduceInShared_native(half2 *const v)
if (threadIdx.x < 64) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 64]; {
if (threadIdx.x < 64)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 64];
__syncthreads(); __syncthreads();
if (threadIdx.x < 32) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 32]; if (threadIdx.x < 32)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 32];
__syncthreads(); __syncthreads();
if (threadIdx.x < 16) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 16]; if (threadIdx.x < 16)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 16];
__syncthreads(); __syncthreads();
if (threadIdx.x < 8) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 8]; if (threadIdx.x < 8)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 8];
__syncthreads(); __syncthreads();
if (threadIdx.x < 4) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 4]; if (threadIdx.x < 4)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 4];
__syncthreads(); __syncthreads();
if (threadIdx.x < 2) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 2]; if (threadIdx.x < 2)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 2];
__syncthreads(); __syncthreads();
if (threadIdx.x < 1) v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 1]; if (threadIdx.x < 1)
v[threadIdx.x] = v[threadIdx.x] + v[threadIdx.x + 1];
__syncthreads(); __syncthreads();
} }
__global__ void scalarProductKernel_intrinsics(half2 const *const a, __global__ void
half2 const *const b, scalarProductKernel_intrinsics(half2 const *const a, half2 const *const b, float *const results, size_t const size)
float *const results, {
size_t const size) {
const int stride = gridDim.x * blockDim.x; const int stride = gridDim.x * blockDim.x;
__shared__ half2 shArray[NUM_OF_THREADS]; __shared__ half2 shArray[NUM_OF_THREADS];
@ -101,10 +109,9 @@ __global__ void scalarProductKernel_intrinsics(half2 const *const a,
} }
} }
__global__ void scalarProductKernel_native(half2 const *const a, __global__ void
half2 const *const b, scalarProductKernel_native(half2 const *const a, half2 const *const b, float *const results, size_t const size)
float *const results, {
size_t const size) {
const int stride = gridDim.x * blockDim.x; const int stride = gridDim.x * blockDim.x;
__shared__ half2 shArray[NUM_OF_THREADS]; __shared__ half2 shArray[NUM_OF_THREADS];
@ -126,7 +133,8 @@ __global__ void scalarProductKernel_native(half2 const *const a,
} }
} }
void generateInput(half2 *a, size_t size) { void generateInput(half2 *a, size_t size)
{
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
half2 temp; half2 temp;
temp.x = static_cast<float>(rand() % 4); temp.x = static_cast<float>(rand() % 4);
@ -135,7 +143,8 @@ void generateInput(half2 *a, size_t size) {
} }
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
srand((unsigned int)time(NULL)); srand((unsigned int)time(NULL));
size_t size = NUM_OF_BLOCKS * NUM_OF_THREADS * 16; size_t size = NUM_OF_BLOCKS * NUM_OF_THREADS * 16;
@ -151,8 +160,7 @@ int main(int argc, char *argv[]) {
checkCudaErrors(cudaGetDeviceProperties(&devProp, devID)); checkCudaErrors(cudaGetDeviceProperties(&devProp, devID));
if (devProp.major < 5 || (devProp.major == 5 && devProp.minor < 3)) { if (devProp.major < 5 || (devProp.major == 5 && devProp.minor < 3)) {
printf( printf("ERROR: fp16ScalarProduct requires GPU devices with compute SM 5.3 or "
"ERROR: fp16ScalarProduct requires GPU devices with compute SM 5.3 or "
"higher.\n"); "higher.\n");
return EXIT_WAIVED; return EXIT_WAIVED;
} }
@ -162,23 +170,17 @@ int main(int argc, char *argv[]) {
checkCudaErrors(cudaMalloc((void **)&devVec[i], size * sizeof *devVec[i])); checkCudaErrors(cudaMalloc((void **)&devVec[i], size * sizeof *devVec[i]));
} }
checkCudaErrors( checkCudaErrors(cudaMallocHost((void **)&results, NUM_OF_BLOCKS * sizeof *results));
cudaMallocHost((void **)&results, NUM_OF_BLOCKS * sizeof *results)); checkCudaErrors(cudaMalloc((void **)&devResults, NUM_OF_BLOCKS * sizeof *devResults));
checkCudaErrors(
cudaMalloc((void **)&devResults, NUM_OF_BLOCKS * sizeof *devResults));
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
generateInput(vec[i], size); generateInput(vec[i], size);
checkCudaErrors(cudaMemcpy(devVec[i], vec[i], size * sizeof *vec[i], checkCudaErrors(cudaMemcpy(devVec[i], vec[i], size * sizeof *vec[i], cudaMemcpyHostToDevice));
cudaMemcpyHostToDevice));
} }
scalarProductKernel_native<<<NUM_OF_BLOCKS, NUM_OF_THREADS>>>( scalarProductKernel_native<<<NUM_OF_BLOCKS, NUM_OF_THREADS>>>(devVec[0], devVec[1], devResults, size);
devVec[0], devVec[1], devResults, size);
checkCudaErrors(cudaMemcpy(results, devResults, checkCudaErrors(cudaMemcpy(results, devResults, NUM_OF_BLOCKS * sizeof *results, cudaMemcpyDeviceToHost));
NUM_OF_BLOCKS * sizeof *results,
cudaMemcpyDeviceToHost));
float result_native = 0; float result_native = 0;
for (int i = 0; i < NUM_OF_BLOCKS; ++i) { for (int i = 0; i < NUM_OF_BLOCKS; ++i) {
@ -186,12 +188,9 @@ int main(int argc, char *argv[]) {
} }
printf("Result native operators\t: %f \n", result_native); printf("Result native operators\t: %f \n", result_native);
scalarProductKernel_intrinsics<<<NUM_OF_BLOCKS, NUM_OF_THREADS>>>( scalarProductKernel_intrinsics<<<NUM_OF_BLOCKS, NUM_OF_THREADS>>>(devVec[0], devVec[1], devResults, size);
devVec[0], devVec[1], devResults, size);
checkCudaErrors(cudaMemcpy(results, devResults, checkCudaErrors(cudaMemcpy(results, devResults, NUM_OF_BLOCKS * sizeof *results, cudaMemcpyDeviceToHost));
NUM_OF_BLOCKS * sizeof *results,
cudaMemcpyDeviceToHost));
float result_intrinsics = 0; float result_intrinsics = 0;
for (int i = 0; i < NUM_OF_BLOCKS; ++i) { for (int i = 0; i < NUM_OF_BLOCKS; ++i) {
@ -199,9 +198,7 @@ int main(int argc, char *argv[]) {
} }
printf("Result intrinsics\t: %f \n", result_intrinsics); printf("Result intrinsics\t: %f \n", result_intrinsics);
printf("&&&& fp16ScalarProduct %s\n", printf("&&&& fp16ScalarProduct %s\n", (fabs(result_intrinsics - result_native) < 0.00001) ? "PASSED" : "FAILED");
(fabs(result_intrinsics - result_native) < 0.00001) ? "PASSED"
: "FAILED");
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
checkCudaErrors(cudaFree(devVec[i])); checkCudaErrors(cudaFree(devVec[i]));

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -2,7 +2,7 @@
## Description ## Description
This sample implements matrix multiplication and is exactly the same as Chapter 6 of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the new CUDA 4.0 interface for CUBLAS to demonstrate high-performance performance for matrix multiplication. This sample implements matrix multiplication and is exactly the same as the second example of the [Shared Memory](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory) section of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the CUDA 4.0+ interface for cuBLAS to demonstrate high-performance performance for matrix multiplication.
## Key Concepts ## Key Concepts
@ -27,6 +27,6 @@ cudaStreamCreateWithFlags, cudaProfilerStop, cudaMalloc, cudaFree, cudaMallocHos
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -40,24 +40,23 @@
*/ */
// System includes // System includes
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
// CUDA runtime // CUDA runtime
#include <cuda_runtime.h>
#include <cuda_profiler_api.h> #include <cuda_profiler_api.h>
#include <cuda_runtime.h>
// Helper functions and utilities to work with CUDA // Helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h> #include <helper_cuda.h>
#include <helper_functions.h>
/** /**
* Matrix multiplication (CUDA Kernel) on the device: C = A * B * Matrix multiplication (CUDA Kernel) on the device: C = A * B
* wA is A's width and wB is B's width * wA is A's width and wB is B's width
*/ */
template <int BLOCK_SIZE> __global__ void MatrixMulCUDA(float *C, float *A, template <int BLOCK_SIZE> __global__ void MatrixMulCUDA(float *C, float *A, float *B, int wA, int wB)
float *B, int wA, {
int wB) {
// Block index // Block index
int bx = blockIdx.x; int bx = blockIdx.x;
int by = blockIdx.y; int by = blockIdx.y;
@ -87,9 +86,7 @@ template <int BLOCK_SIZE> __global__ void MatrixMulCUDA(float *C, float *A,
// Loop over all the sub-matrices of A and B // Loop over all the sub-matrices of A and B
// required to compute the block sub-matrix // required to compute the block sub-matrix
for (int a = aBegin, b = bBegin; for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) {
a <= aEnd;
a += aStep, b += bStep) {
// Declaration of the shared memory array As used to // Declaration of the shared memory array As used to
// store the sub-matrix of A // store the sub-matrix of A
__shared__ float As[BLOCK_SIZE][BLOCK_SIZE]; __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
@ -128,7 +125,8 @@ template <int BLOCK_SIZE> __global__ void MatrixMulCUDA(float *C, float *A,
C[c + wB * ty + tx] = Csub; C[c + wB * ty + tx] = Csub;
} }
void ConstantInit(float *data, int size, float val) { void ConstantInit(float *data, int size, float val)
{
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
data[i] = val; data[i] = val;
} }
@ -137,9 +135,8 @@ void ConstantInit(float *data, int size, float val) {
/** /**
* Run a simple test of matrix multiplication using CUDA * Run a simple test of matrix multiplication using CUDA
*/ */
int MatrixMultiply(int argc, char **argv, int MatrixMultiply(int argc, char **argv, int block_size, const dim3 &dimsA, const dim3 &dimsB)
int block_size, const dim3 &dimsA, {
const dim3 &dimsB) {
// Allocate host memory for matrices A and B // Allocate host memory for matrices A and B
unsigned int size_A = dimsA.x * dimsA.y; unsigned int size_A = dimsA.x * dimsA.y;
unsigned int mem_size_A = sizeof(float) * size_A; unsigned int mem_size_A = sizeof(float) * size_A;
@ -181,10 +178,8 @@ int MatrixMultiply(int argc, char **argv,
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
// copy host memory to device // copy host memory to device
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice, stream));
cudaMemcpyAsync(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice, stream)); checkCudaErrors(cudaMemcpyAsync(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice, stream));
checkCudaErrors(
cudaMemcpyAsync(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice, stream));
// Setup execution parameters // Setup execution parameters
dim3 threads(block_size, block_size); dim3 threads(block_size, block_size);
@ -195,11 +190,10 @@ int MatrixMultiply(int argc, char **argv,
// Performs warmup operation using matrixMul CUDA kernel // Performs warmup operation using matrixMul CUDA kernel
if (block_size == 16) { if (block_size == 16) {
MatrixMulCUDA<16> MatrixMulCUDA<16><<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
<<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x); }
} else { else {
MatrixMulCUDA<32> MatrixMulCUDA<32><<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
<<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
} }
printf("done\n"); printf("done\n");
@ -213,11 +207,10 @@ int MatrixMultiply(int argc, char **argv,
for (int j = 0; j < nIter; j++) { for (int j = 0; j < nIter; j++) {
if (block_size == 16) { if (block_size == 16) {
MatrixMulCUDA<16> MatrixMulCUDA<16><<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
<<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x); }
} else { else {
MatrixMulCUDA<32> MatrixMulCUDA<32><<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
<<<grid, threads, 0, stream>>>(d_C, d_A, d_B, dimsA.x, dimsB.x);
} }
} }
@ -232,19 +225,18 @@ int MatrixMultiply(int argc, char **argv,
// Compute and print the performance // Compute and print the performance
float msecPerMatrixMul = msecTotal / nIter; float msecPerMatrixMul = msecTotal / nIter;
double flopsPerMatrixMul = 2.0 * static_cast<double>(dimsA.x) * double flopsPerMatrixMul =
static_cast<double>(dimsA.y) * 2.0 * static_cast<double>(dimsA.x) * static_cast<double>(dimsA.y) * static_cast<double>(dimsB.x);
static_cast<double>(dimsB.x); double gigaFlops = (flopsPerMatrixMul * 1.0e-9f) / (msecPerMatrixMul / 1000.0f);
double gigaFlops = printf("Performance= %.2f GFlop/s, Time= %.3f msec, Size= %.0f Ops,"
(flopsPerMatrixMul * 1.0e-9f) / (msecPerMatrixMul / 1000.0f);
printf(
"Performance= %.2f GFlop/s, Time= %.3f msec, Size= %.0f Ops,"
" WorkgroupSize= %u threads/block\n", " WorkgroupSize= %u threads/block\n",
gigaFlops, msecPerMatrixMul, flopsPerMatrixMul, threads.x * threads.y); gigaFlops,
msecPerMatrixMul,
flopsPerMatrixMul,
threads.x * threads.y);
// Copy result from device to host // Copy result from device to host
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(h_C, d_C, mem_size_C, cudaMemcpyDeviceToHost, stream));
cudaMemcpyAsync(h_C, d_C, mem_size_C, cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream)); checkCudaErrors(cudaStreamSynchronize(stream));
printf("Checking computed result for correctness: "); printf("Checking computed result for correctness: ");
@ -261,8 +253,7 @@ int MatrixMultiply(int argc, char **argv,
double rel_err = abs_err / abs_val / dot_length; double rel_err = abs_err / abs_val / dot_length;
if (rel_err > eps) { if (rel_err > eps) {
printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > %E\n", printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > %E\n", i, h_C[i], dimsA.x * valB, eps);
i, h_C[i], dimsA.x * valB, eps);
correct = false; correct = false;
} }
} }
@ -278,13 +269,13 @@ int MatrixMultiply(int argc, char **argv,
checkCudaErrors(cudaFree(d_C)); checkCudaErrors(cudaFree(d_C));
checkCudaErrors(cudaEventDestroy(start)); checkCudaErrors(cudaEventDestroy(start));
checkCudaErrors(cudaEventDestroy(stop)); checkCudaErrors(cudaEventDestroy(stop));
printf( printf("\nNOTE: The CUDA Samples are not meant for performance "
"\nNOTE: The CUDA Samples are not meant for performance "
"measurements. Results may vary when GPU Boost is enabled.\n"); "measurements. Results may vary when GPU Boost is enabled.\n");
if (correct) { if (correct) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} else { }
else {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
@ -293,15 +284,15 @@ int MatrixMultiply(int argc, char **argv,
/** /**
* Program main * Program main
*/ */
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("[Matrix Multiply Using CUDA] - Starting...\n"); printf("[Matrix Multiply Using CUDA] - Starting...\n");
if (checkCmdLineFlag(argc, (const char **)argv, "help") || if (checkCmdLineFlag(argc, (const char **)argv, "help") || checkCmdLineFlag(argc, (const char **)argv, "?")) {
checkCmdLineFlag(argc, (const char **)argv, "?")) {
printf("Usage -device=n (n >= 0 for deviceID)\n"); printf("Usage -device=n (n >= 0 for deviceID)\n");
printf(" -wA=WidthA -hA=HeightA (Width x Height of Matrix A)\n"); printf(" -wA=WidthA -hA=HeightA (Width x Height of Matrix A)\n");
printf(" -wB=WidthB -hB=HeightB (Width x Height of Matrix B)\n"); printf(" -wB=WidthB -hB=HeightB (Width x Height of Matrix B)\n");
printf(" Note: Outer matrix dimensions of A & B matrices" \ printf(" Note: Outer matrix dimensions of A & B matrices"
" must be equal.\n"); " must be equal.\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
@ -337,13 +328,11 @@ int main(int argc, char **argv) {
} }
if (dimsA.x != dimsB.y) { if (dimsA.x != dimsB.y) {
printf("Error: outer matrix dimensions must be equal. (%d != %d)\n", printf("Error: outer matrix dimensions must be equal. (%d != %d)\n", dimsA.x, dimsB.y);
dimsA.x, dimsB.y);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, dimsB.y);
dimsB.x, dimsB.y);
checkCudaErrors(cudaProfilerStart()); checkCudaErrors(cudaProfilerStart());
int matrix_result = MatrixMultiply(argc, argv, block_size, dimsA, dimsB); int matrix_result = MatrixMultiply(argc, argv, block_size, dimsA, dimsB);

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries
@ -38,6 +40,12 @@ target_link_libraries(matrixMulDrv PUBLIC
set(CUDA_FATBIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/matrixMul_kernel64.fatbin") set(CUDA_FATBIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/matrixMul_kernel64.fatbin")
set(CUDA_KERNEL_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/matrixMul_kernel.cu") set(CUDA_KERNEL_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/matrixMul_kernel.cu")
# Construct GENCODE_FLAGS explicitly from CUDA architectures
set(GENCODE_FLAGS "")
foreach(arch ${CMAKE_CUDA_ARCHITECTURES})
list(APPEND GENCODE_FLAGS "-gencode=arch=compute_${arch},code=sm_${arch}")
endforeach()
add_custom_command( add_custom_command(
OUTPUT ${CUDA_FATBIN_FILE} OUTPUT ${CUDA_FATBIN_FILE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE} COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE}

View File

@ -27,6 +27,6 @@ cuMemcpyDtoH, cuLaunchKernel, cuMemcpyHtoD, cuDeviceGetName, cuDeviceTotalMem, c
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -46,23 +46,23 @@
// includes, system // includes, system
#include <builtin_types.h> #include <builtin_types.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <cstring> #include <cstring>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project, CUDA // includes, project, CUDA
#include <cstring>
#include <cuda.h> #include <cuda.h>
#include <helper_cuda_drvapi.h> #include <helper_cuda_drvapi.h>
#include <helper_image.h> #include <helper_image.h>
#include <helper_string.h> #include <helper_string.h>
#include <helper_timer.h> #include <helper_timer.h>
#include <cstring>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "matrixMul.h" #include "matrixMul.h"
@ -71,11 +71,9 @@
void runTest(int argc, char **argv); void runTest(int argc, char **argv);
void randomInit(float *, int); void randomInit(float *, int);
extern "C" void computeGold(float *, const float *, const float *, unsigned int, extern "C" void computeGold(float *, const float *, const float *, unsigned int, unsigned int, unsigned int);
unsigned int, unsigned int);
static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul, static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *blk_size);
int *blk_size);
#ifndef FATBIN_FILE #ifndef FATBIN_FILE
#define FATBIN_FILE "matrixMul_kernel64.fatbin" #define FATBIN_FILE "matrixMul_kernel64.fatbin"
@ -91,7 +89,8 @@ size_t totalGlobalMem;
const char *sSDKsample = "matrixMulDrv (Driver API)"; const char *sSDKsample = "matrixMulDrv (Driver API)";
void constantInit(float *data, int size, float val) { void constantInit(float *data, int size, float val)
{
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
data[i] = val; data[i] = val;
} }
@ -100,7 +99,8 @@ void constantInit(float *data, int size, float val) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("[ %s ]\n", sSDKsample); printf("[ %s ]\n", sSDKsample);
runTest(argc, argv); runTest(argc, argv);
@ -109,7 +109,8 @@ int main(int argc, char **argv) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Run a simple test for CUDA //! Run a simple test for CUDA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
// initialize CUDA // initialize CUDA
CUfunction matrixMul = NULL; CUfunction matrixMul = NULL;
int block_size = 0; int block_size = 0;
@ -172,10 +173,19 @@ void runTest(int argc, char **argv) {
size_t Matrix_Width_B = (size_t)WB; size_t Matrix_Width_B = (size_t)WB;
void *args[5] = {&d_C, &d_A, &d_B, &Matrix_Width_A, &Matrix_Width_B}; void *args[5] = {&d_C, &d_A, &d_B, &Matrix_Width_A, &Matrix_Width_B};
// new CUDA 4.0 Driver API Kernel launch call // new CUDA 4.0 Driver API Kernel launch call
checkCudaErrors(cuLaunchKernel( checkCudaErrors(cuLaunchKernel(matrixMul,
matrixMul, grid.x, grid.y, grid.z, block.x, block.y, block.z, grid.x,
2 * block_size * block_size * sizeof(float), NULL, args, NULL)); grid.y,
} else { grid.z,
block.x,
block.y,
block.z,
2 * block_size * block_size * sizeof(float),
NULL,
args,
NULL));
}
else {
// This is the new CUDA 4.0 API for Kernel Parameter passing and Kernel // This is the new CUDA 4.0 API for Kernel Parameter passing and Kernel
// Launching (advanced method) // Launching (advanced method)
int offset = 0; int offset = 0;
@ -198,14 +208,20 @@ void runTest(int argc, char **argv) {
*(reinterpret_cast<CUdeviceptr *>(&argBuffer[offset])) = Matrix_Width_B; *(reinterpret_cast<CUdeviceptr *>(&argBuffer[offset])) = Matrix_Width_B;
offset += sizeof(Matrix_Width_B); offset += sizeof(Matrix_Width_B);
void *kernel_launch_config[5] = {CU_LAUNCH_PARAM_BUFFER_POINTER, argBuffer, void *kernel_launch_config[5] = {
CU_LAUNCH_PARAM_BUFFER_SIZE, &offset, CU_LAUNCH_PARAM_BUFFER_POINTER, argBuffer, CU_LAUNCH_PARAM_BUFFER_SIZE, &offset, CU_LAUNCH_PARAM_END};
CU_LAUNCH_PARAM_END};
// new CUDA 4.0 Driver API Kernel launch call // new CUDA 4.0 Driver API Kernel launch call
checkCudaErrors(cuLaunchKernel( checkCudaErrors(cuLaunchKernel(matrixMul,
matrixMul, grid.x, grid.y, grid.z, block.x, block.y, block.z, grid.x,
2 * block_size * block_size * sizeof(float), NULL, NULL, grid.y,
grid.z,
block.x,
block.y,
block.z,
2 * block_size * block_size * sizeof(float),
NULL,
NULL,
reinterpret_cast<void **>(&kernel_launch_config))); reinterpret_cast<void **>(&kernel_launch_config)));
} }
@ -222,8 +238,7 @@ void runTest(int argc, char **argv) {
for (int i = 0; i < static_cast<int>(WC * HC); i++) { for (int i = 0; i < static_cast<int>(WC * HC); i++) {
if (fabs(h_C[i] - (WA * valB)) > 1e-5) { if (fabs(h_C[i] - (WA * valB)) > 1e-5) {
printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > 1e-5\n", i, printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > 1e-5\n", i, h_C[i], WA * valB);
h_C[i], WA * valB);
correct = false; correct = false;
} }
} }
@ -244,14 +259,15 @@ void runTest(int argc, char **argv) {
} }
// Allocates a matrix with random float entries. // Allocates a matrix with random float entries.
void randomInit(float *data, int size) { void randomInit(float *data, int size)
{
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
data[i] = rand() / static_cast<float>(RAND_MAX); data[i] = rand() / static_cast<float>(RAND_MAX);
} }
} }
static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul, static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *blk_size)
int *blk_size) { {
CUfunction cuFunction = 0; CUfunction cuFunction = 0;
int major = 0, minor = 0; int major = 0, minor = 0;
char deviceName[100]; char deviceName[100];
@ -259,16 +275,13 @@ static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul,
cuDevice = findCudaDeviceDRV(argc, (const char **)argv); cuDevice = findCudaDeviceDRV(argc, (const char **)argv);
// get compute capabilities and the devicename // get compute capabilities and the devicename
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice));
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice)); checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
checkCudaErrors(cuDeviceGetAttribute(
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
checkCudaErrors(cuDeviceGetName(deviceName, sizeof(deviceName), cuDevice)); checkCudaErrors(cuDeviceGetName(deviceName, sizeof(deviceName), cuDevice));
printf("> GPU Device has SM %d.%d compute capability\n", major, minor); printf("> GPU Device has SM %d.%d compute capability\n", major, minor);
checkCudaErrors(cuDeviceTotalMem(&totalGlobalMem, cuDevice)); checkCudaErrors(cuDeviceTotalMem(&totalGlobalMem, cuDevice));
printf(" Total amount of global memory: %llu bytes\n", printf(" Total amount of global memory: %llu bytes\n", (long long unsigned int)totalGlobalMem);
(long long unsigned int)totalGlobalMem);
checkCudaErrors(cuCtxCreate(&cuContext, 0, cuDevice)); checkCudaErrors(cuCtxCreate(&cuContext, 0, cuDevice));
@ -278,7 +291,8 @@ static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul,
if (!findFatbinPath(FATBIN_FILE, module_path, argv, fatbin)) { if (!findFatbinPath(FATBIN_FILE, module_path, argv, fatbin)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} else { }
else {
printf("> initCUDA loading module: <%s>\n", module_path.c_str()); printf("> initCUDA loading module: <%s>\n", module_path.c_str());
} }
@ -291,8 +305,7 @@ static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul,
checkCudaErrors(cuModuleLoadData(&cuModule, fatbin.str().c_str())); checkCudaErrors(cuModuleLoadData(&cuModule, fatbin.str().c_str()));
// select the suitable kernel function // select the suitable kernel function
const char *kernels[] = {"matrixMul_bs32_64bit", "matrixMul_bs16_64bit", const char *kernels[] = {"matrixMul_bs32_64bit", "matrixMul_bs16_64bit", "matrixMul_bs8_64bit"};
"matrixMul_bs8_64bit"};
int idx = 0; int idx = 0;
int block_size = 32; int block_size = 32;
@ -302,12 +315,12 @@ static int initCUDA(int argc, char **argv, CUfunction *pMatrixMul,
checkCudaErrors(cuModuleGetFunction(&cuFunction, cuModule, kernels[idx])); checkCudaErrors(cuModuleGetFunction(&cuFunction, cuModule, kernels[idx]));
checkCudaErrors(cuOccupancyMaxPotentialBlockSize( checkCudaErrors(cuOccupancyMaxPotentialBlockSize(
&blocksPerGrid, &threadsPerBlock, cuFunction, 0, &blocksPerGrid, &threadsPerBlock, cuFunction, 0, 2 * block_size * block_size * sizeof(float), 0));
2 * block_size * block_size * sizeof(float), 0));
if (block_size * block_size <= threadsPerBlock) { if (block_size * block_size <= threadsPerBlock) {
printf("> %d block size selected\n", block_size); printf("> %d block size selected\n", block_size);
break; break;
} else { }
else {
block_size /= 2; block_size /= 2;
} }
idx++; idx++;

View File

@ -42,8 +42,8 @@
//! wA is A's width and wB is B's width //! wA is A's width and wB is B's width
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <int block_size, typename size_type> template <int block_size, typename size_type>
__device__ void matrixMul(float *C, float *A, float *B, size_type wA, __device__ void matrixMul(float *C, float *A, float *B, size_type wA, size_type wB)
size_type wB) { {
// Block index // Block index
size_type bx = blockIdx.x; size_type bx = blockIdx.x;
size_type by = blockIdx.y; size_type by = blockIdx.y;
@ -96,7 +96,8 @@ __device__ void matrixMul(float *C, float *A, float *B, size_type wA,
// of the block sub-matrix // of the block sub-matrix
#pragma unroll #pragma unroll
for (size_type k = 0; k < block_size; ++k) Csub += AS(ty, k) * BS(k, tx); for (size_type k = 0; k < block_size; ++k)
Csub += AS(ty, k) * BS(k, tx);
// Synchronize to make sure that the preceding // Synchronize to make sure that the preceding
// computation is done before loading two new // computation is done before loading two new
@ -111,16 +112,16 @@ __device__ void matrixMul(float *C, float *A, float *B, size_type wA,
} }
// C wrappers around our template kernel // C wrappers around our template kernel
extern "C" __global__ void matrixMul_bs8_64bit(float *C, float *A, float *B, extern "C" __global__ void matrixMul_bs8_64bit(float *C, float *A, float *B, size_t wA, size_t wB)
size_t wA, size_t wB) { {
matrixMul<8, size_t>(C, A, B, wA, wB); matrixMul<8, size_t>(C, A, B, wA, wB);
} }
extern "C" __global__ void matrixMul_bs16_64bit(float *C, float *A, float *B, extern "C" __global__ void matrixMul_bs16_64bit(float *C, float *A, float *B, size_t wA, size_t wB)
size_t wA, size_t wB) { {
matrixMul<16, size_t>(C, A, B, wA, wB); matrixMul<16, size_t>(C, A, B, wA, wB);
} }
extern "C" __global__ void matrixMul_bs32_64bit(float *C, float *A, float *B, extern "C" __global__ void matrixMul_bs32_64bit(float *C, float *A, float *B, size_t wA, size_t wB)
size_t wA, size_t wB) { {
matrixMul<32, size_t>(C, A, B, wA, wB); matrixMul<32, size_t>(C, A, B, wA, wB);
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cuMemcpyDtoH, cuDeviceGetName, cuParamSeti, cuModuleLoadDataEx, cuModuleGetFunct
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -15,13 +15,14 @@
// With these flags defined, this source file will dynamically // With these flags defined, this source file will dynamically
// load the corresponding functions. Disabled by default. // load the corresponding functions. Disabled by default.
//#define CUDA_INIT_D3D9 // #define CUDA_INIT_D3D9
//#define CUDA_INIT_D3D10 // #define CUDA_INIT_D3D10
//#define CUDA_INIT_D3D11 // #define CUDA_INIT_D3D11
//#define CUDA_INIT_OPENGL // #define CUDA_INIT_OPENGL
#include "cuda_drvapi_dynlink.h"
#include <stdio.h> #include <stdio.h>
#include "cuda_drvapi_dynlink.h"
tcuInit *_cuInit; tcuInit *_cuInit;
tcuDriverGetVersion *cuDriverGetVersion; tcuDriverGetVersion *cuDriverGetVersion;
@ -239,8 +240,7 @@ static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)
{ {
*pInstance = LoadLibrary(__CudaLibName); *pInstance = LoadLibrary(__CudaLibName);
if (*pInstance == NULL) if (*pInstance == NULL) {
{
printf("LoadLibrary \"%s\" failed!\n", __CudaLibName); printf("LoadLibrary \"%s\" failed!\n", __CudaLibName);
return CUDA_ERROR_UNKNOWN; return CUDA_ERROR_UNKNOWN;
} }
@ -251,35 +251,32 @@ static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)
#define GET_PROC_EX(name, alias, required) \ #define GET_PROC_EX(name, alias, required) \
alias = (t##name *)GetProcAddress(CudaDrvLib, #name); \ alias = (t##name *)GetProcAddress(CudaDrvLib, #name); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", #name, __CudaLibName); \
#name, __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
#define GET_PROC_EX_V2(name, alias, required) \ #define GET_PROC_EX_V2(name, alias, required) \
alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v2));\ alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v2)); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", STRINGIFY(name##_v2), __CudaLibName); \
STRINGIFY(name##_v2), __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
#define GET_PROC_EX_V3(name, alias, required) \ #define GET_PROC_EX_V3(name, alias, required) \
alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v3));\ alias = (t##name *)GetProcAddress(CudaDrvLib, STRINGIFY(name##_v3)); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", STRINGIFY(name##_v3), __CudaLibName); \
STRINGIFY(name##_v3), __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
#elif defined(__unix__) || defined (__QNX__) || defined(__APPLE__) || defined(__MACOSX) #elif defined(__unix__) || defined(__QNX__) || defined(__APPLE__) || defined(__MACOSX)
#include <dlfcn.h> #include <dlfcn.h>
#if defined(__APPLE__) || defined(__MACOSX) #if defined(__APPLE__) || defined(__MACOSX)
static char __CudaLibName[] = "/usr/local/cuda/lib/libcuda.dylib"; static char __CudaLibName[] = "/usr/local/cuda/lib/libcuda.dylib";
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
#if defined (__aarch64__) #if defined(__aarch64__)
static char __CudaLibName[] = "/system/vendor/lib64/libcuda.so"; static char __CudaLibName[] = "/system/vendor/lib64/libcuda.so";
#elif defined(__arm__) #elif defined(__arm__)
static char __CudaLibName[] = "/system/vendor/lib/libcuda.so"; static char __CudaLibName[] = "/system/vendor/lib/libcuda.so";
@ -294,8 +291,7 @@ static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)
{ {
*pInstance = dlopen(__CudaLibName, RTLD_NOW); *pInstance = dlopen(__CudaLibName, RTLD_NOW);
if (*pInstance == NULL) if (*pInstance == NULL) {
{
printf("dlopen \"%s\" failed!\n", __CudaLibName); printf("dlopen \"%s\" failed!\n", __CudaLibName);
return CUDA_ERROR_UNKNOWN; return CUDA_ERROR_UNKNOWN;
} }
@ -306,24 +302,21 @@ static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)
#define GET_PROC_EX(name, alias, required) \ #define GET_PROC_EX(name, alias, required) \
alias = (t##name *)dlsym(CudaDrvLib, #name); \ alias = (t##name *)dlsym(CudaDrvLib, #name); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", #name, __CudaLibName); \
#name, __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
#define GET_PROC_EX_V2(name, alias, required) \ #define GET_PROC_EX_V2(name, alias, required) \
alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v2)); \ alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v2)); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", STRINGIFY(name##_v2), __CudaLibName); \
STRINGIFY(name##_v2), __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
#define GET_PROC_EX_V3(name, alias, required) \ #define GET_PROC_EX_V3(name, alias, required) \
alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v3)); \ alias = (t##name *)dlsym(CudaDrvLib, STRINGIFY(name##_v3)); \
if (alias == NULL && required) { \ if (alias == NULL && required) { \
printf("Failed to find required function \"%s\" in %s\n", \ printf("Failed to find required function \"%s\" in %s\n", STRINGIFY(name##_v3), __CudaLibName); \
STRINGIFY(name##_v3), __CudaLibName); \
return CUDA_ERROR_UNKNOWN; \ return CUDA_ERROR_UNKNOWN; \
} }
@ -337,13 +330,13 @@ static CUresult LOAD_LIBRARY(CUDADRIVER *pInstance)
if (CUDA_SUCCESS != result) { \ if (CUDA_SUCCESS != result) { \
return result; \ return result; \
} \ } \
} while(0) } while (0)
#define GET_PROC_REQUIRED(name) GET_PROC_EX(name,name,1) #define GET_PROC_REQUIRED(name) GET_PROC_EX(name, name, 1)
#define GET_PROC_OPTIONAL(name) GET_PROC_EX(name,name,0) #define GET_PROC_OPTIONAL(name) GET_PROC_EX(name, name, 0)
#define GET_PROC(name) GET_PROC_REQUIRED(name) #define GET_PROC(name) GET_PROC_REQUIRED(name)
#define GET_PROC_V2(name) GET_PROC_EX_V2(name,name,1) #define GET_PROC_V2(name) GET_PROC_EX_V2(name, name, 1)
#define GET_PROC_V3(name) GET_PROC_EX_V3(name,name,1) #define GET_PROC_V3(name) GET_PROC_EX_V3(name, name, 1)
CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion) CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
{ {
@ -359,8 +352,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
// available since 2.2. if not present, version 1.0 is assumed // available since 2.2. if not present, version 1.0 is assumed
GET_PROC_OPTIONAL(cuDriverGetVersion); GET_PROC_OPTIONAL(cuDriverGetVersion);
if (cuDriverGetVersion) if (cuDriverGetVersion) {
{
CHECKED_CALL(cuDriverGetVersion(&driverVer)); CHECKED_CALL(cuDriverGetVersion(&driverVer));
} }
@ -428,24 +420,21 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC(cuStreamDestroy); GET_PROC(cuStreamDestroy);
// These are CUDA 5.0 new functions // These are CUDA 5.0 new functions
if (driverVer >= 5000) if (driverVer >= 5000) {
{
GET_PROC(cuMipmappedArrayCreate); GET_PROC(cuMipmappedArrayCreate);
GET_PROC(cuMipmappedArrayDestroy); GET_PROC(cuMipmappedArrayDestroy);
GET_PROC(cuMipmappedArrayGetLevel); GET_PROC(cuMipmappedArrayGetLevel);
} }
// These are CUDA 4.2 new functions // These are CUDA 4.2 new functions
if (driverVer >= 4020) if (driverVer >= 4020) {
{
GET_PROC(cuFuncSetSharedMemConfig); GET_PROC(cuFuncSetSharedMemConfig);
GET_PROC(cuCtxGetSharedMemConfig); GET_PROC(cuCtxGetSharedMemConfig);
GET_PROC(cuCtxSetSharedMemConfig); GET_PROC(cuCtxSetSharedMemConfig);
} }
// These are CUDA 4.1 new functions // These are CUDA 4.1 new functions
if (cudaVersion >= 4010 && __CUDA_API_VERSION >= 4010) if (cudaVersion >= 4010 && __CUDA_API_VERSION >= 4010) {
{
GET_PROC(cuDeviceGetByPCIBusId); GET_PROC(cuDeviceGetByPCIBusId);
GET_PROC(cuDeviceGetPCIBusId); GET_PROC(cuDeviceGetPCIBusId);
GET_PROC(cuIpcGetEventHandle); GET_PROC(cuIpcGetEventHandle);
@ -456,8 +445,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
} }
// These could be _v2 interfaces // These could be _v2 interfaces
if (cudaVersion >= 4000 && __CUDA_API_VERSION >= 4000) if (cudaVersion >= 4000 && __CUDA_API_VERSION >= 4000) {
{
GET_PROC_V2(cuCtxDestroy); GET_PROC_V2(cuCtxDestroy);
GET_PROC_V2(cuCtxPopCurrent); GET_PROC_V2(cuCtxPopCurrent);
GET_PROC_V2(cuCtxPushCurrent); GET_PROC_V2(cuCtxPushCurrent);
@ -465,8 +453,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC_V2(cuEventDestroy); GET_PROC_V2(cuEventDestroy);
} }
if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) {
{
GET_PROC_V2(cuDeviceTotalMem); GET_PROC_V2(cuDeviceTotalMem);
GET_PROC_V2(cuCtxCreate); GET_PROC_V2(cuCtxCreate);
GET_PROC_V2(cuModuleGetGlobal); GET_PROC_V2(cuModuleGetGlobal);
@ -507,17 +494,14 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC_V2(cuTexRefSetAddress); GET_PROC_V2(cuTexRefSetAddress);
GET_PROC_V2(cuTexRefGetAddress); GET_PROC_V2(cuTexRefGetAddress);
if (cudaVersion >= 4010 && __CUDA_API_VERSION >= 4010) if (cudaVersion >= 4010 && __CUDA_API_VERSION >= 4010) {
{
GET_PROC_V3(cuTexRefSetAddress2D); GET_PROC_V3(cuTexRefSetAddress2D);
} }
else else {
{
GET_PROC_V2(cuTexRefSetAddress2D); GET_PROC_V2(cuTexRefSetAddress2D);
} }
} }
else else {
{
// versions earlier than 3020 // versions earlier than 3020
GET_PROC(cuDeviceTotalMem); GET_PROC(cuDeviceTotalMem);
GET_PROC(cuCtxCreate); GET_PROC(cuCtxCreate);
@ -562,8 +546,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
} }
// The following functions are specific to CUDA versions // The following functions are specific to CUDA versions
if (driverVer >= 4000) if (driverVer >= 4000) {
{
GET_PROC(cuCtxSetCurrent); GET_PROC(cuCtxSetCurrent);
GET_PROC(cuCtxGetCurrent); GET_PROC(cuCtxGetCurrent);
GET_PROC(cuMemHostRegister); GET_PROC(cuMemHostRegister);
@ -574,8 +557,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC(cuProfilerStop); GET_PROC(cuProfilerStop);
} }
if (driverVer >= 3010) if (driverVer >= 3010) {
{
GET_PROC(cuModuleGetSurfRef); GET_PROC(cuModuleGetSurfRef);
GET_PROC(cuSurfRefSetArray); GET_PROC(cuSurfRefSetArray);
GET_PROC(cuSurfRefGetArray); GET_PROC(cuSurfRefGetArray);
@ -583,8 +565,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC(cuCtxGetLimit); GET_PROC(cuCtxGetLimit);
} }
if (driverVer >= 3000) if (driverVer >= 3000) {
{
GET_PROC(cuMemcpyDtoDAsync); GET_PROC(cuMemcpyDtoDAsync);
GET_PROC(cuFuncSetCacheConfig); GET_PROC(cuFuncSetCacheConfig);
#ifdef CUDA_INIT_D3D11 #ifdef CUDA_INIT_D3D11
@ -595,12 +576,10 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC(cuGraphicsUnregisterResource); GET_PROC(cuGraphicsUnregisterResource);
GET_PROC(cuGraphicsSubResourceGetMappedArray); GET_PROC(cuGraphicsSubResourceGetMappedArray);
if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) if (cudaVersion >= 3020 && __CUDA_API_VERSION >= 3020) {
{
GET_PROC_V2(cuGraphicsResourceGetMappedPointer); GET_PROC_V2(cuGraphicsResourceGetMappedPointer);
} }
else else {
{
GET_PROC(cuGraphicsResourceGetMappedPointer); GET_PROC(cuGraphicsResourceGetMappedPointer);
} }
@ -610,8 +589,7 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
GET_PROC(cuGetExportTable); GET_PROC(cuGetExportTable);
} }
if (driverVer >= 2030) if (driverVer >= 2030) {
{
GET_PROC(cuMemHostGetFlags); GET_PROC(cuMemHostGetFlags);
#ifdef CUDA_INIT_D3D10 #ifdef CUDA_INIT_D3D10
GET_PROC(cuD3D10GetDevice); GET_PROC(cuD3D10GetDevice);
@ -624,17 +602,16 @@ CUresult CUDAAPI cuInit(unsigned int Flags, int cudaVersion)
#endif #endif
} }
if (driverVer >= 2010) if (driverVer >= 2010) {
{
GET_PROC(cuModuleLoadDataEx); GET_PROC(cuModuleLoadDataEx);
GET_PROC(cuModuleLoadFatBinary); GET_PROC(cuModuleLoadFatBinary);
#ifdef CUDA_INIT_OPENGL #ifdef CUDA_INIT_OPENGL
GET_PROC(cuGLCtxCreate); GET_PROC(cuGLCtxCreate);
GET_PROC(cuGraphicsGLRegisterBuffer); GET_PROC(cuGraphicsGLRegisterBuffer);
GET_PROC(cuGraphicsGLRegisterImage); GET_PROC(cuGraphicsGLRegisterImage);
# ifdef WIN32 #ifdef WIN32
GET_PROC(cuWGLGetDevice); GET_PROC(cuWGLGetDevice);
# endif #endif
#endif #endif
#ifdef CUDA_INIT_D3D9 #ifdef CUDA_INIT_D3D9
GET_PROC(cuD3D9GetDevice); GET_PROC(cuD3D9GetDevice);

View File

@ -14,21 +14,17 @@
#ifndef HELPER_CUDA_DRVAPI_H #ifndef HELPER_CUDA_DRVAPI_H
#define HELPER_CUDA_DRVAPI_H #define HELPER_CUDA_DRVAPI_H
#include <helper_string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <helper_string.h>
#ifndef MAX #ifndef MAX
#define MAX(a, b) (a > b ? a : b) #define MAX(a, b) (a > b ? a : b)
#endif #endif
#ifndef HELPER_CUDA_DRVAPI_H #ifndef HELPER_CUDA_DRVAPI_H
inline int ftoi(float value) { inline int ftoi(float value) { return (value >= 0 ? static_cast<int>(value + 0.5) : static_cast<int>(value - 0.5)); }
return (value >= 0 ? static_cast<int>(value + 0.5)
: static_cast<int>(value - 0.5));
}
#endif #endif
#ifndef EXIT_WAIVED #ifndef EXIT_WAIVED
@ -47,39 +43,43 @@ inline int ftoi(float value) {
#define checkCudaErrors(err) __checkCudaErrors(err, __FILE__, __LINE__) #define checkCudaErrors(err) __checkCudaErrors(err, __FILE__, __LINE__)
// These are the inline versions for all of the SDK helper functions // These are the inline versions for all of the SDK helper functions
inline void __checkCudaErrors(CUresult err, const char *file, const int line) { inline void __checkCudaErrors(CUresult err, const char *file, const int line)
{
if (CUDA_SUCCESS != err) { if (CUDA_SUCCESS != err) {
const char *errorStr = NULL; const char *errorStr = NULL;
cuGetErrorString(err, &errorStr); cuGetErrorString(err, &errorStr);
fprintf(stderr, fprintf(stderr,
"checkCudaErrors() Driver API error = %04d \"%s\" from file <%s>, " "checkCudaErrors() Driver API error = %04d \"%s\" from file <%s>, "
"line %i.\n", "line %i.\n",
err, errorStr, file, line); err,
errorStr,
file,
line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
#endif #endif
// This function wraps the CUDA Driver API into a template function // This function wraps the CUDA Driver API into a template function
template <class T> template <class T> inline void getCudaAttribute(T *attribute, CUdevice_attribute device_attribute, int device)
inline void getCudaAttribute(T *attribute, CUdevice_attribute device_attribute, {
int device) {
checkCudaErrors(cuDeviceGetAttribute(attribute, device_attribute, device)); checkCudaErrors(cuDeviceGetAttribute(attribute, device_attribute, device));
} }
#endif #endif
// Beginning of GPU Architecture definitions // Beginning of GPU Architecture definitions
inline int _ConvertSMVer2CoresDRV(int major, int minor) { inline int _ConvertSMVer2CoresDRV(int major, int minor)
{
// Defines for GPU Architecture types (using the SM version to determine the # // Defines for GPU Architecture types (using the SM version to determine the #
// of cores per SM // of cores per SM
typedef struct { typedef struct
{
int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM
// minor version // minor version
int Cores; int Cores;
} sSMtoCores; } sSMtoCores;
sSMtoCores nGpuArchCoresPerSM[] = { sSMtoCores nGpuArchCoresPerSM[] = {{0x30, 192},
{0x30, 192},
{0x32, 192}, {0x32, 192},
{0x35, 192}, {0x35, 192},
{0x37, 192}, {0x37, 192},
@ -110,16 +110,18 @@ inline int _ConvertSMVer2CoresDRV(int major, int minor) {
// If we don't find the values, we default use the previous one to run // If we don't find the values, we default use the previous one to run
// properly // properly
printf( printf("MapSMtoCores for SM %d.%d is undefined. Default to use %d Cores/SM\n",
"MapSMtoCores for SM %d.%d is undefined. Default to use %d Cores/SM\n", major,
major, minor, nGpuArchCoresPerSM[index - 1].Cores); minor,
nGpuArchCoresPerSM[index - 1].Cores);
return nGpuArchCoresPerSM[index - 1].Cores; return nGpuArchCoresPerSM[index - 1].Cores;
} }
// end of GPU Architecture definitions // end of GPU Architecture definitions
#ifdef __cuda_cuda_h__ #ifdef __cuda_cuda_h__
// General GPU Device CUDA Initialization // General GPU Device CUDA Initialization
inline int gpuDeviceInitDRV(int ARGC, const char **ARGV) { inline int gpuDeviceInitDRV(int ARGC, const char **ARGV)
{
int cuDevice = 0; int cuDevice = 0;
int deviceCount = 0; int deviceCount = 0;
checkCudaErrors(cuInit(0, __CUDA_API_VERSION)); checkCudaErrors(cuInit(0, __CUDA_API_VERSION));
@ -140,11 +142,8 @@ inline int gpuDeviceInitDRV(int ARGC, const char **ARGV) {
if (dev > deviceCount - 1) { if (dev > deviceCount - 1) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, ">> %d CUDA capable GPU device(s) detected. <<\n", fprintf(stderr, ">> %d CUDA capable GPU device(s) detected. <<\n", deviceCount);
deviceCount); fprintf(stderr, ">> cudaDeviceInit (-device=%d) is not a valid GPU device. <<\n", dev);
fprintf(stderr,
">> cudaDeviceInit (-device=%d) is not a valid GPU device. <<\n",
dev);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
return -dev; return -dev;
} }
@ -171,7 +170,8 @@ inline int gpuDeviceInitDRV(int ARGC, const char **ARGV) {
} }
// This function returns the best GPU based on performance // This function returns the best GPU based on performance
inline int gpuGetMaxGflopsDeviceIdDRV() { inline int gpuGetMaxGflopsDeviceIdDRV()
{
CUdevice current_device = 0; CUdevice current_device = 0;
CUdevice max_perf_device = 0; CUdevice max_perf_device = 0;
int device_count = 0; int device_count = 0;
@ -187,8 +187,7 @@ inline int gpuGetMaxGflopsDeviceIdDRV() {
checkCudaErrors(cuDeviceGetCount(&device_count)); checkCudaErrors(cuDeviceGetCount(&device_count));
if (device_count == 0) { if (device_count == 0) {
fprintf(stderr, fprintf(stderr, "gpuGetMaxGflopsDeviceIdDRV error: no devices supporting CUDA\n");
"gpuGetMaxGflopsDeviceIdDRV error: no devices supporting CUDA\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -196,36 +195,31 @@ inline int gpuGetMaxGflopsDeviceIdDRV() {
current_device = 0; current_device = 0;
while (current_device < device_count) { while (current_device < device_count) {
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(
&multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, cuDeviceGetAttribute(&multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, current_device));
current_device)); checkCudaErrors(cuDeviceGetAttribute(&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device));
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
&clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, current_device)); checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
checkCudaErrors(cuDeviceGetAttribute(
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
checkCudaErrors(cuDeviceGetAttribute(
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
int computeMode; int computeMode;
getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, getCudaAttribute<int>(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device);
current_device);
if (computeMode != CU_COMPUTEMODE_PROHIBITED) { if (computeMode != CU_COMPUTEMODE_PROHIBITED) {
if (major == 9999 && minor == 9999) { if (major == 9999 && minor == 9999) {
sm_per_multiproc = 1; sm_per_multiproc = 1;
} else { }
else {
sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor); sm_per_multiproc = _ConvertSMVer2CoresDRV(major, minor);
} }
unsigned long long compute_perf = unsigned long long compute_perf = (unsigned long long)(multiProcessorCount * sm_per_multiproc * clockRate);
(unsigned long long)(multiProcessorCount * sm_per_multiproc *
clockRate);
if (compute_perf > max_compute_perf) { if (compute_perf > max_compute_perf) {
max_compute_perf = compute_perf; max_compute_perf = compute_perf;
max_perf_device = current_device; max_perf_device = current_device;
} }
} else { }
else {
devices_prohibited++; devices_prohibited++;
} }
@ -243,7 +237,8 @@ inline int gpuGetMaxGflopsDeviceIdDRV() {
} }
// General initialization call to pick the best CUDA Device // General initialization call to pick the best CUDA Device
inline CUdevice findCudaDeviceDRV(int argc, const char **argv) { inline CUdevice findCudaDeviceDRV(int argc, const char **argv)
{
CUdevice cuDevice; CUdevice cuDevice;
int devID = 0; int devID = 0;
@ -255,7 +250,8 @@ inline CUdevice findCudaDeviceDRV(int argc, const char **argv) {
printf("exiting...\n"); printf("exiting...\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
} else { }
else {
// Otherwise pick the device with highest Gflops/s // Otherwise pick the device with highest Gflops/s
char name[100]; char name[100];
devID = gpuGetMaxGflopsDeviceIdDRV(); devID = gpuGetMaxGflopsDeviceIdDRV();
@ -269,7 +265,8 @@ inline CUdevice findCudaDeviceDRV(int argc, const char **argv) {
return cuDevice; return cuDevice;
} }
inline CUdevice findIntegratedGPUDrv() { inline CUdevice findIntegratedGPUDrv()
{
CUdevice current_device = 0; CUdevice current_device = 0;
int device_count = 0; int device_count = 0;
int devices_prohibited = 0; int devices_prohibited = 0;
@ -286,28 +283,22 @@ inline CUdevice findIntegratedGPUDrv() {
// Find the integrated GPU which is compute capable // Find the integrated GPU which is compute capable
while (current_device < device_count) { while (current_device < device_count) {
int computeMode = -1; int computeMode = -1;
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(cuDeviceGetAttribute(&isIntegrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, current_device));
&isIntegrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, current_device)); checkCudaErrors(cuDeviceGetAttribute(&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device));
checkCudaErrors(cuDeviceGetAttribute(
&computeMode, CU_DEVICE_ATTRIBUTE_COMPUTE_MODE, current_device));
// If GPU is integrated and is not running on Compute Mode prohibited use // If GPU is integrated and is not running on Compute Mode prohibited use
// that // that
if (isIntegrated && (computeMode != CU_COMPUTEMODE_PROHIBITED)) { if (isIntegrated && (computeMode != CU_COMPUTEMODE_PROHIBITED)) {
int major = 0, minor = 0; int major = 0, minor = 0;
char deviceName[256]; char deviceName[256];
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, current_device));
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, current_device));
current_device));
checkCudaErrors(cuDeviceGetAttribute(
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
current_device));
checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device)); checkCudaErrors(cuDeviceGetName(deviceName, 256, current_device));
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", current_device, deviceName, major, minor);
current_device, deviceName, major, minor);
return current_device; return current_device;
} else { }
else {
devices_prohibited++; devices_prohibited++;
} }
@ -323,35 +314,31 @@ inline CUdevice findIntegratedGPUDrv() {
} }
// General check for CUDA GPU SM Capabilities // General check for CUDA GPU SM Capabilities
inline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, inline bool checkCudaCapabilitiesDRV(int major_version, int minor_version, int devID)
int devID) { {
CUdevice cuDevice; CUdevice cuDevice;
char name[256]; char name[256];
int major = 0, minor = 0; int major = 0, minor = 0;
checkCudaErrors(cuDeviceGet(&cuDevice, devID)); checkCudaErrors(cuDeviceGet(&cuDevice, devID));
checkCudaErrors(cuDeviceGetName(name, 100, cuDevice)); checkCudaErrors(cuDeviceGetName(name, 100, cuDevice));
checkCudaErrors(cuDeviceGetAttribute( checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice));
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice)); checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
checkCudaErrors(cuDeviceGetAttribute(
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
if ((major > major_version) || if ((major > major_version) || (major == major_version && minor >= minor_version)) {
(major == major_version && minor >= minor_version)) { printf("> Device %d: <%16s >, Compute SM %d.%d detected\n", devID, name, major, minor);
printf("> Device %d: <%16s >, Compute SM %d.%d detected\n", devID, name,
major, minor);
return true; return true;
} else { }
printf( else {
"No GPU device was found that can support CUDA compute capability " printf("No GPU device was found that can support CUDA compute capability "
"%d.%d.\n", "%d.%d.\n",
major_version, minor_version); major_version,
minor_version);
return false; return false;
} }
} }
#endif #endif
// end of CUDA Helper Functions // end of CUDA Helper Functions
#endif // HELPER_CUDA_DRVAPI_H #endif // HELPER_CUDA_DRVAPI_H

View File

@ -43,10 +43,10 @@
*/ */
// includes, system // includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, CUDA // includes, CUDA
#include "cuda_drvapi_dynlink.h" #include "cuda_drvapi_dynlink.h"
@ -60,7 +60,7 @@
extern "C" void computeGold(float *, const float *, const float *, unsigned int, unsigned int, unsigned int); extern "C" void computeGold(float *, const float *, const float *, unsigned int, unsigned int, unsigned int);
#if defined _MSC_VER #if defined _MSC_VER
#pragma warning (disable : 4312) #pragma warning(disable : 4312)
#endif #endif
@ -78,8 +78,7 @@ static const char *sSDKsample = "matrixMulDynlinkJIT (CUDA dynamic linking)";
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void randomInit(float *data, size_t size) void randomInit(float *data, size_t size)
{ {
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i) {
{
data[i] = rand() / (float)RAND_MAX; data[i] = rand() / (float)RAND_MAX;
} }
} }
@ -100,18 +99,14 @@ CUresult initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *block_size
checkCudaErrors(cuInit(0, __CUDA_API_VERSION)); checkCudaErrors(cuInit(0, __CUDA_API_VERSION));
// This assumes that the user is attempting to specify a explicit device -device=n // This assumes that the user is attempting to specify a explicit device -device=n
if (argc > 1) if (argc > 1) {
{
bool bFound = false; bool bFound = false;
for (int param=0; param < argc; param++) for (int param = 0; param < argc; param++) {
{ if (!strncmp(argv[param], "-device", 7)) {
if (!strncmp(argv[param], "-device", 7)) int i = (int)strlen(argv[1]);
{
int i=(int)strlen(argv[1]);
while (argv[1][i] != '=') while (argv[1][i] != '=') {
{
i--; i--;
} }
@ -128,16 +123,15 @@ CUresult initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *block_size
int deviceCount = 0; int deviceCount = 0;
checkCudaErrors(cuDeviceGetCount(&deviceCount)); checkCudaErrors(cuDeviceGetCount(&deviceCount));
if (deviceCount == 0) if (deviceCount == 0) {
{
fprintf(stderr, "No devices supporting CUDA detected, exiting...\n"); fprintf(stderr, "No devices supporting CUDA detected, exiting...\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
if (devID < 0) devID = 0; if (devID < 0)
devID = 0;
if (devID > deviceCount -1) if (devID > deviceCount - 1) {
{
fprintf(stderr, "initCUDA (Device=%d) invalid GPU device. %d GPU device(s) detected.\n\n", devID, deviceCount); fprintf(stderr, "initCUDA (Device=%d) invalid GPU device. %d GPU device(s) detected.\n\n", devID, deviceCount);
status = CUDA_ERROR_NOT_FOUND; status = CUDA_ERROR_NOT_FOUND;
@ -159,8 +153,7 @@ CUresult initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *block_size
// create context for picked device // create context for picked device
status = cuCtxCreate(&g_cuContext, 0, cuDevice); status = cuCtxCreate(&g_cuContext, 0, cuDevice);
if (CUDA_SUCCESS != status) if (CUDA_SUCCESS != status) {
{
cuCtxDestroy(g_cuContext); cuCtxDestroy(g_cuContext);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -191,31 +184,31 @@ CUresult initCUDA(int argc, char **argv, CUfunction *pMatrixMul, int *block_size
printf("> Compiling CUDA module\n"); printf("> Compiling CUDA module\n");
#if defined(_WIN64) || defined(__LP64__) #if defined(_WIN64) || defined(__LP64__)
status = cuModuleLoadDataEx(&cuModule, matrixMul_kernel_64_ptxdump, jitNumOptions, jitOptions, (void **)jitOptVals); status =
cuModuleLoadDataEx(&cuModule, matrixMul_kernel_64_ptxdump, jitNumOptions, jitOptions, (void **)jitOptVals);
#else #else
status = cuModuleLoadDataEx(&cuModule, matrixMul_kernel_32_ptxdump, jitNumOptions, jitOptions, (void **)jitOptVals); status =
cuModuleLoadDataEx(&cuModule, matrixMul_kernel_32_ptxdump, jitNumOptions, jitOptions, (void **)jitOptVals);
#endif #endif
printf("> PTX JIT log:\n%s\n", jitLogBuffer); printf("> PTX JIT log:\n%s\n", jitLogBuffer);
delete [] jitOptions; delete[] jitOptions;
delete [] jitOptVals; delete[] jitOptVals;
delete [] jitLogBuffer; delete[] jitLogBuffer;
} }
if (CUDA_SUCCESS != status) if (CUDA_SUCCESS != status) {
{
printf("Error while compiling PTX\n"); printf("Error while compiling PTX\n");
cuCtxDestroy(g_cuContext); cuCtxDestroy(g_cuContext);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// retrieve CUDA function from the compiled module // retrieve CUDA function from the compiled module
status = cuModuleGetFunction(&cuFunction, cuModule, status = cuModuleGetFunction(
(block_size == 16) ? "matrixMul_bs16_32bit" : "matrixMul_bs32_32bit"); &cuFunction, cuModule, (block_size == 16) ? "matrixMul_bs16_32bit" : "matrixMul_bs32_32bit");
if (CUDA_SUCCESS != status) if (CUDA_SUCCESS != status) {
{
cuCtxDestroy(g_cuContext); cuCtxDestroy(g_cuContext);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -246,8 +239,8 @@ int main(int argc, char **argv)
size_t size_B = WB * HB; size_t size_B = WB * HB;
size_t mem_size_B = sizeof(float) * size_B; size_t mem_size_B = sizeof(float) * size_B;
float *h_A = (float *) malloc(mem_size_A); float *h_A = (float *)malloc(mem_size_A);
float *h_B = (float *) malloc(mem_size_B); float *h_B = (float *)malloc(mem_size_B);
// initialize host memory // initialize host memory
randomInit(h_A, size_A); randomInit(h_A, size_A);
@ -271,19 +264,17 @@ int main(int argc, char **argv)
checkCudaErrors(cuMemAlloc(&d_C, mem_size_C)); checkCudaErrors(cuMemAlloc(&d_C, mem_size_C));
// allocate mem for the result on host side // allocate mem for the result on host side
float *h_C = (float *) malloc(mem_size_C); float *h_C = (float *)malloc(mem_size_C);
#if __CUDA_API_VERSION >= 4000 #if __CUDA_API_VERSION >= 4000
{ {
// This is the new CUDA 4.0 API for Kernel Parameter passing and Kernel Launching (simpler method) // This is the new CUDA 4.0 API for Kernel Parameter passing and Kernel Launching (simpler method)
int Matrix_Width_A = WA; int Matrix_Width_A = WA;
int Matrix_Width_B = WB; int Matrix_Width_B = WB;
void *args[5] = { &d_C, &d_A, &d_B, &Matrix_Width_A, &Matrix_Width_B }; void *args[5] = {&d_C, &d_A, &d_B, &Matrix_Width_A, &Matrix_Width_B};
checkCudaErrors(cuLaunchKernel(matrixMul, (WC/block_size), (HC/block_size), 1, checkCudaErrors(cuLaunchKernel(
block_size , block_size , 1, matrixMul, (WC / block_size), (HC / block_size), 1, block_size, block_size, 1, 0, NULL, args, NULL));
0,
NULL, args, NULL));
} }
#else // __CUDA_API_VERSION <= 3020 #else // __CUDA_API_VERSION <= 3020
{ {
@ -312,7 +303,7 @@ int main(int argc, char **argv)
checkCudaErrors(cuParamSetSize(matrixMul, offset)); checkCudaErrors(cuParamSetSize(matrixMul, offset));
checkCudaErrors(cuFuncSetBlockShape(matrixMul, block_size, block_size, 1)); checkCudaErrors(cuFuncSetBlockShape(matrixMul, block_size, block_size, 1));
checkCudaErrors(cuFuncSetSharedSize(matrixMul, 2*block_size*block_size*sizeof(float))); checkCudaErrors(cuFuncSetSharedSize(matrixMul, 2 * block_size * block_size * sizeof(float)));
// set execution configuration for the CUDA kernel // set execution configuration for the CUDA kernel
checkCudaErrors(cuLaunchGrid(matrixMul, WC / block_size, HC / block_size)); checkCudaErrors(cuLaunchGrid(matrixMul, WC / block_size, HC / block_size));
@ -322,19 +313,18 @@ int main(int argc, char **argv)
checkCudaErrors(cuCtxSynchronize()); checkCudaErrors(cuCtxSynchronize());
// copy result from device to host // copy result from device to host
checkCudaErrors(cuMemcpyDtoH((void *) h_C, d_C, mem_size_C)); checkCudaErrors(cuMemcpyDtoH((void *)h_C, d_C, mem_size_C));
// compute reference solution // compute reference solution
float *reference = (float *) malloc(mem_size_C); float *reference = (float *)malloc(mem_size_C);
computeGold(reference, h_A, h_B, HA, WA, WB); computeGold(reference, h_A, h_B, HA, WA, WB);
// check result // check result
float diff=0.0f; float diff = 0.0f;
for (unsigned int i=0; i<size_C; i++) for (unsigned int i = 0; i < size_C; i++) {
{
float tmp = reference[i] - h_C[i]; float tmp = reference[i] - h_C[i];
diff += tmp*tmp; diff += tmp * tmp;
} }
int res = (diff / (float)size_C < 1e-6f); int res = (diff / (float)size_C < 1e-6f);
@ -349,7 +339,7 @@ int main(int argc, char **argv)
checkCudaErrors(cuMemFree(d_C)); checkCudaErrors(cuMemFree(d_C));
checkCudaErrors(cuCtxDestroy(g_cuContext)); checkCudaErrors(cuCtxDestroy(g_cuContext));
printf("Test run %s\n", (1==res) ? "success!" : "failed!"); printf("Test run %s\n", (1 == res) ? "success!" : "failed!");
exit((1 == res) ? EXIT_SUCCESS : EXIT_FAILURE); exit((1 == res) ? EXIT_SUCCESS : EXIT_FAILURE);
} }

View File

@ -28,8 +28,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// export C interface // export C interface
extern "C" extern "C" void computeGold(float *, const float *, const float *, unsigned int, unsigned int, unsigned int);
void computeGold(float *, const float *, const float *, unsigned int, unsigned int, unsigned int);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Compute reference data set //! Compute reference data set
@ -40,16 +39,13 @@ void computeGold(float *, const float *, const float *, unsigned int, unsigned i
//! @param hA height of matrix A //! @param hA height of matrix A
//! @param wB width of matrix B //! @param wB width of matrix B
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void void computeGold(float *C, const float *A, const float *B, unsigned int hA, unsigned int wA, unsigned int wB)
computeGold(float *C, const float *A, const float *B, unsigned int hA, unsigned int wA, unsigned int wB)
{ {
for (unsigned int i = 0; i < hA; ++i) for (unsigned int i = 0; i < hA; ++i)
for (unsigned int j = 0; j < wB; ++j) for (unsigned int j = 0; j < wB; ++j) {
{
double sum = 0; double sum = 0;
for (unsigned int k = 0; k < wA; ++k) for (unsigned int k = 0; k < wA; ++k) {
{
double a = A[i * wA + k]; double a = A[i * wA + k];
double b = B[k * wB + j]; double b = B[k * wB + j];
sum += a * b; sum += a * b;

View File

@ -32,7 +32,8 @@
#define __matrixMul_kernel_32_ptxdump_h__ #define __matrixMul_kernel_32_ptxdump_h__
#if defined __cplusplus #if defined __cplusplus
extern "C" { extern "C"
{
#endif #endif
extern unsigned char matrixMul_kernel_32_ptxdump[25784]; extern unsigned char matrixMul_kernel_32_ptxdump[25784];

View File

@ -32,7 +32,8 @@
#define __matrixMul_kernel_64_ptxdump_h__ #define __matrixMul_kernel_64_ptxdump_h__
#if defined __cplusplus #if defined __cplusplus
extern "C" { extern "C"
{
#endif #endif
extern unsigned char matrixMul_kernel_64_ptxdump[26489]; extern unsigned char matrixMul_kernel_64_ptxdump[26489];

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -2,7 +2,7 @@
## Description ## Description
This sample implements matrix multiplication and is exactly the same as Chapter 6 of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the new CUDA 4.0 interface for CUBLAS to demonstrate high-performance performance for matrix multiplication. This sample implements matrix multiplication and is exactly the same as the second example of the [Shared Memory](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory) section of the programming guide. It has been written for clarity of exposition to illustrate various CUDA programming principles, not with the goal of providing the most performant generic kernel for matrix multiplication. To illustrate GPU performance for matrix multiply, this sample also shows how to use the CUDA 4.0+ interface for cuBLAS to demonstrate high-performance performance for matrix multiplication.
## Key Concepts ## Key Concepts
@ -30,7 +30,7 @@ cuMemcpyDtoH, cuLaunchKernel, cuMemcpyHtoD, cuCtxSynchronize, cuMemAlloc, cuMemF
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -42,17 +42,19 @@
*/ */
// System includes // System includes
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
// CUDA runtime // CUDA runtime
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include "nvrtc_helper.h" #include "nvrtc_helper.h"
// Helper functions and utilities to work with CUDA // Helper functions and utilities to work with CUDA
#include <helper_functions.h> #include <helper_functions.h>
void constantInit(float *data, int size, float val) { void constantInit(float *data, int size, float val)
{
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
data[i] = val; data[i] = val;
} }
@ -61,8 +63,8 @@ void constantInit(float *data, int size, float val) {
/** /**
* Run a simple test of matrix multiplication using CUDA * Run a simple test of matrix multiplication using CUDA
*/ */
int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA, int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA, dim3 &dimsB)
dim3 &dimsB) { {
// Allocate host memory for matrices A and B // Allocate host memory for matrices A and B
unsigned int size_A = dimsA.x * dimsA.y; unsigned int size_A = dimsA.x * dimsA.y;
unsigned int mem_size_A = sizeof(float) * size_A; unsigned int mem_size_A = sizeof(float) * size_A;
@ -114,24 +116,27 @@ int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA,
CUfunction kernel_addr; CUfunction kernel_addr;
if (block_size == 16) { if (block_size == 16) {
checkCudaErrors( checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block16"));
cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block16")); }
} else { else {
checkCudaErrors( checkCudaErrors(cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block32"));
cuModuleGetFunction(&kernel_addr, module, "matrixMulCUDA_block32"));
} }
void *arr[] = {(void *)&d_C, (void *)&d_A, (void *)&d_B, (void *)&dimsA.x, void *arr[] = {(void *)&d_C, (void *)&d_A, (void *)&d_B, (void *)&dimsA.x, (void *)&dimsB.x};
(void *)&dimsB.x};
// Execute the kernel // Execute the kernel
int nIter = 300; int nIter = 300;
for (int j = 0; j < nIter; j++) { for (int j = 0; j < nIter; j++) {
checkCudaErrors( checkCudaErrors(cuLaunchKernel(kernel_addr,
cuLaunchKernel(kernel_addr, grid.x, grid.y, grid.z, /* grid dim */ grid.x,
threads.x, threads.y, threads.z, /* block dim */ grid.y,
0, 0, /* shared mem, stream */ grid.z, /* grid dim */
threads.x,
threads.y,
threads.z, /* block dim */
0,
0, /* shared mem, stream */
&arr[0], /* arguments */ &arr[0], /* arguments */
0)); 0));
@ -157,16 +162,14 @@ int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA,
double rel_err = abs_err / abs_val / dot_length; double rel_err = abs_err / abs_val / dot_length;
if (rel_err > eps) { if (rel_err > eps) {
printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > %E\n", i, printf("Error! Matrix[%05d]=%.8f, ref=%.8f error term is > %E\n", i, h_C[i], dimsA.x * valB, eps);
h_C[i], dimsA.x * valB, eps);
correct = false; correct = false;
} }
} }
printf("%s\n", correct ? "Result = PASS" : "Result = FAIL"); printf("%s\n", correct ? "Result = PASS" : "Result = FAIL");
printf( printf("\nNOTE: The CUDA Samples are not meant for performance measurements. "
"\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n"); "Results may vary when GPU Boost is enabled.\n");
// Clean up memory // Clean up memory
@ -180,7 +183,8 @@ int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA,
if (correct) { if (correct) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} else { }
else {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
@ -189,16 +193,15 @@ int matrixMultiply(int argc, char **argv, int block_size, dim3 &dimsA,
* Program main * Program main
*/ */
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("[Matrix Multiply Using CUDA] - Starting...\n"); printf("[Matrix Multiply Using CUDA] - Starting...\n");
if (checkCmdLineFlag(argc, (const char **)argv, "help") || if (checkCmdLineFlag(argc, (const char **)argv, "help") || checkCmdLineFlag(argc, (const char **)argv, "?")) {
checkCmdLineFlag(argc, (const char **)argv, "?")) {
printf("Usage -device=n (n >= 0 for deviceID)\n"); printf("Usage -device=n (n >= 0 for deviceID)\n");
printf(" -wA=WidthA -hA=HeightA (Width x Height of Matrix A)\n"); printf(" -wA=WidthA -hA=HeightA (Width x Height of Matrix A)\n");
printf(" -wB=WidthB -hB=HeightB (Width x Height of Matrix B)\n"); printf(" -wB=WidthB -hB=HeightB (Width x Height of Matrix B)\n");
printf( printf(" Note: Outer matrix dimensions of A & B matrices must be equal.\n");
" Note: Outer matrix dimensions of A & B matrices must be equal.\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
@ -234,13 +237,11 @@ int main(int argc, char **argv) {
} }
if (dimsA.x != dimsB.y) { if (dimsA.x != dimsB.y) {
printf("Error: outer matrix dimensions must be equal. (%d != %d)\n", printf("Error: outer matrix dimensions must be equal. (%d != %d)\n", dimsA.x, dimsB.y);
dimsA.x, dimsB.y);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, printf("MatrixA(%d,%d), MatrixB(%d,%d)\n", dimsA.x, dimsA.y, dimsB.x, dimsB.y);
dimsB.y);
int matrix_result = matrixMultiply(argc, argv, block_size, dimsA, dimsB); int matrix_result = matrixMultiply(argc, argv, block_size, dimsA, dimsB);

View File

@ -48,11 +48,10 @@
#include <cooperative_groups.h> #include <cooperative_groups.h>
template <int BLOCK_SIZE> template <int BLOCK_SIZE> __device__ void matrixMulCUDA(float *C, float *A, float *B, int wA, int wB)
__device__ void matrixMulCUDA(float *C, float *A, float *B, int wA, int wB) { {
// Handle to thread block group // Handle to thread block group
cooperative_groups::thread_block cta = cooperative_groups::thread_block cta = cooperative_groups::this_thread_block();
cooperative_groups::this_thread_block();
// Block index // Block index
int bx = blockIdx.x; int bx = blockIdx.x;
int by = blockIdx.y; int by = blockIdx.y;
@ -120,12 +119,12 @@ __device__ void matrixMulCUDA(float *C, float *A, float *B, int wA, int wB) {
C[c + wB * ty + tx] = Csub; C[c + wB * ty + tx] = Csub;
} }
extern "C" __global__ void matrixMulCUDA_block16(float *C, float *A, float *B, extern "C" __global__ void matrixMulCUDA_block16(float *C, float *A, float *B, int wA, int wB)
int wA, int wB) { {
matrixMulCUDA<16>(C, A, B, wA, wB); matrixMulCUDA<16>(C, A, B, wA, wB);
} }
extern "C" __global__ void matrixMulCUDA_block32(float *C, float *A, float *B, extern "C" __global__ void matrixMulCUDA_block32(float *C, float *A, float *B, int wA, int wB)
int wA, int wB) { {
matrixMulCUDA<32>(C, A, B, wA, wB); matrixMulCUDA<32>(C, A, B, wA, wB);
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaMalloc, cudaDeviceSynchronize, cudaMemcpy, cudaFree
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -28,12 +28,13 @@
#include <cooperative_groups.h> #include <cooperative_groups.h>
namespace cg = cooperative_groups; namespace cg = cooperative_groups;
#include <helper_cuda.h>
#include <assert.h> #include <assert.h>
#include <helper_cuda.h>
#include "mergeSort_common.h" #include "mergeSort_common.h"
inline __device__ void Comparator(uint &keyA, uint &valA, uint &keyB, inline __device__ void Comparator(uint &keyA, uint &valA, uint &keyB, uint &valB, uint arrowDir)
uint &valB, uint arrowDir) { {
uint t; uint t;
if ((keyA > keyB) == arrowDir) { if ((keyA > keyB) == arrowDir) {
@ -46,9 +47,9 @@ inline __device__ void Comparator(uint &keyA, uint &valA, uint &keyB,
} }
} }
__global__ void bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal, __global__ void
uint *d_SrcKey, uint *d_SrcVal, bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, uint *d_SrcVal, uint arrayLength, uint sortDir)
uint arrayLength, uint sortDir) { {
// Handle to thread block group // Handle to thread block group
cg::thread_block cta = cg::this_thread_block(); cg::thread_block cta = cg::this_thread_block();
// Shared memory storage for one or more short vectors // Shared memory storage for one or more short vectors
@ -62,10 +63,8 @@ __global__ void bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x; d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
s_key[threadIdx.x + 0] = d_SrcKey[0]; s_key[threadIdx.x + 0] = d_SrcKey[0];
s_val[threadIdx.x + 0] = d_SrcVal[0]; s_val[threadIdx.x + 0] = d_SrcVal[0];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcKey[(SHARED_SIZE_LIMIT / 2)];
d_SrcKey[(SHARED_SIZE_LIMIT / 2)]; s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] =
d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
for (uint size = 2; size < arrayLength; size <<= 1) { for (uint size = 2; size < arrayLength; size <<= 1) {
// Bitonic merge // Bitonic merge
@ -74,8 +73,7 @@ __global__ void bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
for (uint stride = size / 2; stride > 0; stride >>= 1) { for (uint stride = size / 2; stride > 0; stride >>= 1) {
cg::sync(cta); cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1)); uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], s_val[pos + stride], dir);
s_val[pos + stride], dir);
} }
} }
@ -84,26 +82,25 @@ __global__ void bitonicSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
for (uint stride = arrayLength / 2; stride > 0; stride >>= 1) { for (uint stride = arrayLength / 2; stride > 0; stride >>= 1) {
cg::sync(cta); cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1)); uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], Comparator(s_key[pos + 0], s_val[pos + 0], s_key[pos + stride], s_val[pos + stride], sortDir);
s_val[pos + stride], sortDir);
} }
} }
cg::sync(cta); cg::sync(cta);
d_DstKey[0] = s_key[threadIdx.x + 0]; d_DstKey[0] = s_key[threadIdx.x + 0];
d_DstVal[0] = s_val[threadIdx.x + 0]; d_DstVal[0] = s_val[threadIdx.x + 0];
d_DstKey[(SHARED_SIZE_LIMIT / 2)] = d_DstKey[(SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)]; d_DstVal[(SHARED_SIZE_LIMIT / 2)] = s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
d_DstVal[(SHARED_SIZE_LIMIT / 2)] =
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
} }
// Helper function (also used by odd-even merge sort) // Helper function (also used by odd-even merge sort)
extern "C" uint factorRadix2(uint *log2L, uint L) { extern "C" uint factorRadix2(uint *log2L, uint L)
{
if (!L) { if (!L) {
*log2L = 0; *log2L = 0;
return 0; return 0;
} else { }
else {
for (*log2L = 0; (L & 1) == 0; L >>= 1, *log2L++) for (*log2L = 0; (L & 1) == 0; L >>= 1, *log2L++)
; ;
@ -111,10 +108,14 @@ extern "C" uint factorRadix2(uint *log2L, uint L) {
} }
} }
extern "C" void bitonicSortShared(uint *d_DstKey, uint *d_DstVal, extern "C" void bitonicSortShared(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint batchSize, uint arrayLength, uint *d_SrcKey,
uint sortDir) { uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir)
{
// Nothing to sort // Nothing to sort
if (arrayLength < 2) { if (arrayLength < 2) {
return; return;
@ -131,32 +132,25 @@ extern "C" void bitonicSortShared(uint *d_DstKey, uint *d_DstVal,
assert(arrayLength <= SHARED_SIZE_LIMIT); assert(arrayLength <= SHARED_SIZE_LIMIT);
assert((batchSize * arrayLength) % SHARED_SIZE_LIMIT == 0); assert((batchSize * arrayLength) % SHARED_SIZE_LIMIT == 0);
bitonicSortSharedKernel<<<blockCount, threadCount>>>( bitonicSortSharedKernel<<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength, sortDir);
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength, sortDir);
getLastCudaError("bitonicSortSharedKernel<<<>>> failed!\n"); getLastCudaError("bitonicSortSharedKernel<<<>>> failed!\n");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Merge step 3: merge elementary intervals // Merge step 3: merge elementary intervals
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static inline __host__ __device__ uint iDivUp(uint a, uint b) { static inline __host__ __device__ uint iDivUp(uint a, uint b) { return ((a % b) == 0) ? (a / b) : (a / b + 1); }
return ((a % b) == 0) ? (a / b) : (a / b + 1);
}
static inline __host__ __device__ uint getSampleCount(uint dividend) { static inline __host__ __device__ uint getSampleCount(uint dividend) { return iDivUp(dividend, SAMPLE_STRIDE); }
return iDivUp(dividend, SAMPLE_STRIDE);
}
template <uint sortDir> template <uint sortDir>
static inline __device__ void ComparatorExtended(uint &keyA, uint &valA, static inline __device__ void
uint &flagA, uint &keyB, ComparatorExtended(uint &keyA, uint &valA, uint &flagA, uint &keyB, uint &valB, uint &flagB, uint arrowDir)
uint &valB, uint &flagB, {
uint arrowDir) {
uint t; uint t;
if ((!(flagA || flagB) && ((keyA > keyB) == arrowDir)) || if ((!(flagA || flagB) && ((keyA > keyB) == arrowDir)) || ((arrowDir == sortDir) && (flagA == 1))
((arrowDir == sortDir) && (flagA == 1)) || || ((arrowDir != sortDir) && (flagB == 1))) {
((arrowDir != sortDir) && (flagB == 1))) {
t = keyA; t = keyA;
keyA = keyB; keyA = keyB;
keyB = t; keyB = t;
@ -170,9 +164,15 @@ static inline __device__ void ComparatorExtended(uint &keyA, uint &valA,
} }
template <uint sortDir> template <uint sortDir>
__global__ void bitonicMergeElementaryIntervalsKernel( __global__ void bitonicMergeElementaryIntervalsKernel(uint *d_DstKey,
uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint *d_LimitsA, uint *d_LimitsB, uint stride, uint N) { uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N)
{
// Handle to thread block group // Handle to thread block group
cg::thread_block cta = cg::this_thread_block(); cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[2 * SAMPLE_STRIDE]; __shared__ uint s_key[2 * SAMPLE_STRIDE];
@ -200,10 +200,8 @@ __global__ void bitonicMergeElementaryIntervalsKernel(
startSrcB = d_LimitsB[blockIdx.x]; startSrcB = d_LimitsB[blockIdx.x];
startDst = startSrcA + startSrcB; startDst = startSrcA + startSrcB;
uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] : segmentElementsA;
: segmentElementsA; uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1] : segmentElementsB;
uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1]
: segmentElementsB;
lenSrcA = endSrcA - startSrcA; lenSrcA = endSrcA - startSrcA;
lenSrcB = endSrcB - startSrcB; lenSrcB = endSrcB - startSrcB;
} }
@ -222,10 +220,8 @@ __global__ void bitonicMergeElementaryIntervalsKernel(
// Prepare for bitonic merge by inversing the ordering // Prepare for bitonic merge by inversing the ordering
if (threadIdx.x < lenSrcB) { if (threadIdx.x < lenSrcB) {
s_key[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = s_key[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = d_SrcKey[stride + startSrcB + threadIdx.x];
d_SrcKey[stride + startSrcB + threadIdx.x]; s_val[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = d_SrcVal[stride + startSrcB + threadIdx.x];
s_val[2 * SAMPLE_STRIDE - 1 - threadIdx.x] =
d_SrcVal[stride + startSrcB + threadIdx.x];
s_inf[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = 0; s_inf[2 * SAMPLE_STRIDE - 1 - threadIdx.x] = 0;
} }
@ -233,9 +229,13 @@ __global__ void bitonicMergeElementaryIntervalsKernel(
for (uint stride = SAMPLE_STRIDE; stride > 0; stride >>= 1) { for (uint stride = SAMPLE_STRIDE; stride > 0; stride >>= 1) {
cg::sync(cta); cg::sync(cta);
uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1)); uint pos = 2 * threadIdx.x - (threadIdx.x & (stride - 1));
ComparatorExtended<sortDir>(s_key[pos + 0], s_val[pos + 0], s_inf[pos + 0], ComparatorExtended<sortDir>(s_key[pos + 0],
s_key[pos + stride], s_val[pos + stride], s_val[pos + 0],
s_inf[pos + stride], sortDir); s_inf[pos + 0],
s_key[pos + stride],
s_val[pos + stride],
s_inf[pos + stride],
sortDir);
} }
// Store sorted data // Store sorted data
@ -254,26 +254,28 @@ __global__ void bitonicMergeElementaryIntervalsKernel(
} }
} }
extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey, uint *d_DstVal, extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA, uint *d_LimitsA,
uint *d_LimitsB, uint stride, uint *d_LimitsB,
uint N, uint sortDir) { uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
? getSampleCount(N)
: (N - lastSegmentElements) / SAMPLE_STRIDE;
if (sortDir) { if (sortDir) {
bitonicMergeElementaryIntervalsKernel<1U><<<mergePairs, SAMPLE_STRIDE>>>( bitonicMergeElementaryIntervalsKernel<1U>
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, <<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
N);
getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n"); getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n");
} else { }
bitonicMergeElementaryIntervalsKernel<0U><<<mergePairs, SAMPLE_STRIDE>>>( else {
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, bitonicMergeElementaryIntervalsKernel<0U>
N); <<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n"); getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n");
} }
} }

View File

@ -26,17 +26,19 @@
*/ */
#include <assert.h> #include <assert.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <cuda_runtime.h>
#include <helper_functions.h>
#include <helper_cuda.h>
#include "mergeSort_common.h" #include "mergeSort_common.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Test driver // Test driver
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
uint *h_SrcKey, *h_SrcVal, *h_DstKey, *h_DstVal; uint *h_SrcKey, *h_SrcVal, *h_DstKey, *h_DstVal;
uint *d_SrcKey, *d_SrcVal, *d_BufKey, *d_BufVal, *d_DstKey, *d_DstVal; uint *d_SrcKey, *d_SrcVal, *d_BufKey, *d_BufVal, *d_DstKey, *d_DstVal;
StopWatchInterface *hTimer = NULL; StopWatchInterface *hTimer = NULL;
@ -75,10 +77,8 @@ int main(int argc, char **argv) {
checkCudaErrors(cudaMalloc((void **)&d_BufVal, N * sizeof(uint))); checkCudaErrors(cudaMalloc((void **)&d_BufVal, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_SrcKey, N * sizeof(uint))); checkCudaErrors(cudaMalloc((void **)&d_SrcKey, N * sizeof(uint)));
checkCudaErrors(cudaMalloc((void **)&d_SrcVal, N * sizeof(uint))); checkCudaErrors(cudaMalloc((void **)&d_SrcVal, N * sizeof(uint)));
checkCudaErrors( checkCudaErrors(cudaMemcpy(d_SrcKey, h_SrcKey, N * sizeof(uint), cudaMemcpyHostToDevice));
cudaMemcpy(d_SrcKey, h_SrcKey, N * sizeof(uint), cudaMemcpyHostToDevice)); checkCudaErrors(cudaMemcpy(d_SrcVal, h_SrcVal, N * sizeof(uint), cudaMemcpyHostToDevice));
checkCudaErrors(
cudaMemcpy(d_SrcVal, h_SrcVal, N * sizeof(uint), cudaMemcpyHostToDevice));
printf("Initializing GPU merge sort...\n"); printf("Initializing GPU merge sort...\n");
initMergeSort(); initMergeSort();
@ -93,10 +93,8 @@ int main(int argc, char **argv) {
printf("Time: %f ms\n", sdkGetTimerValue(&hTimer)); printf("Time: %f ms\n", sdkGetTimerValue(&hTimer));
printf("Reading back GPU merge sort results...\n"); printf("Reading back GPU merge sort results...\n");
checkCudaErrors( checkCudaErrors(cudaMemcpy(h_DstKey, d_DstKey, N * sizeof(uint), cudaMemcpyDeviceToHost));
cudaMemcpy(h_DstKey, d_DstKey, N * sizeof(uint), cudaMemcpyDeviceToHost)); checkCudaErrors(cudaMemcpy(h_DstVal, d_DstVal, N * sizeof(uint), cudaMemcpyDeviceToHost));
checkCudaErrors(
cudaMemcpy(h_DstVal, d_DstVal, N * sizeof(uint), cudaMemcpyDeviceToHost));
printf("Inspecting the results...\n"); printf("Inspecting the results...\n");
uint keysFlag = validateSortedKeys(h_DstKey, h_SrcKey, 1, N, numValues, DIR); uint keysFlag = validateSortedKeys(h_DstKey, h_SrcKey, 1, N, numValues, DIR);

View File

@ -39,21 +39,19 @@
namespace cg = cooperative_groups; namespace cg = cooperative_groups;
#include <helper_cuda.h> #include <helper_cuda.h>
#include "mergeSort_common.h" #include "mergeSort_common.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static inline __host__ __device__ uint iDivUp(uint a, uint b) { static inline __host__ __device__ uint iDivUp(uint a, uint b) { return ((a % b) == 0) ? (a / b) : (a / b + 1); }
return ((a % b) == 0) ? (a / b) : (a / b + 1);
}
static inline __host__ __device__ uint getSampleCount(uint dividend) { static inline __host__ __device__ uint getSampleCount(uint dividend) { return iDivUp(dividend, SAMPLE_STRIDE); }
return iDivUp(dividend, SAMPLE_STRIDE);
}
#define W (sizeof(uint) * 8) #define W (sizeof(uint) * 8)
static inline __device__ uint nextPowerOfTwo(uint x) { static inline __device__ uint nextPowerOfTwo(uint x)
{
/* /*
--x; --x;
x |= x >> 1; x |= x >> 1;
@ -66,9 +64,8 @@ static inline __device__ uint nextPowerOfTwo(uint x) {
return 1U << (W - __clz(x - 1)); return 1U << (W - __clz(x - 1));
} }
template <uint sortDir> template <uint sortDir> static inline __device__ uint binarySearchInclusive(uint val, uint *data, uint L, uint stride)
static inline __device__ uint binarySearchInclusive(uint val, uint *data, {
uint L, uint stride) {
if (L == 0) { if (L == 0) {
return 0; return 0;
} }
@ -78,8 +75,7 @@ static inline __device__ uint binarySearchInclusive(uint val, uint *data,
for (; stride > 0; stride >>= 1) { for (; stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L); uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] <= val)) || if ((sortDir && (data[newPos - 1] <= val)) || (!sortDir && (data[newPos - 1] >= val))) {
(!sortDir && (data[newPos - 1] >= val))) {
pos = newPos; pos = newPos;
} }
} }
@ -87,9 +83,8 @@ static inline __device__ uint binarySearchInclusive(uint val, uint *data,
return pos; return pos;
} }
template <uint sortDir> template <uint sortDir> static inline __device__ uint binarySearchExclusive(uint val, uint *data, uint L, uint stride)
static inline __device__ uint binarySearchExclusive(uint val, uint *data, {
uint L, uint stride) {
if (L == 0) { if (L == 0) {
return 0; return 0;
} }
@ -99,8 +94,7 @@ static inline __device__ uint binarySearchExclusive(uint val, uint *data,
for (; stride > 0; stride >>= 1) { for (; stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L); uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] < val)) || if ((sortDir && (data[newPos - 1] < val)) || (!sortDir && (data[newPos - 1] > val))) {
(!sortDir && (data[newPos - 1] > val))) {
pos = newPos; pos = newPos;
} }
} }
@ -112,9 +106,8 @@ static inline __device__ uint binarySearchExclusive(uint val, uint *data,
// Bottom-level merge sort (binary search-based) // Bottom-level merge sort (binary search-based)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <uint sortDir> template <uint sortDir>
__global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal, __global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, uint *d_SrcVal, uint arrayLength)
uint *d_SrcKey, uint *d_SrcVal, {
uint arrayLength) {
// Handle to thread block group // Handle to thread block group
cg::thread_block cta = cg::this_thread_block(); cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[SHARED_SIZE_LIMIT]; __shared__ uint s_key[SHARED_SIZE_LIMIT];
@ -126,10 +119,8 @@ __global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x; d_DstVal += blockIdx.x * SHARED_SIZE_LIMIT + threadIdx.x;
s_key[threadIdx.x + 0] = d_SrcKey[0]; s_key[threadIdx.x + 0] = d_SrcKey[0];
s_val[threadIdx.x + 0] = d_SrcVal[0]; s_val[threadIdx.x + 0] = d_SrcVal[0];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcKey[(SHARED_SIZE_LIMIT / 2)];
d_SrcKey[(SHARED_SIZE_LIMIT / 2)]; s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] = d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)] =
d_SrcVal[(SHARED_SIZE_LIMIT / 2)];
for (uint stride = 1; stride < arrayLength; stride <<= 1) { for (uint stride = 1; stride < arrayLength; stride <<= 1) {
uint lPos = threadIdx.x & (stride - 1); uint lPos = threadIdx.x & (stride - 1);
@ -141,12 +132,8 @@ __global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
uint valA = baseVal[lPos + 0]; uint valA = baseVal[lPos + 0];
uint keyB = baseKey[lPos + stride]; uint keyB = baseKey[lPos + stride];
uint valB = baseVal[lPos + stride]; uint valB = baseVal[lPos + stride];
uint posA = uint posA = binarySearchExclusive<sortDir>(keyA, baseKey + stride, stride, stride) + lPos;
binarySearchExclusive<sortDir>(keyA, baseKey + stride, stride, stride) + uint posB = binarySearchInclusive<sortDir>(keyB, baseKey + 0, stride, stride) + lPos;
lPos;
uint posB =
binarySearchInclusive<sortDir>(keyB, baseKey + 0, stride, stride) +
lPos;
cg::sync(cta); cg::sync(cta);
baseKey[posA] = keyA; baseKey[posA] = keyA;
@ -158,15 +145,18 @@ __global__ void mergeSortSharedKernel(uint *d_DstKey, uint *d_DstVal,
cg::sync(cta); cg::sync(cta);
d_DstKey[0] = s_key[threadIdx.x + 0]; d_DstKey[0] = s_key[threadIdx.x + 0];
d_DstVal[0] = s_val[threadIdx.x + 0]; d_DstVal[0] = s_val[threadIdx.x + 0];
d_DstKey[(SHARED_SIZE_LIMIT / 2)] = d_DstKey[(SHARED_SIZE_LIMIT / 2)] = s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
s_key[threadIdx.x + (SHARED_SIZE_LIMIT / 2)]; d_DstVal[(SHARED_SIZE_LIMIT / 2)] = s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
d_DstVal[(SHARED_SIZE_LIMIT / 2)] =
s_val[threadIdx.x + (SHARED_SIZE_LIMIT / 2)];
} }
static void mergeSortShared(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey, static void mergeSortShared(uint *d_DstKey,
uint *d_SrcVal, uint batchSize, uint arrayLength, uint *d_DstVal,
uint sortDir) { uint *d_SrcKey,
uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir)
{
if (arrayLength < 2) { if (arrayLength < 2) {
return; return;
} }
@ -177,12 +167,11 @@ static void mergeSortShared(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey,
uint threadCount = SHARED_SIZE_LIMIT / 2; uint threadCount = SHARED_SIZE_LIMIT / 2;
if (sortDir) { if (sortDir) {
mergeSortSharedKernel<1U><<<blockCount, threadCount>>>( mergeSortSharedKernel<1U><<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength);
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength);
getLastCudaError("mergeSortShared<1><<<>>> failed\n"); getLastCudaError("mergeSortShared<1><<<>>> failed\n");
} else { }
mergeSortSharedKernel<0U><<<blockCount, threadCount>>>( else {
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength); mergeSortSharedKernel<0U><<<blockCount, threadCount>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, arrayLength);
getLastCudaError("mergeSortShared<0><<<>>> failed\n"); getLastCudaError("mergeSortShared<0><<<>>> failed\n");
} }
} }
@ -191,9 +180,9 @@ static void mergeSortShared(uint *d_DstKey, uint *d_DstVal, uint *d_SrcKey,
// Merge step 1: generate sample ranks // Merge step 1: generate sample ranks
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <uint sortDir> template <uint sortDir>
__global__ void generateSampleRanksKernel(uint *d_RanksA, uint *d_RanksB, __global__ void
uint *d_SrcKey, uint stride, uint N, generateSampleRanksKernel(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey, uint stride, uint N, uint threadCount)
uint threadCount) { {
uint pos = blockIdx.x * blockDim.x + threadIdx.x; uint pos = blockIdx.x * blockDim.x + threadIdx.x;
if (pos >= threadCount) { if (pos >= threadCount) {
@ -214,33 +203,30 @@ __global__ void generateSampleRanksKernel(uint *d_RanksA, uint *d_RanksB,
if (i < segmentSamplesA) { if (i < segmentSamplesA) {
d_RanksA[i] = i * SAMPLE_STRIDE; d_RanksA[i] = i * SAMPLE_STRIDE;
d_RanksB[i] = binarySearchExclusive<sortDir>( d_RanksB[i] = binarySearchExclusive<sortDir>(
d_SrcKey[i * SAMPLE_STRIDE], d_SrcKey + stride, segmentElementsB, d_SrcKey[i * SAMPLE_STRIDE], d_SrcKey + stride, segmentElementsB, nextPowerOfTwo(segmentElementsB));
nextPowerOfTwo(segmentElementsB));
} }
if (i < segmentSamplesB) { if (i < segmentSamplesB) {
d_RanksB[(stride / SAMPLE_STRIDE) + i] = i * SAMPLE_STRIDE; d_RanksB[(stride / SAMPLE_STRIDE) + i] = i * SAMPLE_STRIDE;
d_RanksA[(stride / SAMPLE_STRIDE) + i] = binarySearchInclusive<sortDir>( d_RanksA[(stride / SAMPLE_STRIDE) + i] = binarySearchInclusive<sortDir>(
d_SrcKey[stride + i * SAMPLE_STRIDE], d_SrcKey + 0, segmentElementsA, d_SrcKey[stride + i * SAMPLE_STRIDE], d_SrcKey + 0, segmentElementsA, nextPowerOfTwo(segmentElementsA));
nextPowerOfTwo(segmentElementsA));
} }
} }
static void generateSampleRanks(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey, static void generateSampleRanks(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey, uint stride, uint N, uint sortDir)
uint stride, uint N, uint sortDir) { {
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint threadCount = uint threadCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
(lastSegmentElements > stride)
? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE); : (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
if (sortDir) { if (sortDir) {
generateSampleRanksKernel<1U><<<iDivUp(threadCount, 256), 256>>>( generateSampleRanksKernel<1U>
d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount); <<<iDivUp(threadCount, 256), 256>>>(d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount);
getLastCudaError("generateSampleRanksKernel<1U><<<>>> failed\n"); getLastCudaError("generateSampleRanksKernel<1U><<<>>> failed\n");
} else { }
generateSampleRanksKernel<0U><<<iDivUp(threadCount, 256), 256>>>( else {
d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount); generateSampleRanksKernel<0U>
<<<iDivUp(threadCount, 256), 256>>>(d_RanksA, d_RanksB, d_SrcKey, stride, N, threadCount);
getLastCudaError("generateSampleRanksKernel<0U><<<>>> failed\n"); getLastCudaError("generateSampleRanksKernel<0U><<<>>> failed\n");
} }
} }
@ -248,9 +234,8 @@ static void generateSampleRanks(uint *d_RanksA, uint *d_RanksB, uint *d_SrcKey,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Merge step 2: generate sample ranks and indices // Merge step 2: generate sample ranks and indices
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__global__ void mergeRanksAndIndicesKernel(uint *d_Limits, uint *d_Ranks, __global__ void mergeRanksAndIndicesKernel(uint *d_Limits, uint *d_Ranks, uint stride, uint N, uint threadCount)
uint stride, uint N, {
uint threadCount) {
uint pos = blockIdx.x * blockDim.x + threadIdx.x; uint pos = blockIdx.x * blockDim.x + threadIdx.x;
if (pos >= threadCount) { if (pos >= threadCount) {
@ -269,36 +254,29 @@ __global__ void mergeRanksAndIndicesKernel(uint *d_Limits, uint *d_Ranks,
if (i < segmentSamplesA) { if (i < segmentSamplesA) {
uint dstPos = binarySearchExclusive<1U>( uint dstPos = binarySearchExclusive<1U>(
d_Ranks[i], d_Ranks + segmentSamplesA, segmentSamplesB, d_Ranks[i], d_Ranks + segmentSamplesA, segmentSamplesB, nextPowerOfTwo(segmentSamplesB))
nextPowerOfTwo(segmentSamplesB)) + + i;
i;
d_Limits[dstPos] = d_Ranks[i]; d_Limits[dstPos] = d_Ranks[i];
} }
if (i < segmentSamplesB) { if (i < segmentSamplesB) {
uint dstPos = binarySearchInclusive<1U>(d_Ranks[segmentSamplesA + i], uint dstPos = binarySearchInclusive<1U>(
d_Ranks, segmentSamplesA, d_Ranks[segmentSamplesA + i], d_Ranks, segmentSamplesA, nextPowerOfTwo(segmentSamplesA))
nextPowerOfTwo(segmentSamplesA)) + + i;
i;
d_Limits[dstPos] = d_Ranks[segmentSamplesA + i]; d_Limits[dstPos] = d_Ranks[segmentSamplesA + i];
} }
} }
static void mergeRanksAndIndices(uint *d_LimitsA, uint *d_LimitsB, static void mergeRanksAndIndices(uint *d_LimitsA, uint *d_LimitsB, uint *d_RanksA, uint *d_RanksB, uint stride, uint N)
uint *d_RanksA, uint *d_RanksB, uint stride, {
uint N) {
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint threadCount = uint threadCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
(lastSegmentElements > stride)
? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE); : (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>( mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>(d_LimitsA, d_RanksA, stride, N, threadCount);
d_LimitsA, d_RanksA, stride, N, threadCount);
getLastCudaError("mergeRanksAndIndicesKernel(A)<<<>>> failed\n"); getLastCudaError("mergeRanksAndIndicesKernel(A)<<<>>> failed\n");
mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>( mergeRanksAndIndicesKernel<<<iDivUp(threadCount, 256), 256>>>(d_LimitsB, d_RanksB, stride, N, threadCount);
d_LimitsB, d_RanksB, stride, N, threadCount);
getLastCudaError("mergeRanksAndIndicesKernel(B)<<<>>> failed\n"); getLastCudaError("mergeRanksAndIndicesKernel(B)<<<>>> failed\n");
} }
@ -306,24 +284,30 @@ static void mergeRanksAndIndices(uint *d_LimitsA, uint *d_LimitsB,
// Merge step 3: merge elementary intervals // Merge step 3: merge elementary intervals
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <uint sortDir> template <uint sortDir>
inline __device__ void merge(uint *dstKey, uint *dstVal, uint *srcAKey, inline __device__ void merge(uint *dstKey,
uint *srcAVal, uint *srcBKey, uint *srcBVal, uint *dstVal,
uint lenA, uint nPowTwoLenA, uint lenB, uint *srcAKey,
uint nPowTwoLenB, cg::thread_block cta) { uint *srcAVal,
uint *srcBKey,
uint *srcBVal,
uint lenA,
uint nPowTwoLenA,
uint lenB,
uint nPowTwoLenB,
cg::thread_block cta)
{
uint keyA, valA, keyB, valB, dstPosA, dstPosB; uint keyA, valA, keyB, valB, dstPosA, dstPosB;
if (threadIdx.x < lenA) { if (threadIdx.x < lenA) {
keyA = srcAKey[threadIdx.x]; keyA = srcAKey[threadIdx.x];
valA = srcAVal[threadIdx.x]; valA = srcAVal[threadIdx.x];
dstPosA = binarySearchExclusive<sortDir>(keyA, srcBKey, lenB, nPowTwoLenB) + dstPosA = binarySearchExclusive<sortDir>(keyA, srcBKey, lenB, nPowTwoLenB) + threadIdx.x;
threadIdx.x;
} }
if (threadIdx.x < lenB) { if (threadIdx.x < lenB) {
keyB = srcBKey[threadIdx.x]; keyB = srcBKey[threadIdx.x];
valB = srcBVal[threadIdx.x]; valB = srcBVal[threadIdx.x];
dstPosB = binarySearchInclusive<sortDir>(keyB, srcAKey, lenA, nPowTwoLenA) + dstPosB = binarySearchInclusive<sortDir>(keyB, srcAKey, lenA, nPowTwoLenA) + threadIdx.x;
threadIdx.x;
} }
cg::sync(cta); cg::sync(cta);
@ -340,10 +324,15 @@ inline __device__ void merge(uint *dstKey, uint *dstVal, uint *srcAKey,
} }
template <uint sortDir> template <uint sortDir>
__global__ void mergeElementaryIntervalsKernel(uint *d_DstKey, uint *d_DstVal, __global__ void mergeElementaryIntervalsKernel(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint *d_LimitsA, uint *d_LimitsB, uint *d_SrcKey,
uint stride, uint N) { uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N)
{
// Handle to thread block group // Handle to thread block group
cg::thread_block cta = cg::this_thread_block(); cg::thread_block cta = cg::this_thread_block();
__shared__ uint s_key[2 * SAMPLE_STRIDE]; __shared__ uint s_key[2 * SAMPLE_STRIDE];
@ -368,10 +357,8 @@ __global__ void mergeElementaryIntervalsKernel(uint *d_DstKey, uint *d_DstVal,
startSrcA = d_LimitsA[blockIdx.x]; startSrcA = d_LimitsA[blockIdx.x];
startSrcB = d_LimitsB[blockIdx.x]; startSrcB = d_LimitsB[blockIdx.x];
uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] uint endSrcA = (intervalI + 1 < segmentSamples) ? d_LimitsA[blockIdx.x + 1] : segmentElementsA;
: segmentElementsA; uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1] : segmentElementsB;
uint endSrcB = (intervalI + 1 < segmentSamples) ? d_LimitsB[blockIdx.x + 1]
: segmentElementsB;
lenSrcA = endSrcA - startSrcA; lenSrcA = endSrcA - startSrcA;
lenSrcB = endSrcB - startSrcB; lenSrcB = endSrcB - startSrcB;
startDstA = startSrcA + startSrcB; startDstA = startSrcA + startSrcB;
@ -387,17 +374,23 @@ __global__ void mergeElementaryIntervalsKernel(uint *d_DstKey, uint *d_DstVal,
} }
if (threadIdx.x < lenSrcB) { if (threadIdx.x < lenSrcB) {
s_key[threadIdx.x + SAMPLE_STRIDE] = s_key[threadIdx.x + SAMPLE_STRIDE] = d_SrcKey[stride + startSrcB + threadIdx.x];
d_SrcKey[stride + startSrcB + threadIdx.x]; s_val[threadIdx.x + SAMPLE_STRIDE] = d_SrcVal[stride + startSrcB + threadIdx.x];
s_val[threadIdx.x + SAMPLE_STRIDE] =
d_SrcVal[stride + startSrcB + threadIdx.x];
} }
// Merge data in shared memory // Merge data in shared memory
cg::sync(cta); cg::sync(cta);
merge<sortDir>(s_key, s_val, s_key + 0, s_val + 0, s_key + SAMPLE_STRIDE, merge<sortDir>(s_key,
s_val + SAMPLE_STRIDE, lenSrcA, SAMPLE_STRIDE, lenSrcB, s_val,
SAMPLE_STRIDE, cta); s_key + 0,
s_val + 0,
s_key + SAMPLE_STRIDE,
s_val + SAMPLE_STRIDE,
lenSrcA,
SAMPLE_STRIDE,
lenSrcB,
SAMPLE_STRIDE,
cta);
// Store merged data // Store merged data
cg::sync(cta); cg::sync(cta);
@ -413,63 +406,77 @@ __global__ void mergeElementaryIntervalsKernel(uint *d_DstKey, uint *d_DstVal,
} }
} }
static void mergeElementaryIntervals(uint *d_DstKey, uint *d_DstVal, static void mergeElementaryIntervals(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint *d_LimitsA, uint *d_LimitsB, uint *d_SrcKey,
uint stride, uint N, uint sortDir) { uint *d_SrcVal,
uint *d_LimitsA,
uint *d_LimitsB,
uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
? getSampleCount(N)
: (N - lastSegmentElements) / SAMPLE_STRIDE;
if (sortDir) { if (sortDir) {
mergeElementaryIntervalsKernel<1U><<<mergePairs, SAMPLE_STRIDE>>>( mergeElementaryIntervalsKernel<1U>
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, <<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
N);
getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n"); getLastCudaError("mergeElementaryIntervalsKernel<1> failed\n");
} else { }
mergeElementaryIntervalsKernel<0U><<<mergePairs, SAMPLE_STRIDE>>>( else {
d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, mergeElementaryIntervalsKernel<0U>
N); <<<mergePairs, SAMPLE_STRIDE>>>(d_DstKey, d_DstVal, d_SrcKey, d_SrcVal, d_LimitsA, d_LimitsB, stride, N);
getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n"); getLastCudaError("mergeElementaryIntervalsKernel<0> failed\n");
} }
} }
extern "C" void bitonicSortShared(uint *d_DstKey, uint *d_DstVal, extern "C" void bitonicSortShared(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint batchSize, uint arrayLength, uint *d_SrcKey,
uint *d_SrcVal,
uint batchSize,
uint arrayLength,
uint sortDir); uint sortDir);
extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey, uint *d_DstVal, extern "C" void bitonicMergeElementaryIntervals(uint *d_DstKey,
uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint *d_LimitsA, uint *d_LimitsA,
uint *d_LimitsB, uint stride, uint *d_LimitsB,
uint N, uint sortDir); uint stride,
uint N,
uint sortDir);
static uint *d_RanksA, *d_RanksB, *d_LimitsA, *d_LimitsB; static uint *d_RanksA, *d_RanksB, *d_LimitsA, *d_LimitsB;
static const uint MAX_SAMPLE_COUNT = 32768; static const uint MAX_SAMPLE_COUNT = 32768;
extern "C" void initMergeSort(void) { extern "C" void initMergeSort(void)
checkCudaErrors( {
cudaMalloc((void **)&d_RanksA, MAX_SAMPLE_COUNT * sizeof(uint))); checkCudaErrors(cudaMalloc((void **)&d_RanksA, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors( checkCudaErrors(cudaMalloc((void **)&d_RanksB, MAX_SAMPLE_COUNT * sizeof(uint)));
cudaMalloc((void **)&d_RanksB, MAX_SAMPLE_COUNT * sizeof(uint))); checkCudaErrors(cudaMalloc((void **)&d_LimitsA, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors( checkCudaErrors(cudaMalloc((void **)&d_LimitsB, MAX_SAMPLE_COUNT * sizeof(uint)));
cudaMalloc((void **)&d_LimitsA, MAX_SAMPLE_COUNT * sizeof(uint)));
checkCudaErrors(
cudaMalloc((void **)&d_LimitsB, MAX_SAMPLE_COUNT * sizeof(uint)));
} }
extern "C" void closeMergeSort(void) { extern "C" void closeMergeSort(void)
{
checkCudaErrors(cudaFree(d_RanksA)); checkCudaErrors(cudaFree(d_RanksA));
checkCudaErrors(cudaFree(d_RanksB)); checkCudaErrors(cudaFree(d_RanksB));
checkCudaErrors(cudaFree(d_LimitsB)); checkCudaErrors(cudaFree(d_LimitsB));
checkCudaErrors(cudaFree(d_LimitsA)); checkCudaErrors(cudaFree(d_LimitsA));
} }
extern "C" void mergeSort(uint *d_DstKey, uint *d_DstVal, uint *d_BufKey, extern "C" void mergeSort(uint *d_DstKey,
uint *d_BufVal, uint *d_SrcKey, uint *d_SrcVal, uint *d_DstVal,
uint N, uint sortDir) { uint *d_BufKey,
uint *d_BufVal,
uint *d_SrcKey,
uint *d_SrcVal,
uint N,
uint sortDir)
{
uint stageCount = 0; uint stageCount = 0;
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1, stageCount++) for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1, stageCount++)
@ -482,7 +489,8 @@ extern "C" void mergeSort(uint *d_DstKey, uint *d_DstVal, uint *d_BufKey,
ival = d_BufVal; ival = d_BufVal;
okey = d_DstKey; okey = d_DstKey;
oval = d_DstVal; oval = d_DstVal;
} else { }
else {
ikey = d_DstKey; ikey = d_DstKey;
ival = d_DstVal; ival = d_DstVal;
okey = d_BufKey; okey = d_BufKey;
@ -491,8 +499,7 @@ extern "C" void mergeSort(uint *d_DstKey, uint *d_DstVal, uint *d_BufKey,
assert(N <= (SAMPLE_STRIDE * MAX_SAMPLE_COUNT)); assert(N <= (SAMPLE_STRIDE * MAX_SAMPLE_COUNT));
assert(N % SHARED_SIZE_LIMIT == 0); assert(N % SHARED_SIZE_LIMIT == 0);
mergeSortShared(ikey, ival, d_SrcKey, d_SrcVal, N / SHARED_SIZE_LIMIT, mergeSortShared(ikey, ival, d_SrcKey, d_SrcVal, N / SHARED_SIZE_LIMIT, SHARED_SIZE_LIMIT, sortDir);
SHARED_SIZE_LIMIT, sortDir);
for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1) { for (uint stride = SHARED_SIZE_LIMIT; stride < N; stride <<= 1) {
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
@ -504,18 +511,19 @@ extern "C" void mergeSort(uint *d_DstKey, uint *d_DstVal, uint *d_BufKey,
mergeRanksAndIndices(d_LimitsA, d_LimitsB, d_RanksA, d_RanksB, stride, N); mergeRanksAndIndices(d_LimitsA, d_LimitsB, d_RanksA, d_RanksB, stride, N);
// Merge elementary intervals // Merge elementary intervals
mergeElementaryIntervals(okey, oval, ikey, ival, d_LimitsA, d_LimitsB, mergeElementaryIntervals(okey, oval, ikey, ival, d_LimitsA, d_LimitsB, stride, N, sortDir);
stride, N, sortDir);
if (lastSegmentElements <= stride) { if (lastSegmentElements <= stride) {
// Last merge segment consists of a single array which just needs to be // Last merge segment consists of a single array which just needs to be
// passed through // passed through
checkCudaErrors(cudaMemcpy( checkCudaErrors(cudaMemcpy(okey + (N - lastSegmentElements),
okey + (N - lastSegmentElements), ikey + (N - lastSegmentElements), ikey + (N - lastSegmentElements),
lastSegmentElements * sizeof(uint), cudaMemcpyDeviceToDevice)); lastSegmentElements * sizeof(uint),
checkCudaErrors(cudaMemcpy( cudaMemcpyDeviceToDevice));
oval + (N - lastSegmentElements), ival + (N - lastSegmentElements), checkCudaErrors(cudaMemcpy(oval + (N - lastSegmentElements),
lastSegmentElements * sizeof(uint), cudaMemcpyDeviceToDevice)); ival + (N - lastSegmentElements),
lastSegmentElements * sizeof(uint),
cudaMemcpyDeviceToDevice));
} }
uint *t; uint *t;

View File

@ -36,14 +36,12 @@ typedef unsigned int uint;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Extensive sort validation routine // Extensive sort validation routine
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" uint validateSortedKeys(uint *resKey, uint *srcKey, uint batchSize, extern "C" uint
uint arrayLength, uint numValues, validateSortedKeys(uint *resKey, uint *srcKey, uint batchSize, uint arrayLength, uint numValues, uint sortDir);
uint sortDir);
extern "C" void fillValues(uint *val, uint N); extern "C" void fillValues(uint *val, uint N);
extern "C" int validateSortedValues(uint *resKey, uint *resVal, uint *srcKey, extern "C" int validateSortedValues(uint *resKey, uint *resVal, uint *srcKey, uint batchSize, uint arrayLength);
uint batchSize, uint arrayLength);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// CUDA merge sort // CUDA merge sort
@ -52,13 +50,11 @@ extern "C" void initMergeSort(void);
extern "C" void closeMergeSort(void); extern "C" void closeMergeSort(void);
extern "C" void mergeSort(uint *dstKey, uint *dstVal, uint *bufKey, extern "C" void
uint *bufVal, uint *srcKey, uint *srcVal, uint N, mergeSort(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir);
uint sortDir);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// CPU "emulation" // CPU "emulation"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" void mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, extern "C" void
uint *bufVal, uint *srcKey, uint *srcVal, uint N, mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir);
uint sortDir);

View File

@ -29,19 +29,20 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "mergeSort_common.h" #include "mergeSort_common.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helper functions // Helper functions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void checkOrder(uint *data, uint N, uint sortDir) { static void checkOrder(uint *data, uint N, uint sortDir)
{
if (N <= 1) { if (N <= 1) {
return; return;
} }
for (uint i = 0; i < N - 1; i++) for (uint i = 0; i < N - 1; i++)
if ((sortDir && (data[i] > data[i + 1])) || if ((sortDir && (data[i] > data[i + 1])) || (!sortDir && (data[i] < data[i + 1]))) {
(!sortDir && (data[i] < data[i + 1]))) {
fprintf(stderr, "checkOrder() failed!!!\n"); fprintf(stderr, "checkOrder() failed!!!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -49,12 +50,13 @@ static void checkOrder(uint *data, uint N, uint sortDir) {
static uint umin(uint a, uint b) { return (a <= b) ? a : b; } static uint umin(uint a, uint b) { return (a <= b) ? a : b; }
static uint getSampleCount(uint dividend) { static uint getSampleCount(uint dividend)
return ((dividend % SAMPLE_STRIDE) != 0) ? (dividend / SAMPLE_STRIDE + 1) {
: (dividend / SAMPLE_STRIDE); return ((dividend % SAMPLE_STRIDE) != 0) ? (dividend / SAMPLE_STRIDE + 1) : (dividend / SAMPLE_STRIDE);
} }
static uint nextPowerOfTwo(uint x) { static uint nextPowerOfTwo(uint x)
{
--x; --x;
x |= x >> 1; x |= x >> 1;
x |= x >> 2; x |= x >> 2;
@ -64,7 +66,8 @@ static uint nextPowerOfTwo(uint x) {
return ++x; return ++x;
} }
static uint binarySearchInclusive(uint val, uint *data, uint L, uint sortDir) { static uint binarySearchInclusive(uint val, uint *data, uint L, uint sortDir)
{
if (L == 0) { if (L == 0) {
return 0; return 0;
} }
@ -74,8 +77,7 @@ static uint binarySearchInclusive(uint val, uint *data, uint L, uint sortDir) {
for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) { for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L); uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] <= val)) || if ((sortDir && (data[newPos - 1] <= val)) || (!sortDir && (data[newPos - 1] >= val))) {
(!sortDir && (data[newPos - 1] >= val))) {
pos = newPos; pos = newPos;
} }
} }
@ -83,7 +85,8 @@ static uint binarySearchInclusive(uint val, uint *data, uint L, uint sortDir) {
return pos; return pos;
} }
static uint binarySearchExclusive(uint val, uint *data, uint L, uint sortDir) { static uint binarySearchExclusive(uint val, uint *data, uint L, uint sortDir)
{
if (L == 0) { if (L == 0) {
return 0; return 0;
} }
@ -93,8 +96,7 @@ static uint binarySearchExclusive(uint val, uint *data, uint L, uint sortDir) {
for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) { for (uint stride = nextPowerOfTwo(L); stride > 0; stride >>= 1) {
uint newPos = umin(pos + stride, L); uint newPos = umin(pos + stride, L);
if ((sortDir && (data[newPos - 1] < val)) || if ((sortDir && (data[newPos - 1] < val)) || (!sortDir && (data[newPos - 1] > val))) {
(!sortDir && (data[newPos - 1] > val))) {
pos = newPos; pos = newPos;
} }
} }
@ -105,12 +107,10 @@ static uint binarySearchExclusive(uint val, uint *data, uint L, uint sortDir) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Merge step 1: find sample ranks in each segment // Merge step 1: find sample ranks in each segment
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void generateSampleRanks(uint *ranksA, uint *ranksB, uint *srcKey, static void generateSampleRanks(uint *ranksA, uint *ranksB, uint *srcKey, uint stride, uint N, uint sortDir)
uint stride, uint N, uint sortDir) { {
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint sampleCount = uint sampleCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
(lastSegmentElements > stride)
? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE); : (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
for (uint pos = 0; pos < sampleCount; pos++) { for (uint pos = 0; pos < sampleCount; pos++) {
@ -124,17 +124,14 @@ static void generateSampleRanks(uint *ranksA, uint *ranksB, uint *srcKey,
if (i < nA) { if (i < nA) {
ranksA[(segmentBase + 0) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE; ranksA[(segmentBase + 0) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE;
ranksB[(segmentBase + 0) / SAMPLE_STRIDE + i] = ranksB[(segmentBase + 0) / SAMPLE_STRIDE + i] = binarySearchExclusive(
binarySearchExclusive(srcKey[segmentBase + i * SAMPLE_STRIDE], srcKey[segmentBase + i * SAMPLE_STRIDE], srcKey + segmentBase + stride, lenB, sortDir);
srcKey + segmentBase + stride, lenB, sortDir);
} }
if (i < nB) { if (i < nB) {
ranksB[(segmentBase + stride) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE; ranksB[(segmentBase + stride) / SAMPLE_STRIDE + i] = i * SAMPLE_STRIDE;
ranksA[(segmentBase + stride) / SAMPLE_STRIDE + i] = ranksA[(segmentBase + stride) / SAMPLE_STRIDE + i] = binarySearchInclusive(
binarySearchInclusive( srcKey[segmentBase + stride + i * SAMPLE_STRIDE], srcKey + segmentBase, lenA, sortDir);
srcKey[segmentBase + stride + i * SAMPLE_STRIDE],
srcKey + segmentBase, lenA, sortDir);
} }
} }
} }
@ -142,12 +139,10 @@ static void generateSampleRanks(uint *ranksA, uint *ranksB, uint *srcKey,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Merge step 2: merge ranks and indices to derive elementary intervals // Merge step 2: merge ranks and indices to derive elementary intervals
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void mergeRanksAndIndices(uint *limits, uint *ranks, uint stride, static void mergeRanksAndIndices(uint *limits, uint *ranks, uint stride, uint N)
uint N) { {
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint sampleCount = uint sampleCount = (lastSegmentElements > stride) ? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
(lastSegmentElements > stride)
? (N + 2 * stride - lastSegmentElements) / (2 * SAMPLE_STRIDE)
: (N - lastSegmentElements) / (2 * SAMPLE_STRIDE); : (N - lastSegmentElements) / (2 * SAMPLE_STRIDE);
for (uint pos = 0; pos < sampleCount; pos++) { for (uint pos = 0; pos < sampleCount; pos++) {
@ -161,23 +156,20 @@ static void mergeRanksAndIndices(uint *limits, uint *ranks, uint stride,
if (i < nA) { if (i < nA) {
uint dstPosA = uint dstPosA =
binarySearchExclusive(ranks[(segmentBase + 0) / SAMPLE_STRIDE + i], binarySearchExclusive(
ranks + (segmentBase + stride) / SAMPLE_STRIDE, ranks[(segmentBase + 0) / SAMPLE_STRIDE + i], ranks + (segmentBase + stride) / SAMPLE_STRIDE, nB, 1)
nB, 1) + + i;
i;
assert(dstPosA < nA + nB); assert(dstPosA < nA + nB);
limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = ranks[(segmentBase + 0) / SAMPLE_STRIDE + i];
ranks[(segmentBase + 0) / SAMPLE_STRIDE + i];
} }
if (i < nB) { if (i < nB) {
uint dstPosA = binarySearchInclusive( uint dstPosA =
ranks[(segmentBase + stride) / SAMPLE_STRIDE + i], binarySearchInclusive(
ranks + (segmentBase + 0) / SAMPLE_STRIDE, nA, 1) + ranks[(segmentBase + stride) / SAMPLE_STRIDE + i], ranks + (segmentBase + 0) / SAMPLE_STRIDE, nA, 1)
i; + i;
assert(dstPosA < nA + nB); assert(dstPosA < nA + nB);
limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = limits[(segmentBase / SAMPLE_STRIDE) + dstPosA] = ranks[(segmentBase + stride) / SAMPLE_STRIDE + i];
ranks[(segmentBase + stride) / SAMPLE_STRIDE + i];
} }
} }
} }
@ -185,9 +177,16 @@ static void mergeRanksAndIndices(uint *limits, uint *ranks, uint stride,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Merge step 3: merge elementary intervals (each interval is <= SAMPLE_STRIDE) // Merge step 3: merge elementary intervals (each interval is <= SAMPLE_STRIDE)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void merge(uint *dstKey, uint *dstVal, uint *srcAKey, uint *srcAVal, static void merge(uint *dstKey,
uint *srcBKey, uint *srcBVal, uint lenA, uint lenB, uint *dstVal,
uint sortDir) { uint *srcAKey,
uint *srcAVal,
uint *srcBKey,
uint *srcBVal,
uint lenA,
uint lenB,
uint sortDir)
{
checkOrder(srcAKey, lenA, sortDir); checkOrder(srcAKey, lenA, sortDir);
checkOrder(srcBKey, lenB, sortDir); checkOrder(srcBKey, lenB, sortDir);
@ -206,13 +205,18 @@ static void merge(uint *dstKey, uint *dstVal, uint *srcAKey, uint *srcAVal,
} }
} }
static void mergeElementaryIntervals(uint *dstKey, uint *dstVal, uint *srcKey, static void mergeElementaryIntervals(uint *dstKey,
uint *srcVal, uint *limitsA, uint *limitsB, uint *dstVal,
uint stride, uint N, uint sortDir) { uint *srcKey,
uint *srcVal,
uint *limitsA,
uint *limitsB,
uint stride,
uint N,
uint sortDir)
{
uint lastSegmentElements = N % (2 * stride); uint lastSegmentElements = N % (2 * stride);
uint mergePairs = (lastSegmentElements > stride) uint mergePairs = (lastSegmentElements > stride) ? getSampleCount(N) : (N - lastSegmentElements) / SAMPLE_STRIDE;
? getSampleCount(N)
: (N - lastSegmentElements) / SAMPLE_STRIDE;
for (uint pos = 0; pos < mergePairs; pos++) { for (uint pos = 0; pos < mergePairs; pos++) {
uint i = pos & ((2 * stride) / SAMPLE_STRIDE - 1); uint i = pos & ((2 * stride) / SAMPLE_STRIDE - 1);
@ -240,15 +244,18 @@ static void mergeElementaryIntervals(uint *dstKey, uint *dstVal, uint *srcKey,
(srcKey + segmentBase + 0) + startPosA, (srcKey + segmentBase + 0) + startPosA,
(srcVal + segmentBase + 0) + startPosA, (srcVal + segmentBase + 0) + startPosA,
(srcKey + segmentBase + stride) + startPosB, (srcKey + segmentBase + stride) + startPosB,
(srcVal + segmentBase + stride) + startPosB, endPosA - startPosA, (srcVal + segmentBase + stride) + startPosB,
endPosB - startPosB, sortDir); endPosA - startPosA,
endPosB - startPosB,
sortDir);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Retarded bubble sort // Retarded bubble sort
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void bubbleSort(uint *key, uint *val, uint N, uint sortDir) { static void bubbleSort(uint *key, uint *val, uint N, uint sortDir)
{
if (N <= 1) { if (N <= 1) {
return; return;
} }
@ -278,9 +285,9 @@ static void bubbleSort(uint *key, uint *val, uint N, uint sortDir) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Interface function // Interface function
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" void mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, extern "C" void
uint *bufVal, uint *srcKey, uint *srcVal, uint N, mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey, uint *bufVal, uint *srcKey, uint *srcVal, uint N, uint sortDir)
uint sortDir) { {
uint *ikey, *ival, *okey, *oval; uint *ikey, *ival, *okey, *oval;
uint stageCount = 0; uint stageCount = 0;
@ -292,7 +299,8 @@ extern "C" void mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey,
ival = bufVal; ival = bufVal;
okey = dstKey; okey = dstKey;
oval = dstVal; oval = dstVal;
} else { }
else {
ikey = dstKey; ikey = dstKey;
ival = dstVal; ival = dstVal;
okey = bufKey; okey = bufKey;
@ -304,8 +312,7 @@ extern "C" void mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey,
memcpy(ival, srcVal, N * sizeof(uint)); memcpy(ival, srcVal, N * sizeof(uint));
for (uint pos = 0; pos < N; pos += SHARED_SIZE_LIMIT) { for (uint pos = 0; pos < N; pos += SHARED_SIZE_LIMIT) {
bubbleSort(ikey + pos, ival + pos, umin(SHARED_SIZE_LIMIT, N - pos), bubbleSort(ikey + pos, ival + pos, umin(SHARED_SIZE_LIMIT, N - pos), sortDir);
sortDir);
} }
printf("Merge...\n"); printf("Merge...\n");
@ -329,16 +336,15 @@ extern "C" void mergeSortHost(uint *dstKey, uint *dstVal, uint *bufKey,
mergeRanksAndIndices(limitsB, ranksB, stride, N); mergeRanksAndIndices(limitsB, ranksB, stride, N);
// Merge elementary intervals // Merge elementary intervals
mergeElementaryIntervals(okey, oval, ikey, ival, limitsA, limitsB, stride, mergeElementaryIntervals(okey, oval, ikey, ival, limitsA, limitsB, stride, N, sortDir);
N, sortDir);
if (lastSegmentElements <= stride) { if (lastSegmentElements <= stride) {
// Last merge segment consists of a single array which just needs to be // Last merge segment consists of a single array which just needs to be
// passed through // passed through
memcpy(okey + (N - lastSegmentElements), ikey + (N - lastSegmentElements), memcpy(
lastSegmentElements * sizeof(uint)); okey + (N - lastSegmentElements), ikey + (N - lastSegmentElements), lastSegmentElements * sizeof(uint));
memcpy(oval + (N - lastSegmentElements), ival + (N - lastSegmentElements), memcpy(
lastSegmentElements * sizeof(uint)); oval + (N - lastSegmentElements), ival + (N - lastSegmentElements), lastSegmentElements * sizeof(uint));
} }
uint *t; uint *t;

View File

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

View File

@ -11,8 +11,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -30,7 +30,7 @@ cudaStreamCreateWithFlags, cudaFree, cudaDeviceGetAttribute, cudaMallocHost, cud
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -29,9 +29,9 @@
#include <stdio.h> #include <stdio.h>
// Includes CUDA // Includes CUDA
#include <cuda_runtime.h>
#include <cuda/barrier>
#include <cooperative_groups.h> #include <cooperative_groups.h>
#include <cuda/barrier>
#include <cuda_runtime.h>
// Utilities and timing functions // Utilities and timing functions
#include <helper_functions.h> // includes cuda.h and cuda_runtime_api.h #include <helper_functions.h> // includes cuda.h and cuda_runtime_api.h
@ -43,9 +43,11 @@ namespace cg = cooperative_groups;
#if __CUDA_ARCH__ >= 700 #if __CUDA_ARCH__ >= 700
template <bool writeSquareRoot> template <bool writeSquareRoot>
__device__ void reduceBlockData( __device__ void reduceBlockData(cuda::barrier<cuda::thread_scope_block> &barrier,
cuda::barrier<cuda::thread_scope_block> &barrier, cg::thread_block_tile<32> &tile32,
cg::thread_block_tile<32> &tile32, double &threadSum, double *result) { double &threadSum,
double *result)
{
extern __shared__ double tmp[]; extern __shared__ double tmp[];
#pragma unroll #pragma unroll
@ -62,9 +64,7 @@ __device__ void reduceBlockData(
// The warp 0 will perform last round of reduction // The warp 0 will perform last round of reduction
if (tile32.meta_group_rank() == 0) { if (tile32.meta_group_rank() == 0) {
double beta = tile32.thread_rank() < tile32.meta_group_size() double beta = tile32.thread_rank() < tile32.meta_group_size() ? tmp[tile32.thread_rank()] : 0.0;
? tmp[tile32.thread_rank()]
: 0.0;
#pragma unroll #pragma unroll
for (int offset = tile32.size() / 2; offset > 0; offset /= 2) { for (int offset = tile32.size() / 2; offset > 0; offset /= 2) {
@ -81,8 +81,8 @@ __device__ void reduceBlockData(
} }
#endif #endif
__global__ void normVecByDotProductAWBarrier(float *vecA, float *vecB, __global__ void normVecByDotProductAWBarrier(float *vecA, float *vecB, double *partialResults, int size)
double *partialResults, int size) { {
#if __CUDA_ARCH__ >= 700 #if __CUDA_ARCH__ >= 700
#pragma diag_suppress static_var_with_dynamic_init #pragma diag_suppress static_var_with_dynamic_init
cg::thread_block cta = cg::this_thread_block(); cg::thread_block cta = cg::this_thread_block();
@ -105,8 +105,7 @@ __global__ void normVecByDotProductAWBarrier(float *vecA, float *vecB,
// Each thread block performs reduction of partial dotProducts and writes to // Each thread block performs reduction of partial dotProducts and writes to
// global mem. // global mem.
reduceBlockData<false>(barrier, tile32, threadSum, reduceBlockData<false>(barrier, tile32, threadSum, &partialResults[blockIdx.x]);
&partialResults[blockIdx.x]);
cg::sync(grid); cg::sync(grid);
@ -137,15 +136,15 @@ int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("%s starting...\n", argv[0]); printf("%s starting...\n", argv[0]);
// This will pick the best possible CUDA capable device // This will pick the best possible CUDA capable device
int dev = findCudaDevice(argc, (const char **)argv); int dev = findCudaDevice(argc, (const char **)argv);
int major = 0; int major = 0;
checkCudaErrors( checkCudaErrors(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, dev));
cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, dev));
// Arrive-Wait Barrier require a GPU of Volta (SM7X) architecture or higher. // Arrive-Wait Barrier require a GPU of Volta (SM7X) architecture or higher.
if (major < 7) { if (major < 7) {
@ -154,12 +153,10 @@ int main(int argc, char **argv) {
} }
int supportsCooperativeLaunch = 0; int supportsCooperativeLaunch = 0;
checkCudaErrors(cudaDeviceGetAttribute(&supportsCooperativeLaunch, checkCudaErrors(cudaDeviceGetAttribute(&supportsCooperativeLaunch, cudaDevAttrCooperativeLaunch, dev));
cudaDevAttrCooperativeLaunch, dev));
if (!supportsCooperativeLaunch) { if (!supportsCooperativeLaunch) {
printf( printf("\nSelected GPU (%d) does not support Cooperative Kernel Launch, "
"\nSelected GPU (%d) does not support Cooperative Kernel Launch, "
"Waiving the run\n", "Waiving the run\n",
dev); dev);
exit(EXIT_WAIVED); exit(EXIT_WAIVED);
@ -171,7 +168,8 @@ int main(int argc, char **argv) {
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }
int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId) { int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId)
{
float *vecA, *d_vecA; float *vecA, *d_vecA;
float *vecB, *d_vecB; float *vecB, *d_vecB;
double *d_partialResults; double *d_partialResults;
@ -191,16 +189,14 @@ int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId) {
cudaStream_t stream; cudaStream_t stream;
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
checkCudaErrors(cudaMemcpyAsync(d_vecA, vecA, sizeof(float) * size, checkCudaErrors(cudaMemcpyAsync(d_vecA, vecA, sizeof(float) * size, cudaMemcpyHostToDevice, stream));
cudaMemcpyHostToDevice, stream)); checkCudaErrors(cudaMemcpyAsync(d_vecB, vecB, sizeof(float) * size, cudaMemcpyHostToDevice, stream));
checkCudaErrors(cudaMemcpyAsync(d_vecB, vecB, sizeof(float) * size,
cudaMemcpyHostToDevice, stream));
// Kernel configuration, where a one-dimensional // Kernel configuration, where a one-dimensional
// grid and one-dimensional blocks are configured. // grid and one-dimensional blocks are configured.
int minGridSize = 0, blockSize = 0; int minGridSize = 0, blockSize = 0;
checkCudaErrors(cudaOccupancyMaxPotentialBlockSize( checkCudaErrors(
&minGridSize, &blockSize, (void *)normVecByDotProductAWBarrier, 0, size)); cudaOccupancyMaxPotentialBlockSize(&minGridSize, &blockSize, (void *)normVecByDotProductAWBarrier, 0, size));
int smemSize = ((blockSize / 32) + 1) * sizeof(double); int smemSize = ((blockSize / 32) + 1) * sizeof(double);
@ -209,28 +205,24 @@ int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId) {
&numBlocksPerSm, normVecByDotProductAWBarrier, blockSize, smemSize)); &numBlocksPerSm, normVecByDotProductAWBarrier, blockSize, smemSize));
int multiProcessorCount = 0; int multiProcessorCount = 0;
checkCudaErrors(cudaDeviceGetAttribute( checkCudaErrors(cudaDeviceGetAttribute(&multiProcessorCount, cudaDevAttrMultiProcessorCount, deviceId));
&multiProcessorCount, cudaDevAttrMultiProcessorCount, deviceId));
minGridSize = multiProcessorCount * numBlocksPerSm; minGridSize = multiProcessorCount * numBlocksPerSm;
checkCudaErrors(cudaMalloc(&d_partialResults, minGridSize * sizeof(double))); checkCudaErrors(cudaMalloc(&d_partialResults, minGridSize * sizeof(double)));
printf( printf("Launching normVecByDotProductAWBarrier kernel with numBlocks = %d "
"Launching normVecByDotProductAWBarrier kernel with numBlocks = %d "
"blockSize = %d\n", "blockSize = %d\n",
minGridSize, blockSize); minGridSize,
blockSize);
dim3 dimGrid(minGridSize, 1, 1), dimBlock(blockSize, 1, 1); dim3 dimGrid(minGridSize, 1, 1), dimBlock(blockSize, 1, 1);
void *kernelArgs[] = {(void *)&d_vecA, (void *)&d_vecB, void *kernelArgs[] = {(void *)&d_vecA, (void *)&d_vecB, (void *)&d_partialResults, (void *)&size};
(void *)&d_partialResults, (void *)&size};
checkCudaErrors( checkCudaErrors(cudaLaunchCooperativeKernel(
cudaLaunchCooperativeKernel((void *)normVecByDotProductAWBarrier, dimGrid, (void *)normVecByDotProductAWBarrier, dimGrid, dimBlock, kernelArgs, smemSize, stream));
dimBlock, kernelArgs, smemSize, stream));
checkCudaErrors(cudaMemcpyAsync(vecA, d_vecA, sizeof(float) * size, checkCudaErrors(cudaMemcpyAsync(vecA, d_vecA, sizeof(float) * size, cudaMemcpyDeviceToHost, stream));
cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream)); checkCudaErrors(cudaStreamSynchronize(stream));
float expectedResult = (baseVal / sqrt(size * baseVal * baseVal)); float expectedResult = (baseVal / sqrt(size * baseVal * baseVal));
@ -239,7 +231,8 @@ int runNormVecByDotProductAWBarrier(int argc, char **argv, int deviceId) {
if ((vecA[i] - expectedResult) > 0.00001) { if ((vecA[i] - expectedResult) > 0.00001) {
printf("mismatch at i = %d\n", i); printf("mismatch at i = %d\n", i);
break; break;
} else { }
else {
matches++; matches++;
} }
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Removes -DNDEBUG For Print specific logs in this sample. # Removes -DNDEBUG For Print specific logs in this sample.

View File

@ -27,6 +27,6 @@ cudaDeviceSynchronize, cudaGetErrorString
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -34,8 +34,8 @@
#endif #endif
// Includes, system // Includes, system
#include <stdio.h>
#include <cassert> #include <cassert>
#include <stdio.h>
// Includes CUDA // Includes CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
@ -58,7 +58,8 @@ bool testResult = true;
//! Tests assert function. //! Tests assert function.
//! Thread whose id > N will print assertion failed error message. //! Thread whose id > N will print assertion failed error message.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__global__ void testKernel(int N) { __global__ void testKernel(int N)
{
int gtid = blockIdx.x * blockDim.x + threadIdx.x; int gtid = blockIdx.x * blockDim.x + threadIdx.x;
assert(gtid < N); assert(gtid < N);
} }
@ -70,17 +71,18 @@ void runTest(int argc, char **argv);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName); printf("%s starting...\n", sampleName);
runTest(argc, argv); runTest(argc, argv);
printf("%s completed, returned %s\n", sampleName, printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!");
testResult ? "OK" : "ERROR!");
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
int Nblocks = 2; int Nblocks = 2;
int Nthreads = 32; int Nthreads = 32;
cudaError_t error; cudaError_t error;
@ -94,7 +96,8 @@ void runTest(int argc, char **argv) {
if (!strcasecmp(OS_System_Type.sysname, "Darwin")) { if (!strcasecmp(OS_System_Type.sysname, "Darwin")) {
printf("simpleAssert is not current supported on Mac OSX\n\n"); printf("simpleAssert is not current supported on Mac OSX\n\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else { }
else {
printf("OS Info: <%s>\n\n", OS_System_Type.version); printf("OS Info: <%s>\n\n", OS_System_Type.version);
} }
@ -118,8 +121,7 @@ void runTest(int argc, char **argv) {
// Check for errors and failed asserts in asynchronous kernel launch. // Check for errors and failed asserts in asynchronous kernel launch.
if (error == cudaErrorAssert) { if (error == cudaErrorAssert) {
printf( printf("Device assert failed as expected, "
"Device assert failed as expected, "
"CUDA error message is: %s\n\n", "CUDA error message is: %s\n\n",
cudaGetErrorString(error)); cudaGetErrorString(error));
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -30,7 +30,7 @@ cuModuleGetFunction, cuLaunchKernel, cuCtxSynchronize
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -34,11 +34,12 @@
#endif #endif
// Includes, system // Includes, system
#include <stdio.h>
#include <cassert> #include <cassert>
#include <stdio.h>
// Includes CUDA // Includes CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include "nvrtc_helper.h" #include "nvrtc_helper.h"
// Utilities and timing functions // Utilities and timing functions
@ -58,7 +59,8 @@ void runTest(int argc, char **argv);
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName); printf("%s starting...\n", sampleName);
runTest(argc, argv); runTest(argc, argv);
@ -66,7 +68,8 @@ int main(int argc, char **argv) {
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
int Nblocks = 2; int Nblocks = 2;
int Nthreads = 32; int Nthreads = 32;
@ -91,10 +94,15 @@ void runTest(int argc, char **argv) {
int count = 60; int count = 60;
void *args[] = {(void *)&count}; void *args[] = {(void *)&count};
checkCudaErrors(cuLaunchKernel( checkCudaErrors(cuLaunchKernel(kernel_addr,
kernel_addr, dimGrid.x, dimGrid.y, dimGrid.z, /* grid dim */ dimGrid.x,
dimBlock.x, dimBlock.y, dimBlock.z, /* block dim */ dimGrid.y,
0, 0, /* shared mem, stream */ dimGrid.z, /* grid dim */
dimBlock.x,
dimBlock.y,
dimBlock.z, /* block dim */
0,
0, /* shared mem, stream */
&args[0], /* arguments */ &args[0], /* arguments */
0)); 0));

View File

@ -32,7 +32,8 @@
//! Thread whose id > N will print assertion failed error message. //! Thread whose id > N will print assertion failed error message.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" __global__ void testKernel(int N) { extern "C" __global__ void testKernel(int N)
{
int gtid = blockIdx.x * blockDim.x + threadIdx.x; int gtid = blockIdx.x * blockDim.x + threadIdx.x;
assert(gtid < N); assert(gtid < N);
} }

View File

@ -11,8 +11,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaStreamCreateWithFlags, cudaFree, cudaMallocHost, cudaFreeHost, cudaStreamSyn
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -30,10 +30,10 @@
*/ */
// includes, system // includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#define WINDOWS_LEAN_AND_MEAN #define WINDOWS_LEAN_AND_MEAN
@ -68,20 +68,21 @@ extern "C" bool computeGold(int *gpuData, const int len);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName); printf("%s starting...\n", sampleName);
runTest(argc, argv); runTest(argc, argv);
printf("%s completed, returned %s\n", sampleName, printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!");
testResult ? "OK" : "ERROR!");
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Run a simple test for CUDA //! Run a simple test for CUDA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
cudaStream_t stream; cudaStream_t stream;
// This will pick the best possible CUDA capable device // This will pick the best possible CUDA capable device
findCudaDevice(argc, (const char **)argv); findCudaDevice(argc, (const char **)argv);
@ -100,7 +101,8 @@ void runTest(int argc, char **argv) {
checkCudaErrors(cudaMallocHost(&hOData, memSize)); checkCudaErrors(cudaMallocHost(&hOData, memSize));
// initialize the memory // initialize the memory
for (unsigned int i = 0; i < numData; i++) hOData[i] = 0; for (unsigned int i = 0; i < numData; i++)
hOData[i] = 0;
// To make the AND and XOR tests generate something other than 0... // To make the AND and XOR tests generate something other than 0...
hOData[8] = hOData[10] = 0xff; hOData[8] = hOData[10] = 0xff;
@ -110,15 +112,13 @@ void runTest(int argc, char **argv) {
int *dOData; int *dOData;
checkCudaErrors(cudaMalloc((void **)&dOData, memSize)); checkCudaErrors(cudaMalloc((void **)&dOData, memSize));
// copy host memory to device to initialize to zero // copy host memory to device to initialize to zero
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(dOData, hOData, memSize, cudaMemcpyHostToDevice, stream));
cudaMemcpyAsync(dOData, hOData, memSize, cudaMemcpyHostToDevice, stream));
// execute the kernel // execute the kernel
testKernel<<<numBlocks, numThreads, 0, stream>>>(dOData); testKernel<<<numBlocks, numThreads, 0, stream>>>(dOData);
// Copy result from device to host // Copy result from device to host
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(hOData, dOData, memSize, cudaMemcpyDeviceToHost, stream));
cudaMemcpyAsync(hOData, dOData, memSize, cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream)); checkCudaErrors(cudaStreamSynchronize(stream));
sdkStopTimer(&timer); sdkStopTimer(&timer);

View File

@ -42,7 +42,8 @@ extern "C" int computeGold(int *gpuData, const int len);
//! @param idata input data as provided to device //! @param idata input data as provided to device
//! @param len number of elements in reference / idata //! @param len number of elements in reference / idata
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int computeGold(int *gpuData, const int len) { int computeGold(int *gpuData, const int len)
{
int val = 0; int val = 0;
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) {

View File

@ -35,7 +35,8 @@
//! @param g_idata input data in global memory //! @param g_idata input data in global memory
//! @param g_odata output data in global memory //! @param g_odata output data in global memory
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__global__ void testKernel(int *g_odata) { __global__ void testKernel(int *g_odata)
{
// access thread id // access thread id
const unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x; const unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x;

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -33,7 +33,7 @@ cudaBlockSize, cudaGridSize
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -30,10 +30,10 @@
*/ */
// includes, system // includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#define WINDOWS_LEAN_AND_MEAN #define WINDOWS_LEAN_AND_MEAN
@ -64,13 +64,13 @@ extern "C" bool computeGold(int *gpuData, const int len);
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("%s starting...\n", sampleName); printf("%s starting...\n", sampleName);
runTest(argc, argv); runTest(argc, argv);
printf("%s completed, returned %s\n", sampleName, printf("%s completed, returned %s\n", sampleName, testResult ? "OK" : "ERROR!");
testResult ? "OK" : "ERROR!");
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE); exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
} }
@ -79,7 +79,8 @@ int main(int argc, char **argv) {
//! Run a simple test for CUDA //! Run a simple test for CUDA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
int dev = 0; int dev = 0;
char *cubin, *kernel_file; char *cubin, *kernel_file;
@ -106,7 +107,8 @@ void runTest(int argc, char **argv) {
int *hOData = (int *)malloc(memSize); int *hOData = (int *)malloc(memSize);
// initialize the memory // initialize the memory
for (unsigned int i = 0; i < numData; i++) hOData[i] = 0; for (unsigned int i = 0; i < numData; i++)
hOData[i] = 0;
// To make the AND and XOR tests generate something other than 0... // To make the AND and XOR tests generate something other than 0...
hOData[8] = hOData[10] = 0xff; hOData[8] = hOData[10] = 0xff;
@ -121,11 +123,15 @@ void runTest(int argc, char **argv) {
dim3 cudaGridSize(numBlocks, 1, 1); dim3 cudaGridSize(numBlocks, 1, 1);
void *arr[] = {(void *)&dOData}; void *arr[] = {(void *)&dOData};
checkCudaErrors(cuLaunchKernel(kernel_addr, cudaGridSize.x, cudaGridSize.y, checkCudaErrors(cuLaunchKernel(kernel_addr,
cudaGridSize.x,
cudaGridSize.y,
cudaGridSize.z, /* grid dim */ cudaGridSize.z, /* grid dim */
cudaBlockSize.x, cudaBlockSize.y, cudaBlockSize.x,
cudaBlockSize.y,
cudaBlockSize.z, /* block dim */ cudaBlockSize.z, /* block dim */
0, 0, /* shared mem, stream */ 0,
0, /* shared mem, stream */
&arr[0], /* arguments */ &arr[0], /* arguments */
0)); 0));

View File

@ -43,7 +43,8 @@ extern "C" int computeGold(int *gpuData, const int len);
//! @param len number of elements in reference / idata //! @param len number of elements in reference / idata
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int computeGold(int *gpuData, const int len) { int computeGold(int *gpuData, const int len)
{
int val = 0; int val = 0;
for (int i = 0; i < len; ++i) { for (int i = 0; i < len; ++i) {

View File

@ -36,7 +36,8 @@
//! @param g_odata output data in global memory //! @param g_odata output data in global memory
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" __global__ void testKernel(int *g_odata) { extern "C" __global__ void testKernel(int *g_odata)
{
// access thread id // access thread id
const unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x; const unsigned int tid = blockDim.x * blockIdx.x + threadIdx.x;

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaFree, cudaMallocHost, cudaFreeHost, cudaStreamSynchronize, cudaStreamSetAttr
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -26,10 +26,10 @@
*/ */
// includes, system // includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes CUDA // includes CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
@ -42,7 +42,8 @@
// declaration, forward // declaration, forward
void runTest(int argc, char **argv); void runTest(int argc, char **argv);
cudaAccessPolicyWindow initAccessPolicyWindow(void) { cudaAccessPolicyWindow initAccessPolicyWindow(void)
{
cudaAccessPolicyWindow accessPolicyWindow = {0}; cudaAccessPolicyWindow accessPolicyWindow = {0};
accessPolicyWindow.base_ptr = (void *)0; accessPolicyWindow.base_ptr = (void *)0;
accessPolicyWindow.num_bytes = 0; accessPolicyWindow.num_bytes = 0;
@ -60,8 +61,8 @@ cudaAccessPolicyWindow initAccessPolicyWindow(void) {
//! @param bigDataSize input bigData size //! @param bigDataSize input bigData size
//! @param hitcount how many data access are done within block //! @param hitcount how many data access are done within block
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static __global__ void kernCacheSegmentTest(int *data, int dataSize, int *trash, static __global__ void kernCacheSegmentTest(int *data, int dataSize, int *trash, int bigDataSize, int hitCount)
int bigDataSize, int hitCount) { {
__shared__ unsigned int hit; __shared__ unsigned int hit;
int row = blockIdx.y * blockDim.y + threadIdx.y; int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x; int col = blockIdx.x * blockDim.x + threadIdx.x;
@ -82,9 +83,9 @@ static __global__ void kernCacheSegmentTest(int *data, int dataSize, int *trash,
if ((tID % 2) == 0) { if ((tID % 2) == 0) {
data[psRand % dataSize] = data[psRand % dataSize] + data[idx % dataSize]; data[psRand % dataSize] = data[psRand % dataSize] + data[idx % dataSize];
} else { }
trash[psRand % bigDataSize] = else {
trash[psRand % bigDataSize] + trash[idx % bigDataSize]; trash[psRand % bigDataSize] = trash[psRand % bigDataSize] + trash[idx % bigDataSize];
} }
atomicAdd(&hit, 1); atomicAdd(&hit, 1);
@ -98,7 +99,8 @@ int main(int argc, char **argv) { runTest(argc, argv); }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Run a simple test for CUDA //! Run a simple test for CUDA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) { void runTest(int argc, char **argv)
{
bool bTestResult = true; bool bTestResult = true;
cudaAccessPolicyWindow accessPolicyWindow; cudaAccessPolicyWindow accessPolicyWindow;
cudaDeviceProp deviceProp; cudaDeviceProp deviceProp;
@ -127,8 +129,7 @@ void runTest(int argc, char **argv) {
// Make sure device the l2 optimization // Make sure device the l2 optimization
if (deviceProp.persistingL2CacheMaxSize == 0) { if (deviceProp.persistingL2CacheMaxSize == 0) {
printf( printf("Waiving execution as device %d does not support persisting L2 "
"Waiving execution as device %d does not support persisting L2 "
"Caching\n", "Caching\n",
devID); devID);
exit(EXIT_WAIVED); exit(EXIT_WAIVED);
@ -139,8 +140,7 @@ void runTest(int argc, char **argv) {
// Set the amount of l2 cache that will be persisting to maximum the device // Set the amount of l2 cache that will be persisting to maximum the device
// can support // can support
checkCudaErrors(cudaDeviceSetLimit(cudaLimitPersistingL2CacheSize, checkCudaErrors(cudaDeviceSetLimit(cudaLimitPersistingL2CacheSize, deviceProp.persistingL2CacheMaxSize));
deviceProp.persistingL2CacheMaxSize));
// Stream attribute to set // Stream attribute to set
streamAttrID = cudaStreamAttributeAccessPolicyWindow; streamAttrID = cudaStreamAttributeAccessPolicyWindow;
@ -155,8 +155,7 @@ void runTest(int argc, char **argv) {
// Allocate data // Allocate data
checkCudaErrors(cudaMallocHost(&dataHostPointer, dataSize * sizeof(int))); checkCudaErrors(cudaMallocHost(&dataHostPointer, dataSize * sizeof(int)));
checkCudaErrors( checkCudaErrors(cudaMallocHost(&bigDataHostPointer, bigDataSize * sizeof(int)));
cudaMallocHost(&bigDataHostPointer, bigDataSize * sizeof(int)));
for (int i = 0; i < bigDataSize; ++i) { for (int i = 0; i < bigDataSize; ++i) {
if (i < dataSize) { if (i < dataSize) {
@ -166,16 +165,12 @@ void runTest(int argc, char **argv) {
bigDataHostPointer[bigDataSize - i - 1] = i; bigDataHostPointer[bigDataSize - i - 1] = i;
} }
checkCudaErrors(cudaMalloc((void **)&dataDevicePointer, dataSize * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&bigDataDevicePointer, bigDataSize * sizeof(int)));
checkCudaErrors( checkCudaErrors(
cudaMalloc((void **)&dataDevicePointer, dataSize * sizeof(int))); cudaMemcpyAsync(dataDevicePointer, dataHostPointer, dataSize * sizeof(int), cudaMemcpyHostToDevice, stream));
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(
cudaMalloc((void **)&bigDataDevicePointer, bigDataSize * sizeof(int))); bigDataDevicePointer, bigDataHostPointer, bigDataSize * sizeof(int), cudaMemcpyHostToDevice, stream));
checkCudaErrors(cudaMemcpyAsync(dataDevicePointer, dataHostPointer,
dataSize * sizeof(int),
cudaMemcpyHostToDevice, stream));
checkCudaErrors(cudaMemcpyAsync(bigDataDevicePointer, bigDataHostPointer,
bigDataSize * sizeof(int),
cudaMemcpyHostToDevice, stream));
// Make a window for the buffer of interest // Make a window for the buffer of interest
accessPolicyWindow.base_ptr = (void *)dataDevicePointer; accessPolicyWindow.base_ptr = (void *)dataDevicePointer;
@ -186,8 +181,7 @@ void runTest(int argc, char **argv) {
streamAttrValue.accessPolicyWindow = accessPolicyWindow; streamAttrValue.accessPolicyWindow = accessPolicyWindow;
// Assign window to stream // Assign window to stream
checkCudaErrors( checkCudaErrors(cudaStreamSetAttribute(stream, streamAttrID, &streamAttrValue));
cudaStreamSetAttribute(stream, streamAttrID, &streamAttrValue));
// Demote any previous persisting lines // Demote any previous persisting lines
checkCudaErrors(cudaCtxResetPersistingL2Cache()); checkCudaErrors(cudaCtxResetPersistingL2Cache());

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries
@ -59,12 +61,16 @@ if(${OpenGL_FOUND})
add_custom_command(TARGET simpleCUDA2GL add_custom_command(TARGET simpleCUDA2GL
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/win64/$<CONFIGURATION>/freeglut.dll ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E
copy ${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/win64/$<CONFIGURATION>/freeglut.dll
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>
) )
add_custom_command(TARGET simpleCUDA2GL add_custom_command(TARGET simpleCUDA2GL
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/win64/$<CONFIGURATION>/glew64.dll ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E
copy ${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/win64/$<CONFIGURATION>/glew64.dll
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>
) )
endif() endif()
endif() endif()

View File

@ -30,8 +30,7 @@ cudaHostAlloc, cudaGraphicsUnmapResources, cudaMalloc, cudaFree, cudaGraphicsRes
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
Make sure the dependencies mentioned in [Dependencies]() section above are installed. Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details) ## References (for more details)

View File

@ -50,8 +50,8 @@
#endif #endif
// CUDA includes // CUDA includes
#include <cuda_runtime.h>
#include <cuda_gl_interop.h> #include <cuda_gl_interop.h>
#include <cuda_runtime.h>
// CUDA utilities and system includes // CUDA utilities and system includes
#include <helper_cuda.h> #include <helper_cuda.h>
@ -124,8 +124,7 @@ StopWatchInterface *timer = NULL;
GLuint shDraw; GLuint shDraw;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" void launch_cudaProcess(dim3 grid, dim3 block, int sbytes, extern "C" void launch_cudaProcess(dim3 grid, dim3 block, int sbytes, unsigned int *g_odata, int imgw);
unsigned int *g_odata, int imgw);
// Forward declarations // Forward declarations
void runStdProgram(int argc, char **argv); void runStdProgram(int argc, char **argv);
@ -140,8 +139,7 @@ void createPBO(GLuint *pbo, struct cudaGraphicsResource **pbo_resource);
void deletePBO(GLuint *pbo); void deletePBO(GLuint *pbo);
#endif #endif
void createTextureDst(GLuint *tex_cudaResult, unsigned int size_x, void createTextureDst(GLuint *tex_cudaResult, unsigned int size_x, unsigned int size_y);
unsigned int size_y);
void deleteTexture(GLuint *tex); void deleteTexture(GLuint *tex);
// rendering callbacks // rendering callbacks
@ -155,7 +153,8 @@ void mainMenu(int i);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Create PBO //! Create PBO
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void createPBO(GLuint *pbo, struct cudaGraphicsResource **pbo_resource) { void createPBO(GLuint *pbo, struct cudaGraphicsResource **pbo_resource)
{
// set up vertex data parameter // set up vertex data parameter
num_texels = image_width * image_height; num_texels = image_width * image_height;
num_values = num_texels * 4; num_values = num_texels * 4;
@ -171,33 +170,32 @@ void createPBO(GLuint *pbo, struct cudaGraphicsResource **pbo_resource) {
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
// register this buffer object with CUDA // register this buffer object with CUDA
checkCudaErrors(cudaGraphicsGLRegisterBuffer(pbo_resource, *pbo, checkCudaErrors(cudaGraphicsGLRegisterBuffer(pbo_resource, *pbo, cudaGraphicsMapFlagsNone));
cudaGraphicsMapFlagsNone));
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
} }
void deletePBO(GLuint *pbo) { void deletePBO(GLuint *pbo)
{
glDeleteBuffers(1, pbo); glDeleteBuffers(1, pbo);
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
*pbo = 0; *pbo = 0;
} }
#endif #endif
const GLenum fbo_targets[] = { const GLenum fbo_targets[] = {GL_COLOR_ATTACHMENT0_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT1_EXT,
GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT}; GL_COLOR_ATTACHMENT2_EXT,
GL_COLOR_ATTACHMENT3_EXT};
#ifndef USE_TEXSUBIMAGE2D #ifndef USE_TEXSUBIMAGE2D
static const char *glsl_drawtex_vertshader_src = static const char *glsl_drawtex_vertshader_src = "void main(void)\n"
"void main(void)\n"
"{\n" "{\n"
" gl_Position = gl_Vertex;\n" " gl_Position = gl_Vertex;\n"
" gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" " gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n"
"}\n"; "}\n";
static const char *glsl_drawtex_fragshader_src = static const char *glsl_drawtex_fragshader_src = "#version 130\n"
"#version 130\n"
"uniform usampler2D texImage;\n" "uniform usampler2D texImage;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
@ -227,15 +225,15 @@ static const char *glsl_draw_fragshader_src =
#endif #endif
// copy image and process using CUDA // copy image and process using CUDA
void generateCUDAImage() { void generateCUDAImage()
{
// run the Cuda kernel // run the Cuda kernel
unsigned int *out_data; unsigned int *out_data;
#ifdef USE_TEXSUBIMAGE2D #ifdef USE_TEXSUBIMAGE2D
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_dest_resource, 0)); checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_dest_resource, 0));
size_t num_bytes; size_t num_bytes;
checkCudaErrors(cudaGraphicsResourceGetMappedPointer( checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&out_data, &num_bytes, cuda_pbo_dest_resource));
(void **)&out_data, &num_bytes, cuda_pbo_dest_resource));
// printf("CUDA mapped pointer of pbo_out: May access %ld bytes, expected %d\n", // printf("CUDA mapped pointer of pbo_out: May access %ld bytes, expected %d\n",
// num_bytes, size_tex_data); // num_bytes, size_tex_data);
#else #else
@ -258,8 +256,7 @@ void generateCUDAImage() {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_dest); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_dest);
glBindTexture(GL_TEXTURE_2D, tex_cudaResult); glBindTexture(GL_TEXTURE_2D, tex_cudaResult);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGBA, glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
GL_UNSIGNED_BYTE, NULL);
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
@ -268,21 +265,20 @@ void generateCUDAImage() {
// map buffer objects to get CUDA device pointers // map buffer objects to get CUDA device pointers
cudaArray *texture_ptr; cudaArray *texture_ptr;
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_tex_result_resource, 0)); checkCudaErrors(cudaGraphicsMapResources(1, &cuda_tex_result_resource, 0));
checkCudaErrors(cudaGraphicsSubResourceGetMappedArray( checkCudaErrors(cudaGraphicsSubResourceGetMappedArray(&texture_ptr, cuda_tex_result_resource, 0, 0));
&texture_ptr, cuda_tex_result_resource, 0, 0));
int num_texels = image_width * image_height; int num_texels = image_width * image_height;
int num_values = num_texels * 4; int num_values = num_texels * 4;
int size_tex_data = sizeof(GLubyte) * num_values; int size_tex_data = sizeof(GLubyte) * num_values;
checkCudaErrors(cudaMemcpyToArray(texture_ptr, 0, 0, cuda_dest_resource, checkCudaErrors(cudaMemcpyToArray(texture_ptr, 0, 0, cuda_dest_resource, size_tex_data, cudaMemcpyDeviceToDevice));
size_tex_data, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_tex_result_resource, 0)); checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_tex_result_resource, 0));
#endif #endif
} }
// display image to the screen as textured quad // display image to the screen as textured quad
void displayImage(GLuint texture) { void displayImage(GLuint texture)
{
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -332,7 +328,8 @@ void displayImage(GLuint texture) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Display callback //! Display callback
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void display() { void display()
{
sdkStartTimer(&timer); sdkStartTimer(&timer);
if (enable_cuda) { if (enable_cuda) {
@ -358,9 +355,7 @@ void display() {
sprintf(currentOutputPPM, "kilt.ppm"); sprintf(currentOutputPPM, "kilt.ppm");
g_CheckRender->savePPM(currentOutputPPM, true, NULL); g_CheckRender->savePPM(currentOutputPPM, true, NULL);
if (!g_CheckRender->PPMvsPPM(currentOutputPPM, if (!g_CheckRender->PPMvsPPM(currentOutputPPM, sdkFindFilePath(ref_file, pArgv[0]), MAX_EPSILON, 0.30f)) {
sdkFindFilePath(ref_file, pArgv[0]),
MAX_EPSILON, 0.30f)) {
g_TotalErrors++; g_TotalErrors++;
} }
@ -374,8 +369,7 @@ void display() {
if (++fpsCount == fpsLimit) { if (++fpsCount == fpsLimit) {
char cTitle[256]; char cTitle[256];
float fps = 1000.0f / sdkGetAverageTimerValue(&timer); float fps = 1000.0f / sdkGetAverageTimerValue(&timer);
sprintf(cTitle, "CUDA GL Post Processing (%d x %d): %.1f fps", window_width, sprintf(cTitle, "CUDA GL Post Processing (%d x %d): %.1f fps", window_width, window_height, fps);
window_height, fps);
glutSetWindowTitle(cTitle); glutSetWindowTitle(cTitle);
// printf("%s\n", cTitle); // printf("%s\n", cTitle);
fpsCount = 0; fpsCount = 0;
@ -384,7 +378,8 @@ void display() {
} }
} }
void timerEvent(int value) { void timerEvent(int value)
{
glutPostRedisplay(); glutPostRedisplay();
glutTimerFunc(REFRESH_DELAY, timerEvent, 0); glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
} }
@ -392,7 +387,8 @@ void timerEvent(int value) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Keyboard events handler //! Keyboard events handler
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void keyboard(unsigned char key, int /*x*/, int /*y*/) { void keyboard(unsigned char key, int /*x*/, int /*y*/)
{
switch (key) { switch (key) {
case (27): case (27):
Cleanup(EXIT_SUCCESS); Cleanup(EXIT_SUCCESS);
@ -404,7 +400,8 @@ void keyboard(unsigned char key, int /*x*/, int /*y*/) {
if (enable_cuda) { if (enable_cuda) {
glClearColorIuiEXT(128, 128, 128, 255); glClearColorIuiEXT(128, 128, 128, 255);
} else { }
else {
glClearColor(0.5, 0.5, 0.5, 1.0); glClearColor(0.5, 0.5, 0.5, 1.0);
} }
@ -413,7 +410,8 @@ void keyboard(unsigned char key, int /*x*/, int /*y*/) {
} }
} }
void reshape(int w, int h) { void reshape(int w, int h)
{
window_width = w; window_width = w;
window_height = h; window_height = h;
} }
@ -423,8 +421,8 @@ void mainMenu(int i) { keyboard((unsigned char)i, 0, 0); }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! //!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void createTextureDst(GLuint *tex_cudaResult, unsigned int size_x, void createTextureDst(GLuint *tex_cudaResult, unsigned int size_x, unsigned int size_y)
unsigned int size_y) { {
// create a texture // create a texture
glGenTextures(1, tex_cudaResult); glGenTextures(1, tex_cudaResult);
glBindTexture(GL_TEXTURE_2D, *tex_cudaResult); glBindTexture(GL_TEXTURE_2D, *tex_cudaResult);
@ -436,24 +434,22 @@ void createTextureDst(GLuint *tex_cudaResult, unsigned int size_x,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#ifdef USE_TEXSUBIMAGE2D #ifdef USE_TEXSUBIMAGE2D
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size_x, size_y, 0, GL_RGBA, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size_x, size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
GL_UNSIGNED_BYTE, NULL);
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI_EXT, size_x, size_y, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI_EXT, size_x, size_y, 0, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_BYTE, NULL);
GL_RGBA_INTEGER_EXT, GL_UNSIGNED_BYTE, NULL);
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
// register this texture with CUDA // register this texture with CUDA
checkCudaErrors(cudaGraphicsGLRegisterImage( checkCudaErrors(cudaGraphicsGLRegisterImage(
&cuda_tex_result_resource, *tex_cudaResult, GL_TEXTURE_2D, &cuda_tex_result_resource, *tex_cudaResult, GL_TEXTURE_2D, cudaGraphicsMapFlagsWriteDiscard));
cudaGraphicsMapFlagsWriteDiscard));
#endif #endif
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! //!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void deleteTexture(GLuint *tex) { void deleteTexture(GLuint *tex)
{
glDeleteTextures(1, tex); glDeleteTextures(1, tex);
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
@ -463,7 +459,8 @@ void deleteTexture(GLuint *tex) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
#if defined(__linux__) #if defined(__linux__)
char *Xstatus = getenv("DISPLAY"); char *Xstatus = getenv("DISPLAY");
if (Xstatus == NULL) { if (Xstatus == NULL) {
@ -487,8 +484,7 @@ int main(int argc, char **argv) {
if (checkCmdLineFlag(argc, (const char **)argv, "device")) { if (checkCmdLineFlag(argc, (const char **)argv, "device")) {
printf("[%s]\n", argv[0]); printf("[%s]\n", argv[0]);
printf(" Does not explicitly support -device=n\n"); printf(" Does not explicitly support -device=n\n");
printf( printf(" This sample requires OpenGL. Only -file=<reference> are "
" This sample requires OpenGL. Only -file=<reference> are "
"supported\n"); "supported\n");
printf("exiting...\n"); printf("exiting...\n");
exit(EXIT_WAIVED); exit(EXIT_WAIVED);
@ -497,7 +493,8 @@ int main(int argc, char **argv) {
if (ref_file) { if (ref_file) {
printf("(Test with OpenGL verification)\n"); printf("(Test with OpenGL verification)\n");
runStdProgram(argc, argv); runStdProgram(argc, argv);
} else { }
else {
printf("(Interactive OpenGL Demo)\n"); printf("(Interactive OpenGL Demo)\n");
runStdProgram(argc, argv); runStdProgram(argc, argv);
} }
@ -508,7 +505,8 @@ int main(int argc, char **argv) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! //!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void FreeResource() { void FreeResource()
{
sdkDeleteTimer(&timer); sdkDeleteTimer(&timer);
// unregister this buffer object with CUDA // unregister this buffer object with CUDA
@ -530,18 +528,18 @@ void FreeResource() {
printf("simpleCUDA2GL Exiting...\n"); printf("simpleCUDA2GL Exiting...\n");
} }
void Cleanup(int iExitCode) { void Cleanup(int iExitCode)
{
FreeResource(); FreeResource();
printf("PPM Images are %s\n", printf("PPM Images are %s\n", (iExitCode == EXIT_SUCCESS) ? "Matching" : "Not Matching");
(iExitCode == EXIT_SUCCESS) ? "Matching" : "Not Matching");
exit(iExitCode); exit(iExitCode);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! //!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
GLuint compileGLSLprogram(const char *vertex_shader_src, GLuint compileGLSLprogram(const char *vertex_shader_src, const char *fragment_shader_src)
const char *fragment_shader_src) { {
GLuint v, f, p = 0; GLuint v, f, p = 0;
p = glCreateProgram(); p = glCreateProgram();
@ -556,14 +554,15 @@ GLuint compileGLSLprogram(const char *vertex_shader_src,
glGetShaderiv(v, GL_COMPILE_STATUS, &compiled); glGetShaderiv(v, GL_COMPILE_STATUS, &compiled);
if (!compiled) { if (!compiled) {
//#ifdef NV_REPORT_COMPILE_ERRORS // #ifdef NV_REPORT_COMPILE_ERRORS
char temp[256] = ""; char temp[256] = "";
glGetShaderInfoLog(v, 256, NULL, temp); glGetShaderInfoLog(v, 256, NULL, temp);
printf("Vtx Compile failed:\n%s\n", temp); printf("Vtx Compile failed:\n%s\n", temp);
//#endif // #endif
glDeleteShader(v); glDeleteShader(v);
return 0; return 0;
} else { }
else {
glAttachShader(p, v); glAttachShader(p, v);
} }
} }
@ -578,14 +577,15 @@ GLuint compileGLSLprogram(const char *vertex_shader_src,
glGetShaderiv(f, GL_COMPILE_STATUS, &compiled); glGetShaderiv(f, GL_COMPILE_STATUS, &compiled);
if (!compiled) { if (!compiled) {
//#ifdef NV_REPORT_COMPILE_ERRORS // #ifdef NV_REPORT_COMPILE_ERRORS
char temp[256] = ""; char temp[256] = "";
glGetShaderInfoLog(f, 256, NULL, temp); glGetShaderInfoLog(f, 256, NULL, temp);
printf("frag Compile failed:\n%s\n", temp); printf("frag Compile failed:\n%s\n", temp);
//#endif // #endif
glDeleteShader(f); glDeleteShader(f);
return 0; return 0;
} else { }
else {
glAttachShader(p, f); glAttachShader(p, f);
} }
} }
@ -611,7 +611,8 @@ GLuint compileGLSLprogram(const char *vertex_shader_src,
//! Allocate the "render target" of CUDA //! Allocate the "render target" of CUDA
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef USE_TEXSUBIMAGE2D #ifndef USE_TEXSUBIMAGE2D
void initCUDABuffers() { void initCUDABuffers()
{
// set up vertex data parameter // set up vertex data parameter
num_texels = image_width * image_height; num_texels = image_width * image_height;
num_values = num_texels * 4; num_values = num_texels * 4;
@ -625,7 +626,8 @@ void initCUDABuffers() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! //!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void initGLBuffers() { void initGLBuffers()
{
// create pbo // create pbo
#ifdef USE_TEXSUBIMAGE2D #ifdef USE_TEXSUBIMAGE2D
createPBO(&pbo_dest, &cuda_pbo_dest_resource); createPBO(&pbo_dest, &cuda_pbo_dest_resource);
@ -636,8 +638,7 @@ void initGLBuffers() {
shDraw = compileGLSLprogram(NULL, glsl_draw_fragshader_src); shDraw = compileGLSLprogram(NULL, glsl_draw_fragshader_src);
#ifndef USE_TEXSUBIMAGE2D #ifndef USE_TEXSUBIMAGE2D
shDrawTex = compileGLSLprogram(glsl_drawtex_vertshader_src, shDrawTex = compileGLSLprogram(glsl_drawtex_vertshader_src, glsl_drawtex_fragshader_src);
glsl_drawtex_fragshader_src);
#endif #endif
SDK_CHECK_ERROR_GL(); SDK_CHECK_ERROR_GL();
} }
@ -645,7 +646,8 @@ void initGLBuffers() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Run standard demo loop with or without GL verification //! Run standard demo loop with or without GL verification
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runStdProgram(int argc, char **argv) { void runStdProgram(int argc, char **argv)
{
// First initialize OpenGL context, so we can properly set the GL for CUDA. // First initialize OpenGL context, so we can properly set the GL for CUDA.
// This is necessary in order to achieve optimal performance with OpenGL/CUDA // This is necessary in order to achieve optimal performance with OpenGL/CUDA
// interop. // interop.
@ -683,8 +685,7 @@ void runStdProgram(int argc, char **argv) {
g_CheckRender->EnableQAReadback(true); g_CheckRender->EnableQAReadback(true);
} }
printf( printf("\n"
"\n"
"\tControls\n" "\tControls\n"
"\t(right click mouse button for Menu)\n" "\t(right click mouse button for Menu)\n"
"\t[esc] - Quit\n\n"); "\t[esc] - Quit\n\n");
@ -699,7 +700,8 @@ void runStdProgram(int argc, char **argv) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//! Initialize GL //! Initialize GL
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool initGL(int *argc, char **argv) { bool initGL(int *argc, char **argv)
{
// Create GL context // Create GL context
glutInit(argc, argv); glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH); glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
@ -707,8 +709,8 @@ bool initGL(int *argc, char **argv) {
iGLUTWindowHandle = glutCreateWindow("CUDA OpenGL post-processing"); iGLUTWindowHandle = glutCreateWindow("CUDA OpenGL post-processing");
// initialize necessary OpenGL extensions // initialize necessary OpenGL extensions
if (!isGLVersionSupported(2, 0) || if (!isGLVersionSupported(2, 0)
!areGLExtensionsSupported("GL_ARB_pixel_buffer_object " || !areGLExtensionsSupported("GL_ARB_pixel_buffer_object "
"GL_EXT_framebuffer_object")) { "GL_EXT_framebuffer_object")) {
printf("ERROR: Support for necessary OpenGL extensions missing."); printf("ERROR: Support for necessary OpenGL extensions missing.");
fflush(stderr); fflush(stderr);
@ -729,8 +731,7 @@ bool initGL(int *argc, char **argv) {
// projection // projection
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
gluPerspective(60.0, (GLfloat)window_width / (GLfloat)window_height, 0.1f, gluPerspective(60.0, (GLfloat)window_width / (GLfloat)window_height, 0.1f, 10.0f);
10.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

View File

@ -35,14 +35,16 @@ __device__ float clamp(float x, float a, float b) { return max(a, min(b, x)); }
__device__ int clamp(int x, int a, int b) { return max(a, min(b, x)); } __device__ int clamp(int x, int a, int b) { return max(a, min(b, x)); }
// convert floating point rgb color to 8-bit integer // convert floating point rgb color to 8-bit integer
__device__ int rgbToInt(float r, float g, float b) { __device__ int rgbToInt(float r, float g, float b)
{
r = clamp(r, 0.0f, 255.0f); r = clamp(r, 0.0f, 255.0f);
g = clamp(g, 0.0f, 255.0f); g = clamp(g, 0.0f, 255.0f);
b = clamp(b, 0.0f, 255.0f); b = clamp(b, 0.0f, 255.0f);
return (int(b) << 16) | (int(g) << 8) | int(r); return (int(b) << 16) | (int(g) << 8) | int(r);
} }
__global__ void cudaProcess(unsigned int *g_odata, int imgw) { __global__ void cudaProcess(unsigned int *g_odata, int imgw)
{
extern __shared__ uchar4 sdata[]; extern __shared__ uchar4 sdata[];
int tx = threadIdx.x; int tx = threadIdx.x;
@ -56,7 +58,7 @@ __global__ void cudaProcess(unsigned int *g_odata, int imgw) {
g_odata[y * imgw + x] = rgbToInt(c4.z, c4.y, c4.x); g_odata[y * imgw + x] = rgbToInt(c4.z, c4.y, c4.x);
} }
extern "C" void launch_cudaProcess(dim3 grid, dim3 block, int sbytes, extern "C" void launch_cudaProcess(dim3 grid, dim3 block, int sbytes, unsigned int *g_odata, int imgw)
unsigned int *g_odata, int imgw) { {
cudaProcess<<<grid, block, sbytes>>>(g_odata, imgw); cudaProcess<<<grid, block, sbytes>>>(g_odata, imgw);
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaHostAlloc, cudaStreamDestroy, cudaFree, cudaSetDevice, cudaGetDeviceCount, c
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -29,18 +29,21 @@
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
// Create thread // Create thread
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data) { CUTThread cutStartThread(CUT_THREADROUTINE func, void *data)
{
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, data, 0, NULL); return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, data, 0, NULL);
} }
// Wait for thread to finish // Wait for thread to finish
void cutEndThread(CUTThread thread) { void cutEndThread(CUTThread thread)
{
WaitForSingleObject(thread, INFINITE); WaitForSingleObject(thread, INFINITE);
CloseHandle(thread); CloseHandle(thread);
} }
// Wait for multiple threads // Wait for multiple threads
void cutWaitForThreads(const CUTThread *threads, int num) { void cutWaitForThreads(const CUTThread *threads, int num)
{
WaitForMultipleObjects(num, threads, true, INFINITE); WaitForMultipleObjects(num, threads, true, INFINITE);
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
@ -49,7 +52,8 @@ void cutWaitForThreads(const CUTThread *threads, int num) {
} }
// Create barrier. // Create barrier.
CUTBarrier cutCreateBarrier(int releaseCount) { CUTBarrier cutCreateBarrier(int releaseCount)
{
CUTBarrier barrier; CUTBarrier barrier;
InitializeCriticalSection(&barrier.criticalSection); InitializeCriticalSection(&barrier.criticalSection);
@ -61,7 +65,8 @@ CUTBarrier cutCreateBarrier(int releaseCount) {
} }
// Increment barrier. (execution continues) // Increment barrier. (execution continues)
void cutIncrementBarrier(CUTBarrier *barrier) { void cutIncrementBarrier(CUTBarrier *barrier)
{
int myBarrierCount; int myBarrierCount;
EnterCriticalSection(&barrier->criticalSection); EnterCriticalSection(&barrier->criticalSection);
myBarrierCount = ++barrier->count; myBarrierCount = ++barrier->count;
@ -73,16 +78,15 @@ void cutIncrementBarrier(CUTBarrier *barrier) {
} }
// Wait for barrier release. // Wait for barrier release.
void cutWaitForBarrier(CUTBarrier *barrier) { void cutWaitForBarrier(CUTBarrier *barrier) { WaitForSingleObject(barrier->barrierEvent, INFINITE); }
WaitForSingleObject(barrier->barrierEvent, INFINITE);
}
// Destroy barrier // Destroy barrier
void cutDestroyBarrier(CUTBarrier *barrier) {} void cutDestroyBarrier(CUTBarrier *barrier) {}
#else #else
// Create thread // Create thread
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data) { CUTThread cutStartThread(CUT_THREADROUTINE func, void *data)
{
pthread_t thread; pthread_t thread;
pthread_create(&thread, NULL, func, data); pthread_create(&thread, NULL, func, data);
return thread; return thread;
@ -92,14 +96,16 @@ CUTThread cutStartThread(CUT_THREADROUTINE func, void *data) {
void cutEndThread(CUTThread thread) { pthread_join(thread, NULL); } void cutEndThread(CUTThread thread) { pthread_join(thread, NULL); }
// Wait for multiple threads // Wait for multiple threads
void cutWaitForThreads(const CUTThread *threads, int num) { void cutWaitForThreads(const CUTThread *threads, int num)
{
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
cutEndThread(threads[i]); cutEndThread(threads[i]);
} }
} }
// Create barrier. // Create barrier.
CUTBarrier cutCreateBarrier(int releaseCount) { CUTBarrier cutCreateBarrier(int releaseCount)
{
CUTBarrier barrier; CUTBarrier barrier;
barrier.count = 0; barrier.count = 0;
@ -112,7 +118,8 @@ CUTBarrier cutCreateBarrier(int releaseCount) {
} }
// Increment barrier. (execution continues) // Increment barrier. (execution continues)
void cutIncrementBarrier(CUTBarrier *barrier) { void cutIncrementBarrier(CUTBarrier *barrier)
{
int myBarrierCount; int myBarrierCount;
pthread_mutex_lock(&barrier->mutex); pthread_mutex_lock(&barrier->mutex);
myBarrierCount = ++barrier->count; myBarrierCount = ++barrier->count;
@ -124,7 +131,8 @@ void cutIncrementBarrier(CUTBarrier *barrier) {
} }
// Wait for barrier release. // Wait for barrier release.
void cutWaitForBarrier(CUTBarrier *barrier) { void cutWaitForBarrier(CUTBarrier *barrier)
{
pthread_mutex_lock(&barrier->mutex); pthread_mutex_lock(&barrier->mutex);
while (barrier->count < barrier->releaseCount) { while (barrier->count < barrier->releaseCount) {
@ -135,7 +143,8 @@ void cutWaitForBarrier(CUTBarrier *barrier) {
} }
// Destroy barrier // Destroy barrier
void cutDestroyBarrier(CUTBarrier *barrier) { void cutDestroyBarrier(CUTBarrier *barrier)
{
pthread_mutex_destroy(&barrier->mutex); pthread_mutex_destroy(&barrier->mutex);
pthread_cond_destroy(&barrier->conditionVariable); pthread_cond_destroy(&barrier->conditionVariable);
} }

View File

@ -37,7 +37,8 @@
typedef HANDLE CUTThread; typedef HANDLE CUTThread;
typedef unsigned(WINAPI *CUT_THREADROUTINE)(void *); typedef unsigned(WINAPI *CUT_THREADROUTINE)(void *);
struct CUTBarrier { struct CUTBarrier
{
CRITICAL_SECTION criticalSection; CRITICAL_SECTION criticalSection;
HANDLE barrierEvent; HANDLE barrierEvent;
int releaseCount; int releaseCount;
@ -57,7 +58,8 @@ typedef void *(*CUT_THREADROUTINE)(void *);
#define CUT_THREADPROC void * #define CUT_THREADPROC void *
#define CUT_THREADEND return 0 #define CUT_THREADEND return 0
struct CUTBarrier { struct CUTBarrier
{
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t conditionVariable; pthread_cond_t conditionVariable;
int releaseCount; int releaseCount;
@ -67,29 +69,30 @@ struct CUTBarrier {
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
// Create thread. // Create thread.
CUTThread cutStartThread(CUT_THREADROUTINE, void *data); CUTThread cutStartThread(CUT_THREADROUTINE, void *data);
// Wait for thread to finish. // Wait for thread to finish.
void cutEndThread(CUTThread thread); void cutEndThread(CUTThread thread);
// Wait for multiple threads. // Wait for multiple threads.
void cutWaitForThreads(const CUTThread *threads, int num); void cutWaitForThreads(const CUTThread *threads, int num);
// Create barrier. // Create barrier.
CUTBarrier cutCreateBarrier(int releaseCount); CUTBarrier cutCreateBarrier(int releaseCount);
// Increment barrier. (execution continues) // Increment barrier. (execution continues)
void cutIncrementBarrier(CUTBarrier *barrier); void cutIncrementBarrier(CUTBarrier *barrier);
// Wait for barrier release. // Wait for barrier release.
void cutWaitForBarrier(CUTBarrier *barrier); void cutWaitForBarrier(CUTBarrier *barrier);
// Destroy barrier // Destroy barrier
void cutDestroyBarrier(CUTBarrier *barrier); void cutDestroyBarrier(CUTBarrier *barrier);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -43,8 +43,8 @@
#include <stdio.h> #include <stdio.h>
// helper functions and utilities to work with CUDA // helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h> #include <helper_cuda.h>
#include <helper_functions.h>
#include "multithreading.h" #include "multithreading.h"
@ -53,10 +53,10 @@ const int N_elements_per_workload = 100000;
CUTBarrier thread_barrier; CUTBarrier thread_barrier;
void CUDART_CB myStreamCallback(cudaStream_t event, cudaError_t status, void CUDART_CB myStreamCallback(cudaStream_t event, cudaError_t status, void *data);
void *data);
struct heterogeneous_workload { struct heterogeneous_workload
{
int id; int id;
int cudaDeviceID; int cudaDeviceID;
@ -67,13 +67,16 @@ struct heterogeneous_workload {
bool success; bool success;
}; };
__global__ void incKernel(int *data, int N) { __global__ void incKernel(int *data, int N)
{
int i = blockIdx.x * blockDim.x + threadIdx.x; int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < N) data[i]++; if (i < N)
data[i]++;
} }
CUT_THREADPROC launch(void *void_arg) { CUT_THREADPROC launch(void *void_arg)
{
heterogeneous_workload *workload = (heterogeneous_workload *)void_arg; heterogeneous_workload *workload = (heterogeneous_workload *)void_arg;
// Select GPU for this CPU thread // Select GPU for this CPU thread
@ -81,11 +84,8 @@ CUT_THREADPROC launch(void *void_arg) {
// Allocate Resources // Allocate Resources
checkCudaErrors(cudaStreamCreate(&workload->stream)); checkCudaErrors(cudaStreamCreate(&workload->stream));
checkCudaErrors( checkCudaErrors(cudaMalloc(&workload->d_data, N_elements_per_workload * sizeof(int)));
cudaMalloc(&workload->d_data, N_elements_per_workload * sizeof(int))); checkCudaErrors(cudaHostAlloc(&workload->h_data, N_elements_per_workload * sizeof(int), cudaHostAllocPortable));
checkCudaErrors(cudaHostAlloc(&workload->h_data,
N_elements_per_workload * sizeof(int),
cudaHostAllocPortable));
// CPU thread generates data // CPU thread generates data
for (int i = 0; i < N_elements_per_workload; ++i) { for (int i = 0; i < N_elements_per_workload; ++i) {
@ -97,25 +97,28 @@ CUT_THREADPROC launch(void *void_arg) {
dim3 block(512); dim3 block(512);
dim3 grid((N_elements_per_workload + block.x - 1) / block.x); dim3 grid((N_elements_per_workload + block.x - 1) / block.x);
checkCudaErrors(cudaMemcpyAsync(workload->d_data, workload->h_data, checkCudaErrors(cudaMemcpyAsync(workload->d_data,
workload->h_data,
N_elements_per_workload * sizeof(int), N_elements_per_workload * sizeof(int),
cudaMemcpyHostToDevice, workload->stream)); cudaMemcpyHostToDevice,
incKernel<<<grid, block, 0, workload->stream>>>(workload->d_data, workload->stream));
N_elements_per_workload); incKernel<<<grid, block, 0, workload->stream>>>(workload->d_data, N_elements_per_workload);
checkCudaErrors(cudaMemcpyAsync(workload->h_data, workload->d_data, checkCudaErrors(cudaMemcpyAsync(workload->h_data,
workload->d_data,
N_elements_per_workload * sizeof(int), N_elements_per_workload * sizeof(int),
cudaMemcpyDeviceToHost, workload->stream)); cudaMemcpyDeviceToHost,
workload->stream));
// New in CUDA 5.0: Add a CPU callback which is called once all currently // New in CUDA 5.0: Add a CPU callback which is called once all currently
// pending operations in the CUDA stream have finished // pending operations in the CUDA stream have finished
checkCudaErrors( checkCudaErrors(cudaStreamAddCallback(workload->stream, myStreamCallback, workload, 0));
cudaStreamAddCallback(workload->stream, myStreamCallback, workload, 0));
CUT_THREADEND; CUT_THREADEND;
// CPU thread end of life, GPU continues to process data... // CPU thread end of life, GPU continues to process data...
} }
CUT_THREADPROC postprocess(void *void_arg) { CUT_THREADPROC postprocess(void *void_arg)
{
heterogeneous_workload *workload = (heterogeneous_workload *)void_arg; heterogeneous_workload *workload = (heterogeneous_workload *)void_arg;
// ... GPU is done with processing, continue on new CPU thread... // ... GPU is done with processing, continue on new CPU thread...
@ -140,8 +143,8 @@ CUT_THREADPROC postprocess(void *void_arg) {
CUT_THREADEND; CUT_THREADEND;
} }
void CUDART_CB myStreamCallback(cudaStream_t stream, cudaError_t status, void CUDART_CB myStreamCallback(cudaStream_t stream, cudaError_t status, void *data)
void *data) { {
// Check status of GPU after stream operations are done // Check status of GPU after stream operations are done
checkCudaErrors(status); checkCudaErrors(status);
@ -149,7 +152,8 @@ void CUDART_CB myStreamCallback(cudaStream_t stream, cudaError_t status,
cutStartThread(postprocess, data); cutStartThread(postprocess, data);
} }
int main(int argc, char **argv) { int main(int argc, char **argv)
{
int N_gpus, max_gpus = 0; int N_gpus, max_gpus = 0;
int gpuInfo[32]; // assume a maximum of 32 GPUs in a system configuration int gpuInfo[32]; // assume a maximum of 32 GPUs in a system configuration
@ -168,10 +172,8 @@ int main(int argc, char **argv) {
cudaSetDevice(devid); cudaSetDevice(devid);
cudaGetDeviceProperties(&deviceProp, devid); cudaGetDeviceProperties(&deviceProp, devid);
SMversion = deviceProp.major << 4 + deviceProp.minor; SMversion = deviceProp.major << 4 + deviceProp.minor;
printf("GPU[%d] %s supports SM %d.%d", devid, deviceProp.name, printf("GPU[%d] %s supports SM %d.%d", devid, deviceProp.name, deviceProp.major, deviceProp.minor);
deviceProp.major, deviceProp.minor); printf(", %s GPU Callback Functions\n", (SMversion >= 0x11) ? "capable" : "NOT capable");
printf(", %s GPU Callback Functions\n",
(SMversion >= 0x11) ? "capable" : "NOT capable");
if (SMversion >= 0x11) { if (SMversion >= 0x11) {
gpuInfo[max_gpus++] = devid; gpuInfo[max_gpus++] = devid;
@ -181,8 +183,7 @@ int main(int argc, char **argv) {
printf("%d GPUs available to run Callback Functions\n", max_gpus); printf("%d GPUs available to run Callback Functions\n", max_gpus);
heterogeneous_workload *workloads; heterogeneous_workload *workloads;
workloads = (heterogeneous_workload *)malloc(N_workloads * workloads = (heterogeneous_workload *)malloc(N_workloads * sizeof(heterogeneous_workload));
sizeof(heterogeneous_workload));
; ;
thread_barrier = cutCreateBarrier(N_workloads); thread_barrier = cutCreateBarrier(N_workloads);

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaDeviceSynchronize, cudaGetErrorString
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -38,8 +38,8 @@
* *
*/ */
#include <stdio.h>
#include <cooperative_groups.h> #include <cooperative_groups.h>
#include <stdio.h>
using namespace cooperative_groups; using namespace cooperative_groups;
@ -49,7 +49,8 @@ using namespace cooperative_groups;
* calculates the sum of val across the group g. The workspace array, x, * calculates the sum of val across the group g. The workspace array, x,
* must be large enough to contain g.size() integers. * must be large enough to contain g.size() integers.
*/ */
__device__ int sumReduction(thread_group g, int *x, int val) { __device__ int sumReduction(thread_group g, int *x, int val)
{
// rank of this thread in the group // rank of this thread in the group
int lane = g.thread_rank(); int lane = g.thread_rank();
@ -85,7 +86,8 @@ __device__ int sumReduction(thread_group g, int *x, int val) {
* *
* Creates cooperative groups and performs reductions * Creates cooperative groups and performs reductions
*/ */
__global__ void cgkernel() { __global__ void cgkernel()
{
// threadBlockGroup includes all threads in the block // threadBlockGroup includes all threads in the block
thread_block threadBlockGroup = this_thread_block(); thread_block threadBlockGroup = this_thread_block();
int threadBlockGroupSize = threadBlockGroup.size(); int threadBlockGroupSize = threadBlockGroup.size();
@ -107,24 +109,22 @@ __global__ void cgkernel() {
// master thread in group prints out result // master thread in group prints out result
if (threadBlockGroup.thread_rank() == 0) { if (threadBlockGroup.thread_rank() == 0) {
printf( printf(" Sum of all ranks 0..%d in threadBlockGroup is %d (expected %d)\n\n",
" Sum of all ranks 0..%d in threadBlockGroup is %d (expected %d)\n\n", (int)threadBlockGroup.size() - 1,
(int)threadBlockGroup.size() - 1, output, expectedOutput); output,
expectedOutput);
printf(" Now creating %d groups, each of size 16 threads:\n\n", printf(" Now creating %d groups, each of size 16 threads:\n\n", (int)threadBlockGroup.size() / 16);
(int)threadBlockGroup.size() / 16);
} }
threadBlockGroup.sync(); threadBlockGroup.sync();
// each tiledPartition16 group includes 16 threads // each tiledPartition16 group includes 16 threads
thread_block_tile<16> tiledPartition16 = thread_block_tile<16> tiledPartition16 = tiled_partition<16>(threadBlockGroup);
tiled_partition<16>(threadBlockGroup);
// This offset allows each group to have its own unique area in the workspace // This offset allows each group to have its own unique area in the workspace
// array // array
int workspaceOffset = int workspaceOffset = threadBlockGroup.thread_rank() - tiledPartition16.thread_rank();
threadBlockGroup.thread_rank() - tiledPartition16.thread_rank();
// input to reduction, for each thread, is its' rank in the group // input to reduction, for each thread, is its' rank in the group
input = tiledPartition16.thread_rank(); input = tiledPartition16.thread_rank();
@ -138,10 +138,10 @@ __global__ void cgkernel() {
// each master thread prints out result // each master thread prints out result
if (tiledPartition16.thread_rank() == 0) if (tiledPartition16.thread_rank() == 0)
printf( printf(" Sum of all ranks 0..15 in this tiledPartition16 group is %d "
" Sum of all ranks 0..15 in this tiledPartition16 group is %d "
"(expected %d)\n", "(expected %d)\n",
output, expectedOutput); output,
expectedOutput);
return; return;
} }
@ -149,7 +149,8 @@ __global__ void cgkernel() {
/** /**
* Host main routine * Host main routine
*/ */
int main() { int main()
{
// Error code to check return values for CUDA calls // Error code to check return values for CUDA calls
cudaError_t err; cudaError_t err;
@ -166,8 +167,7 @@ int main() {
err = cudaDeviceSynchronize(); err = cudaDeviceSynchronize();
if (err != cudaSuccess) { if (err != cudaSuccess) {
fprintf(stderr, "Failed to launch kernel (error code %s)!\n", fprintf(stderr, "Failed to launch kernel (error code %s)!\n", cudaGetErrorString(err));
cudaGetErrorString(err));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries

View File

@ -27,6 +27,6 @@ cudaMemcpy, cudaCreateChannelDesc, cudaFreeArray, cudaFree, cudaPitchedPtr, cuda
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -26,27 +26,27 @@
*/ */
/* /*
* This sample demonstrates how to use texture fetches from layered 2D textures * This sample demonstrates how to use texture fetches from layered 2D textures
* in CUDA C * in CUDA C
* *
* This sample first generates a 3D input data array for the layered texture * This sample first generates a 3D input data array for the layered texture
* and the expected output. Then it starts CUDA C kernels, one for each layer, * and the expected output. Then it starts CUDA C kernels, one for each layer,
* which fetch their layer's texture data (using normalized texture coordinates) * which fetch their layer's texture data (using normalized texture coordinates)
* transform it to the expected output, and write it to a 3D output data array. * transform it to the expected output, and write it to a 3D output data array.
*/ */
// includes, system // includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes CUDA // includes CUDA
#include <cuda_runtime.h> #include <cuda_runtime.h>
// helper functions and utilities to work with CUDA // helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h> #include <helper_cuda.h>
#include <helper_functions.h>
static const char *sSDKname = "simpleCubemapTexture"; static const char *sSDKname = "simpleCubemapTexture";
@ -56,8 +56,8 @@ static const char *sSDKname = "simpleCubemapTexture";
//! Transform a cubemap face of a linear buffe using cubemap texture lookups //! Transform a cubemap face of a linear buffe using cubemap texture lookups
//! @param g_odata output data in global memory //! @param g_odata output data in global memory
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__global__ void transformKernel(float *g_odata, int width, __global__ void transformKernel(float *g_odata, int width, cudaTextureObject_t tex)
cudaTextureObject_t tex) { {
// calculate this thread's data point // calculate this thread's data point
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x; unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y; unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
@ -110,15 +110,15 @@ __global__ void transformKernel(float *g_odata, int width,
} }
// read from texture, do expected transformation and write to global memory // read from texture, do expected transformation and write to global memory
g_odata[face * width * width + y * width + x] = g_odata[face * width * width + y * width + x] = -texCubemap<float>(tex, cx, cy, cz);
-texCubemap<float>(tex, cx, cy, cz);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Program main // Program main
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) { int main(int argc, char **argv)
{
// use command-line specified CUDA device, otherwise use device with highest // use command-line specified CUDA device, otherwise use device with highest
// Gflops/s // Gflops/s
int devID = findCudaDevice(argc, (const char **)argv); int devID = findCudaDevice(argc, (const char **)argv);
@ -129,13 +129,11 @@ int main(int argc, char **argv) {
cudaDeviceProp deviceProps; cudaDeviceProp deviceProps;
checkCudaErrors(cudaGetDeviceProperties(&deviceProps, devID)); checkCudaErrors(cudaGetDeviceProperties(&deviceProps, devID));
printf("CUDA device [%s] has %d Multi-Processors ", deviceProps.name, printf("CUDA device [%s] has %d Multi-Processors ", deviceProps.name, deviceProps.multiProcessorCount);
deviceProps.multiProcessorCount);
printf("SM %d.%d\n", deviceProps.major, deviceProps.minor); printf("SM %d.%d\n", deviceProps.major, deviceProps.minor);
if (deviceProps.major < 2) { if (deviceProps.major < 2) {
printf( printf("%s requires SM 2.0 or higher for support of Texture Arrays. Test "
"%s requires SM 2.0 or higher for support of Texture Arrays. Test "
"will exit... \n", "will exit... \n",
sSDKname); sSDKname);
@ -157,8 +155,7 @@ int main(int argc, char **argv) {
for (unsigned int layer = 0; layer < num_layers; layer++) { for (unsigned int layer = 0; layer < num_layers; layer++) {
for (int i = 0; i < (int)(cubemap_size); i++) { for (int i = 0; i < (int)(cubemap_size); i++) {
h_data_ref[layer * cubemap_size + i] = h_data_ref[layer * cubemap_size + i] = -h_data[layer * cubemap_size + i] + layer;
-h_data[layer * cubemap_size + i] + layer;
} }
} }
@ -167,19 +164,16 @@ int main(int argc, char **argv) {
checkCudaErrors(cudaMalloc((void **)&d_data, size)); checkCudaErrors(cudaMalloc((void **)&d_data, size));
// allocate array and copy image data // allocate array and copy image data
cudaChannelFormatDesc channelDesc = cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
cudaArray *cu_3darray; cudaArray *cu_3darray;
// checkCudaErrors(cudaMalloc3DArray( &cu_3darray, &channelDesc, // checkCudaErrors(cudaMalloc3DArray( &cu_3darray, &channelDesc,
// make_cudaExtent(width, height, num_layers), cudaArrayLayered )); // make_cudaExtent(width, height, num_layers), cudaArrayLayered ));
checkCudaErrors(cudaMalloc3DArray(&cu_3darray, &channelDesc, checkCudaErrors(
make_cudaExtent(width, width, num_faces), cudaMalloc3DArray(&cu_3darray, &channelDesc, make_cudaExtent(width, width, num_faces), cudaArrayCubemap));
cudaArrayCubemap));
cudaMemcpy3DParms myparms = {0}; cudaMemcpy3DParms myparms = {0};
myparms.srcPos = make_cudaPos(0, 0, 0); myparms.srcPos = make_cudaPos(0, 0, 0);
myparms.dstPos = make_cudaPos(0, 0, 0); myparms.dstPos = make_cudaPos(0, 0, 0);
myparms.srcPtr = myparms.srcPtr = make_cudaPitchedPtr(h_data, width * sizeof(float), width, width);
make_cudaPitchedPtr(h_data, width * sizeof(float), width, width);
myparms.dstArray = cu_3darray; myparms.dstArray = cu_3darray;
myparms.extent = make_cudaExtent(width, width, num_faces); myparms.extent = make_cudaExtent(width, width, num_faces);
myparms.kind = cudaMemcpyHostToDevice; myparms.kind = cudaMemcpyHostToDevice;
@ -207,10 +201,12 @@ int main(int argc, char **argv) {
dim3 dimBlock(8, 8, 1); dim3 dimBlock(8, 8, 1);
dim3 dimGrid(width / dimBlock.x, width / dimBlock.y, 1); dim3 dimGrid(width / dimBlock.x, width / dimBlock.y, 1);
printf( printf("Covering Cubemap data array of %d~3 x %d: Grid size is %d x %d, each "
"Covering Cubemap data array of %d~3 x %d: Grid size is %d x %d, each "
"block has 8 x 8 threads\n", "block has 8 x 8 threads\n",
width, num_layers, dimGrid.x, dimGrid.y); width,
num_layers,
dimGrid.x,
dimGrid.y);
transformKernel<<<dimGrid, dimBlock>>>(d_data, width, transformKernel<<<dimGrid, dimBlock>>>(d_data, width,
tex); // warmup (for better timing) tex); // warmup (for better timing)
@ -233,8 +229,7 @@ int main(int argc, char **argv) {
checkCudaErrors(cudaDeviceSynchronize()); checkCudaErrors(cudaDeviceSynchronize());
sdkStopTimer(&timer); sdkStopTimer(&timer);
printf("Processing time: %.3f msec\n", sdkGetTimerValue(&timer)); printf("Processing time: %.3f msec\n", sdkGetTimerValue(&timer));
printf("%.2f Mtexlookups/sec\n", printf("%.2f Mtexlookups/sec\n", (cubemap_size / (sdkGetTimerValue(&timer) / 1000.0f) / 1e6));
(cubemap_size / (sdkGetTimerValue(&timer) / 1000.0f) / 1e6));
sdkDeleteTimer(&timer); sdkDeleteTimer(&timer);
// allocate mem for the result on host side // allocate mem for the result on host side
@ -245,14 +240,13 @@ int main(int argc, char **argv) {
// write regression file if necessary // write regression file if necessary
if (checkCmdLineFlag(argc, (const char **)argv, "regression")) { if (checkCmdLineFlag(argc, (const char **)argv, "regression")) {
// write file for regression test // write file for regression test
sdkWriteFile<float>("./data/regression.dat", h_odata, width * width, 0.0f, sdkWriteFile<float>("./data/regression.dat", h_odata, width * width, 0.0f, false);
false); }
} else { else {
printf("Comparing kernel output to expected data\n"); printf("Comparing kernel output to expected data\n");
#define MIN_EPSILON_ERROR 5e-3f #define MIN_EPSILON_ERROR 5e-3f
bResult = bResult = compareData(h_odata, h_data_ref, cubemap_size, MIN_EPSILON_ERROR, 0.0f);
compareData(h_odata, h_data_ref, cubemap_size, MIN_EPSILON_ERROR, 0.0f);
} }
// cleanup memory // cleanup memory

View File

@ -10,8 +10,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120) set(CMAKE_CUDA_ARCHITECTURES 50 52 60 61 70 72 75 80 86 87 89 90 100 101 120)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(ENABLE_CUDA_DEBUG)
# set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (expensive) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
else()
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
endif() endif()
# Include directories and libraries # Include directories and libraries
@ -40,6 +42,12 @@ target_link_libraries(simpleDrvRuntime PUBLIC
set(CUDA_FATBIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/vectorAdd_kernel64.fatbin") set(CUDA_FATBIN_FILE "${CMAKE_CURRENT_BINARY_DIR}/vectorAdd_kernel64.fatbin")
set(CUDA_KERNEL_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/vectorAdd_kernel.cu") set(CUDA_KERNEL_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/vectorAdd_kernel.cu")
# Construct GENCODE_FLAGS explicitly from CUDA architectures
set(GENCODE_FLAGS "")
foreach(arch ${CMAKE_CUDA_ARCHITECTURES})
list(APPEND GENCODE_FLAGS "-gencode=arch=compute_${arch},code=sm_${arch}")
endforeach()
add_custom_command( add_custom_command(
OUTPUT ${CUDA_FATBIN_FILE} OUTPUT ${CUDA_FATBIN_FILE}
COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE} COMMAND ${CMAKE_CUDA_COMPILER} ${INCLUDES} ${ALL_CCFLAGS} -Wno-deprecated-gpu-targets ${GENCODE_FLAGS} -o ${CUDA_FATBIN_FILE} -fatbin ${CUDA_KERNEL_SOURCE}

View File

@ -30,6 +30,6 @@ cudaStreamCreateWithFlags, cudaFree, cudaMallocHost, cudaFreeHost, cudaStreamSyn
## Prerequisites ## Prerequisites
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform. Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
## References (for more details) ## References (for more details)

View File

@ -33,12 +33,12 @@
*/ */
// Includes // Includes
#include <cstring>
#include <cuda.h> #include <cuda.h>
#include <cuda_runtime.h> #include <cuda_runtime.h>
#include <iostream>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <cstring>
#include <iostream>
// includes, project // includes, project
#include <helper_cuda.h> #include <helper_cuda.h>
@ -66,11 +66,10 @@ int CleanupNoFailure(CUcontext &cuContext);
void RandomInit(float *, int); void RandomInit(float *, int);
bool findModulePath(const char *, string &, char **, ostringstream &); bool findModulePath(const char *, string &, char **, ostringstream &);
static void check(CUresult result, char const *const func, static void check(CUresult result, char const *const func, const char *const file, int const line)
const char *const file, int const line) { {
if (result) { if (result) {
fprintf(stderr, "CUDA error at %s:%d code=%d \"%s\" \n", file, line, fprintf(stderr, "CUDA error at %s:%d code=%d \"%s\" \n", file, line, static_cast<unsigned int>(result), func);
static_cast<unsigned int>(result), func);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -78,7 +77,8 @@ static void check(CUresult result, char const *const func,
#define checkCudaDrvErrors(val) check((val), #val, __FILE__, __LINE__) #define checkCudaDrvErrors(val) check((val), #val, __FILE__, __LINE__)
// Host code // Host code
int main(int argc, char **argv) { int main(int argc, char **argv)
{
printf("simpleDrvRuntime..\n"); printf("simpleDrvRuntime..\n");
int N = 50000, devID = 0; int N = 50000, devID = 0;
size_t size = N * sizeof(float); size_t size = N * sizeof(float);
@ -100,7 +100,8 @@ int main(int argc, char **argv) {
if (!findModulePath(FATBIN_FILE, module_path, argv, fatbin)) { if (!findModulePath(FATBIN_FILE, module_path, argv, fatbin)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} else { }
else {
printf("> initCUDA loading module: <%s>\n", module_path.c_str()); printf("> initCUDA loading module: <%s>\n", module_path.c_str());
} }
@ -113,8 +114,7 @@ int main(int argc, char **argv) {
checkCudaDrvErrors(cuModuleLoadData(&cuModule, fatbin.str().c_str())); checkCudaDrvErrors(cuModuleLoadData(&cuModule, fatbin.str().c_str()));
// Get function handle from module // Get function handle from module
checkCudaDrvErrors( checkCudaDrvErrors(cuModuleGetFunction(&vecAdd_kernel, cuModule, "VecAdd_kernel"));
cuModuleGetFunction(&vecAdd_kernel, cuModule, "VecAdd_kernel"));
// Allocate input vectors h_A and h_B in host memory // Allocate input vectors h_A and h_B in host memory
checkCudaErrors(cudaMallocHost(&h_A, size)); checkCudaErrors(cudaMallocHost(&h_A, size));
@ -133,10 +133,8 @@ int main(int argc, char **argv) {
cudaStream_t stream; cudaStream_t stream;
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
// Copy vectors from host memory to device memory // Copy vectors from host memory to device memory
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(d_A, h_A, size, cudaMemcpyHostToDevice, stream));
cudaMemcpyAsync(d_A, h_A, size, cudaMemcpyHostToDevice, stream)); checkCudaErrors(cudaMemcpyAsync(d_B, h_B, size, cudaMemcpyHostToDevice, stream));
checkCudaErrors(
cudaMemcpyAsync(d_B, h_B, size, cudaMemcpyHostToDevice, stream));
int threadsPerBlock = 256; int threadsPerBlock = 256;
int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;
@ -144,14 +142,12 @@ int main(int argc, char **argv) {
void *args[] = {&d_A, &d_B, &d_C, &N}; void *args[] = {&d_A, &d_B, &d_C, &N};
// Launch the CUDA kernel // Launch the CUDA kernel
checkCudaDrvErrors(cuLaunchKernel(vecAdd_kernel, blocksPerGrid, 1, 1, checkCudaDrvErrors(
threadsPerBlock, 1, 1, 0, stream, args, cuLaunchKernel(vecAdd_kernel, blocksPerGrid, 1, 1, threadsPerBlock, 1, 1, 0, stream, args, NULL));
NULL));
// Copy result from device memory to host memory // Copy result from device memory to host memory
// h_C contains the result in host memory // h_C contains the result in host memory
checkCudaErrors( checkCudaErrors(cudaMemcpyAsync(h_C, d_C, size, cudaMemcpyDeviceToHost, stream));
cudaMemcpyAsync(h_C, d_C, size, cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream)); checkCudaErrors(cudaStreamSynchronize(stream));
// Verify result // Verify result
int i; int i;
@ -171,7 +167,8 @@ int main(int argc, char **argv) {
exit((i == N) ? EXIT_SUCCESS : EXIT_FAILURE); exit((i == N) ? EXIT_SUCCESS : EXIT_FAILURE);
} }
int CleanupNoFailure(CUcontext &cuContext) { int CleanupNoFailure(CUcontext &cuContext)
{
// Free device memory // Free device memory
checkCudaErrors(cudaFree(d_A)); checkCudaErrors(cudaFree(d_A));
checkCudaErrors(cudaFree(d_B)); checkCudaErrors(cudaFree(d_B));
@ -195,19 +192,21 @@ int CleanupNoFailure(CUcontext &cuContext) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// Allocates an array with random float entries. // Allocates an array with random float entries.
void RandomInit(float *data, int n) { void RandomInit(float *data, int n)
{
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
data[i] = rand() / (float)RAND_MAX; data[i] = rand() / (float)RAND_MAX;
} }
} }
bool inline findModulePath(const char *module_file, string &module_path, bool inline findModulePath(const char *module_file, string &module_path, char **argv, ostringstream &ostrm)
char **argv, ostringstream &ostrm) { {
char *actual_path = sdkFindFilePath(module_file, argv[0]); char *actual_path = sdkFindFilePath(module_file, argv[0]);
if (actual_path) { if (actual_path) {
module_path = actual_path; module_path = actual_path;
} else { }
else {
printf("> findModulePath file not found: <%s> \n", module_file); printf("> findModulePath file not found: <%s> \n", module_file);
return false; return false;
} }
@ -215,7 +214,8 @@ bool inline findModulePath(const char *module_file, string &module_path,
if (module_path.empty()) { if (module_path.empty()) {
printf("> findModulePath could not find file: <%s> \n", module_file); printf("> findModulePath could not find file: <%s> \n", module_file);
return false; return false;
} else { }
else {
printf("> findModulePath found file at <%s>\n", module_path.c_str()); printf("> findModulePath found file at <%s>\n", module_path.c_str());
if (module_path.rfind("fatbin") != string::npos) { if (module_path.rfind("fatbin") != string::npos) {
ifstream fileIn(module_path.c_str(), ios::binary); ifstream fileIn(module_path.c_str(), ios::binary);

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