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
57 character(len=RT_STATS_MAX_NAME_LEN),
allocatable :: rt_stats_id(:)
62 logical :: enabled = .false.
63 logical :: output_profile = .false.
81 type(json_file),
intent(inout) :: params
87 this%enabled, .false.)
89 'case.runtime_statistics.output_profile', &
90 this%output_profile, .false.)
92 if (this%enabled)
then
100 call this%elapsed_time(i)%init()
103 call this%region_timestamp%init(100)
114 if (
allocated(this%rt_stats_id))
then
115 deallocate(this%rt_stats_id)
118 if (
allocated(this%elapsed_time))
then
119 do i = 1,
size(this%elapsed_time)
120 call this%elapsed_time(i)%free()
122 deallocate(this%elapsed_time)
125 call this%region_timestamp%free()
133 character(len=*),
intent(in) :: name
134 integer,
optional,
intent(in) :: region_id
138 if (.not. this%enabled)
return
140 if (
present(region_id))
then
143 call this%find_region_id(name, id)
147 if (len_trim(this%rt_stats_id(id)) .eq. 0)
then
148 this%rt_stats_id(id) = trim(name)
149 else if (trim(this%rt_stats_id(id)) .ne. trim(name))
then
153 region_data%y = mpi_wtime()
154 call this%region_timestamp%push(region_data)
156 call neko_error(
'Invalid profiling region id')
166 character(len=*),
optional,
intent(in) :: name
167 integer,
optional,
intent(in) :: region_id
168 real(kind=
dp) :: end_time, elapsed_time
170 character(len=1024) :: error_msg
173 if (.not. this%enabled)
return
175 end_time = mpi_wtime()
176 region_data = this%region_timestamp%pop()
178 if (region_data%x .le. 0)
then
179 call neko_error(
'Invalid profiling region closed')
183 if (
present(name))
then
184 if (
present(region_id))
then
187 call this%find_region_id(name, id)
190 if (trim(this%rt_stats_id(id)) .ne. trim(name))
then
191 write(error_msg,
'(A,I0,A,A,A)')
'Invalid profiler region closed (', &
192 id,
', expected: ', trim(this%rt_stats_id(id)),
')'
195 else if (region_data%x .ne. id)
then
197 write(error_msg,
'(A,A,A,A,A)')
'Invalid profiler region closed (', &
198 trim(this%rt_stats_id(region_data%x)),
', expected: ', &
199 trim(this%rt_stats_id(id)),
')'
204 elapsed_time = end_time - region_data%y
205 call this%elapsed_time(region_data%x)%push(elapsed_time)
212 character(len=LOG_SIZE) :: log_buf, fmt
213 character(len=1250) :: hdr
214 real(kind=
dp) :: avg, std, sem, total
215 integer :: i, nsamples, ncols, nrows, col_idx
218 if (.not. this%enabled)
return
222 write(fmt,
'(A,I0,A)')
'(',
rt_stats_max_name_len,
'x,1x,A15,2x,A15,2x,A15)'
223 write(log_buf, fmt)
'Total time',
'Avg. time',
'Range +/-'
232 if (len_trim(this%rt_stats_id(i)) .gt. 0)
then
233 nsamples = this%elapsed_time(i)%size()
235 hdr = trim(hdr) // trim(this%rt_stats_id(i)) //
', '
236 nrows =
max(nrows, nsamples)
237 if (nsamples .gt. 0)
then
238 select type (region_sample => this%elapsed_time(i)%data)
239 type is (double precision)
240 total = sum(region_sample(1:nsamples))
241 call mpi_allreduce(mpi_in_place, total, 1, &
242 mpi_double_precision, mpi_sum,
neko_comm)
244 avg = total / nsamples
245 std = (total - avg)**2 / nsamples
246 sem = std / sqrt(
real(nsamples,
dp))
249 ',1x,E15.7,2x,E15.7,2x,E15.7)'
250 write(log_buf, fmt) this%rt_stats_id(i), total, avg, &
259 if (this%output_profile)
then
261 call profile_data%init(nrows, ncols)
262 do i = 1,
size(this%elapsed_time)
263 if (len_trim(this%rt_stats_id(i)) .gt. 0)
then
264 nsamples = this%elapsed_time(i)%size()
265 col_idx = col_idx + 1
266 if (nsamples .gt. 0)
then
267 select type (region_sample => this%elapsed_time(i)%data)
268 type is (double precision)
269 profile_data%x(1:nsamples,col_idx) = &
270 region_sample(1:nsamples)
271 call mpi_allreduce(mpi_in_place, &
272 profile_data%x(1:nsamples,col_idx), nsamples, &
273 mpi_double_precision, mpi_sum,
neko_comm)
274 profile_data%x(1:nsamples, col_idx) = &
275 profile_data%x(1:nsamples, col_idx) /
pe_size
283 type(
file_t) :: profile_file
284 call profile_file%init(
'profile.csv')
285 call profile_file%set_header(hdr)
286 call profile_file%write(profile_data)
292 call profile_data%free()
299 character(len=*),
intent(in) :: name
300 integer,
intent(out) :: region_id
307 if (trim(this%rt_stats_id(i)) .eq. trim(name))
then
314 if (region_id .ne. -1)
return
318 if (len_trim(this%rt_stats_id(i)) .eq. 0)
then
324 if (region_id .eq. -1)
then
325 call neko_error(
'Not enough profiling regions available')
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
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 logged.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
integer, parameter, public dp
integer, parameter rt_stats_max_name_len
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
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.
subroutine runtime_stats_end_region(this, name, region_id)
Compute elapsed time for the current region.
integer, parameter rt_stats_max_regions
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 .