【问题标题】:Vectorising my scalar function向量化我的标量函数
【发布时间】:2016-01-08 20:51:41
【问题描述】:

假设我想计算一个升余弦。我可以有一个执行#define cos_raised(x) (0.5f + 0.5f * cos(x)) 的宏,但为了我的问题,我想让它成为一个函数,如下所示:

float cos_raised(float x)
{
    return 0.5f + 0.5f * cos(x);
}

这可以正常工作,但只能使用单个浮点输入,因为它可以很容易地向量化。如何正确矢量化它并使其接受 float2/3/4/8/16 作为输入和输出而不复制函数的主体(这是一个简单的示例,但对于更复杂的函数我需要知道这一点)?

编辑:我想我是在问如何制作一个 gentype 函数?只是输入gentype 是行不通的。

【问题讨论】:

  • 在你的内核中会有一个cos_raised 版本,还是有多个版本,即同时有一个float2 和一个float4 版本?如果总是只有一个版本,那么在构建内核时定义一些宏就可以了。
  • 什么宏?我们的想法是有一个单一的版本,但让它适用于那些不同的类型。
  • 我的意思是,假设您的内核仅在float cos_raised(floatN x) 版本上使用,但在您的程序实际运行之前您不知道floatN 将是什么。此方案适用于您将所有函数矢量化以使用相同矢量宽度的情况,但矢量宽度仅在运行时定义。如果是这种情况,您可以使用clBuildProgramoptions 参数并传递类似"-D floatN=float2" 的内容。这样,您的代码中就有了该函数的单一版本,并且它将适用于为floatN 输入的任何类型。这够了吗?
  • 哦,我明白了。这是一个有趣的想法,但不够笼统,因为我可能想把它混为一谈。

标签: opencl vectorization


【解决方案1】:

IIRC:遗憾的是,“gentype”是一个仅存在于 OpenCL 文档中的概念,它实际上并不是一种允许您自己创建通用/类似模板的函数的语言特性。这意味着没有简单的方法可以做你想做的事,你可能需要使用一些预处理器来减少代码重复。参见例如这个 SO 线程:How to use C++ templates in OpenCL kernels? 它提供的知识比我所能提供的更多。

【讨论】:

    【解决方案2】:

    如果编译器在进行矢量化之前内联所有函数调用,那么您就大功告成了。顺便说一句,矢量化可能只需要 CPU 执行,因为现在大多数 GPU 都是标量的。

    【讨论】:

    • 怎么样?因为它只是用 float4 喂 cos_raised() 无法编译。
    • 对不起,我不明白你的问题。请重新声明。
    • 我准备好了吗?我该怎么做才能让它像这样工作?因为它不会编译。
    • 对不起,我看错了。如果您想要采用矢量类型的函数版本,则需要编写每个版本。
    【解决方案3】:

    由于 OpenCL 内核是在运行时编译的,因此您可以在内核的开头添加额外的代码行。我会通过这样的模板函数(例如存储在单独的文本文件中)来使用它:

    float{N:} cos_raised_float{N:}(float{N:} x)
    {
        return 0.5f + 0.5f * cos(x);
    }
    

    由于我更熟悉 Python,因此我使用它的语法来指定字符串中的占位符,即{N:}。您必须为您的主机代码语言找到类似的东西。此后,只需循环通过 2、3、4、8 和 16,每次填写 {N:}。这为您提供了五个额外的字符串,您需要将它们添加到内核代码的开头。不利的一面是,您必须想出一些方法来在主内核代码中指示所有这些生成的函数应该插入的位置。它们需要出现在所有 #pragma XXX: enable 语句之后。之后,您的内核可以调用任何版本,例如cos_raised_float4.

    【讨论】:

      猜你喜欢
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-19
      • 1970-01-01
      • 2013-10-09
      • 2015-10-11
      • 1970-01-01
      相关资源
      最近更新 更多