我知道可以通过以下代码获得数组的大小:
int a = 12;
float b = 12.0f;
char c = 'c';
void *param[] = { (void*)&a, (void*)&b, (void*)&c };
// the element size of param
size_t size = sizeof(param)/sizeof(void*);
但是现在,我希望将param
传递给名为TryToGetTheSize
的函数,并获取大小作为返回值。
size_t TryToGetTheSize(void **array)
{
// return the size of void* array
}
...
size_t size = TryToGetTheSize(param);
我已经尝试过实现strlen
的想法,该想法将char*
指针递增地移动到下一个连续的存储空间,并通过检查当前位置的值是'\0'
来计数是否。
但是该方法不适用于void**
,无法检查void*
指定地址的有效性。
因此,似乎仅凭给定void** array
就无法知道大小,但是当我查找CUDA API时,我发现了这一点:
cudaLaunchKernel(const void* func, dim3 gridDim, dim3 blockDim, void** args, size_t sharedMem, cudaStream_t stream)
在CUDA中,我们通常使用<<<>>>
作为内核启动,但是如果我们手动设置标签并直接调用cudaLaunchKernel
则相同
在cudaLaunchKerenl
API中,我注意到第四个参数args
用作内核函数func
的参数,并且没有其他参数描述args
的大小>
所以,我有两个问题:
1)cudaLaunchKernel
如何知道void** args
的大小?
2)如果cudaLaunchKernel
不需要知道void** args
的大小,它是如何工作的?
这是我的示例代码,它们在内核启动时使用cudaLaunchKernel
而不是<<<>>>
。
#include<stdio.h>
#include<stdlib.h>
#include<cuda_runtime.h>
__global__
void saxpy(int n, float a, float *x, float *y)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < n) y[i] = a * x[i] + y[i];
}
int main(void)
{
int N = 1 << 20;
float *hx, *hy, *dx, *dy;
hx = (float*)malloc(N * sizeof(float));
hy = (float*)malloc(N * sizeof(float));
cudaMalloc(&dx, N * sizeof(float));
cudaMalloc(&dy, N * sizeof(float));
for (int idx = 0; idx < N; idx++)
{
hx[idx] = 1.0f;
hy[idx] = 2.0f;
}
cudaMemcpy(dx, hx, N * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(dy, hy, N * sizeof(float), cudaMemcpyHostToDevice);
unsigned int threads = 256;
unsigned int blocks = (N + 255) / threads;
float ratio = 2.0f;
//saxpy<<<blocks, threads>>>(N, ratio, dx, dy);
void *args[] = { &N, &ratio, &dx, &dy };
cudaLaunchKernel((void*)saxpy, dim3(blocks), dim3(threads), args, 0, NULL);
cudaMemcpy(hy, dy, N * sizeof(float), cudaMemcpyDeviceToHost);
float max_error = 0.0f;
for (int jdx = 0; jdx < N; jdx++)
{
max_error = max(max_error, abs(hy[jdx] - 4.0f));
}
printf("Max Error: %f\n", max_error);
cudaFree(dx);
cudaFree(dy);
free(hx);
free(hy);
return 0;
}
答案 0 :(得分:3)
内核参数的数量及其偏移量和大小不 需要指定,因为直接从中检索信息 内核的图像。
每个CUDA设备功能的参数列表都存储在静态编译的功能代码中。因此,API确切知道对cudaLaunchKernel
的调用需要多少个参数项。如果为启动调用提供的信息过多,则会出现段错误或不确定的行为。