概要
SX-Aurora TSUBASA (SXAT)を使える機会を得たので,Fortran Package ManagerとFortran Standard Libraryを使ってみました.
環境
- Vector Engine Type 10C
- nfort 3.5.1
- fpm 0.7.0
- stdlib 0.2.1
Fortran Package Managerの利用
SXATを使うプログラムを開発するにあたり,Fortran Package Manager (fpm)を利用します.今回は,SXATが接続されているCPUのアーキテクチャがx86-64だったので,fpmのリリースページからそれ用のバイナリfpm-0.7.0-linux-x86_64をダウンロードして利用することにしました.
fpmはいくつかのコンパイラをサポートしており,サポートしているコンパイラに対しては,debugやreleaseといったプロファイルを利用できます.今回使うNEC Fortran (nfort)はfpmのサポート外なので,fpmのオプションを利用して,コンパイラやコンパイル時のオプションを指定します.
$ fpm new sample
+ mkdir -p sample
+ cd sample
+ mkdir -p sample/src
+ mkdir -p sample/app
+ mkdir -p sample/test
+ git config --get user.name > /tmp/filenJJm0v
+ git config --get user.email > /tmp/fileg2ZFgu
+ git config --get user.name > /tmp/fileDT7PTs
+ git init sample
$ fpm build --compiler nfort --flag "-fpp -std=f2008 -O0"
+ mkdir -p build/dependencies
<WARN> Unknown compiler nfort requested! Defaults for this compiler might be incorrect
sample.f90 done.
libsample.a done.
main.f90 done.
sample done.
[100%] Project compiled successfully.
$ fpm run --compiler nfort --flag "-fpp -std=f2008 -O0"
<WARN> Unknown compiler nfort requested! Defaults for this compiler might be incorrect
Project is up to date
Hello, sample!
$ fpm test --compiler nfort --flag "-fpp -std=f2008 -O0"
<WARN> Unknown compiler nfort requested! Defaults for this compiler might be incorrect
check.f90 done.
check done.
[100%] Project compiled successfully.
Put some tests in here!
サポートしていないコンパイラなので,標準(のコンパイルオプションなど)は正しくないよと警告が出ています.ビルドに関わるnfortのコンパイルオプションが概ねgfortranと同じなので,ビルドも実行も問題ありませんでした.
Fortran Standard Libraryのビルド
ソースの入手
SXATでFortran Standard Library (stdlib)を使うために,nfortでのビルドに挑戦しました.stdlibはfpmを用いてビルドできます.fpm対応版を入手するには,下記のコマンドを実行します.
git clone https://github.com/fortran-lang/stdlib -b stdlib-fpm
ビルド
ビルドを実行すると,残念ながらと言うべきか案の定と言うべきか,エラーが生じます.
$ fpm build --compiler nfort --flag "-fpp -std=f2008"
中略
stdlib_hashmap_chaining.f90 failed.
[ 39%] Compiling...
Error: ././src/stdlib_hashmap_chaining.f90, line 222: Invalid redeclaration of host symbol FREE_CHAINING_MAP
detected at FREE_CHAINING_MAP@(
Warning: ././src/stdlib_hashmap_chaining.f90, line 383: Pointer SENTRY never dereferenced
[NEC Fortran Compiler pass 1 error termination, 1 error, 1 warning]
<ERROR> Compilation failed for object " src_stdlib_hashmap_chaining.f90.o "
<ERROR>stopping due to failed compilation
STOP 1
エラーが生じていると報告されたのはstdlib_hashmap_chaining.f90
なのですが,エラーの原因は,stdlib_hasmap.f90
で定義しているユーザ定義派生型の後始末手続(final subroutine)を,submodule機能を利用して実装していることです.案の定と言ったのは,NAG Fortranでも同じエラーが発生したためです.NAG Fortranについては,サポート契約をしている方を経由してベンダにエラーの詳細を伝えていただき,現在のビルドでは修正されています.規格上はstdlibの書き方で問題ないはずで,submoduleとfinal subroutineという使われない機能の重ね技で,コンパイラベンダが考慮していない状況が発生したのだと考えられます.
エラーの解決は簡単で,stdlib_hasmap.f90
にあるfree_chaining_map
とfree_open_map
のmodule subroutine
宣言を削除し,それぞれstdlib_hashmap_chaining.f90
とstdlib_hashmap_open.f90
に書かれている実装をstdlib_hasmap.f90
に移動するだけです.
テスト
ビルドした後,テストを実行します.
$ fpm test --compiler nfort --flag "-fpp -std=f2008 -O0"
中略
<ERROR> Execution failed for object " test_getline "
<ERROR> Execution failed for object " test_string_derivedtype_io "
<ERROR>*cmd_run*:stopping due to failed executions
STOP 1
テストを実行したところ,2個のテストが失敗しました.
test_getline
これは,stdlib_io
モジュールで定義される手続getline
に対するテストです.このテストが失敗した理由は,newunit
を用いて得られた装置番号に関係しており,下記のようなコードで現れます.
type(error_type), allocatable, intent(out) :: error
integer :: io, i, stat
character(len=:), allocatable :: line
open(newunit=io, status="scratch", pad="no")
write(io, "(a)") repeat("abc", 10), repeat("def", 100), repeat("ghi", 1000)
rewind(io)
do i = 1, 3
call getline(io, line, stat)
call check(error, stat)
if (allocated(error)) exit
call check(error, len(line), 3*10**i)
if (allocated(error)) exit
end do
close(io)
open(newunit=io, status="scratch", pad="no")
で得た装置番号io
を,stdlibで提供される手続getline(io, line, stat)
に渡す場合に問題が発生します.
Fortranの規格上,装置番号は正の値しか許可されません.一方で,newunit
を用いた際に自動的に割り付けられる装置番号は,負の値になります.newunit
で得られた装置番号を引数で渡して異なるスコープで使い回す場合,どのように判断するかはコンパイラ依存になります.Intel Fortran, gfortranは有効な装置番号と認識し,NAG Fortranはエラーとすることが判っています.NEC Fortranもエラーとするようです.
test_getline
でテストしたいのは,getline
の引数で指定した装置番号から1行を取得できるか否かなので,装置番号の問題でテストが失敗するのは本意ではありません.装置番号が負になることが問題なので,newunit
で得られた装置番号の絶対値を取って正の値を割り当てることで回避しました.
open(newunit=io, status="scratch")
unit_num = abs(io)
close(io)
io = unit_num
open(unit=io, status="scratch")
test_string_derivedtype_io
これは,stdlib_string_type
で定義されている派生型string_type
の入出力に対するテストです.このテストが失敗した理由は,書式を指定しない場合(List Directed IO)に,出力時に余計な空白を入れてしまうことです.
Fortranでは,write
文に書式を指定しない場合,先頭に空白が追加されることがあります.
!v先頭に空白が入る
write(*,*) "Hello SXAT" ! Hello SXAT
write(*,'(A)') "Hello SXAT" !Hello SXAT
test_string_derivedtype_io
の中では,"Important saved value"
という値を持つ文字列をwrite(io, *) string
で出力した結果,先頭に空白が追加された" Important saved value"
が出力されます.出力された文字列をread(io, *, iostat=stat) string
で取得すると,先頭に空白が追加された値" Important saved value"
が取得され,"Important saved value"
との比較を通して失敗と判定されます.
subroutine test_listdirected_io(error)
!> Error handling
type(error_type), allocatable, intent(out) :: error
type(string_type) :: string
integer :: io, stat
string = "Important saved value"
open(newunit=io, form="formatted", status="scratch")
write(io, *) string
write(io, *) ! Pad with a newline or we might run into EOF while reading
string = ""
rewind(io)
read(io, *, iostat=stat) string
close(io)
call check(error, stat == 0)
if (allocated(error)) return
call check(error, len(string) == 21)
if (allocated(error)) return
call check(error, string == "Important saved value")
end subroutine test_listdirected_io
他のテストの失敗
最適化レベルを0
より大きくすると,test_rawmomentも失敗します.失敗しているのは,複素数型配列の要素のモーメントを計算する手続です.理由はまだ特定できていませんが,最適化に伴って引数の配列サイズの解釈に変化が生じ,最適化がない時とは異なる手続が呼ばれているのではないかと予想しています.
module function moment_mask_2_csp_csp(x, order, dim, center, mask) result(res)
complex(sp), intent(in) :: x(:,:)
integer, intent(in) :: order
integer, intent(in) :: dim
complex(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
logical, intent(in) :: mask(:,:)
complex(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))
integer :: i
real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
complex(sp), allocatable :: mean_(:)
まとめ
Fortranの利便性を改善するために開発されているFortran Package ManagerとFortran Standard Libraryは,SX-Aurora TSUBASAでも利用ができることが判りました.
また,stdlibのビルドで問題が生じることとその回避策を示しました.現状では,複素数型配列のモーメントを計算する処理以外に問題は見つかっていません.CPUと比較してどのくらい高速になっているかなどを調べるのも面白いと思います.