-1

我有一个 CUDA 程序,其内核基本上执行以下操作。

  • 我提供了笛卡尔坐标中的 n 个点的列表,例如维度为 dim_x * dim_y 的平面中的 (x_i,y_i)。我相应地调用内核。
  • 对于这个平面上的每个点 (x_p,y_p),我通过一个公式计算这 n 个点中的每一个到达那里所需的时间;给定这 n 个点以一定的速度移动。
  • 我以 t_0、t_1、...t_n 的递增顺序对这些时间进行排序,其中 t_i 的精度设置为 1。即如果 t'_i=2.3453,那么我将只使用 t_i=2.3。
  • 假设时间是从正态分布生成的,我模拟了 3 个最快的时间,以找出这 3 个点最早到达的时间百分比。因此通过随机实验假设 prob_0 = 0.76,prob_1=0.20 和 prob_2=0.04。由于 t_0 在三者中排名第一,因此我还返回了该点的原始索引(在时间排序之前)。说 idx_0 = 5(整数)。
  • 因此,对于该平面上的每个点,我都会得到一对(prob,idx)。

假设这些点中的 n/2 是一种,其余的是另一种。生成的示例图像如下所示。

未优化

特别是当时间精度设置为 1 时,我注意到唯一 3 个时间元组 (t_0,t_1,t_2) 的数量仅为总数据点的 2.5%,即平面上的点数。这意味着在大多数情况下,内核只能使用先前模拟的值进行无用的模拟。因此,我可以使用一个字典,其键为时间的三元组,值作为索引和概率。由于据我所知和测试,STL 无法在内核内部访问,因此我构造了一个大小为 201000000 的浮点数组。这个选择是通过实验得出的,因为前 3 次都没有超过 20 秒。因此 t_0 可以从 {0.0,0.1,0.2,...,20.0} 中取任何值,因此有 201 个选择。我可以为这样的字典构造一个键,如下所示

  • 键 = t_o * 10^6 + t_1 * 10^3 + t_2

就值而言,我可以将其设为 (prob+idx)。由于 idx 是一个整数并且 0.0<=prob<=1.0,我可以稍后检索这两个值

  • prob=dict[key]-floor(dict[key])
  • idx = floor(dict[key])

所以现在我的内核如下所示

__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 被初始化为全零。基本思想是使数据结构在字典的特定位置“读取多次写入一次”。

我知道可能有更优化的方法来解决这个问题,而不是分配这么多的内存。在这种情况下请告诉我。但我真的很想了解为什么这个特定的解决方案会失败。特别是我想知道如何在这个设置中使用 atomicAdd 。我没有使用它。

4

1 回答 1

0

除非您在else分支中的模拟非常长(大约 100 次浮点运算),否则全局内存中的查找表可能比运行计算要慢。全局内存访问非常昂贵!

在任何情况下,都无法通过使用条件分支“跳过工作”来节省时间。GPU 的单指令多线程架构意味着分支两侧的指令连续执行,除非块中的所有线程都遵循同一分支。

编辑:

您看到由于引入条件分支而提高了性能并且您没有遇到任何死锁问题的事实表明每个块中的所有线程总是采用相同的分支。我怀疑一旦dict开始填充,性能提升就会消失。

也许我误解了一些东西,但是如果你想计算一个事件的概率x,假设一个正态分布并给出平均值mu和标准偏差sigma,就不需要生成大量随机数和近似高斯曲线。可以直接计算概率:

p = exp(-((x - mu) * (x - mu) / (2.0f * sigma * sigma))) / 
    (sigma * sqrt(2.0f * M_PI));
于 2013-11-27T11:20:43.293 回答