在Visual Studio中改进C++ OpenMP支持

随着具有多核和处理器的设备变得无处不在,编程语言适应于为开发人员提供对任务如何在处理器之间分配的控制。这个 OpenMP应用程序接口 对于C、C++和FORTRAN,最初是在20世纪90年代为此目的开发的,今天标准继续发展以支持新的场景,例如卸载附加设备,并提供更细粒度的控制来控制哪些线程执行哪些任务。

null

Microsoft Visual Studio已 支持OpenMP 2.0标准 在VisualStudio2019的初始版本中,我们添加了 -openmp:experimental 切换到启用 对OpenMP SIMD指令的最低支持 首先在OpenMP 4.0标准中引入。

我们的OpenMP计划

从VisualStudio2019版本16.9开始,我们已经开始以更系统的方式为OpenMP标准的较新版本添加实验性支持。作为第一步,我们添加了生成与 LLVM的OpenMP运行库 (libomp)在x64体系结构上。今后,对额外OpenMP功能的支持将利用LLVM的OpenMP运行时。当我们在Windows上的LLVM OpenMP运行时中发现问题时,我们将在我们发布的libomp版本中修复这些问题,并在测试完这些问题后,将修复的内容反馈给LLVM社区。

展望未来,我们对OpenMP支持的下一步将是支持OpenMP 3.1标准中在x86和arm64体系结构以及x64上添加的附加功能。然后,我们将添加对openmp4.5标准中添加的pragma和子句的支持,这些pragma和子句不涉及卸载。之后添加哪些功能将取决于用户反馈。我们很想知道您希望看到哪些特定的OpenMP功能,因此我们可以优先考虑首先支持哪些功能。

新建-openmp:llvm switch

通过使用新的实验CL开关,可以编译一个程序以LLVM OpenMP运行时为目标 -openmp:llvm 而不是 -openmp接口 . 在Visual Studio 2019版本16.9中 -openmp:llvm 交换机仅适用于x64体系结构。新的交换机目前支持与之相同的所有OpenMP 2.0指令 -openmp接口 ,以及根据openmp3.0标准对循环的无符号整数索引的并行支持。对更多指令的支持将在将来的版本中添加。这个 -openmp:llvm switch 与兼容 所有SIMD指令 支持 -openmp:experimental 开关。

使用编译可执行文件 -openmp:llvm 开关会自动将动态链接添加到相应的libomp DLL。要使可执行文件运行,它需要访问libomp140d.x86_64.dll(如果使用/DEBUG编译)或libomp140.x86_64.dll。这些DLL可以在Visual Studio安装目录中找到,位于vcreditmsvcdebugu nonresistx64microsoft.VC142.OpenMP.LLVM的Program Files或Program Files(x86)目录下,如果从x64 NativeTools命令提示符运行可执行文件,这些DLL将自动包含在路径中。

作为 -openmp:llvm 切换仍然是实验性的,运行时的发行版和调试版仍然启用了断言,这使得检测不正确的行为更容易,但会影响性能。dll是用CMAKEu BUILDu TYPE=RelWithDebInfo和LLVMu ENABLEu ASSERTIONS=ON编译的。libomp dll的未来版本可能不向后兼容,并且这些dll的当前版本不可再发行。

这个 -openmp:llvm 开关与不兼容 /清除 /ZW公司 .

改进-openmp:llvm

使用 -openmp:llvm 开关启用一些正确性修复。在Visual Studio版本16.9 Preview 3中 #pragma omp节 现在已正确处理。当与节一起使用时,lastprivate子句保证退出节块时,子句中列出的变量将被设置为该变量在最后一节中的私有版本。例如,在执行以下代码之后,x的值将是6。

int x = 0;
#pragma omp parallel sections lastprivate(x)
{
   #pragma omp section
   x = 4;
   #pragma omp section
   x = 6;
}

VisualStudio2019版本16.9预览版4还包括对优化器的修复,以正确处理OpenMP构造。MSVC现在将避免跨隐式或显式刷新边界移动写操作。使用以下代码 #pragma omp冲洗 例如:

x = 7;
#pragma omp flush
if (omp_get_thread_num() == 0) {
    x = 10;
}

在某些情况下,以前版本的编译器可能会通过将此代码更改为以下代码来错误地优化对x的潜在双写:

#pragma omp flush
x = (omp_get_thread_num() == 0) ? 7 : 10;

但是,这种优化不考虑 #pragma omp冲洗 . 对于原始代码,由于ompu getu threadu num()为组中的一个线程返回0,因此只有该线程会在刷新点之后写入x,而x将是10。因为在优化之后,其他线程可以在刷新点之后写入x并创建争用条件,所以优化是不合法的。

优化器还将正确地认识到,即使是函数的局部变量也可以被OpenMP并行区域内的其他线程更改。例如,在以下代码中,x>共享测试中的shared值不能替换为-1,因为自初始赋值后,另一个线程可能已写入shared:

int shared = -1;
#pragma omp parallel
{
    unsigned int x = omp_get_thread_num();
    #pragma omp critical
    {
        if (x > shared) {
            shared = x;
        }
    }
}

具有的新功能-openmp:llvm

除了正确性修复,新的 -openmp:llvm 交换机已经支持OpenMP 3.0标准中添加的一些功能。并行for循环现在可以使用无符号整数作为索引。有限的支持 #pragma omp任务 已添加,但不能保证任务pragma上的子句有效。由于 #pragma omp任务 此时,pragma仅在 -openmp:experimenta l开关。

反馈

我们鼓励您在中尝试此新功能 Visual Studio 2019版本16.9预览版 . 一如既往,我们欢迎您的反馈。如果在使用 -openmp:llvm visualstudio附带的libomp140 dll中的开关或错误,请告诉我们。我们可以通过以下评论、twitter(@visualc)或 开发者社区 .

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享