我正在开发一个CUDA应用程序,它要求我将一些任意函数传递给CUDA内核。由于为每种可能的情况声明一个函数指针并将它们传递给内核将会太麻烦(> 50个不同的函数),并且它们都是基本函数的组合,如sin(x)/y
,我想要一些最小的Lambda - CUDA内核的表达功能。由于C++ 11功能尚未被设备代码支持(据我所知),并且我没有在网上找到任何相关信息,于是我决定自学自定义表达式模板并实现一些简单的lambda表达式规则以传入内核。在Cuda中使用表达式模板构建lambda表达式
我想出了下面的代码,这是一种在NVCC上编译并运行良好的最小实现。然而,沿着这条道路,我只能用1个变量来实现函数。有什么方法可以扩展我的代码来处理函数组合,如sin(_x) + _y
?
在此先感谢!
#include<math.h>
#ifdef __CUDACC__
#define HOST_DEVICE __host__ __device__
#else
#define HOST_DEVICE
#endif
struct Id {};
template <typename Op, typename Left, typename Right>
struct BinaryOp
{
Left left;
Right right;
HOST_DEVICE BinaryOp(Left t1, Right t2) : left(t1), right(t2) {}
HOST_DEVICE double operator() (double x) {
return Op::apply(left(x), right(x));
}
};
template <typename Op, typename Arg>
struct UnaryOp
{
Arg arg;
HOST_DEVICE UnaryOp(Arg t1) : arg(t1) {}
HOST_DEVICE double operator() (double x) {
return Op::apply(arg(x));
}
};
template <>
struct UnaryOp<Id, double>
{
HOST_DEVICE UnaryOp() {}
HOST_DEVICE double operator() (double x) {
return x;
}
};
struct Sin
{
HOST_DEVICE static double apply(double x) {
return sin(x);
}
};
struct Plus
{
HOST_DEVICE static double apply(double a, double b) {
return a + b;
}
};
template <typename Left, typename Right>
BinaryOp<Plus, Left, Right> operator+ (Left lhs, Right rhs) {
return BinaryOp<Plus, Left, Right>(lhs, rhs);
}
template <typename Arg>
UnaryOp<Sin, Arg> _sin(Arg arg) {
return UnaryOp<Sin, Arg>(arg);
}
template <class T>
__global__ void test(T func, double x) {
printf("%e\n", func(x));
}
int main()
{
UnaryOp<Id, double> _x;
double x = 1.0;
test<<<1, 1>>>(_sin(_x) + _x, x);
cudaDeviceSynchronize(); // Needed or the host will return before kernel is finished
return 0;
}
看[表达式模板](http://en.wikipedia.org/wiki/Expression_templates)。 – Constructor
@Constructor谢谢,但我已详细阅读,并提出了自己的代码来实现表达式模板。但是我不认为该页面有足够的信息用于我想要做的事情:构建超过1个变量的lambda表达式。 –
你能向我解释为什么你所做的比仅仅函数指针更简单吗?我真的很想知道。我一直盯着你的代码2天,我仍然没有看到优势 – portforwardpodcast