fla*_*nik 13 c++ compiler-construction templates metaprogramming opencl
我是OpenCL的新手.
我有一个使用模板的算法.它在OpenMP并行化方面运行良好,但现在数据量已经增长,处理它的唯一方法是重写它以使用OpenCL.我可以轻松地使用MPI为集群构建它,但类似特斯拉的GPU比集群便宜得多:)
有没有办法在OpenCL内核中使用C++模板?
是否有可能以某种方式通过C++编译器或某些工具扩展模板,然后使用如此改变的内核函数?
编辑.解决方法的想法是以某种方式从模板中的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代码:它几乎总是无用的和编译过程包括其代,应被视为翻译的内部阶段.
stg*_*lov 15
有一种旧方法可以用纯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
Run Code Online (Sandbox Code Playgroud)
然后,我们在"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;
}
Run Code Online (Sandbox Code Playgroud)
在主.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
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用它:
double prec = TEMPLATE(NewtonRaphsonRsqrt, double, 4) (1.5, 0.5);
float approx = TEMPLATE(NewtonRaphsonRsqrt, float, 2) (1.5, 0.5);
Run Code Online (Sandbox Code Playgroud)
小智 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]);
}
Run Code Online (Sandbox Code Playgroud)
如果您真的决心完成它,您可以重新选择您的 C++ 编译器来生成 NVidia PTX(并且 Clang 很可能很快就能以任何方式做到这一点)。但这样您就可以将代码绑定到 NVidia 硬件。
另一种方法是基于当前的 CBE 为 LLVM 实现自定义后端,这将生成纯 OpenCL 代码而不是 C。