【问题标题】:Avoid warp divergence避免翘曲发散
【发布时间】:2015-12-10 09:13:08
【问题描述】:

我有布尔一维数组T[N] 控制移位值,如下所示:

**a: 指向全局内存中n*n 矩阵的指针数组 我想为每个矩阵a 构造一个 shift*Identity 来获得:

a=a-shift*eye(n)

我有:

__device__ bool T[N];
__device__ float shift1[N];
__device__ float shift2[N];
__device__ float* a[N];

shift的值由T控制 如果 T[i]==true => shift=shift1 否则 shift=shift2;

int tid=threadIdx.x;

      if(tid < N){

              if(T[tid]){

               for (int i=0;i<n;i++){

                   a[tid][i*n+i]=a[tid][i*n+i]-shift1[tid];
               }

            }
        else {

          for (int i=0;i<n;i++){

                   a[tid][i*n+i]=a[tid][i*n+i]-shift2[tid];
               }
            }
        }
      __syncthreads();

这将导致扭曲发散并减慢我的代码。是否有避免上述循环的扭曲发散的技巧?

【问题讨论】:

  • 感谢您的评论..我是初学者,我怀疑我是否能理解汇编代码..我认为如果我们在 if-then-else 语句中使用条件分支会自动发生扭曲分歧即,如果单个经纱中的某些线程评估为“真”而其他线程评估为“假”

标签: c cuda gpu-warp


【解决方案1】:

正如@AnastasiyaAsadullayeva 所建议的那样,我相信对您的代码进行相当简单的转换可能会减少您对扭曲发散的担忧:

int tid=threadIdx.x;
  float myshift;
  if (T[tid]) myshift = shift1[tid];
  else myshift = shift2[tid];
  if(tid < N){
           for (int i=0;i<n;i++){

               a[tid][i*n+i]=a[tid][i*n+i]-myshift;
           }

        }
  __syncthreads();

编译器将预测myshift 的加载(创建已经提到的“条件加载”)。这种预测将负载本身的发散成本降至最低。此转换下此代码的其余部分是非发散的(tid &gt;= N 除外,这应该是无关紧要的)。

同样,如前所述,编译器可能已经观察到并完成了整个转换。这是可能的,但如果不运行您未提供的实际完整测试用例,则无法确认。

更好的方法是以您认为自然的方式编写代码,然后让编译器处理它。此时,您可以使用分析器和分析驱动的优化来确定翘曲发散是否实际上是您代码中的性能问题(分析器有指标和其他方法来评估翘曲发散并在您的代码中指示其严重性。)

【讨论】:

  • 感谢您的回答..在发布问题之前,我尝试使用可视化分析器检测分歧,但收到一条错误消息..事实上,我的代码使用动态并行性,我只有一个CUDA GPU
猜你喜欢
  • 1970-01-01
  • 2019-09-28
  • 2013-02-04
  • 2015-01-10
  • 2015-01-23
  • 2014-01-18
  • 2016-11-24
  • 1970-01-01
  • 2013-07-01
相关资源
最近更新 更多