portedportable, not yet portedexecuted, not portableexecutable, not hit by this run
| 1 | ! This file is part of MOM6, the Modular Ocean Model version 6. | |
| 2 | ! See the LICENSE file for licensing information. | |
| 3 | ! SPDX-License-Identifier: Apache-2.0 | |
| 4 | ||
| 5 | !> A module to monitor the overall CPU time used by MOM6 and project when to stop the model | |
| 6 | module MOM_write_cputime | |
| 7 | ||
| 8 | use MOM_coms, only : sum_across_PEs, num_pes | |
| 9 | use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, is_root_pe | |
| 10 | use MOM_io, only : open_ASCII_file, close_file, APPEND_FILE, WRITEONLY_FILE | |
| 11 | use MOM_file_parser, only : get_param, log_param, log_version, param_file_type | |
| 12 | use MOM_time_manager, only : time_type, get_time, operator(>) | |
| 13 | ||
| 14 | implicit none ; private | |
| 15 | ||
| 16 | public write_cputime, MOM_write_cputime_init, MOM_write_cputime_end, write_cputime_start_clock | |
| 17 | ||
| 18 | !----------------------------------------------------------------------- | |
| 19 | ||
| 20 | integer :: CLOCKS_PER_SEC = 1000 !< The number of clock cycles per second, used by the system clock | |
| 21 | integer :: MAX_TICKS = 1000 !< The number of ticks per second, used by the system clock | |
| 22 | ||
| 23 | !> A control structure that regulates the writing of CPU time | |
| 24 | type, public :: write_cputime_CS ; private | |
| 25 | logical :: initialized = .false. !< True if this control structure has been initialized. | |
| 26 | real :: maxcpu !< The maximum amount of CPU time per processor | |
| 27 | !! for which MOM should run before saving a restart | |
| 28 | !! file and quitting with a return value that | |
| 29 | !! indicates that further execution is required to | |
| 30 | !! complete the simulation [wall-clock seconds]. | |
| 31 | type(time_type) :: Start_time !< The start time of the simulation. | |
| 32 | !! Start_time is set in MOM_initialization.F90 | |
| 33 | real :: startup_cputime !< The CPU time used in the startup phase of the model [clock_cycles]. | |
| 34 | real :: prev_cputime = 0.0 !< The last measured CPU time [clock_cycles]. | |
| 35 | real :: dn_dcpu_min = -1.0 !< The minimum derivative of timestep with CPU time [steps clock_cycles-1]. | |
| 36 | real :: cputime2 = 0.0 !< The accumulated CPU time [clock_cycles]. | |
| 37 | integer :: previous_calls = 0 !< The number of times write_CPUtime has been called. | |
| 38 | integer :: prev_n = 0 !< The value of n from the last call. | |
| 39 | integer :: fileCPU_ascii= -1 !< The unit number of the CPU time file. | |
| 40 | character(len=200) :: CPUfile !< The name of the CPU time file. | |
| 41 | end type write_cputime_CS | |
| 42 | ||
| 43 | contains | |
| 44 | ||
| 45 | !> Evaluate the CPU time returned by SYSTEM_CLOCK at the start of a run | |
| 46 | 1 | subroutine write_cputime_start_clock(CS) |
| 47 | type(write_cputime_CS), pointer :: CS !< The control structure set up by a previous | |
| 48 | !! call to MOM_write_cputime_init. | |
| 49 | integer :: new_cputime ! The CPU time returned by SYSTEM_CLOCK | |
| 50 | 1 | if (.not.associated(CS)) allocate(CS) |
| 51 | ||
| 52 | 1 | call SYSTEM_CLOCK(new_cputime, CLOCKS_PER_SEC, MAX_TICKS) |
| 53 | 1 | CS%prev_cputime = new_cputime |
| 54 | 1 | end subroutine write_cputime_start_clock |
| 55 | ||
| 56 | !> Initialize the MOM_write_cputime module. | |
| 57 | 1 | subroutine MOM_write_cputime_init(param_file, directory, Input_start_time, CS) |
| 58 | type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters | |
| 59 | character(len=*), intent(in) :: directory !< The directory where the CPU time file goes. | |
| 60 | type(time_type), intent(in) :: Input_start_time !< The start model time of the simulation. | |
| 61 | type(write_cputime_CS), pointer :: CS !< A pointer that may be set to point to the | |
| 62 | !! control structure for this module. | |
| 63 | ||
| 64 | ! Local variables | |
| 65 | integer :: new_cputime ! The CPU time returned by SYSTEM_CLOCK | |
| 66 | ! This include declares and sets the variable "version". | |
| 67 | # include "version_variable.h" | |
| 68 | character(len=40) :: mdl = 'MOM_write_cputime' ! This module's name. | |
| 69 | logical :: all_default ! If true, all parameters are using their default values. | |
| 70 | ||
| 71 | 1 | if (.not.associated(CS)) then |
| 72 | 0 | allocate(CS) |
| 73 | 0 | call SYSTEM_CLOCK(new_cputime, CLOCKS_PER_SEC, MAX_TICKS) |
| 74 | 0 | CS%prev_cputime = new_cputime |
| 75 | endif | |
| 76 | ||
| 77 | 1 | CS%initialized = .true. |
| 78 | ||
| 79 | ! Read all relevant parameters and write them to the model log. | |
| 80 | ||
| 81 | ! Determine whether all parameters are set to their default values. | |
| 82 | 1 | call get_param(param_file, mdl, "MAXCPU", CS%maxcpu, units="wall-clock seconds", default=-1.0, do_not_log=.true.) |
| 83 | 1 | call get_param(param_file, mdl, "CPU_TIME_FILE", CS%CPUfile, default="CPU_stats", do_not_log=.true.) |
| 84 | 1 | all_default = (CS%maxcpu == -1.0) .and. (trim(CS%CPUfile) == trim("CPU_stats")) |
| 85 | ||
| 86 | 1 | call log_version(param_file, mdl, version, "", all_default=all_default) |
| 87 | call get_param(param_file, mdl, "MAXCPU", CS%maxcpu, & | |
| 88 | "The maximum amount of cpu time per processor for which "//& | |
| 89 | "MOM should run before saving a restart file and "//& | |
| 90 | "quitting with a return value that indicates that a "//& | |
| 91 | "further run is required to complete the simulation. "//& | |
| 92 | "If automatic restarts are not desired, use a negative "//& | |
| 93 | "value for MAXCPU. MAXCPU has units of wall-clock "//& | |
| 94 | "seconds, so the actual CPU time used is larger by a "//& | |
| 95 | "factor of the number of processors used.", & | |
| 96 | 1 | units="wall-clock seconds", default=-1.0) |
| 97 | call get_param(param_file, mdl, "CPU_TIME_FILE", CS%CPUfile, & | |
| 98 | 1 | "The file into which CPU time is written.",default="CPU_stats") |
| 99 | 1 | CS%CPUfile = trim(directory)//trim(CS%CPUfile) |
| 100 | 1 | call log_param(param_file, mdl, "directory/CPU_TIME_FILE", CS%CPUfile) |
| 101 | #ifdef STATSLABEL | |
| 102 | CS%CPUfile = trim(CS%CPUfile)//"."//trim(adjustl(STATSLABEL)) | |
| 103 | #endif | |
| 104 | ||
| 105 | 1 | CS%Start_time = Input_start_time |
| 106 | ||
| 107 | 1 | end subroutine MOM_write_cputime_init |
| 108 | ||
| 109 | !> Close the MOM_write_cputime module. | |
| 110 | 1 | subroutine MOM_write_cputime_end(CS) |
| 111 | type(write_cputime_CS), pointer :: CS !< The control structure set up by a previous | |
| 112 | !! call to MOM_write_cputime_init. | |
| 113 | ||
| 114 | 1 | if (.not.associated(CS)) return |
| 115 | ||
| 116 | ! Flush and close the output files. | |
| 117 | 1 | if (is_root_pe() .and. CS%fileCPU_ascii > 0) then |
| 118 | 0 | flush(CS%fileCPU_ascii) |
| 119 | 0 | call close_file(CS%fileCPU_ascii) |
| 120 | endif | |
| 121 | ||
| 122 | 1 | deallocate(CS) |
| 123 | ||
| 124 | end subroutine MOM_write_cputime_end | |
| 125 | ||
| 126 | !> This subroutine assesses how much CPU time the model has taken and determines how long the model | |
| 127 | !! should be run before it saves a restart file and stops itself. Optionally this may also be used | |
| 128 | !! to trigger this module's end routine. | |
| 129 | 2 | subroutine write_cputime(day, n, CS, nmax, call_end) |
| 130 | type(time_type), intent(inout) :: day !< The current model time. | |
| 131 | integer, intent(in) :: n !< The time step number of the current execution. | |
| 132 | type(write_cputime_CS), pointer :: CS !< The control structure set up by a previous | |
| 133 | !! call to MOM_write_cputime_init. | |
| 134 | integer, optional, intent(inout) :: nmax !< The number of iterations after which to stop so | |
| 135 | !! that the simulation will not run out of CPU time. | |
| 136 | logical, optional, intent(in) :: call_end !< If true, also call MOM_write_cputime_end. | |
| 137 | ||
| 138 | ! Local variables | |
| 139 | real :: d_cputime ! The change in CPU time since the last call | |
| 140 | ! this subroutine [clock_cycles] | |
| 141 | integer :: new_cputime ! The CPU time returned by SYSTEM_CLOCK [clock_cycles] | |
| 142 | real :: reday ! The time in days, including fractional days [days] | |
| 143 | integer :: start_of_day ! The number of seconds since the start of the day | |
| 144 | integer :: num_days ! The number of days in the time | |
| 145 | ||
| 146 | 2 | if (.not.associated(CS)) call MOM_error(FATAL, & |
| 147 | 0 | "write_energy: Module must be initialized before it is used.") |
| 148 | ||
| 149 | 2 | if (.not.CS%initialized) call MOM_error(FATAL, & |
| 150 | 0 | "write_cputime: Module must be initialized before it is used.") |
| 151 | ||
| 152 | 2 | call SYSTEM_CLOCK(new_cputime, CLOCKS_PER_SEC, MAX_TICKS) |
| 153 | ! The following lines extract useful information even if the clock has rolled | |
| 154 | ! over, assuming a 32-bit SYSTEM_CLOCK. With more bits, rollover is essentially | |
| 155 | ! impossible. Negative fluctuations of less than 10 seconds are not interpreted | |
| 156 | ! as the clock rolling over. This should be unnecessary but is sometimes needed | |
| 157 | ! on the GFDL SGI/O3k. | |
| 158 | 2 | if (new_cputime < CS%prev_cputime-(10.0*CLOCKS_PER_SEC)) then |
| 159 | 0 | d_cputime = new_cputime - CS%prev_cputime + MAX_TICKS |
| 160 | else | |
| 161 | 2 | d_cputime = new_cputime - CS%prev_cputime |
| 162 | endif | |
| 163 | ||
| 164 | 2 | call sum_across_PEs(d_cputime) |
| 165 | 2 | if (CS%previous_calls == 0) CS%startup_cputime = d_cputime |
| 166 | ||
| 167 | 2 | CS%cputime2 = CS%cputime2 + d_cputime |
| 168 | ||
| 169 | 2 | if ((CS%previous_calls >= 1) .and. (CS%maxcpu > 0.0)) then |
| 170 | ! Determine the slowest rate at which time steps are executed. | |
| 171 | 0 | if ((n > CS%prev_n) .and. (d_cputime > 0.0) .and. & |
| 172 | ((CS%dn_dcpu_min*d_cputime < (n - CS%prev_n)) .or. & | |
| 173 | (CS%dn_dcpu_min < 0.0))) & | |
| 174 | 0 | CS%dn_dcpu_min = (n - CS%prev_n) / d_cputime |
| 175 | 0 | if (present(nmax) .and. (CS%dn_dcpu_min >= 0.0)) then |
| 176 | ! Have the model stop itself after 95% of the CPU time has been used. | |
| 177 | nmax = n + INT( CS%dn_dcpu_min * & | |
| 178 | (0.95*CS%maxcpu * REAL(num_pes())*CLOCKS_PER_SEC - & | |
| 179 | 0 | (CS%startup_cputime + CS%cputime2)) ) |
| 180 | ! write(mesg,*) "Resetting nmax to ",nmax," at day",reday | |
| 181 | ! call MOM_mesg(mesg) | |
| 182 | endif | |
| 183 | endif | |
| 184 | 2 | CS%prev_cputime = new_cputime ; CS%prev_n = n |
| 185 | ||
| 186 | 2 | call get_time(day, start_of_day, num_days) |
| 187 | 2 | reday = REAL(num_days)+ (REAL(start_of_day)/86400.0) |
| 188 | ||
| 189 | ! Reopen or create a text output file. | |
| 190 | 2 | if ((CS%previous_calls == 0) .and. (is_root_pe())) then |
| 191 | 1 | if (day > CS%Start_time) then |
| 192 | 0 | call open_ASCII_file(CS%fileCPU_ascii, trim(CS%CPUfile), action=APPEND_FILE) |
| 193 | else | |
| 194 | 1 | call open_ASCII_file(CS%fileCPU_ascii, trim(CS%CPUfile), action=WRITEONLY_FILE) |
| 195 | endif | |
| 196 | endif | |
| 197 | ||
| 198 | 2 | if (is_root_pe()) then |
| 199 | 2 | if (CS%previous_calls == 0) then |
| 200 | write(CS%fileCPU_ascii, & | |
| 201 | '("Startup CPU time: ", F12.3, " sec summed across", I5, " PEs.")') & | |
| 202 | 1 | (CS%startup_cputime / CLOCKS_PER_SEC), num_pes() |
| 203 | 1 | write(CS%fileCPU_ascii,*)" Day, Step number, CPU time, CPU time change" |
| 204 | endif | |
| 205 | write(CS%fileCPU_ascii,'(F12.3,", ",I11,", ",F12.3,", ",F12.3)') & | |
| 206 | 2 | reday, n, (CS%cputime2 / real(CLOCKS_PER_SEC)), & |
| 207 | 4 | d_cputime / real(CLOCKS_PER_SEC) |
| 208 | ||
| 209 | 2 | flush(CS%fileCPU_ascii) |
| 210 | endif | |
| 211 | 2 | CS%previous_calls = CS%previous_calls + 1 |
| 212 | ||
| 213 | 2 | if (present(call_end)) then |
| 214 | 1 | if (call_end) call MOM_write_cputime_end(CS) |
| 215 | endif | |
| 216 | ||
| 217 | 2 | end subroutine write_cputime |
| 218 | ||
| 219 | !> \namespace mom_write_cputime | |
| 220 | !! | |
| 221 | !! By Robert Hallberg, May 2006. | |
| 222 | !! | |
| 223 | !! This file contains the subroutine (write_cputime) that writes | |
| 224 | !! the summed CPU time across all processors to an output file. In | |
| 225 | !! addition, write_cputime estimates how many more time steps can be | |
| 226 | !! taken before 95% of the available CPU time is used, so that the | |
| 227 | !! model can be checkpointed at that time. | |
| 228 | ||
| 229 | 0 | end module MOM_write_cputime |