某些子网格未使用 CUDA 动态并行执行

2024-04-11

我正在尝试 CUDA 5.0 (GTK 110) 中的新动态并行功能。我遇到了一个奇怪的行为,即我的程序没有返回某些配置的预期结果,不仅是意外的,而且每次启动都会出现不同的结果。

现在我想我找到了问题的根源:似乎当生成太多子网格时,某些子网格(由其他内核启动的内核)有时不会执行同时.

我编写了一个小测试程序来说明这种行为:

#include <stdio.h>

__global__ void out_kernel(char* d_out, int index)
{
    d_out[index] = 1;
}

__global__ void kernel(char* d_out)
{
    int index = blockIdx.x * blockDim.x + threadIdx.x;
    out_kernel<<<1, 1>>>(d_out, index);
}

int main(int argc, char** argv) {

    int griddim = 10, blockdim = 210;
    // optional: read griddim and blockdim from command line
    if(argc > 1) griddim = atoi(argv[1]);
    if(argc > 2) blockdim = atoi(argv[2]);

    const int numLaunches = griddim * blockdim;
    const int memsize = numLaunches * sizeof(char);

    // allocate device memory, set to 0
    char* d_out; cudaMalloc(&d_out, memsize);
    cudaMemset(d_out, 0, memsize);

    // launch outer kernel
    kernel<<<griddim, blockdim>>>(d_out);
    cudaDeviceSynchronize();

    // dowload results
    char* h_out = new char[numLaunches];
    cudaMemcpy(h_out, d_out, memsize, cudaMemcpyDeviceToHost);

    // check results, reduce output to 10 errors
    int maxErrors = 10;
    for (int i = 0; i < numLaunches; ++i) {
        if (h_out[i] != 1) {
            printf("Value at index %d is %d, should be 1.\n", i, h_out[i]);
            if(maxErrors-- == 0) break;
        }
    }

    // clean up
    delete[] h_out;
    cudaFree(d_out);
    cudaDeviceReset();
    return maxErrors < 10 ? 1 : 0;
}

该程序在给定数量的块(第一个参数)中启动一个内核,每个块具有给定数量的线程(第二个参数)。然后,该内核中的每个线程将启动另一个具有单个线程的内核。该子内核将在输出数组(用 0 初始化)的其部分写入 1。

执行结束时,输出数组中的所有值都应为 1。但奇怪的是,对于某些块和网格大小,某些数组值仍然为零。这基本上意味着一些子网格没有被执行。

仅当同时生成许多子网格时才会发生这种情况。在我的测试系统(Tesla K20x)上,有 10 个块,每个块包含 210 个线程。不过,10 个具有 200 个线程的块可以提供正确的结果。但也有 3 个块(每个块有 1024 个线程)会导致错误。 奇怪的是,运行时没有报告任何错误。子网格似乎被调度程序忽略了。

其他人也面临同样的问题吗?此行为是否记录在某处(我没有找到任何内容),或者它确实是设备运行时中的错误?


你没有做错误检查 https://stackoverflow.com/questions/14038589/what-is-the-canonical-way-to-check-for-errors-using-the-cuda-runtime-api我能看到的任何类型。您可以而且应该在设备内核启动时执行类似的错误检查。请参阅文档 http://docs.nvidia.com/cuda/pdf/CUDA_Dynamic_Parallelism_Programming_Guide.pdf这些错误不一定会冒泡到主机:

每个线程都会记录错误,以便每个线程都可以识别它生成的最新错误。

您必须将它们困在设备中。文档中有很多此类设备错误检查的示例。

如果您进行适当的错误检查,您会发现在内核启动失败的每种情况下,cuda 设备运行时 API 都会返回错误 69,cudaErrorLaunchPendingCountExceeded.

如果您扫描文档 http://docs.nvidia.com/cuda/pdf/CUDA_Dynamic_Parallelism_Programming_Guide.pdf对于这个错误,你会发现:

cudaLimitDevRuntimePendingLaunchCount

控制为缓冲由于未解决的依赖性或缺乏执行资源而尚未开始执行的内核启动预留的内存量。当缓冲区已满时,launchs 会将线程的最后一个错误设置为cudaErrorLaunchPendingCountExceeded。默认待处理启动次数为 2048 次启动。

在 10 个块 * 200 个线程中,您将启动 2000 个内核,并且一切似乎都正常。

在 10 个块 * 210 个线程中,您将启动 2100 个内核,这超出了上面提到的 2048 个限制。

请注意,这本质上是动态的;根据您的应用程序启动子内核的方式,您可以轻松启动超过 2048 个内核,而不会达到此限制。但由于您的应用程序几乎同时启动所有内核,因此您已经达到了极限。

当您的 CUDA 代码未按您预期的方式运行时,建议进行适当的 cuda 错误检查。

如果您想对上述内容进行一些确认,您可以在代码中修改主内核,如下所示:

__global__ void kernel(char* d_out)
{
    int index = blockIdx.x * blockDim.x + threadIdx.x;
    out_kernel<<<1, 1>>>(d_out, index);
//    cudaDeviceSynchronize();  // not necessary since error 69 is returned immediately
    cudaError_t err = cudaGetLastError();
    if (err != cudaSuccess) d_out[index] = (char)err;
}

待处理的启动计数限制是可以修改的。请参阅文档cudaLimitDevRuntimePendingLaunchCount

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

