在编写类似的CUDA内核时,如何在没有宏的情况下重复自己?

Dir*_*irk 1 c++ macros cuda dry

我有几个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
}
...
Run Code Online (Sandbox Code Playgroud)

由于宏是讨厌的,丑陋的和邪恶的,我正在寻找一种更好,更清洁的方式.有什么建议?

(switch语句不能完成这项工作:实际上,相同的部分和特定于内核的部分是相互交织的.需要几个switch语句才能使代码变得难以理解.此外,函数调用不会初始化所需的变量.)

(这个问题也可能对一般的C++负责,只需用'function'替换所有'CUDA内核'并删除'__global__')

Arn*_*rtz 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);
}
Run Code Online (Sandbox Code Playgroud)

这是一般C++的答案,你可以使用构造函数和析构函数等OOP技术(它们非常适合那些初始/结束对),或者也可以使用其他语言的模板方法模式:

使用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>(); }
Run Code Online (Sandbox Code Playgroud)

使用模板方法模式,一般"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();
}
Run Code Online (Sandbox Code Playgroud)