mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-23 21:28:17 +08:00
Add and update samples for cuda 11.0 support
This commit is contained in:
@@ -72,9 +72,9 @@ endif
|
||||
# architecture
|
||||
HOST_ARCH := $(shell uname -m)
|
||||
TARGET_ARCH ?= $(HOST_ARCH)
|
||||
ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l))
|
||||
ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 sbsa ppc64le armv7l))
|
||||
ifneq ($(TARGET_ARCH),$(HOST_ARCH))
|
||||
ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le))
|
||||
ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 sbsa ppc64le))
|
||||
TARGET_SIZE := 64
|
||||
else ifneq (,$(filter $(TARGET_ARCH),armv7l))
|
||||
TARGET_SIZE := 32
|
||||
@@ -85,8 +85,17 @@ ifneq (,$(filter $(TARGET_ARCH),x86_64 aarch64 ppc64le armv7l))
|
||||
else
|
||||
$(error ERROR - unsupported value $(TARGET_ARCH) for TARGET_ARCH!)
|
||||
endif
|
||||
|
||||
# sbsa and aarch64 systems look similar. Need to differentiate them at host level for now.
|
||||
ifeq ($(HOST_ARCH),aarch64)
|
||||
ifeq ($(CUDA_PATH)/targets/sbsa-linux,$(shell ls -1d $(CUDA_PATH)/targets/sbsa-linux))
|
||||
HOST_ARCH := sbsa
|
||||
TARGET_ARCH := sbsa
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_ARCH),$(HOST_ARCH))
|
||||
ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-ppc64le))
|
||||
ifeq (,$(filter $(HOST_ARCH)-$(TARGET_ARCH),aarch64-armv7l x86_64-armv7l x86_64-aarch64 x86_64-sbsa x86_64-ppc64le))
|
||||
$(error ERROR - cross compiling from $(HOST_ARCH) to $(TARGET_ARCH) is not supported!)
|
||||
endif
|
||||
endif
|
||||
@@ -141,6 +150,8 @@ else ifneq ($(TARGET_ARCH),$(HOST_ARCH))
|
||||
else ifeq ($(TARGET_OS), android)
|
||||
HOST_COMPILER ?= aarch64-linux-android-clang++
|
||||
endif
|
||||
else ifeq ($(TARGET_ARCH),sbsa)
|
||||
HOST_COMPILER ?= aarch64-linux-gnu-g++
|
||||
else ifeq ($(TARGET_ARCH),ppc64le)
|
||||
HOST_COMPILER ?= powerpc64le-linux-gnu-g++
|
||||
endif
|
||||
@@ -185,19 +196,27 @@ ifneq ($(TARGET_ARCH),$(HOST_ARCH))
|
||||
CCFLAGS += --sysroot=$(TARGET_FS)
|
||||
endif
|
||||
LDFLAGS += --sysroot=$(TARGET_FS)
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L $(TARGET_FS)/lib
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L $(TARGET_FS)/usr/lib/aarch64-linux-gnu
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/lib -L$(TARGET_FS)/lib
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/lib/aarch64-linux-gnu -L$(TARGET_FS)/lib/aarch64-linux-gnu
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib -L$(TARGET_FS)/usr/lib
|
||||
LDFLAGS += -rpath-link=$(TARGET_FS)/usr/lib/aarch64-linux-gnu -L$(TARGET_FS)/usr/lib/aarch64-linux-gnu
|
||||
LDFLAGS += --unresolved-symbols=ignore-in-shared-libs
|
||||
CCFLAGS += -isystem=$(TARGET_FS)/usr/include
|
||||
CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu
|
||||
CCFLAGS += -isystem=$(TARGET_FS)/usr/include -I$(TARGET_FS)/usr/include
|
||||
CCFLAGS += -isystem=$(TARGET_FS)/usr/include/aarch64-linux-gnu -I$(TARGET_FS)/usr/include/aarch64-linux-gnu
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-qnx)
|
||||
CCFLAGS += -DWIN_INTERFACE_CUSTOM -I/usr/include/aarch64-qnx-gnu
|
||||
LDFLAGS += -lsocket
|
||||
LDFLAGS += -rpath=/usr/lib/aarch64-qnx-gnu -L/usr/lib/aarch64-qnx-gnu
|
||||
ifneq ($(TARGET_FS),)
|
||||
LDFLAGS += -rpath=$(TARGET_FS)/usr/lib -L $(TARGET_FS)/usr/lib
|
||||
LDFLAGS += -rpath=$(TARGET_FS)/usr/libnvidia -L $(TARGET_FS)/usr/libnvidia
|
||||
endif
|
||||
ifdef TARGET_OVERRIDE # cuda toolkit targets override
|
||||
NVCCFLAGS += -target-dir $(TARGET_OVERRIDE)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_OS),qnx)
|
||||
CCFLAGS += -DWIN_INTERFACE_CUSTOM
|
||||
LDFLAGS += -lsocket
|
||||
endif
|
||||
|
||||
# Install directory of different arch
|
||||
@@ -206,6 +225,8 @@ ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-linux)
|
||||
CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-gnueabihf/
|
||||
else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-linux)
|
||||
CUDA_INSTALL_TARGET_DIR = targets/aarch64-linux/
|
||||
else ifeq ($(TARGET_ARCH)-$(TARGET_OS),sbsa-linux)
|
||||
CUDA_INSTALL_TARGET_DIR = targets/sbsa-linux/
|
||||
else ifeq ($(TARGET_ARCH)-$(TARGET_OS),armv7l-android)
|
||||
CUDA_INSTALL_TARGET_DIR = targets/armv7-linux-androideabi/
|
||||
else ifeq ($(TARGET_ARCH)-$(TARGET_OS),aarch64-android)
|
||||
@@ -252,6 +273,12 @@ ifeq ($(TARGET_ARCH),aarch64)
|
||||
SAMPLE_ENABLED := 0
|
||||
endif
|
||||
|
||||
# This sample is not supported on sbsa
|
||||
ifeq ($(TARGET_ARCH),sbsa)
|
||||
$(info >>> WARNING - conjugateGradientMultiDeviceCG is not supported on sbsa - waiving sample <<<)
|
||||
SAMPLE_ENABLED := 0
|
||||
endif
|
||||
|
||||
ALL_LDFLAGS :=
|
||||
ALL_LDFLAGS += $(ALL_CCFLAGS)
|
||||
ALL_LDFLAGS += $(addprefix -Xlinker ,$(LDFLAGS))
|
||||
@@ -263,11 +290,38 @@ LIBRARIES :=
|
||||
|
||||
################################################################################
|
||||
|
||||
#Detect if installed version of GCC supports required C++11
|
||||
ifeq ($(TARGET_OS),linux)
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
GCCVERSIONSTRING := $(shell expr `$(HOST_COMPILER) -dumpversion`)
|
||||
#Create version number without "."
|
||||
GCCVERSION := $(shell expr `echo $(GCCVERSIONSTRING)` | cut -f1 -d.)
|
||||
GCCVERSION += $(shell expr `echo $(GCCVERSIONSTRING)` | cut -f2 -d.)
|
||||
GCCVERSION += $(shell expr `echo $(GCCVERSIONSTRING)` | cut -f3 -d.)
|
||||
# Make sure the version number has at least 3 decimals
|
||||
GCCVERSION += 00
|
||||
# Remove spaces from the version number
|
||||
GCCVERSION := $(subst $(space),$(empty),$(GCCVERSION))
|
||||
# Crop the version number to 3 decimals.
|
||||
GCCVERSION := $(shell expr `echo $(GCCVERSION)` | cut -b1-3)
|
||||
#$(warning $(GCCVERSION))
|
||||
|
||||
IS_MIN_VERSION := $(shell expr `echo $(GCCVERSION)` \>= 470)
|
||||
|
||||
ifeq ($(IS_MIN_VERSION), 1)
|
||||
$(info >>> GCC Version is greater or equal to 4.7.0 <<<)
|
||||
else
|
||||
$(info >>> Waiving build. Minimum GCC version required is 4.7.0<<<)
|
||||
SAMPLE_ENABLED := 0
|
||||
endif
|
||||
endif
|
||||
|
||||
# Gencode arguments
|
||||
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),armv7l aarch64))
|
||||
SMS ?= 60 61 70 72 75
|
||||
SMS ?= 60 61 70 72 75 80
|
||||
else
|
||||
SMS ?= 60 61 70 75
|
||||
SMS ?= 60 61 70 75 80
|
||||
endif
|
||||
|
||||
ifeq ($(SMS),)
|
||||
@@ -286,7 +340,7 @@ GENCODE_FLAGS += -gencode arch=compute_$(HIGHEST_SM),code=compute_$(HIGHEST_SM)
|
||||
endif
|
||||
endif
|
||||
|
||||
ALL_CCFLAGS += -dc -maxrregcount=64
|
||||
ALL_CCFLAGS += -dc -maxrregcount=64 --std=c++11
|
||||
|
||||
LIBRARIES += -lcudadevrt
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<cflags>
|
||||
<flag>-dc</flag>
|
||||
<flag>-maxrregcount=64</flag>
|
||||
<flag>--std=c++11</flag>
|
||||
</cflags>
|
||||
<cuda_api_list>
|
||||
<toolkit>cudaMemAdvise</toolkit>
|
||||
@@ -31,6 +32,7 @@
|
||||
<keyword>Sparse Matrix</keyword>
|
||||
<keyword>Unified Memory</keyword>
|
||||
<keyword>Multi-GPU</keyword>
|
||||
<keyword>CPP11</keyword>
|
||||
</keywords>
|
||||
<libraries>
|
||||
<library>cudadevrt</library>
|
||||
@@ -52,6 +54,7 @@
|
||||
<sm-arch>sm70</sm-arch>
|
||||
<sm-arch>sm72</sm-arch>
|
||||
<sm-arch>sm75</sm-arch>
|
||||
<sm-arch>sm80</sm-arch>
|
||||
<supported_envs>
|
||||
<env>
|
||||
<arch>x86_64</arch>
|
||||
|
||||
@@ -10,7 +10,7 @@ Unified Memory, Linear Algebra, Cooperative Groups, MultiDevice Cooperative Grou
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus)
|
||||
[SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
@@ -30,7 +30,7 @@ cudaMemAdvise, cudaMemPrefetchAsync, cudaLaunchCooperativeKernelMultiDevice, cud
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit 10.2](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Download and install the [CUDA Toolkit 11.0](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## Build and Run
|
||||
|
||||
@@ -36,8 +36,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
@@ -46,6 +48,7 @@
|
||||
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
|
||||
|
||||
#include <cooperative_groups.h>
|
||||
#include <cooperative_groups/reduce.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
|
||||
@@ -201,37 +204,31 @@ __device__ void gpuSaxpy(float *x, float *y, float a, int size,
|
||||
__device__ void gpuDotProduct(float *vecA, float *vecB, int size,
|
||||
const cg::thread_block &cta,
|
||||
const cg::multi_grid_group &multi_grid) {
|
||||
__shared__ double tmp[THREADS_PER_BLOCK];
|
||||
extern __shared__ double tmp[];
|
||||
|
||||
double temp_sum = 0.0;
|
||||
|
||||
for (int i = multi_grid.thread_rank(); i < size; i += multi_grid.size()) {
|
||||
temp_sum += static_cast<double>(vecA[i] * vecB[i]);
|
||||
}
|
||||
tmp[cta.thread_rank()] = temp_sum;
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
|
||||
|
||||
double beta = temp_sum;
|
||||
double temp;
|
||||
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
|
||||
|
||||
for (int i = tile32.size() / 2; i > 0; i >>= 1) {
|
||||
if (tile32.thread_rank() < i) {
|
||||
temp = tmp[cta.thread_rank() + i];
|
||||
beta += temp;
|
||||
tmp[cta.thread_rank()] = beta;
|
||||
}
|
||||
cg::sync(tile32);
|
||||
if (tile32.thread_rank() == 0) {
|
||||
tmp[tile32.meta_group_rank()] = temp_sum;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (cta.thread_rank() == 0) {
|
||||
beta = 0.0;
|
||||
for (int i = 0; i < cta.size(); i += tile32.size()) {
|
||||
beta += tmp[i];
|
||||
if (tile32.meta_group_rank() == 0) {
|
||||
temp_sum = tile32.thread_rank() < tile32.meta_group_size() ? tmp[tile32.thread_rank()] : 0.0;
|
||||
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
|
||||
|
||||
if (tile32.thread_rank() == 0) {
|
||||
atomicAdd(&grid_dot_result, temp_sum);
|
||||
}
|
||||
atomicAdd(&grid_dot_result, beta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,24 +239,13 @@ __device__ void gpuCopyVector(float *srcA, float *destB, int size,
|
||||
}
|
||||
}
|
||||
|
||||
__device__ void gpuScaleVector(float *vec, float alpha, int size,
|
||||
const cg::multi_grid_group &multi_grid) {
|
||||
__device__ void gpuScaleVectorAndSaxpy(float *x, float *y, float a, float scale, int size,
|
||||
const cg::multi_grid_group &multi_grid) {
|
||||
for (int i = multi_grid.thread_rank(); i < size; i += multi_grid.size()) {
|
||||
vec[i] = alpha * vec[i];
|
||||
y[i] = a * x[i] + scale * y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__device__ void setDotResultToZero(double *dot_result) {
|
||||
unsigned long long int *address_as_ull = (unsigned long long int *)dot_result;
|
||||
unsigned long long int old = *address_as_ull, assumed;
|
||||
|
||||
do {
|
||||
assumed = old;
|
||||
old = atomicCAS_system(address_as_ull, assumed, 0);
|
||||
|
||||
} while (assumed != old);
|
||||
}
|
||||
|
||||
extern "C" __global__ void multiGpuConjugateGradient(
|
||||
int *I, int *J, float *val, float *x, float *Ax, float *p, float *r,
|
||||
double *dot_result, int nnz, int N, float tol) {
|
||||
@@ -304,10 +290,7 @@ extern "C" __global__ void multiGpuConjugateGradient(
|
||||
while (r1 > tol * tol && k <= max_iter) {
|
||||
if (k > 1) {
|
||||
b = r1 / r0;
|
||||
|
||||
gpuScaleVector(p, b, N, multi_grid);
|
||||
cg::sync(grid);
|
||||
gpuSaxpy(r, p, alpha, N, multi_grid);
|
||||
gpuScaleVectorAndSaxpy(r, p, alpha, b, N, multi_grid);
|
||||
} else {
|
||||
gpuCopyVector(r, p, N, multi_grid);
|
||||
}
|
||||
@@ -317,7 +300,7 @@ extern "C" __global__ void multiGpuConjugateGradient(
|
||||
gpuSpMV(I, J, val, nnz, N, alpha, p, Ax, cta, multi_grid);
|
||||
|
||||
if (multi_grid.thread_rank() == 0) {
|
||||
setDotResultToZero(dot_result);
|
||||
*dot_result = 0.0;
|
||||
}
|
||||
cg::sync(multi_grid);
|
||||
|
||||
@@ -343,7 +326,7 @@ extern "C" __global__ void multiGpuConjugateGradient(
|
||||
|
||||
cg::sync(multi_grid);
|
||||
if (multi_grid.thread_rank() == 0) {
|
||||
setDotResultToZero(dot_result);
|
||||
*dot_result = 0.0;
|
||||
}
|
||||
|
||||
cg::sync(multi_grid);
|
||||
@@ -363,68 +346,31 @@ extern "C" __global__ void multiGpuConjugateGradient(
|
||||
}
|
||||
}
|
||||
|
||||
void getIdenticalGPUs(int num_of_gpus, std::set<int> &identicalGPUs) {
|
||||
int *major_minor =
|
||||
reinterpret_cast<int *>(malloc(sizeof(int) * num_of_gpus * 2));
|
||||
int foundIdenticalGPUs = 0;
|
||||
// Map of device version to device number
|
||||
std::multimap<std::pair<int, int>, int> getIdenticalGPUs() {
|
||||
int numGpus = 0;
|
||||
checkCudaErrors(cudaGetDeviceCount(&numGpus));
|
||||
|
||||
for (int i = 0; i < num_of_gpus; i++) {
|
||||
std::multimap<std::pair<int, int>, int> identicalGpus;
|
||||
|
||||
for (int i = 0; i < numGpus; i++) {
|
||||
cudaDeviceProp deviceProp;
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
|
||||
major_minor[i * 2] = deviceProp.major;
|
||||
major_minor[i * 2 + 1] = deviceProp.minor;
|
||||
|
||||
// Filter unsupported devices
|
||||
if (deviceProp.cooperativeMultiDeviceLaunch &&
|
||||
deviceProp.concurrentManagedAccess) {
|
||||
identicalGpus.emplace(std::make_pair(deviceProp.major, deviceProp.minor), i);
|
||||
}
|
||||
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n", i,
|
||||
deviceProp.name, deviceProp.major, deviceProp.minor);
|
||||
deviceProp.name, deviceProp.major, deviceProp.minor);
|
||||
}
|
||||
|
||||
int maxMajorMinor[2] = {0, 0};
|
||||
|
||||
for (int i = 0; i < num_of_gpus; i++) {
|
||||
for (int j = i + 1; j < num_of_gpus; j++) {
|
||||
if ((major_minor[i * 2] == major_minor[j * 2]) &&
|
||||
(major_minor[i * 2 + 1] == major_minor[j * 2 + 1])) {
|
||||
identicalGPUs.insert(i);
|
||||
identicalGPUs.insert(j);
|
||||
foundIdenticalGPUs = 1;
|
||||
if (maxMajorMinor[0] < major_minor[i * 2] &&
|
||||
maxMajorMinor[1] < major_minor[i * 2 + 1]) {
|
||||
maxMajorMinor[0] = major_minor[i * 2];
|
||||
maxMajorMinor[1] = major_minor[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(major_minor);
|
||||
if (!foundIdenticalGPUs) {
|
||||
printf(
|
||||
"No Two or more GPUs with same architecture found\nWaiving the "
|
||||
"sample\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
std::set<int>::iterator it = identicalGPUs.begin();
|
||||
|
||||
// Iterate over all the identical GPUs found
|
||||
while (it != identicalGPUs.end()) {
|
||||
cudaDeviceProp deviceProp;
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, *it));
|
||||
// Remove all the GPUs which are less than the best arch available
|
||||
if (deviceProp.major != maxMajorMinor[0] &&
|
||||
deviceProp.minor != maxMajorMinor[1]) {
|
||||
identicalGPUs.erase(it);
|
||||
}
|
||||
if (!deviceProp.cooperativeMultiDeviceLaunch ||
|
||||
!deviceProp.concurrentManagedAccess) {
|
||||
identicalGPUs.erase(it);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
return;
|
||||
return identicalGpus;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
constexpr size_t kNumGpusRequired = 2;
|
||||
int N = 0, nz = 0, *I = NULL, *J = NULL;
|
||||
float *val = NULL;
|
||||
const float tol = 1e-5f;
|
||||
@@ -434,33 +380,101 @@ int main(int argc, char **argv) {
|
||||
float *r, *p, *Ax;
|
||||
|
||||
printf("Starting [%s]...\n", sSDKname);
|
||||
auto gpusByArch = getIdenticalGPUs();
|
||||
|
||||
int num_of_gpus = 0;
|
||||
checkCudaErrors(cudaGetDeviceCount(&num_of_gpus));
|
||||
auto it = gpusByArch.begin();
|
||||
auto end = gpusByArch.end();
|
||||
|
||||
if (num_of_gpus <= 1) {
|
||||
printf("No. of GPU on node %d\n", num_of_gpus);
|
||||
printf("Minimum Two or more GPUs are required to run this sample code\n");
|
||||
exit(EXIT_WAIVED);
|
||||
auto bestFit = std::make_pair(it, it);
|
||||
// use std::distance to find the largest number of GPUs amongst architectures
|
||||
auto distance = [](decltype(bestFit) p){return std::distance(p.first, p.second);};
|
||||
|
||||
// Read each unique key/pair element in order
|
||||
for (; it != end; it = gpusByArch.upper_bound(it->first)) {
|
||||
// first and second are iterators bounded within the architecture group
|
||||
auto testFit = gpusByArch.equal_range(it->first);
|
||||
// Always use devices with highest architecture version or whichever has the most devices available
|
||||
if (distance(bestFit) <= distance(testFit))
|
||||
bestFit = testFit;
|
||||
}
|
||||
|
||||
std::set<int> identicalGPUs;
|
||||
getIdenticalGPUs(num_of_gpus, identicalGPUs);
|
||||
|
||||
if (identicalGPUs.size() <= 1) {
|
||||
if (distance(bestFit) < kNumGpusRequired) {
|
||||
printf(
|
||||
"No Two or more GPUs with same architecture capable of "
|
||||
"cooperativeMultiDeviceLaunch & concurrentManagedAccess found. \nWaiving the sample\n");
|
||||
"cooperativeMultiDeviceLaunch & concurrentManagedAccess found. "
|
||||
"\nWaiving the sample\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
std::set<int>::iterator deviceId = identicalGPUs.begin();
|
||||
std::set<int> bestFitDeviceIds;
|
||||
|
||||
// We use only 2 GPUs as for input size of N = 10485760*2 two GPUs are enough.
|
||||
while (identicalGPUs.size() > 2) {
|
||||
identicalGPUs.erase(deviceId);
|
||||
deviceId++;
|
||||
// check & select peer-to-peer access capable GPU devices as enabling p2p access between participating
|
||||
// GPUs gives better performance for multi_grid sync.
|
||||
for (auto itr = bestFit.first; itr != bestFit.second; itr++) {
|
||||
int deviceId = itr->second;
|
||||
checkCudaErrors(cudaSetDevice(deviceId));
|
||||
|
||||
std::for_each(itr, bestFit.second, [&deviceId, &bestFitDeviceIds](decltype(*itr) mapPair) {
|
||||
if (deviceId != mapPair.second)
|
||||
{
|
||||
int access = 0;
|
||||
checkCudaErrors(cudaDeviceCanAccessPeer(&access, deviceId, mapPair.second));
|
||||
printf("Device=%d %s Access Peer Device=%d\n", deviceId, access ? "CAN" : "CANNOT", mapPair.second);
|
||||
if (access && bestFitDeviceIds.size() < kNumGpusRequired) {
|
||||
bestFitDeviceIds.emplace(deviceId);
|
||||
bestFitDeviceIds.emplace(mapPair.second);
|
||||
}
|
||||
else {
|
||||
printf("Ignoring device %i (max devices exceeded)\n", mapPair.second);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (bestFitDeviceIds.size() >= kNumGpusRequired)
|
||||
{
|
||||
printf("Selected p2p capable devices - ");
|
||||
for (auto devicesItr = bestFitDeviceIds.begin(); devicesItr != bestFitDeviceIds.end(); devicesItr++)
|
||||
{
|
||||
printf("deviceId = %d ", *devicesItr);
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if bestFitDeviceIds.size() == 0 it means the GPUs in system are not p2p capable,
|
||||
// hence we add it without p2p capability check.
|
||||
if (!bestFitDeviceIds.size())
|
||||
{
|
||||
printf("Devices involved are not p2p capable.. selecting %zu of them\n", kNumGpusRequired);
|
||||
std::for_each(bestFit.first, bestFit.second, [&bestFitDeviceIds](decltype(*bestFit.first) mapPair) {
|
||||
if (bestFitDeviceIds.size() < kNumGpusRequired) {
|
||||
bestFitDeviceIds.emplace(mapPair.second);
|
||||
}
|
||||
else {
|
||||
printf("Ignoring device %i (max devices exceeded)\n", mapPair.second);
|
||||
}
|
||||
// Insert the sequence into the deviceIds set
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// perform cudaDeviceEnablePeerAccess in both directions for all participating devices
|
||||
// of a cudaLaunchCooperativeKernelMultiDevice call this gives better performance for multi_grid sync.
|
||||
for (auto p1_itr = bestFitDeviceIds.begin(); p1_itr != bestFitDeviceIds.end(); p1_itr++)
|
||||
{
|
||||
checkCudaErrors(cudaSetDevice(*p1_itr));
|
||||
for (auto p2_itr = bestFitDeviceIds.begin(); p2_itr != bestFitDeviceIds.end(); p2_itr++)
|
||||
{
|
||||
if (*p1_itr != *p2_itr)
|
||||
{
|
||||
checkCudaErrors(cudaDeviceEnablePeerAccess(*p2_itr, 0 ));
|
||||
checkCudaErrors(cudaSetDevice(*p1_itr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a random tridiagonal symmetric matrix in CSR format */
|
||||
N = 10485760 * 2;
|
||||
nz = (N - 2) * 3 + 4;
|
||||
@@ -501,87 +515,94 @@ int main(int argc, char **argv) {
|
||||
checkCudaErrors(
|
||||
cudaMallocManaged(reinterpret_cast<void **>(&Ax), N * sizeof(float)));
|
||||
|
||||
std::cout << "\nRunning on GPUs = " << identicalGPUs.size() << std::endl;
|
||||
cudaStream_t *nStreams = reinterpret_cast<cudaStream_t *>(
|
||||
malloc(sizeof(cudaStream_t) * identicalGPUs.size()));
|
||||
std::cout << "\nRunning on GPUs = " << kNumGpusRequired << std::endl;
|
||||
cudaStream_t nStreams[kNumGpusRequired];
|
||||
|
||||
void *kernelArgs[] = {
|
||||
(void *)&I, (void *)&J, (void *)&val, (void *)&x,
|
||||
(void *)&Ax, (void *)&p, (void *)&r, (void *)&dot_result,
|
||||
(void *)&nz, (void *)&N, (void *)&tol,
|
||||
};
|
||||
|
||||
int sMemSize = sizeof(double) * THREADS_PER_BLOCK;
|
||||
int numBlocksPerSm = 0;
|
||||
int sMemSize = sizeof(double) * ((THREADS_PER_BLOCK/32) + 1);
|
||||
int numBlocksPerSm = INT_MAX;
|
||||
int numThreads = THREADS_PER_BLOCK;
|
||||
int numSms = INT_MAX;
|
||||
auto deviceId = bestFitDeviceIds.begin();
|
||||
|
||||
deviceId = identicalGPUs.begin();
|
||||
cudaDeviceProp deviceProp;
|
||||
checkCudaErrors(cudaSetDevice(*deviceId));
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, *deviceId));
|
||||
|
||||
checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor(
|
||||
&numBlocksPerSm, multiGpuConjugateGradient, numThreads, sMemSize));
|
||||
|
||||
int numSms = deviceProp.multiProcessorCount;
|
||||
dim3 dimGrid(numSms * numBlocksPerSm, 1, 1),
|
||||
dimBlock(THREADS_PER_BLOCK, 1, 1);
|
||||
|
||||
int device_count = 0;
|
||||
|
||||
int totalThreadsPerGPU = numSms * numBlocksPerSm * THREADS_PER_BLOCK;
|
||||
|
||||
while (deviceId != identicalGPUs.end()) {
|
||||
// set numSms & numBlocksPerSm to be lowest of 2 devices
|
||||
while (deviceId != bestFitDeviceIds.end()) {
|
||||
cudaDeviceProp deviceProp;
|
||||
checkCudaErrors(cudaSetDevice(*deviceId));
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, *deviceId));
|
||||
|
||||
int numBlocksPerSm_current=0;
|
||||
checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor(
|
||||
&numBlocksPerSm_current, multiGpuConjugateGradient, numThreads, sMemSize));
|
||||
|
||||
if (numBlocksPerSm > numBlocksPerSm_current)
|
||||
{
|
||||
numBlocksPerSm = numBlocksPerSm_current;
|
||||
}
|
||||
if (numSms > deviceProp.multiProcessorCount)
|
||||
{
|
||||
numSms = deviceProp.multiProcessorCount;
|
||||
}
|
||||
deviceId++;
|
||||
}
|
||||
|
||||
if (!numBlocksPerSm) {
|
||||
printf(
|
||||
"Max active blocks per SM is returned as 0.\n Hence, Waiving the "
|
||||
"sample\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
int device_count = 0;
|
||||
int totalThreadsPerGPU = numSms * numBlocksPerSm * THREADS_PER_BLOCK;
|
||||
deviceId = bestFitDeviceIds.begin();;
|
||||
while (deviceId != bestFitDeviceIds.end()) {
|
||||
checkCudaErrors(cudaSetDevice(*deviceId));
|
||||
checkCudaErrors(cudaStreamCreate(&nStreams[device_count]));
|
||||
|
||||
if (deviceProp.concurrentManagedAccess) {
|
||||
int perGPUIter = N / (totalThreadsPerGPU * identicalGPUs.size());
|
||||
int offset_Ax = device_count * totalThreadsPerGPU;
|
||||
int offset_r = device_count * totalThreadsPerGPU;
|
||||
int offset_p = device_count * totalThreadsPerGPU;
|
||||
int offset_x = device_count * totalThreadsPerGPU;
|
||||
int perGPUIter = N / (totalThreadsPerGPU * kNumGpusRequired);
|
||||
int offset_Ax = device_count * totalThreadsPerGPU;
|
||||
int offset_r = device_count * totalThreadsPerGPU;
|
||||
int offset_p = device_count * totalThreadsPerGPU;
|
||||
int offset_x = device_count * totalThreadsPerGPU;
|
||||
|
||||
checkCudaErrors(cudaMemPrefetchAsync(I, sizeof(int) * N, *deviceId,
|
||||
nStreams[device_count]));
|
||||
checkCudaErrors(cudaMemPrefetchAsync(val, sizeof(float) * nz, *deviceId,
|
||||
nStreams[device_count]));
|
||||
checkCudaErrors(cudaMemPrefetchAsync(J, sizeof(float) * nz, *deviceId,
|
||||
nStreams[device_count]));
|
||||
checkCudaErrors(cudaMemPrefetchAsync(I, sizeof(int) * N, *deviceId,
|
||||
nStreams[device_count]));
|
||||
checkCudaErrors(cudaMemPrefetchAsync(val, sizeof(float) * nz, *deviceId,
|
||||
nStreams[device_count]));
|
||||
checkCudaErrors(cudaMemPrefetchAsync(J, sizeof(float) * nz, *deviceId,
|
||||
nStreams[device_count]));
|
||||
|
||||
if (offset_Ax <= N) {
|
||||
for (int i = 0; i < perGPUIter; i++) {
|
||||
cudaMemAdvise(Ax + offset_Ax, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(r + offset_r, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(x + offset_x, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(p + offset_p, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
if (offset_Ax <= N) {
|
||||
for (int i = 0; i < perGPUIter; i++) {
|
||||
cudaMemAdvise(Ax + offset_Ax, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(r + offset_r, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(x + offset_x, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
cudaMemAdvise(p + offset_p, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetPreferredLocation, *deviceId);
|
||||
|
||||
cudaMemAdvise(Ax + offset_Ax, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(r + offset_r, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(p + offset_p, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(x + offset_x, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(Ax + offset_Ax, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(r + offset_r, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(p + offset_p, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
cudaMemAdvise(x + offset_x, sizeof(float) * totalThreadsPerGPU,
|
||||
cudaMemAdviseSetAccessedBy, *deviceId);
|
||||
|
||||
offset_Ax += totalThreadsPerGPU * identicalGPUs.size();
|
||||
offset_r += totalThreadsPerGPU * identicalGPUs.size();
|
||||
offset_p += totalThreadsPerGPU * identicalGPUs.size();
|
||||
offset_x += totalThreadsPerGPU * identicalGPUs.size();
|
||||
offset_Ax += totalThreadsPerGPU * kNumGpusRequired;
|
||||
offset_r += totalThreadsPerGPU * kNumGpusRequired;
|
||||
offset_p += totalThreadsPerGPU * kNumGpusRequired;
|
||||
offset_x += totalThreadsPerGPU * kNumGpusRequired;
|
||||
|
||||
if (offset_Ax >= N) {
|
||||
break;
|
||||
}
|
||||
if (offset_Ax >= N) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_count++;
|
||||
deviceId++;
|
||||
}
|
||||
@@ -600,11 +621,16 @@ int main(int argc, char **argv) {
|
||||
|
||||
printf("Total threads per GPU = %d numBlocksPerSm = %d\n",
|
||||
numSms * numBlocksPerSm * THREADS_PER_BLOCK, numBlocksPerSm);
|
||||
cudaLaunchParams *launchParamsList = reinterpret_cast<cudaLaunchParams *>(
|
||||
malloc(sizeof(cudaLaunchParams) * identicalGPUs.size()));
|
||||
for (int i = 0; i < identicalGPUs.size(); i++) {
|
||||
launchParamsList[i].func =
|
||||
reinterpret_cast<void *>(multiGpuConjugateGradient);
|
||||
dim3 dimGrid(numSms * numBlocksPerSm, 1, 1), dimBlock(THREADS_PER_BLOCK, 1, 1);
|
||||
void *kernelArgs[] = {
|
||||
(void *)&I, (void *)&J, (void *)&val, (void *)&x,
|
||||
(void *)&Ax, (void *)&p, (void *)&r, (void *)&dot_result,
|
||||
(void *)&nz, (void *)&N, (void *)&tol,
|
||||
};
|
||||
cudaLaunchParams *launchParamsList = (cudaLaunchParams *)malloc(
|
||||
sizeof(cudaLaunchParams) * kNumGpusRequired);
|
||||
for (int i = 0; i < kNumGpusRequired; i++) {
|
||||
launchParamsList[i].func = (void *)multiGpuConjugateGradient;
|
||||
launchParamsList[i].gridDim = dimGrid;
|
||||
launchParamsList[i].blockDim = dimBlock;
|
||||
launchParamsList[i].sharedMem = sMemSize;
|
||||
@@ -613,21 +639,20 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
printf("Launching kernel\n");
|
||||
|
||||
checkCudaErrors(cudaLaunchCooperativeKernelMultiDevice(
|
||||
launchParamsList, identicalGPUs.size(),
|
||||
launchParamsList, kNumGpusRequired,
|
||||
cudaCooperativeLaunchMultiDeviceNoPreSync |
|
||||
cudaCooperativeLaunchMultiDeviceNoPostSync));
|
||||
|
||||
if (deviceProp.concurrentManagedAccess) {
|
||||
checkCudaErrors(
|
||||
cudaMemPrefetchAsync(x, sizeof(float) * N, cudaCpuDeviceId));
|
||||
checkCudaErrors(
|
||||
checkCudaErrors(
|
||||
cudaMemPrefetchAsync(x, sizeof(float) * N, cudaCpuDeviceId));
|
||||
checkCudaErrors(
|
||||
cudaMemPrefetchAsync(dot_result, sizeof(double), cudaCpuDeviceId));
|
||||
}
|
||||
|
||||
deviceId = identicalGPUs.begin();
|
||||
deviceId = bestFitDeviceIds.begin();;
|
||||
device_count = 0;
|
||||
while (deviceId != identicalGPUs.end()) {
|
||||
while (deviceId != bestFitDeviceIds.end()) {
|
||||
checkCudaErrors(cudaSetDevice(*deviceId));
|
||||
checkCudaErrors(cudaStreamSynchronize(nStreams[device_count++]));
|
||||
deviceId++;
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<OutputFile>$(OutDir)/conjugateGradientMultiDeviceCG.exe</OutputFile>
|
||||
</Link>
|
||||
<CudaCompile>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;</CodeGeneration>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;compute_80,sm_80;</CodeGeneration>
|
||||
<AdditionalOptions>-Xcompiler "/wd 4819" %(AdditionalOptions)</AdditionalOptions>
|
||||
<Include>./;../../Common</Include>
|
||||
<Defines>WIN32</Defines>
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<OutputFile>$(OutDir)/conjugateGradientMultiDeviceCG.exe</OutputFile>
|
||||
</Link>
|
||||
<CudaCompile>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;</CodeGeneration>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;compute_80,sm_80;</CodeGeneration>
|
||||
<AdditionalOptions>-Xcompiler "/wd 4819" %(AdditionalOptions)</AdditionalOptions>
|
||||
<Include>./;../../Common</Include>
|
||||
<Defines>WIN32</Defines>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<OutputFile>$(OutDir)/conjugateGradientMultiDeviceCG.exe</OutputFile>
|
||||
</Link>
|
||||
<CudaCompile>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;</CodeGeneration>
|
||||
<CodeGeneration>compute_60,sm_60;compute_61,sm_61;compute_70,sm_70;compute_75,sm_75;compute_80,sm_80;</CodeGeneration>
|
||||
<AdditionalOptions>-Xcompiler "/wd 4819" %(AdditionalOptions)</AdditionalOptions>
|
||||
<Include>./;../../Common</Include>
|
||||
<Defines>WIN32</Defines>
|
||||
|
||||
Reference in New Issue
Block a user