Neko 1.99.1
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
runtime_statistics.f90
Go to the documentation of this file.
1! Copyright (c) 2024, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
35 use logger, only : neko_log, log_size
37 use tuple, only : tuple_i4r8_t
38 use num_types, only : dp
40 use json_module, only : json_file
41 use file, only : file_t
42 use matrix, only : matrix_t
43 use utils, only : neko_error
44 use comm, only : pe_rank, pe_size, neko_comm
45 use mpi_f08, only : mpi_wtime, mpi_allreduce, mpi_in_place, &
46 mpi_double_precision, mpi_sum
47 implicit none
48 private
49
50 integer :: rt_stats_max_regions = 50
51
54 character(len=19), allocatable :: rt_stats_id(:)
56 type(stack_r8_t), allocatable :: elapsed_time_(:)
58 type(stack_i4r8t2_t) :: region_timestamp_
59 logical :: enabled_
60 logical :: output_profile_
61 contains
62 procedure, pass(this) :: init => runtime_stats_init
63 procedure, pass(this) :: free => runtime_stats_free
64 procedure, pass(this) :: start_region => runtime_stats_start_region
65 procedure, pass(this) :: end_region => runtime_stats_end_region
66 procedure, pass(this) :: report => runtime_stats_report
67 end type runtime_stats_t
68
70
71contains
72
74 subroutine runtime_stats_init(this, params)
75 class(runtime_stats_t), intent(inout) :: this
76 type(json_file), intent(inout) :: params
77 integer :: i
78
79 call this%free()
80
81 call json_get_or_default(params, 'case.runtime_statistics.enabled', &
82 this%enabled_, .false.)
83 call json_get_or_default(params, &
84 'case.runtime_statistics.output_profile', &
85 this%output_profile_, .false.)
86
87 if (this%enabled_) then
88
89 allocate(this%rt_stats_id(rt_stats_max_regions))
90
91 this%rt_stats_id = ''
92
93 allocate(this%elapsed_time_(rt_stats_max_regions))
94 do i = 1, rt_stats_max_regions
95 call this%elapsed_time_(i)%init()
96 end do
97
98 call this%region_timestamp_%init(100)
99
100 end if
101
102 end subroutine runtime_stats_init
103
105 subroutine runtime_stats_free(this)
106 class(runtime_stats_t), intent(inout) :: this
107 integer :: i
108
109 if (allocated(this%rt_stats_id)) then
110 deallocate(this%rt_stats_id)
111 end if
112
113 if (allocated(this%elapsed_time_)) then
114 do i = 1, size(this%elapsed_time_)
115 call this%elapsed_time_(i)%free()
116 end do
117 deallocate(this%elapsed_time_)
118 end if
119
120 call this%region_timestamp_%free()
121
122 end subroutine runtime_stats_free
123
126 subroutine runtime_stats_start_region(this, name, region_id)
127 class(runtime_stats_t), intent(inout) :: this
128 character(len=*) :: name
129 integer, intent(in) :: region_id
130 type(tuple_i4r8_t) :: region_data
131
132 if (.not. this%enabled_) then
133 return
134 end if
135
136 if (region_id .gt. 0 .and. region_id .le. rt_stats_max_regions) then
137 if (len_trim(this%rt_stats_id(region_id)) .eq. 0) then
138 this%rt_stats_id(region_id) = trim(name)
139 else
140 if (trim(this%rt_stats_id(region_id)) .ne. trim(name)) then
141 call neko_error('Profile region renamed')
142 end if
143 end if
144 region_data%x = region_id
145 region_data%y = mpi_wtime()
146 call this%region_timestamp_%push(region_data)
147 else
148 call neko_error('Invalid profiling region id')
149 end if
150
151 end subroutine runtime_stats_start_region
152
154 subroutine runtime_stats_end_region(this, name, region_id)
155 class(runtime_stats_t), intent(inout) :: this
156 character(len=*) :: name
157 integer, intent(in) :: region_id
158 real(kind=dp) :: end_time, elapsed_time
159 type(tuple_i4r8_t) :: region_data
160
161 if (.not. this%enabled_) then
162 return
163 end if
164
165 end_time = mpi_wtime()
166
167 if (trim(this%rt_stats_id(region_id)) .ne. trim(name)) then
168 call neko_error('Invalid profiler region closed (' // name // ', &
169 &expected: ' // trim(this%rt_stats_id(region_id)) // ')')
170 end if
171 region_data = this%region_timestamp_%pop()
172
173 if (region_data%x .gt. 0) then
174 elapsed_time = end_time - region_data%y
175 call this%elapsed_time_(region_data%x)%push(elapsed_time)
176 end if
177
178 end subroutine runtime_stats_end_region
179
181 subroutine runtime_stats_report(this)
182 class(runtime_stats_t), intent(inout) :: this
183 character(len=LOG_SIZE) :: log_buf
184 character(len=1250) :: hdr
185 real(kind=dp) :: avg, std, sem, total
186 integer :: i, nsamples, ncols, nrows, col_idx
187 type(matrix_t) :: profile_data
188
189 if (.not. this%enabled_) then
190 return
191 end if
192
193 call neko_log%section('Runtime statistics')
194 call neko_log%newline()
195 write(log_buf, '(A,A,1x,A,1x,A)') ' ',&
196 ' Total time ',' Avg. time ',' Range +/-'
197 call neko_log%message(log_buf)
198 write(log_buf, '(A)') &
199 '--------------------------------------------------------------------'
200 call neko_log%message(log_buf)
201
202 ncols = 0
203 nrows = 0
204 hdr = ''
205 do i = 1, size(this%elapsed_time_)
206 if (len_trim(this%rt_stats_id(i)) .gt. 0) then
207 nsamples = this%elapsed_time_(i)%size()
208 ncols = ncols + 1
209 hdr = trim(hdr) // trim(this%rt_stats_id(i)) // ', '
210 nrows = max(nrows, nsamples)
211 if (nsamples .gt. 0) then
212 select type (region_sample => this%elapsed_time_(i)%data)
213 type is (double precision)
214 total = sum(region_sample(1:nsamples))
215 call mpi_allreduce(mpi_in_place, total, 1, &
216 mpi_double_precision, mpi_sum, neko_comm)
217 total = total / pe_size
218 avg = total / nsamples
219 std = (total - avg)**2 / nsamples
220 sem = std /sqrt(real(nsamples, dp))
221 end select
222 write(log_buf, '(A, E15.7,1x,1x,E15.7,1x,1x,E15.7)') &
223 this%rt_stats_id(i), total, avg, 2.5758_dp * sem
224 call neko_log%message(log_buf)
225 end if
226 end if
227 end do
228
229 call neko_log%newline()
230
231 if (this%output_profile_) then
232 col_idx = 0
233 call profile_data%init(nrows, ncols)
234 do i = 1, size(this%elapsed_time_)
235 if (len_trim(this%rt_stats_id(i)) .gt. 0) then
236 nsamples = this%elapsed_time_(i)%size()
237 col_idx = col_idx + 1
238 if (nsamples .gt. 0) then
239 select type (region_sample => this%elapsed_time_(i)%data)
240 type is (double precision)
241 profile_data%x(1:nsamples,col_idx) = &
242 region_sample(1:nsamples)
243 call mpi_allreduce(mpi_in_place, &
244 profile_data%x(1:nsamples,col_idx), nsamples, &
245 mpi_double_precision, mpi_sum, neko_comm)
246 profile_data%x(1:nsamples, col_idx) = &
247 profile_data%x(1:nsamples, col_idx) / pe_size
248 end select
249 end if
250 end if
251 end do
252
253 if (pe_rank .eq. 0) then
254 block
255 type(file_t) :: profile_file
256 call profile_file%init('profile.csv')
257 call profile_file%set_header(hdr)
258 call profile_file%write(profile_data)
259 end block
260 end if
261 end if
262 call neko_log%end_section()
263
264 call profile_data%free()
265
266 end subroutine runtime_stats_report
267
268end module runtime_stats
double real
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:58
integer, public pe_rank
MPI rank.
Definition comm.F90:55
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:42
Module for file I/O operations.
Definition file.f90:34
Utilities for retrieving parameters from the case files.
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:70
integer, parameter, public log_size
Definition log.f90:46
Defines a matrix.
Definition matrix.f90:34
integer, parameter, public dp
Definition num_types.f90:9
Runtime statistics.
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.
type(runtime_stats_t), public neko_rt_stats
subroutine runtime_stats_end_region(this, name, region_id)
Compute elapsed time for the current region.
Implements a dynamic stack ADT.
Definition stack.f90:35
Implements a n-tuple.
Definition tuple.f90:34
Utilities.
Definition utils.f90:35
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:55
Mixed integer-double precision 2-tuple based stack.
Definition stack.f90:98
Double precision based stack.
Definition stack.f90:77
Mixed integer ( ) double precision ( ) 2-tuple .
Definition tuple.f90:87
#define max(a, b)
Definition tensor.cu:40