TimerModule.F90 Source File


Contents

Source Code


Source Code

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!> A module to do timings.
MODULE TimerModule
  USE DataTypesModule, ONLY : NTREAL
  USE LoggingModule, ONLY : EnterSubLog, ExitSubLog, WriteElement, &
       & WriteHeader
  USE ProcessGridModule, ONLY : global_grid
  USE NTMPIModule
  IMPLICIT NONE
  PRIVATE
  INTEGER, PARAMETER :: name_len = 50
  CHARACTER(LEN = name_len), DIMENSION(:), ALLOCATABLE, SAVE :: timer_list
  REAL(NTREAL), DIMENSION(:), ALLOCATABLE, SAVE :: start_times
  REAL(NTREAL), DIMENSION(:), ALLOCATABLE, SAVE:: elapsed_times
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  PUBLIC :: RegisterTimer
  PUBLIC :: StartTimer
  PUBLIC :: StopTimer
  PUBLIC :: PrintTimer
  PUBLIC :: PrintAllTimers
  PUBLIC :: PrintAllTimersDistributed
CONTAINS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Register a timer with the timer module.  Call this before using that timer.
  SUBROUTINE RegisterTimer(timer_name)
    !> Name of the timer.
    CHARACTER(LEN = *), INTENT(IN) :: timer_name
    !! Local Data
    CHARACTER(LEN = name_len), DIMENSION(:), ALLOCATABLE :: temp_timer_list
    REAL(NTREAL), DIMENSION(:), ALLOCATABLE :: temp_start_times
    REAL(NTREAL), DIMENSION(:), ALLOCATABLE :: temp_elapsed_times

    IF (ALLOCATED(timer_list)) THEN
       ALLOCATE(temp_timer_list(SIZE(timer_list)+1))
       ALLOCATE(temp_start_times(SIZE(start_times)+1))
       ALLOCATE(temp_elapsed_times(SIZE(elapsed_times)+1))
       temp_timer_list(:SIZE(timer_list)) = timer_list
       temp_start_times(:SIZE(start_times)) = start_times
       temp_elapsed_times(:SIZE(elapsed_times)) = elapsed_times
       CALL MOVE_ALLOC(temp_timer_list,timer_list)
       CALL MOVE_ALLOC(temp_start_times,start_times)
       CALL MOVE_ALLOC(temp_elapsed_times,elapsed_times)
       timer_list(SIZE(timer_list)) = timer_name
       elapsed_times(SIZE(timer_list)) = 0
    ELSE
       ALLOCATE(timer_list(1))
       ALLOCATE(start_times(1))
       ALLOCATE(elapsed_times(1))
       timer_list(1) = timer_name
       elapsed_times(1) = 0
    END IF
  END SUBROUTINE RegisterTimer
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Start the clock running for a given timer.
  SUBROUTINE StartTimer(timer_name)
    !> Name of the timer. Must be registered.
    CHARACTER(LEN = *), INTENT(IN) :: timer_name
    !! Local Data
    INTEGER :: II
    REAL(NTREAL) :: temp_time

    temp_time = MPI_WTIME()
    II = GetTimerPosition(timer_name)
    IF (II .GT. 0) THEN
       start_times(II) = temp_time
    END IF
  END SUBROUTINE StartTimer
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Stop the clock for a given timer.
  SUBROUTINE StopTimer(timer_name)
    !> Name of the timer. Must be registered.
    CHARACTER(LEN = *), INTENT(IN) :: timer_name
    !! Local Data
    INTEGER :: II
    REAL(NTREAL):: temp_elapsed_time
    REAL(NTREAL) :: temp_start_time

    II = GetTimerPosition(timer_name)
    IF (II .GT. 0) THEN
       temp_elapsed_time = MPI_WTIME()
       temp_start_time = start_times(II)
       elapsed_times(II) = elapsed_times(II) + &
            & temp_elapsed_time - temp_start_time
    END IF
  END SUBROUTINE StopTimer
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Print out the elapsed time for a given timer.
  SUBROUTINE PrintTimer(timer_name)
    !> Name of the timer. Must be registered.
    CHARACTER(LEN = *), INTENT(IN) :: timer_name
    !! Local Data
    INTEGER :: II

    II = GetTimerPosition(timer_name)
    CALL WriteHeader("Timers")
    CALL EnterSubLog
    IF (II > 0) THEN
       CALL WriteElement(key = timer_name, VALUE = elapsed_times(II))
    END IF
    CALL ExitSubLog
  END SUBROUTINE PrintTimer
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Print out the elapsed time for each timer on this process.
  SUBROUTINE PrintAllTimers()
    !! Local Data
    INTEGER :: II

    CALL WriteHeader("Timers")
    CALL EnterSubLog
    DO II = LBOUND(timer_list, dim = 1), UBOUND(timer_list, dim = 1)
       CALL WriteElement(key = timer_list(II), VALUE = elapsed_times(II))
    END DO
    CALL ExitSubLog
  END SUBROUTINE PrintAllTimers
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Print out the elapsed time for each timer based on the max value across
  !> processes.
  SUBROUTINE PrintAllTimersDistributed()
    !! Local Data
    INTEGER      :: II
    REAL(NTREAL) :: elapsed
    REAL(NTREAL) :: max_time
    INTEGER      :: ierr

    CALL WriteHeader("Timers")
    CALL EnterSubLog

    DO II = LBOUND(timer_list, dim = 1), UBOUND(timer_list, dim = 1)
       elapsed = elapsed_times(II)
       CALL MPI_Allreduce(elapsed, max_time, 1, MPI_DOUBLE_PRECISION ,MPI_MAX, &
            & global_grid%global_comm, ierr)
       CALL WriteElement(key = timer_list(II), VALUE = max_time)
    END DO

    CALL ExitSubLog
  END SUBROUTINE PrintAllTimersDistributed
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Figure out the position in the timer list where timer_name is.
  !> This is a utility routine.
  FUNCTION GetTimerPosition(timer_name) RESULT(timer_position)
    !! Parameters
    !> Name of the timer.
    CHARACTER(LEN = *), INTENT(IN) :: timer_name
    !> The position of the timer. 0 means the timer has not been registered.
    INTEGER :: timer_position
    !! Local Data
    INTEGER :: II
    LOGICAL :: not_found

    not_found = .TRUE.

    IF (ALLOCATED(timer_list)) THEN
       DO II = 1, SIZE(timer_list)
          IF (timer_name .EQ. timer_list(II)) THEN
             not_found = .FALSE.
             EXIT
          END IF
       END DO
    END IF

    IF (not_found) THEN
       timer_position = 0
    ELSE
       timer_position = II
    END IF
  END FUNCTION GetTimerPosition
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
END MODULE TimerModule