CUDA-在内核中动态重新分配更多全局内存

CUDA-在内核中动态重新分配更多全局内存,cuda,kernel,nvidia,dynamic-memory-allocation,memory-reallocation,Cuda,Kernel,Nvidia,Dynamic Memory Allocation,Memory Reallocation,我对以下任务有一个问题: 给定一个二维数组“a[N][M]”,那么N条长度为M的线。 数组的每个元素都包含一个介于0和16之间的随机整数值。 编写一个内核“compact(int*a,int*listM,int*listN)”,它只包含一个由N个线程组成的块,每个线程对数组的一行计数有多少个元素的值为16 线程将这些数字写入共享内存中长度为N的数组“num”,然后(在障碍之后)其中一个线程执行下面列出的前缀代码“PrefixSum(int*num,int N)”(在下面的代码中,我解释了这段代码

我对以下任务有一个问题:

给定一个二维数组“a[N][M]”,那么N条长度为M的线。 数组的每个元素都包含一个介于0和16之间的随机整数值。 编写一个内核“compact(int*a,int*listM,int*listN)”,它只包含一个由N个线程组成的块,每个线程对数组的一行计数有多少个元素的值为16

线程将这些数字写入共享内存中长度为N的数组“num”,然后(在障碍之后)其中一个线程执行下面列出的前缀代码“PrefixSum(int*num,int N)”(在下面的代码中,我解释了这段代码的作用)。 最后(同样是屏障),每个线程“Idx”将其行中值为16的元素的N值和M值(或“x坐标和y坐标”)写入全局内存中的两个数组“listM”和“listN”,从这些数组中的位置“num[Idx]”开始。 为了更容易地实现最后一个任务,有上面提到的前缀代码。”

我已经编写了一个内核和一个合适的main来测试它。然而,我仍然有一个我无法解决的问题

在两个数组“listeM”和“listeN”中,应存储数组“a[M][N]”中出现的每16个单独位置。 因此,它们的大小必须等于16个事件的总数,这可能会有所不同

因为您不知道值为16的元素的确切数量,所以您只知道内核运行时两个数组“listeM”和“listeN”需要多少内存。 当然,您可以在程序启动时释放足够的内存以达到最大可能的数量,即N乘以M,但这将是非常低效的。 是否可以编写内核,以便每个线程在计算行中值为16的元素数(仅此数)后,动态放大两个数组“listeM”和“listeN”

这是我的内核:

__global__ void compact(int* a, int* listM, int* listN)
{
    int Idx = threadIdx.x;
    int elements, i;

    i = elements = 0;

    __shared__ int num[N];

    for (i = 0; i < M; i++)
    {
        if (a[Idx][i] == 16)
        {
            elements++;
        }
    }
    num[Idx] = elements;

        //Here at this point, the thread knows the number of elements with the value 16 of its line and would 
        //need to allocate just as much extra memory in "listeM" and "listeN". Is that possible ?

    __syncthreads();

    if (Idx == 0)
    {
                //This function sets the value of each element in the array "num" to the total value of the 
                //elements previously counted in all lines with the value 16.
                //Example: Input: num{2,4,3,1} Output: num{0,2,6,9}
        PrefixSum(num, N);
    }

    __syncthreads();

        // The output of PrefixSum(num, N) can now be used to realize the last task (put the "coordinates" of 
        //each 16 in the two arrays ("listM" and "listN") and each thread starts at the position equal the 
        //number of counted 16s).
    for (i = 0; i < M; i++)
    {
        if (a[Idx][i] == 16)
        {
            listM[num[Idx] + i] = Idx;
            listN[num[Idx] + i] = i;
        }
    }
}
\uuuu全局\uuuuu无效压缩(int*a,int*listM,int*listN)
{
int Idx=threadIdx.x;
int元素,i;
i=元素=0;
__共享的整数[N];
对于(i=0;i
是否可以编写内核,以便每个线程在计算行中值为16的元素数(仅此数)后,动态放大两个数组“listeM”和“listeN”

CUDA设备代码无法扩大使用主机端
cudaMalloc
cudaMallocManaged
cudaHostAlloc
或类似工具创建的现有分配

CUDA设备代码可以在内核
new
malloc
中使用,但是这些分配的数据不能直接传输回主机。要将其传输回主机,需要主机端分配,这样分配的数据就可以复制到主机端分配中,这就回到了原始问题

因此,确实没有方便的方法来做到这一点。你的选择是:

  • (超过)根据可能返回的最大大小分配所需的大小
  • 创建一个算法,运行内核一次以确定所需的大小,并将该大小返回给主机。然后,主机分配该大小并将其传递给内核,以便在第二次调用该算法时使用,从而完成实际需要的工作
  • “可能”的第三种方法是:

  • 只运行一次算法,让内核在内核中分配所需的额外空间。主机端操作无法访问此空间。此内核还将返回此类分配的大小和/或安排

  • 根据返回的设备大小分配大小/排列,主机将分配所需大小的新内存

  • 然后,主机将启动一个新的“复制内核”,将数据从步骤1的设备端分配复制到步骤2中提供的主机端分配

  • 然后,在步骤2中,主机将数据从主机端分配复制到主机内存

  • 这是一个极端复杂的问题,正如你所概述的那样,显而易见的解决方案就是过度分配所需的空间并完成它