0

我在 MatLab (2018a) 中编写了一段代码,它是标准 matlab 代码和 CUDA 代码的混合体,我使用编译与 mexcuda 将其链接起来。我的代码中的核心循环包含一个矩阵的插值,比如从大小 [nxm] 到 [N x M]。我已经使用 GPU 加快了这部分的速度。由于此插值在循环内,并且由于我插值的矩阵的大小(之前和之后)在循环的每次迭代中都是相同的,我想通过预先分配输出大小的数组来加速应用程序显卡。所以我想做类似的事情:zeros(N,M,'gpuArray')在开始时,将它作为输入提供给 mexFunction,然后将插值矩阵写入这个数组。这将节省相当多的分配时间([N_iterations-1]*allocation_time,粗略地说)。

我现在的问题是:我不知道这是否可能。使用 mexFunction() 作为入口点,我知道检索输入数组的唯一方法是使用以下内容:

mxGPUArray const *in  = mxGPUCreateFromMxArray(prhs[0]);
float const *dev_in  = (float const *)(mxGPUGetDataReadOnly(in));

但是,顾名思义,这会导致只读权限。我不能使用mxGPUGetData(in),因为 mxGPUArray 是const,不能用它初始化非常量实体。有谁知道是否有解决这个问题的方法不涉及在 mexFunction 内分配数组?

编辑:

下面的代码显示了两个 C 代码示例,其中第一个是我当前代码的类比,第二个是我正在努力的目标:

当前的:

#include "stdio.h"
int main(const int argc, const char *argv[]) {
// Allocate input matrix and fill from input arguments
FILE *fPtr; fPtr = fopen(argv[1],"rb");
double *mat_in = malloc(n*m*sizeof(*mat_in));
mat_in = fread(mat_in, sizeof(*mat_in), n*m, fPtr);
fclose(fPtr);

double *mat_out;
for (int it = 0, it < 1000, it++) {
    // Allocate output array and fill it;
    mat_out = malloc(N*M*sizeof(*mat_out));
    interpolation_function(mat_in, mat_out);

    // Do stuff with mat_out
    free(mat_out);
}
// Free mat_in, do more stuff and/or exit program

主意:

#include "stdio.h"
int main(const int argc, const char *argv[]) {
// Allocate input matrix and fill from input arguments
FILE *fPtr; fPtr = fopen(argv[1],"rb");
double *mat_in = malloc(n*m*sizeof(*mat_in));
mat_in = fread(mat_in, sizeof(*mat_in), n*m, fPtr);
fclose(fPtr);

// Allocate output array once at the start:
double *mat_out = malloc(N*M*sizeof(*mat_out));

for (int it = 0, it < 1000, it++) {
    interpolation_function(mat_in, mat_out); // Fills mat_out
    // Do stuff with mat_out here;
}
free(mat_out);
// Free mat_in, do more stuff and/or exit program

以上两个是(至少在我看来)以下 matlab-cuda 混合代码的类比:

当前(matlab);mexcuda 函数需要为 input(:,:,indx) 的插值分配内存

accumresult = zeros(N,M);
input = randn(100,100,1000);
for indx = 1:1000
    input_slice = mexcuda_interpolation( input(:,:,indx) );
    accumresult = accumresult + foo( input_slice, other_parameters);
end

想法:内存分配被移出 mexcuda 函数(因此,移出核心循环),并且 mexcuda 函数只需要检索指向这个(可写)数组的指针;

accumresult = zeros(N,M,'gpuArray');
placeholder = zeros(N,M,'gpuArray'); % Memory allocated on GPU once here
input = randn(100,100,1000);
for indx = 1:1000
    accumresult = accumresult + foo( mexcuda_interpolation(input(:,:,indx)), placeholder, other_parameters);
    %mexcuda_interpolation() somehow gets a pointer to the allocated memory which it can write to
end

请注意,确实有可能进一步并行化:如前所述,我正处于并行化整个事物的中间步骤。

4

1 回答 1

1

对于您的 mex 代码,使用mxGPUCreateGPUArray, 而不是在mxGPUCreateFromMxArray没有初始化的情况下分配内存。


关于您的 MATLAB 代码:您为什么要预分配?了解您正在做的事情的原理,因为您需要它与 GPU 一起工作。

在 MATLAB 中,如果您不预先分配,那么每次追加新数据时,MATLAB 所做的是:创建具有新大小的新数组,将数据从较小的旧数组复制到新数组。当然,这是不鼓励的,因为您一直在做不必要的复制。

在 CUDA 中,这是不可能的。动态数组不存在。特别是因为您所做的任何事情都不会连续发生,在 for 循环中,它会“同时”发生。因此,在执行操作时了解输出的大小至关重要。

因此,当您拥有 GPU 阵列A并对其B进行操作f()时,f需要知道输出大小。如果你在 MATLAB 中做C=f(A,B),你不需要预先分配C(事实上,在这个例子中,你也不需要,没有 GPU 计算)。MATLAB 将足够聪明地为您完成。

所以,要么你需要看看为什么在下面的代码中预分配C是浪费时间

A=rand(N,M); % or A=rand(N,M,'gpuArray');
B=rand(N,M); % or B=rand(N,M,'gpuArray');
C=A+B;

或者,您的代码如下所示:

A=rand(N,M,'gpuArray');
B=rand(N,M,'gpuArray');
for ii=1:N
   for jj=1:M
       C(ii,jj)=A(ii,jj)+B(ii,jj);
   end
end

这从根本上意味着您在分离可并行化元素时不会从 GPU 计算中获得任何好处。

于 2018-06-07T13:50:08.087 回答