0

我是 java 编程新手,并试图在 jCUDA 中编写矩阵乘法程序。

在将数据从主机传输到设备时,反之亦然,我使用:

cuMemcpyHtoD(devMatrixA, Pointer.to(hostMatrixA), numRows * numCols * Sizeof.FLOAT);
cuMemcpyHtoD(devMatrixB, Pointer.to(hostMatrixA), numRows * numCols * Sizeof.FLOAT);
cuMemcpyDtoH(Pointer.to(hostMatrixC), devMatrixC, numRows * numCols * Sizeof.FLOAT);

这里,devMatrixA、devMatrixB 和 devMatrixC 是要存储在设备内存中的矩阵。hostMatrixA、hostMatrixB 和 hostMatrixC 是存储在我的主机内存中的矩阵。

当我调用上述函数进行数据传输时,它给了我以下错误“指针类型中的方法 to(byte[]) 不适用于参数 (float[][])”和“指针.to”中的“to” (' 是红色下划线。我正在使用 eclipse。我已经给出了我的完整代码,如下所示。

请原谅我的Java知识,如果我走错方向,请提出建议。

Package JCudaMatrixAddition;
import static jcuda.driver.JCudaDriver.*;

import java.io.*;

import jcuda.*;
import jcuda.driver.*;
import jcuda.Pointer;
import jcuda.Sizeof;


public class JCudaMatrixAddition {
    public static void main(String[] args) throws IOException 
    {
        // Enable exceptions and omit all subsequent error checks
        JCudaDriver.setExceptionsEnabled(true);

        // Create the PTX file by calling the NVCC
        String ptxFilename = preparePtxFile("JCudaMatrixAdditionKernel.cu");

        //Initialize the driver and create a context for the first device.
        cuInit(0);
        CUdevice device = new CUdevice();
        cuDeviceGet (device, 0);
        CUcontext context = new CUcontext();
        cuCtxCreate(context, 0, device);

        //Load PTX file
        CUmodule module = new CUmodule();
        cuModuleLoad(module,ptxFilename);

        //Obtain a function pointer to the Add function
        CUfunction function = new CUfunction();
        cuModuleGetFunction(function, module, "add");

        int numRows = 32;
        int numCols = 32;

        //Allocate and fill Host input Matrices:
        float hostMatrixA[][] = new float[numRows][numCols];
        float hostMatrixB[][] = new float[numRows][numCols];
        float hostMatrixC[][] = new float[numRows][numCols];


        for(int i = 0; i<numRows; i++)

        {
            for(int j = 0; j<numCols; j++)
            {
                hostMatrixA[i][j] = (float) 1.0;
                hostMatrixB[i][j] = (float) 1.0;
            }
        }
        // Allocate the device input data, and copy the
        // host input data to the device
        CUdeviceptr devMatrixA = new CUdeviceptr();
        cuMemAlloc(devMatrixA, numRows * numCols * Sizeof.FLOAT);

        //This is the part where it gives me the error
        cuMemcpyHtoD(devMatrixA, Pointer.to(hostMatrixA), numRows * numCols * Sizeof.FLOAT);

        CUdeviceptr devMatrixB = new CUdeviceptr();
        cuMemAlloc(devMatrixB, numRows * numCols * Sizeof.FLOAT);

        //This is the part where it gives me the error
        cuMemcpyHtoD(devMatrixB, Pointer.to(hostMatrixA), numRows * numCols * Sizeof.FLOAT);

        //Allocate device matrix C to store output
        CUdeviceptr devMatrixC = new CUdeviceptr();
        cuMemAlloc(devMatrixC, numRows * numCols * Sizeof.FLOAT);

        // Set up the kernel parameters: A pointer to an array
        // of pointers which point to the actual values.

        Pointer kernelParameters = Pointer.to(Pointer.to(new int[]{numRows}),
                                   Pointer.to(new int[]{numRows}), 
                                   Pointer.to(devMatrixA),
                                   Pointer.to(devMatrixB),
                                   Pointer.to(devMatrixC));

        //Kernel thread configuration
        int blockSize = 32;
        int gridSize = 1;

        cuLaunchKernel(function, 
                       gridSize, 1, 1,
                       blockSize, 32, 1,
                       0, null, kernelParameters, null);

        cuCtxSynchronize();
        // Allocate host output memory and copy the device output
        // to the host.

        //This is the part where it gives me the error
        cuMemcpyDtoH(Pointer.to(hostMatrixC), devMatrixC, numRows * numCols * Sizeof.FLOAT);

        //verify the result
        for (int i =0; i<numRows; i++)
        {
            for (int j =0; j<numRows; j++)
            {
                System.out.print("   "+ hostMatrixB[i][j]);
            }
            System.out.println("");
        }
        cuMemFree(devMatrixA);
        cuMemFree(devMatrixB);
        cuMemFree(devMatrixC);

    }
4

1 回答 1

2

您不能直接将float[][]阵列从主机复制到设备。

当您创建一个float[][]数组时,这不是一个大的float值数组。相反,它是一个数组数组。想象一下,你甚至可以创建一个像

float array[][] = new float[3];
array[0] = new float[42];
array[1] = null;
array[2] = new float[1234];

这根本不是一个连续的内存块,因此不能将这样的数组复制到设备中。

在 CUDA 中处理矩阵时(不仅在 JCuda 中,而且在一般的 CUDA 中),它们通常表示为一维数组。因此,在这种情况下,您可以将矩阵声明为

float hostMatrixA[] = new float[numRows*numCols];

为了访问矩阵元素,您必须计算适当的索引:

int row = ...;
int col = ...;
hostMatrix[col+row*numCols] = 123.0f; // Column-major

// Or
hostMatrix[row+col*numRows] = 123.0f; // Row-major

最后两行之间的区别在于,一行假设列优先,而另一行假设行优先。有关详细信息,请参阅有关行主要顺序的 Wikipedia 站点

一些旁注:

像 CUBLAS 这样的 CUDA 矩阵库使用列优先排序,因此遵循相同的约定可能是个好主意。特别是当您以后想要使用 CUBLAS/JCublas 函数时。例如,cublasSgeam函数已经提供了执行矩阵加法的功能。

当您只想进行矩阵加法时,使用 CUDA/JCuda 时不会看到加速。我在这个答案中写了一个总结。

顺便说一句:从技术上讲,可以使用“二维数组”。JCudaDriverSample展示了如何做到这一点但它相当不方便,推荐用于矩阵运算。

于 2014-08-11T08:37:09.413 回答