我是OpenCL的新手。
我有一个使用模板的算法。它在OpenMP并行化方面运行良好,但现在数据量已经增长,处理它的唯一方法是重写它以使用OpenCL。 我可以轻松地使用MPI为集群构建它,但类似特斯拉的GPU比集群便宜得多:)
有没有办法在OpenCL内核中使用C ++模板?
是否可以通过C ++编译器或某种工具以某种方式扩展模板,之后使用如此改变的内核函数?
EDIT。解决方法的想法是以某种方式从模板中的C ++代码生成与C99兼容的代码。
我发现了关于Comeau的一些信息:
Comeau C ++ 4.3.3是一个完整而真实的编译器,可执行完整的语法检查,完整的语义检查,完整的错误检查以及所有其他编译器职责。输入C ++代码被转换为内部编译器树和符号表,看起来不像C ++或C.同样,它生成一个内部专有的中间形式。但是,Comeau C ++ 4.3.3不是使用专有的后端代码生成器,而是生成C代码作为输出。除了C ++的技术优势之外,Comeau C ++ 4.3.3等产品的C生成方面也被吹捧为C ++成功的原因,因为C编译器的普遍可用性使其能够被带到大量平台。
仅使用C编译器,仅用于获取本机代码。这意味着Comeau C ++专为与各个平台上的特定C编译器一起使用而定制。请注意,要求剪裁必须由Comeau完成。否则,生成的C代码没有意义,因为它绑定到特定平台(其中平台至少包括CPU,OS和C编译器),此外,生成的C代码不是独立的。因此,它不能单独使用(请注意,这在使用Comeau C ++时是技术和法律要求),这就是为什么通常没有选项来查看生成的C代码:它几乎总是无用的和编译过程包括其代,应被视为翻译的内部阶段。
答案 0 :(得分:14)
有一种旧的方法可以用纯C语言模拟模板。 它基于多次包含单个文件(不包括保护)。 由于OpenCL具有功能齐全的预处理器并允许包含文件,因此可以使用此技巧。
这是一个很好的解释: http://arnold.uthar.net/index.php?n=Work.TemplatesC
它仍然比C ++模板更麻烦:代码必须分成几个部分,你必须显式实例化每个模板实例。此外,您似乎无法做一些有用的事情,例如将factorial实现为递归模板。
让我们将这个想法应用于OpenCL。假设我们想通过Newton-Raphson迭代计算逆平方根(通常不是一个好主意)。但是,浮点类型和迭代次数可能会有所不同。
首先,我们需要一个帮助头(“templates.h”):
#ifndef TEMPLATES_H_
#define TEMPLATES_H_
#define CAT(X,Y,Z) X##_##Y##_##Z //concatenate words
#define TEMPLATE(X,Y,Z) CAT(X,Y,Z)
#endif
然后,我们在“NewtonRaphsonRsqrt.cl”中编写模板函数:
#include "templates.h"
real TEMPLATE(NewtonRaphsonRsqrt, real, iters) (real x, real a) {
int i;
for (i = 0; i<iters; i++) {
x *= ((real)1.5 - (0.5*a)*x*x);
}
return x;
}
在主.cl文件中,按如下方式实例化此模板:
#define real float
#define iters 2
#include "NewtonRaphsonRsqrt.cl" //defining NewtonRaphsonRsqrt_float_2
#define real double
#define iters 3
#include "NewtonRaphsonRsqrt.cl" //defining NewtonRaphsonRsqrt_double_3
#define real double
#define iters 4
#include "NewtonRaphsonRsqrt.cl" //defining NewtonRaphsonRsqrt_double_4
然后可以像这样使用它:
double prec = TEMPLATE(NewtonRaphsonRsqrt, double, 4) (1.5, 0.5);
float approx = TEMPLATE(NewtonRaphsonRsqrt, float, 2) (1.5, 0.5);
答案 1 :(得分:5)
我已经为OpenCL C源转换工具编写了一个实验性的C ++。该工具将C ++源代码(甚至一些STL)编译为LLVM字节代码,并使用修改后的LLVM“C”后端版本将字节代码反汇编为OpenCL“C”。
请参阅http://dimitri-christodoulou.blogspot.com/2013/12/writing-opencl-kernels-in-c.html
例如,使用C ++ 11的std :: enable_if的代码可以转换为OpenCL'C',然后在GPU上执行:
#include <type_traits>
template<class T>
T foo(T t, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
{
return 1;
}
template<class T>
T foo(T t, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
{
return 0;
}
extern "C" void _Kernel_enable_if_int_argument(int* arg0, int* out)
{
out[0] = foo(arg0[0]);
}
答案 2 :(得分:3)
您可以查看使用表达式模板生成OpenCL内核的VexCL。您可以了解如何使OpenCL与模板很好地协作。
正在积极处理的另一个库是Boost.Compute,它是OpenCL之上的一个层,允许使用通用C ++代码。
一般的想法是将内核或多或少地创建为C字符串,并将其传递给OpenCL运行时以进行编译和执行。
答案 3 :(得分:2)
如果你真的决定要完成它,你可以重新定位你选择的C ++编译器来生成NVidia PTX(并且Clang很可能很快就能做到)。但是这样你就可以将你的代码绑定到NVidia硬件了。
另一种方法是基于当前的CBE实现LLVM的自定义后端,它将生成纯OpenCL代码而不是C。
答案 4 :(得分:0)
请注意,新的SYCL Khronos标准在OpenCL中对C ++模板提供原生支持。
答案 5 :(得分:-2)
PyOpenCL现在使用Mako作为它的模板引擎。 http://www.makotemplates.org/