CUDA/C - 在内核函数中使用 malloc 会产生奇怪的结果
CUDA/C - Using malloc in kernel functions gives strange results
我是 CUDA/C 的新手,也是堆栈溢出的新手。这是我的第一个问题。
我试图在内核函数中动态分配内存,但结果出乎意料。
我读到在内核中使用 malloc() 会大大降低性能,但无论如何我都需要它所以我首先尝试使用一个简单的 int **
数组来测试这种可能性,然后我实际上需要分配更复杂的结构.
在我的主程序中,我使用cudaMalloc()
为int *
的数组分配space,然后我为内核函数中的每个线程使用malloc()
来为外部数组的每个索引分配数组。然后我用另一个线程检查结果,但它并不总是有效。
主要代码如下:
#define N_CELLE 1024*2
#define L_CELLE 512
extern "C" {
int main(int argc, char **argv) {
int *result = (int *)malloc(sizeof(int));
int *d_result;
int size_numbers = N_CELLE * sizeof(int *);
int **d_numbers;
cudaMalloc((void **)&d_numbers, size_numbers);
cudaMalloc((void **)&d_result, sizeof(int *));
kernel_one<<<2, 1024>>>(d_numbers);
cudaDeviceSynchronize();
kernel_two<<<1, 1>>>(d_numbers, d_result);
cudaMemcpy(result, d_result, sizeof(int), cudaMemcpyDeviceToHost);
printf("%d\n", *result);
cudaFree(d_numbers);
cudaFree(d_result);
free(result);
}
}
我使用了extern "C"
因为我在导入我的头文件时无法编译,这个示例代码中没有使用它。我粘贴了它,因为我不知道这是否相关。
这是kernel_one代码:
__global__ void kernel_one(int **d_numbers) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
d_numbers[i] = (int *)malloc(L_CELLE*sizeof(int));
for(int j=0; j<L_CELLE;j++)
d_numbers[i][j] = 1;
}
这是 kernel_two 代码:
__global__ void kernel_two(int **d_numbers, int *d_result) {
int temp = 0;
for(int i=0; i<N_CELLE; i++) {
for(int j=0; j<L_CELLE;j++)
temp += d_numbers[i][j];
}
*d_result = temp;
}
一切正常(也就是计数正确),直到我在设备内存中使用的总块数少于 1024*2*512。例如,如果我 #define N_CELLE 1024*4
程序开始给出 "random" 结果,例如负数。
知道问题可能是什么吗?
谢谢任何人!
我对 CUDA 一无所知,但这些是严重的错误:
- 您无法将
int**
转换为 void**
。它们不是兼容的类型。铸造并没有解决问题,而是隐藏了它。
&d_numbers
给出指向指针 的指针的 地址,这是错误的。它的类型是 int***
.
以上两个错误都会导致未定义的行为。如果您的程序在某些情况下似乎可以正常工作,那只是纯粹的(坏)运气。
内核内存分配从静态分配的 运行 时间堆中提取内存。在较大的大小下,您超出了该堆的大小,然后您的两个内核试图从未初始化的内存中读取和写入。这会在设备上产生 运行 时间错误并使结果无效。如果您在主机端添加了正确的 API 错误检查,或者使用 cuda-memcheck
实用程序 运行 您的代码,您就会知道这一点。
解决方案是确保在尝试 运行 内核之前将堆大小设置为适当的值。添加如下内容:
size_t heapsize = sizeof(int) * size_t(N_CELLE) * size_t(2*L_CELLE);
cudaDeviceSetLimit(cudaLimitMallocHeapSize, heapsize);
在任何其他 API 调用之前添加到您的主机代码,应该可以解决问题。
我是 CUDA/C 的新手,也是堆栈溢出的新手。这是我的第一个问题。
我试图在内核函数中动态分配内存,但结果出乎意料。
我读到在内核中使用 malloc() 会大大降低性能,但无论如何我都需要它所以我首先尝试使用一个简单的 int **
数组来测试这种可能性,然后我实际上需要分配更复杂的结构.
在我的主程序中,我使用cudaMalloc()
为int *
的数组分配space,然后我为内核函数中的每个线程使用malloc()
来为外部数组的每个索引分配数组。然后我用另一个线程检查结果,但它并不总是有效。
主要代码如下:
#define N_CELLE 1024*2
#define L_CELLE 512
extern "C" {
int main(int argc, char **argv) {
int *result = (int *)malloc(sizeof(int));
int *d_result;
int size_numbers = N_CELLE * sizeof(int *);
int **d_numbers;
cudaMalloc((void **)&d_numbers, size_numbers);
cudaMalloc((void **)&d_result, sizeof(int *));
kernel_one<<<2, 1024>>>(d_numbers);
cudaDeviceSynchronize();
kernel_two<<<1, 1>>>(d_numbers, d_result);
cudaMemcpy(result, d_result, sizeof(int), cudaMemcpyDeviceToHost);
printf("%d\n", *result);
cudaFree(d_numbers);
cudaFree(d_result);
free(result);
}
}
我使用了extern "C"
因为我在导入我的头文件时无法编译,这个示例代码中没有使用它。我粘贴了它,因为我不知道这是否相关。
这是kernel_one代码:
__global__ void kernel_one(int **d_numbers) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
d_numbers[i] = (int *)malloc(L_CELLE*sizeof(int));
for(int j=0; j<L_CELLE;j++)
d_numbers[i][j] = 1;
}
这是 kernel_two 代码:
__global__ void kernel_two(int **d_numbers, int *d_result) {
int temp = 0;
for(int i=0; i<N_CELLE; i++) {
for(int j=0; j<L_CELLE;j++)
temp += d_numbers[i][j];
}
*d_result = temp;
}
一切正常(也就是计数正确),直到我在设备内存中使用的总块数少于 1024*2*512。例如,如果我 #define N_CELLE 1024*4
程序开始给出 "random" 结果,例如负数。
知道问题可能是什么吗?
谢谢任何人!
我对 CUDA 一无所知,但这些是严重的错误:
- 您无法将
int**
转换为void**
。它们不是兼容的类型。铸造并没有解决问题,而是隐藏了它。 &d_numbers
给出指向指针 的指针的 地址,这是错误的。它的类型是int***
.
以上两个错误都会导致未定义的行为。如果您的程序在某些情况下似乎可以正常工作,那只是纯粹的(坏)运气。
内核内存分配从静态分配的 运行 时间堆中提取内存。在较大的大小下,您超出了该堆的大小,然后您的两个内核试图从未初始化的内存中读取和写入。这会在设备上产生 运行 时间错误并使结果无效。如果您在主机端添加了正确的 API 错误检查,或者使用 cuda-memcheck
实用程序 运行 您的代码,您就会知道这一点。
解决方案是确保在尝试 运行 内核之前将堆大小设置为适当的值。添加如下内容:
size_t heapsize = sizeof(int) * size_t(N_CELLE) * size_t(2*L_CELLE);
cudaDeviceSetLimit(cudaLimitMallocHeapSize, heapsize);
在任何其他 API 调用之前添加到您的主机代码,应该可以解决问题。