我在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 它提供了一个如何工作的好主意。但说实话,我没有让它发挥作用。
我将再次总结一下这些步骤:
根据给定的答案,这是我到目前为止所尝试的内容。 为了便于说明,我将以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.
}
}
答案 0 :(得分:1)
您的数组大小没有意义:
int arr1[1] = {1,2,3};
^
array length of 1 integer storage
您无法使用3个整数初始化长度为1的数组。我认为会引发编译错误。
您已经使用arrayOfArrays[]
存储指向主机阵列的指针,我们需要另一个类似的变量来存储相应设备指针的数组。您现在拥有的只是在cudaMalloc
for-loop中的cudaMalloc
操作未正确设置。这应该为每个整数数组分配空间(例如arr1
等)所以我们需要写这样的东西:
cudaMalloc(&darrayOfArrays[i], arr_len[i] * sizeof(arr[0]));
您无处将arr1
的内容复制到设备上(同样适用于arr2
,arr3
)。所以你错过了一步。我们可以轻松地在您的第一个for循环中完成,例如
cudaMemcpy(darrayOfArrays[i], arrayOfArrays[i], arr_len[i]*sizeof(int), cudaMemcpyHostToDevice); // copy contents of each array to device
这不是cudaMalloc
的工作方式:
void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS);
根据您的其他用法,您似乎已经知道它是如何工作的。
当nr
为0时,您的内核代码将索引越界:
if(arrays[nr+0] == arrays[nr-1+0]) sum +=1;
^
out of bounds when nr = 0
此外,我认为本练习的重点是能够进行双下标数组索引(否则你的内核代码没有多大意义,除非你打算比较指针)。
< / LI>这不是内核启动语法:
multi_array_kernel<1,1>(N_ARRAYS, d_array);
如果要处理不同长度的数组,我们需要在某处跟踪数组长度,并在分配/复制期间使用它。
以下是解决上述问题的固定示例:
$ 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
标记,则会找到大量定义和示例。