无法理解jCuda cuLaunchKernel是如何工作的



我正在努力了解如何在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, ...)???

感谢

JCuda的cuLaunchKernel函数对应于CUDA的cuLaunchKernel函数。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) 

其中CCD_ 3是与该问题相关的唯一参数。文件显示

内核参数可以通过kernelParams指定。如果f有N个参数,那么kernelParams需要是N个指针的数组。kernelParams[0]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值。从这个内存位置复制该值,并将其用作内核调用的实际值"。

相关内容

  • 没有找到相关文章

最新更新