Matrix 矩阵CUDA的分段处理

Matrix 矩阵CUDA的分段处理,matrix,cuda,Matrix,Cuda,好,假设我有一个nxn矩阵,我想处理它。这个矩阵对于我的计算机来说相当大,如果我试图一次将它发送到设备,我会得到一个“内存不足错误” 那么,有没有办法将矩阵的各个部分发送到设备?我可以看到的一种方法是在主机上复制矩阵的一部分,然后将这些可管理的复制部分从主机发送到设备,最后再将它们放回一起 这是我尝试过的,但是for循环中的cudaMemcpy返回错误代码11“invalid argument” int h_N = 10000; size_t h_size_m = h_N*sizeof(floa

好,假设我有一个nxn矩阵,我想处理它。这个矩阵对于我的计算机来说相当大,如果我试图一次将它发送到设备,我会得到一个“内存不足错误”

那么,有没有办法将矩阵的各个部分发送到设备?我可以看到的一种方法是在主机上复制矩阵的一部分,然后将这些可管理的复制部分从主机发送到设备,最后再将它们放回一起

这是我尝试过的,但是for循环中的cudaMemcpy返回错误代码11“invalid argument”

int h_N = 10000;
size_t h_size_m = h_N*sizeof(float);
h_A  = (float*)malloc(h_size_m*h_size_m);

int d_N = 2500;
size_t d_size_m = d_N*sizeof(float);

InitializeMatrices(h_N);

int i;
int iterations = (h_N*h_N)/(d_N*d_N);

for( i = 0; i < iterations; i++ ) 
{
    float* h_array_ref = h_A+(i*d_N*d_N);
    cudasafe( cudaMemcpy(d_A, h_array_ref, d_size_m*d_size_m, cudaMemcpyHostToDevice), "cudaMemcpy");
    cudasafe( cudaFree(d_A), "cudaFree(d_A)" );
}
我试图用上面的代码来完成的是:我没有将整个矩阵发送到设备,而是将指针发送到矩阵中的某个位置,并在设备上保留足够的空间来完成工作,然后在循环的下一次迭代中,在矩阵中向前移动指针,诸如此类。

假设您的问题很容易通过这种方式分解为子数组,那么您不仅可以这样做,而且对于性能来说,这是一件非常有用的事情;一旦您获得了所描述的基本方法,您就可以开始使用和双缓冲来重叠一些内存传输时间和计算卡上已有内容所花费的时间

但首先要做的是让简单的事情起作用。下面是一个1d示例,将一个向量乘以一个标量,然后再添加另一个标量,但使用线性化2d数组将是相同的;关键部分是

CHK_CUDA( cudaMalloc(&xd, batchsize*sizeof(float)) );
CHK_CUDA( cudaMalloc(&yd, batchsize*sizeof(float)) );
tick(&gputimer);

int nbatches = 0;
for (int nstart=0; nstart < n; nstart+=batchsize) {

    int size=batchsize;
    if ((nstart + batchsize) > n) size = n - nstart;

    CHK_CUDA( cudaMemcpy(xd, &(x[nstart]), size*sizeof(float), cudaMemcpyHostToDevice) );

    blocksize = (size+nblocks-1)/nblocks;
    cuda_saxpb<<<nblocks, blocksize>>>(xd, a, b, yd, size);

    CHK_CUDA( cudaMemcpy(&(ycuda[nstart]), yd, size*sizeof(float), cudaMemcpyDeviceToHost) );

    nbatches++;
}
gputime = tock(&gputimer);

CHK_CUDA( cudaFree(xd) );
CHK_CUDA( cudaFree(yd) );
在这种情况下,GPU时间会增加,我们会进行更多的内存拷贝,但答案保持不变

编辑:此代码的原始版本有一个选项,用于运行内核的多个迭代以进行计时,但这在上下文中是不必要的混淆,因此将其删除。

您不仅可以这样做,假设您的问题很容易以这种方式分解为子数组,这对于提高性能非常有用;一旦您获得了所描述的基本方法,您就可以开始使用和双缓冲来重叠一些内存传输时间和计算卡上已有内容所花费的时间

但首先要做的是让简单的事情起作用。下面是一个1d示例,将一个向量乘以一个标量,然后再添加另一个标量,但使用线性化2d数组将是相同的;关键部分是

CHK_CUDA( cudaMalloc(&xd, batchsize*sizeof(float)) );
CHK_CUDA( cudaMalloc(&yd, batchsize*sizeof(float)) );
tick(&gputimer);

int nbatches = 0;
for (int nstart=0; nstart < n; nstart+=batchsize) {

    int size=batchsize;
    if ((nstart + batchsize) > n) size = n - nstart;

    CHK_CUDA( cudaMemcpy(xd, &(x[nstart]), size*sizeof(float), cudaMemcpyHostToDevice) );

    blocksize = (size+nblocks-1)/nblocks;
    cuda_saxpb<<<nblocks, blocksize>>>(xd, a, b, yd, size);

    CHK_CUDA( cudaMemcpy(&(ycuda[nstart]), yd, size*sizeof(float), cudaMemcpyDeviceToHost) );

    nbatches++;
}
gputime = tock(&gputimer);

CHK_CUDA( cudaFree(xd) );
CHK_CUDA( cudaFree(yd) );
在这种情况下,GPU时间会增加,我们会进行更多的内存拷贝,但答案保持不变


编辑:此代码的原始版本有一个选项,用于运行内核的多个迭代以进行计时,但这在上下文中是不必要的混淆,因此将其删除。

当然可以按照您描述的方式对矩阵进行平铺处理。至于您当前的问题,我在代码中没有看到矩阵图块的cudamaloc。请注意,由于矩阵的二维布局,每个磁贴都需要使用cudaMemcpy2D进行复制,因为根据您的存储约定,每个磁贴的行或列都不是连续的。当然可以按照您描述的方式对矩阵进行磁贴处理。至于您当前的问题,我在代码中没有看到矩阵图块的cudamaloc。请注意,由于矩阵的2D布局,每个磁贴都需要使用cudaMemcpy2D进行复制,因为行或列不连续,这取决于每个磁贴的存储约定。请注意,为了代码的清晰性,需要进行轻微的编辑;我刚刚意识到,在这种情况下,迭代内核启动确实令人困惑;我刚刚意识到,在这种情况下,迭代内核启动确实令人困惑。
$  ./batched-saxpb --nvals=10240 --batchsize=10240 --nblocks=20
Y = a*X + b, problemsize = 10240
CPU time = 0.072 millisec.
GPU time = 0.117 millisec (done with 1 batches of 10240).
CUDA and CPU results differ by 0.000000

$ ./batched-saxpb --nvals=10240 --batchsize=5120 --nblocks=20
Y = a*X + b, problemsize = 10240
CPU time = 0.066 millisec.
GPU time = 0.133 millisec (done with 2 batches of 5120).
CUDA and CPU results differ by 0.000000

$ ./batched-saxpb --nvals=10240 --batchsize=2560 --nblocks=20
Y = a*X + b, problemsize = 10240
CPU time = 0.067 millisec.
GPU time = 0.167 millisec (done with 4 batches of 2560).
CUDA and CPU results differ by 0.000000