openmp:检查是否嵌套并行
openmp : check if nested parallesim
假设我有一个方法将两个 std::vector
相乘:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
/*here I could easily do a parallelization with*/
/*#pragma omp parallel loop for*/
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]*b[i];
}
return tmp;
}
如果我在此函数中设置 pragma 宏,对 multiply(...)
的调用将 运行
在所有线程上。
现在假设我想在其他地方做很多向量乘法:
void many_multiplication(std::vector<double>* a, std::vector<double>* b, unsigned int N){
/*here I could easily do a parallelization with*/
/*#pragma omp parallel loop for*/
for(unsigned int i=0;i<N;i++){
for(unsigned int j=0;j<N;j++){
multiply(a[i],b[j]);
}
}
}
我也可以用同样的方式进行并行化。但这会导致
不需要的嵌套并行性。
如何检查 multiply(..)
是否在并行区域内调用,
那么 multiply(...)
的 pragma
宏就是 "turn off"。如果它被称为
来自非平行区域,则为 "turn on".
将 pragma 添加到两个函数。您可以使用 omp_set_nested(int val)
打开和关闭 nested parallelism(零表示关闭,非零表示打开)。
因此,如果您通常希望在您的程序中启用嵌套并行性,但对于 many_multiplication
函数则关闭,您可以按如下方式实现 many_multiplication
:
void many_multiplication(std::vector<double>* a, std::vector<double>* b, unsigned int N){
omp_set_nested(0);
#pragma omp parallel loop for
for(unsigned int i=0;i<N;i++){
for(unsigned int j=0;j<N;j++){
multiply(a[i],b[j]);
}
}
omp_set_nested(1);
}
嵌套并行性默认情况下 禁用 ,除非通过将 OMP_NESTED
设置为 true
或调用 omp_set_nested(1);
(§2.3. OpenMP specification 中的 2 个)按照 Avi Ginsburg 的建议明确修改嵌套设置是个坏主意。相反,您应该使用基于嵌套级别的条件并行执行:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
int active_levels = omp_get_active_level();
#pragma omp parallel for reduction(+:tmp) if(active_level < 1)
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]+b[i];
}
return tmp;
}
omp_get_active_level()
returns 在进行调用时包围线程的活动并行区域的数量。它 returns 0
如果从平行区域外部或不活动的外部区域调用。由于 if(active_level < 1)
子句,平行区域将仅被激活,即 运行 平行,如果它不包含在活动区域中,无论嵌套设置如何。
如果您的编译器不支持 OpenMP 3.0 或更高版本(例如,任何版本的 MS Visual C/C++ 编译器),则可以使用 omp_in_parallel()
调用:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
int in_parallel = omp_in_parallel();
#pragma omp parallel for reduction(+:tmp) if(in_parallel == 0)
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]+b[i];
}
return tmp;
}
omp_in_parallel()
returns 如果至少有一个封闭的平行区域处于活动状态,则非零,但不提供有关嵌套深度的信息,即不太灵活。
无论如何,写这样的代码是一种不好的做法。您应该简单地保留并行区域,让最终用户选择是否启用嵌套并行。
假设我有一个方法将两个 std::vector
相乘:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
/*here I could easily do a parallelization with*/
/*#pragma omp parallel loop for*/
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]*b[i];
}
return tmp;
}
如果我在此函数中设置 pragma 宏,对 multiply(...)
的调用将 运行
在所有线程上。
现在假设我想在其他地方做很多向量乘法:
void many_multiplication(std::vector<double>* a, std::vector<double>* b, unsigned int N){
/*here I could easily do a parallelization with*/
/*#pragma omp parallel loop for*/
for(unsigned int i=0;i<N;i++){
for(unsigned int j=0;j<N;j++){
multiply(a[i],b[j]);
}
}
}
我也可以用同样的方式进行并行化。但这会导致 不需要的嵌套并行性。
如何检查 multiply(..)
是否在并行区域内调用,
那么 multiply(...)
的 pragma
宏就是 "turn off"。如果它被称为
来自非平行区域,则为 "turn on".
将 pragma 添加到两个函数。您可以使用 omp_set_nested(int val)
打开和关闭 nested parallelism(零表示关闭,非零表示打开)。
因此,如果您通常希望在您的程序中启用嵌套并行性,但对于 many_multiplication
函数则关闭,您可以按如下方式实现 many_multiplication
:
void many_multiplication(std::vector<double>* a, std::vector<double>* b, unsigned int N){
omp_set_nested(0);
#pragma omp parallel loop for
for(unsigned int i=0;i<N;i++){
for(unsigned int j=0;j<N;j++){
multiply(a[i],b[j]);
}
}
omp_set_nested(1);
}
嵌套并行性默认情况下 禁用 ,除非通过将 OMP_NESTED
设置为 true
或调用 omp_set_nested(1);
(§2.3. OpenMP specification 中的 2 个)按照 Avi Ginsburg 的建议明确修改嵌套设置是个坏主意。相反,您应该使用基于嵌套级别的条件并行执行:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
int active_levels = omp_get_active_level();
#pragma omp parallel for reduction(+:tmp) if(active_level < 1)
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]+b[i];
}
return tmp;
}
omp_get_active_level()
returns 在进行调用时包围线程的活动并行区域的数量。它 returns 0
如果从平行区域外部或不活动的外部区域调用。由于 if(active_level < 1)
子句,平行区域将仅被激活,即 运行 平行,如果它不包含在活动区域中,无论嵌套设置如何。
如果您的编译器不支持 OpenMP 3.0 或更高版本(例如,任何版本的 MS Visual C/C++ 编译器),则可以使用 omp_in_parallel()
调用:
double multiply(std::vector<double> const& a, std::vector<double> const& b){
double tmp(0);
int in_parallel = omp_in_parallel();
#pragma omp parallel for reduction(+:tmp) if(in_parallel == 0)
for(unsigned int i=0;i<a.size();i++){
tmp += a[i]+b[i];
}
return tmp;
}
omp_in_parallel()
returns 如果至少有一个封闭的平行区域处于活动状态,则非零,但不提供有关嵌套深度的信息,即不太灵活。
无论如何,写这样的代码是一种不好的做法。您应该简单地保留并行区域,让最终用户选择是否启用嵌套并行。