我有一个简单的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)
。这会产生错误“没有合适的构造函数在float
和float2
之间进行转换”。如何构造向量文字?
它最后抱怨的是*
的{{1}}和float
的行没有float2
运算符。如果删除dt*f(x[i])
并将其设置为dt*
,则会抱怨x[i] += f(x[i])
和+=
没有float2
运算符。如何对这些类型执行运算,我可以将向量和标量相乘吗?
在Metal中,当我将函数定义为float2
时,在运行时加载内核函数时,Metal内核编译器将JIT特定的内核优化版本。 Cuda有此功能吗?
答案 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中实现这些操作。