我尝试开发一个小型CUDA程序,用于查找给定数组中的最大值,
int input_data[0...50] = 1,2,3,4,5....,50
max_value
由input_data[0]
的第一个值初始化,
最终答案存储在result[0]
中。
内核给出0作为最大值。我不知道问题是什么。
我执行了1个50个线程。
__device__ int lock=0;
__global__ void max(float *input_data,float *result)
{
float max_value = input_data[0];
int tid = threadIdx.x;
if( input_data[tid] > max_value)
{
do{} while(atomicCAS(&lock,0,1));
max_value=input_data[tid];
__threadfence();
lock=0;
}
__syncthreads();
result[0]=max_value; //Final result of max value
}
尽管有内置功能,但我正在练习小问题。
答案 0 :(得分:4)
您正在尝试设置“关键部分”,但是这种CUDA方法可能导致整个程序挂起 - 尽可能避免使用它。
为什么您的代码会挂起?
您的内核(__global__
函数)由32个线程组执行,称为 warps 。单个warp中的所有线程都是同步执行的。因此,warp将在您的do{} while(atomicCAS(&lock,0,1))
中停止,直到
替代解决方案
您需要的是“并行缩减算法”。你可以在这里开始阅读:
答案 1 :(得分:1)
您的代码有潜在的竞争。我不确定你是否在共享内存中定义了'max_value'变量,但两者都错了。
1)如果'max_value'只是一个局部变量,那么每个线程都保存它的本地副本,它不是实际的最大值(它们只是input_data [0]和input_data [tid]之间的最大值) 。在最后一行代码中,所有线程都将结果[0]写入自己的max_value,这将导致未定义的行为。
2)如果'max_value'是共享变量,49个线程将进入if-statements块,并且他们将尝试使用锁一次更新一个'max_value'。但是没有定义49个线程中的执行顺序,因此某些线程可能会将实际最大值覆盖为较小的值。您需要在关键部分再次比较最大值。
答案 2 :(得分:1)
Max是'减少' - 查看SDK中的减少示例,并执行max而不是求和。
白皮书有点陈旧但仍然相当有用:
http://developer.download.nvidia.com/compute/cuda/1_1/Website/projects/reduction/doc/reduction.pdf
最后的优化步骤是使用'warp synchronous'编码来避免不必要的__syncthreads()调用。
它需要至少2个内核调用 - 一个用于将一堆中间max()值写入全局内存,然后另一个用于获取该数组的max()。
如果要在单个内核调用中执行此操作,请查看threadfenceReduction SDK示例。使用__threadfence()和atomicAdd()来跟踪进度,然后在所有块完成中间结果写入后,有1个块进行最终减少。
答案 3 :(得分:-1)
变量有不同的访问权限。当您通过设备定义变量时,变量将被放置在GPU全局内存中,并且网格中的所有线程都可以访问它,共享将变量放在块共享内存中只能通过该块的线程访问,如果您不使用任何关键字,如 float max_value ,则该变量放在线程寄存器上,它可以是只在该线程中访问。在您的代码中,每个线程都有局部变量max_value,并且它不识别其他线程中的变量。