fortran90において、
このプログラムは何秒かかるか?
早い?遅い?
を調べるためにはもちろん計算時間を計るのが一番です。
- 実時間とCPU時間の違い
- 実時間計測
- CPU時間計測
実時間とCPU時間の違い
『計算時間』には大きく2種類あります。実時間とCPU時間です。
- 実時間 → 現実の世界での経過時間
- CPU時間 → プログラムの実行でCPUを使った時間
※[1]より。参考文献とは程遠いですが、僕の認識とあっていて、綺麗な説明と感じたので載せておきます。
例えば、計算時間はそんなにかかってないのに詳細な画像を得たいがために書き出すデータ量を増やしている場合、実時間は長く、CPU時間は短くなります。
また、あるデータ点1つを得るために計算時間は膨大にかかる場合、実時間≈CPU時間になります。
fortranでは時刻を得るためのサブルーチンが既に用意されています。
ここで紹介するのは、実時間を得るための
date_and_time
と
system_clock
の2種類。
CPU時間を得るためのサブルーチンは
cpu_time
の1種類です。
実時間計測(date_and_time)
その場所で何時何分何秒を出力させたい時、その場所に
c," ",ti(1),"/",ti(2),"/",ti(3), &
" ",ti(5),":",ti(6),":",ti(7),", (yyyy/mm/dd hh:mm:ss)"
を入れましょう[2]。character(10)::b(1:3), integer::ti(1:8)です。
使う際はこうすると良いでしょう。
implicit none
call current_time("program start ")
!program here
write(6,*)"press Enter"
read *
call current_time("program finish")
stop
end program main
subroutine current_time(c)
implicit none
character(*),intent(in)::c
integer::ti(1:8)
character(10)::b(1:3)
call date_and_time(b(1),b(2),b(3),ti)
write(6,*)
write(6,'(3A,i0,A,i0,A,i0,A,i0,A,i0,A,i0,A)')" == ", &
c," ",ti(1),"/",ti(2),"/",ti(3), &
" ",ti(5),":",ti(6),":",ti(7),", (yyyy/mm/dd hh:mm:ss)"
write(6,*)
return
end subroutine current_time
サブルーチンcurrent_timeを定義して、それを呼び出すだけのほうが分かりやすいかと思います。
引数は何という文言をその場所に指定したいかを示すものです。
実行して適当なときにEnterキーを押してプログラムを進めると、
$ ./a.out
== program start 2016/2/15 9:16:38, (yyyy/mm/dd hh:mm:ss)
press Enter
== program finish 2016/2/15 9:16:40, (yyyy/mm/dd hh:mm:ss)
$
という結果が得られるでしょう。もちろん、プログラムを動かした時点での時間が表示されます。
一瞬で終わるプログラムの場合は差は見られ無いと思います。
実時間計測(system_clock)
system_clockはfortran標準実装なので汎用性は高いです[4]。system_clockは組み込まれているサブルーチンなので下のプログラムをそのままコピペして使う事が出来ます。
implicit none
integer::ti,tf,tr ! ti: initial time, tf: finish time, tr: time rate
integer::i
call system_clock(ti)
!program here
write(6,*)"press Enter"
read *
call system_clock(tf,tr)
write(6,'(f10.3,A)')(tf-ti)/dble(tr),"[s]"
return
end program main
上の文を実行して適当なときにEnterキーを押してプログラムを進めると、
$ ./a.out
press Enter
1.283[s]
$
という出力が得られます。
CPU時間の計測(cpu_time)
CPU時間の計測するには
...
call cpu_time(t1)
write(6,'(f10.3,A)')(t1-t0),"[CPU sec]"
を入れましょう[3]。real::t1,t2です。
implicit none
real::t0,t1
integer::i
call cpu_time(t0)
!program here
write(6,*)"press Enter"
read *
call cpu_time(t1)
write(6,'(f10.3,A)')(t1-t0),"[CPU sec]"
stop
end program main
でokです。適当な時間待って、Enterキーを押すと
$ ./a.out
press Enter
0.000[s]
という出力が得られるでしょう。
これはcpuを動かしていないためであり、cpuが動いていた時間というのは限りなく0だ、ということです。
参考文献
[1]ユーザ時間とシステム時間の違いを教えてください。
[2]1.4.7.1 date_and_time: 日付と時刻の取得 -ORACLE®
[3]8 移植性のある時間計測の方法 -nag
[4]9.254 SYSTEM_CLOCK — Time function
はじめまして。最近Fortran言語を学び始めたあかねこと申します。
http://www.cn.kagawa-nct.ac.jp/~kusama/study/cem/fdtd/fdtd_2dtm/fdtd_2dtm.html
上記のURLの2D_TE_FDTDのmainルーチンの実行時間を計測したいと思ったのですが、
main_2dtm.f90ファイルの中に直接cpu_timeを書き込むのでしょうか?
お手数おかけしますがお返事お願い致します
緋猫さん
コメントありがとうございます。
2次元有限要素法みたいですね。
実行時間がcpu時間を指しているならばそれでいいと思います。
ここからは実際に試していないのですが、
use fdtd_lib_2dtm
implicit none
double precision::t1,t2
call cpu_time(t1)
!******** initial condition ********
open(1,file='show_initialdata')
...
!******** time dependent files ********
close(unit=7)
close(unit=8)
call cpu_time(t2)
write(6,*)"cpu_time",t2-t1,"[sec]"
end program main_2dtm
という形でokなはずです。モジュールfdtd_lib_2dtmの中にt1やt2という変数を用いている場合がありますので、t1ではなく、もう少し長い変数名にして確実に被らない名前にしたほうがいいかもしれません。
迅速な回答ありがとうございます.
実際に試してみて,わからなかったことがあればまた質問させていただきます.
僕もまだまだ初心者なので答えられない場合もあるかと思いますが、出来るだけ返答出来るように努力します。