在编写类似的CUDA内核时,如何避免在没有宏的情况下重复自己
How not to repeat myself without macros when writing similar CUDA kernels?
我有几个CUDA内核基本上是做相同的一些变化。我想做的是减少所需的代码量。我的第一个想法是使用宏,所以我得到的内核看起来像这样(简化):
__global__ void kernelA( ... )
{
INIT(); // macro to initialize variables
// do specific stuff for kernelA
b = a + c;
END(); // macro to write back the result
}
__global__ void kernelB( ... )
{
INIT(); // macro to initialize variables
// do specific stuff for kernelB
b = a - c;
END(); // macro to write back the result
}
...
因为宏是讨厌的,丑陋的和邪恶的,我正在寻找一个更好的和更干净的方式。有什么建议吗?
(一个switch语句不能完成这项工作:实际上,相同的部分和特定于内核的部分是相当交织的。需要几个switch语句,这将使代码非常难以读懂。此外,函数调用不会初始化所需的变量。)
(这个问题可能对一般c++也是负责的,只需将所有的'CUDA内核'替换为'函数'并删除'__global__')
更新:我在评论中被告知,类和继承不能很好地与CUDA混合。因此,只有答案的第一部分适用于CUDA,而其他部分是对您问题中更一般的c++部分的回答。
对于CUDA,你必须使用纯函数,"c风格":
struct KernelVars {
int a;
int b;
int c;
};
__device__ void init(KernelVars& vars) {
INIT(); //whatever the actual code is
}
__device__ void end(KernelVars& vars) {
END(); //whatever the actual code is
}
__global__ void KernelA(...) {
KernelVars vars;
init(vars);
b = a + c;
end(vars);
}
这是通用c++的答案,在c++中,您可以使用像构造函数和析构函数这样的OOP技术(它们非常适合那些init/end对),或者可以与其他语言一起使用的模板方法模式:
使用ctor/dtor和模板," c++风格":
class KernelBase {
protected:
int a, b, c;
public:
KernelBase() {
INIT(); //replace by the contents of that macro
}
~KernelBase() {
END(); //replace by the contents of that macro
}
virtual void run() = 0;
};
struct KernelAdd : KernelBase {
void run() { b = a + c; }
};
struct KernelSub : KernelBase {
void run() { b = a - c; }
};
template<class K>
void kernel(...)
{
K k;
k.run();
}
void kernelA( ... ) { kernel<KernelAdd>(); }
使用模板方法模式,通用的"OOP风格"
class KernelBase {
virtual void do_run() = 0;
protected:
int a, b, c;
public:
void run() { //the template method
INIT();
do_run();
END();
}
};
struct KernelAdd : KernelBase {
void do_run() { b = a + c; }
};
struct KernelSub : KernelBase {
void do_run() { b = a - c; }
};
void kernelA(...)
{
KernelAdd k;
k.run();
}
您可以使用设备函数作为"INIT()"answers"END()"的替代。
__device__ int init()
{
return threadIdx.x + blockIdx.x * blockDim.x;
}
另一种选择是使用函数模板:
#define ADD 1
#define SUB 2
template <int __op__> __global__ void caluclate(float* a, float* b, float* c)
{
// init code ...
switch (__op__)
{
case ADD:
c[id] = a[id] + b[id];
break;
case SUB:
c[id] = a[id] - b[id];
break;
}
// end code ...
}
,并使用:
calcualte<ADD><<<...>>>(a, b, c);
CUDA编译器完成工作,构建不同的函数版本并删除死代码部分以进行性能优化。
相关文章:
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 在这种情况下,工会成员会调用自己的析构函数吗
- 尝试在没有opencv calcHist()的情况下计算我自己的直方图
- 允许人们在没有端口转发的情况下主持自己的多人游戏
- 在某些情况下,编写自己的复制构造函数而不是自己的赋值运算符是个好主意吗
- 使用自己的比较器运算符()进行映射<>。在找不到 KEY 的情况下给出错误
- 在这种情况下,编译器可以根据自己的意愿对指令进行重新排序
- 在编写类似的CUDA内核时,如何避免在没有宏的情况下重复自己
- Mac GUI应用程序如何在不使用Sparkle的情况下重新启动自己?
- 如果我自己的构造函数必须在不诉诸"new"的情况下抛出,如何缓解聚合对象构造函数的异常?
- C++ : 如何在不复制和粘贴的情况下做到这一点?它循环自己