cudaLaunchKernel如何知道“ void ** args”的数组大小?

时间:2018-12-25 08:07:05

标签: c++ c cuda

我知道可以通过以下代码获得数组的大小:

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;
}

1 个答案:

答案 0 :(得分:3)

引用related documentation

  

内核参数的数量及其偏移量和大小不   需要指定,因为直接从中检索信息   内核的图像。

每个CUDA设备功能的参数列表都存储在静态编译的功能代码中。因此,API确切知道对cudaLaunchKernel的调用需要多少个参数项。如果为启动调用提供的信息过多,则会出现段错误或不确定的行为。