diff --git a/README.md b/README.md index c16180e..c2a704d 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,21 @@ call t%timer_stop(nloops, message, print) ! nloops, message and print are option call t%timer_write(file_name) ! Optionally, write the result to a file ``` +### Measuring elapsed time (date_and_time) + +To measure the elapsed wall-clock time, use the following: + +```fortran +use fortime +type(timer) :: t + +call t%dtimer_start() +! Your code or section to be timed +call t%dtimer_stop(nloops, message, print) ! nloops, message and print are optional + +call t%dtimer_write(file_name) ! Optionally, write the result to a file +``` + ### Measuring CPU time To measure the CPU time consumed by your code, use these functions: diff --git a/example/example5.f90 b/example/example5.f90 new file mode 100644 index 0000000..838fa66 --- /dev/null +++ b/example/example5.f90 @@ -0,0 +1,13 @@ +program example5 + + use fortime + + implicit none + + type(timer) :: t + + call t%dtimer_start() + call sleep(1) ! Perform operations here + call t%dtimer_stop() + +end program example5 diff --git a/example/example6.f90 b/example/example6.f90 new file mode 100644 index 0000000..0272bbc --- /dev/null +++ b/example/example6.f90 @@ -0,0 +1,17 @@ +program example6 + + use fortime + + implicit none + + type(timer) :: t + integer :: nl, nloops=3 + + call t%dtimer_start() + do nl = 1, nloops + call sleep(1) ! Perform operations ntimes + end do + call t%dtimer_stop(nloops = nloops, message = 'Elapsed time:', print = .true.) ! nloops, message and print are optional. + call t%dtimer_write('example/example6_etimes') ! Optionally, write the elapsed time to a file + +end program example6 diff --git a/example/example6_etimes b/example/example6_etimes new file mode 100644 index 0000000..8790f74 --- /dev/null +++ b/example/example6_etimes @@ -0,0 +1 @@ +1.0000000000000000 diff --git a/fpm.toml b/fpm.toml index 6f6805e..8bad114 100644 --- a/fpm.toml +++ b/fpm.toml @@ -147,6 +147,37 @@ name = "test24" source-dir = "test" main = "test24.f90" +[[test]] +name = "test25" +source-dir = "test" +main = "test25.f90" + +[[test]] +name = "test26" +source-dir = "test" +main = "test26.f90" + +[[test]] +name = "test27" +source-dir = "test" +main = "test27.f90" + +[[test]] +name = "test28" +source-dir = "test" +main = "test28.f90" + +[[test]] +name = "test29" +source-dir = "test" +main = "test29.f90" + +[[test]] +name = "test30" +source-dir = "test" +main = "test30.f90" + + [[example]] name = "example1" source-dir = "example" @@ -165,4 +196,14 @@ main = "example3.f90" [[example]] name = "example4" source-dir = "example" -main = "example4.f90" \ No newline at end of file +main = "example4.f90" + +[[example]] +name = "example5" +source-dir = "example" +main = "example5.f90" + +[[example]] +name = "example6" +source-dir = "example" +main = "example6.f90" \ No newline at end of file diff --git a/src/fortime.f90 b/src/fortime.f90 index 78221e0..ac59be0 100644 --- a/src/fortime.f90 +++ b/src/fortime.f90 @@ -37,6 +37,11 @@ module fortime real(rk), private :: mpi_elapsed ! Elapsed MPI time real(rk) :: mpi_time ! Elapsed time in seconds #endif + + integer, dimension(8), private :: values_start ! Start date and time values + integer, dimension(8), private :: values_end ! End date and time values + integer, dimension(8), private :: values_elapsed ! Elapsed date and time values + real(rk) :: elapsed_dtime ! Elapsed time in seconds contains procedure :: timer_start ! Procedure for starting the timer procedure :: timer_stop ! Procedure for stopping the timer @@ -57,6 +62,10 @@ module fortime procedure :: mtimer_stop ! Procedure for stopping the MPI timer procedure :: mtimer_write ! Procedure for writing elapsed MPI time to a file #endif + + procedure :: dtimer_start ! Procedure for starting the date_and_time timer + procedure :: dtimer_stop ! Procedure for stopping the date_and_time timer + procedure :: dtimer_write ! Procedure for writing elapsed date_and_time time to a file end type !=============================================================================== @@ -434,6 +443,108 @@ end subroutine mtimer_write #endif + !=============================================================================== + !> author: Seyed Ali Ghasemi + !> Starts the timer by recording the current processor clock value. + !> This value is used to calculate the elapsed time later. + impure subroutine dtimer_start(this) + class(timer), intent(inout) :: this + + ! Start the timer + call date_and_time(values=this%values_start) + + end subroutine dtimer_start + !=============================================================================== + + + !=============================================================================== + !> author: Seyed Ali Ghasemi + !> Stops the timer and calculates the elapsed time. + !> Optionally, it can print a message along with the elapsed time. + impure subroutine dtimer_stop(this, nloops, message, print) + class(timer), intent(inout) :: this + integer, intent(in), optional :: nloops + character(*), intent(in), optional :: message + character(:), allocatable :: msg + logical, intent(in), optional :: print + real(rk) :: values_elapsed_sec + + ! Stop the timer + call date_and_time(values=this%values_end) + + ! Calculate the elapsed processor ticks + this%values_elapsed = this%values_end - this%values_start + + ! Convert processor ticks to seconds + if (.not.present(nloops)) & + this%elapsed_dtime = to_seconds(this%values_elapsed) + if ( present(nloops)) & + this%elapsed_dtime = to_seconds(this%values_elapsed) / real(nloops, kind=rk) + + ! Print the elapsed time + if (.not. present(message)) then + msg = "Elapsed time:" + else + msg = message + end if + + if (present(print)) then + if (print) call print_time(this%elapsed_dtime, msg) + else + call print_time(this%elapsed_dtime, msg) + end if + + ! Deallocate the message + if (allocated(msg)) deallocate(msg) + + end subroutine dtimer_stop + !=============================================================================== + + + !=============================================================================== + !> author: Seyed Ali Ghasemi + !> Writes the elapsed time to a file. + impure subroutine dtimer_write(this, file_name) + class(timer), intent(in) :: this + character(*), intent(in) :: file_name + logical :: file_exists + integer :: nunit + + ! Check if the file exists + inquire(file=file_name, exist=file_exists) + + ! Open the file in appropriate mode + if (file_exists) then + open(newunit=nunit, file=file_name, status='old', action='write', position='append') + else + open(newunit=nunit, file=file_name, status='new', action='write') + end if + + ! Write the elapsed time to the file + write(nunit, '(g0)') this%elapsed_dtime + + ! Close the file + close(nunit) + + end subroutine dtimer_write + !=============================================================================== + + + !=============================================================================== + !> author: Seyed Ali Ghasemi + pure function to_seconds(values) result(seconds) + integer, dimension(8), intent(in) :: values + real(rk) :: seconds + + seconds = real(values(3), rk) * 24.0_rk * 60.0_rk * 60.0_rk + & + real(values(5), rk) * 60.0_rk * 60.0_rk + & + real(values(6), rk) * 60.0_rk + & + real(values(7), rk) + + end function to_seconds + !=============================================================================== + + !=============================================================================== !> author: Seyed Ali Ghasemi impure subroutine print_time(time, message) diff --git a/test/test25.f90 b/test/test25.f90 new file mode 100644 index 0000000..b508559 --- /dev/null +++ b/test/test25.f90 @@ -0,0 +1,21 @@ +program test25 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + + + ! Elapsed time + call t%dtimer_start() + call sleep(1) ! Perform operations here + call t%dtimer_stop() + + call ut%check(res=t%elapsed_dtime, expected=1.0_rk, tol=1.0e-1_rk, msg='test25') + +end program test25 + diff --git a/test/test26.f90 b/test/test26.f90 new file mode 100644 index 0000000..16651ea --- /dev/null +++ b/test/test26.f90 @@ -0,0 +1,25 @@ +program test26 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + integer :: nl, nloops=3 + + + ! Elapsed time with nloops + call t%dtimer_start() + do nl = 1, nloops + call sleep(1) ! Perform operations ntimes + end do + call t%dtimer_stop(nloops = nloops, message = 'Elapsed time:') + call t%dtimer_write('test/test26_etimes') ! Optionally, write the elapsed time to a file + + call ut%check(res=t%elapsed_dtime, expected=1.0_rk, tol=1.0e-1_rk, msg='test26') + +end program test26 + diff --git a/test/test26_etimes b/test/test26_etimes new file mode 100644 index 0000000..5893df2 --- /dev/null +++ b/test/test26_etimes @@ -0,0 +1 @@ +1.000000000000000 diff --git a/test/test27.f90 b/test/test27.f90 new file mode 100644 index 0000000..ad34547 --- /dev/null +++ b/test/test27.f90 @@ -0,0 +1,25 @@ +program test27 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + integer :: nl, nloops=3 + + + ! Elapsed time with nloops + call t%dtimer_start() + do nl = 1, nloops + call sleep(1) ! Perform operations ntimes + end do + call t%dtimer_stop(message = 'Elapsed time:') + call t%dtimer_write('test/test27_etimes') ! Optionally, write the elapsed time to a file + + call ut%check(res=t%elapsed_dtime, expected=real(nloops,rk)*1.0_rk, tol=1.0e-1_rk, msg='test27') + +end program test27 + diff --git a/test/test27_etimes b/test/test27_etimes new file mode 100644 index 0000000..5c869bb --- /dev/null +++ b/test/test27_etimes @@ -0,0 +1 @@ +3.000000000000000 diff --git a/test/test28.f90 b/test/test28.f90 new file mode 100644 index 0000000..65ca2af --- /dev/null +++ b/test/test28.f90 @@ -0,0 +1,21 @@ +program test28 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + + + ! Elapsed time + call t%dtimer_start() + call sleep(1) ! Perform operations here + call t%dtimer_stop(print=.false.) + + call ut%check(res=t%elapsed_dtime, expected=1.0_rk, tol=1.0e-1_rk, msg='test28') + +end program test28 + diff --git a/test/test29.f90 b/test/test29.f90 new file mode 100644 index 0000000..cd74da5 --- /dev/null +++ b/test/test29.f90 @@ -0,0 +1,25 @@ +program test29 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + integer :: nl, nloops=3 + + + ! Elapsed time with nloops + call t%dtimer_start() + do nl = 1, nloops + call sleep(1) ! Perform operations ntimes + end do + call t%dtimer_stop(nloops = nloops, message = 'Elapsed time:', print=.false.) + call t%dtimer_write('test/test29_etimes') ! Optionally, write the elapsed time to a file + + call ut%check(res=t%elapsed_dtime, expected=1.0_rk, tol=1.0e-1_rk, msg='test29') + +end program test29 + diff --git a/test/test29_etimes b/test/test29_etimes new file mode 100644 index 0000000..5893df2 --- /dev/null +++ b/test/test29_etimes @@ -0,0 +1 @@ +1.000000000000000 diff --git a/test/test30.f90 b/test/test30.f90 new file mode 100644 index 0000000..607708d --- /dev/null +++ b/test/test30.f90 @@ -0,0 +1,25 @@ +program test30 + + use kinds + use fortime + use forunittest + + implicit none + + type(timer) :: t + type(unit_test) :: ut + integer :: nl, nloops=3 + + + ! Elapsed time with nloops + call t%dtimer_start() + do nl = 1, nloops + call sleep(1) ! Perform operations ntimes + end do + call t%dtimer_stop(message = 'Elapsed time:', print=.false.) + call t%dtimer_write('test/test30_etimes') ! Optionally, write the elapsed time to a file + + call ut%check(res=t%elapsed_dtime, expected=real(nloops,rk)*1.0_rk, tol=1.0e-1_rk, msg='test30') + +end program test30 + diff --git a/test/test30_etimes b/test/test30_etimes new file mode 100644 index 0000000..5c869bb --- /dev/null +++ b/test/test30_etimes @@ -0,0 +1 @@ +3.000000000000000