Dynamic 基于CUDA的并行动态规划

Dynamic 基于CUDA的并行动态规划,dynamic,parallel-processing,cuda,Dynamic,Parallel Processing,Cuda,这是我第一次尝试用CUDA实现递归。目标是使用CUDA的强大功能从一组字符“12345”中提取所有组合,以动态并行化任务。这是我的内核: __device__ char route[31] = { "_________________________"}; __device__ char init[6] = { "12345" }; __global__ void Recursive(int depth) { // up to depth 6 if (depth == 5)

这是我第一次尝试用CUDA实现递归。目标是使用CUDA的强大功能从一组字符“12345”中提取所有组合,以动态并行化任务。这是我的内核:

__device__ char route[31] = { "_________________________"};
__device__ char init[6] = { "12345" };

__global__ void Recursive(int depth) {

    // up to depth 6
    if (depth == 5) return;     
    // newroute = route - idx

    int x = depth * 6;
    printf("%s\n", route);

    int o = 0;
    int newlen = 0;
    for (int i = 0; i<6; ++i)
    {
        if (i != threadIdx.x)
        {
            route[i+x-o] = init[i];
            newlen++;
        }
        else                
        {
            o = 1;
        }
    }

    Recursive<<<1,newlen>>>(depth + 1);

}

__global__ void RecursiveCount() {
    Recursive <<<1,5>>>(0); 

}
\uuuuuu设备\uuuuuuu字符路由[31]={“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
__设备_u; char init[6]={“12345”};
__全局无效递归(整数深度){
//最深6
如果(深度==5)返回;
//newroute=route-idx
int x=深度*6;
printf(“%s\n”,路由);
INTO=0;
int-newlen=0;
对于(int i=0;i
我做错了什么

我可能无法清楚地表达代码中的所有问题,但这些项目应该会让您更接近

  • 我建议提供一个。在我看来,它基本上是堆栈溢出所必需的,请参见第1项,注意“必须”一词的用法。您的示例缺少任何主机代码,包括原始内核调用。这只是几行额外的代码,为什么不包括它?当然,在这种情况下,我可以推断调用必须是什么,但为什么不包括它?无论如何,根据您指出的输出,似乎很明显主机启动的启动配置将你必须是

  • 这对我来说似乎不合逻辑:

    我希望内核会提示如下内容:

    2345_____________________

    内核要做的第一件事就是在对它进行任何更改之前打印出
    路由
    变量,因此我希望
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

  • 您可能会对
    \uuuu设备\uuuu
    变量的含义感到困惑。它是一个全局变量,并且只有一个副本。因此,当您在内核代码中修改它时,每个内核中的每个线程都在试图同时修改同一个全局变量。这不可能在任何线程中都有有序的结果我选择通过为每个线程制作一个本地副本来“修复”这个问题

  • 此循环中存在off-by-1错误和区段错误:

    for (int i = 0; i<6; ++i)
    

    Robert Crovella在第5点给出的答案是正确的,错误在于在每次递归调用中使用
    init
    ,但我想澄清一些对其他CUDA初学者有用的东西

    我之所以使用这个变量,是因为当我试图启动传递局部变量的子内核时,总是会遇到异常:
    错误:指向本地内存的指针不能作为参数传递给启动

    由于我是C#专家开发人员,我不习惯使用指针(
    Ref
    做底层工作),所以我认为在CUDA/C编程中没有办法做到这一点

    正如Robert在其代码中所示,可以使用
    memalloc
    复制指针,将其用作可引用的参数

    下面是一个简化为深度递归示例的内核

    __device__ char init[6] = { "12345" };
    
    __global__ void Recursive(int depth, const char* route) {
    
        // up to depth 6
        if (depth == 5) return;
    
        //declaration for a referable argument (point 6)
        char* newroute = (char*)malloc(6); 
        memcpy(newroute, route, 5);
    
        int o = 0;
        int newlen = 0;
        for (int i = 0; i < (6 - depth); ++i)
        {
            if (i != threadIdx.x)
            {
                newroute[i - o] = route[i];
                newlen++;
            }
            else
            {
                o = 1;
            }
        }
    
        printf("%s\n", newroute);
    
        Recursive <<<1, newlen>>>(depth + 1, newroute);
    
    }
    
    __global__ void RecursiveCount() {
        Recursive <<<1, 5>>>(0, init);
    }
    
    \uuuu设备\uuuuu字符初始化[6]={“12345”};
    __全局无效递归(整数深度,常量字符*路由){
    //最深6
    如果(深度==5)返回;
    //可引用参数的声明(第6点)
    char*newroute=(char*)malloc(6);
    memcpy(新路线,路线5);
    INTO=0;
    int-newlen=0;
    对于(int i=0;i<(6-深度);+i)
    {
    如果(i!=threadIdx.x)
    {
    新路线[i-o]=路线[i];
    newlen++;
    }
    其他的
    {
    o=1;
    }
    }
    printf(“%s\n”,newroute);
    递归(深度+1,新路线);
    }
    __全局_uuu无效递归计数(){
    递归(0,init);
    }
    
    我不添加主调用,因为我使用ManagedCUDA for C#,但正如Robert所说,可以计算出调用
    RecursiveCount
    的方式


    关于用
    /0
    结束字符数组…抱歉,我不知道确切的好处是什么;没有它们,这段代码可以正常工作。

    如果需要调试帮助,请提供一个.和提示:C字符串必须是
    \0
    terminated@talonmies这个内核不仅仅是一个最小的可复制示例,您只需粘贴此代码并调用R来自主机的ecursiveCount()。我们应该猜一下您启动它时使用了多少线程吗?如果只需要添加几行代码就可以将其添加到,您真的懒得添加它们吗?@talonmies您不需要猜任何东西。Recursive(0);表示1个块和5个线程,您可以在main调用中找到它。这是动态并行编程…您可以在此处了解更多信息:RecursiveCount是一个内核。您没有显示启动参数。这就是我所指的。printf仍然存在未定义的行为。路由应为零终止以进行更正我尝试为零终止我的代码中既有
    nroute
    也有
    myinit
    ,虽然我没有在注释列表中列举它。这里可能还有一个逻辑错误。我在使用它之前将它复制到
    nroute
    中,从而避免了对
    route
    本身的零终止的担忧,
    nroute
    是零终止的。对不起,我错过了d复制到后添加到nroute的零终止it@RobertCrovella…您发现了错误(第5点),您帮助我了解如何将价值观从父母传递给孩子(第6点)这导致了我的错误。Thx很多。我不会只关注第5点。第3点、第4点、第5点都是与CUDA关系不大的逻辑错误,但代表了正确使用递归技术或常规编程的失败。第3点、第4点、第5点中的任何一个问题都会导致程序输出与CUDA之间的显著偏差这是我的目标。其中大约有4个错误。我不想告诉未来的读者,唯一重要的是第5点,或者第5点和第6点。
    __device__ char init[6] = { "12345" };
    
    __global__ void Recursive(int depth, const char* route) {
    
        // up to depth 6
        if (depth == 5) return;
    
        //declaration for a referable argument (point 6)
        char* newroute = (char*)malloc(6); 
        memcpy(newroute, route, 5);
    
        int o = 0;
        int newlen = 0;
        for (int i = 0; i < (6 - depth); ++i)
        {
            if (i != threadIdx.x)
            {
                newroute[i - o] = route[i];
                newlen++;
            }
            else
            {
                o = 1;
            }
        }
    
        printf("%s\n", newroute);
    
        Recursive <<<1, newlen>>>(depth + 1, newroute);
    
    }
    
    __global__ void RecursiveCount() {
        Recursive <<<1, 5>>>(0, init);
    }