【问题标题】:OpenCL can't set kernel args for constant arrayOpenCL 无法为常量数组设置内核参数
【发布时间】:2016-03-06 12:59:15
【问题描述】:

我正在尝试设置内核的参数,当我尝试设置 arg-0 时,我不断收到 CL_INVALID_ARG_SIZE,这是界限。奇怪的是,如果我只是注释掉第一个 clSetKernelArgs 其他所有似乎都可以工作。我认为这可能是常量数组的问题,除了它适用于 rand_seeds。

success = clSetKernelArg(solver_kernel, 0, sizeof(cl_float) * 10, bounds);
    if(success != CL_SUCCESS)
    {
        printf("%d\n", success);
        exit(1);
    }
    success = clSetKernelArg(solver_kernel, 1, sizeof(cl_float) * 2, seeds);
    if(success != CL_SUCCESS)
    {
        printf("%d\n", success);
        exit(1);
    }
    success = clSetKernelArg(solver_kernel, 2, sizeof(cl_int), &trials);
    if(success != CL_SUCCESS)
    {
        printf("%d\n", success);
        exit(1);
    }
    success = clSetKernelArg(solver_kernel, 3, sizeof(cl_int), &start_temp);
    if(success != CL_SUCCESS)
    {
        printf("%d\n", success);
        exit(1);
    }

这是我的内核的头文件

  __kernel void solver_kernel
    (
        __constant float bounds[10],
        __constant int rand_seeds[2],
        int trials,
        int start_temp
    )

【问题讨论】:

    标签: c opencl nvidia


    【解决方案1】:

    来自OpenCL specification

    指定为参数值的内存对象必须是缓冲区对象 (或 NULL)如果参数被声明为内置指针或 带有__global__constant 限定符的用户定义类型。

    所以你必须首先创建一个缓冲区并将其设置为你的内核参数。应该是这样的

    cl_mem bounds_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * 10, bounds, &success); 
    success = clSetKernelArg(solver_kernel, 0, sizeof(cl_mem), bounds_buffer);
    

    您需要对 rand_seeds 参数执行相同的操作,即使您在这一行没有收到错误(可能是因为 sizeof(cl_float) * 2 == sizeof(cl_mem) 偶然,仍然会产生不正确的结果)。

    【讨论】:

    • 所以当我说 CL_MEM_READ_ONLY 时,它会进入常量内存。因为我知道我的常量内存比全局内存少得多。为什么我问这个是我可能想创建一个大缓冲区(在全局内存中),我只会使用 CL_MEM_READ_ONLY 读取它。
    • __constant 参数的缓冲区大小的实际限制在我上面链接到的页面上指定。您可以使用 CL_MEM_READ_ONLY 标志分配更大的缓冲区,但不能将它们用作声明为 __constant 的参数的值。
    • 好的,谢谢。我是 CUDA 程序员,我只是习惯于声明常量,直接使用 cudaMemcpyToSymbol 来初始化它们。
    【解决方案2】:

    如果您的缓冲区永远不会改变,您不需要使用缓冲区 + __constant 方式。这是另一种选择。

    实际上有两种在内核中使用常量内存的方法:

    • 使用标准缓冲区 + __constant 标志
    • 使用结构参数

    首选第一个(请使用@Jan 接受的答案),因为您明确说明了您希望如何处理您的数据。但在实践中,所有实现也为第二种情况使用常量内存。因为它传递给内核的数据是静态的,无论如何都不可修改。

    所以,你可以像这样重写你的内核:

     typedef struct float_10 { float f[10];} float_10;
     typedef struct int_2 { int i[2];}int_2;
    
      __kernel void solver_kernel
        (
            float_10 bounds,
            int_2 rand_seeds,
            int trials,
            int start_temp
        )
    

    应该具有相同的性能。

    已编辑:因为您需要结构,而不是数组

    【讨论】:

    • 所以在普通 C 中,即使我给函数参数提供数组边界,它仍然被视为指针,所以我认为这在 opencl c 中有所不同?
    • 现在你让我怀疑了......这两个值具有相同的大小,但是它们受到的威胁不同。也许这个答案是无效的。
    • 我认为你需要将它包装在一个结构中。
    • 已编辑 sicne 我不确定其他方法。 Thoug 应该是破解它的一种方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 2017-10-09
    • 2012-02-05
    • 2020-10-01
    相关资源
    最近更新 更多