I'm a beginner to CUDA and was experimenting with basic programs. I have a 1D array with elements counting down from 100 <99,98,...2,1,0> . My function basically takes an element 'n' at index 'i' and allots the element at index 'n' to index 'i' of a new array. So applying this to the mentioned array should return <0,1,2,....,97,98,99>. And it works, only if I specify the threads per block as 1.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<cuda.h>
#include<cuda_runtime.h>
__global__ void shuffle(int *arr1,int *arr2,int n){
int i = threadIdx.x + blockDim.x+blockIdx.x;
while(i<n){
arr2[i] = arr1[arr1[i]];
i += blockDim.x;
}
}
int main(){
int m=10,n=10;
int num = m*n;
int size = num*sizeof(int);
int *arr1,*arr2;
arr1 = (int*)malloc(size);
arr2 = (int*)malloc(size);
for(int i=num-1;i>=0;i--){
arr1[i] = i;
}
int *d_arr1,*d_arr2;
cudaMalloc(&d_arr1,size);
cudaMalloc(&d_arr2,size);
cudaMemcpy(d_arr1,arr1,size,cudaMemcpyHostToDevice);
shuffle<<<100,1>>>(d_arr1,d_arr2,num);
cudaMemcpy(arr2,d_arr2,size,cudaMemcpyDeviceToHost);
long error = 0;
printf("Num: %d\n",num);
//Prints value if value is right else prints correct value and actual value
for(int i=0;i<num;i++){
if(arr2[i] != i){
error+=1;
printf("%d %d\n",i,arr2[i]);
}
else{printf("%d\n",arr2[i]);}
}
printf("Error: %ld\n",error);
}
If I try calling the function as shuffle<<<25,4>>>
i.e 25 blocks and 4 threads/block, I get the wrong values at indexes 1,4-1. Similarly shuffle<<<25,5>>>
gives wrong values at indexes 1,5-1.
The problem is in your calculation of the array index for each thread.
You need to change the following line in the shuffle
kernel:
int i = threadIdx.x + blockDim.x + blockIdx.x;
To:
/*-------------------------------V----------*/
int i = threadIdx.x + blockDim.x * blockIdx.x;
I.e. use multiplication instead of addition for calculating the array index.
This is because each block consists of blockDim.x
threads, and so blockDim.x * blockIdx.x
will give you the base offset for this block.