40 use json_module,
only : json_file
45 use mpi_f08,
only : mpi_wtime, mpi_allreduce, mpi_in_place, &
46 mpi_double_precision, mpi_sum
60 character(len=RT_STATS_MAX_NAME_LEN),
allocatable :: rt_stats_id(:)
65 logical :: enabled = .false.
66 logical :: output_profile = .false.
85 type(json_file),
intent(inout) :: params
91 this%enabled, .false.)
93 'case.runtime_statistics.output_profile', &
94 this%output_profile, .false.)
96 if (this%enabled)
then
100 this%rt_stats_id =
''
104 call this%elapsed_time(i)%init()
107 call this%region_timestamp%init(100)
118 if (
allocated(this%rt_stats_id))
then
119 deallocate(this%rt_stats_id)
122 if (
allocated(this%elapsed_time))
then
123 do i = 1,
size(this%elapsed_time)
124 call this%elapsed_time(i)%free()
126 deallocate(this%elapsed_time)
129 call this%region_timestamp%free()
137 character(len=*),
intent(in) :: name
138 integer,
optional,
intent(in) :: region_id
140 character(len=RT_STATS_MAX_NAME_LEN) :: key
143 if (.not. this%enabled)
return
148 if (
present(region_id))
then
151 call this%find_region_id(key, id)
154 if (id .gt. 0 .and. id .le.
size(this%rt_stats_id))
then
155 if (len_trim(this%rt_stats_id(id)) .eq. 0)
then
156 this%rt_stats_id(id) = key
157 else if (this%rt_stats_id(id) .ne. key)
then
161 region_data%y = mpi_wtime()
162 call this%region_timestamp%push(region_data)
164 call neko_error(
'Invalid profiling region id')
174 character(len=*),
optional,
intent(in) :: name
175 integer,
optional,
intent(in) :: region_id
176 real(kind=
dp) :: end_time, elapsed_time
178 character(len=1024) :: error_msg
179 character(len=RT_STATS_MAX_NAME_LEN) :: key
182 if (.not. this%enabled)
return
184 end_time = mpi_wtime()
185 region_data = this%region_timestamp%pop()
187 if (region_data%x .le. 0)
then
188 call neko_error(
'Invalid profiling region closed')
192 if (
present(name))
then
195 if (
present(region_id))
then
198 call this%find_region_id(key, id)
201 if (this%rt_stats_id(id) .ne. key)
then
202 write(error_msg,
'(A,I0,A,A,A)')
'Invalid profiler region closed (', &
203 id,
', expected: ', trim(this%rt_stats_id(id)),
')'
206 else if (region_data%x .ne. id)
then
208 write(error_msg,
'(A,A,A,A,A)')
'Invalid profiler region closed (', &
209 trim(this%rt_stats_id(region_data%x)),
', expected: ', &
210 trim(this%rt_stats_id(id)),
')'
215 elapsed_time = end_time - region_data%y
216 call this%elapsed_time(region_data%x)%push(elapsed_time)
223 character(len=LOG_SIZE) :: log_buf, fmt
224 character(len=:),
allocatable :: hdr
225 real(kind=
dp) :: avg, std, sem, total
226 integer :: i, nsamples, ncols, nrows, col_idx
229 if (.not. this%enabled)
return
233 write(fmt,
'(A,I0,A)')
'(',
rt_stats_max_name_len,
'x,1x,A15,2x,A15,2x,A15)'
234 write(log_buf, fmt)
'Total time',
'Avg. time',
'Range +/-'
242 do i = 1,
size(this%rt_stats_id)
243 if (len_trim(this%rt_stats_id(i)) .gt. 0)
then
244 nsamples = this%elapsed_time(i)%size()
246 hdr = trim(hdr) // trim(this%rt_stats_id(i)) //
', '
247 nrows =
max(nrows, nsamples)
248 if (nsamples .gt. 0)
then
249 select type (region_sample => this%elapsed_time(i)%data)
250 type is (double precision)
251 total = sum(region_sample(1:nsamples))
252 call mpi_allreduce(mpi_in_place, total, 1, &
253 mpi_double_precision, mpi_sum,
neko_comm)
255 avg = total / nsamples
256 std = (total - avg)**2 / nsamples
257 sem = std / sqrt(
real(nsamples,
dp))
260 ',1x,E15.7,2x,E15.7,2x,E15.7)'
261 write(log_buf, fmt) this%rt_stats_id(i), total, avg, &
270 if (this%output_profile)
then
272 call profile_data%init(nrows, ncols)
273 do i = 1,
size(this%elapsed_time)
274 if (len_trim(this%rt_stats_id(i)) .gt. 0)
then
275 nsamples = this%elapsed_time(i)%size()
276 col_idx = col_idx + 1
277 if (nsamples .gt. 0)
then
278 select type (region_sample => this%elapsed_time(i)%data)
279 type is (double precision)
280 profile_data%x(1:nsamples, col_idx) = &
281 region_sample(1:nsamples)
282 call mpi_allreduce(mpi_in_place, &
283 profile_data%x(1:nsamples, col_idx), nsamples, &
285 profile_data%x(1:nsamples, col_idx) = &
286 profile_data%x(1:nsamples, col_idx) /
pe_size
294 type(
file_t) :: profile_file
295 call profile_file%init(
'profile.csv')
296 call profile_file%set_header(hdr)
297 call profile_file%write(profile_data)
303 call profile_data%free()
314 character(len=*),
intent(in) :: name
315 integer,
intent(out) :: region_id
316 character(len=RT_STATS_MAX_NAME_LEN) :: key
321 if (.not. this%enabled)
return
328 if (this%rt_stats_id(i) .eq. key)
then
335 if (region_id .ne. -1)
return
339 if (len_trim(this%rt_stats_id(i)) .eq. 0)
then
346 if (region_id .eq. -1)
then
347 region_id =
size(this%rt_stats_id) + 1
356 character(len=RT_STATS_MAX_NAME_LEN),
allocatable :: tmp_id(:)
357 type(stack_r8_t),
allocatable :: tmp_time(:)
360 n =
size(this%rt_stats_id)
362 allocate(tmp_id(2 * n))
363 tmp_id(1:n) = this%rt_stats_id
365 call move_alloc(tmp_id, this%rt_stats_id)
368 allocate(tmp_time(2 * n))
369 tmp_time(1:n) = this%elapsed_time
371 call tmp_time(i)%init()
373 call move_alloc(tmp_time, this%elapsed_time)
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_size
MPI size of communicator.
integer, public pe_rank
MPI rank.
type(mpi_comm), public neko_comm
MPI communicator.
Module for file I/O operations.
Utilities for retrieving parameters from the case files.
integer, parameter, public neko_log_quiet
Always.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
integer, parameter, public dp
subroutine runtime_stats_grow(this)
Double the number of regions, keeping the recorded ones.
integer, parameter rt_stats_max_name_len
Length a region name is stored, looked up and reported with.
subroutine runtime_stats_init(this, params)
Initialise runtime statistics.
subroutine runtime_stats_start_region(this, name, region_id)
Start measuring time for the region named name with id region_id.
subroutine runtime_stats_report(this)
Report runtime statistics for all recorded regions.
subroutine runtime_stats_free(this)
Destroy runtime statistics.
integer, parameter rt_stats_reserved_regions
Region ids reserved for regions started with an explicit id.
type(runtime_stats_t), public neko_rt_stats
subroutine runtime_stats_find_region_id(this, name, region_id)
Find or allocate a region id for the named region name.
integer, parameter rt_stats_init_regions
Initial number of regions, the table grows when it is full.
subroutine runtime_stats_end_region(this, name, region_id)
Compute elapsed time for the current region.
Implements a dynamic stack ADT.
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Mixed integer-double precision 2-tuple based stack.
Double precision based stack.
Mixed integer ( ) double precision ( ) 2-tuple .