问题描述
我正在尝试使用 CUB 和 float/double 类型的二维数组来执行求和。 虽然它适用于行+列的某些组合,但对于相对较大的数组,我在上次传输期间收到非法内存访问错误。 一个最小的例子如下:
#include <stdio.h>
#include <stdlib.h>
#include <cub/device/device_reduce.cuh>
#include "cuda_runtime.h"
#ifdef DP
#define real double
#else
#define real float
#endif
void generatedata(const int num,real* vec,real start,real finish) {
real rrange = finish - start;
for (auto i = 0; i < num; ++i)
vec[i] = rand() / float(RAND_MAX) * rrange + start;
}
real reduce_to_sum(const int num,const real* vec) {
real total = real(0.0);
for (auto i = 0; i < num; ++i)
total += vec[i];
return total;
}
int main() {
int rows = 2001;
int cols = 3145;
size_t msize = rows * cols;
real* data = (real*)malloc(msize * sizeof(real));
if (!data)
return -999;
generatedata(msize,data,0.,50.);
real ref_sum = reduce_to_sum(msize,data);
real* d_data_in = nullptr;
real* d_data_out = nullptr;
size_t pitch_in,pitch_out;
cudaError_t err = cudamallocPitch(&d_data_in,&pitch_in,cols * sizeof(real),rows);
if (err != cudaSuccess) {
printf("data_in :: %s \n",cudaGetErrorString(err));
return -999;
}
err = cudamallocPitch(&d_data_out,&pitch_out,rows);
if (err != cudaSuccess) {
printf("data_out :: %s \n",cudaGetErrorString(err));
return -999;
}
err = cudamemset(d_data_in,rows * pitch_in);
if (err != cudaSuccess) {
printf("set data_in :: %s \n",cudaGetErrorString(err));
return -999;
}
err = cudamemcpy2D(d_data_in,pitch_in,rows,cudamemcpyHostToDevice);
if (err != cudaSuccess) {
printf("copy data :: %s \n",cudaGetErrorString(err));
return -999;
}
void* d_temp = nullptr;
size_t temp_bytes = 0;
cub::DeviceReduce::Sum(d_temp,temp_bytes,d_data_in,d_data_out,rows * pitch_out);
err = cudamalloc(&d_temp,temp_bytes);
if (err != cudaSuccess) {
printf("temp :: %s \n",cudaGetErrorString(err));
return -999;
}
err = cudamemset(d_data_out,rows * pitch_out);
if (err != cudaSuccess) {
printf("set temp :: %s \n",cudaGetErrorString(err));
return -999;
}
// Run sum-reduction
cub::DeviceReduce::Sum(d_temp,rows * pitch_out);
err = cudaGetLastError();
if (err != cudaSuccess) {
printf("reduction :: %s \n",cudaGetErrorString(err));
return -999;
}
real gpu_sum = real(0.0);
err = cudamemcpy(&gpu_sum,sizeof(real),cudamemcpyDevicetoHost);
if (err != cudaSuccess) {
printf("copy final :: %s \n",cudaGetErrorString(err));
return -999;
}
printf("Difference in sum (h)%f - (d)%f = %f \n",ref_sum,gpu_sum,ref_sum - gpu_sum);
if (data) free(data);
if (d_data_in) cudaFree(d_data_in);
if (d_data_out) cudaFree(d_data_out);
if (d_temp) cudaFree(d_temp);
cudaDeviceReset();
return 0;
}
在“copy final ::”处抛出错误。我对为什么某些行 x 列有效而其他行无效的原因感到有些困惑。我确实注意到它是导致它的较大值,但无法理解。 任何建议将不胜感激。
解决方法
cub::DeviceReduce::Sum 的第 5 个参数应该是输入元素的数量。但是,rows * pitch_out
是以字节为单位的输出缓冲区的大小。
假设 pitch_in % sizeof(real) == 0
,以下调用可能有效。
cub::DeviceReduce::Sum(d_temp,temp_bytes,d_data_in,d_data_out,rows * (pitch_in / sizeof(real)));
另请注意,cub::DeviceReduce::Sum 可能会在归约完成之前返回。在这种情况下,如果在执行过程中发生任何错误,cudaMemcpy 将报告此错误。