Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -48,28 +48,28 @@
COMMAND LINE ARGUMENTS
"--shmoo": Test performance for 1 to 32M elements with each of the
"--shmoo": Test performance for 1 to 32M elements with each of the
7 different kernels
"--n=<N>": Specify the number of elements to reduce (default 1048576)
"--threads=<N>": Specify the number of threads per block (default 128)
"--maxblocks=<N>": Specify the maximum number of thread blocks to launch
"--maxblocks=<N>": Specify the maximum number of thread blocks to launch
(kernel 6 only, default 64)
"--cpufinal": Read back the per-block results and do final sum of block
"--cpufinal": Read back the per-block results and do final sum of block
sums on CPU (default false)
"--cputhresh=<N>": The threshold of number of blocks sums below which to
"--cputhresh=<N>": The threshold of number of blocks sums below which to
perform a CPU final reduction (default 1)
"--multipass": Use a multipass reduction instead of a single-pass reduction
*/
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#define VERSION_MAJOR (CUDART_VERSION / 1000)
#define VERSION_MINOR (CUDART_VERSION % 100) / 10
@@ -86,51 +86,52 @@ const char *sSDKsample = "threadFenceReduction";
// declaration, forward
bool runTest(int argc, char **argv);
extern "C" {
void reduce(int size, int threads, int blocks, float *d_idata, float *d_odata);
void reduceSinglePass(int size, int threads, int blocks, float *d_idata,
float *d_odata);
extern "C"
{
void reduce(int size, int threads, int blocks, float *d_idata, float *d_odata);
void reduceSinglePass(int size, int threads, int blocks, float *d_idata, float *d_odata);
}
#if CUDART_VERSION < 2020
void reduce(int size, int threads, int blocks, float *d_idata, float *d_odata) {
printf("reduce(), compiler not supported, aborting tests\n");
void reduce(int size, int threads, int blocks, float *d_idata, float *d_odata)
{
printf("reduce(), compiler not supported, aborting tests\n");
}
void reduceSinglePass(int size, int threads, int blocks, float *d_idata,
float *d_odata) {
printf("reduceSinglePass(), compiler not supported, aborting tests\n");
void reduceSinglePass(int size, int threads, int blocks, float *d_idata, float *d_odata)
{
printf("reduceSinglePass(), compiler not supported, aborting tests\n");
}
#endif
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
cudaDeviceProp deviceProp;
deviceProp.major = 0;
deviceProp.minor = 0;
int dev;
int main(int argc, char **argv)
{
cudaDeviceProp deviceProp;
deviceProp.major = 0;
deviceProp.minor = 0;
int dev;
printf("%s Starting...\n\n", sSDKsample);
printf("%s Starting...\n\n", sSDKsample);
dev = findCudaDevice(argc, (const char **)argv);
dev = findCudaDevice(argc, (const char **)argv);
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));
printf("GPU Device supports SM %d.%d compute capability\n\n",
deviceProp.major, deviceProp.minor);
printf("GPU Device supports SM %d.%d compute capability\n\n", deviceProp.major, deviceProp.minor);
bool bTestResult = false;
bool bTestResult = false;
#if CUDART_VERSION >= 2020
bTestResult = runTest(argc, argv);
bTestResult = runTest(argc, argv);
#else
print_NVCC_min_spec(sSDKsample, "2.2", "Version 185");
exit(EXIT_SUCCESS);
print_NVCC_min_spec(sSDKsample, "2.2", "Version 185");
exit(EXIT_SUCCESS);
#endif
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
////////////////////////////////////////////////////////////////////////////////
@@ -141,137 +142,147 @@ int main(int argc, char **argv) {
//! @param data pointer to input data
//! @param size number of input data elements
////////////////////////////////////////////////////////////////////////////////
template <class T>
T reduceCPU(T *data, int size) {
T sum = data[0];
T c = (T)0.0;
template <class T> T reduceCPU(T *data, int size)
{
T sum = data[0];
T c = (T)0.0;
for (int i = 1; i < size; i++) {
T y = data[i] - c;
T t = sum + y;
c = (t - sum) - y;
sum = t;
}
for (int i = 1; i < size; i++) {
T y = data[i] - c;
T t = sum + y;
c = (t - sum) - y;
sum = t;
}
return sum;
return sum;
}
unsigned int nextPow2(unsigned int x) {
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
unsigned int nextPow2(unsigned int x)
{
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
////////////////////////////////////////////////////////////////////////////////
// Compute the number of threads and blocks to use for the reduction
// We set threads / block to the minimum of maxThreads and n/2.
////////////////////////////////////////////////////////////////////////////////
void getNumBlocksAndThreads(int n, int maxBlocks, int maxThreads, int &blocks,
int &threads) {
if (n == 1) {
threads = 1;
blocks = 1;
} else {
threads = (n < maxThreads * 2) ? nextPow2(n / 2) : maxThreads;
blocks = max(1, n / (threads * 2));
}
void getNumBlocksAndThreads(int n, int maxBlocks, int maxThreads, int &blocks, int &threads)
{
if (n == 1) {
threads = 1;
blocks = 1;
}
else {
threads = (n < maxThreads * 2) ? nextPow2(n / 2) : maxThreads;
blocks = max(1, n / (threads * 2));
}
blocks = min(maxBlocks, blocks);
blocks = min(maxBlocks, blocks);
}
////////////////////////////////////////////////////////////////////////////////
// This function performs a reduction of the input data multiple times and
// measures the average reduction time.
////////////////////////////////////////////////////////////////////////////////
float benchmarkReduce(int n, int numThreads, int numBlocks, int maxThreads,
int maxBlocks, int testIterations, bool multiPass,
bool cpuFinalReduction, int cpuFinalThreshold,
StopWatchInterface *timer, float *h_odata, float *d_idata,
float *d_odata) {
float gpu_result = 0;
bool bNeedReadback = true;
cudaError_t error;
float benchmarkReduce(int n,
int numThreads,
int numBlocks,
int maxThreads,
int maxBlocks,
int testIterations,
bool multiPass,
bool cpuFinalReduction,
int cpuFinalThreshold,
StopWatchInterface *timer,
float *h_odata,
float *d_idata,
float *d_odata)
{
float gpu_result = 0;
bool bNeedReadback = true;
cudaError_t error;
for (int i = 0; i < testIterations; ++i) {
gpu_result = 0;
unsigned int retCnt = 0;
error = setRetirementCount(retCnt);
checkCudaErrors(error);
cudaDeviceSynchronize();
sdkStartTimer(&timer);
if (multiPass) {
// execute the kernel
reduce(n, numThreads, numBlocks, d_idata, d_odata);
// check if kernel execution generated an error
getLastCudaError("Kernel execution failed");
if (cpuFinalReduction) {
// sum partial sums from each block on CPU
// copy result from device to host
error = cudaMemcpy(h_odata, d_odata, numBlocks * sizeof(float),
cudaMemcpyDeviceToHost);
for (int i = 0; i < testIterations; ++i) {
gpu_result = 0;
unsigned int retCnt = 0;
error = setRetirementCount(retCnt);
checkCudaErrors(error);
for (int i = 0; i < numBlocks; i++) {
gpu_result += h_odata[i];
cudaDeviceSynchronize();
sdkStartTimer(&timer);
if (multiPass) {
// execute the kernel
reduce(n, numThreads, numBlocks, d_idata, d_odata);
// check if kernel execution generated an error
getLastCudaError("Kernel execution failed");
if (cpuFinalReduction) {
// sum partial sums from each block on CPU
// copy result from device to host
error = cudaMemcpy(h_odata, d_odata, numBlocks * sizeof(float), cudaMemcpyDeviceToHost);
checkCudaErrors(error);
for (int i = 0; i < numBlocks; i++) {
gpu_result += h_odata[i];
}
bNeedReadback = false;
}
else {
// sum partial block sums on GPU
int s = numBlocks;
while (s > cpuFinalThreshold) {
int threads = 0, blocks = 0;
getNumBlocksAndThreads(s, maxBlocks, maxThreads, blocks, threads);
reduce(s, threads, blocks, d_odata, d_odata);
s = s / (threads * 2);
}
if (s > 1) {
// copy result from device to host
error = cudaMemcpy(h_odata, d_odata, s * sizeof(float), cudaMemcpyDeviceToHost);
checkCudaErrors(error);
for (int i = 0; i < s; i++) {
gpu_result += h_odata[i];
}
bNeedReadback = false;
}
}
}
else {
getLastCudaError("Kernel execution failed");
// execute the kernel
reduceSinglePass(n, numThreads, numBlocks, d_idata, d_odata);
// check if kernel execution generated an error
getLastCudaError("Kernel execution failed");
}
bNeedReadback = false;
} else {
// sum partial block sums on GPU
int s = numBlocks;
while (s > cpuFinalThreshold) {
int threads = 0, blocks = 0;
getNumBlocksAndThreads(s, maxBlocks, maxThreads, blocks, threads);
reduce(s, threads, blocks, d_odata, d_odata);
s = s / (threads * 2);
}
if (s > 1) {
// copy result from device to host
error = cudaMemcpy(h_odata, d_odata, s * sizeof(float),
cudaMemcpyDeviceToHost);
checkCudaErrors(error);
for (int i = 0; i < s; i++) {
gpu_result += h_odata[i];
}
bNeedReadback = false;
}
}
} else {
getLastCudaError("Kernel execution failed");
// execute the kernel
reduceSinglePass(n, numThreads, numBlocks, d_idata, d_odata);
// check if kernel execution generated an error
getLastCudaError("Kernel execution failed");
cudaDeviceSynchronize();
sdkStopTimer(&timer);
}
cudaDeviceSynchronize();
sdkStopTimer(&timer);
}
if (bNeedReadback) {
// copy final sum from device to host
error = cudaMemcpy(&gpu_result, d_odata, sizeof(float), cudaMemcpyDeviceToHost);
checkCudaErrors(error);
}
if (bNeedReadback) {
// copy final sum from device to host
error =
cudaMemcpy(&gpu_result, d_odata, sizeof(float), cudaMemcpyDeviceToHost);
checkCudaErrors(error);
}
return gpu_result;
return gpu_result;
}
////////////////////////////////////////////////////////////////////////////////
@@ -280,186 +291,203 @@ float benchmarkReduce(int n, int numThreads, int numBlocks, int maxThreads,
// for generating a "shmoo" plot showing the performance for each kernel
// variation over a wide range of input sizes.
////////////////////////////////////////////////////////////////////////////////
void shmoo(int minN, int maxN, int maxThreads, int maxBlocks) {
// create random input data on CPU
unsigned int bytes = maxN * sizeof(float);
float *h_idata = (float *)malloc(bytes);
for (int i = 0; i < maxN; i++) {
// Keep the numbers small so we don't get truncation error in the sum
h_idata[i] = (rand() & 0xFF) / (float)RAND_MAX;
}
int maxNumBlocks = min(65535, maxN / maxThreads);
// allocate mem for the result on host side
float *h_odata = (float *)malloc(maxNumBlocks * sizeof(float));
// allocate device memory and data
float *d_idata = NULL;
float *d_odata = NULL;
checkCudaErrors(cudaMalloc((void **)&d_idata, bytes));
checkCudaErrors(cudaMalloc((void **)&d_odata, maxNumBlocks * sizeof(float)));
// copy data directly to device memory
checkCudaErrors(cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_odata, h_idata, maxNumBlocks * sizeof(float),
cudaMemcpyHostToDevice));
// warm-up
reduce(maxN, maxThreads, maxNumBlocks, d_idata, d_odata);
int testIterations = 100;
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
// print headers
printf("N, %d blocks one pass, %d blocks multipass\n", maxBlocks, maxBlocks);
for (int i = minN; i <= maxN; i *= 2) {
printf("%d, ", i);
for (int multiPass = 0; multiPass <= 1; multiPass++) {
sdkResetTimer(&timer);
int numBlocks = 0;
int numThreads = 0;
getNumBlocksAndThreads(i, maxBlocks, maxThreads, numBlocks, numThreads);
benchmarkReduce(i, numThreads, numBlocks, maxThreads, maxBlocks,
testIterations, multiPass == 1, false, 1, timer, h_odata,
d_idata, d_odata);
float reduceTime = sdkGetAverageTimerValue(&timer);
printf("%f%s", reduceTime, multiPass == 0 ? ", " : "\n");
}
}
printf("\n");
// cleanup
sdkDeleteTimer(&timer);
free(h_idata);
free(h_odata);
cudaFree(d_idata);
cudaFree(d_odata);
}
////////////////////////////////////////////////////////////////////////////////
// The main function which runs the reduction test.
////////////////////////////////////////////////////////////////////////////////
bool runTest(int argc, char **argv) {
int size = 1 << 20; // number of elements to reduce
int maxThreads = 128; // number of threads per block
int maxBlocks = 64;
bool cpuFinalReduction = false;
int cpuFinalThreshold = 1;
bool multipass = false;
bool bTestResult = false;
if (checkCmdLineFlag(argc, (const char **)argv, "n")) {
size = getCmdLineArgumentInt(argc, (const char **)argv, "n");
}
if (checkCmdLineFlag(argc, (const char **)argv, "threads")) {
maxThreads = getCmdLineArgumentInt(argc, (const char **)argv, "threads");
}
if (checkCmdLineFlag(argc, (const char **)argv, "maxblocks")) {
maxBlocks = getCmdLineArgumentInt(argc, (const char **)argv, "maxblocks");
}
printf("%d elements\n", size);
printf("%d threads (max)\n", maxThreads);
cpuFinalReduction = checkCmdLineFlag(argc, (const char **)argv, "cpufinal");
multipass = checkCmdLineFlag(argc, (const char **)argv, "multipass");
if (checkCmdLineFlag(argc, (const char **)argv, "cputhresh")) {
cpuFinalThreshold =
getCmdLineArgumentInt(argc, (const char **)argv, "cputhresh");
}
bool runShmoo = checkCmdLineFlag(argc, (const char **)argv, "shmoo");
if (runShmoo) {
shmoo(1, 33554432, maxThreads, maxBlocks);
} else {
void shmoo(int minN, int maxN, int maxThreads, int maxBlocks)
{
// create random input data on CPU
unsigned int bytes = size * sizeof(float);
unsigned int bytes = maxN * sizeof(float);
float *h_idata = (float *)malloc(bytes);
for (int i = 0; i < size; i++) {
// Keep the numbers small so we don't get truncation error in the sum
h_idata[i] = (rand() & 0xFF) / (float)RAND_MAX;
for (int i = 0; i < maxN; i++) {
// Keep the numbers small so we don't get truncation error in the sum
h_idata[i] = (rand() & 0xFF) / (float)RAND_MAX;
}
int numBlocks = 0;
int numThreads = 0;
getNumBlocksAndThreads(size, maxBlocks, maxThreads, numBlocks, numThreads);
if (numBlocks == 1) {
cpuFinalThreshold = 1;
}
int maxNumBlocks = min(65535, maxN / maxThreads);
// allocate mem for the result on host side
float *h_odata = (float *)malloc(numBlocks * sizeof(float));
printf("%d blocks\n", numBlocks);
float *h_odata = (float *)malloc(maxNumBlocks * sizeof(float));
// allocate device memory and data
float *d_idata = NULL;
float *d_odata = NULL;
checkCudaErrors(cudaMalloc((void **)&d_idata, bytes));
checkCudaErrors(cudaMalloc((void **)&d_odata, numBlocks * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_odata, maxNumBlocks * sizeof(float)));
// copy data directly to device memory
checkCudaErrors(
cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_odata, h_idata, numBlocks * sizeof(float),
cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_odata, h_idata, maxNumBlocks * sizeof(float), cudaMemcpyHostToDevice));
// warm-up
reduce(size, numThreads, numBlocks, d_idata, d_odata);
reduce(maxN, maxThreads, maxNumBlocks, d_idata, d_odata);
int testIterations = 100;
StopWatchInterface *timer = 0;
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
float gpu_result = 0;
// print headers
printf("N, %d blocks one pass, %d blocks multipass\n", maxBlocks, maxBlocks);
gpu_result =
benchmarkReduce(size, numThreads, numBlocks, maxThreads, maxBlocks,
testIterations, multipass, cpuFinalReduction,
cpuFinalThreshold, timer, h_odata, d_idata, d_odata);
for (int i = minN; i <= maxN; i *= 2) {
printf("%d, ", i);
float reduceTime = sdkGetAverageTimerValue(&timer);
printf("Average time: %f ms\n", reduceTime);
printf("Bandwidth: %f GB/s\n\n",
(size * sizeof(int)) / (reduceTime * 1.0e6));
for (int multiPass = 0; multiPass <= 1; multiPass++) {
sdkResetTimer(&timer);
int numBlocks = 0;
int numThreads = 0;
getNumBlocksAndThreads(i, maxBlocks, maxThreads, numBlocks, numThreads);
// compute reference solution
float cpu_result = reduceCPU<float>(h_idata, size);
benchmarkReduce(i,
numThreads,
numBlocks,
maxThreads,
maxBlocks,
testIterations,
multiPass == 1,
false,
1,
timer,
h_odata,
d_idata,
d_odata);
printf("GPU result = %0.12f\n", gpu_result);
printf("CPU result = %0.12f\n", cpu_result);
float reduceTime = sdkGetAverageTimerValue(&timer);
printf("%f%s", reduceTime, multiPass == 0 ? ", " : "\n");
}
}
double threshold = 1e-8 * size;
double diff = abs((double)gpu_result - (double)cpu_result);
bTestResult = (diff < threshold);
printf("\n");
// cleanup
sdkDeleteTimer(&timer);
free(h_idata);
free(h_odata);
cudaFree(d_idata);
cudaFree(d_odata);
}
return bTestResult;
}
////////////////////////////////////////////////////////////////////////////////
// The main function which runs the reduction test.
////////////////////////////////////////////////////////////////////////////////
bool runTest(int argc, char **argv)
{
int size = 1 << 20; // number of elements to reduce
int maxThreads = 128; // number of threads per block
int maxBlocks = 64;
bool cpuFinalReduction = false;
int cpuFinalThreshold = 1;
bool multipass = false;
bool bTestResult = false;
if (checkCmdLineFlag(argc, (const char **)argv, "n")) {
size = getCmdLineArgumentInt(argc, (const char **)argv, "n");
}
if (checkCmdLineFlag(argc, (const char **)argv, "threads")) {
maxThreads = getCmdLineArgumentInt(argc, (const char **)argv, "threads");
}
if (checkCmdLineFlag(argc, (const char **)argv, "maxblocks")) {
maxBlocks = getCmdLineArgumentInt(argc, (const char **)argv, "maxblocks");
}
printf("%d elements\n", size);
printf("%d threads (max)\n", maxThreads);
cpuFinalReduction = checkCmdLineFlag(argc, (const char **)argv, "cpufinal");
multipass = checkCmdLineFlag(argc, (const char **)argv, "multipass");
if (checkCmdLineFlag(argc, (const char **)argv, "cputhresh")) {
cpuFinalThreshold = getCmdLineArgumentInt(argc, (const char **)argv, "cputhresh");
}
bool runShmoo = checkCmdLineFlag(argc, (const char **)argv, "shmoo");
if (runShmoo) {
shmoo(1, 33554432, maxThreads, maxBlocks);
}
else {
// create random input data on CPU
unsigned int bytes = size * sizeof(float);
float *h_idata = (float *)malloc(bytes);
for (int i = 0; i < size; i++) {
// Keep the numbers small so we don't get truncation error in the sum
h_idata[i] = (rand() & 0xFF) / (float)RAND_MAX;
}
int numBlocks = 0;
int numThreads = 0;
getNumBlocksAndThreads(size, maxBlocks, maxThreads, numBlocks, numThreads);
if (numBlocks == 1) {
cpuFinalThreshold = 1;
}
// allocate mem for the result on host side
float *h_odata = (float *)malloc(numBlocks * sizeof(float));
printf("%d blocks\n", numBlocks);
// allocate device memory and data
float *d_idata = NULL;
float *d_odata = NULL;
checkCudaErrors(cudaMalloc((void **)&d_idata, bytes));
checkCudaErrors(cudaMalloc((void **)&d_odata, numBlocks * sizeof(float)));
// copy data directly to device memory
checkCudaErrors(cudaMemcpy(d_idata, h_idata, bytes, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_odata, h_idata, numBlocks * sizeof(float), cudaMemcpyHostToDevice));
// warm-up
reduce(size, numThreads, numBlocks, d_idata, d_odata);
int testIterations = 100;
StopWatchInterface *timer = 0;
sdkCreateTimer(&timer);
float gpu_result = 0;
gpu_result = benchmarkReduce(size,
numThreads,
numBlocks,
maxThreads,
maxBlocks,
testIterations,
multipass,
cpuFinalReduction,
cpuFinalThreshold,
timer,
h_odata,
d_idata,
d_odata);
float reduceTime = sdkGetAverageTimerValue(&timer);
printf("Average time: %f ms\n", reduceTime);
printf("Bandwidth: %f GB/s\n\n", (size * sizeof(int)) / (reduceTime * 1.0e6));
// compute reference solution
float cpu_result = reduceCPU<float>(h_idata, size);
printf("GPU result = %0.12f\n", gpu_result);
printf("CPU result = %0.12f\n", cpu_result);
double threshold = 1e-8 * size;
double diff = abs((double)gpu_result - (double)cpu_result);
bTestResult = (diff < threshold);
// cleanup
sdkDeleteTimer(&timer);
free(h_idata);
free(h_odata);
cudaFree(d_idata);
cudaFree(d_odata);
}
return bTestResult;
}

View File

@@ -32,8 +32,8 @@
#ifndef _REDUCE_KERNEL_H_
#define _REDUCE_KERNEL_H_
#include <cuda_runtime_api.h>
#include <cooperative_groups.h>
#include <cuda_runtime_api.h>
namespace cg = cooperative_groups;
@@ -51,85 +51,87 @@ namespace cg = cooperative_groups;
*/
template <unsigned int blockSize>
__device__ void reduceBlock(volatile float *sdata, float mySum,
const unsigned int tid, cg::thread_block cta) {
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
sdata[tid] = mySum;
cg::sync(tile32);
const int VEC = 32;
const int vid = tid & (VEC - 1);
float beta = mySum;
float temp;
for (int i = VEC / 2; i > 0; i >>= 1) {
if (vid < i) {
temp = sdata[tid + i];
beta += temp;
sdata[tid] = beta;
}
__device__ void reduceBlock(volatile float *sdata, float mySum, const unsigned int tid, cg::thread_block cta)
{
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
sdata[tid] = mySum;
cg::sync(tile32);
}
cg::sync(cta);
if (cta.thread_rank() == 0) {
beta = 0;
for (int i = 0; i < blockDim.x; i += VEC) {
beta += sdata[i];
const int VEC = 32;
const int vid = tid & (VEC - 1);
float beta = mySum;
float temp;
for (int i = VEC / 2; i > 0; i >>= 1) {
if (vid < i) {
temp = sdata[tid + i];
beta += temp;
sdata[tid] = beta;
}
cg::sync(tile32);
}
sdata[0] = beta;
}
cg::sync(cta);
cg::sync(cta);
if (cta.thread_rank() == 0) {
beta = 0;
for (int i = 0; i < blockDim.x; i += VEC) {
beta += sdata[i];
}
sdata[0] = beta;
}
cg::sync(cta);
}
template <unsigned int blockSize, bool nIsPow2>
__device__ void reduceBlocks(const float *g_idata, float *g_odata,
unsigned int n, cg::thread_block cta) {
extern __shared__ float sdata[];
__device__ void reduceBlocks(const float *g_idata, float *g_odata, unsigned int n, cg::thread_block cta)
{
extern __shared__ float sdata[];
// perform first level of reduction,
// reading from global memory, writing to shared memory
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x * (blockSize * 2) + threadIdx.x;
unsigned int gridSize = blockSize * 2 * gridDim.x;
float mySum = 0;
// perform first level of reduction,
// reading from global memory, writing to shared memory
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x * (blockSize * 2) + threadIdx.x;
unsigned int gridSize = blockSize * 2 * gridDim.x;
float mySum = 0;
// we reduce multiple elements per thread. The number is determined by the
// number of active thread blocks (via gridDim). More blocks will result
// in a larger gridSize and therefore fewer elements per thread
while (i < n) {
mySum += g_idata[i];
// we reduce multiple elements per thread. The number is determined by the
// number of active thread blocks (via gridDim). More blocks will result
// in a larger gridSize and therefore fewer elements per thread
while (i < n) {
mySum += g_idata[i];
// ensure we don't read out of bounds -- this is optimized away for powerOf2
// sized arrays
if (nIsPow2 || i + blockSize < n) mySum += g_idata[i + blockSize];
// ensure we don't read out of bounds -- this is optimized away for powerOf2
// sized arrays
if (nIsPow2 || i + blockSize < n)
mySum += g_idata[i + blockSize];
i += gridSize;
}
i += gridSize;
}
// do reduction in shared mem
reduceBlock<blockSize>(sdata, mySum, tid, cta);
// do reduction in shared mem
reduceBlock<blockSize>(sdata, mySum, tid, cta);
// write result for this block to global mem
if (tid == 0) g_odata[blockIdx.x] = sdata[0];
// write result for this block to global mem
if (tid == 0)
g_odata[blockIdx.x] = sdata[0];
}
template <unsigned int blockSize, bool nIsPow2>
__global__ void reduceMultiPass(const float *g_idata, float *g_odata,
unsigned int n) {
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
reduceBlocks<blockSize, nIsPow2>(g_idata, g_odata, n, cta);
__global__ void reduceMultiPass(const float *g_idata, float *g_odata, unsigned int n)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
reduceBlocks<blockSize, nIsPow2>(g_idata, g_odata, n, cta);
}
// Global variable used by reduceSinglePass to count how many blocks have
// finished
__device__ unsigned int retirementCount = 0;
cudaError_t setRetirementCount(int retCnt) {
return cudaMemcpyToSymbol(retirementCount, &retCnt, sizeof(unsigned int), 0,
cudaMemcpyHostToDevice);
cudaError_t setRetirementCount(int retCnt)
{
return cudaMemcpyToSymbol(retirementCount, &retCnt, sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
}
// This reduction kernel reduces an arbitrary size array in a single kernel
@@ -148,59 +150,59 @@ cudaError_t setRetirementCount(int retCnt) {
// For more details on the reduction algorithm (notably the multi-pass
// approach), see the "reduction" sample in the CUDA SDK.
template <unsigned int blockSize, bool nIsPow2>
__global__ void reduceSinglePass(const float *g_idata, float *g_odata,
unsigned int n) {
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
//
// PHASE 1: Process all inputs assigned to this block
//
__global__ void reduceSinglePass(const float *g_idata, float *g_odata, unsigned int n)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
//
// PHASE 1: Process all inputs assigned to this block
//
reduceBlocks<blockSize, nIsPow2>(g_idata, g_odata, n, cta);
reduceBlocks<blockSize, nIsPow2>(g_idata, g_odata, n, cta);
//
// PHASE 2: Last block finished will process all partial sums
//
//
// PHASE 2: Last block finished will process all partial sums
//
if (gridDim.x > 1) {
const unsigned int tid = threadIdx.x;
__shared__ bool amLast;
extern float __shared__ smem[];
if (gridDim.x > 1) {
const unsigned int tid = threadIdx.x;
__shared__ bool amLast;
extern float __shared__ smem[];
// wait until all outstanding memory instructions in this thread are
// finished
__threadfence();
// wait until all outstanding memory instructions in this thread are
// finished
__threadfence();
// Thread 0 takes a ticket
if (tid == 0) {
unsigned int ticket = atomicInc(&retirementCount, gridDim.x);
// If the ticket ID is equal to the number of blocks, we are the last
// block!
amLast = (ticket == gridDim.x - 1);
// Thread 0 takes a ticket
if (tid == 0) {
unsigned int ticket = atomicInc(&retirementCount, gridDim.x);
// If the ticket ID is equal to the number of blocks, we are the last
// block!
amLast = (ticket == gridDim.x - 1);
}
cg::sync(cta);
// The last block sums the results of all other blocks
if (amLast) {
int i = tid;
float mySum = 0;
while (i < gridDim.x) {
mySum += g_odata[i];
i += blockSize;
}
reduceBlock<blockSize>(smem, mySum, tid, cta);
if (tid == 0) {
g_odata[0] = smem[0];
// reset retirement count so that next run succeeds
retirementCount = 0;
}
}
}
cg::sync(cta);
// The last block sums the results of all other blocks
if (amLast) {
int i = tid;
float mySum = 0;
while (i < gridDim.x) {
mySum += g_odata[i];
i += blockSize;
}
reduceBlock<blockSize>(smem, mySum, tid, cta);
if (tid == 0) {
g_odata[0] = smem[0];
// reset retirement count so that next run succeeds
retirementCount = 0;
}
}
}
}
bool isPow2(unsigned int x) { return ((x & (x - 1)) == 0); }
@@ -208,233 +210,194 @@ bool isPow2(unsigned int x) { return ((x & (x - 1)) == 0); }
////////////////////////////////////////////////////////////////////////////////
// Wrapper function for kernel launch
////////////////////////////////////////////////////////////////////////////////
extern "C" void reduce(int size, int threads, int blocks, float *d_idata,
float *d_odata) {
dim3 dimBlock(threads, 1, 1);
dim3 dimGrid(blocks, 1, 1);
int smemSize =
(threads <= 32) ? 2 * threads * sizeof(float) : threads * sizeof(float);
extern "C" void reduce(int size, int threads, int blocks, float *d_idata, float *d_odata)
{
dim3 dimBlock(threads, 1, 1);
dim3 dimGrid(blocks, 1, 1);
int smemSize = (threads <= 32) ? 2 * threads * sizeof(float) : threads * sizeof(float);
// choose which of the optimized versions of reduction to launch
if (isPow2(size)) {
switch (threads) {
case 512:
reduceMultiPass<512, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
// choose which of the optimized versions of reduction to launch
if (isPow2(size)) {
switch (threads) {
case 512:
reduceMultiPass<512, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceMultiPass<256, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceMultiPass<256, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceMultiPass<128, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceMultiPass<128, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceMultiPass<64, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceMultiPass<64, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceMultiPass<32, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceMultiPass<32, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceMultiPass<16, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceMultiPass<16, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceMultiPass<8, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceMultiPass<8, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceMultiPass<4, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceMultiPass<4, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceMultiPass<2, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceMultiPass<2, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceMultiPass<1, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceMultiPass<1, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
}
}
} else {
switch (threads) {
case 512:
reduceMultiPass<512, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
else {
switch (threads) {
case 512:
reduceMultiPass<512, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceMultiPass<256, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceMultiPass<256, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceMultiPass<128, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceMultiPass<128, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceMultiPass<64, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceMultiPass<64, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceMultiPass<32, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceMultiPass<32, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceMultiPass<16, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceMultiPass<16, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceMultiPass<8, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceMultiPass<8, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceMultiPass<4, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceMultiPass<4, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceMultiPass<2, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceMultiPass<2, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceMultiPass<1, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceMultiPass<1, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
}
}
}
}
extern "C" void reduceSinglePass(int size, int threads, int blocks,
float *d_idata, float *d_odata) {
dim3 dimBlock(threads, 1, 1);
dim3 dimGrid(blocks, 1, 1);
int smemSize = threads * sizeof(float);
extern "C" void reduceSinglePass(int size, int threads, int blocks, float *d_idata, float *d_odata)
{
dim3 dimBlock(threads, 1, 1);
dim3 dimGrid(blocks, 1, 1);
int smemSize = threads * sizeof(float);
// choose which of the optimized versions of reduction to launch
if (isPow2(size)) {
switch (threads) {
case 512:
reduceSinglePass<512, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
// choose which of the optimized versions of reduction to launch
if (isPow2(size)) {
switch (threads) {
case 512:
reduceSinglePass<512, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceSinglePass<256, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceSinglePass<256, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceSinglePass<128, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceSinglePass<128, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceSinglePass<64, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceSinglePass<64, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceSinglePass<32, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceSinglePass<32, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceSinglePass<16, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceSinglePass<16, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceSinglePass<8, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceSinglePass<8, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceSinglePass<4, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceSinglePass<4, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceSinglePass<2, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceSinglePass<2, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceSinglePass<1, true>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceSinglePass<1, true><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
}
}
} else {
switch (threads) {
case 512:
reduceSinglePass<512, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
else {
switch (threads) {
case 512:
reduceSinglePass<512, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceSinglePass<256, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 256:
reduceSinglePass<256, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceSinglePass<128, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 128:
reduceSinglePass<128, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceSinglePass<64, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 64:
reduceSinglePass<64, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceSinglePass<32, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 32:
reduceSinglePass<32, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceSinglePass<16, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 16:
reduceSinglePass<16, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceSinglePass<8, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 8:
reduceSinglePass<8, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceSinglePass<4, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 4:
reduceSinglePass<4, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceSinglePass<2, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 2:
reduceSinglePass<2, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceSinglePass<1, false>
<<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
case 1:
reduceSinglePass<1, false><<<dimGrid, dimBlock, smemSize>>>(d_idata, d_odata, size);
break;
}
}
}
}
#endif // #ifndef _REDUCE_KERNEL_H_
#endif // #ifndef _REDUCE_KERNEL_H_