J'ai deux algorithmes de réduction, les deux sont de docs.nvidia, donc ils devraient être corrects mais le premier (très efficace) me donne un mauvais résultat. Le deuxième résultat est meilleur mais je m'attendais à une meilleure précision. Y a-t-il une erreur dans les algorithmes ou est-ce que je fais quelque chose de mal?Différents résultats après réduction
#include <stdio.h>
#include <cuda.h>
#include <stdlib.h>
#include <math.h>
#include "cuda_error.h"
//Lock definition
#ifndef __LOCK_H__
#define __LOCK_H__
struct Lock {
int *mutex;
Lock(void) {
CudaSafeCall(cudaMalloc((void**)&mutex,
sizeof(int)));
CudaSafeCall(cudaMemset(mutex, 0, sizeof(int)));
}
~Lock(void) {
cudaFree(mutex);
}
__device__ void lock(void) {
while(atomicCAS(mutex, 0, 1) != 0);
}
__device__ void unlock(void) {
atomicExch(mutex, 0);
}
};
#endif
//-------------------------
const int N = 507904;
const int blockSize = 256;
int blocks = N/blockSize;
template <unsigned int blockSize>
__global__ void reduce(Lock lock, float *g_idata, float *g_odata, int n)
{
extern __shared__ int sdata[];
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x*(blockSize*2) + tid;
unsigned int gridSize = blockSize*2*gridDim.x;
sdata[tid] = 0;
while (i < n)
{
sdata[tid] += g_idata[i] + g_idata[i+blockSize];
i += gridSize;
}
__syncthreads();
if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); }
if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); }
if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); }
if (tid < 32)
{
if (blockSize >= 64) sdata[tid] += sdata[tid + 32];
if (blockSize >= 32) sdata[tid] += sdata[tid + 16];
if (blockSize >= 16) sdata[tid] += sdata[tid + 8];
if (blockSize >= 8) sdata[tid] += sdata[tid + 4];
if (blockSize >= 4) sdata[tid] += sdata[tid + 2];
if (blockSize >= 2) sdata[tid] += sdata[tid + 1];
}
if (tid == 0)
{
lock.lock();
*g_odata += sdata[0];
lock.unlock();
}
}
__global__ void reduction_sum(Lock lock,float *in, float *out, int N)
{
extern __shared__ float sf_data[];
int tid = threadIdx.x;
int i = blockIdx.x * blockDim.x + threadIdx.x;
sf_data[tid] = (i<N) ? in[i] : 0;
__syncthreads();
for (int s = blockDim.x/2; s>0; s>>=1)
{
if (tid < s)
{
sf_data[tid] += sf_data[tid + s];
}
__syncthreads();
}
if (tid == 0)
{
lock.lock();
*out += sf_data[0];
lock.unlock();
}
}
//initializing function
double los()
{
return (double)rand()/(double)RAND_MAX;
}
//-------------------------------------------
int main (void)
{
//memory allocation
float *a;
float *dev_a, *dev_blocksum1, *dev_blocksum2;
float s1=0, s2=0, spr=0;
a = (float*)malloc(N*sizeof(float));
CudaSafeCall(cudaMalloc((void**)&dev_a, N*sizeof(float)));
CudaSafeCall(cudaMemset(dev_a, 0, N*sizeof(float)));
CudaSafeCall(cudaMalloc((void**)&dev_blocksum1, sizeof(float)));
CudaSafeCall(cudaMalloc( (void**)&dev_blocksum2, sizeof(float) ) );
CudaSafeCall(cudaMemset(dev_blocksum1, 0, sizeof(float)));
CudaSafeCall(cudaMemset(dev_blocksum2, 0, sizeof(float)));
//--------------------
//drawing, array fill
srand(2403);
int i;
for (i=0; i<N; i++)
{
a[i]=los();
spr+=a[i];
}
printf("CPU sum: %f \n", spr);
//copy HtoD
CudaSafeCall(cudaMemcpy(dev_a, a, N*sizeof(float), cudaMemcpyHostToDevice));
//---------------------
Lock lock;
//reduce
reduce<blockSize><<<blocks, blockSize, blockSize*sizeof(float)>>>(lock, dev_a, dev_blocksum1, N);
CudaSafeCall( cudaMemcpy (&s1, dev_blocksum1, sizeof(float), cudaMemcpyDeviceToHost ) );
printf("GPU sum1: %f \n", s1);
//-----------------------
//reduction_sum
reduction_sum<<<blocks, blockSize, blockSize*sizeof(float)>>>(lock, dev_a, dev_blocksum2, N);
CudaSafeCall( cudaMemcpy (&s2, dev_blocksum2, sizeof(float), cudaMemcpyDeviceToHost ) );
printf("GPU sum2: %f \n", s2);
//---------------------
return 0;
}
$ CPU sum: 253833.515625
$ GPU sum1: 14021.000000
$ GPU sum2: 253835.906250
Pourriez-vous ajouter les bons résultats? – fxm
Ne supposez jamais que le code de NVidia est toujours correct. Ce n'est pas. Cela s'étend également à la documentation CUDA, qui a été rédigée par un stagiaire à de grandes parties dans les premiers jours et hante toujours leur site Web et Internet. –
Mais de plus, cela pourrait simplement être un cas de stabilité numérique. –