CUDA racecheck、共享内存数组和 cudaDeviceSynchronize()

2024-02-03

我最近发现了比赛检查的工具cuda内存检查,在 CUDA 5.0 中可用(cuda-memcheck --tool racecheck,参见英伟达文档 http://docs.nvidia.com/cuda/cuda-memcheck/index.html#using-racecheck)。该工具可以检测 CUDA 内核中共享内存的竞争条件。

在调试模式下,该工具没有检测到任何东西,这显然是正常的。但是,在发布模式下(-O3),根据问题的参数,我会收到错误。

下面是一个错误示例(第 22 行共享内存初始化,第 119 行赋值):

========= ERROR: Potential WAW hazard detected at __shared__ 0x0 in block (35, 0, 0) :
=========     Write Thread (32, 0, 0) at 0x00000890 in ....h:119:void kernel_test3<float, unsigned int=4, unsigned int=32, unsigned int=64>(Data<float, unsigned int=4, unsigned int=32, unsigned int=64>*)
=========     Write Thread (0, 0, 0) at 0x00000048 in ....h:22:void kernel_test3<float, unsigned int=4, unsigned int=32, unsigned int=64>(Data<float, unsigned int=4, unsigned int=32, unsigned int=64>*)  
=========     Current Value : 13, Incoming Value : 0
  1. 首先让我惊讶的是线程 ID。当我第一次遇到这个错误时,每个块包含 32 个线程(id 0 到 31)。那么为什么线程id 32会出现问题呢?我什至添加了额外的检查threadIdx.x,但这没有改变任何事情。
  2. 我使用共享内存作为临时缓冲区,每个线程处理自己的多维数组参数,例如__shared__ float arr[SIZE_1][SIZE_2][NB_THREADS_PER_BLOCK]。我真的不明白怎么可能存在任何竞争条件,因为每个线程都处理自己的共享内存部分。
  3. 将网格大小从 64 个块减少到 32 个块似乎可以解决该问题(每个块 32 个线程)。我不懂为什么。

为了了解发生了什么,我使用一些更简单的内核进行了测试。 让我向您展示一个产生此类错误的内核示例。基本上,这个内核使用SIZE_X*SIZE_Y*NTHREADS*sizeof(float)字节的共享内存,每个 SM 可以使用 48KB 的共享内存。

test.cu

template <unsigned int NTHREADS>
__global__ void kernel_test()
{
    const int SIZE_X = 4;
    const int SIZE_Y = 4;

    __shared__ float tmp[SIZE_X][SIZE_Y][NTHREADS];

    for (unsigned int i = 0; i < SIZE_X; i++)
        for (unsigned int j = 0; j < SIZE_Y; j++)
            tmp[i][j][threadIdx.x] = threadIdx.x;
}

int main()
{
  const unsigned int NTHREADS = 32;

  //kernel_test<NTHREADS><<<32, NTHREADS>>>(); // ---> works fine
  kernel_test<NTHREADS><<<64, NTHREADS>>>();

  cudaDeviceSynchronize(); // ---> gives racecheck errors if NBLOCKS > 32
}

汇编:

nvcc test.cu --ptxas-options=-v -o test

如果我们运行内核:

cuda-memcheck --tool racecheck test
  • kernel_test<32><<<32, 32>>>();:32 个块,32 个线程 => 不会导致任何明显的竞赛检查错误。

  • kernel_test<32><<<64, 32>>>();:64 个块,32 个线程 => 导致 WAW 危险(threadId.x= 32?!)和错误。

    ========= ERROR: Potential WAW hazard detected at __shared__ 0x6 in block (57, 0, 0) :  
    =========     Write Thread (0, 0, 0) at 0x00000048 in ....h:403:void kernel_test(void)  
    =========     Write Thread (1, 0, 0) at 0x00000048 in ....h:403:void kernel_test(void)  
    =========     Current Value : 0, Incoming Value : 128  
    
    ========= INFO:(Identical data being written) Potential WAW hazard detected at __shared__ 0x0 in block (47, 0, 0) :  
    =========     Write Thread (32, 0, 0) at 0x00000048 in ....h:403:void kernel_test(void)  
    =========     Write Thread (0, 0, 0) at 0x00000048 in ....h:403:void kernel_test(void)  
    =========     Current Value : 0, Incoming Value : 0  
    

那么我在这里缺少什么?我在共享内存方面做错了什么吗? (我还是个初学者)

Update:

问题似乎来自于cudaDeviceSynchronize() when NBLOCKS > 32。为什么会发生这种情况?


对于初学者来说,cudaDeviceSynchronize() 不是原因;您的内核是原因,但它是异步调用,因此在调用 cudaDeviceSynchronize() 时会捕获错误。

对于内核,共享内存的大小为 SIZE_X*SIZE_Y*NTHREADS (在示例中转换为每块 512 个元素)。在嵌套循环中,您使用 [i*blockDim.x*SIZE_Y + j*blockDim.x + threadIdx.x] 对其进行索引 - 这就是您的问题所在。

更具体地说,您的 i 和 j 值的范围为 [0, 4),您的 threadIdx.x 的范围为 [0, 32),您的 SIZE_{X | Y} 值为 4。 当 blockDim.x 为 64 时,循环中使用的最大索引将为 991(来自 3*64*4 + 3*64 + 31)。当您的 blockDim.x 为 32 时,您的最大索引将为 511。

根据您的代码,只要您的 NBLOCKS 超过 NTHREADS,您就应该收到错误

注意:我最初将其发布到https://devtalk.nvidia.com/default/topic/527292/cuda-programming-and-performance/cuda-racecheck-shared-memory-array-and-cudadevicesynchronize-/ https://devtalk.nvidia.com/default/topic/527292/cuda-programming-and-performance/cuda-racecheck-shared-memory-array-and-cudadevicesynchronize-/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA racecheck、共享内存数组和 cudaDeviceSynchronize() 的相关文章

  • 无法从静态初始化代码启动 CUDA 内核

    我有一个在其构造函数中调用内核的类 如下所示 标量场 h include
  • 构建 Erlang 服务器场(用于业余爱好项目)最便宜的方法是什么? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 假设我们有一个 本质上并行 的问题需要用 Erlang 软件来解决 我们有很多并行进程 每个进程都执行顺序代码 不是数字运算 并且我们向它们投入的 C
  • 为什么GK110有192个核心和4个扭曲?

    我想感受一下开普勒的架构 但这对我来说没有意义 如果一个 warp 有 32 个线程 其中 4 个被调度 执行 则意味着 128 个核心正在使用 64 个核心处于空闲状态 白皮书中提到了独立指令 那么64核是为这些指令保留的吗 如果是这样
  • 将 GPUJPEG 项目移植到 Windows

    我目前正在尝试移植 GPUJPEG 在 Sourceforge 上 http sourceforge net projects gpujpeg 库 基于 CUDA 从 Unix 到 Windows 现在我被卡住了 我不知道发生了什么或为什么
  • connect-redis - 如何保护会话对象免受竞争条件影响

    我使用 nodejs 和 connect redis 来存储会话数据 我将用户数据保存在会话中 并在会话生命周期中使用它 我注意到两个更改会话数据的请求之间可能存在竞争条件 我尝试过使用 redis lock 来锁定会话 但这对我来说有点问
  • CUDA:如何在设备上填充动态大小的向量并将其内容返回到另一个设备函数?

    我想知道哪种技术可以填充设备上的动态大小数组 int row 在下面的代码中 然后返回其内容 以供另一个设备函数使用 为了将问题置于上下文中 下面的代码尝试使用在 GPU 上运行的高斯 勒让德求积来跨越勒让德多项式基组中的任意函数 incl
  • cudaMallocManaged() 返回“不支持的操作”

    在 CUDA 6 0 中尝试托管内存给了我operation not supported打电话时cudaMallocManaged include cuda runtime h include
  • 寻找 CUDA 中的最大值

    我正在尝试在 CUDA 中编写代码来查找最大值 对于给定的一组数字 假设您有 20 个数字 并且内核在 2 个块 每块 5 个线程 上运行 现在假设 10 个线程同时比较前 10 个值 并且thread 2找到最大值 因此线程 2 正在更新
  • “计算能力”是什么意思? CUDA?

    我是CUDA编程新手 对此了解不多 您能告诉我 CUDA 计算能力 是什么意思吗 当我在大学服务器上使用以下代码时 它向我显示了以下结果 for device 0 device lt deviceCount device cudaDevic
  • 同时使用 2 个 GPU 调用 cudaMalloc 时性能较差

    我有一个应用程序 可以在用户系统上的 GPU 之间分配处理负载 基本上 每个 GPU 都有一个 CPU 线程来启动一个GPU处理间隔当由主应用程序线程定期触发时 考虑以下图像 使用 NVIDIA 的 CUDA 分析器工具生成 作为示例GPU
  • CUDA程序导致nvidia驱动程序崩溃

    当我超过大约 500 次试验和 256 个完整块时 我的 monte carlo pi 计算 CUDA 程序导致我的 nvidia 驱动程序崩溃 这似乎发生在 monteCarlo 内核函数中 任何帮助都会受到赞赏 include
  • CUDA 中的广义霍夫变换 - 如何加快分箱过程?

    正如标题所示 我正在对并行计算机视觉技术进行一些个人研究 使用 CUDA 我尝试实现 GPGPU 版本的霍夫变换 我遇到的唯一问题是在投票过程中 我调用atomicAdd 来防止多个同时写入操作 但我似乎没有获得太多的性能效率 我在网上搜索
  • 传递给 CUDA 的结构中的指针

    我已经搞砸了一段时间了 但似乎无法正确处理 我正在尝试将包含数组的对象复制到 CUDA 设备内存中 然后再复制回来 但当我遇到它时我会跨过那座桥 struct MyData float data int dataLen void copyT
  • CUDA Thrust 和 sort_by_key

    我正在寻找 CUDA 上的排序算法 它可以对元素数组 A 双精度 进行排序 并返回该数组 A 的键 B 数组 我知道sort by keyThrust 库中的函数 但我希望元素数组 A 保持不变 我能做些什么 我的代码是 void sort
  • MPI+CUDA 与纯 MPI 相比有何优势?

    加速应用程序的常用方法是使用 MPI 或更高级别的库 例如在幕后使用 MPI 的 PETSc 并行化应用程序 然而 现在每个人似乎都对使用 CUDA 来并行化他们的应用程序或使用 MPI 和 CUDA 的混合来解决更雄心勃勃 更大的问题感兴
  • 如何确定完整的 CUDA 版本 + 颠覆版本?

    Linux 上的 CUDA 发行版曾经有一个名为version txt例如 CUDA Version 10 2 89 这非常有用 但是 从 CUDA 11 1 开始 该文件不再存在 我如何在 Linux 上通过命令行确定并检查 path t
  • 运行时 API 应用程序中的 cuda 上下文创建和资源关联

    我想了解如何在 cuda 运行时 API 应用程序中创建 cuda 上下文并与内核关联 我知道这是由驱动程序 API 在幕后完成的 但我想了解一下创作的时间线 首先 我知道 cudaRegisterFatBinary 是第一个 cuda a
  • __syncthreads() 死锁

    如果只有部分线程执行 syncthreads 会导致死锁吗 我有一个这样的内核 global void Kernel int N int a if threadIdx x
  • cuda中有模板化的数学函数吗? [复制]

    这个问题在这里已经有答案了 我一直在寻找 cuda 中的模板化数学函数 但似乎找不到 在普通的 C 中 如果我调用std sqrt它是模板化的 并且将根据参数是浮点数还是双精度数执行不同的版本 我想要这样的 CUDA 设备代码 我的内核将真
  • 如何在cmake中添加cuda源代码的定义

    我使用的是 Visual Studio 2013 Windows 10 CMake 3 5 1 一切都可以使用标准 C 正确编译 例如 CMakeLists txt project Test add definitions D WINDOW

随机推荐