1

我试图了解如何在 Java 中使用 Cuda。我正在使用 jCuda。

一切都很好,直到我遇到一个包含代码的示例:

    // 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[]{numElements}),
        Pointer.to(deviceInputA),
        Pointer.to(deviceInputB),
        Pointer.to(deviceOutput)
    );

核函数原型为:

__global__ void add(int n, float *a, float *b, float *sum)

问题是: 就 c 而言,我们似乎没有传递类似的东西吗?

(***n, ***a, ***b, ***sum)

所以基本上,我们是否总是必须拥有:

Pointer kernelParameters = Pointer.to( double pointer, double pointer, ...)???

谢谢

4

1 回答 1

3

cuLaunchKernelJCuda的功能对应于cuLaunchKernelCUDA 的功能。这个函数在 CUDA 中的签名是

CUresult cuLaunchKernel(
    CUfunction f, 
    unsigned int gridDimX, 
    unsigned int gridDimY, 
    unsigned int gridDimZ, 
    unsigned int blockDimX, 
    unsigned int blockDimY, 
    unsigned int blockDimZ, 
    unsigned int sharedMemBytes, 
    CUstream hStream, 
    void** kernelParams, 
    void** extra) 

其中kernelParams是与此问题相关的唯一参数。文件说

内核参数可以通过kernelParams. 如果f有 N 个参数,则kernelParams需要是一个由 N 个指针组成的数组。每个kernelParams[0]through都kernelParams[N-1]必须指向一个内存区域,从中复制实际的内核参数。


这里的重点是最后一句话:kernelParams数组元素并不是实际的内核参数。它们只指向实际的内核参数。

实际上,这有一个奇怪的效果,对于接收单个 的内核float *pointer,您基本上可以按如下方式设置内核参数:

float *pointer= allocateSomeDeviceMemory();
float** pointerToPointer = &pointer;
float*** pointerToPointerToPointer = &pointerToPointer;
void **kernelParams = pointerToPointerToPointer;

(这只是为了说明这确实是一个指向指针的指针——实际上,你不会这样写)


现在,对于 JCuda 和 CUDA,内核参数的“结构”基本相同。当然你不能在Java中取“指针的地址”,但是间接次数是一样的。想象一下你有一个这样的内核:

__global__ void example(int value, float *pointer)

在 CUDA C API 中,您可以按如下方式定义内核参数:

int value = 123;
float *pointer= allocateSomeDeviceMemory();

int* pointerToValue = &value;
float** pointerToPointer = &pointer;

void **kernelParams = {
    pointerToValue,
    pointerToPointer
};

设置在 JCuda Java API 中类似地完成:

int value = 123;
Pointer pointer= allocateSomeDeviceMemory();

Pointer pointerToValue = Pointer.to(new int[]{value});
float** pointerToPointer = Pointer.to(pointer);

Pointer kernelParameters = Pointer.to(
    pointerToValue,
    pointerToPointer
);

这里相关的主要区别是您可以使用地址运算符在 C 中更简洁地编写它&

void **kernelParams = {
    &value,             // This can be imagined as a pointer to an int
    &pointer            // This can be imagined as a pointer to a pointer
};

但这与您提供的示例基本相同:

Pointer kernelParameters = Pointer.to(
    Pointer.to(new int[]{value}),   // A pointer to an int
    Pointer.to(pointer)             // A pointer to a pointer
);

再一次,关键是用类似的东西

void **kernelParams = {
    &value,
};

或者

Pointer kernelParameters = Pointer.to(
    Pointer.to(new int[]{value}),
);

您没有value直接将其传递给内核。相反,您告诉 CUDA:“这是一个指针数组。第一个指针指向一个int值。从该内存位置复制该值,并将其用作内核调用的实际值”。

于 2015-12-30T17:10:18.317 回答