我正在努力了解如何在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
值。从这个内存位置复制该值,并将其用作内核调用的实际值"。