OpenMP:ON NUMA 的 pragma cancel
OpenMP: pragma cancel for ON NUMA
--------------------编辑------------------------ --
我已将代码编辑如下:
#pragma omp parallel for private(i, piold, err) shared(threshold_err) reduction(+:pi) schedule (static)
{
for (i = 0; i < 10000000000; i++){ //1000000000//705035067
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}
}
}
pi = 4*pi;
我用LLVM3.9/Clang4.0编译的。当我用一个线程 运行 它时,我得到了 pragma cancel 操作的预期结果(针对非 pragma cancel 版本进行了检查,导致更快 运行)。
但是当我 运行 它的线程 >=2 时,程序进入循环。我是 运行 NUMA 机器上的代码。怎么了?也许取消条件不满足!但是代码比单线程非 pragma-cancel 版本花费的时间更长!!仅供参考,当 OMP_CANCELLATION=false 时 运行s 文件。
我有以下 OpenMP 代码。我正在使用 LLVM-3.9/Clang-4.0 来编译这段代码。
#pragma omp parallel private(i, piold, err) shared(pi, threshold_err)
{
#pragma omp for reduction(+:pi) schedule (static)
for (i = 0; i < 10000000 ; i++){
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
#pragma omp critical
{
err = fabs(pi-piold);// printf("Err: %0.11f\n", err);
}
if ( err < threshold_err){
printf("Cancelling!\n");
#pragma omp cancel for
}
}
}
不幸的是,我认为 #pragma omp cancel for
不会终止整个 for
循环。我最后要打印出 err
值,但是由于并行性,它又会混淆正在打印哪个值。 err
的最终值小于 threshold_err
。打印取消正在打印,但是在程序的最开始,这令人惊讶。之后程序保持 运行ning!
如何确保这是正确的实施?顺便说一句 OMP_CANCELLATION 设置为 true 和一个小测试程序 returns '1' 用于相应的函数 omp_get_cancellation()。
我知道 omp cancel 只是一个中断信号,它通知以后不会创建线程。仍然是 运行 的线程将继续到最后。参见 http://bisqwit.iki.fi/story/howto/openmp/ and http://jakascorner.com/blog/2016/08/omp-cancel.html
事实上,在我看来,我看到你的程序产品是可以接受的近似值。但是,某些变量可以保留在较小的范围内。这是我的建议
#include <iostream>
#include <cmath>
#include <iomanip>
int main() {
long double pi = 0.0;
long double threshold_err = 1e-7;
int cancelFre = 0;
#pragma omp parallel shared(pi, threshold_err, cancelFre)
{
#pragma omp for reduction(+:pi) schedule (static)
for (int i = 0; i < 100000000; i++){
long double piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
long double err = std::fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
cancelFre++;
}
}
}
std::cout << std::setprecision(10) << pi * 4 << " " << cancelFre;
return 0;
}
好的,我解决了。在我上面的代码中,问题出在这里:
err = fabs(pi-piold);
在上面的行中,pi
在以下 if 条件更改之前更改。多个线程也做同样的事情。据我了解,这会使程序陷入僵局。
我通过强制只有一个线程,master,来做这个检查解决了这个问题:
if(omp_get_thread_num()==0){
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}
}
我本可以使用 #pragma omp single
但它给出了有关嵌套编译指示的错误。
这里的性能因线程数少而受到影响(1-4 比正常的顺序代码差)。之后性能会提高。这不是最好的解决方案,肯定有人可以对此进行改进。
--------------------编辑------------------------ --
我已将代码编辑如下:
#pragma omp parallel for private(i, piold, err) shared(threshold_err) reduction(+:pi) schedule (static)
{
for (i = 0; i < 10000000000; i++){ //1000000000//705035067
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}
}
}
pi = 4*pi;
我用LLVM3.9/Clang4.0编译的。当我用一个线程 运行 它时,我得到了 pragma cancel 操作的预期结果(针对非 pragma cancel 版本进行了检查,导致更快 运行)。
但是当我 运行 它的线程 >=2 时,程序进入循环。我是 运行 NUMA 机器上的代码。怎么了?也许取消条件不满足!但是代码比单线程非 pragma-cancel 版本花费的时间更长!!仅供参考,当 OMP_CANCELLATION=false 时 运行s 文件。
我有以下 OpenMP 代码。我正在使用 LLVM-3.9/Clang-4.0 来编译这段代码。
#pragma omp parallel private(i, piold, err) shared(pi, threshold_err)
{
#pragma omp for reduction(+:pi) schedule (static)
for (i = 0; i < 10000000 ; i++){
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
#pragma omp critical
{
err = fabs(pi-piold);// printf("Err: %0.11f\n", err);
}
if ( err < threshold_err){
printf("Cancelling!\n");
#pragma omp cancel for
}
}
}
不幸的是,我认为 #pragma omp cancel for
不会终止整个 for
循环。我最后要打印出 err
值,但是由于并行性,它又会混淆正在打印哪个值。 err
的最终值小于 threshold_err
。打印取消正在打印,但是在程序的最开始,这令人惊讶。之后程序保持 运行ning!
如何确保这是正确的实施?顺便说一句 OMP_CANCELLATION 设置为 true 和一个小测试程序 returns '1' 用于相应的函数 omp_get_cancellation()。
我知道 omp cancel 只是一个中断信号,它通知以后不会创建线程。仍然是 运行 的线程将继续到最后。参见 http://bisqwit.iki.fi/story/howto/openmp/ and http://jakascorner.com/blog/2016/08/omp-cancel.html
事实上,在我看来,我看到你的程序产品是可以接受的近似值。但是,某些变量可以保留在较小的范围内。这是我的建议
#include <iostream>
#include <cmath>
#include <iomanip>
int main() {
long double pi = 0.0;
long double threshold_err = 1e-7;
int cancelFre = 0;
#pragma omp parallel shared(pi, threshold_err, cancelFre)
{
#pragma omp for reduction(+:pi) schedule (static)
for (int i = 0; i < 100000000; i++){
long double piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
long double err = std::fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
cancelFre++;
}
}
}
std::cout << std::setprecision(10) << pi * 4 << " " << cancelFre;
return 0;
}
好的,我解决了。在我上面的代码中,问题出在这里:
err = fabs(pi-piold);
在上面的行中,pi
在以下 if 条件更改之前更改。多个线程也做同样的事情。据我了解,这会使程序陷入僵局。
我通过强制只有一个线程,master,来做这个检查解决了这个问题:
if(omp_get_thread_num()==0){
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}
}
我本可以使用 #pragma omp single
但它给出了有关嵌套编译指示的错误。
这里的性能因线程数少而受到影响(1-4 比正常的顺序代码差)。之后性能会提高。这不是最好的解决方案,肯定有人可以对此进行改进。