我有一个CUDA程序,其内核基本上执行以下操作。
假设这些点中的n / 2是一种,其余的是其他点。生成的示例图像如下所示。
特别是当时间精度设置为1时,我注意到唯一的3个时间元组(t_0,t_1,t_2)的数量仅为总数据点的2.5%,即平面上的点数。这意味着大多数时候内核无法模拟,只能使用之前模拟的值。因此,我可以使用具有键的字典作为3元组的时间和值作为索引和概率。因为据我所知和测试,STL不能在内核中访问,我构造了一个大小为201000000的浮点数组。这个选择是通过实验,因为前三次都没有超过20秒。因此t_0可以取{0.0,0.1,0.2,...,20.0}的任何值,因此有201个选择。我可以为这样的字典构建一个键,如下所示
就值而言,我可以将其设为(prob + idx)。由于idx是一个整数且0.0< = prob< = 1.0,我可以稍后通过
检索这两个值所以现在我的内核看起来像下面的
__global__ my_kernel(float* points,float* dict,float *p,float *i,size_t w,...){
unsigned int col = blockIdx.y*blockDim.y + threadIdx.y;
unsigned int row = blockIdx.x*blockDim.x + threadIdx.x;
//Calculate time taken for each of the points to reach a particular point on the plane
//Order the times in increasing order t_0,t_1,...,t_n
//Calculate Key = t_o * 10^6 + t_1 * 10^3 + t_2
if(dict[key]>0.0){
prob=dict[key]-floor(dict[key])
idx = floor(dict[key])
}
else{
//Simulate and find prob and idx
dict[key]=(prob+idx)
}
p[row*width+col]=prob;
i[row*width+col]=idx;
}
结果与大多数积分的原始程序非常相似,但对于某些人来说这是错误的。
我很确定这是因为竞争条件。请注意,dict已使用全零进行初始化。基本思想是在dict的特定位置使数据结构“读多次写入”。
我知道可能有更多优化方法来解决这个问题而不是分配如此多的内存。那个案子请告诉我。但我真的很想了解为什么这个特定的解决方案失败了。特别是我想知道如何在此设置中使用atomicAdd。我没有使用它。
答案 0 :(得分:0)
除非您在else
分支中的模拟非常长(~100s的浮点运算),否则全局内存中的查找表可能比运行计算慢。全局内存访问非常昂贵!
在任何情况下,都没有办法通过"跳过工作来节省时间"使用条件分支。 GPU的单指令,多线程架构意味着分支的两个侧的指令将被串行执行,除非块中的所有线程都遵循相同的指令分支。
由于引入了条件分支和而导致性能提升的事实,你没有遇到任何死锁问题,这表明每个块中的所有线程都在同一个分支。我怀疑,一旦dict
开始填充,性能提升就会消失。
也许我误解了一些事情,但是如果你想计算一个事件的概率x
,假设一个正态分布并给出平均值mu
和标准差sigma
,那么无需生成随机数的负载并近似高斯曲线。您可以直接计算概率:
p = exp(-((x - mu) * (x - mu) / (2.0f * sigma * sigma))) /
(sigma * sqrt(2.0f * M_PI));