MODFLOW 6  version 6.7.0.dev1
USGS Modular Hydrologic Model
profilermodule Module Reference

Data Types

type  measuredsectiontype
 
type  profilertype
 A public type for profiling performance in the application. The ProfilerType is used to measure and record the performance of various parts of the application. It provides mechanisms to start, stop, and. More...
 

Functions/Subroutines

subroutine initialize (this)
 
integer(i4b) function add_section (this, title, parent_id)
 Add a new timed section to the tree, passing the parent id will add it as a child. More...
 
subroutine start (this, title, section_id)
 Start section timing, add when not exist yet (i.e. when id < 1) More...
 
subroutine stop (this, section_id)
 
subroutine print (this, output_unit)
 
recursive subroutine print_section (this, section_id, level)
 
subroutine print_total (this, subtitle)
 
real(dp) function aggregate_walltime (this, title)
 Aggregate walltime over sections with a certain title. More...
 
integer(i4b) function aggregate_counts (this, title)
 Aggregate counts over sections with a certain title. More...
 
subroutine set_print_option (this, profile_option)
 Set the profile option from the user input. More...
 
subroutine destroy (this)
 Clean up the CPU timer object. More...
 
logical(lgp) function is_initialized (this)
 
integer(i4b) function largest_title_length (this)
 Calculate the largest title length. More...
 
subroutine sort_by_walltime (this, idxs)
 Sort section indexes based on walltime. More...
 

Variables

integer(i4b), parameter max_nr_timed_sections = 75
 
integer(i4b), parameter, public len_section_title = 128
 
type(profilertype), public g_prof
 the global timer object (to reduce trivial lines of code) More...
 

Function/Subroutine Documentation

◆ add_section()

