我有几个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 ++也可能是有问题的,只需用'function'替换所有'CUDA内核'并删除'__global__')
答案 0 :(得分:5)
更新:我在评论中告诉我,类和继承与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 ++的答案,你可以使用构造函数和析构函数等OOP技术(它们非常适合那些初始/结束对),或者也可以使用其他语言的模板方法模式: / p>
使用ctor / dtor和模板,“C ++ Style”:
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();
}
答案 1 :(得分:1)
您可以将设备功能用作&#34; INIT()&#34;和&#34; END()&#34;替代品。
__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编译器完成工作,构建不同的函数版本并删除死代码部分以进行性能优化。