fortran66のブログ

fortran について書きます。

CAF 先着4image 様まで

CoArray Fortranで先着幾名かまで実行

atomic_ref と atomic_define で何とかなるかとも思いましたが、atomic な読み出しと書き込みの間隙をぬって、他の image が入り込む可能性があるので、critical .... end critical 構文でやる必要がある気がします。

Fortran2018 では atomic_fetch_add 関数が導入されるので、これが使えるようになれば楽になろうかともいます。

critical 構文と atomic サブルーチン

critical .... end critical 構文と atomic サブルーチンはどちらも排他的実行に関わるものです。これらの違いはというと、critical 構文は critical と end critical で挟まれた一連の命令文の排他的実行であり、atomic サブルーチンは coarray 変数に対する排他的操作になっています。

つまり critical の方が文の排他実行で抽象度が高いのに対して、atomic サブルーチンは単一の coarray 変数の値に対する低レベルな排他的な読み書きになっています。

Fortran 2008 の段階では、本当に読み出しないし書き込みしか出来ないため、利用しづらいものがあります。そのためか、Fortran2018 では、以下のように仲間が増えて拡充されます。

  • call atomic add ( atom, value[ , stat] )
  • call atomic and ( atom, value[ , stat] )
  • call atomic or ( atom, value[ , stat] )
  • call atomic xor ( atom, value[ , stat] )
  • call atomic fetch add ( atom, value, old[ , stat] )
  • call atomic fetch and ( atom, value, old[ , stat] )
  • call atomic fetch or ( atom, value, old[ , stat] )
  • call atomic fetch xor ( atom, value, old[ , stat] )
  • call atomic cas ( atom, old, compare, new[ , stat] )

N2161 The New Features of Fortran 2018 (Reid - Replaces N2145) §3.20 New and enhanced atomic subroutines

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)

Modern Fortran Explained: Incorporating Fortran 2018 (Numerical Mathematics and Scientific Computation)

プログラム

nr[1] を特別扱いして、カウンタとします。変数 k には先着順が入ります。

    program caf04
        implicit none
        integer :: ne, me, k, nr[*]
        real :: x
        ne = num_images()
        me = this_image()
        if (me == 1) nr = 1
        sync all
        x = sqrt(real( me ))
        
        critical
            k = nr[1]  
            nr[1] = nr[1] + 1  
        end critical     
      
        if (k <= 4) print *, k, ':', me, '/', ne, x
    end program caf04

将来:

    program caf04
        use, intrinsic :: iso_fortran_env
        implicit none
        integer(atomic_int_kind) :: k, nr[*]
        integer :: ne, me
        real :: x
        ne = num_images()
        me = this_image()
        if (me == 1) nr = 1
        sync all
        x = sqrt(real( me ))
        
       call atomic_fetch_add(nr[1], 1, k)  ! 多分
      
        if (k <= 4) print *, k, ':', me, '/', ne, x
    end program caf04

実行結果

           1 :           1 /           8   1.000000
           2 :           5 /           8   2.236068
           4 :           7 /           8   2.645751
           3 :           6 /           8   2.449490
続行するには何かキーを押してください . . .

Parallel Programming with Co-arrays (Chapman & Hall/CRC Computational Science)

Parallel Programming with Co-arrays (Chapman & Hall/CRC Computational Science)