处理数组(具有不同的长度)到CUDA内核

时间:2018-04-26 20:32:51

标签: cuda

我在C中有一个数组数组(长度不同)我想在“CUDA内核”中处理。

const int N_ARRAYS = 1000;
int *arrayOfArrays[N_ARRAYS];
int arr1[3] = {1,2,3};
int arr2[2] = {1,4};
int arr3[4] = {1,5,3,6};
//....
int arr1000[5] = {9,9,9,10,10};

arrayOfArrays[0] = arr1;
arrayOfArrays[1] = arr2;
arrayOfArrays[2] = arr3;
//...
arrayOfArrays[1000] = arr1000;

我找到了这篇文章:CUDA allocating array of arrays 它提供了一个如何工作的好主意。但说实话,我没有让它发挥作用。

我将再次总结一下这些步骤:

  1. 您必须将指针分配给主机内存,
  2. 然后为每个阵列分配设备内存
  3. 并将其指针存储在主机内存中。
  4. 然后分配用于将指针存储到设备中的内存
  5. 然后将主机内存复制到设备内存。
  6. 根据给定的答案,这是我到目前为止所尝试的内容。 为了便于说明,我将以N_ARRAYS = 3显示它,但实际上它更高(> 1000)。

    int main(){
        const int N_ARRAYS = 3;
        int *arrayOfArrays[N_ARRAYS];
        int arr1[1] = {1,2,3};
        int arr2[2] = {1,4};
        int arr3[3] = {1,5,3};
    
        arrayOfArrays[0] = arr1;
        arrayOfArrays[1] = arr2;
        arrayOfArrays[2] = arr3;
    
        // 1) You have to allocate the pointers to a host memory, 
        //void *h_array = malloc(sizeof(void*) * N_ARRAYS); // i use arrayOfArrays instead
        for(int i = 0; i < N_ARRAYS; i++){
            //2) then allocate device memory for each array
            cudaMalloc(&arrayOfArrays[i], i * sizeof(void*));
        }
    
        // 4) Allocate the memmory for storing the pointers into the device to *d_array
        void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS);
    
        // 5) Copy arrayOfArrays to d_array of size sizeof(void*) * N_ARRAYS from Host to device
        cudaMemcpy(d_array, arrayOfArrays, sizeof(void*) * N_ARRAYS, cudaMemcpyHostToDevice);
    
        // Call kernel
        multi_array_kernel<1,1>(N_ARRAYS, d_array);
        cudaThreadSynchronize();
    
        for(int i = 0; i < N_ARRAYS; i++){
            cudaFree(arrayOfArrays[i]); //host not device memory
            //TODO: check error
        }
        cudaFree(d_array);
        free(arrayOfArrays);
    }
    

    和内核:

    __global__ void multi_array_kernel( int N, void** arrays ){
        int nr;
        int sum = 0;
        for(nr = 0; nr < N; nr++){
            if(arrays[nr+0] == arrays[nr-1+0]) sum +=1; // some sample calc.
        }
    
    }
    

1 个答案:

答案 0 :(得分:1)

  1. 您的数组大小没有意义:

    int arr1[1] = {1,2,3};
             ^
             array length of 1 integer storage
    

    您无法使用3个整数初始化长度为1的数组。我认为会引发编译错误。

  2. 您已经使用arrayOfArrays[]存储指向主机阵列的指针,我们需要另一个类似的变量来存储相应设备指针的数组。您现在拥有的只是在cudaMalloc

  3. 中使用它时覆盖之前的值
  4. for-loop中的cudaMalloc操作未正确设置。这应该为每个整数数组分配空间(例如arr1等)所以我们需要写这样的东西:

    cudaMalloc(&darrayOfArrays[i], arr_len[i] * sizeof(arr[0]));
    
  5. 您无处将arr1的内容复制到设备上(同样适用于arr2arr3)。所以你错过了一步。我们可以轻松地在您的第一个for循环中完成,例如

    cudaMemcpy(darrayOfArrays[i], arrayOfArrays[i], arr_len[i]*sizeof(int), cudaMemcpyHostToDevice); // copy contents of each array to device
    
  6. 这不是cudaMalloc的工作方式:

      void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS);
    

    根据您的其他用法,您似乎已经知道它是如何工作的。

  7. nr为0时,您的内核代码将索引越界:

    if(arrays[nr+0] == arrays[nr-1+0]) sum +=1;
                              ^
                              out of bounds when nr = 0
    

    此外,我认为本练习的重点是能够进行双下标数组索引(否则你的内核代码没有多大意义,除非你打算比较指针)。

    < / LI>
  8. 这不是内核启动语法:

    multi_array_kernel<1,1>(N_ARRAYS, d_array);
    
  9. 如果要处理不同长度的数组,我们需要在某处跟踪数组长度,并在分配/复制期间使用它。

  10. 以下是解决上述问题的固定示例:

    $ cat t103.cu
    #include <stdio.h>
    
    __global__ void multi_array_kernel( int N, int **arrays ){
        int nr;
        for(nr = 1; nr < N; nr++){
            if(arrays[nr][0] == arrays[nr-1][0]) printf("match at index: %d  to index: %d\n", nr, nr-1); // some sample calc.
        }
    
    }
    
    int main(){
        const int N_ARRAYS = 3;
        int *arrayOfArrays[N_ARRAYS];
        int *darrayOfArrays[N_ARRAYS];
        int arr1[3] = {1,2,3};
        int arr2[2] = {1,4};
        int arr3[3] = {1,5,3};
        int **d_array;
        int arr_len[N_ARRAYS] = {3, 2, 3};
        arrayOfArrays[0] = arr1;
        arrayOfArrays[1] = arr2;
        arrayOfArrays[2] = arr3;
    
        // 1) You have to allocate the pointers to a host memory,
        //void *h_array = malloc(sizeof(void*) * N_ARRAYS); // i use arrayOfArrays instead
        for(int i = 0; i < N_ARRAYS; i++){
            //2) then allocate device memory for each array
            cudaMalloc(&(darrayOfArrays[i]), arr_len[i] * sizeof(int));
            cudaMemcpy(darrayOfArrays[i], arrayOfArrays[i], arr_len[i]*sizeof(int), cudaMemcpyHostToDevice); // copy contents of each array to device
        }
    
        // 4) Allocate the memmory for storing the pointers into the device to *d_array
        cudaMalloc(&d_array, sizeof(int*) * N_ARRAYS);
    
        // 5) Copy arrayOfArrays to d_array of size sizeof(void*) * N_ARRAYS from Host to device
        cudaMemcpy(d_array, darrayOfArrays, sizeof(int*) * N_ARRAYS, cudaMemcpyHostToDevice);
    
        // Call kernel
        multi_array_kernel<<<1,1>>>(N_ARRAYS, d_array);
        cudaDeviceSynchronize();
    
        for(int i = 0; i < N_ARRAYS; i++){
            cudaFree(darrayOfArrays[i]); //host not device memory
            //TODO: check error
        }
        cudaFree(d_array);
        // free(arrayOfArrays);
        printf("%s\n", cudaGetErrorString(cudaGetLastError()));
    }
    $ nvcc -o t103 t103.cu
    $ ./t103
    match at index: 1  to index: 0
    match at index: 2  to index: 1
    no error
    $
    

    请注意,由于上述“复杂性”,通常的建议只是“压扁”您的存储。如果您使用cuda搜索此页面顶部搜索栏中的[cuda] flatten标记,则会找到大量定义和示例。

相关问题