如何在CUDA Kernel中处理C语言中不同长度的数组的数组?
嘿,我来帮你把这个问题掰明白!你在CPU上定义的这种「数组的数组」(每个子数组长度不一样),直接拿到CUDA核里用肯定不行——因为GPU认不出主机内存里的指针。我给你一步步拆解怎么把数据搬到GPU并处理:
第一步:准备子数组的关键信息
首先得把每个子数组的长度记下来,同时计算每个子数组在后续连续内存里的起始偏移:
// 先定义数组存每个子数组的长度 int subarray_lengths[N_ARRAYS]; subarray_lengths[0] = 3; // arr1的长度 subarray_lengths[1] = 2; // arr2的长度 subarray_lengths[2] = 4; // arr3的长度 // ... 依次填完1000个子数组的长度 subarray_lengths[999] = 5; // arr1000的长度 // 计算总元素数,用来分配GPU内存 int total_elements = 0; for (int i = 0; i < N_ARRAYS; i++) { total_elements += subarray_lengths[i]; } // 计算每个子数组在连续内存中的起始偏移 int *h_offsets = (int*)malloc(N_ARRAYS * sizeof(int)); h_offsets[0] = 0; for (int i = 1; i < N_ARRAYS; i++) { h_offsets[i] = h_offsets[i-1] + subarray_lengths[i-1]; }
第二步:把数据搬到GPU
接下来要把所有子数组的数据、偏移数组、长度数组都拷贝到GPU内存:
// 分配一块连续的GPU内存,装所有子数组的数据 int *d_all_data; cudaMalloc(&d_all_data, total_elements * sizeof(int)); // 分配GPU内存存偏移和长度数组 int *d_offsets, *d_subarray_lengths; cudaMalloc(&d_offsets, N_ARRAYS * sizeof(int)); cudaMalloc(&d_subarray_lengths, N_ARRAYS * sizeof(int)); // 把偏移和长度数组拷贝到GPU cudaMemcpy(d_offsets, h_offsets, N_ARRAYS * sizeof(int), cudaMemcpyHostToDevice); cudaMemcpy(d_subarray_lengths, subarray_lengths, N_ARRAYS * sizeof(int), cudaMemcpyHostToDevice); // 把每个子数组的数据依次拷贝到GPU的连续内存里 int current_offset = 0; for (int i = 0; i < N_ARRAYS; i++) { cudaMemcpy(d_all_data + current_offset, arrayOfArrays[i], subarray_lengths[i] * sizeof(int), cudaMemcpyHostToDevice); current_offset += subarray_lengths[i]; }
第三步:编写CUDA核函数处理数据
现在GPU上有了所有数据,我们可以写核函数来处理每个子数组。比如让每个线程对应一个子数组(如果子数组处理逻辑独立的话):
__global__ void processArrays(int *all_data, int *offsets, int *lengths, int n_arrays) { // 计算当前线程处理的子数组索引 int arr_idx = blockIdx.x * blockDim.x + threadIdx.x; if (arr_idx >= n_arrays) return; // 超出范围直接返回 // 获取当前子数组的起始位置和长度 int start = offsets[arr_idx]; int len = lengths[arr_idx]; int *subarray = all_data + start; // 这里写你的处理逻辑,比如给每个元素乘2 for (int i = 0; i < len; i++) { subarray[i] *= 2; } }
然后调用核函数:
// 配置线程块和网格大小(通常线程块设256或512) int block_size = 256; int grid_size = (N_ARRAYS + block_size - 1) / block_size; // 向上取整 // 启动核函数 processArrays<<<grid_size, block_size>>>(d_all_data, d_offsets, d_subarray_lengths, N_ARRAYS); cudaDeviceSynchronize(); // 等待核函数执行完成,也可以用cudaGetLastError检查错误
第四步:结果拷贝回主机与内存释放
如果需要把处理后的结果拿回到CPU,就按偏移和长度拷贝:
current_offset = 0; for (int i = 0; i < N_ARRAYS; i++) { cudaMemcpy(arrayOfArrays[i], d_all_data + current_offset, subarray_lengths[i] * sizeof(int), cudaMemcpyDeviceToHost); current_offset += subarray_lengths[i]; } // 最后别忘了释放所有内存 cudaFree(d_all_data); cudaFree(d_offsets); cudaFree(d_subarray_lengths); free(h_offsets);
额外:统一内存简化方案(可选)
如果你觉得手动拷贝太麻烦,可以用CUDA的统一内存(Unified Memory),它会自动管理数据在主机和GPU之间的迁移,代码会简洁很多:
// 用cudaMallocManaged分配统一内存 int *d_all_data, *d_offsets, *d_subarray_lengths; cudaMallocManaged(&d_all_data, total_elements * sizeof(int)); cudaMallocManaged(&d_offsets, N_ARRAYS * sizeof(int)); cudaMallocManaged(&d_subarray_lengths, N_ARRAYS * sizeof(int)); // 直接在主机上填充偏移和长度数组 memcpy(d_offsets, h_offsets, N_ARRAYS * sizeof(int)); memcpy(d_subarray_lengths, subarray_lengths, N_ARRAYS * sizeof(int)); // 拷贝子数组数据到统一内存(也可以直接在主机上写arrayOfArrays的内容到d_all_data) current_offset = 0; for (int i = 0; i < N_ARRAYS; i++) { memcpy(d_all_data + current_offset, arrayOfArrays[i], subarray_lengths[i] * sizeof(int)); current_offset += subarray_lengths[i]; } // 预取数据到GPU(可选,但能提升性能) cudaMemPrefetchAsync(d_all_data, total_elements * sizeof(int), 0); cudaMemPrefetchAsync(d_offsets, N_ARRAYS * sizeof(int), 0); cudaMemPrefetchAsync(d_subarray_lengths, N_ARRAYS * sizeof(int), 0); // 核函数调用和之前一样 processArrays<<<grid_size, block_size>>>(d_all_data, d_offsets, d_subarray_lengths, N_ARRAYS); cudaDeviceSynchronize(); // 结果会自动回到主机,直接用arrayOfArrays接收就行 current_offset = 0; for (int i = 0; i < N_ARRAYS; i++) { memcpy(arrayOfArrays[i], d_all_data + current_offset, subarray_lengths[i] * sizeof(int)); current_offset += subarray_lengths[i]; } // 释放统一内存 cudaFree(d_all_data); cudaFree(d_offsets); cudaFree(d_subarray_lengths); free(h_offsets);
统一内存适合快速开发,但如果是性能敏感的场景,还是手动管理内存更高效哦。
内容的提问来源于stack exchange,提问作者Tlatwork
相关产品推荐
相关产品推荐

