【问题标题】:How can I synchronize threads within warp in conditional while statement in CUDA?如何在 CUDA 中的条件 while 语句中同步 warp 中的线程?
【发布时间】:2020-01-02 16:02:25
【问题描述】:

假设我们有以下代码:

while (condition) {
  ...

  for (uint32_t gap = x >> 1; gap > 0; gap >>= 1) {
    val += __shfl_down_sync(mask, val, gap);
  }

  if (warpLane == 0)
    atomicAdd(&global_memory[threadIdx.x], val);

  ...
}

在这种情况下,如果warp中的线程按以下顺序进入while循环:

全部 32 个线程,全部 32 个线程,只有 16 个线程。

如何获得参与 while 循环语句的线程掩码?

根据https://devblogs.nvidia.com/using-cuda-warp-level-primitives 中描述的指南,以下代码可能会导致未定义的行为:

while (condition) {
  uint32_t active = __activemask();
  for (uint32_t gap = x >> 1; gap > 0; gap >>= 1) {
    val += __shfl_down_sync(active, val, gap);
  }

  if (warpLane == 0)
    atomicAdd(&global_memory[threadIdx.x], val);

  ...
}

根据指南,__activemask() 可能不会像我预期的那样生成掩码。

根据上述指南,以下也会导致未定义的行为:

while (condition) {
  uint32_t active = __activemask();
  for (uint32_t gap = x >> 1; gap > 0; gap >>= 1) {
    val += __shfl_down_sync(active, val, gap);
  }

  if (warpLane == 0)
    atomicAdd(&global_memory[threadIdx.x], val);

  ...
  __warpsync(active);
}

那么,如何正确获取口罩呢?

【问题讨论】:

    标签: cuda


    【解决方案1】:

    您可以使用cooperative groups 喜欢:

    #include <cooperative_groups.h>
    namespace cg = cooperative_groups;
    
    while (condition) { 
    ...
    auto active = cg::coalesced_threads(); // this line can be moved out of while if the condition does not cause thread divergence
    
     for (uint32_t gap = x >> 1; gap > 0; gap >>= 1) { 
            //val += __shfl_down_sync(mask, val, gap);
            val += active.shfl_down(val, gap);
     }
     if (warpLane == 0)
        atomicAdd(&global_memory[threadIdx.x], val); 
    
    ... 
    }
    

    如果你想自己生成面具并做老式的你可以使用:

    uint32_t FullMask = 0xFFFFFFFF;
    uint32_t mask =  __ballot_sync(FullMask, someCondition);
    

    但是,如果您在代码中有进一步的分支,则必须始终在分支之前跟踪 mask,并在 ballot 中使用它而不是 FullMask。所以分支之前的第二次更新将是:

    uint32_t newMask =  __ballot_sync(mask, someNewCondition);
    

    【讨论】:

    • while 循环中的 coalesced_threads() 是否保证收集活动时的同步?
    • @sungjuncho 这取决于架构。组(活动)全部同步。不在组中的线程在 >Volta arch 中不同步
    • @sungjuncho 如果你想同步整个warp,你必须强制每个人进入while循环并让那些处于空闲状态的人保持空闲
    • 你的意思是所有调用 coalesced_threads() 的线程在调用这个函数的时候同步吗? (我不在乎其他不调用此函数的线程)我问它的原因是我不想要像 activemask() 这样的行为,也就是说,活动线程可能会导致意外的掩码,因为它们可以在不同的位置调用 activemask()时间。
    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-04
    相关资源
    最近更新 更多