J'ai mis en œuvre un produit vectoriel dot comme ci-dessous. Il est compilé avec CUDA 7.5 avec compute_20,sm_20
et const int THREADS_PER_BLOCK = 16;
.cuda dot produit de deux vecteurs ne fonctionnant pas pour N> = 369
Cela se produit pour les flotteurs et les doubles.
Cela fonctionne jusqu'à n=368
, mais au-delà, le résultat est incorrect. Je me demandais si le problème venait de mon code d'implémentation ou des valeurs que j'utilise (voir le deuxième code, les initialisations), par ex. peut être l'ajout au-delà de n=368
introduit des erreurs à virgule flottante (cela peut être étrange car la même erreur se produit à la fois pour float et doubles).
int divUp(int total, int grain) { return (total+grain-1)/grain; }
__device__ __forceinline__ double atomicAdd(double* address, double val)
{
unsigned long long int* address_as_ull = (unsigned long long int*)address;
unsigned long long int old = *address_as_ull, assumed;
do
{
assumed = old;
old = atomicCAS(address_as_ull, assumed, __double_as_longlong(val+__longlong_as_double(assumed)));
}
while(assumed!=old);
return __longlong_as_double(old);
}
__device__ __forceinline__ float atomicAdd(float* address, float val)
{
unsigned int *ptr = (unsigned int *)address;
unsigned int old, newint, ret = *ptr;
do {
old = ret;
newint = __float_as_int(__int_as_float(old)+val);
} while((ret = atomicCAS(ptr, old, newint)) != old);
return __int_as_float(ret);
}
template<typename T>
__global__ void vecdotk(const T* a, const T* b, const int n, T* c)
{
__shared__ T temp[THREADS_PER_BLOCK];
int x = threadIdx.x+blockIdx.x*blockDim.x;
if(x==0) c[0] = 0.0;
if(x<n) {temp[threadIdx.x] = a[x]*b[x];
}
else temp[threadIdx.x] = 0.0;
__syncthreads();
if(0==threadIdx.x)
{
T sum = 0.0;
for(int j=0; j<THREADS_PER_BLOCK; ++j)
{
sum += temp[j];
}
atomicAdd(c, sum);
}
}
template<typename T>
void dot(const T* a, const T* b, const int n, T* c)
{
dim3 block(THREADS_PER_BLOCK);
dim3 grid(divUp(n, block.x), 1);
vecdotk<T><<<grid, block>>>(a, b, n, c);
cudaSafeCall(cudaGetLastError());
};
J'utilise les deux vecteurs hôtes suivants pour remplir les matrices de dispositif d'entrée (qui a je ne suis pas représentés car ils font partie d'une plus grande bibliothèque). Fondamentalement, je veux calculer la somme de la série carrée c.-à-
// fill host vectors a and b
for(int i=0; i<n; ++i)
{
h_vec_a[i] = i+1;//__mat_rand();
h_vec_b[i] = i+1;//__mat_rand();
}
Je suis en train d'apprendre les bases de CUDA et de programmer des GPU pour l'informatique générale. Mais, comment cela sera-t-il si j'utilise '__threadfence()' après la ligne 'if (x == 0) c [0] = 0.0;' – user62039
Merci Robert. Aussi, je pense qu'il serait alors préférable d'initialiser la somme = 0.0 dans la fonction 'void dot (...)' seulement. Droite? La threadfence – user62039
n'applique pas l'ordre d'exécution du thread. Et oui vous pouvez initialiser c où vous voulez tant que c'est avant l'appel du noyau –