某些子网格未使用 CUDA 动态并行执行 的相关文章

  • 动态获取当前LDAP路径

    我正在使用 C 和 NET Framework 4 0 开发一个库 我想检索所有活动目录用户 它效果很好 但我的问题是 如果我在另一个域上运行我的程序 我必须更改此设置 private static string ldapPath LDAP
  • C# 从字符串中删除 URL

    这看起来非常简单 但我尝试的一切似乎都不起作用 假设我有以下字符串 string myString http www mysite com folder file jpg 我该如何处理它以删除 URL 并仅保留 file jpg 作为字符串
  • 使用静态函数变量与类变量来存储某些状态

    可以说我有这样的功能 void processElement doSomething someArray lastProcessedElement 1 问题是 每次调用这个函数时 我都需要存储我调用 doSomething 的最后一个元素
  • Microsoft SQL Server,在服务器资源管理器中创建新表

    对于 C 编程作业 我必须在 Microsoft SQL Server 中创建一个表 我新安装了 Visual Studio 2013 和 Microsoft SQL Server 2012 当我安装它时 我指定了我的用户进行管理员访问 无
  • char* 与 const char* 作为参数

    我在使用的时候很多时候都会遇到编译错误char 代替const char 所以 我不确定实际的区别 语法和编译机制 如果您追求两者之间的差异 只需将它们视为 char 是一个指针 指向包含也可以更改的 char 类型值的位置 指针的值可以更
  • 在执行方法的括号内声明变量

    默认情况下 变量在方法执行之前定义 例如 DateTime myDate if DateTime TryParse date out myDate 我们可以实现内联声明 并且该变量可以在外部使用 例如 if DateTime TryPars
  • 硬币数量有限的最小硬币找零问题

    具体来说 问题是 给定面值数组coins 每个硬币的限制数组limits 和数量amount 返回minimum需要的硬币数量 以获得amount 或者如果不可能返回 null 另外填充数组change解决方案中使用的每个硬币的数量 这是我
  • 如何将类成员函数的返回类型设置为私有结构的对象

    很抱歉这个又长又令人困惑的标题 但我想不出更好的方法来问这个问题 所以 我有一堂课 template
  • 为什么 Clang 更喜欢主模板而不是 C++17 的专业化?

    下列program https godbolt org z f43EK4PnY从此代码中减少question https stackoverflow com questions 66740188 template
  • DateTimeOffset解析和自定义时区

    我们将 XML DateTime 值解析为 DateTimeOffset 值 根据DateTime 的 W3C XSD 文档 http www w3 org TR 2012 REC xmlschema11 2 20120405 dataty
  • 无需使用abs函数或if语句即可获取绝对值

    我在想如何在不使用的情况下获得整数的绝对值if声明也不abs 起初我使用的是左移位 lt lt 试图将负号移出范围 然后将位右移回原来的位置 但不幸的是它对我不起作用 请让我知道为什么它不起作用以及其他替代方法 From 位摆弄黑客 htt
  • C++:如何通过时间和本地时间获取实际时间?

    我正在寻找一种在 C 中以 HH MM SS 方式节省时间的方法 我在这里看到它们有很多解决方案 经过一番研究后我选择了time and localtime 然而 似乎localtime函数有点棘手 因为它says http rabbit
  • 当 Bool 变量变为 True 时更改标签

    我不太确定如何解释这一点 我将把代码放在伪代码中以便于阅读 我几乎想要一个标签在类的 bool 变量更改时更改其文本 我不确定我需要使用什么 因为我使用的是 WPF 并且该类不能只更改我不更改的标签你不觉得吗 我需要举办某种活动吗 或者 W
  • C++:ostream 和 ostringstream 有什么区别?

    ostream 和 ostringstream 有什么区别 你什么时候会使用其中一种而不是另一种 简单地说 ostringstream提供了一个streambuf ostream要求用户提供一份 要理解其中的含义 有必要了解一点 流是如何工
  • 可以匹配具有任意小数位数的非零浮点数的最短正则表达式是什么?

    可以匹配具有任意小数位数的非零浮点数的最短正则表达式是什么 它应该接受像这样的数字 1 5 9652 7 00002 0 8 0 0500 0 58000 0 01 0 000005 0 9900 5 7 5 7 005 但拒绝诸如 02
  • 当代码依赖于两个对象的子类型时,是否有设计模式可以处理

    我会尽力尽可能明确 以防有比回答我的问题更好的解决方案 我正在使用 C 工作 我有一个报告模板 可以包含任意数量的打开的 功能 功能可能是信息表 饼图 条形图 列表等 我将报告生成为文本文件或 PDF 将来可能有其他选项 到目前为止我有一个
  • gfortran 未定义的引用

    我正在尝试编译一个依赖很多东西的程序 我使用并修改了提供的 makefile 来代表我的计算机设置 但在编译的最后一步中我不断收到许多未定义的引用 导致问题的命令行是 gfortran o cosmomc ParamNames o Matr
  • 在 g++ 中链接文件

    最近我尝试用g 在Ubuntu上 编译一个程序 通常我使用 Dev C 在 Windows 上 只要我创建一个项目并将所有必要的文件放入其中 它就可以正常工作 编译程序时出现的错误是 filename cpp undefined refer
  • 判断一个点是否在多面体内部

    我试图确定某个特定点是否位于多面体内部 在我当前的实现中 我正在研究的方法采用我们正在寻找多面体面的数组 在本例中为三角形 但稍后可能是其他多边形 的点 我一直在尝试根据这里找到的信息进行工作 http softsurfer com Arc
  • 非通用接口是通用接口的同义词

    我在 C 中有一个通用接口 并且几乎总是将它与其中一种类型一起使用 我想为该类型创建一个非通用接口并使用它 假设我有以下代码 public interface IMyGenericList

随机推荐