I am developing a CUDA program and I want to enhance my performance. I have a kernel function which is consuming more than 70% of execution time. The kernel calculates the distance between several spatial points and based on whether they are neighbors or not, it fills a boolean vector.
Any ideas on how to get more speedup?
Here is the code:
#include <cuda.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/device_ptr.h>
#include <iostream>
#define _SQR(a) ((a)*(a))
#define _BLOCKSIZE 32
__host__ void RandGen(double* A, int n){
double a = 1.0;
for (int i = 0; i < n; i++) {
A[i] = (double)std::rand()/(double)(RAND_MAX)*a;
}
}
//kernel for parallel distance check
__global__ void DistanceChecker(double* xPos, double* yPos, double* zPos, double* h,
int* particles1, int* particles2,
int NumberOfP1, int NumberOfP2, bool* distance)
{
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;
double DISTANCE;
if(idx < NumberOfP1 && idy < NumberOfP2){
DISTANCE = _SQR(xPos[particles1[idx]] - xPos[particles2[idy]])+
_SQR(yPos[particles1[idx]] - yPos[particles2[idy]])+
_SQR(zPos[particles1[idx]] - zPos[particles2[idy]]);
distance [idy + NumberOfP2 * idx] = (DISTANCE < _SQR(h[particles1[idx]] + h[particles2[idy]]));
}
}
int main( int argc, char* argv[] ){
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
int num = 1024; // number of particles
thrust::host_vector<double> h_xPos(num), h_yPos(num), h_zPos(num), h_h(num,0.001);
std::srand(11);
RandGen(&h_xPos[0],num);
std::srand(15);
RandGen(&h_yPos[0],num);
std::srand(19);
RandGen(&h_zPos[0],num);
thrust::device_vector<double> d_xPos(h_xPos), d_yPos(h_yPos), d_zPos(h_zPos), d_h(h_h);
float dummymili;
float distanceCheck = 0.f;
int nBranches = 1024;
for (int i = 0; i < nBranches; i++) {
thrust::device_vector<int> particles1(500);
thrust::device_vector<int> particles2(500);
thrust::device_vector<bool> distance(particles1.size()*particles2.size(), true);
dim3 blockSize(32,32); // also tested for blockSize(16,16)
dim3 gridSize;
gridSize.x = (particles1.size() + blockSize.x - 1) / blockSize.x;
gridSize.y = (particles2.size() + blockSize.y - 1) / blockSize.y;
cudaEventRecord(start);
DistanceChecker<<<gridSize,blockSize>>>(
thrust::raw_pointer_cast(&d_xPos[0]),
thrust::raw_pointer_cast(&d_yPos[0]),
thrust::raw_pointer_cast(&d_zPos[0]),
thrust::raw_pointer_cast(&d_h[0]),
thrust::raw_pointer_cast(&particles1[0]),
thrust::raw_pointer_cast(&particles2[0]),
particles1.size(), particles2.size(),
thrust::raw_pointer_cast(&distance[0]));
cudaDeviceSynchronize();
cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&dummymili, start, stop);
distanceCheck += dummymili;
}
std::cout << "KERNEL TIME = " << distanceCheck << " milliseconds" << std::endl;
return 0;
}
I have sorted the data in the original code before using them in kernel which I think it has a positive effect on future memory accesses. So please consider that the data have sorted to optimize the memory access.
All the calculations must be done with double precision to decrease the round off errors.
The GPU device I am using is NVidia Quadro K2000, and my CUDA version is 7.5.
DistanceChecker
kernel performance. \$\endgroup\$std::hypot
? \$\endgroup\$