diff --git a/Makefile b/Makefile index fb555345f..b5fb81071 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ SWIFTEST_MODULES = swiftest_globals.f90 \ swiftest_operators.f90 \ lambda_function.f90\ + walltime_classes.f90 \ swiftest_classes.f90 \ fraggle_classes.f90 \ whm_classes.f90 \ diff --git a/src/io/io.f90 b/src/io/io.f90 index b938af8c2..eacaacf48 100644 --- a/src/io/io.f90 +++ b/src/io/io.f90 @@ -275,18 +275,12 @@ module subroutine io_dump_system(self, param) integer(I4B), save :: idx = 1 !! Index of current dump file. Output flips between 2 files for extra security !! in case the program halts during writing character(len=:), allocatable :: param_file_name - real(DP) :: deltawall, wallperstep, tfrac - integer(I8B) :: clock_count, count_rate, count_max + real(DP) :: tfrac character(*), parameter :: statusfmt = '("Time = ", ES12.5, "; fraction done = ", F6.3, "; Number of active pl, tp = ", I5, ", ", I5)' character(*), parameter :: symbastatfmt = '("Time = ", ES12.5, "; fraction done = ", F6.3, "; Number of active plm, pl, tp = ", I5, ", ", I5, ", ", I5)' - character(len=*), parameter :: walltimefmt = '(" Wall time (s): ", es12.5, "; Wall time/step in this interval (s): ", es12.5)' logical, save :: lfirst = .true. - real(DP), save :: start, finish if (lfirst) then - call system_clock(clock_count, count_rate, count_max) - start = clock_count / (count_rate * 1.0_DP) - finish = start lfirst = .false. if (param%lenergy) call self%conservation_report(param, lterminal=.false.) else @@ -312,17 +306,12 @@ module subroutine io_dump_system(self, param) tfrac = (param%t - param%t0) / (param%tstop - param%t0) - call system_clock(clock_count, count_rate, count_max) - deltawall = clock_count / (count_rate * 1.0_DP) - finish - wallperstep = deltawall / param%istep_dump - finish = clock_count / (count_rate * 1.0_DP) select type(pl => self%pl) class is (symba_pl) write(*, symbastatfmt) param%t, tfrac, pl%nplm, pl%nbody, self%tp%nbody class default write(*, statusfmt) param%t, tfrac, pl%nbody, self%tp%nbody end select - write(*, walltimefmt) finish - start, wallperstep end if return diff --git a/src/main/swiftest_driver.f90 b/src/main/swiftest_driver.f90 index 9d06d1ddb..876e0effd 100644 --- a/src/main/swiftest_driver.f90 +++ b/src/main/swiftest_driver.f90 @@ -20,6 +20,7 @@ program swiftest_driver integer(I8B) :: ioutput_t0 !! The output frame counter at time 0 integer(I8B) :: nloops !! Number of steps to take in the simulation real(DP) :: old_t_final = 0.0_DP !! Output time at which writing should start, in order to prevent duplicate lines being written for restarts + type(walltimer) :: timer !! Object used for computing elapsed wall time ierr = io_get_args(integrator, param_file_name) if (ierr /= 0) then @@ -69,6 +70,7 @@ program swiftest_driver !$ write(*,'(a)') ' OpenMP parameters:' !$ write(*,'(a)') ' ------------------' !$ write(*,'(a,i3,/)') ' Number of threads = ', nthreads + call timer%reset() write(*, *) " *************** Main Loop *************** " do iloop = 1, nloops !> Step the system forward in time @@ -84,7 +86,9 @@ program swiftest_driver iout = iout - 1 if (iout == 0) then ioutput = ioutput_t0 + iloop / istep_out + call timer%finish(nsubsteps=istep_out, message="Integration steps:") if (t > old_t_final) call nbody_system%write_frame(param) + call timer%finish(nsubsteps=1, message="File I/O: ") iout = istep_out end if end if diff --git a/src/modules/swiftest.f90 b/src/modules/swiftest.f90 index a6daff9a7..d3f8996f0 100644 --- a/src/modules/swiftest.f90 +++ b/src/modules/swiftest.f90 @@ -12,6 +12,7 @@ module swiftest use symba_classes use fraggle_classes use lambda_function + use walltime_classes !use advisor_annotate !$ use omp_lib implicit none diff --git a/src/modules/swiftest_classes.f90 b/src/modules/swiftest_classes.f90 index 363ed6f66..82d684f1a 100644 --- a/src/modules/swiftest_classes.f90 +++ b/src/modules/swiftest_classes.f90 @@ -7,7 +7,6 @@ module swiftest_classes implicit none public - type :: netcdf_parameters integer(I4B) :: out_type !! NetCDF output type (will be assigned either NF90_DOUBLE or NF90_FLOAT, depending on the user parameter) integer(I4B) :: ncid !! NetCDF ID for the output file diff --git a/src/modules/walltime_classes.f90 b/src/modules/walltime_classes.f90 new file mode 100644 index 000000000..71334db0f --- /dev/null +++ b/src/modules/walltime_classes.f90 @@ -0,0 +1,119 @@ +module walltime_classes + !! author: David A. Minton + !! + !! Classes and methods used to compute elasped wall time + use swiftest_globals + implicit none + public + + type :: walltimer + integer(I8B) :: count_rate !! Rate at wich the clock ticks + integer(I8B) :: count_max !! Maximum value of the clock ticker + integer(I8B) :: count_start_main !! Value of the clock ticker at when the timer is first called + integer(I8B) :: count_start_step !! Value of the clock ticker at the start of a timed step + integer(I8B) :: count_finish_step !! Value of the clock ticker at the end of a timed step + logical :: lmain_is_started = .false. !! Logical flag indicating whether or not the main timer has been reset or not + contains + procedure :: reset => walltime_reset !! Resets the clock ticker, settting main_start to the current ticker value + procedure :: start => walltime_start !! Starts the timer, setting step_start to the current ticker value + procedure :: finish => walltime_finish !! Ends the timer, setting step_finish to the current ticker value and printing the elapsed time information to the terminal + end type + + interface + module subroutine walltime_finish(self, nsubsteps, message) + implicit none + class(walltimer), intent(inout) :: self !! Walltimer object + integer(I4B), intent(in) :: nsubsteps !! Number of substeps used to compute the time per step + character(len=*), intent(in) :: message !! Message to prepend to the wall time terminal output + end subroutine walltime_finish + + module subroutine walltime_reset(self) + implicit none + class(walltimer), intent(inout) :: self !! Walltimer object + end subroutine walltime_reset + + module subroutine walltime_start(self) + implicit none + class(walltimer), intent(inout) :: self !! Walltimer object + end subroutine walltime_start + end interface + + contains + + module subroutine walltime_finish(self, nsubsteps, message) + !! author: David A. Minton + !! + !! Ends the timer, setting step_finish to the current ticker value and printing the elapsed time information to the terminal + use swiftest_globals + implicit none + ! Arguments + class(walltimer), intent(inout) :: self !! Walltimer object + integer(I4B), intent(in) :: nsubsteps !! Number of substeps used to compute the time per step + character(len=*), intent(in) :: message !! Message to prepend to the wall time terminal output + ! Internals + character(len=*), parameter :: walltimefmt = '" Wall time (s): ", es12.5, "; Wall time/step in this interval (s): ", es12.5' + character(len=STRMAX) :: fmt + integer(I8B) :: count_delta_step, count_delta_main + real(DP) :: wall_main !! Value of total elapsed time at the end of a timed step + real(DP) :: wall_step !! Value of elapsed time since the start of a timed step + real(DP) :: wall_per_substep !! Value of time per substep + + if (.not.self%lmain_is_started) then + write(*,*) "Wall timer error: The step finish time cannot be calculated because the timer is not started!" + return + end if + + call system_clock(self%count_finish_step) + + count_delta_step = self%count_finish_step - self%count_start_step + count_delta_main = self%count_finish_step - self%count_start_main + wall_step = count_delta_step / (self%count_rate * 1.0_DP) + wall_main = count_delta_main / (self%count_rate * 1.0_DP) + wall_per_substep = wall_step / nsubsteps + + fmt = '("' // trim(adjustl(message)) // '",' // walltimefmt // ')' + write(*,trim(adjustl(fmt))) wall_main, wall_per_substep + + call self%start() + + return + end subroutine walltime_finish + + module subroutine walltime_reset(self) + !! author: David A. Minton + !! + !! Resets the clock ticker, settting main_start to the current ticker value + use swiftest_globals + implicit none + ! Arguments + class(walltimer), intent(inout) :: self + + call system_clock(self%count_start_main, self%count_rate, self%count_max) + self%lmain_is_started = .true. + call self%start() + + return + end subroutine walltime_reset + + + module subroutine walltime_start(self) + !! author: David A. Minton + !! + !! Starts the timer, setting step_start to the current ticker value + use swiftest_globals + implicit none + ! Arguments + class(walltimer), intent(inout) :: self + + if (.not.self%lmain_is_started) then + write(*,*) "Wall timer error: Cannot start the step time until reset is called at least once!" + return + end if + + call system_clock(self%count_start_step) + + return + end subroutine walltime_start + + +end module walltime_classes \ No newline at end of file