【发布时间】:2018-01-16 03:59:37
【问题描述】:
有没有一种聪明的方法可以减少 CUDA 内核中 if statements 的数量?
我正在编写一个计算多体哈密顿量的应用程序(模拟量子系统)。计算高度依赖于conditional expressions。
我想减少这些语句的原因是它们引入了性能开销。 (整个warp 输入if(){} else if(){} 语句的每个选项 - 如果不满足条件,则thread 在给定时间内保持不活动状态。
问题:
1. switch() 语句能解决问题吗?
2. 下面的代码是为了代表一个总体思路:
class tag_option_1 {};
class tag_option_2 {};
class tag_option_3 {};
template<typename T> __device__
int cal_something(int ab, int cd)
{
return -12345; // error value. default case is an error.
};
template<> __device__
int cal_something<tag_option_1>(int ab, int cd)
{
// return something
}
template<> __device__
int cal_something<tag_option_2>(int ab, int cd)
{
// return something
}
template<> __device__
int cal_something<tag_option_3>(int ab, int cd)
{
// return something
}
////////////////////////////////
// version #1:
__global__
void calc_hamiltonian(int * foo, int * bar)
{
unsigned int tid = /* calce thread index*/;
// do something...
if (/* condition */)
{
cal_something<tag_option_1>(foo[tid], bar[tid]);
}
else if(/* condition */)
{
cal_something<tag_option_2>(foo[tid], bar[tid]);
}
else if(/* condition */)
{
cal_something<tag_option_3>(foo[tid], bar[tid]);
}
// no default case.
// do something...
}
////////////////////////////////
// version #2:
// "magical" way to select a version:
// variant is meant to be something like "boost::variant" but implementented without a single "if" statement.
// This "magical" step is meant to be resolved at compile time.
__devcie__
variant <tag_option_1, tag_option_2, tag_option_3>
version_selector(int ab, int cd)
{
// magic happens here.
}
__global__
void calc_hamiltonian(int * foo, int * bar)
{
unsigned int tid = /* calce thread index*/;
// do something...
cal_something <version_selector(foo[tid], bar[tid])> (foo[tid], bar[tid]);
// do something...
}
有没有办法实现上面例子的version #2,或者在CUDA C/C++中是不可能的?
【问题讨论】:
-
根据结果做出决定的任何评估都是分支代码。这包括
if-statements、switch-statements、三元组、循环条件等。 GPU 对所有这些的支持都很差:( -
您做出了许多不一定正确的假设。 CUDA GPU 支持谓词执行,编译器不一定会发出代码,这些代码将为发出分支的代码(例如 if、switch 或任何其他类似结构)产生指令重放。
-
除了@talonmies cmets,我看到的唯一建议是尝试组织您的代码(实际上是数据),以便在扭曲边界上发生分支。如果这样的事情是可能的,你的代码仍然可以利用条件执行,但不会为此付出太多的代价,就像内部扭曲分支的情况一样。此外,任何将类似路径组合在一起的东西(例如输入数据的排序)都可能有助于降低扭曲散度的净成本。通常,当分析器表明这是一个需要解决的顶级问题时,我们会解决此问题。
-
除了@talonmies 指出的谓词执行之外,GPU 还支持 CUDA 编译器用来避免分支的选择类型指令(例如
SEL)。我的长期建议是:以自然的风格编写 CUDA 代码,不要担心源代码中的分支,直到分析器告诉您它们对由于分歧导致的性能瓶颈负责。如果你提供了一个具体的例子(我们可以编译的代码),这个问题可能是可以回答的。否则,我认为它“过于宽泛”。 -
@njuffa:在我的回答中提到了
slct。我其实不认为它太宽泛。
标签: c++ cuda control-flow idioms