fortran - OpenMP 竞争条件(Fortran 77 w/COMMON block )

标签 fortran openmp race-condition fortran77 inspector

我正在尝试将一些旧版 Fortran 代码与 OpenMP 并行化。 使用 Intel Inspector 检查竞争条件时,我在以下代码中遇到了问题(简化的测试示例):

        PROGRAM TEST

!$      use omp_lib
        implicit none
        DOUBLE PRECISION :: x,y,z
        COMMON /firstcomm/ x,y,z
!$OMP THREADPRIVATE(/firstcomm/)

        INTEGER :: i
!$      call omp_set_num_threads(3)       

!$OMP PARALLEL DO
!$OMP+ COPYIN(/firstcomm/)
!$OMP+ PRIVATE(i)
        do i=1,3000
            z = 3.D0
            y = z+log10(z)
            x=y+z
        enddo
!$OMP END PARALLEL DO

        END PROGRAM TEST

英特尔 Inspector 检测到以下几行之间的竞争条件:

  • !$OMP PARALLEL DO (阅读)
  • z = 3.D0 (写)

检查器“反汇编” View 分别提供了有关这两行的以下内容(除了两行中的内存地址似乎不同之外,我对这些不太了解):

  • 0x3286 callq 0x2a30 <memcpy>
  • 0x3338 movq %r14, 0x10(%r12)

与我的主应用程序一样,问题发生在公共(public) block 中的一个(/某些)变量上,但不会发生在以相同方式处理的其他变量上。

任何人都可以发现我的错误,还是这个竞争条件是误报?

我知道一般情况下不鼓励使用 COMMON block ,但我无法为当前项目更改这一点。

最佳答案

从技术上讲,您的示例代码不正确,因为您使用的是 COPYIN使用未初始化的数据初始化线程私有(private)副本 COMMON BLOCK 。但这并不是数据竞争的原因 - 添加 DATA语句或简单地分配给 x , y ,和z在并行区域之前不会改变结果。

这要么是英特尔 Fortran 编译器中的一个(非常古老的)错误,要么是英特尔正在奇怪地解释 OpenMP 标准的文本(当前版本的 section 2.15.4.1):

The copy is done, as if by assignment, after the team is formed and prior to the start of execution of the associated structured block.

英特尔通过插入 memcpy 来实现强调文本。在概述的程序开始时。换句话说:

!$OMP PARALLEL DO COPYIN(/firstcomm/)
do i = 1, 3000
   ...
end do
!$OMP END PARALLEL DO

变成(Fortran 和伪代码的混合):

par_region0:
   my_firstcomm = get_threadprivate_copy(/firstcomm/)
   if (my_firstcomm != firstcomm) then
      memcpy(my_firstcomm, firstcomm, size of firstcomm)
   end if
   // Actual implementation of the DO worksharing construct
   call determine_iterations(1, 3000, low_it, high_it)
   do i = low_it, high_it
     ...
     ... my_firstcomm used here instead of firstcomm
     ...
   end do
   call openmp_barrier
end par_region0

MAIN:
   // Prepare a parallel region with 3 threads
   // and fire the outlined code in the worker threads
   call start_parallel_region(3, par_region0)
   // Fire the outlined code in the master thread
   call par_region0
   call end_parallel_region

概述的过程首先找到公共(public) block 的线程私有(private)副本的地址,然后将该地址与公共(public) block 本身的地址进行比较。如果两个地址匹配,则代码正在主线程中执行,不需要复制,否则 memcpy被调用以将主数据按位复制到 threadprivate block 中。

现在,人们会期望在初始化部分的末尾和循环开始之前应该有一个障碍,尽管 Intel employees claim that there is one ,没有(使用 ifort 11.0、14.0 和 16.0 进行测试)。更重要的是,英特尔 Fortran 编译器不支持 COPYIN 中的变量列表。子句,如果子句中列出了其中包含的任何变量,则复制​​整个公共(public) block ,即 COPYIN(x)COPYIN(/firstcomm/) 的处理方式相同.

这些究竟是英特尔 Fortran 编译器的错误还是功能,只有英特尔才能知道。也可能是我误读了汇编输出。 如果有人能找到缺失的障碍,请告诉我。一种可能的解决方法是拆分组合指令并在工作共享构造之前插入显式障碍:

!$OMP PARALLEL COPYIN(/firstcomm/) PRIVATE(I)
!$OMP BARRIER
!$OMP DO
      do i = 1, 3000
         z = 3.D0
         y = z+log10(z)
         x = y+z
      end do
!$OMP END DO
!$OMP END PARALLEL

随着这一变化,数据竞争将转向log10内内部调度表的初始化。调用,这可能是误报。

GCC 实现 COPYIN不同。它创建主线程的线程私有(private)数据的共享副本,然后将其复制到工作线程以在复制过程中使用。

关于fortran - OpenMP 竞争条件(Fortran 77 w/COMMON block ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35001653/

相关文章:

compiler-errors - Msys2 -> f951.exe : Fatal Error: Reading module '...' at line 2 column 1: Unexpected EOF

c++ - 为并行化的 for() 循环提供线程私有(private)预分配缓冲区?

C++11 原子 : why does this code work?

javascript - 这对 AJAX 请求是否存在竞争条件?

arrays - 如何将字符数组传递给字符串

visual-studio-code - 在带有 makefile 的 VSCODE 中使用英特尔 Fortran 编译器 - `make: ifort: Command not found`

bash - 在 bash 脚本中使用变量名进行编译

c - OSX 10.12 GCC OpenMP 错误

c++ - 使用 openMP 的线程安全随机数生成器

javascript - JavaScript 中的事件计时