This lightly commented program performs a unit test on the Timer Class.
module Unit_Test_Module use Caesar_Intrinsics_Module use Caesar_Timer_Class use Caesar_Communication_Class implicit none contains subroutine Red (R) type(real) :: R type(integer) :: i do i = 1, 100 R = 2+R**.781828 end do return end subroutine Red subroutine Julian_Day_Output (year, month, day) type(integer), intent(in) :: day, month, year type(integer) :: julian, gregorian julian = Julian_Day(year,month,day,'Julian') gregorian = Julian_Day(year,month,day,'Gregorian') if (this_is_IO_PE) then write (6,100) 'Date: ', year, month, day, & ' Julian Day:', julian, gregorian 100 format (a, i6, '/', i2, '/', i2, a, i10, i10) end if return end subroutine Julian_Day_Output subroutine Check_Interval (Hostname, Value, Min, Max) type(character,*) :: Hostname type(real) :: Value, Min, Max if (Value .NotInInterval. (/ Min, Max /) ) then if (this_is_IO_PE) then write (6,*) 'Hostname: ', Hostname write (6,*) ' **Timer not in interval**' write (6,*) ' Value = ', Value write (6,*) ' Interval = (', Min, ',', Max, ')' end if end if return end subroutine Check_Interval end module Unit_Test_Module program Unit_Test use Unit_Test_Module use Caesar_Intrinsics_Module use Caesar_Data_Structures_Module use Caesar_Timer_Class use Caesar_Numbers_Module, only: zero, one implicit none type(real) :: R, Timer_CPU_Mean, Timer_Wall_Clock_Max type(real) :: JD_avg, JD_min, JD_max, CPU_speed type(integer) :: day, i, Julian_Day_Number, month, month_end, year, & year_end, year_start type(integer), dimension(12) :: days_in_month type(logical) :: Debug, Show_Timer_Output type(Timer_type) :: Blue_Loop_Timer, Julian_Day_Timer, Red_Subroutine_Timer type(Communication_type) :: Comm !-------- ! Uncomment here and two places below to compare ! Wall Clock time with MPI_Wtime (parallel only). !type(real) :: Time_MPI, MPI_WTime !-------- ! Initialize communications. call Initialize (Comm) call Output (Comm) if (this_is_IO_PE) write (6,*) ! Timer output toggle. Turn off for unit tests. Show_Timer_Output = .false. ! Initialize Timers. call Initialize (Blue_Loop_Timer, "Blue Loop") call Initialize (Red_Subroutine_Timer, "Red Subroutine") call Initialize (Julian_Day_Timer, "Julian Day") ! Time some loops and subroutines. call Start (Blue_Loop_Timer) !-------- ! Uncomment here; in declarations; and below to compare ! Wall Clock time with MPI_Wtime (parallel only). !Time_MPI = MPI_WTime() !-------- R = 0 do i = 1, 10000/NPEs call Start (Red_Subroutine_Timer) call Red (R) call Stop (Red_Subroutine_Timer) end do call Stop (Blue_Loop_Timer) if (Show_Timer_Output) then call Output (Blue_Loop_Timer, Verbose=.true., Global=.false.) if (this_is_IO_PE) write (6,*) ' ' call Output (Blue_Loop_Timer, Verbose=.true., Global=.true.) !-------- ! Uncomment here; in declarations; and above to compare ! Wall Clock time with MPI_Wtime (parallel only). !if (this_is_IO_PE) write (6,*) 'MPI_WTime = ', MPI_WTime() - Time_MPI !-------- if (this_is_IO_PE) write (6,*) ' ' call Output (Red_Subroutine_Timer, Verbose=.true., Global=.false.) if (this_is_IO_PE) write (6,*) ' ' call Output (Red_Subroutine_Timer, Verbose=.true., Global=.true.) end if ! Tests on the Julian_Day procedure. ! Output some representative dates. These have all been checked. call Start (Julian_Day_Timer) if (this_is_IO_PE) then write (6,*) write (6,100) 'Significant dates Julian Gregorian' write (6,100) ' Calendar Calendar' end if call Julian_Day_Output (-4713, 1, 1) call Julian_Day_Output ( -753, 4, 21) call Julian_Day_Output ( -2, 10, 30) call Julian_Day_Output ( -1, 1, 1) call Julian_Day_Output ( 1, 1, 1) call Julian_Day_Output ( 200, 2, 28) call Julian_Day_Output ( 200, 2, 29) call Julian_Day_Output ( 200, 3, 1) call Julian_Day_Output ( 300, 2, 28) call Julian_Day_Output ( 300, 2, 29) call Julian_Day_Output ( 300, 3, 1) call Julian_Day_Output ( 1582, 10, 4) call Julian_Day_Output ( 1582, 10, 14) call Julian_Day_Output ( 1752, 9, 2) call Julian_Day_Output ( 1752, 9, 13) call Julian_Day_Output ( 1858, 11, 16) call Julian_Day_Output ( 1968, 5, 23) call Julian_Day_Output ( 1995, 10, 9) call Julian_Day_Output ( 2000, 1, 1) call Julian_Day_Output ( 2132, 8, 31) if (this_is_IO_PE) write (6,*) ' ' ! Turn off verifications inside the Julian_Day procedure for parallel ! versions of the thousands of calls in the next few tests. if (parallel) Debug = .false. ! Julian = Gregorian Test: ! ! Julian Day numbers for Julian calendar and Gregorian calendar dates will ! generally be different. They are only the same for dates from March 1st, ! 200, to February 28, 300. Here we check to make sure they are the same ! for those dates. days_in_month = (/ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 /) if (this_is_IO_PE) write (6,100) 'Julian = Gregorian test starting...' do year = 200, 300 do month = 1, 12 if ((year /= 200 .or. month >= 3) .and. & (year /= 300 .or. month <= 2)) then month_end = days_in_month(month) if (MOD(year,4) == 0 .and. month == 2) then month_end = month_end + 1 end if do day = 1, month_end if (Julian_Day(year, month, day, 'Gregorian', Debug) /= & Julian_Day(year, month, day, 'Julian', Debug) .and. & this_is_IO_PE) then write (6,*) '*******************************************' write (6,*) 'Error -- Julian Day number not the same for' write (6,*) 'Gregorian and Julian calendars on: ' write (6,*) ' ' write (6,*) ' Date = ', year, month, day write (6,*) ' ' write (6,*) 'and it should be.' write (6,*) '*******************************************' end if end do end if end do end do if (this_is_IO_PE) then write (6,100) 'Julian = Gregorian test finished.' write (6,*) end if call Stop (Julian_Day_Timer) ! Julian Calendar Sequential Test. ! ! Check to see if all Julian Days are sequential for the Julian calendar. call Start (Julian_Day_Timer) if (this_is_IO_PE) & write (6,100) 'Julian Calendar Sequential test starting...' year_start = -4713 year_end = 2100 Julian_Day_Number = Julian_Day(year_start, 1, 1, 'Julian') do year = year_start, year_end if (year /= 0) then do month = 1, 12 month_end = days_in_month(month) if (year > 0) then if (MOD(year,4) == 0 .and. month == 2) then month_end = month_end + 1 end if else if (MOD(year,4) == -1 .and. month == 2) then month_end = month_end + 1 end if end if do day = 1, month_end if (Julian_Day(year, month, day, 'Julian', Debug) /= & Julian_Day_Number .and. this_is_IO_PE) then write (6,*) '**********************************************' write (6,*) 'Error -- Julian Day number not sequential for:' write (6,*) ' ' write (6,*) ' Date = ', year, month, day write (6,*) ' ' write (6,*) 'and it should be.' write (6,*) '**********************************************' end if Julian_Day_Number = Julian_Day_Number + 1 end do end do end if end do if (this_is_IO_PE) then write (6,100) 'Julian Calendar Sequential test finished.' write (6,*) end if call Stop (Julian_Day_Timer) ! Gregorian Calendar Sequential Test. ! ! Check to see if all Julian Days are sequential for the Gregorian calendar. call Start (Julian_Day_Timer) if (this_is_IO_PE) & write (6,100) 'Gregorian Calendar Sequential test starting...' year_start = -4713 year_end = 2100 Julian_Day_Number = Julian_Day(year_start, 1, 1, 'Gregorian') do year = year_start, year_end if (year /= 0) then do month = 1, 12 month_end = days_in_month(month) if (year > 0) then if (MOD(year,4) == 0 .and. month == 2) then month_end = month_end + 1 end if if (MOD(year,100) == 0 .and. MOD(year,400) /= 0 .and. & month == 2) then month_end = month_end - 1 end if else if (MOD(year,4) == -1 .and. month == 2) then month_end = month_end + 1 end if if (MOD(year,100) == -1 .and. MOD(year,400) /= -1 .and. & month == 2) then month_end = month_end - 1 end if end if do day = 1, month_end if (Julian_Day(year, month, day, 'Gregorian', Debug) /= & Julian_Day_Number .and. this_is_IO_PE) then write (6,*) '**********************************************' write (6,*) 'Error -- Julian Day number not sequential for:' write (6,*) ' ' write (6,*) ' Date = ', year, month, day write (6,*) ' ' write (6,*) 'and it should be.' write (6,*) '**********************************************' end if Julian_Day_Number = Julian_Day_Number + 1 end do end do end if end do if (this_is_IO_PE) then write (6,100) 'Gregorian Calendar Sequential test finished.' write (6,*) end if call Stop (Julian_Day_Timer) if (Show_Timer_Output) then call Output (Julian_Day_Timer, Verbose=.true., Global=.false.) if (this_is_IO_PE) write (6,*) call Output (Julian_Day_Timer, Verbose=.true., Global=.true.) end if ! Check timings for various systems. Timer_CPU_Mean = & Mean(Julian_Day_Timer, 'CPU', Global=.true., Split=.false.) Timer_Wall_Clock_Max = & Maximum(Julian_Day_Timer, 'Wall_Clock', Global=.true., Split=.false.) ! Turn this on for new systems to see the timings. if (.false.) then if (this_is_IO_PE) then write (6,*) ' Timer_CPU_Mean = ', Timer_CPU_Mean write (6,*) ' Timer_Wall_Clock_Max = ', Timer_Wall_Clock_Max end if end if ! Galt: Xeon_Intel_Linux-2.4.2_Absoft-8.2 ! Xeon_Intel_Linux-2.4.2_Lahey-L6.00c ! NPES: 2 ! uname -a: Linux galt 2.4.2-2smp #1 SMP \ ! Sun Apr 8 20:21:34 EDT 2001 i686 unknown ! f90 -V f.f90: Copyright Absoft Corporation 1994-2003; \ ! Absoft Pro FORTRAN Version 8.2 ! lf95 --version: Lahey/Fujitsu Fortran 95 Express Release L6.00c ! ! Lahey Absoft ! Run times: CPU Wall Clock CPU Wall Clock ! serial 1.32 1.32 1.47 1.47 ! 1-parallel 1.32 1.32 1.45 1.45 ! 2-parallel 1.22 1.24 .75 1.46 ! 4-parallel 1.25 2.54 .40 1.56 ! 8-parallel 1.27 5.1 .24 1.78 ! 16-parallel 1.30 10.6 .16 2.53 ! 32-parallel 1.36 22.4 .13 4.52 ! ! Comment: After scrutiny, I determined that the Absoft compiler is ! optimizing out the work on the PEs that don't need to communicate ! back! This is with no optimization on! Full output shows that, ! for example, the 32-PE CPU time is 1.46 on the IO_PE and an ! average of 0.08 on the other 31 PEs, resulting in an overall average ! of 0.13. if ('HOSTNAME' == 'galt') then if ('COMPILER' == 'Lahey') then if (parallel) then call Check_Interval ('Galt', Timer_CPU_Mean, 1.20d0, 1.50d0) JD_avg = 1.25 + MAX(0, NPEs-2)*0.63 JD_min = 0.9 * JD_avg JD_max = 1.2 * JD_avg call Check_Interval ('Galt', Timer_Wall_Clock_Max, JD_min, JD_max) else call Check_Interval ('Galt', Timer_CPU_Mean, 1.25d0, 1.50d0) call Check_Interval ('Galt', Timer_Wall_Clock_Max, 1.25d0, 1.50d0) end if else if ('COMPILER' == 'Absoft') then if (parallel) then JD_avg = 1.2298 * NPEs**(-0.70916) JD_min = 0.8 * JD_avg JD_max = 1.2 * JD_avg call Check_Interval ('Galt', Timer_CPU_Mean, JD_min, JD_max) JD_avg = 1.3586 * EXP( 0.037611 * NPEs ) JD_min = 0.9 * JD_avg JD_max = 1.3 * JD_avg call Check_Interval ('Galt', Timer_Wall_Clock_Max, JD_min, JD_max) else call Check_Interval ('Galt', Timer_CPU_Mean, 1.30d0, 1.60d0) call Check_Interval ('Galt', Timer_Wall_Clock_Max, 1.30d0, 1.60d0) end if end if ! Dagny: PentiumIII_Intel_Linux-2.4.20_Absoft-8.2 ! uname -a: Linux dagny 2.4.20-emp_2420p6a0328 #1 \ ! Tue Apr 1 19:52:06 EST 2003 i686 i686 i386 GNU/Linux ! f90 -V f.f90: Copyright Absoft Corporation 1994-2003; \ ! Absoft Pro FORTRAN Version 8.2 ! ! Run times: CPU Wall Clock ! serial 2.33 2.33 ! 1-parallel 2.33 2.33 ! 2-parallel 1.20 2.41 ! 4-parallel .64 2.64 ! 8-parallel .37 3.40 ! 16-parallel .25 4.81 ! 32-parallel .19 9.16 ! ! See comments on Absoft compiler under Galt above. else if ('HOSTNAME' == 'dagny') then if ('COMPILER' == 'Absoft') then if (parallel) then JD_avg = 2.0016 * NPEs**(-0.73317) JD_min = 0.8 * JD_avg JD_max = 1.3 * JD_avg call Check_Interval ('Dagny', Timer_CPU_Mean, JD_min, JD_max) JD_avg = 2.1876 + 0.11487 * NPEs + 0.0032143 * NPEs**2 JD_min = 0.9 * JD_avg JD_max = 1.2 * JD_avg call Check_Interval ('Dagny', Timer_Wall_Clock_Max, JD_min, JD_max) else call Check_Interval ('Dagny', Timer_CPU_Mean, 2.20d0, 2.50d0) call Check_Interval ('Dagny', Timer_Wall_Clock_Max, 2.20d0, 2.50d0) end if end if ! Kira: PentiumM_Intel_Linux-2.4.23_Absoft-8.2 ! uname -a: Linux kira 2.4.23-emp_2423sw #1 \ ! Mon Dec 8 20:12:14 EST 2003 i686 i686 i386 GNU/Linux ! f90 -V f.f90: Copyright Absoft Corporation 1994-2003; \ ! Absoft Pro FORTRAN Version 8.2 ! ! The PentiumM chip in kira varies its processor speed from time to time. ! Two times are given below: ! ! 600 MHz 1600 MHz ! Run times: CPU Wall Clock CPU Wall Clock ! serial 3.19 3.20 1.2 1.2 ! 1-parallel 3.21 3.20 1.2 1.2 ! 2-parallel 1.66 3.51 0.62 1.25 ! 4-parallel .90 3.82 0.33 1.37 ! 8-parallel .52 4.62 0.195 1.64 ! 16-parallel .32 6.24 0.122 2.27 ! 32-parallel .24 10.22 0.090 3.98 ! ! The current CPU_speed variable can be seen via "gmake environment". ! The current speed can then be set below to allow correct timing ! results. ! ! See comments on Absoft compiler under Galt above. else if ('HOSTNAME' == 'kira') then CPU_speed = 1600.d0 if ('COMPILER' == 'Absoft') then if (parallel) then JD_avg = 1702.14 * NPEs**(-0.76068) / CPU_speed JD_min = 0.8 * JD_avg JD_max = 1.2 * JD_avg call Check_Interval ('Kira', Timer_CPU_Mean, JD_min, JD_max) JD_avg = (1767.78 + 133.542 * NPEs) / CPU_speed JD_min = 0.9 * JD_avg JD_max = 1.3 * JD_avg call Check_Interval ('Kira', Timer_Wall_Clock_Max, JD_min, JD_max) else JD_avg = 1920.0 / CPU_speed JD_min = JD_avg - 0.1 JD_max = JD_avg + 0.1 call Check_Interval ('Kira', Timer_CPU_Mean, JD_min, JD_max) JD_avg = 1950.0 / CPU_speed JD_min = JD_avg - 0.1 JD_max = JD_avg + 0.1 call Check_Interval ('Kira', Timer_Wall_Clock_Max, JD_min, JD_max) end if end if ! Caesar: UltraSPARC-IIi_Sun_Solaris-5.6_Native-6.2 ! uname -a: SunOS caesar 5.6 Generic_105181-03 sun4u sparc SUNW,Ultra-5_10 ! f90 -V: Sun WorkShop 6 update 2 Fortran 95 6.2 2001/05/15 ! ! Note that CPU Time scales with the number of PEs! This must ! mean that Suns return the CPU Time of the parent process. Also, ! some runs have given results that lead me to suspect that Suns ! return Wall Clock Time from the CPU_TIME call -- not sure about ! this. ! ! Run times: Both CPU and Both CPU and ! Wall Clock Wall Clock (optimized) ! serial 7.2 4.7 ! 1-parallel 7.06 4.4 ! 2-parallel 14.35 9.9 ! 4-parallel 29.8 19.1 ! 8-parallel 58.1 41.4 ! 16-parallel 123.8 99.1 ! 32-parallel 281.3 191.0 else if ('HOSTNAME' == 'caesar') then if (parallel) then JD_avg = 1.631 + 3.261 * NPEs + 0.2697 * NPEs**2 - 0.005832 * NPEs**3 ! Non-optimized version: !JD_avg = 1.011 + 6.626 * NPEs + 0.06659 * NPEs**2 JD_min = 0.8 * JD_avg JD_max = 1.1 * JD_avg call Check_Interval ('Caesar', Timer_CPU_Mean, JD_min, JD_max) call Check_Interval ('Caesar', Timer_Wall_Clock_Max, JD_min, JD_max) else JD_min = 4.4d0 JD_max = 5.0d0 ! Non-optimized version: ! JD_min = 6.9d0 ! JD_max = 7.5d0 call Check_Interval ('Caesar', Timer_CPU_Mean, JD_min, JD_max) call Check_Interval ('Caesar', Timer_Wall_Clock_Max, JD_min, JD_max) end if end if ! Check state of Timer. VERIFY(Valid_State(Blue_Loop_Timer),0) VERIFY(Valid_State(Red_Subroutine_Timer),0) VERIFY(Valid_State(Julian_Day_Timer),0) ! Finalize Timers. call Finalize (Blue_Loop_Timer) call Finalize (Red_Subroutine_Timer) call Finalize (Julian_Day_Timer) ! Finalize communications. call Finalize (Comm) ! Format statements. 100 format (a) end