Skip to content
Snippets Groups Projects
CudaSum.cuh 2.08 KiB
Newer Older
Eric Wait's avatar
Eric Wait committed
#pragma once
#include "Vec.h"
#include "CudaUtilities.cuh"
Eric Wait's avatar
Eric Wait committed

Eric Wait's avatar
Eric Wait committed
template <class PixelType>
__global__ void cudaSum(PixelType* arrayIn, double* arrayOut, size_t n)
Eric Wait's avatar
Eric Wait committed
{
	extern __shared__ double sums[];
Eric Wait's avatar
Eric Wait committed

	size_t i = threadIdx.x + blockIdx.x*blockDim.x;
	size_t stride = blockDim.x*gridDim.x;
	if (i<n)
Eric Wait's avatar
Eric Wait committed
	{
		sums[threadIdx.x] = (double)(arrayIn[i]);
Eric Wait's avatar
Eric Wait committed

		while (i<n)
		{
			sums[threadIdx.x] += (double)(arrayIn[i]);
Eric Wait's avatar
Eric Wait committed

			i += stride;
		}
Eric Wait's avatar
Eric Wait committed
		__syncthreads();
Eric Wait's avatar
Eric Wait committed


		for (int reduceUpTo = blockDim.x/2; reduceUpTo>0; reduceUpTo /= 2)
Eric Wait's avatar
Eric Wait committed
		{
			if (threadIdx.x<reduceUpTo)
				sums[threadIdx.x] += sums[threadIdx.x+reduceUpTo];
			__syncthreads();
Eric Wait's avatar
Eric Wait committed
		}

		if (threadIdx.x==0)
Eric Wait's avatar
Eric Wait committed
		{
			arrayOut[blockIdx.x] = sums[0];
Eric Wait's avatar
Eric Wait committed
		}
	}
	__syncthreads();
}

template <class PixelType>
double sumArray(const PixelType* imageIn, size_t n, int device=0)
{
	double sum = 0.0;
	double* deviceSum;
	double* hostSum;
	PixelType* deviceBuffer;

	cudaDeviceProp props;
	cudaGetDeviceProperties(&props, device);

	size_t availMem, total;
	cudaMemGetInfo(&availMem,&total);

	size_t numValsPerChunk = MIN(n,(size_t)((availMem*MAX_MEM_AVAIL)/sizeof(PixelType)));
	HANDLE_ERROR(cudaMalloc((void**)&deviceBuffer,sizeof(PixelType)*numValsPerChunk));
	HANDLE_ERROR(cudaMalloc((void**)&deviceSum,sizeof(double)*props.multiProcessorCount));
	hostSum = new double[props.multiProcessorCount];
	for (size_t startIdx=0; startIdx<n; startIdx += numValsPerChunk)
		size_t curNumVals = MIN(numValsPerChunk,n-startIdx);

		HANDLE_ERROR(cudaMemcpy(deviceBuffer,imageIn+startIdx,sizeof(PixelType)*curNumVals,cudaMemcpyHostToDevice));
		int threads = (int)MIN((size_t)props.maxThreadsPerBlock,curNumVals);
		int blocks = MIN(props.multiProcessorCount,(int)ceil((double)curNumVals/threads));
		cudaSum<<<blocks,threads,sizeof(double)*threads>>>(deviceBuffer,deviceSum,curNumVals);
		DEBUG_KERNEL_CHECK();

		HANDLE_ERROR(cudaMemcpy(hostSum,deviceSum,sizeof(double)*blocks,cudaMemcpyDeviceToHost));

		for (int i=0; i<blocks; ++i)
			sum += (PixelType)hostSum[i];
		}
	}

	HANDLE_ERROR(cudaFree(deviceSum));
	HANDLE_ERROR(cudaFree(deviceBuffer));

	delete[] hostSum;

	return sum;
Eric Wait's avatar
Eric Wait committed
}