GFortranとCo-array Fortran

ソースコードは https://github.com/osada-yum/examples/tree/main/GFortran_and_Co-array_Fortran に.

# Co-array Fortran

Co-array Fortran はFortranの言語仕様の一部に組込まれているが, gfortran のみでは使えない. この記事はCo-arrayで書かれたプログラムを gfortran により実行するためのメモである. 
- Ubuntu20.04では `apt` を使う方法とソースからビルドする方法がある. `apt` を使う方法はインストールが楽だがコンパイルが面倒. 
- ソースからビルドするとラッパースクリプトの `caf` と `cafrun` が手に入るためコンパイルは楽になる.
- (2022/03/06(日)追記) どうも, Ubuntu18.04では `apt` に `open-coarrays-bin` があり, その中に `caf` と `cafrun` が入っている. Ubuntu20.04にはそのパッケージがない.
  https://fortran66.hatenablog.com/entry/2018/09/28/220201
  https://qiita.com/cure_honey/items/6ef209405d77bcabf70d
  

<a id="orgdb13c51"></a>

# 最初に失敗話

私のPCでは最初にCo-array Fortranを使っても高速化しなかった. おそらく, `gfortran` や `mpirun` などのPATHがめちゃくちゃだったせい.(再現ができないので原因が分からない&#x2026;) 環境の整理をしたら直った.
(どうやら, 実行ファイルを生成したmpiのバージョンと `mpirun` するmpiのバージョンが違うと高速化しないらしい? 高速化しないのならば `ldd a.out` で動的リンクライブラリのパスを確認した方がよいのかもしれない. 2022/02/07(月)追記)


<a id="org7ba6ccc"></a>

# 実行環境

-   Ubuntu20.04
-   Ubuntu20.04 on VirtualBox6.1.14

```bash
$ echo ${PATH} | sed -s "s=${HOME}=~=g"
~/.nvm/versions/node/v16.3.0/bin:~/.cabal/bin:/usr/local/gcc-11.2.0/bin:/opt/bin/:~/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
```
```bash
$ which gfortran
/usr/local/gcc-11.2.0/bin/gfortran
```
```bash
$ gfortran --version
GNU Fortran (GCC) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
```bash
$ which mpirun
/usr/local/gcc-11.2.0/bin/mpirun
```
```bash
$ mpirun --version

mpirun (Open MPI) 4.1.2
    
Report bugs to http://www.open-mpi.org/community/help/
```

<a id="org17542c2"></a>

# gfortranでCo-array Fortranを使う方法

Co-array Fortranのコンパイルのテスト用ファイル.

```coarrays_test.f90
program coarrays_test
  implicit none
  integer :: my_image, n_images
  my_image = this_image()
  n_images = num_images()
  print*, "I'm ", my_image, "/", n_images
end program coarrays_test
```


<a id="org8239c93"></a>

## apt を使う方法

まずは `apt` で検索をかけてみる.

```bash
$ apt search coarrays
    ソート中...
    全文検索...
    libcaf-mpich-3/focal 2.8.0-1 amd64
      Co-Array Fortran libraries  (MPICH)
    
    libcaf-openmpi-3/focal,now 2.8.0-1 amd64 [インストール済み、自動]
      Co-Array Fortran libraries  (OpenMPI)
    
    libcoarrays-dev/focal,now 2.8.0-1 amd64 [インストール済み]
      Co-Array Fortran libraries
    
    libcoarrays-mpich-dev/focal 2.8.0-1 amd64
      Co-Array Fortran libraries for - development files (MPICH)
    
    libcoarrays-openmpi-dev/focal,now 2.8.0-1 amd64 [インストール済み]
      Co-Array Fortran libraries  - development files (OpenMPI)
```
`mpich` と `openmpi` がある. `openmpi` を使うならば.

```bash
$ sudo apt install -y libcoarrays-openmpi-dev
```

実行するには必要なライブラリをリンクする必要があるが, `pkg-config` を使えば良い. インストールされた `.pc` ファイルを検索すると

```bash
$ dpkg -L libcoarrays-openmpi-dev | grep -e '\.pc$'
    /usr/lib/x86_64-linux-gnu/pkgconfig/caf-openmpi.pc
    /usr/lib/x86_64-linux-gnu/open-coarrays/openmpi/pkgconfig/caf-openmpi.pc
    /usr/lib/x86_64-linux-gnu/open-coarrays/openmpi/pkgconfig/caf.pc
```

OpenMPIを使う場合は, `caf-openmpi.pc` を利用する.

```bash
$ gfortran -o coarrays_test.out -fcoarray=lib coarrays_test.f90 $(pkg-config --libs --cflags caf-openmpi)
$ mpirun -np 2 ./coarrays_test.out
    I'm            1 /           2
    I'm            2 /           2
```

おそらく, `-lcaf_openmpi` だけで十分.

```bash
$ gfortran -o coarrays_test.out -fcoarray=lib coarrays_test.f90 -lcaf_openmpi
$ mpirun -np 2 ./coarrays_test.out
    I'm            1 /           2
    I'm            2 /           2
```

<a id="org3dff734"></a>

## ソースからビルドする方法

<http://www.opencoarrays.org/> の <https://github.com/sourceryinstitute/OpenCoarrays/tree/master> からソースコードをクローンする.

```bash
$ git clone https://github.com/sourceryinstitute/OpenCoarrays.git
$ cd OpenCoarrays/
```

cmakeを使ってビルドとインストールをする.

```bash
$ FC=/usr/local/gcc-11.2.0/bin/gfortran cmake -B _build -DBUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/gcc-11.2.0
$ cmake --build _build
$ cmake --build _build --target install
```

これでラッパースクリプトの `caf` と `cafrun` が `/usr/local/gcc-11.2.0` にインストールされる. FC や PREFIX を変えれば好きな場所にインストールできる. `caf` が何をラップしているかを知るためには

```bash
$ caf -w
    caf wraps /usr/local/gcc-11.2.0/bin/gfortran-11.2.0
```

`caf` のversionを知るためには

```bash
$ caf -v
    OpenCoarrays Coarray Fortran Compiler Wrapper (caf version 2.9.2-13-g235167d)
    Copyright (C) 2015-2020 Sourcery Institute
    Copyright (C) 2015-2020 Sourcery, Inc.
    
    OpenCoarrays comes with NO WARRANTY, to the extent permitted by law.
    You may redistribute copies of OpenCoarrays under the terms of the
    BSD 3-Clause License.  For more information about these matters, see
    the file named LICENSE that is distributed with OpenCoarrays.
```

を実行すればよい.

```bash
$ caf -o coarrays_test_caf.out coarrays_test.f90
$ cafrun -np 2 ./coarrays_test_caf.out
    I'm            1 /           2
    I'm            2 /           2
```

<a id="orgc590f8f"></a>

# 実行

ソースコードはNAGのチュートリアルからダウンロード <https://www.nag-j.co.jp/fortran/coarray/coarrayTutorial_3.html>.

```bash
$ [ -f quad1.f90 ]    || wget https://www.nag-j.co.jp/fortran/coarray/code/quad1.f90
$ [ -f coquad1.f90 ]  || wget https://www.nag-j.co.jp/fortran/coarray/code/coquad1.f90
$ [ -f coarrays.f90 ] || wget https://www.nag-j.co.jp/fortran/coarray/code/coarrays.f90
$ gfortran -fcoarray=lib -o coarrays.out quad1.f90 coquad1.f90 coarrays.f90 -lcaf_openmpi
$ caf -o coarrays_caf.out quad1.f90 coquad1.f90 coarrays.f90
```


<a id="org4774ac9"></a>

## apt から

```bash
$ mpirun -np 1 ./coarrays.out
    Calculated value:     0.90000000000031166
    True value (approx):  0.90000000000000002
    Relative error   3.4626622556920158E-013
    Time taken 9.620 seconds by 1 images, = 9.62 computing power
```

```bash
$ mpirun -np 4 ./coarrays.out
    Calculated value:     0.90000000000022018
    True value (approx):  0.90000000000000002
    Relative error   2.4461913975907617E-013
    Time taken 2.742 seconds by 4 images, = 10.97 computing power
```

<a id="org3ffeffc"></a>

## caf

```bash
$ cafrun -np 1 ./coarrays_caf.out
    Calculated value:     0.90000000000031166
    True value (approx):  0.90000000000000002
    Relative error   3.4626622556920158E-013
    Time taken 9.626 seconds by 1 images, = 9.63 computing power
```

```bash
$ cafrun -np 4 ./coarrays_caf.out
    Calculated value:     0.90000000000022018
    True value (approx):  0.90000000000000002
    Relative error   2.4461913975907617E-013
    Time taken 2.644 seconds by 4 images, = 10.58 computing power
```

<a id="orge63dec1"></a>

## 速度の比較

- aptから

|              | time  | speedup   |
|------------ |----- |--------- |
| mpirun -np 1 | 9.620 | 1         |
| mpirun -np 4 | 2.742 | 3.5083880 |

- caf

|              | time  | speedup   |
|------------ |----- |--------- |
| cafrun -np 1 | 9.626 | 1         |
| cafrun -np 4 | 2.644 | 3.6406959 |


<a id="org158964b"></a>

# 結論

どちらの方法でも速度は大して変わらない. おおよそコア数分のスピードアップをしている.

ビルドの手間とコンパイルの手間を天秤にかけると, コンパイルが楽な `caf` を使った方が良いだろう.


<a id="orgfb8f477"></a>

# 参考

-   OpenCoarrays
    
http://www.opencoarrays.org/
    
https://github.com/sourceryinstitute/OpenCoarrays/tree/master

-   NAGのチュートリアル
    
https://www.nag-j.co.jp/fortran/coarray/coarrayTutorial_3.html

- Ubuntu18.04

https://fortran66.hatenablog.com/entry/2018/09/28/220201

https://qiita.com/cure_honey/items/6ef209405d77bcabf70d