首页 文章

CUDA中的动态编程:用于与子内核交换数据的全局内存分配

提问于
浏览
1

我有以下代码:

__global__ void interpolation(const double2* __restrict__ data, double2* __restrict__ result, const double* __restrict__ x, const double* __restrict__ y, const int N1, const int N2, int M)
{
    int i = threadIdx.x + blockDim.x * blockIdx.x;

    [...]        

    double phi_cap1, phi_cap2;

    if(i<M) {   

         for(int m=0; m<(2*K+1); m++) {

              [calculate phi_cap1];

              for(int n=0; n<(2*K+1); n++) {

                 [calculate phi_cap2];

                 [calculate phi_cap=phi_cap1*phi_cap2];

                 [use phi_cap];

             }
    }

}

}

我想在Kepler K20卡上使用动态编程将 phi_cap1phi_cap2 的处理并行调度到一堆线程,以减少计算时间 . K=6 在我的代码中,所以我启动了一个 13x13 线程的块 .

遵循CUDA动态并行编程指南,我在全局内存中分配了一个 169 _的 169 元素(由 phi_cap1phi_cap2 的产品构成),这些元素是与子内核交换数据所必需的 . 确实,引用指南,

作为一般规则,传递给子内核的所有存储都应该从全局内存堆中显式分配 .

然后我用以下代码结束了

__global__ void interpolation(const double2* __restrict__ data, double2* __restrict__ result, const double* __restrict__ x, const double* __restrict__ y, const int N1, const int N2, int M)
{
    int i = threadIdx.x + blockDim.x * blockIdx.x;

    [...]   

    dim3 dimBlock(2*K+1,2*K+1); dim3 dimGrid(1,1);

    if(i<M) {   

    double* phi_cap; cudaMalloc((void**)&phi_cap,sizeof(double)*(2*K+1)*(2*K+1));

    child_kernel<<<dimGrid,dimBlock>>>(cc_diff1,cc_diff2,phi_cap);

    for(int m=0; m<(2*K+1); m++) {

        for(int n=0; n<(2*K+1); n++) {

                        [use phi_cap];

        }
    }

}

}

问题是第一个例程运行 5ms ,而第二个例程,即使通过注释 child_kernel 启动,也需要 23ms ,几乎所有时间都花在了 cudaMalloc API上 .

因为在动态编程中,人们经常需要分配内存空间来与子内核交换数据,唯一的解决方案似乎是全局内存需要花费很多时间,在我看来,动态编程的有用性的一个严重瓶颈就是数据交换,除非有办法规避全局内存分配问题 .

那么问题是:上述问题是否有任何解决方法,即从内核中分配全局内存需要花费大量时间?谢谢

SOLUTION PROPOSED IN THE COMMENTS

从父内核外部分配所需的全局内存 . 我已经验证从父内核之外分配所需的全局内存要快得多 .

1 回答

  • 4

    你从每个线程调用cudaMalloc,其中i <M表示你正在进行M cudaMalloc调用 .

    M越大,它就越糟糕 .

    相反,你可以从块的第一个线程调用一个cudaMalloc,分配M次你之前使用的大小(实际上在你的情况下你应该分配更多,所以每个块都正确对齐) . 在同步线程之后,您可以为每个子内核使用正确计算的phi_cap地址启动子内核 .

    或者(如果您的特定情况允许您分配足够的内存,您可以在内核调用之间保留),您可以在内核之外分配内存并重用它 . 那会更快 . 如果M在内核调用之间变化,则可以根据最大M的需要进行分配 .

相关问题