integer(i4b) function profilermodule::add_section ( class(profilertype this,
character(len=*)  title,
integer(i4b)  parent_id 
)
private

Definition at line 107 of file Profiler.f90.

108  use simmodule, only: ustop
109  class(ProfilerType) :: this
110  character(len=*) :: title
111  integer(I4B) :: parent_id
112  integer(I4B) :: section_id
113 
114  ! increment to new section id
115  this%nr_sections = this%nr_sections + 1
116  section_id = this%nr_sections
117  if (section_id > size(this%all_sections)) then
118  write (*, *) "Internal error: Too many profiled sections, "&
119  &"increase MAX_NR_TIMED_SECTIONS"
120  call ustop()
121  end if
122 
123  ! initialize new section
124  this%all_sections(section_id)%title = title
125  this%all_sections(section_id)%walltime = dzero
126  this%all_sections(section_id)%status = 0
127 
128  ! if parent, otherwise root section
129  if (parent_id > 0) then
130  ! add child to parent
131  this%all_sections(section_id)%parent_id = parent_id
132  call this%all_sections(parent_id)%children%push_back(section_id)
133  else
134  ! this is the root, assume there's only one!
135  this%all_sections(section_id)%parent_id = 0
136  this%root_id = section_id
137  end if
138 
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public ustop(stopmess, ioutlocal)
Stop the simulation.
Definition: Sim.f90:312
Here is the call graph for this function:

◆ aggregate_counts()

integer(i4b) function profilermodule::aggregate_counts ( class(profilertype this,
character(len=*)  title 
)
private

Definition at line 328 of file Profiler.f90.

329  class(ProfilerType) :: this
330  character(len=*) :: title
331  integer(I4B) :: counts
332  ! local
333  integer(I4B) :: i
334 
335  counts = 0
336  do i = 1, this%nr_sections
337  if (index(this%all_sections(i)%title, trim(title)) > 0) then
338  counts = counts + this%all_sections(i)%count
339  end if
340  end do
341 

◆ aggregate_walltime()

real(dp) function profilermodule::aggregate_walltime ( class(profilertype this,
character(len=*)  title 
)
private

Definition at line 310 of file Profiler.f90.

311  class(ProfilerType) :: this
312  character(len=*) :: title
313  real(DP) :: walltime
314  ! local
315  integer(I4B) :: i
316 
317  walltime = dzero
318  do i = 1, this%nr_sections
319  if (index(this%all_sections(i)%title, trim(title)) > 0) then
320  walltime = walltime + this%all_sections(i)%walltime
321  end if
322  end do
323 
Here is the caller graph for this function:

◆ destroy()

subroutine profilermodule::destroy ( class(profilertype this)
private

Definition at line 365 of file Profiler.f90.

366  class(ProfilerType) :: this
367  ! local
368  integer(I4B) :: i
369 
370  call this%callstack%destroy()
371 
372  do i = 1, max_nr_timed_sections
373  call this%all_sections(i)%children%destroy()
374  end do
375  deallocate (this%all_sections)
376  nullify (this%all_sections)
377 

◆ initialize()

subroutine profilermodule::initialize ( class(profilertype this)
private

Definition at line 71 of file Profiler.f90.

72  class(ProfilerType) :: this
73  ! local
74  integer(I4B) :: i
75 
76  this%tmr_run = -1
77  this%tmr_init = -1
78  this%tmr_update = -1
79  this%tmr_finalize = -1
80  this%tmr_prep_tstp = -1
81  this%tmr_do_tstp = -1
82  this%tmr_final_tstp = -1
83  this%tmr_output = -1
84  this%tmr_nc_export = -1
85 
86  call this%callstack%init()
87 
88  allocate (this%all_sections(max_nr_timed_sections))
89  do i = 1, max_nr_timed_sections
90  this%all_sections(i)%title = "undefined"
91  this%all_sections(i)%status = 0
92  this%all_sections(i)%walltime = dzero
93  this%all_sections(i)%count = 0
94  this%all_sections(i)%parent_id = 0
95  call this%all_sections(i)%children%init()
96  end do
97 
98  this%nr_sections = 0
99  this%root_id = 0
100  this%top_three = [0, 0, 0]
101 

◆ is_initialized()

logical(lgp) function profilermodule::is_initialized ( class(profilertype this)
private

Definition at line 380 of file Profiler.f90.

381  class(ProfilerType) :: this
382  logical(LGP) :: initialized
383 
384  initialized = associated(this%all_sections)
385 

◆ largest_title_length()

integer(i4b) function profilermodule::largest_title_length ( class(profilertype this)
private

Definition at line 390 of file Profiler.f90.

391  class(ProfilerType) :: this
392  integer(I4B) :: max_length
393  integer(I4B) :: i
394 
395  max_length = 0
396  do i = 1, this%nr_sections
397  max_length = max(max_length, len_trim(this%all_sections(i)%title))
398  end do
399 

◆ print()

subroutine profilermodule::print ( class(profilertype this,
integer(i4b), intent(in)  output_unit 
)
private

Definition at line 190 of file Profiler.f90.

191  class(ProfilerType) :: this
192  integer(I4B), intent(in) :: output_unit
193  ! local
194  integer(I4B) :: level, i, top_idx
195  integer(I4B), dimension(:), allocatable :: sorted_idxs
196 
197  this%iout = output_unit
198  if (this%pr_option == 0) return
199 
200  ! get top three leaf sections based on walltime
201  top_idx = 1
202  sorted_idxs = (/(i, i=1, this%nr_sections)/)
203  call this%sort_by_walltime(sorted_idxs)
204  do i = 1, this%nr_sections
205  if (this%all_sections(sorted_idxs(i))%children%size == 0) then ! leaf node
206  if (top_idx > 3) exit
207  this%top_three(top_idx) = sorted_idxs(i)
208  top_idx = top_idx + 1
209  end if
210  end do
211 
212  this%max_title_len = this%largest_title_length()
213 
214  if (this%pr_option > 1) then
215  ! print timing call stack
216  level = 0
217  write (this%iout, '(/1x,a/)') &
218  repeat('-', 18)//" Profiler: Call Stack "//repeat('-', 18)
219  call this%print_section(this%root_id, level)
220  end if
221 
222  ! print walltime per category from substring (if exist)
223  ! note: the sections containing the substring should not be nested,
224  ! otherwise the walltime will be counted multiple times
225  write (this%iout, '(1x,a/)') &
226  repeat('-', 20)//" Profiler: Totals "//repeat('-', 20)
227  call this%print_total("Formulate")
228  call this%print_total("Linear solve")
229  call this%print_total("Calculate flows")
230  call this%print_total("Calculate budgets")
231  call this%print_total("Write output")
232  call this%print_total("Parallel Solution")
233  call this%print_total("MPI_WaitAll")
234  write (this%iout, '(/1x,a/)') &
235  repeat('-', 22)//" End Profiler "//repeat('-', 22)
236 
Here is the caller graph for this function:

◆ print_section()

recursive subroutine profilermodule::print_section ( class(profilertype this,
integer(i4b)  section_id,
integer(i4b)  level 
)
private

Definition at line 239 of file Profiler.f90.

240  use arrayhandlersmodule, only: ifind
241  class(ProfilerType) :: this
242  integer(I4B) :: section_id
243  integer(I4B) :: level
244  ! local
245  integer(I4B) :: i, new_level, nr_padding, idx_top
246  real(DP) :: percent
247  type(MeasuredSectionType), pointer :: section
248  character(len=:), allocatable :: title_padded
249  character(len=LINELENGTH) :: top_marker
250 
251  section => this%all_sections(section_id)
252 
253  ! calculate percentage
254  percent = 1.0_dp
255  if (section%parent_id /= 0) then
256  percent = section%walltime / this%all_sections(this%root_id)%walltime
257  end if
258  percent = percent * 100.0_dp
259 
260  ! determine if section should be marked as top three
261  top_marker = ""
262  idx_top = ifind(this%top_three, section_id)
263  if (idx_top > 0) then
264  nr_padding = max(0, 32 - level * 4)
265  write (top_marker, '(a,i0)') repeat(" ", nr_padding)//"<== #", idx_top
266  end if
267 
268  ! print section timing
269  nr_padding = this%max_title_len - len_trim(section%title) + 2
270  title_padded = trim(section%title)//":"//repeat(' ', nr_padding)
271  write (this%iout, '(3a,f6.2,2a,f14.6,2a,i0,a,a)') " ", &
272  repeat('....', level), "[", percent, "%] ", title_padded, &
273  section%walltime, "s", " (", section%count, "x)", trim(top_marker)
274 
275  ! print children
276  new_level = level + 1
277  do i = 1, section%children%size
278  call this%print_section(section%children%at(i), new_level)
279  end do
280 
281  if (level == 0) write (this%iout, *)
282 

◆ print_total()

subroutine profilermodule::print_total ( class(profilertype this,
character(len=*)  subtitle 
)

Definition at line 285 of file Profiler.f90.

286  class(ProfilerType) :: this
287  character(len=*) :: subtitle
288  ! local
289  integer(I4B) :: count
290  real(DP) :: walltime, percent
291  integer(I4B) :: nr_padding
292  character(len=:), allocatable :: title_padded
293 
294  ! get maximum length of title
295  nr_padding = this%max_title_len - len_trim(subtitle)
296  title_padded = trim(subtitle)//repeat(' ', nr_padding)
297 
298  count = this%aggregate_counts(subtitle)
299  if (count > 0) then
300  walltime = aggregate_walltime(this, subtitle)
301  percent = (walltime / this%all_sections(this%root_id)%walltime) * 100.0_dp
302  write (this%iout, '(2a,f6.2,3a,f14.6,2a,i0,a)') " ", "[", percent, &
303  "%] ", title_padded, ": ", walltime, "s", " (", count, "x)"
304  end if
305 
Here is the call graph for this function:

◆ set_print_option()

subroutine profilermodule::set_print_option ( class(profilertype this,
character(len=*), intent(in)  profile_option 
)
private

Definition at line 346 of file Profiler.f90.

347  class(ProfilerType) :: this
348  character(len=*), intent(in) :: profile_option
349 
350  select case (trim(profile_option))
351  case ("NONE")
352  this%pr_option = 0
353  case ("SUMMARY")
354  this%pr_option = 1
355  case ("DETAIL")
356  this%pr_option = 2
357  case default
358  this%pr_option = 0
359  end select
360 

◆ sort_by_walltime()

subroutine profilermodule::sort_by_walltime ( class(profilertype this,
integer(i4b), dimension(:), allocatable  idxs 
)
private
Parameters
idxsarray with unsorted section idxs

Definition at line 404 of file Profiler.f90.

405  class(ProfilerType) :: this
406  integer(I4B), dimension(:), allocatable :: idxs !< array with unsorted section idxs
407  integer(I4B) :: i, j, temp
408 
409  ! Simple bubble sort for demonstration purposes
410  do i = 1, size(idxs) - 1
411  do j = 1, size(idxs) - i
412  if (this%all_sections(idxs(j))%walltime < &
413  this%all_sections(idxs(j + 1))%walltime) then
414  temp = idxs(j)
415  idxs(j) = idxs(j + 1)
416  idxs(j + 1) = temp
417  end if
418  end do
419  end do
420 

◆ start()

subroutine profilermodule::start ( class(profilertype this,
character(len=*)  title,
integer(i4b)  section_id 
)

Definition at line 143 of file Profiler.f90.

144  class(ProfilerType) :: this
145  character(len=*) :: title
146  integer(I4B) :: section_id
147  ! local
148  integer(I4B) :: parent_id
149  real(DP) :: start_time
150  type(MeasuredSectionType), pointer :: section
151 
152  call cpu_time(start_time)
153 
154  if (section_id == -1) then
155  ! add section if not exist
156  parent_id = 0 ! root
157  if (this%callstack%size() > 0) then
158  parent_id = this%callstack%top()
159  end if
160  section_id = this%add_section(title, parent_id)
161  end if
162  call this%callstack%push(section_id)
163 
164  section => this%all_sections(section_id)
165  section%count = section%count + 1
166  section%status = 1
167  section%walltime = section%walltime - start_time
168 

◆ stop()

subroutine profilermodule::stop ( class(profilertype this,
integer(i4b)  section_id 
)
private

Definition at line 171 of file Profiler.f90.

172  class(ProfilerType) :: this
173  integer(I4B) :: section_id
174  ! local
175  real(DP) :: end_time
176  type(MeasuredSectionType), pointer :: section
177 
178  call cpu_time(end_time)
179 
180  ! nett result (c.f. start(...)) is adding (dt = end_time - start_time)
181  section => this%all_sections(section_id)
182  section%status = 0
183  section%walltime = section%walltime + end_time
184 
185  ! pop from call stack
186  call this%callstack%pop()
187 

Variable Documentation

◆ g_prof

type(profilertype), public profilermodule::g_prof

Definition at line 65 of file Profiler.f90.

65  type(ProfilerType), public :: g_prof !< the global timer object (to reduce trivial lines of code)

◆ len_section_title

integer(i4b), parameter, public profilermodule::len_section_title = 128

Definition at line 11 of file Profiler.f90.

11  integer(I4B), public, parameter :: LEN_SECTION_TITLE = 128

◆ max_nr_timed_sections

integer(i4b), parameter profilermodule::max_nr_timed_sections = 75
private

Definition at line 10 of file Profiler.f90.

10  integer(I4B), parameter :: MAX_NR_TIMED_SECTIONS = 75