我正在开发一些并行的C ++模拟代码,我想尽可能有效地进行矢量化。这就是我使用模板参数和OpenMP SIMD指令的原因:
我的意思的一个(愚蠢的)例子如下:
template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n ) {
#pragma omp simd
for ( int i = 0; i < n; i++ ) {
if ( checkNeeded ) { // dead code removed by the compiler when template is false
if ( denom == 0 ) {
std::cout << "Houston, we've got a problem\n";
return i;
}
}
res[i] = num[i] / denom[i];
}
return n;
}
在全球范围内,它运行良好,但我遇到的麻烦是在(非常罕见的)我希望使用代码的ratio<true>()
版本的情况下,这个由编译器进行了矢量化,因为#pragma omp simd
指令,由于测试,打印和循环的早期退出,比非矢量化版本慢...
所以我需要的是在我的if
指令中添加simd
子句,指示编译器何时服从指令。这会是这样的:
#pragma omp simd if( checkNeeded == false )
不幸的是,尽管许多OpenMP指令支持这样的if
条款,但它不适用于simd
...我不认为我的请求是完全愚蠢的,所以我想知道为什么是这样的,以及它是否有可能在未来得到支持。
有人知道吗?
答案 0 :(得分:2)
我不认为我的请求是完全愚蠢的,所以我想知道为什么 所以,以及它是否有可能在未来得到支持。任何人 我知道吗?
SIMD指令在编译时影响代码生成,而&#34; if&#34;其他OpenMP构造的子句实现了运行时测试。 (&#34; if&#34;条件不是编译时常量)。实施&#34; if&#34;因此,在SIMD子句中,需要编译器克隆循环体并生成两个不同的版本,然后选择在运行时动态执行的版本。
这对于一个非常罕见的情况似乎付出了很多努力,所以我怀疑它是否会成为标准。 (而且,无论如何,在这一点上,你可以看到它的第一个标准是赢了几年,所以你可能需要更实用的修复: - )
答案 1 :(得分:1)
扩展user3528438的注释,这可能是将您的功能分成两个不同功能的最合理的地方之一。一个处理false
的情况,并按照您的方式编写,另一个处理true
情况并且没有simd命令。
或者,如果你坚持使用一个功能,你可以很容易地写
template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n ) {
if (!checkNeeded) {
#pragma omp simd
for ( int i = 0; i < n; i++ ) {
res[i] = num[i] / denom[i];
}
return n;
} else {
for ( int i = 0; i < n; i++ ) {
if ( denom == 0 ) {
std::cout << "Houston, we've got a problem\n";
return i;
}
res[i] = num[i] / denom[i];
}
return n;
}
}
这会比false
案例中的初始函数稍慢,因为有一个if语句要评估(假设n
很大,则不是一个很重要的因素[甚至大于10且你不应该'注意减速])。此外,true
情况会更快,因为您不必每次迭代都要评估第一个if语句。
答案 2 :(得分:0)
template< bool checkNeeded >
int ratio( double *res, double *num, double *denom, int n );// c++ declaration
template<>int ratio<true>( double *res, double *num, double *denom, int n )
{
for ( int i = 0; i < n; i++ ) {
res[i] = num[i] / denom[i];
}
return n;
}
template<>int ratio<false>( double *res, double *num, double *denom, int n ) {
for ( int i = 0; i < n; i++ ) {
if ( denom == 0 ) {
std::cout << "Houston, we've got a problem\n";
return i;
}
res[i] = num[i] / denom[i];
}
return n;
}