【问题标题】:OpenCL max_work_item_sizesOpenCL max_work_item_sizes
【发布时间】:2021-04-20 17:34:10
【问题描述】:

我无法理解工作项约束的含义。我正在使用pyopencl 并查看max_work_item_sizes,它给出了我假设的每个维度的最大全局工作线程数。

import pyopencl as cl
import numpy as np

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

queue.device.max_work_item_sizes # [1024, 1024, 64]

我可以通过以下方式模拟np.arange 函数:

prg = cl.Program(ctx, """
__kernel void arange(__global int *res_g)
{
  int gid = get_global_id(0);
  res_g[gid] = gid;
}
""").build()

res_g = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, 4 * 4096)
prg.arange(queue, [4096], None, res_g)

# transfer back to cpu
res_np = np.empty(4096).astype(np.int32)
cl.enqueue_copy(queue, res_np, res_g)

assert (res_np == np.arange(4096)).all() # this is true

如何为第一个维度指定超过 1024 个工作项? max_work_item_sizes 是什么意思?

与此相关的另一个问题是使用尽可能多的工作维度是否有益?据我了解,最多可以使用 3 个维度。使用 2 个工作项维度模拟 np.arange 的方法可以通过以下方式完成:

prg = cl.Program(ctx, """
__kernel void arange(__global int *res_g)
{
  int gid = get_global_id(0) * get_global_id(1);
  barrier(CLK_GLOBAL_MEM_FENCE);
  res_g[gid] = gid;
}
""").build()

res_g = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, 4 * 4096)
prg.arange(queue, [64, 64], [1,1], res_g)

# transfer back to cpu
res_np = np.empty(4096).astype(np.int32)
cl.enqueue_copy(queue, res_np, res_g)

assert (res_np == np.arange(4096)).all()

由于某种原因,断言并不总是正确的

但我的问题是,在处理大型数组时,是否最好使用全部 3 个work_item_dimensions?还是将数组视为一维连续数组并仅使用get_global_id(0) 更好?

【问题讨论】:

    标签: python arrays numpy opencl pyopencl


    【解决方案1】:

    如何为第一个指定超过 1024 个工作项 方面? max_work_item_sizes 是什么意思?

    max_work_item_sizes 返回每​​个维度中每个工作组的最大工作项数。

    通过将None 作为第三个参数传递:

    prg.arange(queue, [4096], None, res_g)
                              ^^^^
    

    要求实施选择最佳的工作组规模。可以通过这种方式检查工作组大小,例如:

    res_g[gid] = get_local_size(0);
    

    在我的系统max_work_item_sizes=[4096, 4096, 4096] 中,get_local_size(0) 返回的值为 1024,这意味着实施决定工作组大小为 1024 项,而 4096 / 1024 为我们安排了 4 个工作组。

    指定工作组大小,例如到 256 个工作项:

    prg.arange(queue, [4096], [256], res_g)
    

    将安排 4 倍的工作组。

    与此相关的另一个问题是使用尽可能多的 工作尺寸尽可能?据我了解可以使用 3 最大尺寸。

    但我的问题是,在处理大型数组时,是否更好 利用所有 3 个 work_item_dimensions?还是治疗比较好 数组作为一维连续数组并且只使用 get_global_id(0)?

    根据我的经验,使用一个或多个维度没有区别。所以你做对你来说更方便。

    由于某种原因,断言并不总是正确的

    那是因为您的代码中存在错误。计算索引应该是:

    int gid = get_global_id(0) * get_global_size(0) + get_global_id(1);
    

    【讨论】:

    • 谢谢。那么查看documentationmax_work_item_sizes 是否为每个对应维度指定了最大local_size(或工作组大小)?如果我设置local_size=Noneglobal_size 是否有任何限制?
    • max_work_item_sizesget_local_size(dimension)可以在内核内部查询到的工作组中的最大工作项数;是否指定local_sizeglobal_size 的值没有任何影响。只是限制是global_size 必须是可被local_size 整除的数字。我没有听说 global_size 有任何限制,但它可能受到用于它的数据类型或处理如此大内核所需的资源的限制(例如,需要将更多数据传递给受全局内存限制的内核大小)。
    • 我还有一个问题:在 gpu 上进行简单的运算(如乘法和加法)时,最好将 local_size 指定为 1 并且不启动任何不必要的线程(如果有意义的话) ?由于进行了 addition,我们只需要在两个数组(操作数)大小相同的情况下使用 get_global_id(0)
    • 指定 local_size=1 可能会损害性能。对于 1D(对于大于或等于 2 维的 2D 乘法),最小 local_size 应该是 32 或 64。但是如果算法只使用 global_id/size 那么通常最好让实现来决定最佳的本地大小。
    猜你喜欢
    • 1970-01-01
    • 2014-06-15
    • 2018-05-16
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 2021-08-05
    相关资源
    最近更新 更多