相当于Metal Compute内核的Cuda内核

时间:2019-01-18 23:09:18

标签: cuda metal

我有一个简单的Metal计算内核,我正在尝试使其等效于Cuda。金属内核的来源是

#include <metal_stdlib>
using namespace metal;

constant uint stride [[function_constant(0)]];
constant float dt    [[function_constant(1)]];
constant float a     [[function_constant(2)]];
constant float b     [[function_constant(3)]];

float2 f(const float2 x) {
    return float2(a, -b)*x.yx;
}

kernel void harmonic_occilator_stride(device float2 *x [[buffer(0)]],
                                             uint    i [[thread_position_in_grid]]) {
    for (uint j = 0; j < stride; j++) {
        x[i] += dt*f(x[i]);
    }
}

我第一次尝试将其转换为Cuda会导致在编译ptx文件时出现很多错误。

__constant__ uint  stride;
__constant__ float dt;
__constant__ float a;
__constant__ float b;

__device__ float2 f(const float2 x) {
    return float2(a, -b)*x.yx;
}

extern "C" __global__ void harmonic_occilator_stride(float2 *x) {
    size_t i = blockIdx.x*blockDim.x + threadIdx.x;
    for (uint j = 0; j < stride; j++) {
        x[i] += dt*f(x[i]);
    }
}

它不喜欢的第一件事是x.yx。在Metal中,这将反转float2内容的顺序。如何在Cuda中反转或更改向量的访问顺序?

接下来的事情它也不喜欢float2(a, -b)。这会产生错误“没有合适的构造函数在floatfloat2之间进行转换”。如何构造向量文字?

它最后抱怨的是*的{​​{1}}和float的行没有float2运算符。如果删除dt*f(x[i])并将其设置为dt*,则会抱怨x[i] += f(x[i])+=没有float2运算符。如何对这些类型执行运算,我可以将向量和标量相乘吗?

在Metal中,当我将函数定义为float2时,在运行时加载内核函数时,Metal内核编译器将JIT特定的内核优化版本。 Cuda有此功能吗?

1 个答案:

答案 0 :(得分:1)

我现在只看了metal specification。我不会尝试完全解决您的最后一个问题。但是我认为语法问题可以从概念上回答,只需处理各种组件并遵循metal定义的算术规则即可。

  

它也不喜欢float2(a,-b)。这给出了错误“没有合适的构造函数在float和float2之间进行转换”。如何构造向量文字?

为此,请使用头文件vector_functions.h(或.hpp)中定义的函数。 (请参见下面的示例)在vector_types.h中为CUDA定义的向量类型没有构造函数。

  

它不喜欢的第一件事是x.yx。在Metal中,这将反转float2内容的顺序。如何在Cuda中反转或更改向量的访问顺序?

CUDA没有这种内置的多个矢量元素处理/旋转功能。只需使用元素类型对元素执行操作即可。

metal:  return float2(a, -b)*x.yx;

CUDA:   #include <vector_functions.h>
        ...
        return make_float2(a*x.y, -b*x.x);
  

它最后抱怨的是,对于dt f(x [i])行的float和float2没有*运算符。如果删除dt 并将其设置为x [i] + = f(x [i]),则会抱怨没有float =和float2的+ =运算符。如何对这些类型执行运算,我可以将向量和标量相乘吗?

与上述类似,您需要在等效的算术元素上进行构造。

metal:  x[i] += dt*f(x[i]);

CUDA:   float2 temp1 = x[i];
        float2 temp2 = f(temp1);
        temp1.x += dt*temp2.x;
        temp1.y += dt*temp2.y;
        x[i] = temp1;

应该有可能定义一组自己的向量类型,以匹配金属的大多数功能。我在这里描述的内容使用的是“内置”功能,如果您想使用构造函数,算术运算符等创建自己的类型,则可以作为模型。

关于您的最后一个问题,CUDA并不总是在运行时按照您描述金属的方式进行JIT。可能最接近您所描述的内容可能是使用CUDA支持的C ++模板的内容。通常,如果您可以将金属操作转换为等效的C ++操作,则应该能够直接在CUDA中实现这些操作。