Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CUDA全球屏障——作用于开普勒而非费米_Cuda - Fatal编程技术网

CUDA全球屏障——作用于开普勒而非费米

CUDA全球屏障——作用于开普勒而非费米,cuda,Cuda,以下全局势垒适用于开普勒K10,而非费米GTX580: __global__ void cudaKernel (float* ref1, float* ref2, int* lock, int time, int dim) { int gid = blockIdx.x * blockDim.x + threadIdx.x; int lid = threadIdx.x; int numT = blockDim.x * gridDi

以下全局势垒适用于开普勒K10,而非费米GTX580:

__global__ void cudaKernel (float* ref1, float* ref2, int* lock, int time, int dim) {
  int gid  = blockIdx.x * blockDim.x + threadIdx.x;
  int lid  = threadIdx.x;                          
  int numT = blockDim.x * gridDim.x;               
  int numP = int (dim / numT);                     
  int numB = gridDim.x;

  for (int t = 0; t < time; ++t) {
    // compute @ time t
    for (int i = 0; i < numP; ++i) {
      int idx  = gid + i * numT;
      if (idx > 0 && idx < dim - 1)
        ref2 [idx]  = 0.333f * ((ref1 [idx - 1] + ref1 [idx]) + ref1 [idx + 1]);
    }

    // global sync
    if (lid == 0){
      atomicSub (lock, 1);
      while (atomicCAS(lock, 0, 0) != 0);
    }
    __syncthreads();

    // copy-back @ time t
    for (int i = 0; i < numP; ++i) {
      int idx  = gid + i * numT;
      if (idx > 0 && idx < dim - 1)
        ref1 [idx]  = ref2 [idx];
    }

    // global sync
    if (lid == 0){
      atomicAdd (lock, 1);
      while (atomicCAS(lock, numB, numB) != numB);
    }
    __syncthreads();
  }
}
\uuuu全局\uuuuu无效cudaKernel(浮点*ref1,浮点*ref2,整数*lock,整数时间,整数dim){
int gid=blockIdx.x*blockDim.x+threadIdx.x;
int lid=threadIdx.x;
int numT=blockDim.x*gridDim.x;
int numP=int(dim/numT);
int numB=gridDim.x;
for(int t=0;t0&&idx0&&idx
因此,通过查看发送回CPU的输出,我注意到有一个线程(第一个或最后一个线程)逃过了障碍,比其他线程更早地恢复执行。我正在使用CUDA 5.0。块的数量也总是小于SMs的数量(在我的运行集合中)


知道为什么相同的代码不能在两种体系结构上工作吗?开普勒有什么新功能可以帮助实现全局同步?

因此我怀疑屏障代码本身可能也在以同样的方式工作。看起来,与屏障功能本身无关的其他数据结构上发生的事情才是问题所在

尼瑟·开普勒和费米都有相互关联的L1缓存。您发现(尽管它与屏障代码本身无关)和之间的一级缓存行为不同

特别是,开普勒一级缓存在全局负载上不起作用,如上面链接中所述,因此缓存行为在设备范围内的二级处理,因此是一致的。当开普勒SMX读取它的全局数据时,它从L2获得一致的值

另一方面,费米具有也参与全局加载的L1缓存(默认情况下——尽管可以关闭此行为),并且上面链接中描述的L1缓存对于每个费米SM都是唯一的,并且与其他SMs中的L1缓存不一致。当费米SM读取其全局数据时,它从L1获取值,这可能与其他SMs中的其他L1缓存不一致

这就是您所看到的“一致性”的差异,即您在屏障前后操作的数据的一致性


正如我提到的,我相信屏障代码本身在两种设备上的工作方式可能是相同的

如果你在断言这不起作用的时候多加一些实质性的东西,那就好了。提供一个特定的完整示例,以及您测试的两个设备上的实际和预期输出,将很有帮助。根据我所看到的,由于atomicCAS指令生成的访问将在threadblocks之间序列化,我完全希望threadblocks以串行方式退出“屏障”。因此,在任何情况下,我都希望一个线程块比其他线程块更早地恢复执行。因此,我对你们所定义的差异和“通过”或“失败”感兴趣。开普勒GK110全球原子操作是。对于从单独SMs发出的原子,它们可以有效地背对背,并以开普勒GK110(K20)的核心时钟频率完成。我的观点是,这将比费米序列化/完成快得多。然而,根据您的代码,这并不影响退出屏障仍然是ThreadBlock之间的串行操作这一事实。K10不是GK110。因此,我编写的代码为每个CUDA线程提供一个索引(例如,映射到1D数组a[I]),并要求每个线程从全局内存中获取3个相邻数据元素(a[I-1]、a[I]、a[I+1]),并计算平均值。稍后,在每个线程停止在“全局”屏障后,继续并更新原始数据数组。整个事情重复了好几次。因此,每个线程执行以下循环:对于(t=0到t){compute;sync;copy;sync}@Naseria,由于内核正在执行全局内存访问,因此除了全局屏障之外,还应该使用全局内存围栏。您可能还需要将指针限定为volatile或在禁用L1缓存的情况下编译。请按照Robert的建议提供一个完整的例子。我用CUDA内核更新了原始帖子。这是一个1-D三点雅可比式代码。输入数组是“ref1”,“ref2”是用于复制回的临时数组,“lock”是全局互斥锁,“time”是时间步数,“dim”是数据元素总数。我已经测试了内存围栏“\uuuThreadFence()”,但没有任何帮助。然而,“易失性”技巧是有帮助的。问题似乎在于一些数据元素如何缓存在L1中,通过使用“volatile”关键字,我确保这些元素“ref1和ref2数组”不会缓存在L1中。我仍然不太相信屏障功能。这段代码的一个奇怪之处是,当我没有使用“volatile”时,对于t>1(意味着重新使用已经缓存的数据),每个线程块中只有“一个”线程(第一个或最后一个线程)似乎没有得到“最新值”,从而弄乱了结果。尽管它已经用“volatile”解决方案解决了,但仍然是个谜,为什么只有一个线程?这就是我第一次开始研究全局屏障的原因。你说添加到参考文献1和参考文献2时,
volatile
修复了代码。对吗?如果是这样的话,我看不出这和巴里之间有什么逻辑联系